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/platform/graphics/GraphicsContextStateSaver.h"
     29 #include "core/rendering/LayoutRepainter.h"
     30 #include "core/rendering/RenderView.h"
     31 #include "core/rendering/svg/SVGRenderingContext.h"
     32 #include "core/rendering/svg/SVGResources.h"
     33 #include "core/rendering/svg/SVGResourcesCache.h"
     34 
     35 namespace WebCore {
     36 
     37 RenderSVGContainer::RenderSVGContainer(SVGElement* node)
     38     : RenderSVGModelObject(node)
     39     , m_objectBoundingBoxValid(false)
     40     , m_needsBoundariesUpdate(true)
     41 {
     42 }
     43 
     44 RenderSVGContainer::~RenderSVGContainer()
     45 {
     46 }
     47 
     48 void RenderSVGContainer::layout()
     49 {
     50     StackStats::LayoutCheckPoint layoutCheckPoint;
     51     ASSERT(needsLayout());
     52 
     53     // RenderSVGRoot disables layoutState for the SVG rendering tree.
     54     ASSERT(!view()->layoutStateEnabled());
     55 
     56     LayoutRepainter repainter(*this, SVGRenderSupport::checkForSVGRepaintDuringLayout(this) || selfWillPaint());
     57 
     58     // Allow RenderSVGViewportContainer to update its viewport.
     59     calcViewport();
     60 
     61     // Allow RenderSVGTransformableContainer to update its transform.
     62     bool updatedTransform = calculateLocalTransform();
     63 
     64     // RenderSVGViewportContainer needs to set the 'layout size changed' flag.
     65     determineIfLayoutSizeChanged();
     66 
     67     SVGRenderSupport::layoutChildren(this, selfNeedsLayout() || SVGRenderSupport::filtersForceContainerLayout(this));
     68 
     69     // Invalidate all resources of this client if our layout changed.
     70     if (everHadLayout() && needsLayout())
     71         SVGResourcesCache::clientLayoutChanged(this);
     72 
     73     // At this point LayoutRepainter already grabbed the old bounds,
     74     // recalculate them now so repaintAfterLayout() uses the new bounds.
     75     if (m_needsBoundariesUpdate || updatedTransform) {
     76         updateCachedBoundaries();
     77         m_needsBoundariesUpdate = false;
     78 
     79         // If our bounds changed, notify the parents.
     80         RenderSVGModelObject::setNeedsBoundariesUpdate();
     81     }
     82 
     83     repainter.repaintAfterLayout();
     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     if (paintInfo.context->paintingDisabled())
    111         return;
    112 
    113     // Spec: groups w/o children still may render filter content.
    114     if (!firstChild() && !selfWillPaint())
    115         return;
    116 
    117     FloatRect repaintRect = repaintRectInLocalCoordinates();
    118     if (!SVGRenderSupport::paintInfoIntersectsRepaintRect(repaintRect, localToParentTransform(), paintInfo))
    119         return;
    120 
    121     PaintInfo childPaintInfo(paintInfo);
    122     {
    123         GraphicsContextStateSaver stateSaver(*childPaintInfo.context);
    124 
    125         // Let the RenderSVGViewportContainer subclass clip if necessary
    126         applyViewportClip(childPaintInfo);
    127 
    128         childPaintInfo.applyTransform(localToParentTransform());
    129 
    130         SVGRenderingContext renderingContext;
    131         bool continueRendering = true;
    132         if (childPaintInfo.phase == PaintPhaseForeground) {
    133             renderingContext.prepareToRenderSVGContent(this, childPaintInfo);
    134             continueRendering = renderingContext.isRenderingPrepared();
    135         }
    136 
    137         if (continueRendering) {
    138             childPaintInfo.updatePaintingRootForChildren(this);
    139             for (RenderObject* child = firstChild(); child; child = child->nextSibling())
    140                 child->paint(childPaintInfo, IntPoint());
    141         }
    142     }
    143 
    144     // FIXME: This really should be drawn from local coordinates, but currently we hack it
    145     // to avoid our clip killing our outline rect.  Thus we translate our
    146     // outline rect into parent coords before drawing.
    147     // FIXME: This means our focus ring won't share our rotation like it should.
    148     // We should instead disable our clip during PaintPhaseOutline
    149     if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE) {
    150         IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRect));
    151         paintOutline(paintInfo, paintRectInParent);
    152     }
    153 }
    154 
    155 // addFocusRingRects is called from paintOutline and needs to be in the same coordinates as the paintOuline call
    156 void RenderSVGContainer::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint&, const RenderLayerModelObject*)
    157 {
    158     IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates()));
    159     if (!paintRectInParent.isEmpty())
    160         rects.append(paintRectInParent);
    161 }
    162 
    163 void RenderSVGContainer::updateCachedBoundaries()
    164 {
    165     SVGRenderSupport::computeContainerBoundingBoxes(this, m_objectBoundingBox, m_objectBoundingBoxValid, m_strokeBoundingBox, m_repaintBoundingBox);
    166     SVGRenderSupport::intersectRepaintRectWithResources(this, m_repaintBoundingBox);
    167 }
    168 
    169 bool RenderSVGContainer::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
    170 {
    171     // Give RenderSVGViewportContainer a chance to apply its viewport clip
    172     if (!pointIsInsideViewportClip(pointInParent))
    173         return false;
    174 
    175     FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent);
    176 
    177     if (!SVGRenderSupport::pointInClippingArea(this, 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     // Spec: Only graphical elements can be targeted by the mouse, period.
    188     // 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."
    189     return false;
    190 }
    191 
    192 }
    193