15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* 25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) Research In Motion Limited 2010-2012. All rights reserved. 35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This library is free software; you can redistribute it and/or 55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modify it under the terms of the GNU Library General Public 65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * License as published by the Free Software Foundation; either 75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * version 2 of the License, or (at your option) any later version. 85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This library is distributed in the hope that it will be useful, 105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * but WITHOUT ANY WARRANTY; without even the implied warranty of 115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Library General Public License for more details. 135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * You should have received a copy of the GNU Library General Public License 155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * along with this library; see the file COPYING.LIB. If not, write to 165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Boston, MA 02110-1301, USA. 185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */ 195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h" 2153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/svg/SVGTextQuery.h" 225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/InlineFlowBox.h" 24197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#include "core/rendering/RenderBlockFlow.h" 2553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/RenderInline.h" 2653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/svg/RenderSVGInlineText.h" 2753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/svg/SVGInlineTextBox.h" 2853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/svg/SVGTextMetrics.h" 291e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/FloatConversion.h" 3002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch#include "wtf/MathExtras.h" 315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 32c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink { 335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Base structure for callback user data 355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)struct SVGTextQuery::Data { 365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Data() 375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) : isVerticalText(false) 385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , processedCharacters(0) 395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , textRenderer(0) 405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , textBox(0) 415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) { 425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) bool isVerticalText; 455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) unsigned processedCharacters; 465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RenderSVGInlineText* textRenderer; 475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const SVGInlineTextBox* textBox; 485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}; 495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static inline InlineFlowBox* flowBoxForRenderer(RenderObject* renderer) 515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!renderer) 535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return 0; 545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (renderer->isRenderBlock()) { 565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // If we're given a block element, it has to be a RenderSVGText. 575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(renderer->isSVGText()); 58197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch RenderBlockFlow* renderBlockFlow = toRenderBlockFlow(renderer); 595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // RenderSVGText only ever contains a single line box. 61197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch InlineFlowBox* flowBox = renderBlockFlow->firstLineBox(); 62197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch ASSERT(flowBox == renderBlockFlow->lastLineBox()); 635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return flowBox; 645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (renderer->isRenderInline()) { 675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // We're given a RenderSVGInline or objects that derive from it (RenderSVGTSpan / RenderSVGTextPath) 685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RenderInline* renderInline = toRenderInline(renderer); 695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // RenderSVGInline only ever contains a single line box. 715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) InlineFlowBox* flowBox = renderInline->firstLineBox(); 725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(flowBox == renderInline->lastLineBox()); 735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return flowBox; 745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT_NOT_REACHED(); 775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return 0; 785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)SVGTextQuery::SVGTextQuery(RenderObject* renderer) 815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) collectTextBoxesInFlowBox(flowBoxForRenderer(renderer)); 835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void SVGTextQuery::collectTextBoxesInFlowBox(InlineFlowBox* flowBox) 865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!flowBox) 885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (InlineBox* child = flowBox->firstChild(); child; child = child->nextOnLine()) { 915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (child->isInlineFlowBox()) { 925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Skip generated content. 93d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) if (!child->renderer().node()) 945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) continue; 955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 9606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) collectTextBoxesInFlowBox(toInlineFlowBox(child)); 975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) continue; 985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (child->isSVGInlineTextBox()) 101591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch m_textBoxes.append(toSVGInlineTextBox(child)); 1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool SVGTextQuery::executeQuery(Data* queryData, ProcessTextFragmentCallback fragmentCallback) const 1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) unsigned processedCharacters = 0; 1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) unsigned textBoxCount = m_textBoxes.size(); 1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Loop over all text boxes 1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (unsigned textBoxPosition = 0; textBoxPosition < textBoxCount; ++textBoxPosition) { 1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) queryData->textBox = m_textBoxes.at(textBoxPosition); 113c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) queryData->textRenderer = &toRenderSVGInlineText(queryData->textBox->renderer()); 1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(queryData->textRenderer->style()); 1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 116197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch queryData->isVerticalText = queryData->textRenderer->style()->svgStyle().isVerticalWritingMode(); 1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const Vector<SVGTextFragment>& fragments = queryData->textBox->textFragments(); 11802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch 1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Loop over all text fragments in this text box, firing a callback for each. 1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) unsigned fragmentCount = fragments.size(); 1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (unsigned i = 0; i < fragmentCount; ++i) { 1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const SVGTextFragment& fragment = fragments.at(i); 1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if ((this->*fragmentCallback)(queryData, fragment)) 1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) processedCharacters += fragment.length; 1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) queryData->processedCharacters = processedCharacters; 1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool SVGTextQuery::mapStartEndPositionsIntoFragmentCoordinates(Data* queryData, const SVGTextFragment& fragment, int& startPosition, int& endPosition) const 1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Reuse the same logic used for text selection & painting, to map our query start/length into start/endPositions of the current text fragment. 1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) startPosition -= queryData->processedCharacters; 1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) endPosition -= queryData->processedCharacters; 1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 141197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // <startPosition, endPosition> is now a tuple of offsets relative to the current text box. 142197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // Compute the offsets of the fragment in the same offset space. 143197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch int fragmentStartInBox = fragment.characterOffset - queryData->textBox->start(); 144197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch int fragmentEndInBox = fragmentStartInBox + fragment.length; 145197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 146197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // Check if the ranges intersect. 147197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch startPosition = std::max(startPosition, fragmentStartInBox); 148197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch endPosition = std::min(endPosition, fragmentEndInBox); 14907a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch 15007a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch if (startPosition >= endPosition) 1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 153197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch modifyStartEndPositionsRespectingLigatures(queryData, fragment, startPosition, endPosition); 1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!queryData->textBox->mapStartEndPositionsIntoFragmentCoordinates(fragment, startPosition, endPosition)) 1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(startPosition < endPosition); 1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 161197021e6b966cfb06891637935ef33fff06433d1Ben Murdochvoid SVGTextQuery::modifyStartEndPositionsRespectingLigatures(Data* queryData, const SVGTextFragment& fragment, int& startPosition, int& endPosition) const 1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) SVGTextLayoutAttributes* layoutAttributes = queryData->textRenderer->layoutAttributes(); 1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Vector<SVGTextMetrics>& textMetricsValues = layoutAttributes->textMetricsValues(); 1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 166197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch unsigned textMetricsOffset = fragment.metricsListOffset; 1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 168197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // Compute the offset of the fragment within the box, since that's the 169197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // space <startPosition, endPosition> is in (and that's what we need). 170197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch int fragmentOffsetInBox = fragment.characterOffset - queryData->textBox->start(); 171197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch int fragmentEndInBox = fragmentOffsetInBox + fragment.length; 1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 173197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // Find the text metrics cell that start at or contain the character startPosition. 174197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch while (fragmentOffsetInBox < fragmentEndInBox) { 1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) SVGTextMetrics& metrics = textMetricsValues[textMetricsOffset]; 176197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch int glyphEnd = fragmentOffsetInBox + metrics.length(); 177197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch if (startPosition < glyphEnd) 1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) break; 179197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch fragmentOffsetInBox = glyphEnd; 180197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch textMetricsOffset++; 181197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch } 1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 183197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch startPosition = fragmentOffsetInBox; 1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 185197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // Find the text metrics cell that contain or ends at the character endPosition. 186197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch while (fragmentOffsetInBox < fragmentEndInBox) { 187197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch SVGTextMetrics& metrics = textMetricsValues[textMetricsOffset]; 188197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch fragmentOffsetInBox += metrics.length(); 189197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch if (fragmentOffsetInBox >= endPosition) 1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) break; 191197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch textMetricsOffset++; 1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 194197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch endPosition = fragmentOffsetInBox; 1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// numberOfCharacters() implementation 1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool SVGTextQuery::numberOfCharactersCallback(Data*, const SVGTextFragment&) const 1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // no-op 2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)unsigned SVGTextQuery::numberOfCharacters() const 2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Data data; 2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) executeQuery(&data, &SVGTextQuery::numberOfCharactersCallback); 2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return data.processedCharacters; 2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// textLength() implementation 2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)struct TextLengthData : SVGTextQuery::Data { 2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) TextLengthData() 2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) : textLength(0) 2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) { 2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) float textLength; 2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}; 2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool SVGTextQuery::textLengthCallback(Data* queryData, const SVGTextFragment& fragment) const 2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) TextLengthData* data = static_cast<TextLengthData*>(queryData); 2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) data->textLength += queryData->isVerticalText ? fragment.height : fragment.width; 2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)float SVGTextQuery::textLength() const 2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) TextLengthData data; 2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) executeQuery(&data, &SVGTextQuery::textLengthCallback); 2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return data.textLength; 2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// subStringLength() implementation 2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)struct SubStringLengthData : SVGTextQuery::Data { 2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) SubStringLengthData(unsigned queryStartPosition, unsigned queryLength) 2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) : startPosition(queryStartPosition) 2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , length(queryLength) 2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , subStringLength(0) 2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) { 2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) unsigned startPosition; 2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) unsigned length; 2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) float subStringLength; 2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}; 2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool SVGTextQuery::subStringLengthCallback(Data* queryData, const SVGTextFragment& fragment) const 2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) SubStringLengthData* data = static_cast<SubStringLengthData*>(queryData); 2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int startPosition = data->startPosition; 2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int endPosition = startPosition + data->length; 2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition)) 2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset + startPosition, endPosition - startPosition); 2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) data->subStringLength += queryData->isVerticalText ? metrics.height() : metrics.width(); 2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)float SVGTextQuery::subStringLength(unsigned startPosition, unsigned length) const 2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) SubStringLengthData data(startPosition, length); 2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) executeQuery(&data, &SVGTextQuery::subStringLengthCallback); 2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return data.subStringLength; 2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// startPositionOfCharacter() implementation 2725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)struct StartPositionOfCharacterData : SVGTextQuery::Data { 2735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) StartPositionOfCharacterData(unsigned queryPosition) 2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) : position(queryPosition) 2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) { 2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) unsigned position; 2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) FloatPoint startPosition; 2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}; 2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool SVGTextQuery::startPositionOfCharacterCallback(Data* queryData, const SVGTextFragment& fragment) const 2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) StartPositionOfCharacterData* data = static_cast<StartPositionOfCharacterData*>(queryData); 2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int startPosition = data->position; 2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int endPosition = startPosition + 1; 2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition)) 2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) data->startPosition = FloatPoint(fragment.x, fragment.y); 2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (startPosition) { 2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset, startPosition); 2955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (queryData->isVerticalText) 2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) data->startPosition.move(0, metrics.height()); 2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else 2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) data->startPosition.move(metrics.width(), 0); 2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) AffineTransform fragmentTransform; 3025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) fragment.buildFragmentTransform(fragmentTransform, SVGTextFragment::TransformIgnoringTextLength); 3035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (fragmentTransform.isIdentity()) 3045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 3055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) data->startPosition = fragmentTransform.mapPoint(data->startPosition); 3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 3085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 3095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)FloatPoint SVGTextQuery::startPositionOfCharacter(unsigned position) const 3115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 3125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) StartPositionOfCharacterData data(position); 3135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) executeQuery(&data, &SVGTextQuery::startPositionOfCharacterCallback); 3145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return data.startPosition; 3155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 3165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// endPositionOfCharacter() implementation 3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)struct EndPositionOfCharacterData : SVGTextQuery::Data { 3195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) EndPositionOfCharacterData(unsigned queryPosition) 3205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) : position(queryPosition) 3215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) { 3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 3235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) unsigned position; 3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) FloatPoint endPosition; 3265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}; 3275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool SVGTextQuery::endPositionOfCharacterCallback(Data* queryData, const SVGTextFragment& fragment) const 3295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 3305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) EndPositionOfCharacterData* data = static_cast<EndPositionOfCharacterData*>(queryData); 3315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int startPosition = data->position; 3335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int endPosition = startPosition + 1; 3345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition)) 3355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 3365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) data->endPosition = FloatPoint(fragment.x, fragment.y); 3385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset, startPosition + 1); 3405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (queryData->isVerticalText) 3415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) data->endPosition.move(0, metrics.height()); 3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else 3435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) data->endPosition.move(metrics.width(), 0); 3445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) AffineTransform fragmentTransform; 3465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) fragment.buildFragmentTransform(fragmentTransform, SVGTextFragment::TransformIgnoringTextLength); 3475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (fragmentTransform.isIdentity()) 3485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) data->endPosition = fragmentTransform.mapPoint(data->endPosition); 3515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 3525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 3535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)FloatPoint SVGTextQuery::endPositionOfCharacter(unsigned position) const 3555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 3565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) EndPositionOfCharacterData data(position); 3575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) executeQuery(&data, &SVGTextQuery::endPositionOfCharacterCallback); 3585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return data.endPosition; 3595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 3605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// rotationOfCharacter() implementation 3625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)struct RotationOfCharacterData : SVGTextQuery::Data { 3635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RotationOfCharacterData(unsigned queryPosition) 3645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) : position(queryPosition) 3655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , rotation(0) 3665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) { 3675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 3685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) unsigned position; 3705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) float rotation; 3715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}; 3725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool SVGTextQuery::rotationOfCharacterCallback(Data* queryData, const SVGTextFragment& fragment) const 3745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 3755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RotationOfCharacterData* data = static_cast<RotationOfCharacterData*>(queryData); 3765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int startPosition = data->position; 3785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int endPosition = startPosition + 1; 3795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition)) 3805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 3815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) AffineTransform fragmentTransform; 3835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) fragment.buildFragmentTransform(fragmentTransform, SVGTextFragment::TransformIgnoringTextLength); 3845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (fragmentTransform.isIdentity()) 3855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) data->rotation = 0; 3865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else { 3875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) fragmentTransform.scale(1 / fragmentTransform.xScale(), 1 / fragmentTransform.yScale()); 3885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) data->rotation = narrowPrecisionToFloat(rad2deg(atan2(fragmentTransform.b(), fragmentTransform.a()))); 3895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 3905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 3925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 3935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)float SVGTextQuery::rotationOfCharacter(unsigned position) const 3955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 3965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RotationOfCharacterData data(position); 3975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) executeQuery(&data, &SVGTextQuery::rotationOfCharacterCallback); 3985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return data.rotation; 3995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 4005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// extentOfCharacter() implementation 4025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)struct ExtentOfCharacterData : SVGTextQuery::Data { 4035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ExtentOfCharacterData(unsigned queryPosition) 4045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) : position(queryPosition) 4055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) { 4065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 4075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) unsigned position; 4095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) FloatRect extent; 4105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}; 4115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static inline void calculateGlyphBoundaries(SVGTextQuery::Data* queryData, const SVGTextFragment& fragment, int startPosition, FloatRect& extent) 4135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 4145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) float scalingFactor = queryData->textRenderer->scalingFactor(); 4155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(scalingFactor); 4165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) extent.setLocation(FloatPoint(fragment.x, fragment.y - queryData->textRenderer->scaledFont().fontMetrics().floatAscent() / scalingFactor)); 4185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (startPosition) { 4205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset, startPosition); 4215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (queryData->isVerticalText) 4225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) extent.move(0, metrics.height()); 4235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else 4245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) extent.move(metrics.width(), 0); 4255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 4265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset + startPosition, 1); 4285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) extent.setSize(FloatSize(metrics.width(), metrics.height())); 4295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) AffineTransform fragmentTransform; 4315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) fragment.buildFragmentTransform(fragmentTransform, SVGTextFragment::TransformIgnoringTextLength); 4325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) extent = fragmentTransform.mapRect(extent); 4345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 4355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 436197021e6b966cfb06891637935ef33fff06433d1Ben Murdochstatic inline FloatRect calculateFragmentBoundaries(const RenderSVGInlineText& textRenderer, const SVGTextFragment& fragment) 437197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch{ 438197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch float scalingFactor = textRenderer.scalingFactor(); 439197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch ASSERT(scalingFactor); 440197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch float baseline = textRenderer.scaledFont().fontMetrics().floatAscent() / scalingFactor; 441197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 442197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch AffineTransform fragmentTransform; 443197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height); 444197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch fragment.buildFragmentTransform(fragmentTransform); 445197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch return fragmentTransform.mapRect(fragmentRect); 446197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch} 447197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 4485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool SVGTextQuery::extentOfCharacterCallback(Data* queryData, const SVGTextFragment& fragment) const 4495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 4505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ExtentOfCharacterData* data = static_cast<ExtentOfCharacterData*>(queryData); 4515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int startPosition = data->position; 4535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int endPosition = startPosition + 1; 4545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition)) 4555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 4565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) calculateGlyphBoundaries(queryData, fragment, startPosition, data->extent); 4585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 4595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 4605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 46109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)FloatRect SVGTextQuery::extentOfCharacter(unsigned position) const 4625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 4635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ExtentOfCharacterData data(position); 4645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) executeQuery(&data, &SVGTextQuery::extentOfCharacterCallback); 4655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return data.extent; 4665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 4675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// characterNumberAtPosition() implementation 4695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)struct CharacterNumberAtPositionData : SVGTextQuery::Data { 4705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) CharacterNumberAtPositionData(const FloatPoint& queryPosition) 4715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) : position(queryPosition) 4725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) { 4735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 4745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) FloatPoint position; 4765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}; 4775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool SVGTextQuery::characterNumberAtPositionCallback(Data* queryData, const SVGTextFragment& fragment) const 4795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 4805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) CharacterNumberAtPositionData* data = static_cast<CharacterNumberAtPositionData*>(queryData); 4815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 482197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // Test the query point against the bounds of the entire fragment first. 483197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch FloatRect fragmentExtents = calculateFragmentBoundaries(*queryData->textRenderer, fragment); 484197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch if (!fragmentExtents.contains(data->position)) 485197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch return false; 4865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 487197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // Iterate through the glyphs in this fragment, and check if their extents 488197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // contain the query point. 489197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch FloatRect extent; 490197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch const Vector<SVGTextMetrics>& textMetrics = queryData->textRenderer->layoutAttributes()->textMetricsValues(); 491197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch unsigned textMetricsOffset = fragment.metricsListOffset; 492197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch unsigned fragmentOffset = 0; 493197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch while (fragmentOffset < fragment.length) { 494197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch calculateGlyphBoundaries(queryData, fragment, fragmentOffset, extent); 4955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (extent.contains(data->position)) { 496197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // Compute the character offset of the glyph within the text box 497197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // and add to processedCharacters. 498197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch unsigned characterOffset = fragment.characterOffset + fragmentOffset; 499197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch data->processedCharacters += characterOffset - data->textBox->start(); 5005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 5015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 502197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch fragmentOffset += textMetrics[textMetricsOffset].length(); 503197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch textMetricsOffset++; 5045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 5055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 5065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 5075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 50809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)int SVGTextQuery::characterNumberAtPosition(const FloatPoint& position) const 5095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 5105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) CharacterNumberAtPositionData data(position); 5115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!executeQuery(&data, &SVGTextQuery::characterNumberAtPositionCallback)) 5125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return -1; 5135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return data.processedCharacters; 5155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 5165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 518