1a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch/*
2a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * Copyright (C) Research In Motion Limited 2010. All rights reserved.
3a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch *
4a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * This library is free software; you can redistribute it and/or
5a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * modify it under the terms of the GNU Library General Public
6a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * License as published by the Free Software Foundation; either
7a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * version 2 of the License, or (at your option) any later version.
8a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch *
9a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * This library is distributed in the hope that it will be useful,
10a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * but WITHOUT ANY WARRANTY; without even the implied warranty of
11a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * Library General Public License for more details.
13a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch *
14a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * You should have received a copy of the GNU Library General Public License
15a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * along with this library; see the file COPYING.LIB.  If not, write to
16a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * Boston, MA 02110-1301, USA.
18a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch */
19a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
20a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "config.h"
21a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
22a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#if ENABLE(SVG)
23a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "SVGTextLayoutEngine.h"
24a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
25a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "RenderSVGInlineText.h"
26a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "RenderSVGTextPath.h"
27a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "SVGElement.h"
28a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "SVGInlineTextBox.h"
29a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "SVGTextLayoutEngineBaseline.h"
30a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "SVGTextLayoutEngineSpacing.h"
31a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
32a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch// Set to a value > 0 to dump the text fragments
33a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#define DUMP_TEXT_FRAGMENTS 0
34a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
35a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochnamespace WebCore {
36a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
372bde8e466a4451c7319e3a072d118917957d6554Steve BlockSVGTextLayoutEngine::SVGTextLayoutEngine(Vector<SVGTextLayoutAttributes>& layoutAttributes)
382bde8e466a4451c7319e3a072d118917957d6554Steve Block    : m_layoutAttributes(layoutAttributes)
392bde8e466a4451c7319e3a072d118917957d6554Steve Block    , m_logicalCharacterOffset(0)
402bde8e466a4451c7319e3a072d118917957d6554Steve Block    , m_logicalMetricsListOffset(0)
412bde8e466a4451c7319e3a072d118917957d6554Steve Block    , m_visualCharacterOffset(0)
422bde8e466a4451c7319e3a072d118917957d6554Steve Block    , m_visualMetricsListOffset(0)
432bde8e466a4451c7319e3a072d118917957d6554Steve Block    , m_x(0)
44a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    , m_y(0)
45a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    , m_dx(0)
46a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    , m_dy(0)
47a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    , m_isVerticalText(false)
48a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    , m_inPathLayout(false)
49a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    , m_textPathLength(0)
50a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    , m_textPathCurrentOffset(0)
51a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    , m_textPathSpacing(0)
52a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    , m_textPathScaling(1)
53a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
542bde8e466a4451c7319e3a072d118917957d6554Steve Block    ASSERT(!m_layoutAttributes.isEmpty());
55a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
56a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
57a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid SVGTextLayoutEngine::updateCharacerPositionIfNeeded(float& x, float& y)
58a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
59a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (m_inPathLayout)
60a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return;
61a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
62a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // Replace characters x/y position, with the current text position plus any
63a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // relative adjustments, if it doesn't specify an absolute position itself.
64a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (x == SVGTextLayoutAttributes::emptyValue())
65a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        x = m_x + m_dx;
66a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
67a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (y == SVGTextLayoutAttributes::emptyValue())
68a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        y = m_y + m_dy;
69a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
70a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_dx = 0;
71a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_dy = 0;
72a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
73a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
74a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid SVGTextLayoutEngine::updateCurrentTextPosition(float x, float y, float glyphAdvance)
75a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
76a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // Update current text position after processing the character.
77a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (m_isVerticalText) {
78a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        m_x = x;
79a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        m_y = y + glyphAdvance;
80a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    } else {
81a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        m_x = x + glyphAdvance;
82a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        m_y = y;
83a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
84a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
85a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
862bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid SVGTextLayoutEngine::updateRelativePositionAdjustmentsIfNeeded(Vector<float>& dxValues, Vector<float>& dyValues)
87a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
88a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // Update relative positioning information.
89a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (dxValues.isEmpty() && dyValues.isEmpty())
90a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return;
91a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
92a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    float dx = 0;
93a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (!dxValues.isEmpty()) {
942bde8e466a4451c7319e3a072d118917957d6554Steve Block        float& dxCurrent = dxValues.at(m_logicalCharacterOffset);
95a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (dxCurrent != SVGTextLayoutAttributes::emptyValue())
96a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            dx = dxCurrent;
97a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
98a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
99a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    float dy = 0;
100a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (!dyValues.isEmpty()) {
1012bde8e466a4451c7319e3a072d118917957d6554Steve Block        float& dyCurrent = dyValues.at(m_logicalCharacterOffset);
102a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (dyCurrent != SVGTextLayoutAttributes::emptyValue())
103a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            dy = dyCurrent;
104a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
105a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
106a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (m_inPathLayout) {
107a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (m_isVerticalText) {
108a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            m_dx += dx;
109a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            m_dy = dy;
110a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        } else {
111a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            m_dx = dx;
112a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            m_dy += dy;
113a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        }
114a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
115a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return;
116a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
117a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
118a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_dx = dx;
119a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_dy = dy;
120a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
121a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
1222bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid SVGTextLayoutEngine::recordTextFragment(SVGInlineTextBox* textBox, Vector<SVGTextMetrics>& textMetricsValues)
123a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
124a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    ASSERT(!m_currentTextFragment.length);
1252bde8e466a4451c7319e3a072d118917957d6554Steve Block    ASSERT(m_visualMetricsListOffset > 0);
126a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
127a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // Figure out length of fragment.
1282bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_currentTextFragment.length = m_visualCharacterOffset - m_currentTextFragment.characterOffset;
129a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
130a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // Figure out fragment metrics.
1312bde8e466a4451c7319e3a072d118917957d6554Steve Block    SVGTextMetrics& lastCharacterMetrics = textMetricsValues.at(m_visualMetricsListOffset - 1);
1322bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_currentTextFragment.width = lastCharacterMetrics.width();
1332bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_currentTextFragment.height = lastCharacterMetrics.height();
1342bde8e466a4451c7319e3a072d118917957d6554Steve Block
1352bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (m_currentTextFragment.length > 1) {
1362bde8e466a4451c7319e3a072d118917957d6554Steve Block        // SVGTextLayoutAttributesBuilder assures that the length of the range is equal to the sum of the individual lengths of the glyphs.
1372bde8e466a4451c7319e3a072d118917957d6554Steve Block        float length = 0;
1382bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (m_isVerticalText) {
1392bde8e466a4451c7319e3a072d118917957d6554Steve Block            for (unsigned i = m_currentTextFragment.metricsListOffset; i < m_visualMetricsListOffset; ++i)
1402bde8e466a4451c7319e3a072d118917957d6554Steve Block                length += textMetricsValues.at(i).height();
1412bde8e466a4451c7319e3a072d118917957d6554Steve Block            m_currentTextFragment.height = length;
1422bde8e466a4451c7319e3a072d118917957d6554Steve Block        } else {
1432bde8e466a4451c7319e3a072d118917957d6554Steve Block            for (unsigned i = m_currentTextFragment.metricsListOffset; i < m_visualMetricsListOffset; ++i)
1442bde8e466a4451c7319e3a072d118917957d6554Steve Block                length += textMetricsValues.at(i).width();
1452bde8e466a4451c7319e3a072d118917957d6554Steve Block            m_currentTextFragment.width = length;
1462bde8e466a4451c7319e3a072d118917957d6554Steve Block        }
147a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
148a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
149a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    textBox->textFragments().append(m_currentTextFragment);
150a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_currentTextFragment = SVGTextFragment();
151a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
152a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
153a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochbool SVGTextLayoutEngine::parentDefinesTextLength(RenderObject* parent) const
154a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
155a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    RenderObject* currentParent = parent;
156a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    while (currentParent) {
157a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(currentParent);
158a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (textContentElement) {
159a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            SVGTextContentElement::SVGLengthAdjustType lengthAdjust = static_cast<SVGTextContentElement::SVGLengthAdjustType>(textContentElement->lengthAdjust());
1602daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            if (lengthAdjust == SVGTextContentElement::LENGTHADJUST_SPACING && textContentElement->specifiedTextLength().value(textContentElement) > 0)
161a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                return true;
162a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        }
163a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
164a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (currentParent->isSVGText())
165a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            return false;
166a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
167a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        currentParent = currentParent->parent();
168a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
169a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
170a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    ASSERT_NOT_REACHED();
171a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    return false;
172a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
173a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
174a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid SVGTextLayoutEngine::beginTextPathLayout(RenderObject* object, SVGTextLayoutEngine& lineLayout)
175a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
176a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    ASSERT(object);
177a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
178a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_inPathLayout = true;
179a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    RenderSVGTextPath* textPath = toRenderSVGTextPath(object);
180a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
181a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_textPath = textPath->layoutPath();
182a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_textPathStartOffset = textPath->startOffset();
183a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_textPathLength = m_textPath.length();
184a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (m_textPathStartOffset > 0 && m_textPathStartOffset <= 1)
185a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        m_textPathStartOffset *= m_textPathLength;
186a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
187a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    float totalLength = 0;
188a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    unsigned totalCharacters = 0;
189a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
190a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    lineLayout.m_chunkLayoutBuilder.buildTextChunks(lineLayout.m_lineLayoutBoxes);
191a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    const Vector<SVGTextChunk>& textChunks = lineLayout.m_chunkLayoutBuilder.textChunks();
192a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
193a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    unsigned size = textChunks.size();
194a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    for (unsigned i = 0; i < size; ++i) {
195a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        const SVGTextChunk& chunk = textChunks.at(i);
196a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
197a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        float length = 0;
198a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        unsigned characters = 0;
199a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        chunk.calculateLength(length, characters);
200a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
201a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        // Handle text-anchor as additional start offset for text paths.
202a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        m_textPathStartOffset += chunk.calculateTextAnchorShift(length);
203a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
204a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        totalLength += length;
205a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        totalCharacters += characters;
206a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
207a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
208a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_textPathCurrentOffset = m_textPathStartOffset;
209a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
210a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // Eventually handle textLength adjustments.
211a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    SVGTextContentElement::SVGLengthAdjustType lengthAdjust = SVGTextContentElement::LENGTHADJUST_UNKNOWN;
212a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    float desiredTextLength = 0;
213a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
214a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(textPath)) {
215a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        lengthAdjust = static_cast<SVGTextContentElement::SVGLengthAdjustType>(textContentElement->lengthAdjust());
2162daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        desiredTextLength = textContentElement->specifiedTextLength().value(textContentElement);
217a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
218a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
219a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (!desiredTextLength)
220a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return;
221a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
222a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (lengthAdjust == SVGTextContentElement::LENGTHADJUST_SPACING)
223a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        m_textPathSpacing = (desiredTextLength - totalLength) / totalCharacters;
224a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    else
225a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        m_textPathScaling = desiredTextLength / totalLength;
226a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
227a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
228a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid SVGTextLayoutEngine::endTextPathLayout()
229a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
230a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_inPathLayout = false;
231a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_textPath = Path();
232a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_textPathLength = 0;
233a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_textPathStartOffset = 0;
234a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_textPathCurrentOffset = 0;
235a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_textPathSpacing = 0;
236a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_textPathScaling = 1;
237a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
238a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
239a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid SVGTextLayoutEngine::layoutInlineTextBox(SVGInlineTextBox* textBox)
240a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
241a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    ASSERT(textBox);
242a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
243a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    RenderSVGInlineText* text = toRenderSVGInlineText(textBox->textRenderer());
244a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    ASSERT(text);
245a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    ASSERT(text->parent());
246a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    ASSERT(text->parent()->node());
247a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    ASSERT(text->parent()->node()->isSVGElement());
248a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
249a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    const RenderStyle* style = text->style();
250a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    ASSERT(style);
251a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
252a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    textBox->clearTextFragments();
253a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_isVerticalText = style->svgStyle()->isVerticalWritingMode();
254a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    layoutTextOnLineOrPath(textBox, text, style);
255a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
256a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (m_inPathLayout) {
257a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        m_pathLayoutBoxes.append(textBox);
258a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return;
259a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
260a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
261a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_lineLayoutBoxes.append(textBox);
262a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
263a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
264a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#if DUMP_TEXT_FRAGMENTS > 0
2652daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic inline void dumpTextBoxes(Vector<SVGInlineTextBox*>& boxes)
266a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
267a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    unsigned boxCount = boxes.size();
268a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    fprintf(stderr, "Dumping all text fragments in text sub tree, %i boxes\n", boxCount);
269a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
270a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) {
271a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        SVGInlineTextBox* textBox = boxes.at(boxPosition);
272a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        Vector<SVGTextFragment>& fragments = textBox->textFragments();
273a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        fprintf(stderr, "-> Box %i: Dumping text fragments for SVGInlineTextBox, textBox=%p, textRenderer=%p\n", boxPosition, textBox, textBox->textRenderer());
2742bde8e466a4451c7319e3a072d118917957d6554Steve Block        fprintf(stderr, "        textBox properties, start=%i, len=%i, box direction=%i\n", textBox->start(), textBox->len(), textBox->direction());
275a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        fprintf(stderr, "   textRenderer properties, textLength=%i\n", textBox->textRenderer()->textLength());
276a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
277a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        const UChar* characters = textBox->textRenderer()->characters();
278a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
279a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        unsigned fragmentCount = fragments.size();
280a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        for (unsigned i = 0; i < fragmentCount; ++i) {
281a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            SVGTextFragment& fragment = fragments.at(i);
2822bde8e466a4451c7319e3a072d118917957d6554Steve Block            String fragmentString(characters + fragment.characterOffset, fragment.length);
2832bde8e466a4451c7319e3a072d118917957d6554Steve Block            fprintf(stderr, "    -> Fragment %i, x=%lf, y=%lf, width=%lf, height=%lf, characterOffset=%i, length=%i, characters='%s'\n"
2842bde8e466a4451c7319e3a072d118917957d6554Steve Block                          , i, fragment.x, fragment.y, fragment.width, fragment.height, fragment.characterOffset, fragment.length, fragmentString.utf8().data());
285a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        }
286a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
2872daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}
288a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#endif
289a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
2902daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochvoid SVGTextLayoutEngine::finalizeTransformMatrices(Vector<SVGInlineTextBox*>& boxes)
2912daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{
2922daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    unsigned boxCount = boxes.size();
293a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (!boxCount)
294a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return;
295a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
296a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    AffineTransform textBoxTransformation;
297a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) {
298a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        SVGInlineTextBox* textBox = boxes.at(boxPosition);
299a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        Vector<SVGTextFragment>& fragments = textBox->textFragments();
300a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
301a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        unsigned fragmentCount = fragments.size();
302a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        for (unsigned i = 0; i < fragmentCount; ++i) {
303a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            m_chunkLayoutBuilder.transformationForTextBox(textBox, textBoxTransformation);
304a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            if (textBoxTransformation.isIdentity())
305a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                continue;
3062daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            ASSERT(fragments[i].lengthAdjustTransform.isIdentity());
3072daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            fragments[i].lengthAdjustTransform = textBoxTransformation;
308a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        }
309a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
310a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
311a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    boxes.clear();
312a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
313a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
3142daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochvoid SVGTextLayoutEngine::finishLayout()
3152daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{
3162daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    // After all text fragments are stored in their correpsonding SVGInlineTextBoxes, we can layout individual text chunks.
3172daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    // Chunk layouting is only performed for line layout boxes, not for path layout, where it has already been done.
3182daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    m_chunkLayoutBuilder.layoutTextChunks(m_lineLayoutBoxes);
3192daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
3202daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    // Finalize transform matrices, after the chunk layout corrections have been applied, and all fragment x/y positions are finalized.
3212daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (!m_lineLayoutBoxes.isEmpty()) {
3222daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#if DUMP_TEXT_FRAGMENTS > 0
3232daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        fprintf(stderr, "Line layout: ");
3242daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        dumpTextBoxes(m_lineLayoutBoxes);
3252daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#endif
3262daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
3272daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        finalizeTransformMatrices(m_lineLayoutBoxes);
3282daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    }
3292daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
3302daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (!m_pathLayoutBoxes.isEmpty()) {
3312daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#if DUMP_TEXT_FRAGMENTS > 0
3322daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        fprintf(stderr, "Path layout: ");
3332daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        dumpTextBoxes(m_pathLayoutBoxes);
3342daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#endif
3352daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
3362daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        finalizeTransformMatrices(m_pathLayoutBoxes);
3372daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    }
3382daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}
3392daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
3402bde8e466a4451c7319e3a072d118917957d6554Steve Blockbool SVGTextLayoutEngine::currentLogicalCharacterAttributes(SVGTextLayoutAttributes& logicalAttributes)
3412bde8e466a4451c7319e3a072d118917957d6554Steve Block{
3422daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (m_layoutAttributes.isEmpty())
3432daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return false;
3442daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
3452bde8e466a4451c7319e3a072d118917957d6554Steve Block    logicalAttributes = m_layoutAttributes.first();
3462bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (m_logicalCharacterOffset != logicalAttributes.xValues().size())
3472bde8e466a4451c7319e3a072d118917957d6554Steve Block        return true;
3482bde8e466a4451c7319e3a072d118917957d6554Steve Block
3492bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_layoutAttributes.remove(0);
3502bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (m_layoutAttributes.isEmpty())
3512bde8e466a4451c7319e3a072d118917957d6554Steve Block        return false;
3522bde8e466a4451c7319e3a072d118917957d6554Steve Block
3532bde8e466a4451c7319e3a072d118917957d6554Steve Block    logicalAttributes = m_layoutAttributes.first();
3542bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_logicalMetricsListOffset = 0;
3552bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_logicalCharacterOffset = 0;
3562bde8e466a4451c7319e3a072d118917957d6554Steve Block    return true;
3572bde8e466a4451c7319e3a072d118917957d6554Steve Block}
3582bde8e466a4451c7319e3a072d118917957d6554Steve Block
3592bde8e466a4451c7319e3a072d118917957d6554Steve Blockbool SVGTextLayoutEngine::currentLogicalCharacterMetrics(SVGTextLayoutAttributes& logicalAttributes, SVGTextMetrics& logicalMetrics)
3602bde8e466a4451c7319e3a072d118917957d6554Steve Block{
3612bde8e466a4451c7319e3a072d118917957d6554Steve Block    logicalMetrics = SVGTextMetrics::emptyMetrics();
3622bde8e466a4451c7319e3a072d118917957d6554Steve Block
3632bde8e466a4451c7319e3a072d118917957d6554Steve Block    Vector<SVGTextMetrics>& textMetricsValues = logicalAttributes.textMetricsValues();
3642bde8e466a4451c7319e3a072d118917957d6554Steve Block    unsigned textMetricsSize = textMetricsValues.size();
3652bde8e466a4451c7319e3a072d118917957d6554Steve Block    while (true) {
3662bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (m_logicalMetricsListOffset == textMetricsSize) {
3672bde8e466a4451c7319e3a072d118917957d6554Steve Block            if (!currentLogicalCharacterAttributes(logicalAttributes))
3682bde8e466a4451c7319e3a072d118917957d6554Steve Block                return false;
3692bde8e466a4451c7319e3a072d118917957d6554Steve Block
3702bde8e466a4451c7319e3a072d118917957d6554Steve Block            textMetricsValues = logicalAttributes.textMetricsValues();
3712bde8e466a4451c7319e3a072d118917957d6554Steve Block            textMetricsSize = textMetricsValues.size();
3722bde8e466a4451c7319e3a072d118917957d6554Steve Block            continue;
3732bde8e466a4451c7319e3a072d118917957d6554Steve Block        }
3742bde8e466a4451c7319e3a072d118917957d6554Steve Block
3752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        ASSERT(textMetricsSize);
3762daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        ASSERT(m_logicalMetricsListOffset < textMetricsSize);
3772bde8e466a4451c7319e3a072d118917957d6554Steve Block        logicalMetrics = textMetricsValues.at(m_logicalMetricsListOffset);
3782bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (logicalMetrics == SVGTextMetrics::emptyMetrics() || (!logicalMetrics.width() && !logicalMetrics.height())) {
3792bde8e466a4451c7319e3a072d118917957d6554Steve Block            advanceToNextLogicalCharacter(logicalMetrics);
3802bde8e466a4451c7319e3a072d118917957d6554Steve Block            continue;
3812bde8e466a4451c7319e3a072d118917957d6554Steve Block        }
3822bde8e466a4451c7319e3a072d118917957d6554Steve Block
3832bde8e466a4451c7319e3a072d118917957d6554Steve Block        // Stop if we found the next valid logical text metrics object.
3842bde8e466a4451c7319e3a072d118917957d6554Steve Block        return true;
3852bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
3862bde8e466a4451c7319e3a072d118917957d6554Steve Block
3872bde8e466a4451c7319e3a072d118917957d6554Steve Block    ASSERT_NOT_REACHED();
3882bde8e466a4451c7319e3a072d118917957d6554Steve Block    return true;
3892bde8e466a4451c7319e3a072d118917957d6554Steve Block}
3902bde8e466a4451c7319e3a072d118917957d6554Steve Block
3912bde8e466a4451c7319e3a072d118917957d6554Steve Blockbool SVGTextLayoutEngine::currentVisualCharacterMetrics(SVGInlineTextBox* textBox, RenderSVGInlineText* text, SVGTextMetrics& metrics)
3922bde8e466a4451c7319e3a072d118917957d6554Steve Block{
3932bde8e466a4451c7319e3a072d118917957d6554Steve Block    SVGTextLayoutAttributes& attributes = text->layoutAttributes();
3942bde8e466a4451c7319e3a072d118917957d6554Steve Block    Vector<SVGTextMetrics>& textMetricsValues = attributes.textMetricsValues();
3952bde8e466a4451c7319e3a072d118917957d6554Steve Block    ASSERT(!textMetricsValues.isEmpty());
3962bde8e466a4451c7319e3a072d118917957d6554Steve Block
3972bde8e466a4451c7319e3a072d118917957d6554Steve Block    unsigned textMetricsSize = textMetricsValues.size();
3982bde8e466a4451c7319e3a072d118917957d6554Steve Block    unsigned boxStart = textBox->start();
3992bde8e466a4451c7319e3a072d118917957d6554Steve Block    unsigned boxLength = textBox->len();
4002bde8e466a4451c7319e3a072d118917957d6554Steve Block
4012bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (m_visualMetricsListOffset == textMetricsSize)
4022bde8e466a4451c7319e3a072d118917957d6554Steve Block        return false;
4032bde8e466a4451c7319e3a072d118917957d6554Steve Block
4042bde8e466a4451c7319e3a072d118917957d6554Steve Block    while (m_visualMetricsListOffset < textMetricsSize) {
4052bde8e466a4451c7319e3a072d118917957d6554Steve Block        SVGTextMetrics& visualMetrics = textMetricsValues.at(m_visualMetricsListOffset);
4062bde8e466a4451c7319e3a072d118917957d6554Steve Block
4072bde8e466a4451c7319e3a072d118917957d6554Steve Block        // Advance to text box start location.
4082bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (m_visualCharacterOffset < boxStart) {
4092bde8e466a4451c7319e3a072d118917957d6554Steve Block            advanceToNextVisualCharacter(visualMetrics);
4102bde8e466a4451c7319e3a072d118917957d6554Steve Block            continue;
4112bde8e466a4451c7319e3a072d118917957d6554Steve Block        }
4122bde8e466a4451c7319e3a072d118917957d6554Steve Block
4132bde8e466a4451c7319e3a072d118917957d6554Steve Block        // Stop if we've finished processing this text box.
4142bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (m_visualCharacterOffset >= boxStart + boxLength)
4152bde8e466a4451c7319e3a072d118917957d6554Steve Block            return false;
4162bde8e466a4451c7319e3a072d118917957d6554Steve Block
4172bde8e466a4451c7319e3a072d118917957d6554Steve Block        metrics = visualMetrics;
4182bde8e466a4451c7319e3a072d118917957d6554Steve Block        return true;
4192bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
4202bde8e466a4451c7319e3a072d118917957d6554Steve Block
4212bde8e466a4451c7319e3a072d118917957d6554Steve Block    return false;
4222bde8e466a4451c7319e3a072d118917957d6554Steve Block}
4232bde8e466a4451c7319e3a072d118917957d6554Steve Block
4242bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid SVGTextLayoutEngine::advanceToNextLogicalCharacter(const SVGTextMetrics& logicalMetrics)
4252bde8e466a4451c7319e3a072d118917957d6554Steve Block{
4262bde8e466a4451c7319e3a072d118917957d6554Steve Block    ++m_logicalMetricsListOffset;
4272bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_logicalCharacterOffset += logicalMetrics.length();
4282bde8e466a4451c7319e3a072d118917957d6554Steve Block}
4292bde8e466a4451c7319e3a072d118917957d6554Steve Block
4302bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid SVGTextLayoutEngine::advanceToNextVisualCharacter(const SVGTextMetrics& visualMetrics)
4312bde8e466a4451c7319e3a072d118917957d6554Steve Block{
4322bde8e466a4451c7319e3a072d118917957d6554Steve Block    ++m_visualMetricsListOffset;
4332bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_visualCharacterOffset += visualMetrics.length();
4342bde8e466a4451c7319e3a072d118917957d6554Steve Block}
4352bde8e466a4451c7319e3a072d118917957d6554Steve Block
436a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, RenderSVGInlineText* text, const RenderStyle* style)
437a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
438a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    SVGElement* lengthContext = static_cast<SVGElement*>(text->parent()->node());
439a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
440a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    RenderObject* textParent = text->parent();
441a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    bool definesTextLength = textParent ? parentDefinesTextLength(textParent) : false;
442a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
443a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    const SVGRenderStyle* svgStyle = style->svgStyle();
444a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    ASSERT(svgStyle);
445a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
4462bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_visualMetricsListOffset = 0;
4472bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_visualCharacterOffset = 0;
448a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
4492bde8e466a4451c7319e3a072d118917957d6554Steve Block    Vector<SVGTextMetrics>& textMetricsValues = text->layoutAttributes().textMetricsValues();
450a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    const UChar* characters = text->characters();
451a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
452a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    const Font& font = style->font();
453a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    SVGTextLayoutEngineSpacing spacingLayout(font);
454a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    SVGTextLayoutEngineBaseline baselineLayout(font);
455a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
456a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    bool didStartTextFragment = false;
457a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    bool applySpacingToNextCharacter = false;
458a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
459a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    float lastAngle = 0;
460a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    float baselineShift = baselineLayout.calculateBaselineShift(svgStyle, lengthContext);
461a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    baselineShift -= baselineLayout.calculateAlignmentBaselineShift(m_isVerticalText, text);
462a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
463a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // Main layout algorithm.
4642bde8e466a4451c7319e3a072d118917957d6554Steve Block    while (true) {
4652bde8e466a4451c7319e3a072d118917957d6554Steve Block        // Find the start of the current text box in this list, respecting ligatures.
4662bde8e466a4451c7319e3a072d118917957d6554Steve Block        SVGTextMetrics visualMetrics = SVGTextMetrics::emptyMetrics();
4672bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (!currentVisualCharacterMetrics(textBox, text, visualMetrics))
4682bde8e466a4451c7319e3a072d118917957d6554Steve Block            break;
4692bde8e466a4451c7319e3a072d118917957d6554Steve Block
4702bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (visualMetrics == SVGTextMetrics::emptyMetrics()) {
4712bde8e466a4451c7319e3a072d118917957d6554Steve Block            advanceToNextVisualCharacter(visualMetrics);
472a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            continue;
473a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        }
474a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
4752bde8e466a4451c7319e3a072d118917957d6554Steve Block        SVGTextLayoutAttributes logicalAttributes;
4762bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (!currentLogicalCharacterAttributes(logicalAttributes))
477a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            break;
478a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
4792bde8e466a4451c7319e3a072d118917957d6554Steve Block        SVGTextMetrics logicalMetrics = SVGTextMetrics::emptyMetrics();
4802bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (!currentLogicalCharacterMetrics(logicalAttributes, logicalMetrics))
4812bde8e466a4451c7319e3a072d118917957d6554Steve Block            break;
482a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
4832bde8e466a4451c7319e3a072d118917957d6554Steve Block        Vector<float>& xValues = logicalAttributes.xValues();
4842bde8e466a4451c7319e3a072d118917957d6554Steve Block        Vector<float>& yValues = logicalAttributes.yValues();
4852bde8e466a4451c7319e3a072d118917957d6554Steve Block        Vector<float>& dxValues = logicalAttributes.dxValues();
4862bde8e466a4451c7319e3a072d118917957d6554Steve Block        Vector<float>& dyValues = logicalAttributes.dyValues();
4872bde8e466a4451c7319e3a072d118917957d6554Steve Block        Vector<float>& rotateValues = logicalAttributes.rotateValues();
4882bde8e466a4451c7319e3a072d118917957d6554Steve Block
4892bde8e466a4451c7319e3a072d118917957d6554Steve Block        float x = xValues.at(m_logicalCharacterOffset);
4902bde8e466a4451c7319e3a072d118917957d6554Steve Block        float y = yValues.at(m_logicalCharacterOffset);
4912bde8e466a4451c7319e3a072d118917957d6554Steve Block
4922bde8e466a4451c7319e3a072d118917957d6554Steve Block        // When we've advanced to the box start offset, determine using the original x/y values,
4932bde8e466a4451c7319e3a072d118917957d6554Steve Block        // whether this character starts a new text chunk, before doing any further processing.
4942bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (m_visualCharacterOffset == textBox->start())
4952bde8e466a4451c7319e3a072d118917957d6554Steve Block            textBox->setStartsNewTextChunk(logicalAttributes.context()->characterStartsNewTextChunk(m_logicalCharacterOffset));
496a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
497a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        float angle = 0;
498a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (!rotateValues.isEmpty()) {
4992bde8e466a4451c7319e3a072d118917957d6554Steve Block            float newAngle = rotateValues.at(m_logicalCharacterOffset);
500a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            if (newAngle != SVGTextLayoutAttributes::emptyValue())
501a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                angle = newAngle;
502a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        }
503a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
504a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        // Calculate glyph orientation angle.
5052bde8e466a4451c7319e3a072d118917957d6554Steve Block        const UChar* currentCharacter = characters + m_visualCharacterOffset;
506a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        float orientationAngle = baselineLayout.calculateGlyphOrientationAngle(m_isVerticalText, svgStyle, *currentCharacter);
507a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
508a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        // Calculate glyph advance & x/y orientation shifts.
509a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        float xOrientationShift = 0;
510a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        float yOrientationShift = 0;
5112bde8e466a4451c7319e3a072d118917957d6554Steve Block        float glyphAdvance = baselineLayout.calculateGlyphAdvanceAndOrientation(m_isVerticalText, visualMetrics, orientationAngle, xOrientationShift, yOrientationShift);
512a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
513a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        // Assign current text position to x/y values, if needed.
514a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        updateCharacerPositionIfNeeded(x, y);
515a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
516a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        // Apply dx/dy value adjustments to current text position, if needed.
5172bde8e466a4451c7319e3a072d118917957d6554Steve Block        updateRelativePositionAdjustmentsIfNeeded(dxValues, dyValues);
518a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
519a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        // Calculate SVG Fonts kerning, if needed.
5202bde8e466a4451c7319e3a072d118917957d6554Steve Block        float kerning = spacingLayout.calculateSVGKerning(m_isVerticalText, visualMetrics.glyph());
521a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
522a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        // Calculate CSS 'kerning', 'letter-spacing' and 'word-spacing' for next character, if needed.
523a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        float spacing = spacingLayout.calculateCSSKerningAndSpacing(svgStyle, lengthContext, currentCharacter);
524a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
525a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        float textPathOffset = 0;
526a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (m_inPathLayout) {
527a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            float scaledGlyphAdvance = glyphAdvance * m_textPathScaling;
528a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            if (m_isVerticalText) {
529a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                // If there's an absolute y position available, it marks the beginning of a new position along the path.
530a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                if (y != SVGTextLayoutAttributes::emptyValue())
531a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                    m_textPathCurrentOffset = y + m_textPathStartOffset;
532a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
533a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                m_textPathCurrentOffset += m_dy - kerning;
534a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                m_dy = 0;
535a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
536a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                // Apply dx/dy correction and setup translations that move to the glyph midpoint.
537a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                xOrientationShift += m_dx + baselineShift;
538a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                yOrientationShift -= scaledGlyphAdvance / 2;
539a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            } else {
540a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                // If there's an absolute x position available, it marks the beginning of a new position along the path.
541a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                if (x != SVGTextLayoutAttributes::emptyValue())
542a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                    m_textPathCurrentOffset = x + m_textPathStartOffset;
543a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
544a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                m_textPathCurrentOffset += m_dx - kerning;
545a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                m_dx = 0;
546a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
547a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                // Apply dx/dy correction and setup translations that move to the glyph midpoint.
548a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                xOrientationShift -= scaledGlyphAdvance / 2;
549a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                yOrientationShift += m_dy - baselineShift;
550a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            }
551a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
552a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            // Calculate current offset along path.
553a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            textPathOffset = m_textPathCurrentOffset + scaledGlyphAdvance / 2;
554a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
555a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            // Move to next character.
556a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            m_textPathCurrentOffset += scaledGlyphAdvance + m_textPathSpacing + spacing * m_textPathScaling;
557a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
558a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            // Skip character, if we're before the path.
559a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            if (textPathOffset < 0) {
5602bde8e466a4451c7319e3a072d118917957d6554Steve Block                advanceToNextLogicalCharacter(logicalMetrics);
5612bde8e466a4451c7319e3a072d118917957d6554Steve Block                advanceToNextVisualCharacter(visualMetrics);
562a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                continue;
563a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            }
564a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
565a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            // Stop processing, if the next character lies behind the path.
566a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            if (textPathOffset > m_textPathLength)
567a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                break;
568a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
569a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            bool ok = false;
570a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            FloatPoint point = m_textPath.pointAtLength(textPathOffset, ok);
571a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            ASSERT(ok);
572a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
573a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            x = point.x();
574a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            y = point.y();
575a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            angle = m_textPath.normalAngleAtLength(textPathOffset, ok);
576a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            ASSERT(ok);
577a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
578a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            // For vertical text on path, the actual angle has to be rotated 90 degrees anti-clockwise, not the orientation angle!
579a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            if (m_isVerticalText)
580a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                angle -= 90;
581a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        } else {
582a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            // Apply all previously calculated shift values.
583a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            if (m_isVerticalText) {
584a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                x += baselineShift;
585a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                y -= kerning;
586a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            } else {
587a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                x -= kerning;
588a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                y -= baselineShift;
589a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            }
590a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
591a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            x += m_dx;
592a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            y += m_dy;
593a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        }
594a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
595a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        // Determine wheter we have to start a new fragment.
596a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        bool shouldStartNewFragment = false;
597a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
598a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (m_dx || m_dy)
599a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            shouldStartNewFragment = true;
600a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
601a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (!shouldStartNewFragment && (m_isVerticalText || m_inPathLayout))
602a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            shouldStartNewFragment = true;
603a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
604a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (!shouldStartNewFragment && (angle || angle != lastAngle || orientationAngle))
605a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            shouldStartNewFragment = true;
606a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
607a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (!shouldStartNewFragment && (kerning || applySpacingToNextCharacter || definesTextLength))
608a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            shouldStartNewFragment = true;
609a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
610a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        // If we already started a fragment, close it now.
611a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (didStartTextFragment && shouldStartNewFragment) {
612a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            applySpacingToNextCharacter = false;
6132bde8e466a4451c7319e3a072d118917957d6554Steve Block            recordTextFragment(textBox, textMetricsValues);
614a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        }
615a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
616a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        // Eventually start a new fragment, if not yet done.
617a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (!didStartTextFragment || shouldStartNewFragment) {
6182bde8e466a4451c7319e3a072d118917957d6554Steve Block            ASSERT(!m_currentTextFragment.characterOffset);
619a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            ASSERT(!m_currentTextFragment.length);
620a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
621a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            didStartTextFragment = true;
6222bde8e466a4451c7319e3a072d118917957d6554Steve Block            m_currentTextFragment.characterOffset = m_visualCharacterOffset;
6232bde8e466a4451c7319e3a072d118917957d6554Steve Block            m_currentTextFragment.metricsListOffset = m_visualMetricsListOffset;
624a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            m_currentTextFragment.x = x;
625a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            m_currentTextFragment.y = y;
626a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
627a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            // Build fragment transformation.
628a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            if (angle)
629a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                m_currentTextFragment.transform.rotate(angle);
630a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
631a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            if (xOrientationShift || yOrientationShift)
632a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                m_currentTextFragment.transform.translate(xOrientationShift, yOrientationShift);
633a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
634a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            if (orientationAngle)
635a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                m_currentTextFragment.transform.rotate(orientationAngle);
636a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
6372daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            m_currentTextFragment.isTextOnPath = m_inPathLayout && m_textPathScaling != 1;
6382daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            if (m_currentTextFragment.isTextOnPath) {
639a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                if (m_isVerticalText)
6402daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                    m_currentTextFragment.lengthAdjustTransform.scaleNonUniform(1, m_textPathScaling);
641a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                else
6422daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                    m_currentTextFragment.lengthAdjustTransform.scaleNonUniform(m_textPathScaling, 1);
643a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            }
644a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        }
645a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
646a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        // Update current text position, after processing of the current character finished.
647a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (m_inPathLayout)
648a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            updateCurrentTextPosition(x, y, glyphAdvance);
649a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        else {
650a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            // Apply CSS 'kerning', 'letter-spacing' and 'word-spacing' to next character, if needed.
651a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            if (spacing)
652a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                applySpacingToNextCharacter = true;
653a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
654a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            float xNew = x - m_dx;
655a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            float yNew = y - m_dy;
656a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
657a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            if (m_isVerticalText)
658a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                xNew -= baselineShift;
659a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            else
660a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                yNew += baselineShift;
661a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
662a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            updateCurrentTextPosition(xNew, yNew, glyphAdvance + spacing);
663a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        }
664a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
6652bde8e466a4451c7319e3a072d118917957d6554Steve Block        advanceToNextLogicalCharacter(logicalMetrics);
6662bde8e466a4451c7319e3a072d118917957d6554Steve Block        advanceToNextVisualCharacter(visualMetrics);
667a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        lastAngle = angle;
668a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
669a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
670a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (!didStartTextFragment)
671a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return;
672a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
673a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // Close last open fragment, if needed.
6742bde8e466a4451c7319e3a072d118917957d6554Steve Block    recordTextFragment(textBox, textMetricsValues);
675a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
676a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
677a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
678a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
679a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#endif // ENABLE(SVG)
680