void SVGTextLayoutEngine::layoutInlineTextBox(SVGInlineTextBox* textBox) { ASSERT(textBox); LineLayoutSVGInlineText textLineLayout = LineLayoutSVGInlineText(textBox->lineLayoutItem()); ASSERT(textLineLayout.parent()); ASSERT(textLineLayout.parent().node()); ASSERT(textLineLayout.parent().node()->isSVGElement()); const ComputedStyle& style = textLineLayout.styleRef(); textBox->clearTextFragments(); m_isVerticalText = !style.isHorizontalWritingMode(); layoutTextOnLineOrPath(textBox, textLineLayout, style); if (m_inPathLayout) return; m_lineLayoutBoxes.append(textBox); }
void SVGTextChunkBuilder::handleTextChunk(BoxListConstIterator boxStart, BoxListConstIterator boxEnd) { ASSERT(*boxStart); const LineLayoutSVGInlineText textLineLayout = LineLayoutSVGInlineText((*boxStart)->getLineLayoutItem()); const ComputedStyle& style = textLineLayout.styleRef(); // Handle 'lengthAdjust' property. float desiredTextLength = 0; SVGLengthAdjustType lengthAdjust = SVGLengthAdjustUnknown; if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromLineLayoutItem( textLineLayout.parent())) { lengthAdjust = textContentElement->lengthAdjust()->currentValue()->enumValue(); SVGLengthContext lengthContext(textContentElement); if (textContentElement->textLengthIsSpecifiedByUser()) desiredTextLength = textContentElement->textLength()->currentValue()->value( lengthContext); else desiredTextLength = 0; } bool processTextLength = desiredTextLength > 0; bool processTextAnchor = needsTextAnchorAdjustment(style); if (!processTextAnchor && !processTextLength) return; bool isVerticalText = !style.isHorizontalWritingMode(); // Calculate absolute length of whole text chunk (starting from text box // 'start', spanning 'length' text boxes). ChunkLengthAccumulator lengthAccumulator(isVerticalText); lengthAccumulator.processRange(boxStart, boxEnd); if (processTextLength) { float chunkLength = lengthAccumulator.length(); if (lengthAdjust == SVGLengthAdjustSpacing) { float textLengthShift = (desiredTextLength - chunkLength) / lengthAccumulator.numCharacters(); unsigned atCharacter = 0; for (auto boxIter = boxStart; boxIter != boxEnd; ++boxIter) { Vector<SVGTextFragment>& fragments = (*boxIter)->textFragments(); if (fragments.isEmpty()) continue; processTextLengthSpacingCorrection(isVerticalText, textLengthShift, fragments, atCharacter); } // Fragments have been adjusted, we have to recalculate the chunk // length, to be able to apply the text-anchor shift. if (processTextAnchor) { lengthAccumulator.reset(); lengthAccumulator.processRange(boxStart, boxEnd); } } else { ASSERT(lengthAdjust == SVGLengthAdjustSpacingAndGlyphs); float textLengthScale = desiredTextLength / chunkLength; float textLengthBias = 0; bool foundFirstFragment = false; for (auto boxIter = boxStart; boxIter != boxEnd; ++boxIter) { SVGInlineTextBox* textBox = *boxIter; Vector<SVGTextFragment>& fragments = textBox->textFragments(); if (fragments.isEmpty()) continue; if (!foundFirstFragment) { foundFirstFragment = true; textLengthBias = computeTextLengthBias(fragments.first(), textLengthScale); } applyTextLengthScaleAdjustment(textLengthScale, textLengthBias, fragments); } } } if (!processTextAnchor) return; float textAnchorShift = calculateTextAnchorShift(style, lengthAccumulator.length()); for (auto boxIter = boxStart; boxIter != boxEnd; ++boxIter) { Vector<SVGTextFragment>& fragments = (*boxIter)->textFragments(); if (fragments.isEmpty()) continue; processTextAnchorCorrection(isVerticalText, textAnchorShift, fragments); } }