Further code review
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
#include <Utf8.h>
|
#include <Utf8.h>
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
FontDecompressor::~FontDecompressor() { deinit(); }
|
FontDecompressor::~FontDecompressor() { deinit(); }
|
||||||
|
|
||||||
@@ -263,12 +264,14 @@ int FontDecompressor::prewarmCache(const EpdFontData* fontData, const char* utf8
|
|||||||
// Step 2: Compute total buffer size and collect unique groups
|
// Step 2: Compute total buffer size and collect unique groups
|
||||||
uint32_t totalBytes = 0;
|
uint32_t totalBytes = 0;
|
||||||
uint16_t neededGroups[128];
|
uint16_t neededGroups[128];
|
||||||
|
uint16_t neededGlyphGroups[MAX_PAGE_GLYPHS]; // parallel to neededGlyphs; avoids re-calling getGroupIndex later
|
||||||
uint8_t groupCount = 0;
|
uint8_t groupCount = 0;
|
||||||
bool groupCapWarned = false;
|
bool groupCapWarned = false;
|
||||||
|
|
||||||
for (uint16_t i = 0; i < glyphCount; i++) {
|
for (uint16_t i = 0; i < glyphCount; i++) {
|
||||||
totalBytes += fontData->glyph[neededGlyphs[i]].dataLength;
|
totalBytes += fontData->glyph[neededGlyphs[i]].dataLength;
|
||||||
uint16_t gi = getGroupIndex(fontData, neededGlyphs[i]);
|
const uint16_t gi = getGroupIndex(fontData, neededGlyphs[i]);
|
||||||
|
neededGlyphGroups[i] = gi;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (uint8_t j = 0; j < groupCount; j++) {
|
for (uint8_t j = 0; j < groupCount; j++) {
|
||||||
if (neededGroups[j] == gi) {
|
if (neededGroups[j] == gi) {
|
||||||
@@ -319,7 +322,7 @@ int FontDecompressor::prewarmCache(const EpdFontData* fontData, const char* utf8
|
|||||||
|
|
||||||
// Initialize lookup entries (bufferOffset = UINT32_MAX means not yet extracted)
|
// Initialize lookup entries (bufferOffset = UINT32_MAX means not yet extracted)
|
||||||
for (uint16_t i = 0; i < glyphCount; i++) {
|
for (uint16_t i = 0; i < glyphCount; i++) {
|
||||||
slot.glyphs[i] = {neededGlyphs[i], UINT32_MAX, 0};
|
slot.glyphs[i] = {neededGlyphs[i], UINT32_MAX, 0, neededGlyphGroups[i]};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort by glyphIndex for binary search in getBitmap()
|
// Sort by glyphIndex for binary search in getBitmap()
|
||||||
@@ -338,21 +341,25 @@ int FontDecompressor::prewarmCache(const EpdFontData* fontData, const char* utf8
|
|||||||
uint32_t groupAlignedTracker[128] = {}; // running byte-aligned offset for each needed group
|
uint32_t groupAlignedTracker[128] = {}; // running byte-aligned offset for each needed group
|
||||||
|
|
||||||
if (fontData->glyphToGroup) {
|
if (fontData->glyphToGroup) {
|
||||||
// Frequency-grouped: single O(totalGlyphs) pass through glyphToGroup
|
// Frequency-grouped: single O(totalGlyphs) pass through glyphToGroup.
|
||||||
|
// Reverse map (fontGroupIdx → position in neededGroups) replaces the inner
|
||||||
|
// linear scan, dropping this pass from O(totalGlyphs × groupCount) to O(totalGlyphs).
|
||||||
|
uint8_t* groupIdToPos = static_cast<uint8_t*>(malloc(fontData->groupCount));
|
||||||
|
if (!groupIdToPos) {
|
||||||
|
LOG_ERR("FDC", "OOM: cannot allocate %u bytes for groupIdToPos map", fontData->groupCount);
|
||||||
|
freePageBuffer();
|
||||||
|
return glyphCount;
|
||||||
|
}
|
||||||
|
memset(groupIdToPos, 0xFF, fontData->groupCount);
|
||||||
|
for (uint8_t j = 0; j < groupCount; j++) groupIdToPos[neededGroups[j]] = j;
|
||||||
|
|
||||||
const auto& lastInterval = fontData->intervals[fontData->intervalCount - 1];
|
const auto& lastInterval = fontData->intervals[fontData->intervalCount - 1];
|
||||||
const uint32_t totalGlyphs = lastInterval.offset + (lastInterval.last - lastInterval.first + 1);
|
const uint32_t totalGlyphs = lastInterval.offset + (lastInterval.last - lastInterval.first + 1);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < totalGlyphs; i++) {
|
for (uint32_t i = 0; i < totalGlyphs; i++) {
|
||||||
const uint16_t gi = fontData->glyphToGroup[i];
|
const uint16_t gi = fontData->glyphToGroup[i];
|
||||||
// Find this glyph's group position in neededGroups
|
const uint8_t gpPos = groupIdToPos[gi];
|
||||||
uint8_t gpPos = groupCount;
|
if (gpPos == 0xFF) continue; // not a needed group
|
||||||
for (uint8_t j = 0; j < groupCount; j++) {
|
|
||||||
if (neededGroups[j] == gi) {
|
|
||||||
gpPos = j;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (gpPos == groupCount) continue; // not a needed group
|
|
||||||
|
|
||||||
const EpdGlyph& glyph = fontData->glyph[i];
|
const EpdGlyph& glyph = fontData->glyph[i];
|
||||||
|
|
||||||
@@ -374,6 +381,8 @@ int FontDecompressor::prewarmCache(const EpdFontData* fontData, const char* utf8
|
|||||||
groupAlignedTracker[gpPos] += ((glyph.width + 3) / 4) * glyph.height;
|
groupAlignedTracker[gpPos] += ((glyph.width + 3) / 4) * glyph.height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(groupIdToPos);
|
||||||
} else {
|
} else {
|
||||||
// Contiguous-group: iterate each needed group's glyphs directly
|
// Contiguous-group: iterate each needed group's glyphs directly
|
||||||
for (uint8_t g = 0; g < groupCount; g++) {
|
for (uint8_t g = 0; g < groupCount; g++) {
|
||||||
@@ -432,11 +441,10 @@ int FontDecompressor::prewarmCache(const EpdFontData* fontData, const char* utf8
|
|||||||
// alignedOffset was pre-computed in step 3b — no full-group compact scan needed.
|
// alignedOffset was pre-computed in step 3b — no full-group compact scan needed.
|
||||||
for (uint16_t i = 0; i < slot.glyphCount; i++) {
|
for (uint16_t i = 0; i < slot.glyphCount; i++) {
|
||||||
if (slot.glyphs[i].bufferOffset != UINT32_MAX) continue; // already extracted
|
if (slot.glyphs[i].bufferOffset != UINT32_MAX) continue; // already extracted
|
||||||
if (getGroupIndex(fontData, slot.glyphs[i].glyphIndex) != groupIdx) continue;
|
if (slot.glyphs[i].groupIndex != groupIdx) continue;
|
||||||
|
|
||||||
const EpdGlyph& glyph = fontData->glyph[slot.glyphs[i].glyphIndex];
|
const EpdGlyph& glyph = fontData->glyph[slot.glyphs[i].glyphIndex];
|
||||||
compactSingleGlyph(&groupBuf[slot.glyphs[i].alignedOffset], &slot.buffer[writeOffset], glyph.width,
|
compactSingleGlyph(&groupBuf[slot.glyphs[i].alignedOffset], &slot.buffer[writeOffset], glyph.width, glyph.height);
|
||||||
glyph.height);
|
|
||||||
slot.glyphs[i].bufferOffset = writeOffset;
|
slot.glyphs[i].bufferOffset = writeOffset;
|
||||||
writeOffset += glyph.dataLength;
|
writeOffset += glyph.dataLength;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ class FontDecompressor {
|
|||||||
uint32_t glyphIndex;
|
uint32_t glyphIndex;
|
||||||
uint32_t bufferOffset;
|
uint32_t bufferOffset;
|
||||||
uint32_t alignedOffset; // byte-aligned offset within its decompressed group (set during prewarm pre-scan)
|
uint32_t alignedOffset; // byte-aligned offset within its decompressed group (set during prewarm pre-scan)
|
||||||
|
uint16_t groupIndex; // cached to avoid re-calling getGroupIndex in prewarm Step 4
|
||||||
};
|
};
|
||||||
struct PageSlot {
|
struct PageSlot {
|
||||||
uint8_t* buffer = nullptr;
|
uint8_t* buffer = nullptr;
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ bool isClosingPunctuation(const uint32_t cp) {
|
|||||||
case 0x2019: // ' right single quotation mark
|
case 0x2019: // ' right single quotation mark
|
||||||
case 0x201D: // " right double quotation mark
|
case 0x201D: // " right double quotation mark
|
||||||
case 0x2026: // … ellipsis
|
case 0x2026: // … ellipsis
|
||||||
|
case 0x2013: // – en dash
|
||||||
|
case 0x2014: // — em dash
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user