diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextLine.kt b/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextLine.kt index 5ae229b1e..ca4e5a428 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextLine.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextLine.kt @@ -82,7 +82,7 @@ data class TextLine( fun addColumn(column: BaseColumn) { if (column !is TextColumn) { onlyTextColumn = false - } else if (column.textColor != null || column.bgColor != null || column.underlineMode != 0 || column.bgImage.isNotEmpty()) { + } else if (column.textColor != null || column.bgColor != null || column.underlineMode != 0 || column.bgImage.isNotEmpty() || column.fontPath.isNotEmpty()) { onlyTextColumn = false } column.textLine = this diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/entities/column/TextColumn.kt b/app/src/main/java/io/legado/app/ui/book/read/page/entities/column/TextColumn.kt index 33acaacf4..6ea1a3019 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/entities/column/TextColumn.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/entities/column/TextColumn.kt @@ -110,15 +110,19 @@ data class TextColumn( } private fun getCustomTypeface(): Typeface? { - if (fontPath.isEmpty()) return null - return typefaceCache.getOrPut(fontPath) { - loadTypeface(fontPath) - } + return getTypeface(fontPath) } companion object { private val typefaceCache = HashMap() + internal fun getTypeface(fontPath: String): Typeface? { + if (fontPath.isEmpty()) return null + return typefaceCache.getOrPut(fontPath) { + loadTypeface(fontPath) + } + } + private fun loadTypeface(fontPath: String): Typeface? { return runCatching { when { diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/provider/TextChapterLayout.kt b/app/src/main/java/io/legado/app/ui/book/read/page/provider/TextChapterLayout.kt index dd2d50a2a..0edfa0eff 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/provider/TextChapterLayout.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/provider/TextChapterLayout.kt @@ -924,6 +924,10 @@ class TextChapterLayout( val charStyles = applyHighlightRules(text, isTitle) val widthsArray = allocateFloatArray(text.length) textPaint.getTextWidthsCompat(text, widthsArray) + // 用高亮规则字体重新测量字符宽度,确保排版和绘制使用同一套字体 + if (charStyles != null) { + remeasureWithHighlightFonts(text, charStyles, textPaint, widthsArray) + } val layout = if (useZhLayout) { val (words, widths) = measureTextSplit(text, widthsArray) val indentSize = if (isFirstLine) paragraphIndent.length else 0 @@ -1359,6 +1363,35 @@ class TextChapterLayout( return code == 8203 || code == 8204 || code == 8205 || code == 8288 } + /** + * 对有自定义字体的高亮字符重新测量宽度,确保排版和绘制使用同一套字体度量。 + */ + private fun remeasureWithHighlightFonts( + text: String, + charStyles: Array, + textPaint: TextPaint, + widthsArray: FloatArray + ) { + val originalTypeface = textPaint.typeface + var i = 0 + while (i < text.length) { + val fontPath = charStyles[i]?.fontPath.orEmpty() + if (fontPath.isEmpty()) { i++; continue } + // 找连续使用同一字体的区间 + val segStart = i + i++ + while (i < text.length && charStyles[i]?.fontPath.orEmpty() == fontPath) i++ + val segEnd = i + val typeface = TextColumn.getTypeface(fontPath) ?: continue + textPaint.typeface = typeface + val segment = text.substring(segStart, segEnd) + val segWidths = FloatArray(segEnd - segStart) + textPaint.getTextWidthsCompat(segment, segWidths) + segWidths.copyInto(widthsArray, segStart) + } + textPaint.typeface = originalTypeface + } + /** * 对文本应用高亮规则,返回每字符的样式数组。无匹配时返回 null。 */