Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) 2007, 2008 Rob Buis <buis (at) kde.org>
      3  * Copyright (C) 2007 Nikolas Zimmermann <zimmermann (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  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
      8  *
      9  * This library is free software; you can redistribute it and/or
     10  * modify it under the terms of the GNU Library General Public
     11  * License as published by the Free Software Foundation; either
     12  * version 2 of the License, or (at your option) any later version.
     13  *
     14  * This library is distributed in the hope that it will be useful,
     15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17  * Library General Public License for more details.
     18  *
     19  * You should have received a copy of the GNU Library General Public License
     20  * along with this library; see the file COPYING.LIB.  If not, write to
     21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     22  * Boston, MA 02110-1301, USA.
     23  */
     24 
     25 #include "config.h"
     26 
     27 #if ENABLE(SVG)
     28 #include "SVGRenderSupport.h"
     29 
     30 #include "FrameView.h"
     31 #include "ImageBuffer.h"
     32 #include "NodeRenderStyle.h"
     33 #include "RenderLayer.h"
     34 #include "RenderSVGPath.h"
     35 #include "RenderSVGResource.h"
     36 #include "RenderSVGResourceClipper.h"
     37 #include "RenderSVGResourceFilter.h"
     38 #include "RenderSVGResourceMarker.h"
     39 #include "RenderSVGResourceMasker.h"
     40 #include "RenderSVGRoot.h"
     41 #include "SVGResources.h"
     42 #include "SVGStyledElement.h"
     43 #include "TransformState.h"
     44 #include <wtf/UnusedParam.h>
     45 
     46 namespace WebCore {
     47 
     48 IntRect SVGRenderSupport::clippedOverflowRectForRepaint(RenderObject* object, RenderBoxModelObject* repaintContainer)
     49 {
     50     // Return early for any cases where we don't actually paint
     51     if (object->style()->visibility() != VISIBLE && !object->enclosingLayer()->hasVisibleContent())
     52         return IntRect();
     53 
     54     // Pass our local paint rect to computeRectForRepaint() which will
     55     // map to parent coords and recurse up the parent chain.
     56     IntRect repaintRect = enclosingIntRect(object->repaintRectInLocalCoordinates());
     57     object->computeRectForRepaint(repaintContainer, repaintRect);
     58     return repaintRect;
     59 }
     60 
     61 void SVGRenderSupport::computeRectForRepaint(RenderObject* object, RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed)
     62 {
     63     const SVGRenderStyle* svgStyle = object->style()->svgStyle();
     64     if (const ShadowData* shadow = svgStyle->shadow())
     65         shadow->adjustRectForShadow(repaintRect);
     66 
     67     // Translate to coords in our parent renderer, and then call computeRectForRepaint on our parent
     68     repaintRect = object->localToParentTransform().mapRect(repaintRect);
     69     object->parent()->computeRectForRepaint(repaintContainer, repaintRect, fixed);
     70 }
     71 
     72 void SVGRenderSupport::mapLocalToContainer(const RenderObject* object, RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState)
     73 {
     74     ASSERT(!fixed); // We should have no fixed content in the SVG rendering tree.
     75     ASSERT(useTransforms); // Mapping a point through SVG w/o respecting transforms is useless.
     76     transformState.applyTransform(object->localToParentTransform());
     77     object->parent()->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState);
     78 }
     79 
     80 bool SVGRenderSupport::prepareToRenderSVGContent(RenderObject* object, PaintInfo& paintInfo)
     81 {
     82     ASSERT(object);
     83 
     84     RenderStyle* style = object->style();
     85     ASSERT(style);
     86 
     87     const SVGRenderStyle* svgStyle = style->svgStyle();
     88     ASSERT(svgStyle);
     89 
     90     // Setup transparency layers before setting up SVG resources!
     91     float opacity = style->opacity();
     92     const ShadowData* shadow = svgStyle->shadow();
     93     if (opacity < 1 || shadow) {
     94         FloatRect repaintRect = object->repaintRectInLocalCoordinates();
     95 
     96         if (opacity < 1) {
     97             paintInfo.context->clip(repaintRect);
     98             paintInfo.context->beginTransparencyLayer(opacity);
     99         }
    100 
    101         if (shadow) {
    102             paintInfo.context->clip(repaintRect);
    103             paintInfo.context->setShadow(IntSize(shadow->x(), shadow->y()), shadow->blur(), shadow->color(), style->colorSpace());
    104             paintInfo.context->beginTransparencyLayer(1);
    105         }
    106     }
    107 
    108     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
    109     if (!resources)
    110         return true;
    111 
    112     if (RenderSVGResourceMasker* masker = resources->masker()) {
    113         if (!masker->applyResource(object, style, paintInfo.context, ApplyToDefaultMode))
    114             return false;
    115     }
    116 
    117     if (RenderSVGResourceClipper* clipper = resources->clipper()) {
    118         if (!clipper->applyResource(object, style, paintInfo.context, ApplyToDefaultMode))
    119             return false;
    120     }
    121 
    122 #if ENABLE(FILTERS)
    123     if (RenderSVGResourceFilter* filter = resources->filter()) {
    124         if (!filter->applyResource(object, style, paintInfo.context, ApplyToDefaultMode))
    125             return false;
    126     }
    127 #endif
    128 
    129     return true;
    130 }
    131 
    132 void SVGRenderSupport::finishRenderSVGContent(RenderObject* object, PaintInfo& paintInfo, GraphicsContext* savedContext)
    133 {
    134 #if !ENABLE(FILTERS)
    135     UNUSED_PARAM(savedContext);
    136 #endif
    137 
    138     ASSERT(object);
    139 
    140     const RenderStyle* style = object->style();
    141     ASSERT(style);
    142 
    143     const SVGRenderStyle* svgStyle = style->svgStyle();
    144     ASSERT(svgStyle);
    145 
    146 #if ENABLE(FILTERS)
    147     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
    148     if (resources) {
    149         if (RenderSVGResourceFilter* filter = resources->filter()) {
    150             filter->postApplyResource(object, paintInfo.context, ApplyToDefaultMode, /* path */0);
    151             paintInfo.context = savedContext;
    152         }
    153     }
    154 #endif
    155 
    156     if (style->opacity() < 1)
    157         paintInfo.context->endTransparencyLayer();
    158 
    159     if (svgStyle->shadow())
    160         paintInfo.context->endTransparencyLayer();
    161 }
    162 
    163 void SVGRenderSupport::computeContainerBoundingBoxes(const RenderObject* container, FloatRect& objectBoundingBox, FloatRect& strokeBoundingBox, FloatRect& repaintBoundingBox)
    164 {
    165     for (RenderObject* current = container->firstChild(); current; current = current->nextSibling()) {
    166         if (current->isSVGHiddenContainer())
    167             continue;
    168 
    169         const AffineTransform& transform = current->localToParentTransform();
    170         if (transform.isIdentity()) {
    171             objectBoundingBox.unite(current->objectBoundingBox());
    172             strokeBoundingBox.unite(current->strokeBoundingBox());
    173             repaintBoundingBox.unite(current->repaintRectInLocalCoordinates());
    174         } else {
    175             objectBoundingBox.unite(transform.mapRect(current->objectBoundingBox()));
    176             strokeBoundingBox.unite(transform.mapRect(current->strokeBoundingBox()));
    177             repaintBoundingBox.unite(transform.mapRect(current->repaintRectInLocalCoordinates()));
    178         }
    179     }
    180 }
    181 
    182 bool SVGRenderSupport::paintInfoIntersectsRepaintRect(const FloatRect& localRepaintRect, const AffineTransform& localTransform, const PaintInfo& paintInfo)
    183 {
    184     if (localTransform.isIdentity())
    185         return localRepaintRect.intersects(paintInfo.rect);
    186 
    187     return localTransform.mapRect(localRepaintRect).intersects(paintInfo.rect);
    188 }
    189 
    190 const RenderSVGRoot* SVGRenderSupport::findTreeRootObject(const RenderObject* start)
    191 {
    192     while (start && !start->isSVGRoot())
    193         start = start->parent();
    194 
    195     ASSERT(start);
    196     ASSERT(start->isSVGRoot());
    197     return toRenderSVGRoot(start);
    198 }
    199 
    200 static inline void invalidateResourcesOfChildren(RenderObject* start)
    201 {
    202     ASSERT(!start->needsLayout());
    203     if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(start))
    204         resources->removeClientFromCache(start, false);
    205 
    206     for (RenderObject* child = start->firstChild(); child; child = child->nextSibling())
    207         invalidateResourcesOfChildren(child);
    208 }
    209 
    210 void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout)
    211 {
    212     bool layoutSizeChanged = findTreeRootObject(start)->isLayoutSizeChanged();
    213     HashSet<RenderObject*> notlayoutedObjects;
    214 
    215     for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
    216         bool needsLayout = selfNeedsLayout;
    217 
    218         if (layoutSizeChanged) {
    219             // When selfNeedsLayout is false and the layout size changed, we have to check whether this child uses relative lengths
    220             if (SVGElement* element = child->node()->isSVGElement() ? static_cast<SVGElement*>(child->node()) : 0) {
    221                 if (element->isStyled() && static_cast<SVGStyledElement*>(element)->hasRelativeLengths()) {
    222                     // When the layout size changed and when using relative values tell the RenderSVGPath to update its Path object
    223                     if (child->isSVGPath())
    224                         toRenderSVGPath(child)->setNeedsPathUpdate();
    225 
    226                     needsLayout = true;
    227                 }
    228             }
    229         }
    230 
    231         if (needsLayout) {
    232             child->setNeedsLayout(true, false);
    233             child->layout();
    234         } else {
    235             if (child->needsLayout())
    236                 child->layout();
    237             else if (layoutSizeChanged)
    238                 notlayoutedObjects.add(child);
    239         }
    240 
    241         ASSERT(!child->needsLayout());
    242     }
    243 
    244     if (!layoutSizeChanged) {
    245         ASSERT(notlayoutedObjects.isEmpty());
    246         return;
    247     }
    248 
    249     // If the layout size changed, invalidate all resources of all children that didn't go through the layout() code path.
    250     HashSet<RenderObject*>::iterator end = notlayoutedObjects.end();
    251     for (HashSet<RenderObject*>::iterator it = notlayoutedObjects.begin(); it != end; ++it)
    252         invalidateResourcesOfChildren(*it);
    253 }
    254 
    255 bool SVGRenderSupport::isOverflowHidden(const RenderObject* object)
    256 {
    257     // SVG doesn't support independent x/y overflow
    258     ASSERT(object->style()->overflowX() == object->style()->overflowY());
    259 
    260     // OSCROLL is never set for SVG - see CSSStyleSelector::adjustRenderStyle
    261     ASSERT(object->style()->overflowX() != OSCROLL);
    262 
    263     // RenderSVGRoot should never query for overflow state - it should always clip itself to the initial viewport size.
    264     ASSERT(!object->isRoot());
    265 
    266     return object->style()->overflowX() == OHIDDEN;
    267 }
    268 
    269 void SVGRenderSupport::intersectRepaintRectWithResources(const RenderObject* object, FloatRect& repaintRect)
    270 {
    271     ASSERT(object);
    272 
    273     RenderStyle* style = object->style();
    274     ASSERT(style);
    275 
    276     const SVGRenderStyle* svgStyle = style->svgStyle();
    277     ASSERT(svgStyle);
    278 
    279     RenderObject* renderer = const_cast<RenderObject*>(object);
    280     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer);
    281     if (!resources) {
    282         if (const ShadowData* shadow = svgStyle->shadow())
    283             shadow->adjustRectForShadow(repaintRect);
    284         return;
    285     }
    286 
    287 #if ENABLE(FILTERS)
    288     if (RenderSVGResourceFilter* filter = resources->filter())
    289         repaintRect = filter->resourceBoundingBox(renderer);
    290 #endif
    291 
    292     if (RenderSVGResourceClipper* clipper = resources->clipper())
    293         repaintRect.intersect(clipper->resourceBoundingBox(renderer));
    294 
    295     if (RenderSVGResourceMasker* masker = resources->masker())
    296         repaintRect.intersect(masker->resourceBoundingBox(renderer));
    297 
    298     if (const ShadowData* shadow = svgStyle->shadow())
    299         shadow->adjustRectForShadow(repaintRect);
    300 }
    301 
    302 bool SVGRenderSupport::pointInClippingArea(RenderObject* object, const FloatPoint& point)
    303 {
    304     ASSERT(object);
    305 
    306     // We just take clippers into account to determine if a point is on the node. The Specification may
    307     // change later and we also need to check maskers.
    308     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
    309     if (!resources)
    310         return true;
    311 
    312     if (RenderSVGResourceClipper* clipper = resources->clipper())
    313         return clipper->hitTestClipContent(object->objectBoundingBox(), point);
    314 
    315     return true;
    316 }
    317 
    318 void SVGRenderSupport::applyStrokeStyleToContext(GraphicsContext* context, const RenderStyle* style, const RenderObject* object)
    319 {
    320     ASSERT(context);
    321     ASSERT(style);
    322     ASSERT(object);
    323     ASSERT(object->node());
    324     ASSERT(object->node()->isSVGElement());
    325 
    326     const SVGRenderStyle* svgStyle = style->svgStyle();
    327     ASSERT(svgStyle);
    328 
    329     SVGElement* lengthContext = static_cast<SVGElement*>(object->node());
    330     context->setStrokeThickness(svgStyle->strokeWidth().value(lengthContext));
    331     context->setLineCap(svgStyle->capStyle());
    332     context->setLineJoin(svgStyle->joinStyle());
    333     if (svgStyle->joinStyle() == MiterJoin)
    334         context->setMiterLimit(svgStyle->strokeMiterLimit());
    335 
    336     const Vector<SVGLength>& dashes = svgStyle->strokeDashArray();
    337     if (dashes.isEmpty())
    338         context->setStrokeStyle(SolidStroke);
    339     else {
    340         DashArray dashArray;
    341         const Vector<SVGLength>::const_iterator end = dashes.end();
    342         for (Vector<SVGLength>::const_iterator it = dashes.begin(); it != end; ++it)
    343             dashArray.append((*it).value(lengthContext));
    344 
    345         context->setLineDash(dashArray, svgStyle->strokeDashOffset().value(lengthContext));
    346     }
    347 }
    348 
    349 }
    350 
    351 #endif
    352