Given a sorted array of unique codepoints, resolve glyph indices per style, batch-read advanceX from SD, and merge into the persistent advance table. Caller owns the codepoints buffer.
| 1093 | // batch-read advanceX from SD, and merge into the persistent advance table. |
| 1094 | // Caller owns the codepoints buffer. |
| 1095 | int SdCardFont::fetchAdvancesForCodepoints(uint32_t* codepoints, uint32_t cpCount, uint8_t styleMask) { |
| 1096 | int totalMissed = 0; |
| 1097 | for (uint8_t si = 0; si < MAX_STYLES; si++) { |
| 1098 | if (!(styleMask & (1 << si)) || !styles_[si].present) continue; |
| 1099 | const auto& s = styles_[si]; |
| 1100 | |
| 1101 | // Stop fetching once the cache is full — further inserts would be dropped |
| 1102 | // by the merge anyway. The renderer fast path tolerates missing entries |
| 1103 | // (returns 0); the slow path is still correct for those codepoints. |
| 1104 | if (advanceTableSize_[si] >= ADVANCE_CACHE_LIMIT) continue; |
| 1105 | |
| 1106 | // For each codepoint in `codepoints`, skip those already cached, then |
| 1107 | // resolve to a glyph index. Build a parallel array sorted by glyph index |
| 1108 | // for sequential SD reads. |
| 1109 | struct CpIdx { |
| 1110 | uint32_t codepoint; |
| 1111 | int32_t glyphIndex; |
| 1112 | }; |
| 1113 | std::unique_ptr<CpIdx[]> mappings(new (std::nothrow) CpIdx[cpCount]); |
| 1114 | if (!mappings) { |
| 1115 | LOG_ERR("SDCF", "buildAdvanceTable: failed to allocate mappings for style %u", si); |
| 1116 | totalMissed += cpCount; |
| 1117 | continue; |
| 1118 | } |
| 1119 | |
| 1120 | uint32_t needCount = 0; |
| 1121 | uint32_t missedThisStyle = 0; |
| 1122 | const int32_t replacementIdx = findGlobalGlyphIndex(s, REPLACEMENT_GLYPH); |
| 1123 | for (uint32_t i = 0; i < cpCount; i++) { |
| 1124 | const uint32_t cp = codepoints[i]; |
| 1125 | if (advanceTableLookup(si, cp, nullptr)) continue; // already cached |
| 1126 | int32_t idx = findGlobalGlyphIndex(s, cp); |
| 1127 | if (idx < 0) { |
| 1128 | if (replacementIdx < 0) { |
| 1129 | missedThisStyle++; |
| 1130 | continue; |
| 1131 | } |
| 1132 | idx = replacementIdx; |
| 1133 | } |
| 1134 | mappings[needCount].codepoint = cp; |
| 1135 | mappings[needCount].glyphIndex = idx; |
| 1136 | needCount++; |
| 1137 | } |
| 1138 | totalMissed += static_cast<int>(missedThisStyle); |
| 1139 | |
| 1140 | if (needCount == 0) continue; |
| 1141 | |
| 1142 | // Sort by glyph index so SD reads are mostly sequential. |
| 1143 | std::sort(mappings.get(), mappings.get() + needCount, |
| 1144 | [](const CpIdx& a, const CpIdx& b) { return a.glyphIndex < b.glyphIndex; }); |
| 1145 | |
| 1146 | // Open file once and read advanceX for each needed glyph. |
| 1147 | HalFile file; |
| 1148 | if (!Storage.openFileForRead("SDCF", filePath_, file)) { |
| 1149 | LOG_ERR("SDCF", "buildAdvanceTable: failed to open .cpfont for style %u", si); |
| 1150 | continue; |
| 1151 | } |
| 1152 |
nothing calls this directly
no test coverage detected