refactor: Use std binary search algorithms for font lookups (#1202)
## Summary **What is the goal of this PR?** Rewrite of font routines to use std binary search algorithms instead of custom repeated implementations: `lookupKernClass`, `EpdFont::getLigature`, and `EpdFont::getGlyph`. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**NO**_
This commit is contained in:
@@ -80,21 +80,19 @@ static uint8_t lookupKernClass(const EpdKernClassEntry* entries, const uint16_t
|
|||||||
if (!entries || count == 0 || cp > 0xFFFF) {
|
if (!entries || count == 0 || cp > 0xFFFF) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto target = static_cast<uint16_t>(cp);
|
const auto target = static_cast<uint16_t>(cp);
|
||||||
int left = 0;
|
const auto* end = entries + count;
|
||||||
int right = static_cast<int>(count) - 1;
|
|
||||||
while (left <= right) {
|
// lower_bound: exact-key lookup. Finds the first entry with codepoint >= target,
|
||||||
const int mid = left + (right - left) / 2;
|
// then the equality check confirms an exact match exists.
|
||||||
const uint16_t midCp = entries[mid].codepoint;
|
const auto it = std::lower_bound(
|
||||||
if (midCp == target) {
|
entries, end, target, [](const EpdKernClassEntry& entry, uint16_t value) { return entry.codepoint < value; });
|
||||||
return entries[mid].classId;
|
|
||||||
}
|
if (it != end && it->codepoint == target) {
|
||||||
if (midCp < target) {
|
return it->classId;
|
||||||
left = mid + 1;
|
|
||||||
} else {
|
|
||||||
right = mid - 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,21 +115,17 @@ uint32_t EpdFont::getLigature(const uint32_t leftCp, const uint32_t rightCp) con
|
|||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t key = (leftCp << 16) | rightCp;
|
const uint32_t key = (leftCp << 16) | rightCp;
|
||||||
int left = 0;
|
const auto* end = pairs + count;
|
||||||
int right = static_cast<int>(count) - 1;
|
|
||||||
|
|
||||||
while (left <= right) {
|
// lower_bound: exact-key lookup. Finds the first entry with pair >= key,
|
||||||
const int mid = left + (right - left) / 2;
|
// then the equality check confirms an exact match exists.
|
||||||
const uint32_t midKey = pairs[mid].pair;
|
const auto it =
|
||||||
if (midKey == key) {
|
std::lower_bound(pairs, end, key, [](const EpdLigaturePair& pair, uint32_t value) { return pair.pair < value; });
|
||||||
return pairs[mid].ligatureCp;
|
|
||||||
}
|
if (it != end && it->pair == key) {
|
||||||
if (midKey < key) {
|
return it->ligatureCp;
|
||||||
left = mid + 1;
|
|
||||||
} else {
|
|
||||||
right = mid - 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,29 +148,25 @@ uint32_t EpdFont::applyLigatures(uint32_t cp, const char*& text) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const EpdGlyph* EpdFont::getGlyph(const uint32_t cp) const {
|
const EpdGlyph* EpdFont::getGlyph(const uint32_t cp) const {
|
||||||
const EpdUnicodeInterval* intervals = data->intervals;
|
|
||||||
const int count = data->intervalCount;
|
const int count = data->intervalCount;
|
||||||
|
|
||||||
if (count == 0) return nullptr;
|
if (count == 0) return nullptr;
|
||||||
|
|
||||||
// Binary search for O(log n) lookup instead of O(n)
|
const EpdUnicodeInterval* intervals = data->intervals;
|
||||||
// Critical for Korean fonts with many unicode intervals
|
const auto* end = intervals + count;
|
||||||
int left = 0;
|
|
||||||
int right = count - 1;
|
|
||||||
|
|
||||||
while (left <= right) {
|
// upper_bound: range lookup. Finds the first interval with first > cp, so the
|
||||||
const int mid = left + (right - left) / 2;
|
// interval just before it is the last one with first <= cp. That's the only
|
||||||
const EpdUnicodeInterval* interval = &intervals[mid];
|
// candidate that could contain cp. Then we verify cp <= candidate.last.
|
||||||
|
const auto it = std::upper_bound(
|
||||||
|
intervals, end, cp, [](uint32_t value, const EpdUnicodeInterval& interval) { return value < interval.first; });
|
||||||
|
|
||||||
if (cp < interval->first) {
|
if (it != intervals) {
|
||||||
right = mid - 1;
|
const auto& interval = *(it - 1);
|
||||||
} else if (cp > interval->last) {
|
if (cp <= interval.last) {
|
||||||
left = mid + 1;
|
return &data->glyph[interval.offset + (cp - interval.first)];
|
||||||
} else {
|
|
||||||
// Found: cp >= interval->first && cp <= interval->last
|
|
||||||
return &data->glyph[interval->offset + (cp - interval->first)];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cp != REPLACEMENT_GLYPH) {
|
if (cp != REPLACEMENT_GLYPH) {
|
||||||
return getGlyph(REPLACEMENT_GLYPH);
|
return getGlyph(REPLACEMENT_GLYPH);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user