CTTE: RenderSVGResourceMasker always has an SVGMaskElement.
[WebKit-https.git] / Source / WebCore / 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
22 #if ENABLE(SVG)
23 #include "RenderSVGResourceMasker.h"
24
25 #include "AffineTransform.h"
26 #include "Element.h"
27 #include "FloatPoint.h"
28 #include "FloatRect.h"
29 #include "GraphicsContext.h"
30 #include "Image.h"
31 #include "ImageBuffer.h"
32 #include "IntRect.h"
33 #include "RenderSVGResource.h"
34 #include "SVGElement.h"
35 #include "SVGMaskElement.h"
36 #include "SVGRenderingContext.h"
37 #include "SVGUnitTypes.h"
38 #include <wtf/Vector.h>
39
40 namespace WebCore {
41
42 RenderSVGResourceType RenderSVGResourceMasker::s_resourceType = MaskerResourceType;
43
44 RenderSVGResourceMasker::RenderSVGResourceMasker(SVGMaskElement& element)
45     : RenderSVGResourceContainer(&element)
46 {
47 }
48
49 RenderSVGResourceMasker::~RenderSVGResourceMasker()
50 {
51 }
52
53 void RenderSVGResourceMasker::removeAllClientsFromCache(bool markForInvalidation)
54 {
55     m_maskContentBoundaries = FloatRect();
56     m_masker.clear();
57
58     markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation);
59 }
60
61 void RenderSVGResourceMasker::removeClientFromCache(RenderObject* client, bool markForInvalidation)
62 {
63     ASSERT(client);
64     m_masker.remove(client);
65
66     markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation);
67 }
68
69 bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode)
70 {
71     ASSERT(object);
72     ASSERT(context);
73     ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode);
74
75     bool missingMaskerData = !m_masker.contains(object);
76     if (missingMaskerData)
77         m_masker.set(object, createOwned<MaskerData>().release());
78
79     MaskerData* maskerData = m_masker.get(object);
80
81     AffineTransform absoluteTransform;
82     SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransform);
83
84     FloatRect repaintRect = object->repaintRectInLocalCoordinates();
85
86     if (!maskerData->maskImage && !repaintRect.isEmpty()) {
87         ASSERT(style());
88         const SVGRenderStyle* svgStyle = style()->svgStyle();
89         ASSERT(svgStyle);
90         ColorSpace colorSpace = svgStyle->colorInterpolation() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB;
91         if (!SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, maskerData->maskImage, colorSpace, Unaccelerated))
92             return false;
93
94         if (!drawContentIntoMaskImage(maskerData, colorSpace, object)) {
95             maskerData->maskImage.clear();
96         }
97     }
98
99     if (!maskerData->maskImage)
100         return false;
101
102     SVGRenderingContext::clipToImageBuffer(context, absoluteTransform, repaintRect, maskerData->maskImage, missingMaskerData);
103     return true;
104 }
105
106 bool RenderSVGResourceMasker::drawContentIntoMaskImage(MaskerData* maskerData, ColorSpace colorSpace, RenderObject* object)
107 {
108     GraphicsContext* maskImageContext = maskerData->maskImage->context();
109     ASSERT(maskImageContext);
110
111     // Eventually adjust the mask image context according to the target objectBoundingBox.
112     AffineTransform maskContentTransformation;
113     if (maskElement().maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
114         FloatRect objectBoundingBox = object->objectBoundingBox();
115         maskContentTransformation.translate(objectBoundingBox.x(), objectBoundingBox.y());
116         maskContentTransformation.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
117         maskImageContext->concatCTM(maskContentTransformation);
118     }
119
120     // Draw the content into the ImageBuffer.
121     for (Node* node = maskElement().firstChild(); node; node = node->nextSibling()) {
122         RenderObject* renderer = node->renderer();
123         if (!node->isSVGElement() || !renderer)
124             continue;
125         if (renderer->needsLayout())
126             return false;
127         RenderStyle* style = renderer->style();
128         if (!style || style->display() == NONE || style->visibility() != VISIBLE)
129             continue;
130         SVGRenderingContext::renderSubtreeToImageBuffer(maskerData->maskImage.get(), renderer, maskContentTransformation);
131     }
132
133 #if !USE(CG)
134     maskerData->maskImage->transformColorSpace(ColorSpaceDeviceRGB, colorSpace);
135 #else
136     UNUSED_PARAM(colorSpace);
137 #endif
138
139     ASSERT(style());
140     ASSERT(style()->svgStyle());
141     // Create the luminance mask.
142     if (style()->svgStyle()->maskType() == MT_LUMINANCE)
143         maskerData->maskImage->convertToLuminanceMask();
144
145     return true;
146 }
147
148 void RenderSVGResourceMasker::calculateMaskContentRepaintRect()
149 {
150     for (Node* childNode = maskElement().firstChild(); childNode; childNode = childNode->nextSibling()) {
151         RenderObject* renderer = childNode->renderer();
152         if (!childNode->isSVGElement() || !renderer)
153             continue;
154         RenderStyle* style = renderer->style();
155         if (!style || style->display() == NONE || style->visibility() != VISIBLE)
156              continue;
157         m_maskContentBoundaries.unite(renderer->localToParentTransform().mapRect(renderer->repaintRectInLocalCoordinates()));
158     }
159 }
160
161 FloatRect RenderSVGResourceMasker::resourceBoundingBox(RenderObject* object)
162 {
163     FloatRect objectBoundingBox = object->objectBoundingBox();
164     FloatRect maskBoundaries = SVGLengthContext::resolveRectangle<SVGMaskElement>(&maskElement(), maskElement().maskUnits(), objectBoundingBox);
165
166     // Resource was not layouted yet. Give back clipping rect of the mask.
167     if (selfNeedsLayout())
168         return maskBoundaries;
169
170     if (m_maskContentBoundaries.isEmpty())
171         calculateMaskContentRepaintRect();
172
173     FloatRect maskRect = m_maskContentBoundaries;
174     if (maskElement().maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
175         AffineTransform transform;
176         transform.translate(objectBoundingBox.x(), objectBoundingBox.y());
177         transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
178         maskRect = transform.mapRect(maskRect);
179     }
180
181     maskRect.intersect(maskBoundaries);
182     return maskRect;
183 }
184
185 }
186
187 #endif // ENABLE(SVG)