Beispiel #1
0
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;
}