void HarfBuzzShaper::fillGlyphBufferFromHarfBuzzRun(GlyphBuffer* glyphBuffer, HarfBuzzRun* currentRun, FloatPoint& firstOffsetOfNextRun) { FloatPoint* offsets = currentRun->offsets(); uint16_t* glyphs = currentRun->glyphs(); float* advances = currentRun->advances(); unsigned numGlyphs = currentRun->numGlyphs(); uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes(); for (unsigned i = 0; i < numGlyphs; ++i) { uint16_t currentCharacterIndex = currentRun->startIndex() + glyphToCharacterIndexes[i]; FloatPoint& currentOffset = offsets[i]; FloatPoint& nextOffset = (i == numGlyphs - 1) ? firstOffsetOfNextRun : offsets[i + 1]; float glyphAdvanceX = advances[i] + nextOffset.x() - currentOffset.x(); float glyphAdvanceY = nextOffset.y() - currentOffset.y(); if (m_run.rtl()) { if (currentCharacterIndex > m_toIndex) m_startOffset.move(glyphAdvanceX, glyphAdvanceY); else if (currentCharacterIndex >= m_fromIndex) glyphBuffer->add(glyphs[i], currentRun->fontData(), createGlyphBufferAdvance(glyphAdvanceX, glyphAdvanceY)); } else { if (currentCharacterIndex < m_fromIndex) m_startOffset.move(glyphAdvanceX, glyphAdvanceY); else if (currentCharacterIndex < m_toIndex) glyphBuffer->add(glyphs[i], currentRun->fontData(), createGlyphBufferAdvance(glyphAdvanceX, glyphAdvanceY)); } } }
void HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun(GlyphBuffer* glyphBuffer) { hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(m_harfbuzzBuffer, 0); hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(m_harfbuzzBuffer, 0); HarfBuzzRun* currentRun = m_harfbuzzRuns.last().get(); unsigned numGlyphs = currentRun->numGlyphs(); float totalAdvance = 0; float nextOffsetX = harfbuzzPositionToFloat(glyphPositions[0].x_offset); float nextOffsetY = -harfbuzzPositionToFloat(glyphPositions[0].y_offset); // HarfBuzz returns the shaping result in visual order. We need not to flip them for RTL. for (size_t i = 0; i < numGlyphs; ++i) { bool runEnd = i + 1 == numGlyphs; uint16_t glyph = glyphInfos[i].codepoint; float offsetX = nextOffsetX; float offsetY = nextOffsetY; float advance = harfbuzzPositionToFloat(glyphPositions[i].x_advance); nextOffsetX = runEnd ? 0 : harfbuzzPositionToFloat(glyphPositions[i + 1].x_offset); nextOffsetY = runEnd ? 0 : -harfbuzzPositionToFloat(glyphPositions[i + 1].y_offset); unsigned currentCharacterIndex = m_startIndexOfCurrentRun + glyphInfos[i].cluster; bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1].cluster; float spacing = isClusterEnd ? m_letterSpacing : 0; if (isClusterEnd && isWordEnd(currentCharacterIndex)) spacing += determineWordBreakSpacing(); if (m_currentFontData->isZeroWidthSpaceGlyph(glyph)) { currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0); if (glyphBuffer) glyphBuffer->add(glyph, m_currentFontData, createGlyphBufferAdvance(0, 0)); continue; } advance += spacing; currentRun->setGlyphAndPositions(i, glyph, totalAdvance + offsetX, offsetY, advance); if (glyphBuffer) { float glyphAdvanceX = advance + nextOffsetX - offsetX; float glyphAdvanceY = nextOffsetY - offsetY; glyphBuffer->add(glyph, m_currentFontData, createGlyphBufferAdvance(glyphAdvanceX, glyphAdvanceY)); } totalAdvance += advance; } currentRun->setWidth(totalAdvance > 0.0 ? totalAdvance : 0.0); m_totalWidth += currentRun->width(); }