Horis 1 anno fa
parent
commit
4e50417624

+ 3 - 3
app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt

@@ -35,7 +35,8 @@ data class TextPage(
     var chapterSize: Int = 0,
     var chapterIndex: Int = 0,
     var height: Float = 0f,
-    var leftLineSize: Int = 0
+    var leftLineSize: Int = 0,
+    var renderHeight: Int = 0
 ) {
 
     companion object {
@@ -332,8 +333,7 @@ data class TextPage(
 
     fun render(view: ContentTextView): Boolean {
         if (!isCompleted) return false
-        val height = lines.lastOrNull()?.lineBottom?.toInt() ?: 0
-        return canvasRecorder.recordIfNeeded(view.width, height) {
+        return canvasRecorder.recordIfNeeded(view.width, renderHeight) {
             drawPage(view, this)
         }
     }

+ 68 - 134
app/src/main/java/io/legado/app/ui/book/read/page/provider/TextChapterLayout.kt

@@ -86,6 +86,9 @@ class TextChapterLayout(
 
     var channel = Channel<TextPage>(Int.MAX_VALUE)
 
+    var durY = 0f
+    var absStartX = paddingLeft
+
     init {
         job = Coroutine.async(
             scope,
@@ -127,7 +130,7 @@ class TextChapterLayout(
     }
 
     private fun onPageCompleted() {
-        val textPage = textPages.last()
+        val textPage = pendingTextPage
         textPage.index = textPages.lastIndex
         textPage.chapterIndex = bookChapter.index
         textPage.chapterSize = chaptersSize
@@ -137,6 +140,8 @@ class TextChapterLayout(
         textPage.isCompleted = true
         textPage.textChapter = textChapter
         textPage.upLinesPosition()
+        textPage.renderHeight = textPage.lines.maxOf { it.lineBottom.toInt() }
+        textPages.add(textPage)
         channel.trySend(textPage)
         try {
             listener?.onLayoutPageCompleted(textPages.lastIndex, textPage)
@@ -184,16 +189,15 @@ class TextChapterLayout(
         bookContent: BookContent,
     ) {
         val contents = bookContent.textList
-        var absStartX = paddingLeft
-        var durY = 0f
         val imageStyle = book.getImageStyle()
         val isSingleImageStyle = imageStyle.equals(Book.imgStyleSingle, true)
+        val isTextImageStyle = imageStyle.equals(Book.imgStyleText, true)
 
         if (ReadBookConfig.titleMode != 2 || bookChapter.isVolume || contents.isEmpty()) {
             //标题非隐藏
             displayTitle.splitNotBlank("\n").forEach { text ->
                 setTypeText(
-                    book, absStartX, durY,
+                    book,
                     if (AppConfig.enableReview) text + ChapterProvider.reviewChar else text,
                     titlePaint,
                     titlePaintTextHeight,
@@ -202,10 +206,7 @@ class TextChapterLayout(
                     isTitle = true,
                     emptyContent = contents.isEmpty(),
                     isVolumeTitle = bookChapter.isVolume
-                ).let {
-                    absStartX = it.first
-                    durY = it.second
-                }
+                )
             }
             pendingTextPage.lines.last().isParagraphEnd = true
             stringBuilder.append("\n")
@@ -213,19 +214,15 @@ class TextChapterLayout(
 
             // 如果是单图模式且当前页有内容,强制分页
             if (isSingleImageStyle && pendingTextPage.lines.isNotEmpty()) {
-                pendingTextPage.height = durY
-                textPages.add(pendingTextPage)
-                onPageCompleted()
-                pendingTextPage = TextPage()
-                stringBuilder.clear()
-                absStartX = paddingLeft
-                durY = 0f
+                prepareNextPageIfNeed()
             }
         }
+
         val sb = StringBuffer()
+        var isSetTypedImage = false
         contents.forEach { content ->
             coroutineContext.ensureActive()
-            if (book.getImageStyle().equals(Book.imgStyleText, true)) {
+            if (isTextImageStyle) {
                 //图片样式为文字嵌入类型
                 var text = content.replace(ChapterProvider.srcReplaceChar, "▣")
                 val srcList = LinkedList<String>()
@@ -241,19 +238,18 @@ class TextChapterLayout(
                 text = sb.toString()
                 setTypeText(
                     book,
-                    absStartX,
-                    durY,
                     text,
                     contentPaint,
                     contentPaintTextHeight,
                     contentPaintFontMetrics,
                     book.getImageStyle(),
                     srcList = srcList
-                ).let {
-                    absStartX = it.first
-                    durY = it.second
-                }
+                )
             } else {
+                if (isSingleImageStyle && isSetTypedImage) {
+                    isSetTypedImage = false
+                    prepareNextPageIfNeed()
+                }
                 val matcher = AppPattern.imgPattern.matcher(content)
                 var start = 0
                 while (matcher.find()) {
@@ -262,57 +258,45 @@ class TextChapterLayout(
                     if (text.isNotBlank()) {
                         setTypeText(
                             book,
-                            absStartX,
-                            durY,
                             text,
                             contentPaint,
                             contentPaintTextHeight,
                             contentPaintFontMetrics,
                             book.getImageStyle(),
                             isFirstLine = start == 0
-                        ).let {
-                            absStartX = it.first
-                            durY = it.second
-                        }
+                        )
                     }
                     setTypeImage(
                         book,
                         matcher.group(1)!!,
-                        absStartX,
-                        durY,
                         contentPaintTextHeight,
-                        stringBuilder,
                         book.getImageStyle()
-                    ).let {
-                        absStartX = it.first
-                        durY = it.second
-                    }
+                    )
+                    isSetTypedImage = true
                     start = matcher.end()
                 }
                 if (start < content.length) {
+                    if (isSingleImageStyle && isSetTypedImage) {
+                        isSetTypedImage = false
+                        prepareNextPageIfNeed()
+                    }
                     val text = content.substring(start, content.length)
                     if (text.isNotBlank()) {
                         setTypeText(
-                            book, absStartX, durY,
+                            book,
                             if (AppConfig.enableReview) text + ChapterProvider.reviewChar else text,
                             contentPaint,
                             contentPaintTextHeight,
                             contentPaintFontMetrics,
                             book.getImageStyle(),
                             isFirstLine = start == 0
-                        ).let {
-                            absStartX = it.first
-                            durY = it.second
-                        }
+                        )
                     }
                 }
             }
-            if (pendingTextPage.lines.isNotEmpty()) {
-                pendingTextPage.lines.last().isParagraphEnd = true
-            }
+            pendingTextPage.lines.last().isParagraphEnd = true
             stringBuilder.append("\n")
         }
-        textPages.add(pendingTextPage)
         val textPage = pendingTextPage
         val endPadding = 20.dpToPx()
         val durYPadding = durY + endPadding
@@ -333,29 +317,12 @@ class TextChapterLayout(
     private suspend fun setTypeImage(
         book: Book,
         src: String,
-        x: Int,
-        y: Float,
         textHeight: Float,
-        stringBuilder: StringBuilder,
         imageStyle: String?,
-    ): Pair<Int, Float> {
-        var absStartX = x
-        var durY = y
+    ) {
         val size = ImageProvider.getImageSize(book, src, ReadBook.bookSource)
         if (size.width > 0 && size.height > 0) {
-            if (durY > visibleHeight) {
-                val textPage = pendingTextPage
-                if (textPage.height < durY) {
-                    textPage.height = durY
-                }
-                textPage.text = stringBuilder.toString().ifEmpty { "本页无文字内容" }
-                stringBuilder.clear()
-                textPages.add(textPage)
-                coroutineContext.ensureActive()
-                onPageCompleted()
-                pendingTextPage = TextPage()
-                durY = 0f
-            }
+            prepareNextPageIfNeed(durY)
             var height = size.height
             var width = size.width
             when (imageStyle?.uppercase()) {
@@ -372,17 +339,7 @@ class TextChapterLayout(
                         height = visibleHeight
                     }
                     if (durY > 0f) {
-                        val textPage = pendingTextPage
-                        if (textPage.height < durY) {
-                            textPage.height = durY
-                        }
-                        textPage.text = stringBuilder.toString().ifEmpty { "本页无文字内容" }
-                        stringBuilder.clear()
-                        textPages.add(textPage)
-                        coroutineContext.ensureActive()
-                        onPageCompleted()
-                        pendingTextPage = TextPage()
-                        durY = 0f
+                        prepareNextPageIfNeed()
                     }
 
                     // 图片竖直方向居中:调整 Y 坐标
@@ -401,30 +358,7 @@ class TextChapterLayout(
                         width = width * visibleHeight / height
                         height = visibleHeight
                     }
-                    if (durY + height > visibleHeight) {
-                        val textPage = pendingTextPage
-                        // 双页的 durY 不正确,可能会小于实际高度
-                        if (textPage.height < durY) {
-                            textPage.height = durY
-                        }
-                        if (doublePage && absStartX < viewWidth / 2) {
-                            //当前页面左列结束
-                            textPage.leftLineSize = textPage.lineSize
-                            absStartX = viewWidth / 2 + paddingLeft
-                        } else {
-                            //当前页面结束
-                            if (textPage.leftLineSize == 0) {
-                                textPage.leftLineSize = textPage.lineSize
-                            }
-                            textPage.text = stringBuilder.toString().ifEmpty { "本页无文字内容" }
-                            stringBuilder.clear()
-                            textPages.add(textPage)
-                            coroutineContext.ensureActive()
-                            onPageCompleted()
-                            pendingTextPage = TextPage()
-                        }
-                        durY = 0f
-                    }
+                    prepareNextPageIfNeed(durY + height)
                 }
             }
             val textLine = TextLine(isImage = true)
@@ -439,13 +373,13 @@ class TextChapterLayout(
                 Pair(0f, width.toFloat())
             }
             textLine.addColumn(
-                ImageColumn(start = x + start, end = x + end, src = src)
+                ImageColumn(start = absStartX + start, end = absStartX + end, src = src)
             )
             calcTextLinePosition(textPages, textLine, stringBuilder.length)
             stringBuilder.append(" ") // 确保翻页时索引计算正确
             pendingTextPage.addLine(textLine)
         }
-        return absStartX to durY + textHeight * paragraphSpacing / 10f
+        durY += textHeight * paragraphSpacing / 10f
     }
 
     /**
@@ -454,8 +388,6 @@ class TextChapterLayout(
     @Suppress("DEPRECATION")
     private suspend fun setTypeText(
         book: Book,
-        x: Int,
-        y: Float,
         text: String,
         textPaint: TextPaint,
         textHeight: Float,
@@ -466,8 +398,7 @@ class TextChapterLayout(
         emptyContent: Boolean = false,
         isVolumeTitle: Boolean = false,
         srcList: LinkedList<String>? = null
-    ): Pair<Int, Float> {
-        var absStartX = x
+    ) {
         val widthsArray = FloatArray(text.length)
         textPaint.getTextWidths(text, widthsArray)
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
@@ -485,7 +416,7 @@ class TextChapterLayout(
         } else {
             StaticLayout(text, textPaint, visibleWidth, Layout.Alignment.ALIGN_NORMAL, 0f, 0f, true)
         }
-        var durY = when {
+        durY = when {
             //标题y轴居中
             emptyContent && textPages.isEmpty() -> {
                 val textPage = pendingTextPage
@@ -503,7 +434,7 @@ class TextChapterLayout(
                         it.lineBase -= textLayoutHeight
                         it.lineBottom -= textLayoutHeight
                     }
-                    y - textLayoutHeight
+                    durY - textLayoutHeight
                 }
             }
 
@@ -514,39 +445,15 @@ class TextChapterLayout(
                         if (ty > titleTopSpacing) ty else titleTopSpacing.toFloat()
                     }
 
-                    else -> y + titleTopSpacing
+                    else -> durY + titleTopSpacing
                 }
             }
 
-            else -> y
+            else -> durY
         }
         for (lineIndex in 0 until layout.lineCount) {
             val textLine = TextLine(isTitle = isTitle)
-            if (durY + textHeight > visibleHeight) {
-                val textPage = pendingTextPage
-                if (textPage.height < durY) {
-                    textPage.height = durY
-                }
-                if (doublePage && absStartX < viewWidth / 2) {
-                    //当前页面左列结束
-                    textPage.leftLineSize = textPage.lineSize
-                    absStartX = viewWidth / 2 + paddingLeft
-                } else {
-                    //当前页面结束,设置各种值
-                    if (textPage.leftLineSize == 0) {
-                        textPage.leftLineSize = textPage.lineSize
-                    }
-                    textPage.text = stringBuilder.toString()
-                    textPages.add(textPage)
-                    coroutineContext.ensureActive()
-                    onPageCompleted()
-                    //新建页面
-                    pendingTextPage = TextPage()
-                    stringBuilder.clear()
-                    absStartX = paddingLeft
-                }
-                durY = 0f
-            }
+            prepareNextPageIfNeed(durY + textHeight)
             val lineStart = layout.getLineStart(lineIndex)
             val lineEnd = layout.getLineEnd(lineIndex)
             val lineText = text.substring(lineStart, lineEnd)
@@ -615,7 +522,6 @@ class TextChapterLayout(
             }
         }
         durY += textHeight * paragraphSpacing / 10f
-        return Pair(absStartX, durY)
     }
 
     private fun calcTextLinePosition(
@@ -850,6 +756,34 @@ class TextChapterLayout(
         }
     }
 
+    private suspend fun prepareNextPageIfNeed(requestHeight: Float = -1f) {
+        if (requestHeight > visibleHeight || requestHeight == -1f) {
+            val textPage = pendingTextPage
+            // 双页的 durY 不正确,可能会小于实际高度
+            if (textPage.height < durY) {
+                textPage.height = durY
+            }
+            if (doublePage && absStartX < viewWidth / 2) {
+                //当前页面左列结束
+                textPage.leftLineSize = textPage.lineSize
+                absStartX = viewWidth / 2 + paddingLeft
+            } else {
+                //当前页面结束,设置各种值
+                if (textPage.leftLineSize == 0) {
+                    textPage.leftLineSize = textPage.lineSize
+                }
+                textPage.text = stringBuilder.toString()
+                coroutineContext.ensureActive()
+                onPageCompleted()
+                //新建页面
+                pendingTextPage = TextPage()
+                stringBuilder.clear()
+                absStartX = paddingLeft
+            }
+            durY = 0f
+        }
+    }
+
     private fun measureTextSplit(
         text: String,
         widthsArray: FloatArray,