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

« back to all changes in this revision

Viewing changes to src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.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 Rob Buis <buis@kde.org>
4
4
                  2007 Eric Seidel <eric@webkit.org>
5
 
 
6
 
    This file is part of the KDE project
 
5
    Copyright (C) 2009 Google, Inc.  All rights reserved.
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 "RenderSVGContainer.h"
28
27
 
29
28
#include "AXObjectCache.h"
 
29
#include "FloatQuad.h"
30
30
#include "GraphicsContext.h"
31
31
#include "RenderView.h"
32
32
#include "SVGRenderSupport.h"
37
37
namespace WebCore {
38
38
 
39
39
RenderSVGContainer::RenderSVGContainer(SVGStyledElement* node)
40
 
    : RenderObject(node)
41
 
    , m_firstChild(0)
42
 
    , m_lastChild(0)
43
 
    , m_width(0)
44
 
    , m_height(0)
 
40
    : RenderSVGModelObject(node)
45
41
    , m_drawsContents(true)
46
42
{
47
 
    setReplaced(true);
48
 
}
49
 
 
50
 
RenderSVGContainer::~RenderSVGContainer()
51
 
{
52
 
}
53
 
 
54
 
bool RenderSVGContainer::canHaveChildren() const
55
 
{
56
 
    return true;
57
 
}
58
 
 
59
 
void RenderSVGContainer::addChild(RenderObject* newChild, RenderObject* beforeChild)
60
 
{
61
 
    insertChildNode(newChild, beforeChild);
62
 
}
63
 
 
64
 
void RenderSVGContainer::removeChild(RenderObject* oldChild)
65
 
{
66
 
    // We do this here instead of in removeChildNode, since the only extremely low-level uses of remove/appendChildNode
67
 
    // cannot affect the positioned object list, and the floating object list is irrelevant (since the list gets cleared on
68
 
    // layout anyway).
69
 
    oldChild->removeFromObjectLists();
70
 
 
71
 
    removeChildNode(oldChild);
72
 
}
73
 
 
74
 
void RenderSVGContainer::destroy()
75
 
{
76
 
    destroyLeftoverChildren();
77
 
    RenderObject::destroy();
78
 
}
79
 
 
80
 
void RenderSVGContainer::destroyLeftoverChildren()
81
 
{
82
 
    while (m_firstChild) {
83
 
        // Destroy any anonymous children remaining in the render tree, as well as implicit (shadow) DOM elements like those used in the engine-based text fields.
84
 
        if (m_firstChild->element())
85
 
            m_firstChild->element()->setRenderer(0);
86
 
 
87
 
        m_firstChild->destroy();
88
 
    }
89
 
}
90
 
 
91
 
RenderObject* RenderSVGContainer::removeChildNode(RenderObject* oldChild, bool fullRemove)
92
 
{
93
 
    ASSERT(oldChild->parent() == this);
94
 
 
95
 
    // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or
96
 
    // that a positioned child got yanked).  We also repaint, so that the area exposed when the child
97
 
    // disappears gets repainted properly.
98
 
    if (!documentBeingDestroyed() && fullRemove) {
99
 
        oldChild->setNeedsLayoutAndPrefWidthsRecalc();
100
 
        oldChild->repaint();
101
 
    }
102
 
 
103
 
    // If we have a line box wrapper, delete it.
104
 
    oldChild->deleteLineBoxWrapper();
105
 
 
106
 
    if (!documentBeingDestroyed() && fullRemove) {
107
 
        // If oldChild is the start or end of the selection, then clear the selection to
108
 
        // avoid problems of invalid pointers.
109
 
        // FIXME: The SelectionController should be responsible for this when it
110
 
        // is notified of DOM mutations.
111
 
        if (oldChild->isSelectionBorder())
112
 
            view()->clearSelection();
113
 
    }
114
 
 
115
 
    // remove the child
116
 
    if (oldChild->previousSibling())
117
 
        oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
118
 
    if (oldChild->nextSibling())
119
 
        oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
120
 
 
121
 
    if (m_firstChild == oldChild)
122
 
        m_firstChild = oldChild->nextSibling();
123
 
    if (m_lastChild == oldChild)
124
 
        m_lastChild = oldChild->previousSibling();
125
 
 
126
 
    oldChild->setPreviousSibling(0);
127
 
    oldChild->setNextSibling(0);
128
 
    oldChild->setParent(0);
129
 
 
130
 
    if (AXObjectCache::accessibilityEnabled())
131
 
        document()->axObjectCache()->childrenChanged(this);
132
 
 
133
 
    return oldChild;
134
 
}
135
 
 
136
 
void RenderSVGContainer::appendChildNode(RenderObject* newChild, bool)
137
 
{
138
 
    ASSERT(!newChild->parent());
139
 
    ASSERT(newChild->element()->isSVGElement());
140
 
 
141
 
    newChild->setParent(this);
142
 
    RenderObject* lChild = m_lastChild;
143
 
 
144
 
    if (lChild) {
145
 
        newChild->setPreviousSibling(lChild);
146
 
        lChild->setNextSibling(newChild);
147
 
    } else
148
 
        m_firstChild = newChild;
149
 
 
150
 
    m_lastChild = newChild;
151
 
 
152
 
    newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy.
153
 
    if (!normalChildNeedsLayout())
154
 
        setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
155
 
 
156
 
    if (AXObjectCache::accessibilityEnabled())
157
 
        document()->axObjectCache()->childrenChanged(this);
158
 
}
159
 
 
160
 
void RenderSVGContainer::insertChildNode(RenderObject* child, RenderObject* beforeChild, bool)
161
 
{
162
 
    if (!beforeChild) {
163
 
        appendChildNode(child);
164
 
        return;
165
 
    }
166
 
 
167
 
    ASSERT(!child->parent());
168
 
    ASSERT(beforeChild->parent() == this);
169
 
    ASSERT(child->element()->isSVGElement());
170
 
 
171
 
    if (beforeChild == m_firstChild)
172
 
        m_firstChild = child;
173
 
 
174
 
    RenderObject* prev = beforeChild->previousSibling();
175
 
    child->setNextSibling(beforeChild);
176
 
    beforeChild->setPreviousSibling(child);
177
 
    if (prev)
178
 
        prev->setNextSibling(child);
179
 
    child->setPreviousSibling(prev);
180
 
 
181
 
    child->setParent(this);
182
 
 
183
 
    child->setNeedsLayoutAndPrefWidthsRecalc();
184
 
    if (!normalChildNeedsLayout())
185
 
        setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
186
 
 
187
 
    if (AXObjectCache::accessibilityEnabled())
188
 
        document()->axObjectCache()->childrenChanged(this);
189
43
}
190
44
 
191
45
bool RenderSVGContainer::drawsContents() const
198
52
    m_drawsContents = drawsContents;
199
53
}
200
54
 
