- add third_party src.
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / rendering / svg / SVGRenderSupport.cpp
1 /*
2  * Copyright (C) 2007, 2008 Rob Buis <buis@kde.org>
3  * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
4  * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
5  * Copyright (C) 2009 Google, Inc.  All rights reserved.
6  * Copyright (C) 2009 Dirk Schulze <krit@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 #include "core/rendering/svg/SVGRenderSupport.h"
28
29 #include "core/rendering/RenderGeometryMap.h"
30 #include "core/rendering/RenderLayer.h"
31 #include "core/rendering/SubtreeLayoutScope.h"
32 #include "core/rendering/svg/RenderSVGInlineText.h"
33 #include "core/rendering/svg/RenderSVGResourceClipper.h"
34 #include "core/rendering/svg/RenderSVGResourceFilter.h"
35 #include "core/rendering/svg/RenderSVGResourceMasker.h"
36 #include "core/rendering/svg/RenderSVGRoot.h"
37 #include "core/rendering/svg/RenderSVGText.h"
38 #include "core/rendering/svg/RenderSVGViewportContainer.h"
39 #include "core/rendering/svg/SVGResources.h"
40 #include "core/rendering/svg/SVGResourcesCache.h"
41 #include "core/svg/SVGElement.h"
42 #include "platform/geometry/TransformState.h"
43 #include "wtf/UnusedParam.h"
44
45 namespace WebCore {
46
47 LayoutRect SVGRenderSupport::clippedOverflowRectForRepaint(const RenderObject* object, const RenderLayerModelObject* repaintContainer)
48 {
49     // Return early for any cases where we don't actually paint
50     if (object->style()->visibility() != VISIBLE && !object->enclosingLayer()->hasVisibleContent())
51         return LayoutRect();
52
53     // Pass our local paint rect to computeRectForRepaint() which will
54     // map to parent coords and recurse up the parent chain.
55     FloatRect repaintRect = object->repaintRectInLocalCoordinates();
56     object->computeFloatRectForRepaint(repaintContainer, repaintRect);
57     return enclosingLayoutRect(repaintRect);
58 }
59
60 void SVGRenderSupport::computeFloatRectForRepaint(const RenderObject* object, const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed)
61 {
62     repaintRect.inflate(object->style()->outlineWidth());
63
64     // Translate to coords in our parent renderer, and then call computeFloatRectForRepaint() on our parent.
65     repaintRect = object->localToParentTransform().mapRect(repaintRect);
66     object->parent()->computeFloatRectForRepaint(repaintContainer, repaintRect, fixed);
67 }
68
69 void SVGRenderSupport::mapLocalToContainer(const RenderObject* object, const RenderLayerModelObject* repaintContainer, TransformState& transformState, bool* wasFixed)
70 {
71     transformState.applyTransform(object->localToParentTransform());
72
73     RenderObject* parent = object->parent();
74
75     // At the SVG/HTML boundary (aka RenderSVGRoot), we apply the localToBorderBoxTransform
76     // to map an element from SVG viewport coordinates to CSS box coordinates.
77     // RenderSVGRoot's mapLocalToContainer method expects CSS box coordinates.
78     if (parent->isSVGRoot())
79         transformState.applyTransform(toRenderSVGRoot(parent)->localToBorderBoxTransform());
80
81     MapCoordinatesFlags mode = UseTransforms;
82     parent->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
83 }
84
85 const RenderObject* SVGRenderSupport::pushMappingToContainer(const RenderObject* object, const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap)
86 {
87     ASSERT_UNUSED(ancestorToStopAt, ancestorToStopAt != object);
88
89     RenderObject* parent = object->parent();
90
91     // At the SVG/HTML boundary (aka RenderSVGRoot), we apply the localToBorderBoxTransform
92     // to map an element from SVG viewport coordinates to CSS box coordinates.
93     // RenderSVGRoot's mapLocalToContainer method expects CSS box coordinates.
94     if (parent->isSVGRoot()) {
95         TransformationMatrix matrix(object->localToParentTransform());
96         matrix.multiply(toRenderSVGRoot(parent)->localToBorderBoxTransform());
97         geometryMap.push(object, matrix);
98     } else
99         geometryMap.push(object, object->localToParentTransform());
100
101     return parent;
102 }
103
104 bool SVGRenderSupport::checkForSVGRepaintDuringLayout(RenderObject* object)
105 {
106     if (!object->checkForRepaintDuringLayout())
107         return false;
108     // When a parent container is transformed in SVG, all children will be painted automatically
109     // so we are able to skip redundant repaint checks.
110     RenderObject* parent = object->parent();
111     return !(parent && parent->isSVGContainer() && toRenderSVGContainer(parent)->didTransformToRootUpdate());
112 }
113
114 // Update a bounding box taking into account the validity of the other bounding box.
115 static inline void updateObjectBoundingBox(FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, RenderObject* other, FloatRect otherBoundingBox)
116 {
117     bool otherValid = other->isSVGContainer() ? toRenderSVGContainer(other)->isObjectBoundingBoxValid() : true;
118     if (!otherValid)
119         return;
120
121     if (!objectBoundingBoxValid) {
122         objectBoundingBox = otherBoundingBox;
123         objectBoundingBoxValid = true;
124         return;
125     }
126
127     objectBoundingBox.uniteEvenIfEmpty(otherBoundingBox);
128 }
129
130 void SVGRenderSupport::computeContainerBoundingBoxes(const RenderObject* container, FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, FloatRect& strokeBoundingBox, FloatRect& repaintBoundingBox)
131 {
132     objectBoundingBox = FloatRect();
133     objectBoundingBoxValid = false;
134     strokeBoundingBox = FloatRect();
135
136     // When computing the strokeBoundingBox, we use the repaintRects of the container's children so that the container's stroke includes
137     // the resources applied to the children (such as clips and filters). This allows filters applied to containers to correctly bound
138     // the children, and also improves inlining of SVG content, as the stroke bound is used in that situation also.
139     for (RenderObject* current = container->firstChild(); current; current = current->nextSibling()) {
140         if (current->isSVGHiddenContainer())
141             continue;
142
143         const AffineTransform& transform = current->localToParentTransform();
144         if (transform.isIdentity()) {
145             updateObjectBoundingBox(objectBoundingBox, objectBoundingBoxValid, current, current->objectBoundingBox());
146             strokeBoundingBox.unite(current->repaintRectInLocalCoordinates());
147         } else {
148             updateObjectBoundingBox(objectBoundingBox, objectBoundingBoxValid, current, transform.mapRect(current->objectBoundingBox()));
149             strokeBoundingBox.unite(transform.mapRect(current->repaintRectInLocalCoordinates()));
150         }
151     }
152
153     repaintBoundingBox = strokeBoundingBox;
154 }
155
156 bool SVGRenderSupport::paintInfoIntersectsRepaintRect(const FloatRect& localRepaintRect, const AffineTransform& localTransform, const PaintInfo& paintInfo)
157 {
158     if (localTransform.isIdentity())
159         return localRepaintRect.intersects(paintInfo.rect);
160
161     return localTransform.mapRect(localRepaintRect).intersects(paintInfo.rect);
162 }
163
164 const RenderSVGRoot* SVGRenderSupport::findTreeRootObject(const RenderObject* start)
165 {
166     while (start && !start->isSVGRoot())
167         start = start->parent();
168
169     ASSERT(start);
170     ASSERT(start->isSVGRoot());
171     return toRenderSVGRoot(start);
172 }
173
174 static inline void invalidateResourcesOfChildren(RenderObject* start)
175 {
176     ASSERT(!start->needsLayout());
177     if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(start))
178         resources->removeClientFromCache(start, false);
179
180     for (RenderObject* child = start->firstChild(); child; child = child->nextSibling())
181         invalidateResourcesOfChildren(child);
182 }
183
184 static inline bool layoutSizeOfNearestViewportChanged(const RenderObject* start)
185 {
186     while (start && !start->isSVGRoot() && !start->isSVGViewportContainer())
187         start = start->parent();
188
189     ASSERT(start);
190     ASSERT(start->isSVGRoot() || start->isSVGViewportContainer());
191     if (start->isSVGViewportContainer())
192         return toRenderSVGViewportContainer(start)->isLayoutSizeChanged();
193
194     return toRenderSVGRoot(start)->isLayoutSizeChanged();
195 }
196
197 bool SVGRenderSupport::transformToRootChanged(RenderObject* ancestor)
198 {
199     while (ancestor && !ancestor->isSVGRoot()) {
200         if (ancestor->isSVGTransformableContainer())
201             return toRenderSVGContainer(ancestor)->didTransformToRootUpdate();
202         if (ancestor->isSVGViewportContainer())
203             return toRenderSVGViewportContainer(ancestor)->didTransformToRootUpdate();
204         ancestor = ancestor->parent();
205     }
206
207     return false;
208 }
209
210 void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout)
211 {
212     bool layoutSizeChanged = layoutSizeOfNearestViewportChanged(start);
213     bool transformChanged = transformToRootChanged(start);
214     HashSet<RenderObject*> notlayoutedObjects;
215
216     for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
217         bool needsLayout = selfNeedsLayout;
218         bool childEverHadLayout = child->everHadLayout();
219
220         if (transformChanged) {
221             // If the transform changed we need to update the text metrics (note: this also happens for layoutSizeChanged=true).
222             if (child->isSVGText())
223                 toRenderSVGText(child)->setNeedsTextMetricsUpdate();
224             needsLayout = true;
225         }
226
227         if (layoutSizeChanged) {
228             // When selfNeedsLayout is false and the layout size changed, we have to check whether this child uses relative lengths
229             if (SVGElement* element = child->node()->isSVGElement() ? toSVGElement(child->node()) : 0) {
230                 if (element->hasRelativeLengths()) {
231                     // When the layout size changed and when using relative values tell the RenderSVGShape to update its shape object
232                     if (child->isSVGShape())
233                         toRenderSVGShape(child)->setNeedsShapeUpdate();
234                     else if (child->isSVGText()) {
235                         toRenderSVGText(child)->setNeedsTextMetricsUpdate();
236                         toRenderSVGText(child)->setNeedsPositioningValuesUpdate();
237                     }
238
239                     needsLayout = true;
240                 }
241             }
242         }
243
244         SubtreeLayoutScope layoutScope(child);
245         // Resource containers are nasty: they can invalidate clients outside the current SubtreeLayoutScope.
246         // Since they only care about viewport size changes (to resolve their relative lengths), we trigger
247         // their invalidation directly from SVGSVGElement::svgAttributeChange() or at a higher
248         // SubtreeLayoutScope (in RenderView::layout()).
249         if (needsLayout && !child->isSVGResourceContainer())
250             layoutScope.setNeedsLayout(child);
251
252         layoutResourcesIfNeeded(child);
253
254         if (child->needsLayout()) {
255             child->layout();
256             // Renderers are responsible for repainting themselves when changing, except
257             // for the initial paint to avoid potential double-painting caused by non-sensical "old" bounds.
258             // We could handle this in the individual objects, but for now it's easier to have
259             // parent containers call repaint().  (RenderBlock::layout* has similar logic.)
260             if (!childEverHadLayout)
261                 child->repaint();
262         } else if (layoutSizeChanged)
263             notlayoutedObjects.add(child);
264     }
265
266     if (!layoutSizeChanged) {
267         ASSERT(notlayoutedObjects.isEmpty());
268         return;
269     }
270
271     // If the layout size changed, invalidate all resources of all children that didn't go through the layout() code path.
272     HashSet<RenderObject*>::iterator end = notlayoutedObjects.end();
273     for (HashSet<RenderObject*>::iterator it = notlayoutedObjects.begin(); it != end; ++it)
274         invalidateResourcesOfChildren(*it);
275 }
276
277 void SVGRenderSupport::layoutResourcesIfNeeded(const RenderObject* object)
278 {
279     ASSERT(object);
280
281     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
282     if (resources)
283         resources->layoutIfNeeded();
284 }
285
286 bool SVGRenderSupport::isOverflowHidden(const RenderObject* object)
287 {
288     // SVG doesn't support independent x/y overflow
289     ASSERT(object->style()->overflowX() == object->style()->overflowY());
290
291     // OSCROLL is never set for SVG - see StyleResolver::adjustRenderStyle
292     ASSERT(object->style()->overflowX() != OSCROLL);
293
294     // RenderSVGRoot should never query for overflow state - it should always clip itself to the initial viewport size.
295     ASSERT(!object->isRoot());
296
297     return object->style()->overflowX() == OHIDDEN;
298 }
299
300 void SVGRenderSupport::intersectRepaintRectWithResources(const RenderObject* object, FloatRect& repaintRect)
301 {
302     ASSERT(object);
303
304     RenderObject* renderer = const_cast<RenderObject*>(object);
305     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer);
306     if (!resources)
307         return;
308
309     if (RenderSVGResourceFilter* filter = resources->filter())
310         repaintRect = filter->resourceBoundingBox(renderer);
311
312     if (RenderSVGResourceClipper* clipper = resources->clipper())
313         repaintRect.intersect(clipper->resourceBoundingBox(renderer));
314
315     if (RenderSVGResourceMasker* masker = resources->masker())
316         repaintRect.intersect(masker->resourceBoundingBox(renderer));
317 }
318
319 bool SVGRenderSupport::filtersForceContainerLayout(RenderObject* object)
320 {
321     // If any of this container's children need to be laid out, and a filter is applied
322     // to the container, we need to repaint the entire container.
323     if (!object->normalChildNeedsLayout())
324         return false;
325
326     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
327     if (!resources || !resources->filter())
328         return false;
329
330     return true;
331 }
332
333 bool SVGRenderSupport::pointInClippingArea(RenderObject* object, const FloatPoint& point)
334 {
335     ASSERT(object);
336
337     // We just take clippers into account to determine if a point is on the node. The Specification may
338     // change later and we also need to check maskers.
339     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
340     if (!resources)
341         return true;
342
343     if (RenderSVGResourceClipper* clipper = resources->clipper())
344         return clipper->hitTestClipContent(object->objectBoundingBox(), point);
345
346     return true;
347 }
348
349 void SVGRenderSupport::applyStrokeStyleToContext(GraphicsContext* context, const RenderStyle* style, const RenderObject* object)
350 {
351     ASSERT(context);
352     ASSERT(style);
353     ASSERT(object);
354     ASSERT(object->node());
355     ASSERT(object->node()->isSVGElement());
356
357     const SVGRenderStyle* svgStyle = style->svgStyle();
358     ASSERT(svgStyle);
359
360     SVGLengthContext lengthContext(toSVGElement(object->node()));
361     context->setStrokeThickness(svgStyle->strokeWidth().value(lengthContext));
362     context->setLineCap(svgStyle->capStyle());
363     context->setLineJoin(svgStyle->joinStyle());
364     context->setMiterLimit(svgStyle->strokeMiterLimit());
365
366     const Vector<SVGLength>& dashes = svgStyle->strokeDashArray();
367     if (dashes.isEmpty())
368         return;
369
370     DashArray dashArray;
371     const Vector<SVGLength>::const_iterator end = dashes.end();
372     for (Vector<SVGLength>::const_iterator it = dashes.begin(); it != end; ++it)
373         dashArray.append((*it).value(lengthContext));
374
375     context->setLineDash(dashArray, svgStyle->strokeDashOffset().value(lengthContext));
376 }
377
378 void SVGRenderSupport::applyStrokeStyleToStrokeData(StrokeData* strokeData, const RenderStyle* style, const RenderObject* object)
379 {
380     ASSERT(strokeData);
381     ASSERT(style);
382     ASSERT(object);
383     ASSERT(object->node());
384     ASSERT(object->node()->isSVGElement());
385
386     const SVGRenderStyle* svgStyle = style->svgStyle();
387     ASSERT(svgStyle);
388
389     SVGLengthContext lengthContext(toSVGElement(object->node()));
390     strokeData->setThickness(svgStyle->strokeWidth().value(lengthContext));
391     strokeData->setLineCap(svgStyle->capStyle());
392     strokeData->setLineJoin(svgStyle->joinStyle());
393     strokeData->setMiterLimit(svgStyle->strokeMiterLimit());
394
395     const Vector<SVGLength>& dashes = svgStyle->strokeDashArray();
396     if (dashes.isEmpty())
397         return;
398
399     DashArray dashArray;
400     const Vector<SVGLength>::const_iterator end = dashes.end();
401     for (Vector<SVGLength>::const_iterator it = dashes.begin(); it != end; ++it)
402         dashArray.append((*it).value(lengthContext));
403
404     strokeData->setLineDash(dashArray, svgStyle->strokeDashOffset().value(lengthContext));
405 }
406
407 bool SVGRenderSupport::isEmptySVGInlineText(const RenderObject* object)
408 {
409     // RenderSVGInlineText performs whitespace filtering in order to support xml:space
410     // (http://www.w3.org/TR/SVG/struct.html#LangSpaceAttrs), and can end up with an empty string
411     // even when its original constructor argument is non-empty.
412     return object->isSVGInlineText() && toRenderSVGInlineText(object)->hasEmptyText();
413 }
414
415 }