Home | History | Annotate | Download | only in rendering
      1 /*
      2     Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann (at) kde.org>
      3                   2004, 2005, 2007, 2008 Rob Buis <buis (at) kde.org>
      4                   2007 Eric Seidel <eric (at) webkit.org>
      5     Copyright (C) 2009 Google, Inc.  All rights reserved.
      6                   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     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.
     22 */
     23 
     24 #include "config.h"
     25 
     26 #if ENABLE(SVG)
     27 #include "RenderSVGContainer.h"
     28 
     29 #include "GraphicsContext.h"
     30 #include "RenderView.h"
     31 #include "SVGRenderSupport.h"
     32 #include "SVGResourceFilter.h"
     33 #include "SVGStyledElement.h"
     34 
     35 namespace WebCore {
     36 
     37 RenderSVGContainer::RenderSVGContainer(SVGStyledElement* node)
     38     : RenderSVGModelObject(node)
     39     , m_drawsContents(true)
     40 {
     41 }
     42 
     43 bool RenderSVGContainer::drawsContents() const
     44 {
     45     return m_drawsContents;
     46 }
     47 
     48 void RenderSVGContainer::setDrawsContents(bool drawsContents)
     49 {
     50     m_drawsContents = drawsContents;
     51 }
     52 
     53 void RenderSVGContainer::layout()
     54 {
     55     ASSERT(needsLayout());
     56     ASSERT(!view()->layoutStateEnabled()); // RenderSVGRoot disables layoutState for the SVG rendering tree.
     57 
     58     calcViewport(); // Allow RenderSVGViewportContainer to update its viewport
     59 
     60     LayoutRepainter repainter(*this, checkForRepaintDuringLayout() || selfWillPaint());
     61     calculateLocalTransform(); // Allow RenderSVGTransformableContainer to update its transform
     62 
     63     layoutChildren(this, selfNeedsLayout());
     64     repainter.repaintAfterLayout();
     65 
     66     setNeedsLayout(false);
     67 }
     68 
     69 bool RenderSVGContainer::selfWillPaint() const
     70 {
     71 #if ENABLE(FILTERS)
     72     const SVGRenderStyle* svgStyle = style()->svgStyle();
     73     SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter(), this);
     74     if (filter)
     75         return true;
     76 #endif
     77     return false;
     78 }
     79 
     80 void RenderSVGContainer::paint(PaintInfo& paintInfo, int, int)
     81 {
     82     if (paintInfo.context->paintingDisabled() || !drawsContents())
     83         return;
     84 
     85     // Spec: groups w/o children still may render filter content.
     86     if (!firstChild() && !selfWillPaint())
     87         return;
     88 
     89     PaintInfo childPaintInfo(paintInfo);
     90 
     91     childPaintInfo.context->save();
     92 
     93     // Let the RenderSVGViewportContainer subclass clip if necessary
     94     applyViewportClip(childPaintInfo);
     95 
     96     applyTransformToPaintInfo(childPaintInfo, localToParentTransform());
     97 
     98     SVGResourceFilter* filter = 0;
     99     FloatRect boundingBox = repaintRectInLocalCoordinates();
    100 
    101     bool continueRendering = true;
    102     if (childPaintInfo.phase == PaintPhaseForeground)
    103         continueRendering = prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter);
    104 
    105     if (continueRendering) {
    106         childPaintInfo.paintingRoot = paintingRootForChildren(childPaintInfo);
    107         for (RenderObject* child = firstChild(); child; child = child->nextSibling())
    108             child->paint(childPaintInfo, 0, 0);
    109     }
    110 
    111     if (paintInfo.phase == PaintPhaseForeground)
    112         finishRenderSVGContent(this, childPaintInfo, filter, paintInfo.context);
    113 
    114     childPaintInfo.context->restore();
    115 
    116     // FIXME: This really should be drawn from local coordinates, but currently we hack it
    117     // to avoid our clip killing our outline rect.  Thus we translate our
    118     // outline rect into parent coords before drawing.
    119     // FIXME: This means our focus ring won't share our rotation like it should.
    120     // We should instead disable our clip during PaintPhaseOutline
    121     IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates()));
    122     if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE)
    123         paintOutline(paintInfo.context, paintRectInParent.x(), paintRectInParent.y(), paintRectInParent.width(), paintRectInParent.height(), style());
    124 }
    125 
    126 // addFocusRingRects is called from paintOutline and needs to be in the same coordinates as the paintOuline call
    127 void RenderSVGContainer::addFocusRingRects(Vector<IntRect>& rects, int, int)
    128 {
    129     IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates()));
    130     if (!paintRectInParent.isEmpty())
    131         rects.append(paintRectInParent);
    132 }
    133 
    134 FloatRect RenderSVGContainer::objectBoundingBox() const
    135 {
    136     return computeContainerBoundingBox(this, false);
    137 }
    138 
    139 FloatRect RenderSVGContainer::strokeBoundingBox() const
    140 {
    141     return computeContainerBoundingBox(this, true);
    142 }
    143 
    144 // RenderSVGContainer is used for <g> elements which do not themselves have a
    145 // width or height, so we union all of our child rects as our repaint rect.
    146 FloatRect RenderSVGContainer::repaintRectInLocalCoordinates() const
    147 {
    148     FloatRect repaintRect = computeContainerBoundingBox(this, true);
    149 
    150     FloatRect rect = filterBoundingBoxForRenderer(this);
    151     if (!rect.isEmpty())
    152         repaintRect = rect;
    153 
    154     rect = clipperBoundingBoxForRenderer(this);
    155     if (!rect.isEmpty())
    156         repaintRect.intersect(rect);
    157 
    158     rect = maskerBoundingBoxForRenderer(this);
    159     if (!rect.isEmpty())
    160         repaintRect.intersect(rect);
    161 
    162     style()->svgStyle()->inflateForShadow(repaintRect);
    163 
    164     return repaintRect;
    165 }
    166 
    167 bool RenderSVGContainer::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
    168 {
    169     // Give RenderSVGViewportContainer a chance to apply its viewport clip
    170     if (!pointIsInsideViewportClip(pointInParent))
    171         return false;
    172 
    173     FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent);
    174 
    175     for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
    176         if (child->nodeAtFloatPoint(request, result, localPoint, hitTestAction)) {
    177             updateHitTestResult(result, roundedIntPoint(localPoint));
    178             return true;
    179         }
    180     }
    181 
    182     // Spec: Only graphical elements can be targeted by the mouse, period.
    183     // 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."
    184     return false;
    185 }
    186 
    187 }
    188 
    189 #endif // ENABLE(SVG)
    190