Compare commits

...

7 Commits

Author SHA1 Message Date
dependabot[bot]
f132e92772
Merge d1af37e04b into 576a370da1 2024-06-20 11:39:05 +08:00
Antecer
576a370da1 优化复合字体轮廓数据结构 2024-06-20 10:57:02 +08:00
Antecer
d6c2b5eceb 替换轮廓数据时忽略索引0 2024-06-20 10:54:29 +08:00
Antecer
da7093214f 修复format4字形索引gIndex参数计算错误的BUG 2024-06-19 19:00:47 +08:00
Antecer
dc9ce168c1 修复TTF字体loca表识别错误的bug 2024-06-18 17:07:01 +08:00
Horis
0337e465de 优化 2024-06-14 12:12:08 +08:00
dependabot[bot]
d1af37e04b
Bump activity from 1.8.2 to 1.9.0
Bumps `activity` from 1.8.2 to 1.9.0.

Updates `androidx.activity:activity` from 1.8.2 to 1.9.0

Updates `androidx.activity:activity-compose` from 1.8.2 to 1.9.0

Updates `androidx.activity:activity-ktx` from 1.8.2 to 1.9.0

---
updated-dependencies:
- dependency-name: androidx.activity:activity
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: androidx.activity:activity-compose
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: androidx.activity:activity-ktx
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-06 04:22:02 +00:00
8 changed files with 36 additions and 26 deletions

View File

