Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann (at) kde.org>
      3  * Copyright (C) 2004, 2005, 2007, 2008 Rob Buis <buis (at) kde.org>
      4  * Copyright (C) 2007 Eric Seidel <eric (at) webkit.org>
      5  * Copyright (C) 2009 Google, Inc.  All rights reserved.
      6  * Copyright (C) 2009 Dirk Schulze <krit (at) webkit.org>
      7  *
      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.
     12  *
     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.
     17  *
     18  * You should have received a copy of the GNU Library General Public License
     19  * along 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.
     22  */
     23 
     24 #include "config.h"
     25 
     26 #include "core/rendering/svg/RenderSVGContainer.h"
     27 
     28 #include "core/frame/Settings.h"
     29 #include "core/rendering/GraphicsContextAnnotator.h"
     30 #include "core/rendering/RenderView.h"
     31 #include "core/rendering/svg/SVGRenderSupport.h"
     32 #include "core/rendering/svg/SVGRenderingContext.h"
     33 #include "core/rendering/svg/SVGResources.h"
     34 #include "core/rendering/svg/SVGResourcesCache.h"
     35 #include "platform/graphics/GraphicsContextCullSaver.h"
     36 #include "platform/graphics/GraphicsContextStateSaver.h"
     37 
     38 namespace blink {
     39 
     40 RenderSVGContainer::RenderSVGContainer(SVGElement* node)
     41     : RenderSVGModelObject(node)
     42     , m_objectBoundingBoxValid(false)
     43     , m_needsBoundariesUpdate(true)
     44 {
     45 }
     46 
     47 RenderSVGContainer::~RenderSVGContainer()
     48 {
     49 }
     50 
     51 void RenderSVGContainer::trace(Visitor* visitor)
     52 {
     53     visitor->trace(m_children);
     54     RenderSVGModelObject::trace(visitor);
     55 }
     56 
     57 void RenderSVGContainer::layout()
     58 {
     59     ASSERT(needsLayout());
     60 
     61     // Allow RenderSVGViewportContainer to update its viewport.
     62     calcViewport();
     63 
     64     // Allow RenderSVGTransformableContainer to update its transform.
     65     bool updatedTransform = calculateLocalTransform();
     66 
     67     // RenderSVGViewportContainer needs to set the 'layout size changed' flag.
     68     determineIfLayoutSizeChanged();
     69 
     70     SVGRenderSupport::layoutChildren(this, selfNeedsLayout() || SVGRenderSupport::filtersForceContainerLayout(this));
     71 
     72     // Invalidate all resources of this client if our layout changed.
     73     if (everHadLayout() && needsLayout())
     74         SVGResourcesCache::clientLayoutChanged(this);
     75 
     76     if (m_needsBoundariesUpdate || updatedTransform) {
     77         updateCachedBoundaries();
     78         m_needsBoundariesUpdate = false;
     79 
     80         // If our bounds changed, notify the parents.
     81         RenderSVGModelObject::setNeedsBoundariesUpdate();
     82     }
     83 
     84     clearNeedsLayout();
     85 }
     86 
     87 void RenderSVGContainer::addChild(RenderObject* child, RenderObject* beforeChild)
     88 {
     89     RenderSVGModelObject::addChild(child, beforeChild);
     90     SVGResourcesCache::clientWasAddedToTree(child, child->style());
     91 }
     92 
     93 void RenderSVGContainer::removeChild(RenderObject* child)
     94 {
     95     SVGResourcesCache::clientWillBeRemovedFromTree(child);
     96     RenderSVGModelObject::removeChild(child);
     97 }
     98 
     99 
    100 bool RenderSVGContainer::selfWillPaint()
    101 {
    102     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this);
    103     return resources && resources->filter();
    104 }
    105 
    106 void RenderSVGContainer::paint(PaintInfo& paintInfo, const LayoutPoint&)
    107 {
    108     ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this);
    109 
    110     // Spec: groups w/o children still may render filter content.
    111     if (!firstChild() && !selfWillPaint())
    112         return;
    113 
    114     FloatRect paintInvalidationRect = paintInvalidationRectInLocalCoordinates();
    115     if (!SVGRenderSupport::paintInfoIntersectsPaintInvalidationRect(paintInvalidationRect, localToParentTransform(), paintInfo))
    116         return;
    117 
    118     PaintInfo childPaintInfo(paintInfo);
    119     {
    120         GraphicsContextStateSaver stateSaver(*childPaintInfo.context);
    121 
    122         // Let the RenderSVGViewportContainer subclass clip if necessary
    123         applyViewportClip(childPaintInfo);
    124 
    125         childPaintInfo.applyTransform(localToParentTransform());
    126 
    127         SVGRenderingContext renderingContext;
    128         GraphicsContextCullSaver cullSaver(*childPaintInfo.context);
    129         bool continueRendering = true;
    130         if (childPaintInfo.phase == PaintPhaseForeground) {
    131             renderingContext.prepareToRenderSVGContent(this, childPaintInfo);
    132             continueRendering = renderingContext.isRenderingPrepared();
    133 
    134             if (continueRendering && document().settings()->containerCullingEnabled())
    135                 cullSaver.cull(paintInvalidationRectInLocalCoordinates());
    136         }
    137 
    138         if (continueRendering) {
    139             childPaintInfo.updatePaintingRootForChildren(this);
    140             for (RenderObject* child = firstChild(); child; child = child->nextSibling())
    141                 child->paint(childPaintInfo, IntPoint());
    142         }
    143     }
    144 
    145     // FIXME: This really should be drawn from local coordinates, but currently we hack it
    146     // to avoid our clip killing our outline rect. Thus we translate our
    147     // outline rect into parent coords before drawing.
    148     // FIXME: This means our focus ring won't share our rotation like it should.
    149     // We should instead disable our clip during PaintPhaseOutline
    150     if (paintInfo.phase == PaintPhaseForeground && style()->outlineWidth() && style()->visibility() == VISIBLE) {
    151         IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(paintInvalidationRect));
    152         paintOutline(paintInfo, paintRectInParent);
    153     }
    154 }
    155 
    156 // addFocusRingRects is called from paintOutline and needs to be in the same coordinates as the paintOuline call
    157 void RenderSVGContainer::addFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoint&, const RenderLayerModelObject*) const
    158 {
    159     LayoutRect paintRectInParent = LayoutRect(localToParentTransform().mapRect(paintInvalidationRectInLocalCoordinates()));
    160     if (!paintRectInParent.isEmpty())
    161         rects.append(paintRectInParent);
    162 }
    163 
    164 void RenderSVGContainer::updateCachedBoundaries()
    165 {
    166     SVGRenderSupport::computeContainerBoundingBoxes(this, m_objectBoundingBox, m_objectBoundingBoxValid, m_strokeBoundingBox, m_paintInvalidationBoundingBox);
    167     SVGRenderSupport::intersectPaintInvalidationRectWithResources(this, m_paintInvalidationBoundingBox);
    168 }
    169 
    170 bool RenderSVGContainer::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
    171 {
    172     // Give RenderSVGViewportContainer a chance to apply its viewport clip
    173     if (!pointIsInsideViewportClip(pointInParent))
    174         return false;
    175 
    176     FloatPoint localPoint;
    177     if (!SVGRenderSupport::transformToUserSpaceAndCheckClipping(this, localToParentTransform(), pointInParent, localPoint))
    178         return false;
    179 
    180     for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
    181         if (child->nodeAtFloatPoint(request, result, localPoint, hitTestAction)) {
    182             updateHitTestResult(result, roundedLayoutPoint(localPoint));
    183             return true;
    184         }
    185     }
    186 
    187     // pointer-events=boundingBox makes it possible for containers to be direct targets
    188     if (style()->pointerEvents() == PE_BOUNDINGBOX) {
    189         ASSERT(isObjectBoundingBoxValid());
    190         if (objectBoundingBox().contains(localPoint)) {
    191             updateHitTestResult(result, roundedLayoutPoint(localPoint));
    192             return true;
    193         }
    194     }
    195     // 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."
    196     return false;
    197 }
    198 
    199 }
    200