Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / rendering / svg / RenderSVGResourceMasker.cpp
1 /*
2  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include "config.h"
21 #include "core/rendering/svg/RenderSVGResourceMasker.h"
22
23 #include "core/dom/ElementTraversal.h"
24 #include "core/rendering/svg/SVGRenderingContext.h"
25 #include "core/svg/SVGElement.h"
26 #include "platform/graphics/DisplayList.h"
27 #include "platform/graphics/GraphicsContextStateSaver.h"
28 #include "platform/transforms/AffineTransform.h"
29
30 namespace blink {
31
32 RenderSVGResourceMasker::RenderSVGResourceMasker(SVGMaskElement* node)
33     : RenderSVGResourceContainer(node)
34 {
35 }
36
37 RenderSVGResourceMasker::~RenderSVGResourceMasker()
38 {
39 }
40
41 void RenderSVGResourceMasker::removeAllClientsFromCache(bool markForInvalidation)
42 {
43     m_maskContentDisplayList.clear();
44     m_maskContentBoundaries = FloatRect();
45     markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation);
46 }
47
48 void RenderSVGResourceMasker::removeClientFromCache(RenderObject* client, bool markForInvalidation)
49 {
50     ASSERT(client);
51     markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation);
52 }
53
54 bool RenderSVGResourceMasker::prepareEffect(RenderObject* object, GraphicsContext*& context)
55 {
56     ASSERT(object);
57     ASSERT(context);
58     ASSERT(style());
59     ASSERT_WITH_SECURITY_IMPLICATION(!needsLayout());
60
61     clearInvalidationMask();
62
63     FloatRect paintInvalidationRect = object->paintInvalidationRectInLocalCoordinates();
64     if (paintInvalidationRect.isEmpty() || !element()->hasChildren())
65         return false;
66
67     // Content layer start.
68     context->beginTransparencyLayer(1, &paintInvalidationRect);
69
70     return true;
71 }
72
73 void RenderSVGResourceMasker::finishEffect(RenderObject* object, GraphicsContext*& context)
74 {
75     ASSERT(object);
76     ASSERT(context);
77     ASSERT(style());
78     ASSERT_WITH_SECURITY_IMPLICATION(!needsLayout());
79
80     FloatRect paintInvalidationRect = object->paintInvalidationRectInLocalCoordinates();
81
82     const SVGRenderStyle& svgStyle = style()->svgStyle();
83     ColorFilter maskLayerFilter = svgStyle.maskType() == MT_LUMINANCE
84         ? ColorFilterLuminanceToAlpha : ColorFilterNone;
85     ColorFilter maskContentFilter = svgStyle.colorInterpolation() == CI_LINEARRGB
86         ? ColorFilterSRGBToLinearRGB : ColorFilterNone;
87
88     // Mask layer start.
89     context->beginLayer(1, CompositeDestinationIn, &paintInvalidationRect, maskLayerFilter);
90     {
91         // Draw the mask with color conversion (when needed).
92         GraphicsContextStateSaver maskContentSaver(*context);
93         context->setColorFilter(maskContentFilter);
94
95         drawMaskForRenderer(context, object->objectBoundingBox());
96     }
97
98     // Transfer mask layer -> content layer (DstIn)
99     context->endLayer();
100     // Transfer content layer -> backdrop (SrcOver)
101     context->endLayer();
102 }
103
104 void RenderSVGResourceMasker::drawMaskForRenderer(GraphicsContext* context, const FloatRect& targetBoundingBox)
105 {
106     ASSERT(context);
107
108     AffineTransform contentTransformation;
109     SVGUnitTypes::SVGUnitType contentUnits = toSVGMaskElement(element())->maskContentUnits()->currentValue()->enumValue();
110     if (contentUnits == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
111         contentTransformation.translate(targetBoundingBox.x(), targetBoundingBox.y());
112         contentTransformation.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.height());
113         context->concatCTM(contentTransformation);
114     }
115
116     if (!m_maskContentDisplayList) {
117         SubtreeContentTransformScope contentTransformScope(contentTransformation);
118         createDisplayList(context);
119     }
120     ASSERT(m_maskContentDisplayList);
121     context->drawDisplayList(m_maskContentDisplayList.get());
122 }
123
124 void RenderSVGResourceMasker::createDisplayList(GraphicsContext* context)
125 {
126     ASSERT(context);
127
128     // Using strokeBoundingBox (instead of paintInvalidationRectInLocalCoordinates) to avoid the intersection
129     // with local clips/mask, which may yield incorrect results when mixing objectBoundingBox and
130     // userSpaceOnUse units (http://crbug.com/294900).
131     FloatRect bounds = strokeBoundingBox();
132     context->beginRecording(bounds);
133     for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement)) {
134         RenderObject* renderer = childElement->renderer();
135         if (!renderer)
136             continue;
137         RenderStyle* style = renderer->style();
138         if (!style || style->display() == NONE || style->visibility() != VISIBLE)
139             continue;
140
141         SVGRenderingContext::renderSubtree(context, renderer);
142     }
143     m_maskContentDisplayList = context->endRecording();
144 }
145
146 void RenderSVGResourceMasker::calculateMaskContentPaintInvalidationRect()
147 {
148     for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement)) {
149         RenderObject* renderer = childElement->renderer();
150         if (!renderer)
151             continue;
152         RenderStyle* style = renderer->style();
153         if (!style || style->display() == NONE || style->visibility() != VISIBLE)
154              continue;
155         m_maskContentBoundaries.unite(renderer->localToParentTransform().mapRect(renderer->paintInvalidationRectInLocalCoordinates()));
156     }
157 }
158
159 FloatRect RenderSVGResourceMasker::resourceBoundingBox(const RenderObject* object)
160 {
161     SVGMaskElement* maskElement = toSVGMaskElement(element());
162     ASSERT(maskElement);
163
164     FloatRect objectBoundingBox = object->objectBoundingBox();
165     FloatRect maskBoundaries = SVGLengthContext::resolveRectangle<SVGMaskElement>(maskElement, maskElement->maskUnits()->currentValue()->enumValue(), objectBoundingBox);
166
167     // Resource was not layouted yet. Give back clipping rect of the mask.
168     if (selfNeedsLayout())
169         return maskBoundaries;
170
171     if (m_maskContentBoundaries.isEmpty())
172         calculateMaskContentPaintInvalidationRect();
173
174     FloatRect maskRect = m_maskContentBoundaries;
175     if (maskElement->maskContentUnits()->currentValue()->value() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
176         AffineTransform transform;
177         transform.translate(objectBoundingBox.x(), objectBoundingBox.y());
178         transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
179         maskRect = transform.mapRect(maskRect);
180     }
181
182     maskRect.intersect(maskBoundaries);
183     return maskRect;
184 }
185
186 }