@ -802,8 +802,9 @@ interface JsExtensions : JsEncodeUtils {
if (errorQueryTTF.isBlankUnicode(oldCode)) { if (errorQueryTTF.isBlankUnicode(oldCode)) {
return@forEachIndexed return@forEachIndexed
} }
val glyf = errorQueryTTF.getGlyfByUnicode(oldCode)
// 删除轮廓数据不存在的字符 // 删除轮廓数据不存在的字符
var glyf = errorQueryTTF.getGlyfByUnicode(oldCode) // 轮廓数据不存在
if (errorQueryTTF.getGlyfIdByUnicode(oldCode) == 0) glyf = null; // 轮廓数据指向保留索引0
if (filter && (glyf == null)) { if (filter && (glyf == null)) {
contentArray[index] = "" contentArray[index] = ""
return@forEachIndexed return@forEachIndexed

View File

@ -188,7 +188,6 @@ class ContentProcessor private constructor(
mContent = mContent.replace('\u00A0', ' ') mContent = mContent.replace('\u00A0', ' ')
} }
val contents = arrayListOf<String>() val contents = arrayListOf<String>()
val paragraphIndent = ReadBookConfig.paragraphIndent
mContent.split("\n").forEach { str -> mContent.split("\n").forEach { str ->
val paragraph = str.trim { val paragraph = str.trim {
it.code <= 0x20 || it == ' ' it.code <= 0x20 || it == ' '
@ -197,14 +196,10 @@ class ContentProcessor private constructor(
if (contents.isEmpty() && includeTitle) { if (contents.isEmpty() && includeTitle) {
contents.add(paragraph) contents.add(paragraph)
} else { } else {
contents.add("$paragraphIndent$paragraph") contents.add("${ReadBookConfig.paragraphIndent}$paragraph")
} }
} }
} }
if (contents.isEmpty()) {
contents.add("${paragraphIndent}加载正文失败")
contents.add("${paragraphIndent}内容处理后为空")
}
return BookContent(sameTitleRemoved, contents, effectiveReplaceRules) return BookContent(sameTitleRemoved, contents, effectiveReplaceRules)
} }

View File

@ -648,6 +648,8 @@ public class QueryTTF {
var reader = new BufferReader(buffer, dataTable.offset); var reader = new BufferReader(buffer, dataTable.offset);
if (head.indexToLocFormat == 0) { if (head.indexToLocFormat == 0) {
loca = reader.ReadUInt16Array(dataTable.length / 2); loca = reader.ReadUInt16Array(dataTable.length / 2);
// 当loca表数据长度为Uint16时,需要翻倍
for (var i = 0; i < loca.length; i++) loca[i] *= 2;
} else { } else {
loca = reader.ReadInt32Array(dataTable.length / 4); loca = reader.ReadInt32Array(dataTable.length / 4);
} }
@ -712,7 +714,7 @@ public class QueryTTF {
if (idRangeOffset == 0) { if (idRangeOffset == 0) {
unicodeToGlyphId.put(unicode, (unicode + idDelta) & 0xFFFF); unicodeToGlyphId.put(unicode, (unicode + idDelta) & 0xFFFF);
} else { } else {
int gIndex = (idRangeOffset / 2) + unicode - unicodeInclusive + segmentIndex; int gIndex = (idRangeOffset / 2) + unicode - unicodeInclusive + segmentIndex - segCount;
unicodeToGlyphId.put(unicode, gIndex < glyphIdArrayLength ? f.glyphIdArray[gIndex] + idDelta : 0); unicodeToGlyphId.put(unicode, gIndex < glyphIdArrayLength ? f.glyphIdArray[gIndex] + idDelta : 0);
} }
} }
@ -771,21 +773,24 @@ public class QueryTTF {
var dataTable = directorys.get("glyf"); var dataTable = directorys.get("glyf");
assert dataTable != null; assert dataTable != null;
int glyfCount = maxp.numGlyphs; int glyfCount = maxp.numGlyphs;
glyfArray = new GlyfLayout[glyfCount + 1]; // 创建容器多创建一个作为保留区 glyfArray = new GlyfLayout[glyfCount]; // 创建字形容器
var reader = new BufferReader(buffer, 0); var reader = new BufferReader(buffer, 0);
for (int index = 1; index <= glyfCount; index++) { for (int index = 0; index < glyfCount; index++) {
if (loca[index - 1] == loca[index]) continue; // 当前loca与下一个loca相同表示这个字形不存在 if (loca[index] == loca[index + 1]) continue; // 当前loca与下一个loca相同表示这个字形不存在
int offset = dataTable.offset + loca[index - 1]; int offset = dataTable.offset + loca[index];
// 读GlyphHeaders // 读GlyphHeaders
var glyph = new GlyfLayout(); var glyph = new GlyfLayout();
reader.position(offset); reader.position(offset);
glyph.numberOfContours = reader.ReadInt16(); glyph.numberOfContours = reader.ReadInt16();
if (glyph.numberOfContours > maxp.maxContours) continue; // 如果字形轮廓数大于非复合字形中包含的最大轮廓数则说明该字形无效
glyph.xMin = reader.ReadInt16(); glyph.xMin = reader.ReadInt16();
glyph.yMin = reader.ReadInt16(); glyph.yMin = reader.ReadInt16();
glyph.xMax = reader.ReadInt16(); glyph.xMax = reader.ReadInt16();
glyph.yMax = reader.ReadInt16(); glyph.yMax = reader.ReadInt16();
// 轮廓数为0时不需要解析轮廓数据
if (glyph.numberOfContours == 0) continue;
// 读Glyph轮廓数据 // 读Glyph轮廓数据
if (glyph.numberOfContours > 0) { if (glyph.numberOfContours > 0) {
// 简单轮廓 // 简单轮廓
@ -888,7 +893,7 @@ public class QueryTTF {
if ((glyphTableComponent.flags & 0x20) == 0) break; if ((glyphTableComponent.flags & 0x20) == 0) break;
} }
} }
glyfArray[index] = glyph; // 根据文档 glyfId=0 作为保留区使用这里赋值从索引1开始 glyfArray[index] = glyph;
} }
} }
@ -914,7 +919,15 @@ public class QueryTTF {
// 复合字形 // 复合字形
LinkedList<String> glyphIdList = new LinkedList<>(); LinkedList<String> glyphIdList = new LinkedList<>();
for (var g : glyph.glyphComponent) { for (var g : glyph.glyphComponent) {
glyphIdList.add(String.valueOf(g.glyphIndex)); glyphIdList.add("{" +
"flags:" + g.flags + "," +
"glyphIndex:" + g.glyphIndex + "," +
"arg1:" + g.argument1 + "," +
"arg2:" + g.argument2 + "," +
"xScale:" + g.xScale + "," +
"scale01:" + g.scale01 + "," +
"scale10:" + g.scale10 + "," +
"yScale:" + g.yScale + "}");
} }
glyphString = "[" + String.join(",", glyphIdList) + "]"; glyphString = "[" + String.join(",", glyphIdList) + "]";
} }
@ -960,10 +973,11 @@ public class QueryTTF {
int glyfArrayLength = glyfArray.length; int glyfArrayLength = glyfArray.length;
for (var item : unicodeToGlyphId.entrySet()) { for (var item : unicodeToGlyphId.entrySet()) {
int key = item.getKey(); int key = item.getKey();
int val = item.getValue() + 1; // glyphArray已根据TTF文档将索引0作为保留位这里从1开始索引 int val = item.getValue();
if (val >= glyfArrayLength) continue; if (val >= glyfArrayLength) continue;
String glyfString = getGlyfById(val); String glyfString = getGlyfById(val);
unicodeToGlyph.put(key, glyfString); unicodeToGlyph.put(key, glyfString);
if (glyfString == null) continue; // null 不能用作hashmap的key
glyphToUnicode.put(glyfString, key); glyphToUnicode.put(glyfString, key);
} }
// Log.i("QueryTTF", "字体处理完成"); // Log.i("QueryTTF", "字体处理完成");
@ -981,8 +995,8 @@ public class QueryTTF {
*/ */
public int getGlyfIdByUnicode(int unicode) { public int getGlyfIdByUnicode(int unicode) {
var result = unicodeToGlyphId.get(unicode); var result = unicodeToGlyphId.get(unicode);
if (result == null) return 0; if (result == null) return 0; // 如果找不到Unicode对应的轮廓索引就返回默认值0
return result + 1; // 根据TTF文档轮廓索引的定义从1开始 return result;
} }
/** /**
@ -1003,7 +1017,7 @@ public class QueryTTF {
*/ */
public int getUnicodeByGlyf(String glyph) { public int getUnicodeByGlyf(String glyph) {
var result = glyphToUnicode.get(glyph); var result = glyphToUnicode.get(glyph);
if (result == null) return 0; if (result == null) return 0; // 如果轮廓数据找不到对应的Unicode就返回默认值0
return result; return result;
} }

View File

@ -218,7 +218,7 @@ abstract class BaseReadAloudService : BaseService(),
} }
nowSpeak = textChapter.getParagraphNum(readAloudNumber + 1, readAloudByPage) - 1 nowSpeak = textChapter.getParagraphNum(readAloudNumber + 1, readAloudByPage) - 1
if (!readAloudByPage && startPos == 0 && !toLast) { if (!readAloudByPage && startPos == 0 && !toLast) {
pos = page.lines.first().chapterPosition - pos = page.chapterPosition -
textChapter.paragraphs[nowSpeak].chapterPosition textChapter.paragraphs[nowSpeak].chapterPosition
} }
if (toLast) { if (toLast) {
@ -226,7 +226,7 @@ abstract class BaseReadAloudService : BaseService(),
readAloudNumber = textChapter.getLastParagraphPosition() readAloudNumber = textChapter.getLastParagraphPosition()
nowSpeak = contentList.lastIndex nowSpeak = contentList.lastIndex
if (page.paragraphs.size == 1) { if (page.paragraphs.size == 1) {
pos = page.lines.first().chapterPosition - pos = page.chapterPosition -
textChapter.paragraphs[nowSpeak].chapterPosition textChapter.paragraphs[nowSpeak].chapterPosition
} }
} }

