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) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto target = static_cast<uint16_t>(cp);
|
||||
int left = 0;
|
||||
int right = static_cast<int>(count) - 1;
|
||||
while (left <= right) {
|
||||
const int mid = left + (right - left) / 2;
|
||||
const uint16_t midCp = entries[mid].codepoint;
|
||||
if (midCp == target) {
|
||||
return entries[mid].classId;
|
||||
}
|
||||
if (midCp < target) {
|
||||
left = mid + 1;
|
||||
} else {
|
||||
right = mid - 1;
|
||||
}
|
||||
const auto* end = entries + count;
|
||||
|
||||
// lower_bound: exact-key lookup. Finds the first entry with codepoint >= target,
|
||||
// then the equality check confirms an exact match exists.
|
||||
const auto it = std::lower_bound(
|
||||
entries, end, target, [](const EpdKernClassEntry& entry, uint16_t value) { return entry.codepoint < value; });
|
||||
|
||||
if (it != end && it->codepoint == target) {
|
||||
return it->classId;
|
||||
}
|
||||
|
||||
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;
|
||||
int left = 0;
|
||||
int right = static_cast<int>(count) - 1;
|
||||
const auto* end = pairs + count;
|
||||
|
||||
while (left <= right) {
|
||||
const int mid = left + (right - left) / 2;
|
||||
const uint32_t midKey = pairs[mid].pair;
|
||||
if (midKey == key) {
|
||||
return pairs[mid].ligatureCp;
|
||||
}
|
||||
if (midKey < key) {
|
||||
left = mid + 1;
|
||||
} else {
|
||||
right = mid - 1;
|
||||
}
|
||||
// lower_bound: exact-key lookup. Finds the first entry with pair >= key,
|
||||
// then the equality check confirms an exact match exists.
|
||||
const auto it =
|
||||
std::lower_bound(pairs, end, key, [](const EpdLigaturePair& pair, uint32_t value) { return pair.pair < value; });
|
||||
|
||||
if (it != end && it->pair == key) {
|
||||
return it->ligatureCp;
|
||||
}
|
||||
|
||||
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 EpdUnicodeInterval* intervals = data->intervals;
|
||||
const int count = data->intervalCount;
|
||||
|
||||
if (count == 0) return nullptr;
|
||||
|
||||
// Binary search for O(log n) lookup instead of O(n)
|
||||
// Critical for Korean fonts with many unicode intervals
|
||||
int left = 0;
|
||||
int right = count - 1;
|
||||
const EpdUnicodeInterval* intervals = data->intervals;
|
||||
const auto* end = intervals + count;
|
||||
|
||||
while (left <= right) {
|
||||
const int mid = left + (right - left) / 2;
|
||||
const EpdUnicodeInterval* interval = &intervals[mid];
|
||||
// upper_bound: range lookup. Finds the first interval with first > cp, so the
|
||||
// interval just before it is the last one with first <= cp. That's the only
|
||||
// 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) {
|
||||
right = mid - 1;
|
||||
} else if (cp > interval->last) {
|
||||
left = mid + 1;
|
||||
} else {
|
||||
// Found: cp >= interval->first && cp <= interval->last
|
||||
return &data->glyph[interval->offset + (cp - interval->first)];
|
||||
if (it != intervals) {
|
||||
const auto& interval = *(it - 1);
|
||||
if (cp <= interval.last) {
|
||||
return &data->glyph[interval.offset + (cp - interval.first)];
|
||||
}
|
||||
}
|
||||
|
||||
if (cp != REPLACEMENT_GLYPH) {
|
||||
return getGlyph(REPLACEMENT_GLYPH);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user