File indexing completed on 2024-04-28 15:24:17

0001 /*
0002     Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
0003                   2004, 2005, 2007 Rob Buis <buis@kde.org>
0004                   2007 Eric Seidel <eric@webkit.org>
0005 
0006     This file is part of the KDE project
0007 
0008     This library is free software; you can redistribute it and/or
0009     modify it under the terms of the GNU Library General Public
0010     License as published by the Free Software Foundation; either
0011     version 2 of the License, or (at your option) any later version.
0012 
0013     This library is distributed in the hope that it will be useful,
0014     but WITHOUT ANY WARRANTY; without even the implied warranty of
0015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0016     Library General Public License for more details.
0017 
0018     You should have received a copy of the GNU Library General Public License
0019     aint with this library; see the file COPYING.LIB.  If not, write to
0020     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0021     Boston, MA 02110-1301, USA.
0022 */
0023 
0024 #include "wtf/Platform.h"
0025 
0026 #if ENABLE(SVG)
0027 #include "RenderSVGContainer.h"
0028 
0029 /*#include "AXObjectCache.h"
0030 #include "GraphicsContext.h"*/
0031 #include "RenderView.h"
0032 #include "SVGRenderSupport.h"
0033 #include "SVGResourceFilter.h"
0034 #include "SVGStyledElement.h"
0035 #include "SVGURIReference.h"
0036 
0037 namespace WebCore
0038 {
0039 
0040 RenderSVGContainer::RenderSVGContainer(SVGStyledElement *node)
0041     : RenderObject(node)
0042     , m_firstChild(nullptr)
0043     , m_lastChild(nullptr)
0044     , m_width(0)
0045     , m_height(0)
0046     , m_drawsContents(true)
0047 {
0048     setReplaced(true);
0049 }
0050 
0051 RenderSVGContainer::~RenderSVGContainer()
0052 {
0053 }
0054 
0055 bool RenderSVGContainer::canHaveChildren() const
0056 {
0057     return true;
0058 }
0059 
0060 void RenderSVGContainer::addChild(RenderObject *newChild, RenderObject *beforeChild)
0061 {
0062     insertChildNode(newChild, beforeChild);
0063 }
0064 
0065 void RenderSVGContainer::removeChild(RenderObject *oldChild)
0066 {
0067     // We do this here instead of in removeChildNode, since the only extremely low-level uses of remove/appendChildNode
0068     // cannot affect the positioned object list, and the floating object list is irrelevant (since the list gets cleared on
0069     // layout anyway).
0070     oldChild->removeFromObjectLists();
0071 
0072     removeChildNode(oldChild);
0073 }
0074 
0075 void RenderSVGContainer::destroy()
0076 {
0077     /*destroyLeftoverChildren();
0078     RenderObject::destroy();*/
0079 }
0080 
0081 void RenderSVGContainer::destroyLeftoverChildren()
0082 {
0083     /*while (m_firstChild) {
0084         // 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.
0085         if (m_firstChild->element())
0086             m_firstChild->element()->setRenderer(0);
0087 
0088         m_firstChild->destroy();
0089     }*/
0090 }
0091 
0092 RenderObject *RenderSVGContainer::removeChildNode(RenderObject *oldChild)
0093 {
0094     ASSERT(oldChild->parent() == this);
0095     bool inCleanup = documentBeingDestroyed();
0096 
0097     // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or
0098     // that a positioned child got yanked).  We also repaint, so that the area exposed when the child
0099     // disappears gets repainted properly.
0100 
0101     if (!inCleanup) {
0102         oldChild->setNeedsLayoutAndMinMaxRecalc(); // Dirty the containing block chain
0103         oldChild->setNeedsLayout(false);   // The child itself does not need to layout - it's going away.
0104         oldChild->repaint();
0105     }
0106 
0107     // detach the place holder box
0108     if (oldChild->isBox()) {
0109         RenderBox *rb = static_cast<RenderBox *>(oldChild);
0110         InlineBox *ph = rb->placeHolderBox();
0111         if (ph) {
0112             ph->detach(rb->renderArena(), inCleanup /*NoRemove*/);
0113             rb->setPlaceHolderBox(nullptr);
0114         }
0115     }
0116 
0117     if (!inCleanup) {
0118         // If oldChild is the start or end of the selection, then clear the selection to
0119         // avoid problems of invalid pointers.
0120         // FIXME: The SelectionController should be responsible for this when it
0121         // is notified of DOM mutations.
0122         /* FIXME if (oldChild->isSelectionBorder())
0123             view()->clearSelection();*/
0124         if (oldChild->isSelectionBorder()) {
0125             canvas()->clearSelection();
0126         }
0127     }
0128 
0129     // remove the child
0130     if (oldChild->previousSibling()) {
0131         oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
0132     }
0133     if (oldChild->nextSibling()) {
0134         oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
0135     }
0136 
0137     if (m_firstChild == oldChild) {
0138         m_firstChild = oldChild->nextSibling();
0139     }
0140     if (m_lastChild == oldChild) {
0141         m_lastChild = oldChild->previousSibling();
0142     }
0143 
0144     oldChild->setPreviousSibling(nullptr);
0145     oldChild->setNextSibling(nullptr);
0146     oldChild->setParent(nullptr);
0147 
0148     /*if (AXObjectCache::accessibilityEnabled())
0149         document()->axObjectCache()->childrenChanged(this);*/
0150 
0151     return oldChild;
0152 }
0153 
0154 void RenderSVGContainer::appendChildNode(RenderObject *newChild)
0155 {
0156     ASSERT(!newChild->parent());
0157     /*khtml vtokarevASSERT(newChild->element()->isSVGElement());*/
0158     // remove it when I have SVG render text; SVGInlineText
0159 
0160     newChild->setParent(this);
0161     RenderObject *lChild = m_lastChild;
0162 
0163     if (lChild) {
0164         newChild->setPreviousSibling(lChild);
0165         lChild->setNextSibling(newChild);
0166     } else {
0167         m_firstChild = newChild;
0168     }
0169 
0170     m_lastChild = newChild;
0171 
0172     newChild->setNeedsLayoutAndMinMaxRecalc(); // Goes up the containing block hierarchy.*/
0173     if (!normalChildNeedsLayout()) {
0174         setChildNeedsLayout(true);    // We may supply the static position for an absolute positioned child.
0175     }
0176 
0177     /*if (AXObjectCache::accessibilityEnabled())
0178         document()->axObjectCache()->childrenChanged(this);*/
0179 }
0180 
0181 void RenderSVGContainer::insertChildNode(RenderObject *child, RenderObject *beforeChild)
0182 {
0183     if (!beforeChild) {
0184         appendChildNode(child);
0185         return;
0186     }
0187 
0188     ASSERT(!child->parent());
0189     ASSERT(beforeChild->parent() == this);
0190     ASSERT(child->element()->isSVGElement());
0191 
0192     if (beforeChild == m_firstChild) {
0193         m_firstChild = child;
0194     }
0195 
0196     RenderObject *prev = beforeChild->previousSibling();
0197     child->setNextSibling(beforeChild);
0198     beforeChild->setPreviousSibling(child);
0199     if (prev) {
0200         prev->setNextSibling(child);
0201     }
0202     child->setPreviousSibling(prev);
0203 
0204     child->setParent(this);
0205 
0206     child->setNeedsLayoutAndMinMaxRecalc();
0207     if (!normalChildNeedsLayout()) {
0208         setChildNeedsLayout(true);    // We may supply the static position for an absolute positioned child.
0209     }
0210 
0211     /*if (AXObjectCache::accessibilityEnabled())
0212         document()->axObjectCache()->childrenChanged(this);*/
0213 }
0214 
0215 bool RenderSVGContainer::drawsContents() const
0216 {
0217     return m_drawsContents;
0218 }
0219 
0220 void RenderSVGContainer::setDrawsContents(bool drawsContents)
0221 {
0222     m_drawsContents = drawsContents;
0223 }
0224 
0225 AffineTransform RenderSVGContainer::localTransform() const
0226 {
0227     return m_localTransform;
0228 }
0229 
0230 bool RenderSVGContainer::requiresLayer() const
0231 {
0232     // Only allow an <svg> element to generate a layer when it's positioned in a non-SVG context
0233     return false;
0234 }
0235 
0236 short RenderSVGContainer::lineHeight(bool b) const
0237 {
0238     Q_UNUSED(b);
0239     return height() + marginTop() + marginBottom();
0240 }
0241 
0242 short RenderSVGContainer::baselinePosition(bool b) const
0243 {
0244     Q_UNUSED(b);
0245     return height() + marginTop() + marginBottom();
0246 }
0247 
0248 bool RenderSVGContainer::calculateLocalTransform()
0249 {
0250     // subclasses can override this to add transform support
0251     return false;
0252 }
0253 
0254 void RenderSVGContainer::layout()
0255 {
0256     ASSERT(needsLayout());
0257 
0258     // Arbitrary affine transforms are incompatible with LayoutState.
0259     /*canvas()->disableLayoutState();*/
0260 
0261     /*IntRect oldBounds;
0262     IntRect oldOutlineBox;
0263     bool checkForRepaint = checkForRepaintDuringLayout() && selfWillPaint();
0264     if (checkForRepaint) {
0265         oldBounds = m_absoluteBounds;
0266         oldOutlineBox = absoluteOutlineBox();
0267     }*/
0268 
0269     calculateLocalTransform();
0270 
0271     for (RenderObject *child = firstChild(); child; child = child->nextSibling()) {
0272         // ### TODO: we only want to relayout if our size/transform changed kids
0273         if (child->isText()) {
0274             continue;
0275         }
0276         child->setNeedsLayout(true);
0277         child->layoutIfNeeded();
0278         ASSERT(!child->needsLayout());
0279     }
0280 
0281     calcBounds();
0282 
0283     /*if (checkForRepaint)
0284         repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);*/
0285 
0286     /*canvas()->enableLayoutState();*/
0287     setNeedsLayout(false);
0288 }
0289 
0290 int RenderSVGContainer::calcReplacedWidth() const
0291 {
0292     switch (style()->width().type()) {
0293     case Fixed:
0294         return qMax(0, style()->width().value());
0295     case Percent: {
0296         const int cw = containingBlockWidth();
0297         return cw > 0 ? qMax(0, style()->width().minWidth(cw)) : 0;
0298     }
0299     default:
0300         return 0;
0301     }
0302 }
0303 
0304 int RenderSVGContainer::calcReplacedHeight() const
0305 {
0306     switch (style()->height().type()) {
0307     case Fixed:
0308         return qMax(0, style()->height().value());
0309     case Percent: {
0310         RenderBlock *cb = containingBlock();
0311         return style()->height().width(cb->availableHeight());
0312     }
0313     default:
0314         return 0;
0315     }
0316 }
0317 
0318 void RenderSVGContainer::applyContentTransforms(PaintInfo &paintInfo)
0319 {
0320     if (!localTransform().isIdentity()) {
0321         paintInfo.p->setWorldMatrix(localTransform(), true);
0322     }
0323     /*paintInfo.context->concatCTM(localTransform());*/
0324 }
0325 
0326 void RenderSVGContainer::applyAdditionalTransforms(PaintInfo &paintInfo)
0327 {
0328     Q_UNUSED(paintInfo);
0329     // no-op
0330 }
0331 
0332 void RenderSVGContainer::calcBounds()
0333 {
0334     m_width = calcReplacedWidth();
0335     m_height = calcReplacedHeight();
0336     //m_absoluteBounds = absoluteClippedOverflowRect();
0337 }
0338 
0339 bool RenderSVGContainer::selfWillPaint() const
0340 {
0341 #if ENABLE(SVG_FILTERS)
0342     const SVGRenderStyle *svgStyle = style()->svgStyle();
0343     AtomicString filterId(SVGURIReference::getTarget(svgStyle->filter()));
0344     SVGResourceFilter *filter = getFilterById(document(), filterId);
0345     if (filter) {
0346         return true;
0347     }
0348 #endif
0349     return false;
0350 }
0351 
0352 void RenderSVGContainer::paint(PaintInfo &paintInfo, int parentX, int parentY)
0353 {
0354     Q_UNUSED(parentX);
0355     Q_UNUSED(parentY);
0356     if (/*paintInfo.context->paintingDisabled() || */!drawsContents()) {
0357         return;
0358     }
0359 
0360     // Spec: groups w/o children still may render filter content.
0361     /*if (!firstChild() && !selfWillPaint())
0362         return;*/
0363 
0364     paintInfo.p->save();
0365     applyContentTransforms(paintInfo);
0366 
0367     SVGResourceFilter *filter = nullptr;
0368     /*PaintInfo savedInfo(paintInfo);*/
0369 
0370     FloatRect boundingBox = relativeBBox(true);
0371     /*if (paintInfo.phase == PaintPhaseForeground)*/
0372     prepareToRenderSVGContent(this, paintInfo, boundingBox, filter);
0373 
0374     applyAdditionalTransforms(paintInfo);
0375 
0376     // default implementation. Just pass paint through to the children
0377     PaintInfo childInfo(paintInfo);
0378     /*childInfo.paintingRoot = paintingRootForChildren(paintInfo);*/
0379     for (RenderObject *child = firstChild(); child; child = child->nextSibling()) {
0380         child->paint(childInfo, 0, 0);
0381     }
0382 
0383     /*if (paintInfo.phase == PaintPhaseForeground)
0384         finishRenderSVGContent(this, paintInfo, boundingBox, filter, savedInfo.context);*/
0385 
0386     paintInfo.p->restore();
0387 
0388     /*if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE)
0389         paintOutline(paintInfo.context, m_absoluteBounds.x(), m_absoluteBounds.y(), m_absoluteBounds.width(), m_absoluteBounds.height(), style());*/
0390 }
0391 
0392 AffineTransform RenderSVGContainer::viewportTransform() const
0393 {
0394     return AffineTransform();
0395 }
0396 
0397 IntRect RenderSVGContainer::absoluteClippedOverflowRect()
0398 {
0399     /*FloatRect repaintRect;
0400 
0401     for (RenderObject* current = firstChild(); current != 0; current = current->nextSibling())
0402         repaintRect.unite(current->absoluteClippedOverflowRect());
0403 
0404     #if ENABLE(SVG_FILTERS)
0405     // Filters can expand the bounding box
0406     SVGResourceFilter* filter = getFilterById(document(), SVGURIReference::getTarget(style()->svgStyle()->filter()));
0407     if (filter)
0408         repaintRect.unite(filter->filterBBoxForItemBBox(repaintRect));
0409     #endif
0410 
0411     if (!repaintRect.isEmpty())
0412         repaintRect.inflate(1); // inflate 1 pixel for antialiasing
0413 
0414     return enclosingIntRect(repaintRect);*/
0415     ASSERT(false);
0416     return IntRect();
0417 }
0418 
0419 void RenderSVGContainer::absoluteRects(Vector<IntRect> &rects, int, int, bool)
0420 {
0421     Q_UNUSED(rects);
0422     //FIXME rects.append(absoluteClippedOverflowRect());
0423 }
0424 
0425 FloatRect RenderSVGContainer::relativeBBox(bool includeStroke) const
0426 {
0427     FloatRect rect;
0428 
0429     RenderObject *current = firstChild();
0430     for (; current != nullptr; current = current->nextSibling()) {
0431         FloatRect childBBox = current->relativeBBox(includeStroke);
0432         FloatRect mappedBBox = current->localTransform().mapRect(childBBox);
0433 
0434         // <svg> can have a viewBox contributing to the bbox
0435         if (current->isSVGContainer()) {
0436             mappedBBox = static_cast<RenderSVGContainer *>(current)->viewportTransform().mapRect(mappedBBox);
0437         }
0438 
0439         rect.unite(mappedBBox);
0440     }
0441 
0442     return rect;
0443 }
0444 
0445 /*bool RenderSVGContainer::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction)
0446 {
0447     for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
0448         if (child->nodeAtPoint(request, result, _x, _y, _tx, _ty, hitTestAction)) {
0449             updateHitTestResult(result, IntPoint(_x - _tx, _y - _ty));
0450             return true;
0451         }
0452     }
0453 
0454     // Spec: Only graphical elements can be targeted by the mouse, period.
0455     // 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."
0456     return false;
0457 }*/
0458 
0459 }
0460 
0461 #endif // ENABLE(SVG)
0462