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(); }
// TODO crbug.com/542701: This should be a method on ShapeResult. void HarfBuzzShaper::insertRunIntoShapeResult(ShapeResult* result, PassOwnPtr<ShapeResult::RunInfo> runToInsert, unsigned startGlyph, unsigned numGlyphs, hb_buffer_t* harfBuzzBuffer) { ASSERT(numGlyphs > 0); OwnPtr<ShapeResult::RunInfo> run(std::move(runToInsert)); ASSERT(numGlyphs == run->m_glyphData.size()); const SimpleFontData* currentFontData = run->m_fontData.get(); const hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(harfBuzzBuffer, 0); const hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(harfBuzzBuffer, 0); const unsigned startCluster = HB_DIRECTION_IS_FORWARD(hb_buffer_get_direction(harfBuzzBuffer)) ? glyphInfos[startGlyph].cluster : glyphInfos[startGlyph + numGlyphs - 1].cluster; float totalAdvance = 0.0f; FloatPoint glyphOrigin; bool hasVerticalOffsets = !HB_DIRECTION_IS_HORIZONTAL(run->m_direction); // HarfBuzz returns result in visual order, no need to flip for RTL. for (unsigned i = 0; i < numGlyphs; ++i) { uint16_t glyph = glyphInfos[startGlyph + i].codepoint; float offsetX = harfBuzzPositionToFloat(glyphPositions[startGlyph + i].x_offset); float offsetY = -harfBuzzPositionToFloat(glyphPositions[startGlyph + i].y_offset); // One out of x_advance and y_advance is zero, depending on // whether the buffer direction is horizontal or vertical. float advance = harfBuzzPositionToFloat(glyphPositions[startGlyph + i].x_advance - glyphPositions[startGlyph + i].y_advance); RELEASE_ASSERT(m_normalizedBufferLength > glyphInfos[startGlyph + i].cluster); // The characterIndex of one ShapeResult run is normalized to the run's // startIndex and length. TODO crbug.com/542703: Consider changing that // and instead pass the whole run to hb_buffer_t each time. run->m_glyphData[i].characterIndex = glyphInfos[startGlyph + i].cluster - startCluster; run->setGlyphAndPositions(i, glyph, advance, offsetX, offsetY); totalAdvance += advance; hasVerticalOffsets |= (offsetY != 0); FloatRect glyphBounds = currentFontData->boundsForGlyph(glyph); glyphBounds.move(glyphOrigin.x(), glyphOrigin.y()); result->m_glyphBoundingBox.unite(glyphBounds); glyphOrigin += FloatSize(advance + offsetX, offsetY); } run->m_width = std::max(0.0f, totalAdvance); result->m_width += run->m_width; result->m_numGlyphs += numGlyphs; ASSERT(result->m_numGlyphs >= numGlyphs); // no overflow result->m_hasVerticalOffsets |= hasVerticalOffsets; // The runs are stored in result->m_runs in visual order. For LTR, we place // the run to be inserted before the next run with a bigger character // start index. For RTL, we place the run before the next run with a lower // character index. Otherwise, for both directions, at the end. if (HB_DIRECTION_IS_FORWARD(run->m_direction)) { for (size_t pos = 0; pos < result->m_runs.size(); ++pos) { if (result->m_runs.at(pos)->m_startIndex > run->m_startIndex) { result->m_runs.insert(pos, run.release()); break; } } } else { for (size_t pos = 0; pos < result->m_runs.size(); ++pos) { if (result->m_runs.at(pos)->m_startIndex < run->m_startIndex) { result->m_runs.insert(pos, run.release()); break; } } } // If we didn't find an existing slot to place it, append. if (run) { result->m_runs.append(run.release()); } }
void ShapeResult::insertRun(std::unique_ptr<ShapeResult::RunInfo> runToInsert, unsigned startGlyph, unsigned numGlyphs, hb_buffer_t* harfBuzzBuffer) { ASSERT(numGlyphs > 0); std::unique_ptr<ShapeResult::RunInfo> run(std::move(runToInsert)); ASSERT(numGlyphs == run->m_glyphData.size()); const SimpleFontData* currentFontData = run->m_fontData.get(); const hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(harfBuzzBuffer, 0); const hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(harfBuzzBuffer, 0); const unsigned startCluster = HB_DIRECTION_IS_FORWARD(hb_buffer_get_direction(harfBuzzBuffer)) ? glyphInfos[startGlyph].cluster : glyphInfos[startGlyph + numGlyphs - 1].cluster; float totalAdvance = 0.0f; FloatPoint glyphOrigin; bool hasVerticalOffsets = !HB_DIRECTION_IS_HORIZONTAL(run->m_direction); // HarfBuzz returns result in visual order, no need to flip for RTL. for (unsigned i = 0; i < numGlyphs; ++i) { uint16_t glyph = glyphInfos[startGlyph + i].codepoint; hb_glyph_position_t pos = glyphPositions[startGlyph + i]; float offsetX = harfBuzzPositionToFloat(pos.x_offset); float offsetY = -harfBuzzPositionToFloat(pos.y_offset); // One out of x_advance and y_advance is zero, depending on // whether the buffer direction is horizontal or vertical. // Convert to float and negate to avoid integer-overflow for ULONG_MAX. float advance; if (LIKELY(pos.x_advance)) advance = harfBuzzPositionToFloat(pos.x_advance); else advance = -harfBuzzPositionToFloat(pos.y_advance); run->m_glyphData[i].characterIndex = glyphInfos[startGlyph + i].cluster - startCluster; run->setGlyphAndPositions(i, glyph, advance, offsetX, offsetY); totalAdvance += advance; hasVerticalOffsets |= (offsetY != 0); FloatRect glyphBounds = currentFontData->boundsForGlyph(glyph); glyphBounds.move(glyphOrigin.x(), glyphOrigin.y()); m_glyphBoundingBox.unite(glyphBounds); glyphOrigin += FloatSize(advance + offsetX, offsetY); } run->m_width = std::max(0.0f, totalAdvance); m_width += run->m_width; m_numGlyphs += numGlyphs; ASSERT(m_numGlyphs >= numGlyphs); m_hasVerticalOffsets |= hasVerticalOffsets; // The runs are stored in result->m_runs in visual order. For LTR, we place // the run to be inserted before the next run with a bigger character // start index. For RTL, we place the run before the next run with a lower // character index. Otherwise, for both directions, at the end. if (HB_DIRECTION_IS_FORWARD(run->m_direction)) { for (size_t pos = 0; pos < m_runs.size(); ++pos) { if (m_runs.at(pos)->m_startIndex > run->m_startIndex) { m_runs.insert(pos, std::move(run)); break; } } } else { for (size_t pos = 0; pos < m_runs.size(); ++pos) { if (m_runs.at(pos)->m_startIndex < run->m_startIndex) { m_runs.insert(pos, std::move(run)); break; } } } // If we didn't find an existing slot to place it, append. if (run) m_runs.append(std::move(run)); }