View File

@ -112,7 +112,7 @@ data class TextChapter(
*/ */
fun getReadLength(pageIndex: Int): Int { fun getReadLength(pageIndex: Int): Int {
if (pageIndex < 0) return 0 if (pageIndex < 0) return 0
return pages[min(pageIndex, lastIndex)].lines.first().chapterPosition return pages[min(pageIndex, lastIndex)].chapterPosition
/* /*
var length = 0 var length = 0
val maxIndex = min(pageIndex, pages.size) val maxIndex = min(pageIndex, pages.size)
@ -224,14 +224,13 @@ data class TextChapter(
return -1 return -1
} }
val bIndex = pages.fastBinarySearchBy(charIndex, 0, pageSize) { val bIndex = pages.fastBinarySearchBy(charIndex, 0, pageSize) {
it.lines.first().chapterPosition it.chapterPosition
} }
val index = abs(bIndex + 1) - 1 val index = abs(bIndex + 1) - 1
// 判断是否已经排版到 charIndex ,没有则返回 -1 // 判断是否已经排版到 charIndex ,没有则返回 -1
if (!isCompleted && index == pageSize - 1) { if (!isCompleted && index == pageSize - 1) {
val page = pages[index] val page = pages[index]
val line = page.lines.first() val pageEndPos = page.chapterPosition + page.charSize
val pageEndPos = line.chapterPosition + page.charSize
if (charIndex > pageEndPos) { if (charIndex > pageEndPos) {
return -1 return -1
} }

View File

@ -45,6 +45,7 @@ data class TextPage(
val lines: List<TextLine> get() = textLines val lines: List<TextLine> get() = textLines
val lineSize: Int get() = textLines.size val lineSize: Int get() = textLines.size
val charSize: Int get() = text.length.coerceAtLeast(1) val charSize: Int get() = text.length.coerceAtLeast(1)
val chapterPosition: Int get() = textLines.first().chapterPosition
val searchResult = hashSetOf<TextColumn>() val searchResult = hashSetOf<TextColumn>()
var isMsgPage: Boolean = false var isMsgPage: Boolean = false
var canvasRecorder = CanvasRecorderFactory.create(true) var canvasRecorder = CanvasRecorderFactory.create(true)

View File

@ -177,7 +177,7 @@ class TextChapterLayout(
val contents = bookContent.textList val contents = bookContent.textList
var absStartX = paddingLeft var absStartX = paddingLeft
var durY = 0f var durY = 0f
if (ReadBookConfig.titleMode != 2 || bookChapter.isVolume) { if (ReadBookConfig.titleMode != 2 || bookChapter.isVolume || contents.isEmpty()) {
//标题非隐藏 //标题非隐藏
displayTitle.splitNotBlank("\n").forEach { text -> displayTitle.splitNotBlank("\n").forEach { text ->
setTypeText( setTypeText(

View File

@ -38,7 +38,7 @@ quickChineseTransfer = "0.2.13"
room = "2.6.1" room = "2.6.1"
splitties = "3.0.0" splitties = "3.0.0"
activity = "1.8.2" activity = "1.9.0"
kotlinxSerialization = "1.6.3" kotlinxSerialization = "1.6.3"
swiperefreshlayout = "1.1.0" swiperefreshlayout = "1.1.0"
viewpager2 = "1.0.0" viewpager2 = "1.0.0"