static void measureTextRenderer(RenderSVGInlineText* text, MeasureTextData* data, bool processRenderer) { ASSERT(text); SVGTextLayoutAttributes* attributes = text->layoutAttributes(); Vector<SVGTextMetrics>* textMetricsValues = &attributes->textMetricsValues(); if (processRenderer) { if (data->allCharactersMap) attributes->clear(); else textMetricsValues->clear(); } SVGTextMetricsCalculator calculator(text); bool preserveWhiteSpace = text->style()->whiteSpace() == PRE; unsigned surrogatePairCharacters = 0; unsigned skippedCharacters = 0; unsigned textPosition = 0; unsigned textLength = calculator.textLength(); SVGTextMetrics currentMetrics; for (; textPosition < textLength; textPosition += currentMetrics.length()) { currentMetrics = calculator.computeMetricsForCharacter(textPosition); if (!currentMetrics.length()) break; bool characterIsWhiteSpace = calculator.characterIsWhiteSpace(textPosition); if (characterIsWhiteSpace && !preserveWhiteSpace && data->lastCharacterWasWhiteSpace) { if (processRenderer) textMetricsValues->append(SVGTextMetrics(SVGTextMetrics::SkippedSpaceMetrics)); if (data->allCharactersMap) skippedCharacters += currentMetrics.length(); continue; } if (processRenderer) { if (data->allCharactersMap) { const SVGCharacterDataMap::const_iterator it = data->allCharactersMap->find(data->valueListPosition + textPosition - skippedCharacters - surrogatePairCharacters + 1); if (it != data->allCharactersMap->end()) attributes->characterDataMap().set(textPosition + 1, it->value); } textMetricsValues->append(currentMetrics); } if (data->allCharactersMap && calculator.characterStartsSurrogatePair(textPosition)) surrogatePairCharacters++; data->lastCharacterWasWhiteSpace = characterIsWhiteSpace; } if (!data->allCharactersMap) return; data->valueListPosition += textPosition - skippedCharacters; }
SVGTextMetrics SVGTextMetricsCalculator::computeMetricsForCharacter(unsigned textPosition) { if (m_bidiRun) { if (textPosition >= static_cast<unsigned>(m_bidiRun->stop())) { m_bidiRun = m_bidiRun->next(); // New BiDi run means new reference position for measurements, so reset |m_totalWidth|. m_totalWidth = 0; } ASSERT(m_bidiRun); ASSERT(static_cast<int>(textPosition) < m_bidiRun->stop()); m_textDirection = m_bidiRun->direction(); } unsigned metricsLength = characterStartsSurrogatePair(textPosition) ? 2 : 1; SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(m_text, textPosition, metricsLength, m_textDirection); ASSERT(metrics.length() == metricsLength); unsigned startPosition = m_bidiRun ? m_bidiRun->start() : 0; ASSERT(startPosition <= textPosition); SVGTextMetrics complexStartToCurrentMetrics = SVGTextMetrics::measureCharacterRange(m_text, startPosition, textPosition - startPosition + metricsLength, m_textDirection); // Frequent case for Arabic text: when measuring a single character the arabic isolated form is taken // when laying out the glyph "in context" (with it's surrounding characters) it changes due to shaping. // So whenever currentWidth != currentMetrics.width(), we are processing a text run whose length is // not equal to the sum of the individual lengths of the glyphs, when measuring them isolated. float currentWidth = complexStartToCurrentMetrics.width() - m_totalWidth; if (currentWidth != metrics.width()) metrics.setWidth(currentWidth); m_totalWidth = complexStartToCurrentMetrics.width(); return metrics; }
void SVGTextLayoutAttributesBuilder::propagateLayoutAttributes(RenderObject* start, unsigned& atCharacter, UChar& lastCharacter) const { for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) { if (child->isSVGInlineText()) { RenderSVGInlineText* text = toRenderSVGInlineText(child); const UChar* characters = text->characters(); unsigned textLength = text->textLength(); bool preserveWhiteSpace = shouldPreserveAllWhiteSpace(text->style()); SVGTextLayoutAttributes attributes; attributes.reserveCapacity(textLength); unsigned valueListPosition = atCharacter; unsigned metricsLength = 1; for (unsigned textPosition = 0; textPosition < textLength; textPosition += metricsLength) { const UChar& currentCharacter = characters[textPosition]; SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(text, textPosition, 1); metricsLength = metrics.length(); if (!preserveWhiteSpace && characterIsSpace(currentCharacter) && characterIsSpaceOrNull(lastCharacter)) { assignEmptyLayoutAttributesForCharacter(attributes); attributes.textMetricsValues().append(SVGTextMetrics::emptyMetrics()); continue; } assignLayoutAttributesForCharacter(attributes, metrics, valueListPosition); if (metricsLength > 1) { for (unsigned i = 0; i < metricsLength - 1; ++i) assignEmptyLayoutAttributesForCharacter(attributes); } lastCharacter = currentCharacter; valueListPosition += metricsLength; } #if DUMP_TEXT_LAYOUT_ATTRIBUTES > 0 fprintf(stderr, "\nDumping layout attributes for RenderSVGInlineText, renderer=%p, node=%p (atCharacter: %i)\n", text, text->node(), atCharacter); attributes.dump(); #endif text->storeLayoutAttributes(attributes); atCharacter = valueListPosition; continue; } if (!child->isSVGInline()) continue; propagateLayoutAttributes(child, atCharacter, lastCharacter); } }
SVGTextMetrics SVGTextMetricsCalculator::computeMetricsForCharacterComplex(unsigned textPosition) { unsigned metricsLength = characterStartsSurrogatePair(textPosition) ? 2 : 1; SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(m_text, textPosition, metricsLength, m_textDirection); ASSERT(metrics.length() == metricsLength); unsigned startPosition = m_bidiRun ? m_bidiRun->start() : 0; ASSERT(startPosition <= textPosition); SVGTextMetrics complexStartToCurrentMetrics = SVGTextMetrics::measureCharacterRange(m_text, startPosition, textPosition - startPosition + metricsLength, m_textDirection); // Frequent case for Arabic text: when measuring a single character the arabic isolated form is taken // when rendering the glyph "in context" (with it's surrounding characters) it changes due to shaping. // So whenever currentWidth != currentMetrics.width(), we are processing a text run whose length is // not equal to the sum of the individual lengths of the glyphs, when measuring them isolated. float currentWidth = complexStartToCurrentMetrics.width() - m_totalWidth; if (currentWidth != metrics.width()) metrics.setWidth(currentWidth); m_totalWidth = complexStartToCurrentMetrics.width(); return metrics; }
void SVGTextLayoutEngine::advanceToNextLogicalCharacter(const SVGTextMetrics& logicalMetrics) { ++m_logicalMetricsListOffset; m_logicalCharacterOffset += logicalMetrics.length(); }
void SVGTextLayoutEngine::advanceToNextVisualCharacter(const SVGTextMetrics& visualMetrics) { ++m_visualMetricsListOffset; m_visualCharacterOffset += visualMetrics.length(); }
void SVGTextLayoutAttributesBuilder::propagateLayoutAttributes(RenderObject* start, Vector<SVGTextLayoutAttributes>& allAttributes, unsigned& atCharacter, UChar& lastCharacter) const { for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) { if (child->isSVGInlineText()) { RenderSVGInlineText* text = toRenderSVGInlineText(child); const UChar* characters = text->characters(); unsigned textLength = text->textLength(); bool preserveWhiteSpace = shouldPreserveAllWhiteSpace(text->style()); SVGTextLayoutAttributes attributes(text); attributes.reserveCapacity(textLength); unsigned valueListPosition = atCharacter; unsigned metricsLength = 1; SVGTextMetrics lastMetrics(SVGTextMetrics::SkippedSpaceMetrics); for (unsigned textPosition = 0; textPosition < textLength; textPosition += metricsLength) { const UChar& currentCharacter = characters[textPosition]; SVGTextMetrics startToCurrentMetrics; SVGTextMetrics currentMetrics; unsigned valueListAdvance = 0; if (U16_IS_LEAD(currentCharacter) && (textPosition + 1) < textLength && U16_IS_TRAIL(characters[textPosition + 1])) { // Handle surrogate pairs. startToCurrentMetrics = SVGTextMetrics::measureCharacterRange(text, 0, textPosition + 2); currentMetrics = SVGTextMetrics::measureCharacterRange(text, textPosition, 2); metricsLength = currentMetrics.length(); valueListAdvance = 1; } else { // Handle BMP characters. startToCurrentMetrics = SVGTextMetrics::measureCharacterRange(text, 0, textPosition + 1); currentMetrics = SVGTextMetrics::measureCharacterRange(text, textPosition, 1); metricsLength = currentMetrics.length(); valueListAdvance = metricsLength; } if (!metricsLength) break; // Frequent case for Arabic text: when measuring a single character the arabic isolated form is taken // when rendering the glyph "in context" (with it's surrounding characters) it changes due to shaping. // So whenever runWidthAdvance != currentMetrics.width(), we are processing a text run whose length is // not equal to the sum of the individual lengths of the glyphs, when measuring them isolated. float runWidthAdvance = startToCurrentMetrics.width() - lastMetrics.width(); if (runWidthAdvance != currentMetrics.width()) currentMetrics.setWidth(runWidthAdvance); lastMetrics = startToCurrentMetrics; if (!preserveWhiteSpace && characterIsSpace(currentCharacter) && characterIsSpaceOrNull(lastCharacter)) { attributes.positioningLists().appendEmptyValues(); attributes.textMetricsValues().append(SVGTextMetrics(SVGTextMetrics::SkippedSpaceMetrics)); continue; } SVGTextLayoutAttributes::PositioningLists& positioningLists = attributes.positioningLists(); positioningLists.appendValuesFromPosition(m_positioningLists, valueListPosition); attributes.textMetricsValues().append(currentMetrics); // Pad x/y/dx/dy/rotate value lists with empty values, if the metrics span more than one character. if (metricsLength > 1) { for (unsigned i = 0; i < metricsLength - 1; ++i) positioningLists.appendEmptyValues(); } lastCharacter = currentCharacter; valueListPosition += valueListAdvance; } #if DUMP_TEXT_LAYOUT_ATTRIBUTES > 0 fprintf(stderr, "\nDumping layout attributes for RenderSVGInlineText, renderer=%p, node=%p (atCharacter: %i)\n", text, text->node(), atCharacter); fprintf(stderr, "BiDi properties: unicode-bidi=%i, block direction=%i\n", text->style()->unicodeBidi(), text->style()->direction()); attributes.dump(); #endif text->storeLayoutAttributes(attributes); allAttributes.append(attributes); atCharacter = valueListPosition; continue; } if (!child->isSVGInline()) continue; propagateLayoutAttributes(child, allAttributes, atCharacter, lastCharacter); } }