This commit is contained in:
Horis
2023-09-29 13:18:57 +08:00
parent 083293df39
commit 861636d9ed
5 changed files with 98 additions and 50 deletions
@@ -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)
}
@@ -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)
@@ -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 {
@@ -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
@@ -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()
}