~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2009-11-02 18:30:08 UTC
  • mfrom: (1.2.2 upstream)
  • mto: (15.2.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 88.
  • Revision ID: james.westby@ubuntu.com-20091102183008-b6a4gcs128mvfb3m
Tags: upstream-4.6.0~beta1
ImportĀ upstreamĀ versionĀ 4.6.0~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
    Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
3
3
                  2004, 2005, 2007, 2008, 2009 Rob Buis <buis@kde.org>
4
4
                  2007 Eric Seidel <eric@webkit.org>
5
 
 
6
 
    This file is part of the KDE project
 
5
                  2009 Google, Inc.
7
6
 
8
7
    This library is free software; you can redistribute it and/or
9
8
    modify it under the terms of the GNU Library General Public
27
26
#include "RenderSVGRoot.h"
28
27
 
29
28
#include "GraphicsContext.h"
30
 
#include "RenderPath.h"
31
29
#include "RenderSVGContainer.h"
32
30
#include "RenderView.h"
33
31
#include "SVGLength.h"
34
32
#include "SVGRenderSupport.h"
35
 
#include "SVGResourceClipper.h"
36
 
#include "SVGResourceFilter.h"
37
 
#include "SVGResourceMasker.h"
38
33
#include "SVGSVGElement.h"
39
34
#include "SVGStyledElement.h"
40
 
#include "SVGURIReference.h"
 
35
#include "TransformState.h"
 
36
 
 
37
#if ENABLE(FILTERS)
 
38
#include "SVGResourceFilter.h"
 
39
#endif
41
40
 
42
41
using namespace std;
43
42
 
44
43
namespace WebCore {
45
44
 
46
45
RenderSVGRoot::RenderSVGRoot(SVGStyledElement* node)
47
 
    : RenderContainer(node)
 
46
    : RenderBox(node)
48
47
{
49
48
    setReplaced(true);
50
49
}
51
50
 
52
 
RenderSVGRoot::~RenderSVGRoot()
53
 
{
54
 
}
55
 
 
56
51
int RenderSVGRoot::lineHeight(bool, bool) const
57
52
{
58
53
    return height() + marginTop() + marginBottom();
86
81
{
87
82
    ASSERT(needsLayout());
88
83
 
89
 
    calcViewport();
90
 
 
91
84
    // Arbitrary affine transforms are incompatible with LayoutState.
92
85
    view()->disableLayoutState();
93
86
 
94
 
    IntRect oldBounds = m_absoluteBounds;
95
 
    IntRect oldOutlineBox;
96
 
    bool checkForRepaint = checkForRepaintDuringLayout() && selfNeedsLayout();
97
 
    if (checkForRepaint)
98
 
        oldOutlineBox = absoluteOutlineBounds();
 
87
    LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && selfNeedsLayout());
99
88
 
100
89
    calcWidth();
101
90
    calcHeight();
102
91
 
103
 
    m_absoluteBounds = absoluteClippedOverflowRect();
104
 
    SVGSVGElement* svg = static_cast<SVGSVGElement*>(element());
105
 
    m_width = static_cast<int>(m_width * svg->currentScale());
106
 
    m_height = static_cast<int>(m_height * svg->currentScale());
 
92
    SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
 
93
    setWidth(static_cast<int>(width() * svg->currentScale()));
 
94
    setHeight(static_cast<int>(height() * svg->currentScale()));
 
95
 
 
96
    calcViewport();
107
97
    
108
98
    for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
109
99
        if (selfNeedsLayout()) // either bounds or transform changed, force kids to relayout
110
 
            child->setNeedsLayout(true);
 
100
            child->setNeedsLayout(true, false);
111
101
        
112
102
        child->layoutIfNeeded();
113
103
        ASSERT(!child->needsLayout());
114
104
    }
115
105
 
116
 
    if (checkForRepaint)
117
 
        repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
 
106
    repainter.repaintAfterLayout();
118
107
 
119
108
    view()->enableLayoutState();
120
109
    setNeedsLayout(false);
121
110
}
122
111
 
123
 
void RenderSVGRoot::applyContentTransforms(PaintInfo& paintInfo, int parentX, int parentY)
 
112
bool RenderSVGRoot::selfWillPaint() const
124
113
{
125
 
    // Translate from parent offsets (html renderers) to a relative transform (svg renderers)
126
 
    IntPoint origin;
127
 
    origin.move(parentX, parentY);
128
 
    origin.move(m_x, m_y);
129
 
    origin.move(borderLeft(), borderTop());
130
 
    origin.move(paddingLeft(), paddingTop());
131
 
 
132
 
    if (origin.x() || origin.y()) {
133
 
        paintInfo.context->concatCTM(TransformationMatrix().translate(origin.x(), origin.y()));
134
 
        paintInfo.rect.move(-origin.x(), -origin.y());
135
 
    }
136
 
 
137
 
    // Respect scroll offset caused by html parents
138
 
    TransformationMatrix ctm = RenderContainer::absoluteTransform();
139
 
    paintInfo.rect.move(static_cast<int>(ctm.e()), static_cast<int>(ctm.f()));
140
 
 
141
 
    SVGSVGElement* svg = static_cast<SVGSVGElement*>(element());
142
 
    paintInfo.context->concatCTM(TransformationMatrix().scale(svg->currentScale()));
143
 
 
144
 
    if (!viewport().isEmpty()) {
145
 
        if (style()->overflowX() != OVISIBLE)
146
 
            paintInfo.context->clip(enclosingIntRect(viewport())); // FIXME: Eventually we'll want float-precision clipping
147
 
        
148
 
        paintInfo.context->concatCTM(TransformationMatrix().translate(viewport().x(), viewport().y()));
149
 
    }
150
 
 
151
 
    paintInfo.context->concatCTM(TransformationMatrix().translate(svg->currentTranslate().x(), svg->currentTranslate().y()));
 
114
#if ENABLE(FILTERS)
 
115
    const SVGRenderStyle* svgStyle = style()->svgStyle();
 
116
    SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter());
 
117
    if (filter)
 
118
        return true;
 
119
#endif
 
120
    return false;
152
121
}
153
122
 
