2 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
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.
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.
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.
21 #include "RenderSVGResourceMasker.h"
24 #include "ElementIterator.h"
25 #include "FloatPoint.h"
28 #include "RenderBoxModelObject.h"
29 #include "SVGRenderingContext.h"
33 RenderSVGResourceMasker::RenderSVGResourceMasker(SVGMaskElement& element, Ref<RenderStyle>&& style)
34 : RenderSVGResourceContainer(element, WTF::move(style))
38 RenderSVGResourceMasker::~RenderSVGResourceMasker()
42 void RenderSVGResourceMasker::removeAllClientsFromCache(bool markForInvalidation)
44 m_maskContentBoundaries = FloatRect();
47 markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation);
50 void RenderSVGResourceMasker::removeClientFromCache(RenderElement& client, bool markForInvalidation)
52 m_masker.remove(&client);
54 markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation);
57 bool RenderSVGResourceMasker::applySVGMask(RenderElement& renderer, GraphicsContext*& context, bool applyClip)
61 bool missingMaskerData = !m_masker.contains(&renderer);
62 if (missingMaskerData)
63 m_masker.set(&renderer, std::make_unique<MaskerData>());
65 MaskerData* maskerData = m_masker.get(&renderer);
66 AffineTransform absoluteTransform = SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(renderer);
67 FloatRect repaintRect = renderer.repaintRectInLocalCoordinates();
69 if (!maskerData->maskImage && !repaintRect.isEmpty()) {
70 const SVGRenderStyle& svgStyle = style().svgStyle();
71 ColorSpace colorSpace = svgStyle.colorInterpolation() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB;
72 maskerData->maskImage = SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, colorSpace, Unaccelerated);
73 if (!maskerData->maskImage)
76 if (!drawContentIntoMaskImage(maskerData, colorSpace, &renderer))
77 maskerData->maskImage.reset();
80 if (!maskerData->maskImage)
84 SVGRenderingContext::clipToImageBuffer(context, absoluteTransform, repaintRect, maskerData->maskImage, missingMaskerData);
89 bool RenderSVGResourceMasker::applyResource(RenderElement& renderer, const RenderStyle&, GraphicsContext*& context, unsigned short resourceMode)
91 ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode);
92 return applySVGMask(renderer, context, true);
95 bool RenderSVGResourceMasker::drawContentIntoMaskImage(MaskerData* maskerData, ColorSpace colorSpace, RenderObject* object)
97 GraphicsContext* maskImageContext = maskerData->maskImage->context();
98 ASSERT(maskImageContext);
100 // Eventually adjust the mask image context according to the target objectBoundingBox.
101 AffineTransform maskContentTransformation;
102 if (maskElement().maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
103 FloatRect objectBoundingBox = object->objectBoundingBox();
104 maskContentTransformation.translate(objectBoundingBox.x(), objectBoundingBox.y());
105 maskContentTransformation.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
106 maskImageContext->concatCTM(maskContentTransformation);
109 // Draw the content into the ImageBuffer.
110 for (auto& child : childrenOfType<SVGElement>(maskElement())) {
111 auto renderer = child.renderer();
114 if (renderer->needsLayout())
116 const RenderStyle& style = renderer->style();
117 if (style.display() == NONE || style.visibility() != VISIBLE)
119 SVGRenderingContext::renderSubtreeToImageBuffer(maskerData->maskImage.get(), *renderer, maskContentTransformation);
123 maskerData->maskImage->transformColorSpace(ColorSpaceDeviceRGB, colorSpace);
125 UNUSED_PARAM(colorSpace);
128 // Create the luminance mask.
129 if (style().svgStyle().maskType() == MT_LUMINANCE)
130 maskerData->maskImage->convertToLuminanceMask();
135 void RenderSVGResourceMasker::drawMaskForRenderer(RenderElement& renderer, const BackgroundImageGeometry& geometry, GraphicsContext* context, CompositeOperator compositeOp)
137 if (context->paintingDisabled())
140 if (!applySVGMask(renderer, context, false))
143 MaskerData* maskerData = maskerDataForRenderer(renderer);
146 FloatRect oneTileRect;
147 FloatSize actualTileSize(geometry.tileSize().width() + geometry.spaceSize().width(), geometry.tileSize().height() + geometry.spaceSize().height());
148 oneTileRect.setX(geometry.destRect().x() + fmodf(fmodf(-geometry.phase().width(), actualTileSize.width()) - actualTileSize.width(), actualTileSize.width()));
149 oneTileRect.setY(geometry.destRect().y() + fmodf(fmodf(-geometry.phase().height(), actualTileSize.height()) - actualTileSize.height(), actualTileSize.height()));
150 oneTileRect.setSize(geometry.tileSize());
152 FloatSize intrinsicTileSize = maskerData->maskImage->logicalSize();
153 FloatSize scale(geometry.tileSize().width() / intrinsicTileSize.width(), geometry.tileSize().height() / intrinsicTileSize.height());
155 FloatRect visibleSrcRect;
156 visibleSrcRect.setX((geometry.destRect().x() - oneTileRect.x()) / scale.width());
157 visibleSrcRect.setY((geometry.destRect().y() - oneTileRect.y()) / scale.height());
158 visibleSrcRect.setWidth(geometry.destRect().width() / scale.width());
159 visibleSrcRect.setHeight(geometry.destRect().height() / scale.height());
160 context->drawImageBuffer(maskerData->maskImage.get(), ColorSpaceDeviceRGB, geometry.destRect(), visibleSrcRect, compositeOp);
163 void RenderSVGResourceMasker::calculateMaskContentRepaintRect()
165 for (Node* childNode = maskElement().firstChild(); childNode; childNode = childNode->nextSibling()) {
166 RenderObject* renderer = childNode->renderer();
167 if (!childNode->isSVGElement() || !renderer)
169 const RenderStyle& style = renderer->style();
170 if (style.display() == NONE || style.visibility() != VISIBLE)
172 m_maskContentBoundaries.unite(renderer->localToParentTransform().mapRect(renderer->repaintRectInLocalCoordinates()));
176 FloatRect RenderSVGResourceMasker::resourceBoundingBox(const RenderObject& object)
178 FloatRect objectBoundingBox = object.objectBoundingBox();
179 FloatRect maskBoundaries = SVGLengthContext::resolveRectangle<SVGMaskElement>(&maskElement(), maskElement().maskUnits(), objectBoundingBox);
181 // Resource was not layouted yet. Give back clipping rect of the mask.
182 if (selfNeedsLayout())
183 return maskBoundaries;
185 if (m_maskContentBoundaries.isEmpty())
186 calculateMaskContentRepaintRect();
188 FloatRect maskRect = m_maskContentBoundaries;
189 if (maskElement().maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
190 AffineTransform transform;
191 transform.translate(objectBoundingBox.x(), objectBoundingBox.y());
192 transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
193 maskRect = transform.mapRect(maskRect);
196 maskRect.intersect(maskBoundaries);