Horis 3 سال پیش
والد
کامیت
886cecb280

+ 1 - 1
app/src/main/java/io/legado/app/help/config/AppConfig.kt

@@ -213,7 +213,7 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
         get() = appCtx.getPrefBoolean(PreferKey.autoRefresh)
 
     var enableReview: Boolean
-        get() = appCtx.getPrefBoolean(PreferKey.enableReview, false) && BuildConfig.DEBUG
+        get() = BuildConfig.DEBUG && appCtx.getPrefBoolean(PreferKey.enableReview, false)
         set(value) {
             appCtx.putPrefBoolean(PreferKey.enableReview, value)
         }

+ 3 - 3
app/src/main/java/io/legado/app/model/ImageProvider.kt

@@ -129,14 +129,14 @@ object ImageProvider {
         bookSource: BookSource?
     ): Size {
         val file = cacheImage(book, src, bookSource)
-        //svg size
-        val size = SvgUtils.getSize(file.absolutePath)
-        if (size != null) return size
         val op = BitmapFactory.Options()
         // inJustDecodeBounds如果设置为true,仅仅返回图片实际的宽和高,宽和高是赋值给opts.outWidth,opts.outHeight;
         op.inJustDecodeBounds = true
         BitmapFactory.decodeFile(file.absolutePath, op)
         if (op.outWidth < 1 && op.outHeight < 1) {
+            //svg size
+            val size = SvgUtils.getSize(file.absolutePath)
+            if (size != null) return size
             putDebug("ImageProvider: $src Unsupported image type")
             //file.delete() 重复下载
             return Size(errorBitmap.width, errorBitmap.height)

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

@@ -1,5 +1,6 @@
 package io.legado.app.ui.book.read.page.entities
 
+import android.graphics.Paint.FontMetrics
 import android.text.TextPaint
 import androidx.annotation.Keep
 import io.legado.app.ui.book.read.page.entities.column.BaseColumn
@@ -51,10 +52,10 @@ data class TextLine(
         return textColumns.size
     }
 
-    fun upTopBottom(durY: Float, textPaint: TextPaint) {
+    fun upTopBottom(durY: Float, textHeight: Float, fontMetrics: FontMetrics) {
         lineTop = ChapterProvider.paddingTop + durY
-        lineBottom = lineTop + textPaint.textHeight
-        lineBase = lineBottom - textPaint.fontMetrics.descent
+        lineBottom = lineTop + textHeight
+        lineBase = lineBottom - fontMetrics.descent
     }
 
     fun isTouch(x: Float, y: Float, relativeOffset: Float): Boolean {

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

@@ -8,7 +8,6 @@ import io.legado.app.help.config.ReadBookConfig
 import io.legado.app.model.ReadBook
 import io.legado.app.ui.book.read.page.entities.column.TextColumn
 import io.legado.app.ui.book.read.page.provider.ChapterProvider
-import io.legado.app.utils.textHeight
 import splitties.init.appCtx
 import java.text.DecimalFormat
 import kotlin.math.min
@@ -76,7 +75,7 @@ data class TextPage(
             val lastLine = textLines[leftLineSize - 1]
             if (lastLine.isImage) return@run
             val lastLineHeight = with(lastLine) { lineBottom - lineTop }
-            val pageHeight = lastLine.lineBottom + contentPaint.textHeight * lineSpacingExtra
+            val pageHeight = lastLine.lineBottom + contentPaintTextHeight * lineSpacingExtra
             if (visibleHeight - pageHeight >= lastLineHeight) return@run
             val surplus = (visibleBottom - lastLine.lineBottom)
             if (surplus == 0f) return@run
@@ -94,7 +93,7 @@ data class TextPage(
             val lastLine = textLines.last()
             if (lastLine.isImage) return@run
             val lastLineHeight = with(lastLine) { lineBottom - lineTop }
-            val pageHeight = lastLine.lineBottom + contentPaint.textHeight * lineSpacingExtra
+            val pageHeight = lastLine.lineBottom + contentPaintTextHeight * lineSpacingExtra
             if (visibleHeight - pageHeight >= lastLineHeight) return@run
             val surplus = (visibleBottom - lastLine.lineBottom)
             if (surplus == 0f) return@run

+ 88 - 40
app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt

@@ -1,6 +1,7 @@
 package io.legado.app.ui.book.read.page.provider
 
 import android.graphics.Paint
+import android.graphics.Paint.FontMetrics
 import android.graphics.Typeface
 import android.net.Uri
 import android.os.Build
@@ -25,6 +26,7 @@ import io.legado.app.ui.book.read.page.entities.column.TextColumn
 import io.legado.app.utils.*
 import splitties.init.appCtx
 import java.util.*
+import kotlin.collections.ArrayList
 
 /**
  * 解析内容生成章节和页面
@@ -97,7 +99,13 @@ object ChapterProvider {
     private var titlePaintTextHeight = 0f
 
     @JvmStatic
-    private var  contentPaintTextHeight = 0f
+    var contentPaintTextHeight = 0f
+
+    @JvmStatic
+    private var titlePaintFontMetrics = FontMetrics()
+
+    @JvmStatic
+    var contentPaintFontMetrics = FontMetrics()
 
     @JvmStatic
     var typeface: Typeface? = Typeface.DEFAULT
@@ -146,6 +154,7 @@ object ChapterProvider {
                     stringBuilder,
                     titlePaint,
                     titlePaintTextHeight,
+                    titlePaintFontMetrics,
                     isTitle = true,
                     emptyContent = contents.isEmpty(),
                     isVolumeTitle = bookChapter.isVolume
@@ -180,6 +189,7 @@ object ChapterProvider {
                     stringBuilder,
                     contentPaint,
                     contentPaintTextHeight,
+                    contentPaintFontMetrics,
                     srcList = srcList
                 ).let {
                     absStartX = it.first
@@ -199,7 +209,8 @@ object ChapterProvider {
                             textPages,
                             stringBuilder,
                             contentPaint,
-                            contentPaintTextHeight
+                            contentPaintTextHeight,
+                            contentPaintFontMetrics
                         ).let {
                             absStartX = it.first
                             durY = it.second
@@ -220,7 +231,8 @@ object ChapterProvider {
                             textPages,
                             stringBuilder,
                             contentPaint,
-                            contentPaintTextHeight
+                            contentPaintTextHeight,
+                            contentPaintFontMetrics
                         ).let {
                             absStartX = it.first
                             durY = it.second
@@ -331,6 +343,7 @@ object ChapterProvider {
         stringBuilder: StringBuilder,
         textPaint: TextPaint,
         textHeight: Float,
+        fontMetrics: FontMetrics,
         isTitle: Boolean = false,
         emptyContent: Boolean = false,
         isVolumeTitle: Boolean = false,
@@ -342,6 +355,9 @@ object ChapterProvider {
         } else {
             StaticLayout(text, textPaint, visibleWidth, Layout.Alignment.ALIGN_NORMAL, 0f, 0f, true)
         }
+        val widthsArray = FloatArray(text.length)
+        textPaint.getTextWidths(text, widthsArray)
+        val widthsList = widthsArray.asList()
         var durY = when {
             //标题y轴居中
             emptyContent && textPages.size == 1 -> {
@@ -371,7 +387,7 @@ object ChapterProvider {
         }
         for (lineIndex in 0 until layout.lineCount) {
             val textLine = TextLine(isTitle = isTitle)
-            if (durY + textPaint.textHeight > visibleHeight) {
+            if (durY + textHeight > visibleHeight) {
                 val textPage = textPages.last()
                 if (doublePage && absStartX < viewWidth / 2) {
                     textPage.leftLineSize = textPage.lineSize
@@ -390,16 +406,18 @@ object ChapterProvider {
                 }
                 durY = 0f
             }
-            val words =
-                text.substring(layout.getLineStart(lineIndex), layout.getLineEnd(lineIndex))
-            val desiredWidth = layout.getLineWidth(lineIndex)
+            val lineStart = layout.getLineStart(lineIndex)
+            val lineEnd = layout.getLineEnd(lineIndex)
+            val words = text.substring(lineStart, lineEnd)
+            val textWidths = widthsList.subList(lineStart, lineEnd)
+            val desiredWidth = textWidths.sum()
             when {
                 lineIndex == 0 && layout.lineCount > 1 && !isTitle -> {
                     //第一行 非标题
                     textLine.text = words
                     addCharsToLineFirst(
-                        book, absStartX, textLine, words.toStringArray(),
-                        textPaint, desiredWidth, srcList
+                        book, absStartX, textLine, words,
+                        textPaint, desiredWidth, textWidths, srcList
                     )
                 }
 
@@ -412,13 +430,13 @@ object ChapterProvider {
                         isTitle &&
                         (ReadBookConfig.isMiddleTitle || emptyContent || isVolumeTitle)
                     ) {
-                        (visibleWidth - layout.getLineWidth(lineIndex)) / 2
+                        (visibleWidth - desiredWidth) / 2
                     } else {
                         0f
                     }
                     addCharsToLineNatural(
-                        book, absStartX, textLine, words.toStringArray(), textPaint,
-                        startX, !isTitle && lineIndex == 0, srcList
+                        book, absStartX, textLine, words, textPaint,
+                        startX, !isTitle && lineIndex == 0, textWidths, srcList
                     )
                 }
 
@@ -428,17 +446,17 @@ object ChapterProvider {
                         (ReadBookConfig.isMiddleTitle || emptyContent || isVolumeTitle)
                     ) {
                         //标题居中
-                        val startX = (visibleWidth - layout.getLineWidth(lineIndex)) / 2
+                        val startX = (visibleWidth - desiredWidth) / 2
                         addCharsToLineNatural(
-                            book, absStartX, textLine, words.toStringArray(),
-                            textPaint, startX, false, srcList
+                            book, absStartX, textLine, words,
+                            textPaint, startX, false, textWidths, srcList
                         )
                     } else {
                         //中间行
                         textLine.text = words
                         addCharsToLineMiddle(
-                            book, absStartX, textLine, words.toStringArray(),
-                            textPaint, desiredWidth, 0f, srcList
+                            book, absStartX, textLine, words,
+                            textPaint, desiredWidth, 0f, textWidths, srcList
                         )
                     }
                 }
@@ -462,7 +480,7 @@ object ChapterProvider {
                 } ?: 0) + sbLength
             textLine.pagePosition = sbLength
             textPages.last().addLine(textLine)
-            textLine.upTopBottom(durY, textPaint)
+            textLine.upTopBottom(durY, textHeight, fontMetrics)
             durY += textHeight * lineSpacingExtra
             textPages.last().height = durY
         }
@@ -477,17 +495,18 @@ object ChapterProvider {
         book: Book,
         absStartX: Int,
         textLine: TextLine,
-        words: Array<String>,
+        text: String,
         textPaint: TextPaint,
         /**自然排版长度**/
         desiredWidth: Float,
+        textWidths: List<Float>,
         srcList: LinkedList<String>?
     ) {
         var x = 0f
         if (!ReadBookConfig.textFullJustify) {
             addCharsToLineNatural(
-                book, absStartX, textLine, words, textPaint,
-                x, true, srcList
+                book, absStartX, textLine, text, textPaint,
+                x, true, textWidths, srcList
             )
             return
         }
@@ -504,11 +523,12 @@ object ChapterProvider {
             x = x1
             textLine.indentWidth = x
         }
-        if (words.size > bodyIndent.length) {
-            val words1 = words.copyOfRange(bodyIndent.length, words.size)
+        if (text.length > bodyIndent.length) {
+            val text1 = text.substring(bodyIndent.length, text.length)
+            val textWidths1 = textWidths.subList(bodyIndent.length, textWidths.size)
             addCharsToLineMiddle(
-                book, absStartX, textLine, words1,
-                textPaint, desiredWidth, x, srcList
+                book, absStartX, textLine, text1,
+                textPaint, desiredWidth, x, textWidths1, srcList
             )
         }
     }
@@ -520,28 +540,30 @@ object ChapterProvider {
         book: Book,
         absStartX: Int,
         textLine: TextLine,
-        words: Array<String>,
+        text: String,
         textPaint: TextPaint,
         /**自然排版长度**/
         desiredWidth: Float,
         /**起始x坐标**/
         startX: Float,
+        textWidths: List<Float>,
         srcList: LinkedList<String>?
     ) {
         if (!ReadBookConfig.textFullJustify) {
             addCharsToLineNatural(
-                book, absStartX, textLine, words, textPaint,
-                startX, false, srcList
+                book, absStartX, textLine, text, textPaint,
+                startX, false, textWidths, srcList
             )
             return
         }
         val residualWidth = visibleWidth - desiredWidth
-        val spaceSize = words.filter { it == " " }.size
+        val spaceSize = text.count { it == ' ' }
+        val (words, widths) = getStringArrayAndTextWidths(text, textWidths)
         if (spaceSize > 1) {
             val d = residualWidth / spaceSize
             var x = startX
             words.forEachIndexed { index, char ->
-                val cw = StaticLayout.getDesiredWidth(char, textPaint)
+                val cw = widths[index]
                 val x1 = if (char == " ") {
                     if (index != words.lastIndex) (x + cw + d) else (x + cw)
                 } else {
@@ -558,7 +580,7 @@ object ChapterProvider {
             val d = residualWidth / gapCount
             var x = startX
             words.forEachIndexed { index, char ->
-                val cw = StaticLayout.getDesiredWidth(char, textPaint)
+                val cw = widths[index]
                 val x1 = if (index != words.lastIndex) (x + cw + d) else (x + cw)
                 addCharToLine(
                     book, absStartX, textLine, char,
@@ -567,7 +589,7 @@ object ChapterProvider {
                 x = x1
             }
         }
-        exceed(absStartX, textLine, words)
+        exceed(absStartX, textLine)
     }
 
     /**
@@ -577,16 +599,18 @@ object ChapterProvider {
         book: Book,
         absStartX: Int,
         textLine: TextLine,
-        words: Array<String>,
+        text: String,
         textPaint: TextPaint,
         startX: Float,
         hasIndent: Boolean,
+        textWidths: List<Float>,
         srcList: LinkedList<String>?
     ) {
         val indentLength = ReadBookConfig.paragraphIndent.length
         var x = startX
+        val (words, widths) = getStringArrayAndTextWidths(text, textWidths)
         words.forEachIndexed { index, char ->
-            val cw = StaticLayout.getDesiredWidth(char, textPaint)
+            val cw = widths[index]
             val x1 = x + cw
             addCharToLine(book, absStartX, textLine, char, x, x1, index + 1 == words.size, srcList)
             x = x1
@@ -594,7 +618,28 @@ object ChapterProvider {
                 textLine.indentWidth = x
             }
         }
-        exceed(absStartX, textLine, words)
+        exceed(absStartX, textLine)
+    }
+
+    private fun getStringArrayAndTextWidths(
+        text: String,
+        textWidths: List<Float>
+    ): Pair<List<String>, List<Float>> {
+        val strList = arrayListOf<String>()
+        val textWidthList = arrayListOf<Float>()
+        for (i in textWidths.indices) {
+            if (text[i].isLowSurrogate()) {
+                continue
+            }
+            val char = if (i + 1 < text.lastIndex && text[i + 1].isLowSurrogate()) {
+                text.substring(i, i + 2)
+            } else {
+                text.substring(i, i + 1)
+            }
+            strList.add(char)
+            textWidthList.add(textWidths[i])
+        }
+        return strList to textWidthList
     }
 
     /**
@@ -643,14 +688,15 @@ object ChapterProvider {
     /**
      * 超出边界处理
      */
-    private fun exceed(absStartX: Int, textLine: TextLine, words: Array<String>) {
+    private fun exceed(absStartX: Int, textLine: TextLine) {
         val visibleEnd = absStartX + visibleWidth
-        val endX = textLine.columns.lastOrNull()?.end ?: return
+        val columns = textLine.columns
+        val endX = columns.lastOrNull()?.end ?: return
         if (endX > visibleEnd) {
-            val cc = (endX - visibleEnd) / words.size
-            for (i in 0..words.lastIndex) {
+            val cc = (endX - visibleEnd) / columns.size
+            for (i in 0..columns.lastIndex) {
                 textLine.getColumnReverseAt(i).let {
-                    val py = cc * (words.size - i)
+                    val py = cc * (columns.size - i)
                     it.start = it.start - py
                     it.end = it.end - py
                 }
@@ -679,6 +725,8 @@ object ChapterProvider {
         indentCharWidth = StaticLayout.getDesiredWidth(bodyIndent, contentPaint) / bodyIndent.length
         titlePaintTextHeight = titlePaint.textHeight
         contentPaintTextHeight = contentPaint.textHeight
+        titlePaintFontMetrics = titlePaint.fontMetrics
+        contentPaintFontMetrics = contentPaint.fontMetrics
         upLayout()
     }