154
123
void RenderSVGRoot::paint(PaintInfo& paintInfo, int parentX, int parentY)
156
125
    if (paintInfo.context->paintingDisabled())
157
126
        return;
158
127
 
159
 
    calcViewport();
160
 
 
161
 
    SVGSVGElement* svg = static_cast<SVGSVGElement*>(element());
162
 
    // A value of zero disables rendering of the element. 
163
 
    if (viewport().width() <= 0. || viewport().height() <= 0.)
164
 
        return;
165
 
 
166
 
    // This should only exist for <svg> renderers
 
128
    IntPoint parentOriginInContainer(parentX, parentY);
 
129
    IntPoint borderBoxOriginInContainer = parentOriginInContainer + IntSize(x(), y());
 
130
 
167
131
    if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) 
168
 
        paintBoxDecorations(paintInfo, m_x + parentX, m_y + parentY);
169
 
 
170
 
    if (!firstChild()) {
171
 
#if ENABLE(SVG_FILTERS)
172
 
        // Spec: groups w/o children still may render filter content.
173
 
        const SVGRenderStyle* svgStyle = style()->svgStyle();
174
 
        SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter());
175
 
        if (!filter)
176
 
#endif
177
 
            return;
178
 
    }
179
 
 
 
132
        paintBoxDecorations(paintInfo, borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y());
 
133
 
 
134
    // An empty viewport disables rendering.  FIXME: Should we still render filters?
 
135
    if (viewportSize().isEmpty())
 
136
        return;
 
137
 
 
138
    // Don't paint if we don't have kids, except if we have filters we should paint those.
 
139
    if (!firstChild() && !selfWillPaint())
 
140
        return;
 
141
 
 
142
    // Make a copy of the PaintInfo because applyTransformToPaintInfo will modify the damage rect.
180
143
    RenderObject::PaintInfo childPaintInfo(paintInfo);
181
144
    childPaintInfo.context->save();
182
 
 
183
 
    applyContentTransforms(childPaintInfo, parentX, parentY);
 
145
 
 
146
    // SVG does not support independent x/y clipping
 
147
    if (style()->overflowX() != OVISIBLE)
 
148
        childPaintInfo.context->clip(overflowClipRect(borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y()));
 
149
 
 
150
    // Convert from container offsets (html renderers) to a relative transform (svg renderers).
 
151
    // Transform from our paint container's coordinate system to our local coords.
 
152
    applyTransformToPaintInfo(childPaintInfo, localToRepaintContainerTransform(parentOriginInContainer));
184
153
 
185
154
    SVGResourceFilter* filter = 0;
186
 
 
187
 
    FloatRect boundingBox = relativeBBox(true);
188
 
    if (childPaintInfo.phase == PaintPhaseForeground)
189
 
        prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter);        
190
 
 
191
 
    childPaintInfo.context->concatCTM(svg->viewBoxToViewTransform(width(), height()));
