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