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