• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007, 2008 Rob Buis <buis@kde.org>
3  *           (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
4  *           (C) 2007 Eric Seidel <eric@webkit.org>
5  * Copyright (C) 2009 Google, Inc.  All rights reserved.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  */
23 
24 #include "config.h"
25 
26 #if ENABLE(SVG)
27 #include "SVGRenderSupport.h"
28 
29 #include "ImageBuffer.h"
30 #include "RenderObject.h"
31 #include "RenderSVGContainer.h"
32 #include "RenderView.h"
33 #include "SVGResourceClipper.h"
34 #include "SVGResourceFilter.h"
35 #include "SVGResourceMasker.h"
36 #include "SVGStyledElement.h"
37 #include "SVGURIReference.h"
38 #include "TransformState.h"
39 #include "TransformationMatrix.h"
40 #include <wtf/UnusedParam.h>
41 
42 namespace WebCore {
43 
clippedOverflowRectForRepaint(RenderObject * object,RenderBoxModelObject * repaintContainer)44 IntRect SVGRenderBase::clippedOverflowRectForRepaint(RenderObject* object, RenderBoxModelObject* repaintContainer)
45 {
46     // Return early for any cases where we don't actually paint
47     if (object->style()->visibility() != VISIBLE && !object->enclosingLayer()->hasVisibleContent())
48         return IntRect();
49 
50     // Pass our local paint rect to computeRectForRepaint() which will
51     // map to parent coords and recurse up the parent chain.
52     IntRect repaintRect = enclosingIntRect(object->repaintRectInLocalCoordinates());
53     object->computeRectForRepaint(repaintContainer, repaintRect);
54     return repaintRect;
55 }
56 
computeRectForRepaint(RenderObject * object,RenderBoxModelObject * repaintContainer,IntRect & repaintRect,bool fixed)57 void SVGRenderBase::computeRectForRepaint(RenderObject* object, RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed)
58 {
59     // Translate to coords in our parent renderer, and then call computeRectForRepaint on our parent
60     repaintRect = object->localToParentTransform().mapRect(repaintRect);
61     object->parent()->computeRectForRepaint(repaintContainer, repaintRect, fixed);
62 }
63 
mapLocalToContainer(const RenderObject * object,RenderBoxModelObject * repaintContainer,bool fixed,bool useTransforms,TransformState & transformState)64 void SVGRenderBase::mapLocalToContainer(const RenderObject* object, RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState)
65 {
66     ASSERT(!fixed); // We should have no fixed content in the SVG rendering tree.
67     ASSERT(useTransforms); // mapping a point through SVG w/o respecting trasnforms is useless.
68     transformState.applyTransform(object->localToParentTransform());
69     object->parent()->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState);
70 }
71 
prepareToRenderSVGContent(RenderObject * object,RenderObject::PaintInfo & paintInfo,const FloatRect & boundingBox,SVGResourceFilter * & filter,SVGResourceFilter * rootFilter)72 void SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, const FloatRect& boundingBox, SVGResourceFilter*& filter, SVGResourceFilter* rootFilter)
73 {
74 #if !ENABLE(FILTERS)
75     UNUSED_PARAM(filter);
76     UNUSED_PARAM(rootFilter);
77 #endif
78 
79     ASSERT(object);
80     SVGElement* svgElement = static_cast<SVGElement*>(object->node());
81     ASSERT(svgElement && svgElement->document() && svgElement->isStyled());
82 
83     SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement);
84     const 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 filters!
91     float opacity = style->opacity();
92     if (opacity < 1.0f) {
93         paintInfo.context->clip(enclosingIntRect(boundingBox));
94         paintInfo.context->beginTransparencyLayer(opacity);
95     }
96 
97 #if ENABLE(FILTERS)
98     AtomicString filterId(svgStyle->filter());
99 #endif
100 
101     AtomicString clipperId(svgStyle->clipPath());
102     AtomicString maskerId(svgStyle->maskElement());
103 
104     Document* document = object->document();
105 
106 #if ENABLE(FILTERS)
107     SVGResourceFilter* newFilter = getFilterById(document, filterId);
108     if (newFilter == rootFilter) {
109         // Catch <text filter="url(#foo)">Test<tspan filter="url(#foo)">123</tspan></text>.
110         // The filter is NOT meant to be applied twice in that case!
111         filter = 0;
112         filterId = String();
113     } else
114         filter = newFilter;
115 #endif
116 
117     SVGResourceClipper* clipper = getClipperById(document, clipperId);
118     SVGResourceMasker* masker = getMaskerById(document, maskerId);
119 
120 #if ENABLE(FILTERS)
121     if (filter) {
122         filter->addClient(styledElement);
123         filter->prepareFilter(paintInfo.context, object);
124     } else if (!filterId.isEmpty())
125         svgElement->document()->accessSVGExtensions()->addPendingResource(filterId, styledElement);
126 #endif
127 
128     if (clipper) {
129         clipper->addClient(styledElement);
130         clipper->applyClip(paintInfo.context, boundingBox);
131     } else if (!clipperId.isEmpty())
132         svgElement->document()->accessSVGExtensions()->addPendingResource(clipperId, styledElement);
133 
134     if (masker) {
135         masker->addClient(styledElement);
136         masker->applyMask(paintInfo.context, boundingBox);
137     } else if (!maskerId.isEmpty())
138         svgElement->document()->accessSVGExtensions()->addPendingResource(maskerId, styledElement);
139 }
140 
finishRenderSVGContent(RenderObject * object,RenderObject::PaintInfo & paintInfo,SVGResourceFilter * & filter,GraphicsContext * savedContext)141 void SVGRenderBase::finishRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, SVGResourceFilter*& filter, GraphicsContext* savedContext)
142 {
143 #if !ENABLE(FILTERS)
144     UNUSED_PARAM(filter);
145     UNUSED_PARAM(savedContext);
146 #endif
147 
148     ASSERT(object);
149 
150     const RenderStyle* style = object->style();
151     ASSERT(style);
152 
153 #if ENABLE(FILTERS)
154     if (filter) {
155         filter->applyFilter(paintInfo.context, object);
156         paintInfo.context = savedContext;
157     }
158 #endif
159 
160     float opacity = style->opacity();
161     if (opacity < 1.0f)
162         paintInfo.context->endTransparencyLayer();
163 }
164 
renderSubtreeToImage(ImageBuffer * image,RenderObject * item)165 void renderSubtreeToImage(ImageBuffer* image, RenderObject* item)
166 {
167     ASSERT(item);
168     ASSERT(image);
169     ASSERT(image->context());
170     RenderObject::PaintInfo info(image->context(), IntRect(), PaintPhaseForeground, 0, 0, 0);
171 
172     // FIXME: isSVGContainer returns true for RenderSVGViewportContainer, so if this is ever
173     // called with one of those, we will read from the wrong offset in an object due to a bad cast.
174     RenderSVGContainer* svgContainer = 0;
175     if (item && item->isSVGContainer())
176         svgContainer = toRenderSVGContainer(item);
177 
178     bool drawsContents = svgContainer ? svgContainer->drawsContents() : false;
179     if (svgContainer && !drawsContents)
180         svgContainer->setDrawsContents(true);
181 
182     item->layoutIfNeeded();
183     item->paint(info, 0, 0);
184 
185     if (svgContainer && !drawsContents)
186         svgContainer->setDrawsContents(false);
187 }
188 
clampImageBufferSizeToViewport(FrameView * frameView,IntSize & size)189 void clampImageBufferSizeToViewport(FrameView* frameView, IntSize& size)
190 {
191     if (!frameView)
192         return;
193 
194     int viewWidth = frameView->visibleWidth();
195     int viewHeight = frameView->visibleHeight();
196 
197     if (size.width() > viewWidth)
198         size.setWidth(viewWidth);
199 
200     if (size.height() > viewHeight)
201         size.setHeight(viewHeight);
202 }
203 
computeContainerBoundingBox(const RenderObject * container,bool includeAllPaintedContent)204 FloatRect SVGRenderBase::computeContainerBoundingBox(const RenderObject* container, bool includeAllPaintedContent)
205 {
206     FloatRect boundingBox;
207 
208     RenderObject* current = container->firstChild();
209     for (; current != 0; current = current->nextSibling()) {
210         FloatRect childBBox = includeAllPaintedContent ? current->repaintRectInLocalCoordinates() : current->objectBoundingBox();
211         FloatRect childBBoxInLocalCoords = current->localToParentTransform().mapRect(childBBox);
212         boundingBox.unite(childBBoxInLocalCoords);
213     }
214 
215     return boundingBox;
216 }
217 
filterBoundingBoxForRenderer(const RenderObject * object)218 FloatRect SVGRenderBase::filterBoundingBoxForRenderer(const RenderObject* object)
219 {
220 #if ENABLE(FILTERS)
221     SVGResourceFilter* filter = getFilterById(object->document(), object->style()->svgStyle()->filter());
222     if (filter)
223         return filter->filterBBoxForItemBBox(object->objectBoundingBox());
224 #else
225     UNUSED_PARAM(object);
226 #endif
227     return FloatRect();
228 }
229 
applyTransformToPaintInfo(RenderObject::PaintInfo & paintInfo,const TransformationMatrix & localToAncestorTransform)230 void applyTransformToPaintInfo(RenderObject::PaintInfo& paintInfo, const TransformationMatrix& localToAncestorTransform)
231 {
232     if (localToAncestorTransform.isIdentity())
233         return;
234 
235     paintInfo.context->concatCTM(localToAncestorTransform);
236     paintInfo.rect = localToAncestorTransform.inverse().mapRect(paintInfo.rect);
237 }
238 
239 } // namespace WebCore
240 
241 #endif // ENABLE(SVG)
242