void SVGRootInlineBox::layoutCharactersInTextBoxes(InlineFlowBox* start, SVGTextLayoutEngine& characterLayout) { for (InlineBox* child = start->firstChild(); child; child = child->nextOnLine()) { if (child->isSVGInlineTextBox()) { ASSERT(child->renderer().isSVGInlineText()); SVGInlineTextBox* textBox = toSVGInlineTextBox(child); characterLayout.layoutInlineTextBox(textBox); } else { // Skip generated content. Node* node = child->renderer().node(); if (!node) continue; ASSERT_WITH_SECURITY_IMPLICATION(child->isInlineFlowBox()); SVGInlineFlowBox* flowBox = toSVGInlineFlowBox(child); bool isTextPath = node->hasTagName(SVGNames::textPathTag); if (isTextPath) { // Build text chunks for all <textPath> children, using the line layout algorithm. // This is needeed as text-anchor is just an additional startOffset for text paths. SVGTextLayoutEngine lineLayout(characterLayout.layoutAttributes()); layoutCharactersInTextBoxes(flowBox, lineLayout); characterLayout.beginTextPathLayout(&child->renderer(), lineLayout); } layoutCharactersInTextBoxes(flowBox, characterLayout); if (isTextPath) characterLayout.endTextPathLayout(); } } }
void SVGTextLayoutEngine::beginTextPathLayout(SVGInlineFlowBox* flowBox) { // Build text chunks for all <textPath> children, using the line layout algorithm. // This is needeed as text-anchor is just an additional startOffset for text paths. SVGTextLayoutEngine lineLayout(m_layoutAttributes); lineLayout.m_textLengthSpacingInEffect = m_textLengthSpacingInEffect; lineLayout.layoutCharactersInTextBoxes(flowBox); m_inPathLayout = true; LayoutSVGTextPath* textPath = &toLayoutSVGTextPath(flowBox->layoutObject()); Path path = textPath->layoutPath(); if (path.isEmpty()) return; m_textPathCalculator = new Path::PositionCalculator(path); m_textPathStartOffset = textPath->startOffset(); m_textPathLength = path.length(); if (m_textPathStartOffset > 0 && m_textPathStartOffset <= 1) m_textPathStartOffset *= m_textPathLength; SVGTextPathChunkBuilder textPathChunkLayoutBuilder; textPathChunkLayoutBuilder.processTextChunks(lineLayout.m_lineLayoutBoxes); m_textPathStartOffset += textPathChunkLayoutBuilder.totalTextAnchorShift(); m_textPathCurrentOffset = m_textPathStartOffset; // Eventually handle textLength adjustments. SVGLengthAdjustType lengthAdjust = SVGLengthAdjustUnknown; float desiredTextLength = 0; if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromLayoutObject(textPath)) { SVGLengthContext lengthContext(textContentElement); lengthAdjust = textContentElement->lengthAdjust()->currentValue()->enumValue(); if (textContentElement->textLengthIsSpecifiedByUser()) desiredTextLength = textContentElement->textLength()->currentValue()->value(lengthContext); else desiredTextLength = 0; } if (!desiredTextLength) return; float totalLength = textPathChunkLayoutBuilder.totalLength(); if (lengthAdjust == SVGLengthAdjustSpacing) m_textPathSpacing = (desiredTextLength - totalLength) / textPathChunkLayoutBuilder.totalCharacters(); else m_textPathScaling = desiredTextLength / totalLength; }