float getAdvance(const float* advances, const char* src) { const size_t BUF_SIZE = 256; uint16_t buf[BUF_SIZE]; size_t offset; size_t size; ParseUnicode(buf, BUF_SIZE, src, &size, &offset); return getRunAdvance(advances, buf, 0, size, offset); }
/** * Essentially the inverse of getRunAdvance. Compute the value of offset for which the * measured caret comes closest to the provided advance param, and which is on a grapheme * cluster boundary. * * The actual implementation fast-forwards through clusters to get "close", then does a finer-grain * search within the cluster and grapheme breaks. */ size_t getOffsetForAdvance(const float* advances, const uint16_t* buf, size_t start, size_t count, float advance) { float x = 0.0f, xLastClusterStart = 0.0f, xSearchStart = 0.0f; size_t lastClusterStart = start, searchStart = start; for (size_t i = start; i < start + count; i++) { if (GraphemeBreak::isGraphemeBreak(advances, buf, start, count, i)) { searchStart = lastClusterStart; xSearchStart = xLastClusterStart; } float width = advances[i - start]; if (width != 0.0f) { lastClusterStart = i; xLastClusterStart = x; x += width; if (x > advance) { break; } } } size_t best = searchStart; float bestDist = FLT_MAX; for (size_t i = searchStart; i <= start + count; i++) { if (GraphemeBreak::isGraphemeBreak(advances, buf, start, count, i)) { // "getRunAdvance(layout, buf, start, count, i) - advance" but more efficient float delta = getRunAdvance(advances, buf, start, searchStart, count - searchStart, i) + xSearchStart - advance; if (std::abs(delta) < bestDist) { bestDist = std::abs(delta); best = i; } if (delta >= 0.0f) { break; } } } return best; }
float getRunAdvance(const float* advances, const uint16_t* buf, size_t start, size_t count, size_t offset) { return getRunAdvance(advances, buf, start, start, count, offset); }