File indexing completed on 2024-05-05 12:16:13
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