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:
Zach Nelson
2026-03-01 10:28:15 -06:00
committed by GitHub
parent 80d1856330
commit 3cc8e272ca

View File

@@ -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);
} }