void HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun(HarfBuzzRun* currentRun, hb_buffer_t* harfBuzzBuffer) { const SimpleFontData* currentFontData = currentRun->fontData(); hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(harfBuzzBuffer, 0); hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(harfBuzzBuffer, 0); unsigned numGlyphs = currentRun->numGlyphs(); uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes(); float totalAdvance = 0; // HarfBuzz returns the shaping result in visual order. We need not to flip for RTL. for (size_t i = 0; i < numGlyphs; ++i) { bool runEnd = i + 1 == numGlyphs; uint16_t glyph = glyphInfos[i].codepoint; float offsetX = harfBuzzPositionToFloat(glyphPositions[i].x_offset); float offsetY = -harfBuzzPositionToFloat(glyphPositions[i].y_offset); float advance = harfBuzzPositionToFloat(glyphPositions[i].x_advance); unsigned currentCharacterIndex = currentRun->startIndex() + glyphInfos[i].cluster; bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1].cluster; float spacing = 0; glyphToCharacterIndexes[i] = glyphInfos[i].cluster; if (isClusterEnd && !Font::treatAsZeroWidthSpace(m_normalizedBuffer[currentCharacterIndex])) spacing += m_letterSpacing; if (isClusterEnd && isWordEnd(currentCharacterIndex)) spacing += determineWordBreakSpacing(); if (currentFontData->isZeroWidthSpaceGlyph(glyph)) { currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0); continue; } advance += spacing; if (m_run.rtl()) { // In RTL, spacing should be added to left side of glyphs. offsetX += spacing; if (!isClusterEnd) offsetX += m_letterSpacing; } currentRun->setGlyphAndPositions(i, glyph, advance, offsetX, offsetY); totalAdvance += advance; } currentRun->setWidth(totalAdvance > 0.0 ? totalAdvance : 0.0); m_totalWidth += currentRun->width(); }
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(); }
void ComplexTextController::setGlyphPositions(bool isRTL) { const double rtlFlip = isRTL ? -1 : 1; double position = 0; // logClustersIndex indexes logClusters for the first codepoint of the current glyph. // Each time we advance a glyph, we skip over all the codepoints that contributed to the current glyph. int logClustersIndex = 0; // Iterate through the glyphs in logical order, flipping for RTL where necessary. // Glyphs are positioned starting from m_offsetX; in RTL mode they go leftwards from there. for (size_t i = 0; i < m_item.num_glyphs; ++i) { while (static_cast<unsigned>(logClustersIndex) < m_item.item.length && m_item.log_clusters[logClustersIndex] < i) logClustersIndex++; // If the current glyph is just after a space, add in the word spacing. position += determineWordBreakSpacing(logClustersIndex); m_glyphs16[i] = m_item.glyphs[i]; double offsetX = truncateFixedPointToInteger(m_item.offsets[i].x); double offsetY = truncateFixedPointToInteger(m_item.offsets[i].y); double advance = truncateFixedPointToInteger(m_item.advances[i]); if (isRTL) offsetX -= advance; m_positions[i].set(m_offsetX + (position * rtlFlip) + offsetX, m_startingY + offsetY); if (m_currentFontData->isZeroWidthSpaceGlyph(m_glyphs16[i])) continue; // At the end of each cluster, add in the letter spacing. if (i + 1 == m_item.num_glyphs || m_item.attributes[i + 1].clusterStart) position += m_letterSpacing; position += advance; } m_pixelWidth = std::max(position, 0.0); m_offsetX += m_pixelWidth * rtlFlip; }