void commitRunBuffer()

in skiko/src/commonMain/cpp/common/include/TextLineRunHandler.hh [57:90]


    void commitRunBuffer(const RunInfo& info) override {
        TextLine::Run& run = fLine->fRuns.back();
        if (0 < info.glyphCount) {
            int32_t glyph = 0;
            int32_t graphemesInGlyph = 1;
            SkScalar glyphLeft = run.fPos[glyph].fX;
            run.fBreakOffsets.reserve(info.utf8Range.size() + 1);
            run.fBreakPositions.reserve(info.utf8Range.size() + 1);

            // Only record grapheme clusters boundaries
            for (int32_t offset = fGlyphOffsets[0]; offset <= info.utf8Range.end(); offset = ubrk_following(fGraphemeIter.get(), offset)) {
                run.fBreakOffsets.push_back(conv.from8To16(offset));

                // if grapheme clusters includes multiple glyphs, skip over them
                while (glyph < info.glyphCount && fGlyphOffsets[glyph] < offset)
                    ++glyph;

                // if one glyph includes multiple grapheme clusters (ligature, e.g. <->), accumulate
                if ((glyph < info.glyphCount ? fGlyphOffsets[glyph] : info.utf8Range.end()) > offset)
                    ++graphemesInGlyph;

                // when boundaries meet, distribute break positions evenly inside glyph
                else {
                    SkScalar glyphRight = glyph < info.glyphCount ? run.fPos[glyph].fX : fPosition + info.fAdvance.fX;
                    SkScalar step = (glyphRight - glyphLeft) / graphemesInGlyph;
                    for (int i = 0; i < graphemesInGlyph; ++i)
                        run.fBreakPositions.push_back(glyphLeft + step * (i + 1));
                    graphemesInGlyph = 1;
                    glyphLeft = glyphRight;
                }
            }
        }
        fPosition += info.fAdvance.fX;
    }