192
 
    RenderContainer::paint(childPaintInfo, 0, 0);
193
 
 
194
 
    if (childPaintInfo.phase == PaintPhaseForeground)
195
 
        finishRenderSVGContent(this, childPaintInfo, boundingBox, filter, paintInfo.context);
 
155
    FloatRect boundingBox = repaintRectInLocalCoordinates();
 
156
    if (childPaintInfo.phase == PaintPhaseForeground)
 
157
        prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter);
 
158
 
 
159
    RenderBox::paint(childPaintInfo, 0, 0);
 
160
 
 
161
    if (childPaintInfo.phase == PaintPhaseForeground)
 
162
        finishRenderSVGContent(this, childPaintInfo, filter, paintInfo.context);
196
163
 
197
164
    childPaintInfo.context->restore();
198
 
    
199
 
    if ((childPaintInfo.phase == PaintPhaseOutline || childPaintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE)
200
 
        paintOutline(childPaintInfo.context, m_absoluteBounds.x(), m_absoluteBounds.y(), m_absoluteBounds.width(), m_absoluteBounds.height(), style());
 
165
 
 
166
    if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE)
 
167
        paintOutline(paintInfo.context, borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y(), width(), height(), style());
201
168
}
202
169
 
203
 
FloatRect RenderSVGRoot::viewport() const
 
170
const FloatSize& RenderSVGRoot::viewportSize() const
204
171
{
205
 
    return m_viewport;
 
172
    return m_viewportSize;
206
173
}
207
174
 
