Update To 11.40.268.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 #include "core/rendering/svg/SVGRenderSupport.h"
27
28 #include "core/frame/FrameView.h"
29 #include "core/frame/LocalFrame.h"
30 #include "core/rendering/PaintInfo.h"
31 #include "core/rendering/RenderGeometryMap.h"
32 #include "core/rendering/RenderLayer.h"
33 #include "core/rendering/SubtreeLayoutScope.h"
34 #include "core/rendering/svg/RenderSVGInlineText.h"
35 #include "core/rendering/svg/RenderSVGResourceClipper.h"
36 #include "core/rendering/svg/RenderSVGResourceFilter.h"
37 #include "core/rendering/svg/RenderSVGResourceMasker.h"
38 #include "core/rendering/svg/RenderSVGRoot.h"
39 #include "core/rendering/svg/RenderSVGShape.h"
40 #include "core/rendering/svg/RenderSVGText.h"
41 #include "core/rendering/svg/RenderSVGViewportContainer.h"
42 #include "core/rendering/svg/SVGResources.h"
43 #include "core/rendering/svg/SVGResourcesCache.h"
44 #include "core/svg/SVGElement.h"
45 #include "platform/geometry/TransformState.h"
46
47 namespace blink {
48
49 LayoutRect SVGRenderSupport::clippedOverflowRectForPaintInvalidation(const RenderObject* object, const RenderLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState)
50 {
51     // Return early for any cases where we don't actually paint
52     if (object->style()->visibility() != VISIBLE && !object->enclosingLayer()->hasVisibleContent())
53         return LayoutRect();
54
55     // Pass our local paint rect to computeRectForPaintInvalidation() which will
56     // map to parent coords and recurse up the parent chain.
57     FloatRect paintInvalidationRect = object->paintInvalidationRectInLocalCoordinates();
58     paintInvalidationRect.inflate(object->style()->outlineWidth());
59
60     if (paintInvalidationState && paintInvalidationState->canMapToContainer(paintInvalidationContainer)) {
61         // Compute accumulated SVG transform and apply to local paint rect.
62         AffineTransform transform = paintInvalidationState->svgTransform() * object->localToParentTransform();
63         paintInvalidationRect = transform.mapRect(paintInvalidationRect);
64         // FIXME: These are quirks carried forward from RenderSVGRoot::computeFloatRectForPaintInvalidation.
65         LayoutRect rect;
66         if (!paintInvalidationRect.isEmpty())
67             rect = enclosingIntRect(paintInvalidationRect);
68         // Offset by SVG root paint offset and apply clipping as needed.
69         rect.move(paintInvalidationState->paintOffset());
70         if (paintInvalidationState->isClipped())
71             rect.intersect(paintInvalidationState->clipRect());
72         return rect;
73     }
74
75     object->computeFloatRectForPaintInvalidation(paintInvalidationContainer, paintInvalidationRect, paintInvalidationState);
76     return enclosingLayoutRect(paintInvalidationRect);
77 }
78
79 void SVGRenderSupport::computeFloatRectForPaintInvalidation(const RenderObject* object, const RenderLayerModelObject* paintInvalidationContainer, FloatRect& paintInvalidationRect, const PaintInvalidationState* paintInvalidationState)
80 {
81     // Translate to coords in our parent renderer, and then call computeFloatRectForPaintInvalidation() on our parent.
82     paintInvalidationRect = object->localToParentTransform().mapRect(paintInvalidationRect);
83     object->parent()->computeFloatRectForPaintInvalidation(paintInvalidationContainer, paintInvalidationRect, paintInvalidationState);
84 }
85
86 void SVGRenderSupport::mapLocalToContainer(const RenderObject* object, const RenderLayerModelObject* paintInvalidationContainer, TransformState& transformState, bool* wasFixed, const PaintInvalidationState* paintInvalidationState)
87 {
88     transformState.applyTransform(object->localToParentTransform());
89
90     if (paintInvalidationState && paintInvalidationState->canMapToContainer(paintInvalidationContainer)) {
91         // |svgTransform| contains localToBorderBoxTransform mentioned below.
92         transformState.applyTransform(paintInvalidationState->svgTransform());
93         transformState.move(paintInvalidationState->paintOffset());
94         return;
95     }
96
97     RenderObject* parent = object->parent();
98
99     // At the SVG/HTML boundary (aka RenderSVGRoot), we apply the localToBorderBoxTransform
100     // to map an element from SVG viewport coordinates to CSS box coordinates.
101     // RenderSVGRoot's mapLocalToContainer method expects CSS box coordinates.
102     if (parent->isSVGRoot())
103         transformState.applyTransform(toRenderSVGRoot(parent)->localToBorderBoxTransform());
104
105     MapCoordinatesFlags mode = UseTransforms;
106     parent->mapLocalToContainer(paintInvalidationContainer, transformState, mode, wasFixed, paintInvalidationState);
107 }
108
109 const RenderObject* SVGRenderSupport::pushMappingToContainer(const RenderObject* object, const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap)
110 {
111     ASSERT_UNUSED(ancestorToStopAt, ancestorToStopAt != object);
112
113     RenderObject* parent = object->parent();
114
115     // At the SVG/HTML boundary (aka RenderSVGRoot), we apply the localToBorderBoxTransform
116     // to map an element from SVG viewport coordinates to CSS box coordinates.
117     // RenderSVGRoot's mapLocalToContainer method expects CSS box coordinates.
118     if (parent->isSVGRoot()) {
119         TransformationMatrix matrix(object->localToParentTransform());
120         matrix.multiply(toRenderSVGRoot(parent)->localToBorderBoxTransform());
121         geometryMap.push(object, matrix);
122     } else
123         geometryMap.push(object, object->localToParentTransform());
124
125     return parent;
126 }
127
128 // Update a bounding box taking into account the validity of the other bounding box.
129 inline void SVGRenderSupport::updateObjectBoundingBox(FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, RenderObject* other, FloatRect otherBoundingBox)
130 {
131     bool otherValid = other->isSVGContainer() ? toRenderSVGContainer(other)->isObjectBoundingBoxValid() : true;
132     if (!otherValid)
133         return;
134
135     if (!objectBoundingBoxValid) {
136         objectBoundingBox = otherBoundingBox;
137         objectBoundingBoxValid = true;
138         return;
139     }
140
141     objectBoundingBox.uniteEvenIfEmpty(otherBoundingBox);
142 }
143
144 void SVGRenderSupport::computeContainerBoundingBoxes(const RenderObject* container, FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, FloatRect& strokeBoundingBox, FloatRect& paintInvalidationBoundingBox)
145 {
146     objectBoundingBox = FloatRect();
147     objectBoundingBoxValid = false;
148     strokeBoundingBox = FloatRect();
149
150     // When computing the strokeBoundingBox, we use the paintInvalidationRects of the container's children so that the container's stroke includes
151     // the resources applied to the children (such as clips and filters). This allows filters applied to containers to correctly bound
152     // the children, and also improves inlining of SVG content, as the stroke bound is used in that situation also.
153     for (RenderObject* current = container->slowFirstChild(); current; current = current->nextSibling()) {
154         if (current->isSVGHiddenContainer())
155             continue;
156
157         // Don't include elements in the union that do not render.
158         if (current->isSVGShape() && toRenderSVGShape(current)->isShapeEmpty())
159             continue;
160
161         const AffineTransform& transform = current->localToParentTransform();
162         updateObjectBoundingBox(objectBoundingBox, objectBoundingBoxValid, current,
163             transform.mapRect(current->objectBoundingBox()));
164         strokeBoundingBox.unite(transform.mapRect(current->paintInvalidationRectInLocalCoordinates()));
165     }
166
167     paintInvalidationBoundingBox = strokeBoundingBox;
168 }
169
170 bool SVGRenderSupport::paintInfoIntersectsPaintInvalidationRect(const FloatRect& localPaintInvalidationRect, const AffineTransform& localTransform, const PaintInfo& paintInfo)
171 {
172     return localTransform.mapRect(localPaintInvalidationRect).intersects(paintInfo.rect);
173 }
174
175 const RenderSVGRoot* SVGRenderSupport::findTreeRootObject(const RenderObject* start)
176 {
177     while (start && !start->isSVGRoot())
178         start = start->parent();
179
180     ASSERT(start);
181     ASSERT(start->isSVGRoot());
182     return toRenderSVGRoot(start);
183 }
184
185 inline bool SVGRenderSupport::layoutSizeOfNearestViewportChanged(const RenderObject* start)
186 {
187     while (start && !start->isSVGRoot() && !start->isSVGViewportContainer())
188         start = start->parent();
189
190     ASSERT(start);
191     ASSERT(start->isSVGRoot() || start->isSVGViewportContainer());
192     if (start->isSVGViewportContainer())
193         return toRenderSVGViewportContainer(start)->isLayoutSizeChanged();
194
195     return toRenderSVGRoot(start)->isLayoutSizeChanged();
196 }
197
198 bool SVGRenderSupport::transformToRootChanged(RenderObject* ancestor)
199 {
200     while (ancestor && !ancestor->isSVGRoot()) {
201         if (ancestor->isSVGTransformableContainer())
202             return toRenderSVGContainer(ancestor)->didTransformToRootUpdate();
203         if (ancestor->isSVGViewportContainer())
204             return toRenderSVGViewportContainer(ancestor)->didTransformToRootUpdate();
205         ancestor = ancestor->parent();
206     }
207
208     return false;
209 }
210
211 void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout)
212 {
213     // When hasRelativeLengths() is false, no descendants have relative lengths
214     // (hence no one is interested in viewport size changes).
215     bool layoutSizeChanged = toSVGElement(start->node())->hasRelativeLengths()
216         && layoutSizeOfNearestViewportChanged(start);
217     bool transformChanged = transformToRootChanged(start);
218
219     for (RenderObject* child = start->slowFirstChild(); child; child = child->nextSibling()) {
220         bool forceLayout = selfNeedsLayout;
221
222         if (transformChanged) {
223             // If the transform changed we need to update the text metrics (note: this also happens for layoutSizeChanged=true).
224             if (child->isSVGText())
225                 toRenderSVGText(child)->setNeedsTextMetricsUpdate();
226             forceLayout = true;
227         }
228
229         if (layoutSizeChanged) {
230             // When selfNeedsLayout is false and the layout size changed, we have to check whether this child uses relative lengths
231             if (SVGElement* element = child->node()->isSVGElement() ? toSVGElement(child->node()) : 0) {
232                 if (element->hasRelativeLengths()) {
233                     // FIXME: this should be done on invalidation, not during layout.
234                     // When the layout size changed and when using relative values tell the RenderSVGShape to update its shape object
235                     if (child->isSVGShape()) {
236                         toRenderSVGShape(child)->setNeedsShapeUpdate();
237                     } else if (child->isSVGText()) {
238                         toRenderSVGText(child)->setNeedsTextMetricsUpdate();
239                         toRenderSVGText(child)->setNeedsPositioningValuesUpdate();
240                     }
241
242                     forceLayout = true;
243                 }
244             }
245         }
246
247         SubtreeLayoutScope layoutScope(*child);
248         // Resource containers are nasty: they can invalidate clients outside the current SubtreeLayoutScope.
249         // Since they only care about viewport size changes (to resolve their relative lengths), we trigger
250         // their invalidation directly from SVGSVGElement::svgAttributeChange() or at a higher
251         // SubtreeLayoutScope (in RenderView::layout()).
252         if (forceLayout && !child->isSVGResourceContainer())
253             layoutScope.setNeedsLayout(child);
254
255         // Lay out any referenced resources before the child.
256         layoutResourcesIfNeeded(child);
257         child->layoutIfNeeded();
258     }
259 }
260
261 void SVGRenderSupport::layoutResourcesIfNeeded(const RenderObject* object)
262 {
263     ASSERT(object);
264
265     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
266     if (resources)
267         resources->layoutIfNeeded();
268 }
269
270 bool SVGRenderSupport::isOverflowHidden(const RenderObject* object)
271 {
272     // RenderSVGRoot should never query for overflow state - it should always clip itself to the initial viewport size.
273     ASSERT(!object->isDocumentElement());
274
275     return object->style()->overflowX() == OHIDDEN || object->style()->overflowX() == OSCROLL;
276 }
277
278 bool SVGRenderSupport::isRenderingClipPathAsMaskImage(const RenderObject& object)
279 {
280     return object.frame() && object.frame()->view() && object.frame()->view()->paintBehavior() & PaintBehaviorRenderingClipPathAsMask;
281 }
282
283 void SVGRenderSupport::intersectPaintInvalidationRectWithResources(const RenderObject* renderer, FloatRect& paintInvalidationRect)
284 {
285     ASSERT(renderer);
286
287     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer);
288     if (!resources)
289         return;
290
291     if (RenderSVGResourceFilter* filter = resources->filter())
292         paintInvalidationRect = filter->resourceBoundingBox(renderer);
293
294     if (RenderSVGResourceClipper* clipper = resources->clipper())
295         paintInvalidationRect.intersect(clipper->resourceBoundingBox(renderer));
296
297     if (RenderSVGResourceMasker* masker = resources->masker())
298         paintInvalidationRect.intersect(masker->resourceBoundingBox(renderer));
299 }
300
301 bool SVGRenderSupport::filtersForceContainerLayout(RenderObject* object)
302 {
303     // If any of this container's children need to be laid out, and a filter is applied
304     // to the container, we need to issue paint invalidations the entire container.
305     if (!object->normalChildNeedsLayout())
306         return false;
307
308     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
309     if (!resources || !resources->filter())
310         return false;
311
312     return true;
313 }
314
315 bool SVGRenderSupport::pointInClippingArea(RenderObject* object, const FloatPoint& point)
316 {
317     ASSERT(object);
318
319     // We just take clippers into account to determine if a point is on the node. The Specification may
320     // change later and we also need to check maskers.
321     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
322     if (!resources)
323         return true;
324
325     if (RenderSVGResourceClipper* clipper = resources->clipper())
326         return clipper->hitTestClipContent(object->objectBoundingBox(), point);
327
328     return true;
329 }
330
331 bool SVGRenderSupport::transformToUserSpaceAndCheckClipping(RenderObject* object, const AffineTransform& localTransform, const FloatPoint& pointInParent, FloatPoint& localPoint)
332 {
333     if (!localTransform.isInvertible())
334         return false;
335     localPoint = localTransform.inverse().mapPoint(pointInParent);
336     return pointInClippingArea(object, localPoint);
337 }
338
339 void SVGRenderSupport::applyStrokeStyleToContext(GraphicsContext* context, const RenderStyle* style, const RenderObject* object)
340 {
341     ASSERT(context);
342     ASSERT(style);
343     ASSERT(object);
344     ASSERT(object->node());
345     ASSERT(object->node()->isSVGElement());
346
347     const SVGRenderStyle& svgStyle = style->svgStyle();
348
349     SVGLengthContext lengthContext(toSVGElement(object->node()));
350     context->setStrokeThickness(svgStyle.strokeWidth()->value(lengthContext));
351     context->setLineCap(svgStyle.capStyle());
352     context->setLineJoin(svgStyle.joinStyle());
353     context->setMiterLimit(svgStyle.strokeMiterLimit());
354
355     RefPtr<SVGLengthList> dashes = svgStyle.strokeDashArray();
356     if (dashes->isEmpty())
357         return;
358
359     DashArray dashArray;
360     SVGLengthList::ConstIterator it = dashes->begin();
361     SVGLengthList::ConstIterator itEnd = dashes->end();
362     for (; it != itEnd; ++it)
363         dashArray.append(it->value(lengthContext));
364
365     context->setLineDash(dashArray, svgStyle.strokeDashOffset()->value(lengthContext));
366 }
367
368 void SVGRenderSupport::applyStrokeStyleToStrokeData(StrokeData* strokeData, const RenderStyle* style, const RenderObject* object)
369 {
370     ASSERT(strokeData);
371     ASSERT(style);
372     ASSERT(object);
373     ASSERT(object->node());
374     ASSERT(object->node()->isSVGElement());
375
376     const SVGRenderStyle& svgStyle = style->svgStyle();
377
378     SVGLengthContext lengthContext(toSVGElement(object->node()));
379     strokeData->setThickness(svgStyle.strokeWidth()->value(lengthContext));
380     strokeData->setLineCap(svgStyle.capStyle());
381     strokeData->setLineJoin(svgStyle.joinStyle());
382     strokeData->setMiterLimit(svgStyle.strokeMiterLimit());
383
384     RefPtr<SVGLengthList> dashes = svgStyle.strokeDashArray();
385     if (dashes->isEmpty())
386         return;
387
388     DashArray dashArray;
389     size_t length = dashes->length();
390     for (size_t i = 0; i < length; ++i)
391         dashArray.append(dashes->at(i)->value(lengthContext));
392
393     strokeData->setLineDash(dashArray, svgStyle.strokeDashOffset()->value(lengthContext));
394 }
395
396 bool SVGRenderSupport::updateGraphicsContext(GraphicsContextStateSaver& stateSaver, RenderStyle* style, RenderObject& renderer, RenderSVGResourceMode resourceMode, const AffineTransform* additionalPaintServerTransform)
397 {
398     ASSERT(style);
399
400     GraphicsContext* context = stateSaver.context();
401     if (isRenderingClipPathAsMaskImage(renderer)) {
402         if (resourceMode == ApplyToStrokeMode)
403             return false;
404         context->setAlphaAsFloat(1);
405         context->setFillColor(SVGRenderStyle::initialFillPaintColor());
406         return true;
407     }
408
409     SVGPaintServer paintServer = SVGPaintServer::requestForRenderer(renderer, style, resourceMode);
410     if (!paintServer.isValid())
411         return false;
412
413     if (additionalPaintServerTransform && paintServer.isTransformDependent())
414         paintServer.prependTransform(*additionalPaintServerTransform);
415
416     paintServer.apply(*context, resourceMode, &stateSaver);
417
418     const SVGRenderStyle& svgStyle = style->svgStyle();
419
420     if (resourceMode == ApplyToFillMode) {
421         context->setAlphaAsFloat(svgStyle.fillOpacity());
422         context->setFillRule(svgStyle.fillRule());
423     } else {
424         context->setAlphaAsFloat(svgStyle.strokeOpacity());
425         applyStrokeStyleToContext(context, style, &renderer);
426     }
427     return true;
428 }
429
430 bool SVGRenderSupport::isRenderableTextNode(const RenderObject* object)
431 {
432     ASSERT(object->isText());
433     // <br> is marked as text, but is not handled by the SVG rendering code-path.
434     return object->isSVGInlineText() && !toRenderSVGInlineText(object)->hasEmptyText();
435 }
436
437 }