201
 
TransformationMatrix RenderSVGContainer::localTransform() const
202
 
{
203
 
    return m_localTransform;
204
 
}
205
 
 
206
 
bool RenderSVGContainer::requiresLayer()
207
 
{
208
 
    // Only allow an <svg> element to generate a layer when it's positioned in a non-SVG context
209
 
    return false;
210
 
}
211
 
 
212
 
int RenderSVGContainer::lineHeight(bool, bool) const
213
 
{
214
 
    return height() + marginTop() + marginBottom();
215
 
}
216
 
 
217
 
int RenderSVGContainer::baselinePosition(bool, bool) const
218
 
{
219
 
    return height() + marginTop() + marginBottom();
220
 
}
221
 
 
222
 
bool RenderSVGContainer::calculateLocalTransform()
223
 
{
224
 
    // subclasses can override this to add transform support
225
 
    return false;
226
 
}
227
 
 
228
55
void RenderSVGContainer::layout()
229
56
{
230
57
    ASSERT(needsLayout());
231
 
 
232
 
    // Arbitrary affine transforms are incompatible with LayoutState.
233
 
    view()->disableLayoutState();
234
 
 
235
 
    IntRect oldBounds;
236
 
    IntRect oldOutlineBox;
237
 
    bool checkForRepaint = checkForRepaintDuringLayout() && selfWillPaint();
238
 
    if (checkForRepaint) {
239
 
        oldBounds = m_absoluteBounds;
240
 
        oldOutlineBox = absoluteOutlineBounds();
241
 
    }
242
 
    
243
 
    calculateLocalTransform();
 
58
    ASSERT(!view()->layoutStateEnabled()); // RenderSVGRoot disables layoutState for the SVG rendering tree.
 
59
 
 
60
    calcViewport(); // Allow RenderSVGViewportContainer to update its viewport
 
61
 
 
62
    LayoutRepainter repainter(*this, checkForRepaintDuringLayout() || selfWillPaint());
 
63
    calculateLocalTransform(); // Allow RenderSVGTransformableContainer to update its transform
244
64
 
245
65
    for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
246
66
        // Only force our kids to layout if we're being asked to relayout as a result of a parent changing
253
73
        child->layoutIfNeeded();
254
74
        ASSERT(!child->needsLayout());
255
75
    }
256
 
 
257
 
    calcBounds();
258
 
 
259
 
    if (checkForRepaint)
260
 
        repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
261
 
 
262
 
    view()->enableLayoutState();
 
76
    repainter.repaintAfterLayout();
 
77
 
263
78
    setNeedsLayout(false);
264
79
}
265
80
 
