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