fix logic
[personal-kdelibs.git] / khtml / rendering / RenderSVGContainer.cpp
blobeff04e5de973d1f116587551f5c2704cd3ad0020
1 /*
2 Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
3 2004, 2005, 2007 Rob Buis <buis@kde.org>
4 2007 Eric Seidel <eric@webkit.org>
6 This file is part of the KDE project
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
18 You should have received a copy of the GNU Library General Public License
19 aint with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
24 #include "config.h"
25 #include "wtf/Platform.h"
27 #if ENABLE(SVG)
28 #include "RenderSVGContainer.h"
30 /*#include "AXObjectCache.h"
31 #include "GraphicsContext.h"*/
32 #include "RenderView.h"
33 #include "SVGRenderSupport.h"
34 #include "SVGResourceFilter.h"
35 #include "SVGStyledElement.h"
36 #include "SVGURIReference.h"
38 namespace WebCore {
40 RenderSVGContainer::RenderSVGContainer(SVGStyledElement* node)
41 : RenderObject(node)
42 , m_firstChild(0)
43 , m_lastChild(0)
44 , m_width(0)
45 , m_height(0)
46 , m_drawsContents(true)
48 setReplaced(true);
51 RenderSVGContainer::~RenderSVGContainer()
55 bool RenderSVGContainer::canHaveChildren() const
57 return true;
60 void RenderSVGContainer::addChild(RenderObject* newChild, RenderObject* beforeChild)
62 insertChildNode(newChild, beforeChild);
65 void RenderSVGContainer::removeChild(RenderObject* oldChild)
67 // We do this here instead of in removeChildNode, since the only extremely low-level uses of remove/appendChildNode
68 // cannot affect the positioned object list, and the floating object list is irrelevant (since the list gets cleared on
69 // layout anyway).
70 oldChild->removeFromObjectLists();
72 removeChildNode(oldChild);
75 void RenderSVGContainer::destroy()
77 /*destroyLeftoverChildren();
78 RenderObject::destroy();*/
81 void RenderSVGContainer::destroyLeftoverChildren()
83 /*while (m_firstChild) {
84 // 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.
85 if (m_firstChild->element())
86 m_firstChild->element()->setRenderer(0);
88 m_firstChild->destroy();
89 }*/
92 RenderObject* RenderSVGContainer::removeChildNode(RenderObject* oldChild, bool fullRemove)
94 ASSERT(oldChild->parent() == this);
95 bool inCleanup = documentBeingDestroyed();
97 // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or
98 // that a positioned child got yanked). We also repaint, so that the area exposed when the child
99 // disappears gets repainted properly.
101 if (!inCleanup && fullRemove) {
102 oldChild->setNeedsLayoutAndMinMaxRecalc(); // Dirty the containing block chain
103 oldChild->setNeedsLayout( false ); // The child itself does not need to layout - it's going away.
104 oldChild->repaint();
107 // detach the place holder box
108 if (oldChild->isBox()) {
109 RenderBox* rb = static_cast<RenderBox*>(oldChild);
110 InlineBox* ph = rb->placeHolderBox();
111 if (ph) {
112 ph->detach(rb->renderArena(), inCleanup /*NoRemove*/);
113 rb->setPlaceHolderBox( 0 );
117 if (!inCleanup && fullRemove) {
118 // If oldChild is the start or end of the selection, then clear the selection to
119 // avoid problems of invalid pointers.
120 // FIXME: The SelectionController should be responsible for this when it
121 // is notified of DOM mutations.
122 /* FIXME if (oldChild->isSelectionBorder())
123 view()->clearSelection();*/
124 if (oldChild->isSelectionBorder())
125 canvas()->clearSelection();
128 // remove the child
129 if (oldChild->previousSibling())
130 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
131 if (oldChild->nextSibling())
132 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
134 if (m_firstChild == oldChild)
135 m_firstChild = oldChild->nextSibling();
136 if (m_lastChild == oldChild)
137 m_lastChild = oldChild->previousSibling();
139 oldChild->setPreviousSibling(0);
140 oldChild->setNextSibling(0);
141 oldChild->setParent(0);
143 /*if (AXObjectCache::accessibilityEnabled())
144 document()->axObjectCache()->childrenChanged(this);*/
146 return oldChild;
149 void RenderSVGContainer::appendChildNode(RenderObject* newChild, bool)
151 ASSERT(!newChild->parent());
152 /*khtml vtokarevASSERT(newChild->element()->isSVGElement());*/
153 // remove it when I have SVG render text; SVGInlineText
155 newChild->setParent(this);
156 RenderObject* lChild = m_lastChild;
158 if (lChild) {
159 newChild->setPreviousSibling(lChild);
160 lChild->setNextSibling(newChild);
161 } else
162 m_firstChild = newChild;
164 m_lastChild = newChild;
166 newChild->setNeedsLayoutAndMinMaxRecalc(); // Goes up the containing block hierarchy.*/
167 if (!normalChildNeedsLayout())
168 setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
170 /*if (AXObjectCache::accessibilityEnabled())
171 document()->axObjectCache()->childrenChanged(this);*/
174 void RenderSVGContainer::insertChildNode(RenderObject* child, RenderObject* beforeChild, bool)
176 if (!beforeChild) {
177 appendChildNode(child);
178 return;
181 ASSERT(!child->parent());
182 ASSERT(beforeChild->parent() == this);
183 ASSERT(child->element()->isSVGElement());
185 if (beforeChild == m_firstChild)
186 m_firstChild = child;
188 RenderObject* prev = beforeChild->previousSibling();
189 child->setNextSibling(beforeChild);
190 beforeChild->setPreviousSibling(child);
191 if (prev)
192 prev->setNextSibling(child);
193 child->setPreviousSibling(prev);
195 child->setParent(this);
197 child->setNeedsLayoutAndMinMaxRecalc();
198 if (!normalChildNeedsLayout())
199 setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
201 /*if (AXObjectCache::accessibilityEnabled())
202 document()->axObjectCache()->childrenChanged(this);*/
205 bool RenderSVGContainer::drawsContents() const
207 return m_drawsContents;
210 void RenderSVGContainer::setDrawsContents(bool drawsContents)
212 m_drawsContents = drawsContents;
215 AffineTransform RenderSVGContainer::localTransform() const
217 return m_localTransform;
220 bool RenderSVGContainer::requiresLayer()
222 // Only allow an <svg> element to generate a layer when it's positioned in a non-SVG context
223 return false;
226 short RenderSVGContainer::lineHeight(bool b, bool isRootLineBox) const
228 return height() + marginTop() + marginBottom();
231 short RenderSVGContainer::baselinePosition(bool b, bool isRootLineBox) const
233 return height() + marginTop() + marginBottom();
236 bool RenderSVGContainer::calculateLocalTransform()
238 // subclasses can override this to add transform support
239 return false;
242 void RenderSVGContainer::layout()
244 ASSERT(needsLayout());
246 // Arbitrary affine transforms are incompatible with LayoutState.
247 /*canvas()->disableLayoutState();*/
249 /*IntRect oldBounds;
250 IntRect oldOutlineBox;
251 bool checkForRepaint = checkForRepaintDuringLayout() && selfWillPaint();
252 if (checkForRepaint) {
253 oldBounds = m_absoluteBounds;
254 oldOutlineBox = absoluteOutlineBox();
257 calculateLocalTransform();
259 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
260 // Only force our kids to layout if we're being asked to relayout as a result of a parent changing
261 // FIXME: We should be able to skip relayout of non-relative kids when only bounds size has changed
262 // that's a possible future optimization using LayoutState
263 // http://bugs.webkit.org/show_bug.cgi?id=15391
264 if (child->isText()) continue;
265 if (selfNeedsLayout())
266 child->setNeedsLayout(true);
268 child->layoutIfNeeded();
269 ASSERT(!child->needsLayout());
272 calcBounds();
274 /*if (checkForRepaint)
275 repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);*/
277 /*canvas()->enableLayoutState();*/
278 setNeedsLayout(false);
281 int RenderSVGContainer::calcReplacedWidth() const
283 switch (style()->width().type()) {
284 case Fixed:
285 return qMax(0, style()->width().value());
286 case Percent:
288 const int cw = containingBlockWidth();
289 return cw > 0 ? qMax(0, style()->width().minWidth(cw)) : 0;
291 default:
292 return 0;
296 int RenderSVGContainer::calcReplacedHeight() const
298 switch (style()->height().type()) {
299 case Fixed:
300 return qMax(0, style()->height().value());
301 case Percent:
303 RenderBlock* cb = containingBlock();
304 return style()->height().width(cb->availableHeight());
306 default:
307 return 0;
311 void RenderSVGContainer::applyContentTransforms(PaintInfo& paintInfo)
313 if (!localTransform().isIdentity())
314 paintInfo.p->setWorldMatrix(localTransform(), true);
315 /*paintInfo.context->concatCTM(localTransform());*/
318 void RenderSVGContainer::applyAdditionalTransforms(PaintInfo& paintInfo)
320 // no-op
323 void RenderSVGContainer::calcBounds()
325 m_width = calcReplacedWidth();
326 m_height = calcReplacedHeight();
327 //m_absoluteBounds = absoluteClippedOverflowRect();
330 bool RenderSVGContainer::selfWillPaint() const
332 #if ENABLE(SVG_FILTERS)
333 const SVGRenderStyle* svgStyle = style()->svgStyle();
334 AtomicString filterId(SVGURIReference::getTarget(svgStyle->filter()));
335 SVGResourceFilter* filter = getFilterById(document(), filterId);
336 if (filter)
337 return true;
338 #endif
339 return false;
342 void RenderSVGContainer::paint(PaintInfo& paintInfo, int parentX, int parentY)
344 if (/*paintInfo.context->paintingDisabled() || */!drawsContents())
345 return;
347 // Spec: groups w/o children still may render filter content.
348 /*if (!firstChild() && !selfWillPaint())
349 return;*/
351 paintInfo.p->save();
352 applyContentTransforms(paintInfo);
354 SVGResourceFilter* filter = 0;
355 /*PaintInfo savedInfo(paintInfo);*/
357 FloatRect boundingBox = relativeBBox(true);
358 /*if (paintInfo.phase == PaintPhaseForeground)*/
359 prepareToRenderSVGContent(this, paintInfo, boundingBox, filter);
361 applyAdditionalTransforms(paintInfo);
363 // default implementation. Just pass paint through to the children
364 PaintInfo childInfo(paintInfo);
365 /*childInfo.paintingRoot = paintingRootForChildren(paintInfo);*/
366 for (RenderObject* child = firstChild(); child; child = child->nextSibling())
367 child->paint(childInfo, 0, 0);
369 /*if (paintInfo.phase == PaintPhaseForeground)
370 finishRenderSVGContent(this, paintInfo, boundingBox, filter, savedInfo.context);*/
372 paintInfo.p->restore();
374 /*if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE)
375 paintOutline(paintInfo.context, m_absoluteBounds.x(), m_absoluteBounds.y(), m_absoluteBounds.width(), m_absoluteBounds.height(), style());*/
378 AffineTransform RenderSVGContainer::viewportTransform() const
380 return AffineTransform();
383 IntRect RenderSVGContainer::absoluteClippedOverflowRect()
385 /*FloatRect repaintRect;
387 for (RenderObject* current = firstChild(); current != 0; current = current->nextSibling())
388 repaintRect.unite(current->absoluteClippedOverflowRect());
390 #if ENABLE(SVG_FILTERS)
391 // Filters can expand the bounding box
392 SVGResourceFilter* filter = getFilterById(document(), SVGURIReference::getTarget(style()->svgStyle()->filter()));
393 if (filter)
394 repaintRect.unite(filter->filterBBoxForItemBBox(repaintRect));
395 #endif
397 if (!repaintRect.isEmpty())
398 repaintRect.inflate(1); // inflate 1 pixel for antialiasing
400 return enclosingIntRect(repaintRect);*/
401 ASSERT(false);
402 return IntRect();
405 void RenderSVGContainer::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty)
407 //FIXME graphicsContext->addFocusRingRect(m_absoluteBounds);
410 void RenderSVGContainer::absoluteRects(Vector<IntRect>& rects, int, int, bool)
412 //FIXME rects.append(absoluteClippedOverflowRect());
415 FloatRect RenderSVGContainer::relativeBBox(bool includeStroke) const
417 FloatRect rect;
419 RenderObject* current = firstChild();
420 for (; current != 0; current = current->nextSibling()) {
421 FloatRect childBBox = current->relativeBBox(includeStroke);
422 FloatRect mappedBBox = current->localTransform().mapRect(childBBox);
424 // <svg> can have a viewBox contributing to the bbox
425 if (current->isSVGContainer())
426 mappedBBox = static_cast<RenderSVGContainer*>(current)->viewportTransform().mapRect(mappedBBox);
428 rect.unite(mappedBBox);
431 return rect;
434 /*bool RenderSVGContainer::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction)
436 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
437 if (child->nodeAtPoint(request, result, _x, _y, _tx, _ty, hitTestAction)) {
438 updateHitTestResult(result, IntPoint(_x - _tx, _y - _ty));
439 return true;
443 // Spec: Only graphical elements can be targeted by the mouse, period.
444 // 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."
445 return false;
450 #endif // ENABLE(SVG)
452 // vim:ts=4