37
37
namespace WebCore {
39
39
RenderSVGContainer::RenderSVGContainer(SVGStyledElement* node)
40
: RenderSVGModelObject(node)
45
41
, m_drawsContents(true)
50
RenderSVGContainer::~RenderSVGContainer()
54
bool RenderSVGContainer::canHaveChildren() const
59
void RenderSVGContainer::addChild(RenderObject* newChild, RenderObject* beforeChild)
61
insertChildNode(newChild, beforeChild);
64
void RenderSVGContainer::removeChild(RenderObject* oldChild)
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
69
oldChild->removeFromObjectLists();
71
removeChildNode(oldChild);
74
void RenderSVGContainer::destroy()
76
destroyLeftoverChildren();
77
RenderObject::destroy();
80
void RenderSVGContainer::destroyLeftoverChildren()
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);
87
m_firstChild->destroy();
91
RenderObject* RenderSVGContainer::removeChildNode(RenderObject* oldChild, bool fullRemove)
93
ASSERT(oldChild->parent() == this);
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();
103
// If we have a line box wrapper, delete it.
104
oldChild->deleteLineBoxWrapper();
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();
116
if (oldChild->previousSibling())
117
oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
118
if (oldChild->nextSibling())
119
oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
121
if (m_firstChild == oldChild)
122
m_firstChild = oldChild->nextSibling();
123
if (m_lastChild == oldChild)
124
m_lastChild = oldChild->previousSibling();
126
oldChild->setPreviousSibling(0);
127
oldChild->setNextSibling(0);
128
oldChild->setParent(0);
130
if (AXObjectCache::accessibilityEnabled())
131
document()->axObjectCache()->childrenChanged(this);
136
void RenderSVGContainer::appendChildNode(RenderObject* newChild, bool)
138
ASSERT(!newChild->parent());
139
ASSERT(newChild->element()->isSVGElement());
141
newChild->setParent(this);
142
RenderObject* lChild = m_lastChild;
145
newChild->setPreviousSibling(lChild);
146
lChild->setNextSibling(newChild);
148
m_firstChild = newChild;
150
m_lastChild = newChild;
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.
156
if (AXObjectCache::accessibilityEnabled())
157
document()->axObjectCache()->childrenChanged(this);
160
void RenderSVGContainer::insertChildNode(RenderObject* child, RenderObject* beforeChild, bool)
163
appendChildNode(child);
167
ASSERT(!child->parent());
168
ASSERT(beforeChild->parent() == this);
169
ASSERT(child->element()->isSVGElement());
171
if (beforeChild == m_firstChild)
172
m_firstChild = child;
174
RenderObject* prev = beforeChild->previousSibling();
175
child->setNextSibling(beforeChild);
176
beforeChild->setPreviousSibling(child);
178
prev->setNextSibling(child);
179
child->setPreviousSibling(prev);
181
child->setParent(this);
183
child->setNeedsLayoutAndPrefWidthsRecalc();
184
if (!normalChildNeedsLayout())
185
setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
187
if (AXObjectCache::accessibilityEnabled())
188
document()->axObjectCache()->childrenChanged(this);
191
45
bool RenderSVGContainer::drawsContents() const
198
52
m_drawsContents = drawsContents;
201
TransformationMatrix RenderSVGContainer::localTransform() const
203
return m_localTransform;
206
bool RenderSVGContainer::requiresLayer()
208
// Only allow an <svg> element to generate a layer when it's positioned in a non-SVG context
212
int RenderSVGContainer::lineHeight(bool, bool) const
214
return height() + marginTop() + marginBottom();
217
int RenderSVGContainer::baselinePosition(bool, bool) const
219
return height() + marginTop() + marginBottom();
222
bool RenderSVGContainer::calculateLocalTransform()
224
// subclasses can override this to add transform support
228
55
void RenderSVGContainer::layout()
230
57
ASSERT(needsLayout());
232
// Arbitrary affine transforms are incompatible with LayoutState.
233
view()->disableLayoutState();
236
IntRect oldOutlineBox;
237
bool checkForRepaint = checkForRepaintDuringLayout() && selfWillPaint();
238
if (checkForRepaint) {
239
oldBounds = m_absoluteBounds;
240
oldOutlineBox = absoluteOutlineBounds();
243
calculateLocalTransform();
58
ASSERT(!view()->layoutStateEnabled()); // RenderSVGRoot disables layoutState for the SVG rendering tree.
60
calcViewport(); // Allow RenderSVGViewportContainer to update its viewport
62
LayoutRepainter repainter(*this, checkForRepaintDuringLayout() || selfWillPaint());
63
calculateLocalTransform(); // Allow RenderSVGTransformableContainer to update its transform
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());
260
repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
262
view()->enableLayoutState();
76
repainter.repaintAfterLayout();
263
78
setNeedsLayout(false);
266
int RenderSVGContainer::calcReplacedWidth() const
268
switch (style()->width().type()) {
270
return max(0, style()->width().value());
273
const int cw = containingBlockWidth();
274
return cw > 0 ? max(0, style()->width().calcMinValue(cw)) : 0;
281
int RenderSVGContainer::calcReplacedHeight() const
283
switch (style()->height().type()) {
285
return max(0, style()->height().value());
288
RenderBlock* cb = containingBlock();
289
return style()->height().calcValue(cb->availableHeight());
296
void RenderSVGContainer::applyContentTransforms(PaintInfo& paintInfo)
298
if (!localTransform().isIdentity())
299
paintInfo.context->concatCTM(localTransform());
302
void RenderSVGContainer::applyAdditionalTransforms(PaintInfo&)
307
void RenderSVGContainer::calcBounds()
309
m_width = calcReplacedWidth();
310
m_height = calcReplacedHeight();
311
m_absoluteBounds = absoluteClippedOverflowRect();
314
81
bool RenderSVGContainer::selfWillPaint() const
316
#if ENABLE(SVG_FILTERS)
317
84
const SVGRenderStyle* svgStyle = style()->svgStyle();
318
85
SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter());
330
97
// Spec: groups w/o children still may render filter content.
331
98
if (!firstChild() && !selfWillPaint())
334
paintInfo.context->save();
335
applyContentTransforms(paintInfo);
101
PaintInfo childPaintInfo(paintInfo);
103
childPaintInfo.context->save();
105
// Let the RenderSVGViewportContainer subclass clip if necessary
106
applyViewportClip(childPaintInfo);
108
applyTransformToPaintInfo(childPaintInfo, localToParentTransform());
337
110
SVGResourceFilter* filter = 0;
338
PaintInfo savedInfo(paintInfo);
340
FloatRect boundingBox = relativeBBox(true);
341
if (paintInfo.phase == PaintPhaseForeground)
342
prepareToRenderSVGContent(this, paintInfo, boundingBox, filter);
344
applyAdditionalTransforms(paintInfo);
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);
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);
352
119
if (paintInfo.phase == PaintPhaseForeground)
353
finishRenderSVGContent(this, paintInfo, boundingBox, filter, savedInfo.context);
355
paintInfo.context->restore();
120
finishRenderSVGContent(this, childPaintInfo, filter, paintInfo.context);
122
childPaintInfo.context->restore();
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());
361
TransformationMatrix RenderSVGContainer::viewportTransform() const
363
return TransformationMatrix();
366
IntRect RenderSVGContainer::absoluteClippedOverflowRect()
368
FloatRect repaintRect;
370
for (RenderObject* current = firstChild(); current != 0; current = current->nextSibling())
371
repaintRect.unite(current->absoluteClippedOverflowRect());
373
#if ENABLE(SVG_FILTERS)
374
// Filters can expand the bounding box
375
SVGResourceFilter* filter = getFilterById(document(), style()->svgStyle()->filter());
377
repaintRect.unite(filter->filterBBoxForItemBBox(repaintRect));
380
if (!repaintRect.isEmpty())
381
repaintRect.inflate(1); // inflate 1 pixel for antialiasing
383
return enclosingIntRect(repaintRect);
131
paintOutline(paintInfo.context, paintRectInParent.x(), paintRectInParent.y(), paintRectInParent.width(), paintRectInParent.height(), style());
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)
388
graphicsContext->addFocusRingRect(m_absoluteBounds);
391
void RenderSVGContainer::absoluteRects(Vector<IntRect>& rects, int, int, bool)
393
rects.append(absoluteClippedOverflowRect());
396
void RenderSVGContainer::absoluteQuads(Vector<FloatQuad>& quads, bool)
398
quads.append(absoluteClippedOverflowRect());
401
FloatRect RenderSVGContainer::relativeBBox(bool includeStroke) const
405
RenderObject* current = firstChild();
406
for (; current != 0; current = current->nextSibling()) {
407
FloatRect childBBox = current->relativeBBox(includeStroke);
408
FloatRect mappedBBox = current->localTransform().mapRect(childBBox);
410
// <svg> can have a viewBox contributing to the bbox
411
if (current->isSVGContainer())
412
mappedBBox = static_cast<RenderSVGContainer*>(current)->viewportTransform().mapRect(mappedBBox);
414
rect.unite(mappedBBox);
420
bool RenderSVGContainer::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction)
137
IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates()));
138
graphicsContext->addFocusRingRect(paintRectInParent);
141
FloatRect RenderSVGContainer::objectBoundingBox() const
143
return computeContainerBoundingBox(this, false);
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
150
FloatRect repaintRect = computeContainerBoundingBox(this, true);
152
// A filter on this container can paint outside of the union of the child repaint rects
153
repaintRect.unite(filterBoundingBoxForRenderer(this));
158
bool RenderSVGContainer::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
160
// Give RenderSVGViewportContainer a chance to apply its viewport clip
161
if (!pointIsInsideViewportClip(pointInParent))
164
FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent);
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));