266
 
int RenderSVGContainer::calcReplacedWidth() const
267
 
{
268
 
    switch (style()->width().type()) {
269
 
    case Fixed:
270
 
        return max(0, style()->width().value());
271
 
    case Percent:
272
 
    {
273
 
        const int cw = containingBlockWidth();
274
 
        return cw > 0 ? max(0, style()->width().calcMinValue(cw)) : 0;
275
 
    }
276
 
    default:
277
 
        return 0;
278
 
    }
279
 
}
280
 
 
281
 
int RenderSVGContainer::calcReplacedHeight() const
282
 
{
283
 
    switch (style()->height().type()) {
284
 
    case Fixed:
285
 
        return max(0, style()->height().value());
286
 
    case Percent:
287
 
    {
288
 
        RenderBlock* cb = containingBlock();
289
 
        return style()->height().calcValue(cb->availableHeight());
290
 
    }
291
 
    default:
292
 
        return 0;
293
 
    }
294
 
}
295
 
 
296
 
void RenderSVGContainer::applyContentTransforms(PaintInfo& paintInfo)
297
 
{
298
 
    if (!localTransform().isIdentity())
299
 
        paintInfo.context->concatCTM(localTransform());
300
 
}
301
 
 
302
 
void RenderSVGContainer::applyAdditionalTransforms(PaintInfo&)
303
 
{
304
 
    // no-op
305
 
}
306
 
 
307
 
void RenderSVGContainer::calcBounds()
308
 
{
309
 
    m_width = calcReplacedWidth();
310
 
    m_height = calcReplacedHeight();
311
 
    m_absoluteBounds = absoluteClippedOverflowRect();
312
 
}
313
 
 
314
81
bool RenderSVGContainer::selfWillPaint() const
315
82
{
316
 
#if ENABLE(SVG_FILTERS)
 
83
#if ENABLE(FILTERS)
317
84
    const SVGRenderStyle* svgStyle = style()->svgStyle();
318
85
    SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter());
319
86
    if (filter)
330
97
     // Spec: groups w/o children still may render filter content.
331
98
    if (!firstChild() && !selfWillPaint())
332
99
        return;
333
 
    
334
 
    paintInfo.context->save();
335
 
    applyContentTransforms(paintInfo);
 
100
 
 
101
    PaintInfo childPaintInfo(paintInfo);
 
102
 
 
103
    childPaintInfo.context->save();
 
104
 
 
105
    // Let the RenderSVGViewportContainer subclass clip if necessary
 
106
    applyViewportClip(childPaintInfo);
 
107
 
 
108
    applyTransformToPaintInfo(childPaintInfo, localToParentTransform());
336
109
 
337
110
    SVGResourceFilter* filter = 0;
338
 
    PaintInfo savedInfo(paintInfo);
339
 
 
340
 
    FloatRect boundingBox = relativeBBox(true);
341
 
    if (paintInfo.phase == PaintPhaseForeground)
342
 
        prepareToRenderSVGContent(this, paintInfo, boundingBox, filter); 
343
 
 
344
 
    applyAdditionalTransforms(paintInfo);
345
 
 
346
 
    // default implementation. Just pass paint through to the children
347
 
    PaintInfo childInfo(paintInfo);
348
 
    childInfo.paintingRoot = paintingRootForChildren(paintInfo);
 
111
    FloatRect boundingBox = repaintRectInLocalCoordinates();
 
112
    if (childPaintInfo.phase == PaintPhaseForeground)
 
113
        prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter);
 
114
 
 
115
    childPaintInfo.paintingRoot = paintingRootForChildren(childPaintInfo);
349
116
    for (RenderObject* child = firstChild(); child; child = child->nextSibling())
350
 
        child->paint(childInfo, 0, 0);
 
117
        child->paint(childPaintInfo, 0, 0);
351
118
 
352
119
    if (paintInfo.phase == PaintPhaseForeground)
353
 
        finishRenderSVGContent(this, paintInfo, boundingBox, filter, savedInfo.context);
354
 
 
355
 
    paintInfo.context->restore();
356
 
    
 
120
        finishRenderSVGContent(this, childPaintInfo, filter, paintInfo.context);
 
121
 
 
122
    childPaintInfo.context->restore();
 
123
 
 
124
    // FIXME: This really should be drawn from local coordinates, but currently we hack it
 
125
    // to avoid our clip killing our outline rect.  Thus we translate our
 
126
    // outline rect into parent coords before drawing.
 
127
    // FIXME: This means our focus ring won't share our rotation like it should.
 
128
    // We should instead disable our clip during PaintPhaseOutline
 
129
    IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates()));
357
130
    if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE)
358
 
        paintOutline(paintInfo.context, m_absoluteBounds.x(), m_absoluteBounds.y(), m_absoluteBounds.width(), m_absoluteBounds.height(), style());