208
175
void RenderSVGRoot::calcViewport()
209
176
{
210
 
    SVGElement* svgelem = static_cast<SVGElement*>(element());
211
 
    if (svgelem->hasTagName(SVGNames::svgTag)) {
212
 
        SVGSVGElement* svg = static_cast<SVGSVGElement*>(element());
213
 
 
214
 
        if (!selfNeedsLayout() && !svg->hasRelativeValues())
215
 
            return;
216
 
 
217
 
        float w, h;
 
177
    SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
 
178
 
 
179
    if (!selfNeedsLayout() && !svg->hasRelativeValues())
 
180
        return;
 
181
 
 
182
    if (!svg->hasSetContainerSize()) {
 
183
        // In the normal case of <svg> being stand-alone or in a CSSBoxModel object we use
 
184
        // RenderBox::width()/height() (which pulls data from RenderStyle)
 
185
        m_viewportSize = FloatSize(width(), height());
 
186
    } else {
 
187
        // In the SVGImage case grab the SVGLength values off of SVGSVGElement and use
 
188
        // the special relativeWidthValue accessors which respect the specified containerSize
218
189
        SVGLength width = svg->width();
219
 
        if (width.unitType() == LengthTypePercentage && svg->hasSetContainerSize())
220
 
            w = svg->relativeWidthValue();
221
 
        else
222
 
            w = width.value(svg);
223
 
        
224
190
        SVGLength height = svg->height();
225
 
        if (height.unitType() == LengthTypePercentage && svg->hasSetContainerSize())
226
 
            h = svg->relativeHeightValue();
227
 
        else
228
 
            h = height.value(svg);
229
 
 
230
 
        m_viewport = FloatRect(0, 0, w, h);
 
191
        float viewportWidth = (width.unitType() == LengthTypePercentage) ? svg->relativeWidthValue() : width.value(svg);
 
192
        float viewportHeight = (height.unitType() == LengthTypePercentage) ? svg->relativeHeightValue() : height.value(svg);
 
193
        m_viewportSize = FloatSize(viewportWidth, viewportHeight);
231
194
    }
232
195
}
233
196
 
234
 
IntRect RenderSVGRoot::absoluteClippedOverflowRect()
235
 
{
236
 
    IntRect repaintRect;
237
 
 
238
 
    for (RenderObject* current = firstChild(); current != 0; current = current->nextSibling())
239
 
        repaintRect.unite(current->absoluteClippedOverflowRect());
240
 
 
241
 
#if ENABLE(SVG_FILTERS)
242
 
    // Filters can expand the bounding box
243
 
    SVGResourceFilter* filter = getFilterById(document(), style()->svgStyle()->filter());
244
 
    if (filter)
245
 
        repaintRect.unite(enclosingIntRect(filter->filterBBoxForItemBBox(repaintRect)));
246
 
#endif
247
 
 
248
 
    return repaintRect;
249
 
}
250
 
 
251
 
void RenderSVGRoot::addFocusRingRects(GraphicsContext* graphicsContext, int, int)
252
 
{
253
 
    graphicsContext->addFocusRingRect(m_absoluteBounds);
254
 
}
255
 
 
256
 
void RenderSVGRoot::absoluteRects(Vector<IntRect>& rects, int, int)
257
 
{
258
 
    for (RenderObject* current = firstChild(); current != 0; current = current->nextSibling())
259
 
        current->absoluteRects(rects, 0, 0);
260
 
}
261
 
 
262
 
void RenderSVGRoot::absoluteQuads(Vector<FloatQuad>& quads, bool)
263
 
{
264
 
    for (RenderObject* current = firstChild(); current != 0; current = current->nextSibling())
265
 
        current->absoluteQuads(quads);
266
 
}
267
 
 
268
 
TransformationMatrix RenderSVGRoot::absoluteTransform() const
269
 
{
270
 
    TransformationMatrix ctm = RenderContainer::absoluteTransform();
271
 
    ctm.translate(m_x, m_y);
272
 
    SVGSVGElement* svg = static_cast<SVGSVGElement*>(element());
 
197
// RenderBox methods will expect coordinates w/o any transforms in coordinates
 
198
// relative to our borderBox origin.  This method gives us exactly that.
 
199
TransformationMatrix RenderSVGRoot::localToBorderBoxTransform() const
 
200
{
 
201
    TransformationMatrix ctm;
 
202
    IntSize borderAndPadding = borderOriginToContentBox();
 
203
    ctm.translate(borderAndPadding.width(), borderAndPadding.height());
 
204
    SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
273
205
    ctm.scale(svg->currentScale());
274
206
    ctm.translate(svg->currentTranslate().x(), svg->currentTranslate().y());
275
 
    ctm.translate(viewport().x(), viewport().y());
276
207
    return svg->viewBoxToViewTransform(width(), height()) * ctm;
277
208
}
278
209
 
279
 
FloatRect RenderSVGRoot::relativeBBox(bool includeStroke) const
280
 
{
281
 
    FloatRect rect;
282
 
    
283
 
    RenderObject* current = firstChild();
284
 
    for (; current != 0; current = current->nextSibling()) {
285
 
        FloatRect childBBox = current->relativeBBox(includeStroke);
286
 
        FloatRect mappedBBox = current->localTransform().mapRect(childBBox);
287
 
        // <svg> can have a viewBox contributing to the bbox
288
 
        if (current->isSVGContainer())
289
 
            mappedBBox = static_cast<RenderSVGContainer*>(current)->viewportTransform().mapRect(mappedBBox);
290
 
        rect.unite(mappedBBox);
291
 
    }
292
 
 
293
 
    return rect;
 
210
IntSize RenderSVGRoot::parentOriginToBorderBox() const
 
211
{
 
212
    return IntSize(x(), y());
 
213
}
 
214
 
 
215
IntSize RenderSVGRoot::borderOriginToContentBox() const
 
216
{
 
217
    return IntSize(borderLeft() + paddingLeft(), borderTop() + paddingTop());
 
218
}
 
219
 
 
220
TransformationMatrix RenderSVGRoot::localToRepaintContainerTransform(const IntPoint& parentOriginInContainer) const
 
221
{
 
222
    TransformationMatrix parentToContainer;
 
223
    parentToContainer.translate(parentOriginInContainer.x(), parentOriginInContainer.y());
 
224
    return localToParentTransform() * parentToContainer;
 
225
}
 
226
 
 
227
TransformationMatrix RenderSVGRoot::localToParentTransform() const
 
228
{
 
229
    IntSize parentToBorderBoxOffset = parentOriginToBorderBox();
 
230
 
 
231
    TransformationMatrix borderBoxOriginToParentOrigin;
 
232
    borderBoxOriginToParentOrigin.translate(parentToBorderBoxOffset.width(), parentToBorderBoxOffset.height());
 
233
 
 
234
    return localToBorderBoxTransform() * borderBoxOriginToParentOrigin;
 
235
}
 
236
 
 
237
// FIXME: This method should be removed as soon as callers to RenderBox::absoluteTransform() can be removed.
 
238
TransformationMatrix RenderSVGRoot::absoluteTransform() const
 
239
{
 
240
    // This would apply localTransform() twice if localTransform() were not the identity.
 
241
    return localToParentTransform() * RenderBox::absoluteTransform();
 
242
}
 
243
 
 
244
FloatRect RenderSVGRoot::objectBoundingBox() const
 
245
{
 
246
    return computeContainerBoundingBox(this, false);
 
247
}
 
248
 
 
249
FloatRect RenderSVGRoot::repaintRectInLocalCoordinates() const
 
250
{
 
251
    // FIXME: This does not include the border but it should!
 
252
    return computeContainerBoundingBox(this, true);
294
253
}
295
254
 
296
255
TransformationMatrix RenderSVGRoot::localTransform() const
298
257
    return TransformationMatrix();
299
258
}
300
259
 
 
260
void RenderSVGRoot::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed)
 
261
{
 
262
    // Apply our local transforms (except for x/y translation) and call RenderBox's method to handle all the normal CSS Box model bits
 
263
    repaintRect = localToBorderBoxTransform().mapRect(repaintRect);
 
264
    RenderBox::computeRectForRepaint(repaintContainer, repaintRect, fixed);
 
265
}
 
266
 
 
267
void RenderSVGRoot::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState) const
 
