1/*
2 * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
3 * Copyright (C) 2006 Apple Computer Inc.
4 * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
5 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB.  If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23#include "config.h"
24#include "SVGInlineFlowBox.h"
25
26#if ENABLE(SVG)
27#include "DocumentMarkerController.h"
28#include "GraphicsContext.h"
29#include "RenderSVGInlineText.h"
30#include "RenderedDocumentMarker.h"
31#include "SVGInlineTextBox.h"
32#include "SVGRenderingContext.h"
33
34using namespace std;
35
36namespace WebCore {
37
38void SVGInlineFlowBox::paintSelectionBackground(PaintInfo& paintInfo)
39{
40    ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection);
41    ASSERT(!paintInfo.context->paintingDisabled());
42
43    PaintInfo childPaintInfo(paintInfo);
44    for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) {
45        if (child->isSVGInlineTextBox())
46            static_cast<SVGInlineTextBox*>(child)->paintSelectionBackground(childPaintInfo);
47        else if (child->isSVGInlineFlowBox())
48            static_cast<SVGInlineFlowBox*>(child)->paintSelectionBackground(childPaintInfo);
49    }
50}
51
52void SVGInlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUnit, LayoutUnit)
53{
54    ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection);
55    ASSERT(!paintInfo.context->paintingDisabled());
56
57    RenderObject* boxRenderer = renderer();
58    ASSERT(boxRenderer);
59
60    SVGRenderingContext renderingContext(boxRenderer, paintInfo, SVGRenderingContext::SaveGraphicsContext);
61    if (renderingContext.isRenderingPrepared()) {
62        for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) {
63            if (child->isSVGInlineTextBox())
64                computeTextMatchMarkerRectForRenderer(toRenderSVGInlineText(static_cast<SVGInlineTextBox*>(child)->textRenderer()));
65
66            child->paint(paintInfo, LayoutPoint(), 0, 0);
67        }
68    }
69}
70
71FloatRect SVGInlineFlowBox::calculateBoundaries() const
72{
73    FloatRect childRect;
74    for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) {
75        if (!child->isSVGInlineTextBox() && !child->isSVGInlineFlowBox())
76            continue;
77        childRect.unite(child->calculateBoundaries());
78    }
79    return childRect;
80}
81
82void SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(RenderSVGInlineText* textRenderer)
83{
84    ASSERT(textRenderer);
85
86    Node* node = textRenderer->node();
87    if (!node || !node->inDocument())
88        return;
89
90    RenderStyle* style = textRenderer->style();
91    ASSERT(style);
92
93    AffineTransform fragmentTransform;
94    Document* document = textRenderer->document();
95    Vector<DocumentMarker*> markers = document->markers()->markersFor(textRenderer->node());
96
97    Vector<DocumentMarker*>::iterator markerEnd = markers.end();
98    for (Vector<DocumentMarker*>::iterator markerIt = markers.begin(); markerIt != markerEnd; ++markerIt) {
99        DocumentMarker* marker = *markerIt;
100
101        // SVG is only interessted in the TextMatch marker, for now.
102        if (marker->type() != DocumentMarker::TextMatch)
103            continue;
104
105        FloatRect markerRect;
106        for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
107            if (!box->isSVGInlineTextBox())
108                continue;
109
110            SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(box);
111
112            int markerStartPosition = max<int>(marker->startOffset() - textBox->start(), 0);
113            int markerEndPosition = min<int>(marker->endOffset() - textBox->start(), textBox->len());
114
115            if (markerStartPosition >= markerEndPosition)
116                continue;
117
118            int fragmentStartPosition = 0;
119            int fragmentEndPosition = 0;
120
121            const Vector<SVGTextFragment>& fragments = textBox->textFragments();
122            unsigned textFragmentsSize = fragments.size();
123            for (unsigned i = 0; i < textFragmentsSize; ++i) {
124                const SVGTextFragment& fragment = fragments.at(i);
125
126                fragmentStartPosition = markerStartPosition;
127                fragmentEndPosition = markerEndPosition;
128                if (!textBox->mapStartEndPositionsIntoFragmentCoordinates(fragment, fragmentStartPosition, fragmentEndPosition))
129                    continue;
130
131                FloatRect fragmentRect = textBox->selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style);
132                fragment.buildFragmentTransform(fragmentTransform);
133                if (!fragmentTransform.isIdentity())
134                    fragmentRect = fragmentTransform.mapRect(fragmentRect);
135
136                markerRect.unite(fragmentRect);
137            }
138        }
139
140        toRenderedDocumentMarker(marker)->setRenderedRect(textRenderer->localToAbsoluteQuad(markerRect).enclosingBoundingBox());
141    }
142}
143
144} // namespace WebCore
145
146#endif // ENABLE(SVG)
147