359
 
}
360
 
 
361
 
TransformationMatrix RenderSVGContainer::viewportTransform() const
362
 
{
363
 
     return TransformationMatrix();
364
 
}
365
 
 
366
 
IntRect RenderSVGContainer::absoluteClippedOverflowRect()
367
 
{
368
 
    FloatRect repaintRect;
369
 
 
370
 
    for (RenderObject* current = firstChild(); current != 0; current = current->nextSibling())
371
 
        repaintRect.unite(current->absoluteClippedOverflowRect());
372
 
 
373
 
#if ENABLE(SVG_FILTERS)
374
 
    // Filters can expand the bounding box
375
 
    SVGResourceFilter* filter = getFilterById(document(), style()->svgStyle()->filter());
376
 
    if (filter)
377
 
        repaintRect.unite(filter->filterBBoxForItemBBox(repaintRect));
378
 
#endif
379
 
 
380
 
    if (!repaintRect.isEmpty())
381
 
        repaintRect.inflate(1); // inflate 1 pixel for antialiasing
382
 
 
383
 
    return enclosingIntRect(repaintRect);
384
 
}
385
 
 
 
131
        paintOutline(paintInfo.context, paintRectInParent.x(), paintRectInParent.y(), paintRectInParent.width(), paintRectInParent.height(), style());
 
132
}
 
133
 
 
134
// addFocusRingRects is called from paintOutline and needs to be in the same coordinates as the paintOuline call
386
135
void RenderSVGContainer::addFocusRingRects(GraphicsContext* graphicsContext, int, int)
387
136
{
388
 
    graphicsContext->addFocusRingRect(m_absoluteBounds);
389
 
}
390
 
 
391
 
void RenderSVGContainer::absoluteRects(Vector<IntRect>& rects, int, int, bool)
392
 
{
393
 
    rects.append(absoluteClippedOverflowRect());
394
 
}
395
 
 
396
 
void RenderSVGContainer::absoluteQuads(Vector<FloatQuad>& quads, bool)
397
 
{
398
 
    quads.append(absoluteClippedOverflowRect());
399
 
}
400
 
 
401
 
FloatRect RenderSVGContainer::relativeBBox(bool includeStroke) const
402
 
{
403
 
    FloatRect rect;
404
 
    
405
 
    RenderObject* current = firstChild();
406
 
    for (; current != 0; current = current->nextSibling()) {
407
 
        FloatRect childBBox = current->relativeBBox(includeStroke);
408
 
        FloatRect mappedBBox = current->localTransform().mapRect(childBBox);
409
 
 
410
 
        // <svg> can have a viewBox contributing to the bbox
411
 
        if (current->isSVGContainer())
412
 
            mappedBBox = static_cast<RenderSVGContainer*>(current)->viewportTransform().mapRect(mappedBBox);
413
 
 
414
 
        rect.unite(mappedBBox);
415
 
    }
416
 
 
417
 
    return rect;
418
 
}
419
 
 
420
 
bool RenderSVGContainer::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction)
421
 
{
 
137
    IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates()));
 
138
    graphicsContext->addFocusRingRect(paintRectInParent);
 
139
}
 
140
 
 
141
FloatRect RenderSVGContainer::objectBoundingBox() const
 
142
{
 
143
    return computeContainerBoundingBox(this, false);
 
144
}
 
145
 
 
146
// RenderSVGContainer is used for <g> elements which do not themselves have a
 
147
// width or height, so we union all of our child rects as our repaint rect.
 
148
FloatRect RenderSVGContainer::repaintRectInLocalCoordinates() const
 
149
{
 
150
    FloatRect repaintRect = computeContainerBoundingBox(this, true);
 
151
 
 
152
    // A filter on this container can paint outside of the union of the child repaint rects
 
153
    repaintRect.unite(filterBoundingBoxForRenderer(this));
 
154
 
 
155
    return repaintRect;
 
156
}
 
157
 
 
158
bool RenderSVGContainer::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
 
159
{
 
160
    // Give RenderSVGViewportContainer a chance to apply its viewport clip
 
161
    if (!pointIsInsideViewportClip(pointInParent))
 
162
        return false;
 
163
 
 
164
    FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent);
 
165
 
422
166
    for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
423
 
        if (child->nodeAtPoint(request, result, _x, _y, _tx, _ty, hitTestAction)) {
424
 
            updateHitTestResult(result, IntPoint(_x - _tx, _y - _ty));
 
167
        if (child->nodeAtFloatPoint(request, result, localPoint, hitTestAction)) {
 
168
            updateHitTestResult(result, roundedIntPoint(localPoint));
425
169
            return true;
426
170
        }
427
171
    }