268
{
 
269
    ASSERT(!fixed); // We should have no fixed content in the SVG rendering tree.
 
270
    ASSERT(useTransforms); // mapping a point through SVG w/o respecting trasnforms is useless.
 
271
 
 
272
    // Transform to our border box and let RenderBox transform the rest of the way.
 
273
    transformState.applyTransform(localToBorderBoxTransform());
 
274
    RenderBox::mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState);
 
275
}
 
276
 
301
277
bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction)
302
278
{
303
 
    TransformationMatrix ctm = RenderContainer::absoluteTransform();
304
 
 
305
 
    int sx = (_tx - static_cast<int>(ctm.e())); // scroll offset
306
 
    int sy = (_ty - static_cast<int>(ctm.f())); // scroll offset
307
 
 
308
 
    if (!viewport().isEmpty()
309
 
        && style()->overflowX() == OHIDDEN
310
 
        && style()->overflowY() == OHIDDEN) {
311
 
        int tx = m_x - _tx + sx;
312
 
        int ty = m_y - _ty + sy;
313
 
 
314
 
        // Check if we need to do anything at all.
315
 
        IntRect overflowBox = overflowRect(false);
316
 
        overflowBox.move(tx, ty);
317
 
        ctm.translate(viewport().x(), viewport().y());
318
 
        double localX, localY;
319
 
        ctm.inverse().map(_x - _tx, _y - _ty, &localX, &localY);
320
 
        if (!overflowBox.contains((int)localX, (int)localY))
 
279
    IntPoint pointInContainer(_x, _y);
 
280
    IntSize containerToParentOffset(_tx, _ty);
 
281
 
 
282
    IntPoint pointInParent = pointInContainer - containerToParentOffset;
 
283
    IntPoint pointInBorderBox = pointInParent - parentOriginToBorderBox();
 
284
 
 
285
    // Note: For now, we're ignoring hits to border and padding for <svg>
 
286
 
 
287
    if (style()->overflowX() == OHIDDEN) {
 
288
        // SVG doesn't support independent x/y overflow
 
289
        ASSERT(style()->overflowY() == OHIDDEN);
 
290
        IntPoint pointInContentBox = pointInBorderBox - borderOriginToContentBox();
 
291
        if (!contentBoxRect().contains(pointInContentBox))
321
292
            return false;
322
293
    }
323
294
 
 
295
    IntPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent);
 
296
 
324
297
    for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
325
 
        if (child->nodeAtPoint(request, result, _x - sx, _y - sy, 0, 0, hitTestAction)) {
326
 
            updateHitTestResult(result, IntPoint(_x - _tx, _y - _ty));
 
298
        if (child->nodeAtFloatPoint(request, result, localPoint, hitTestAction)) {
 
299
            // FIXME: CSS/HTML assumes the local point is relative to the border box, right?
 
300
            updateHitTestResult(result, pointInBorderBox);
327
301
            return true;
328
302
        }
329
303
    }
330
 
    
331
 
    // Spec: Only graphical elements can be targeted by the mouse, period.
 
304
 
 
305
    // Spec: Only graphical elements can be targeted by the mouse, so we don't check self here.
332
306
    // 16.4: "If there are no graphics elements whose relevant graphics content is under the pointer (i.e., there is no target element), the event is not dispatched."
333
307
    return false;
334
308
}
335
309
 
336
 
void RenderSVGRoot::position(InlineBox* box)
337
 
{
338
 
    RenderContainer::position(box);
339
 
    if (m_absoluteBounds.isEmpty())
340
 
        setNeedsLayout(true, false);
341
 
}
342
 
 
343
310
}
344
311
 
345
312
#endif // ENABLE(SVG)