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