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