2 * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com>
3 * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
4 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
5 * Copyright (C) 2012 University of Szeged
6 * Copyright (C) 2013 Google Inc. All rights reserved.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
26 #include "platform/graphics/filters/FilterEffect.h"
28 #include "platform/graphics/filters/Filter.h"
32 static const float kMaxFilterArea = 4096 * 4096;
34 FilterEffect::FilterEffect(Filter* filter)
41 , m_clipsToBounds(true)
42 , m_operatingColorSpace(ColorSpaceLinearRGB)
43 , m_resultColorSpace(ColorSpaceDeviceRGB)
48 FilterEffect::~FilterEffect()
52 float FilterEffect::maxFilterArea()
54 return kMaxFilterArea;
57 bool FilterEffect::isFilterSizeValid(const FloatRect& rect)
59 if (rect.width() < 0 || rect.height() < 0
60 || (rect.height() * rect.width() > kMaxFilterArea))
66 FloatRect FilterEffect::determineAbsolutePaintRect(const FloatRect& originalRequestedRect)
68 FloatRect requestedRect = originalRequestedRect;
69 // Filters in SVG clip to primitive subregion, while CSS doesn't.
71 requestedRect.intersect(maxEffectRect());
73 // We may be called multiple times if result is used more than once. Return
74 // quickly if if nothing new is required.
75 if (absolutePaintRect().contains(enclosingIntRect(requestedRect)))
78 FloatRect inputRect = mapPaintRect(requestedRect, false);
80 unsigned size = m_inputEffects.size();
82 for (unsigned i = 0; i < size; ++i)
83 inputUnion.unite(m_inputEffects.at(i)->determineAbsolutePaintRect(inputRect));
84 inputUnion = mapPaintRect(inputUnion, true);
86 if (affectsTransparentPixels() || !size) {
87 inputUnion = requestedRect;
89 // Rect may have inflated. Re-intersect with request.
90 inputUnion.intersect(requestedRect);
93 addAbsolutePaintRect(inputUnion);
97 FloatRect FilterEffect::mapRectRecursive(const FloatRect& rect)
100 if (m_inputEffects.size() > 0) {
101 result = m_inputEffects.at(0)->mapRectRecursive(rect);
102 for (unsigned i = 1; i < m_inputEffects.size(); ++i)
103 result.unite(m_inputEffects.at(i)->mapRectRecursive(rect));
106 return mapRect(result);
109 FloatRect FilterEffect::getSourceRect(const FloatRect& destRect, const FloatRect& destClipRect)
111 FloatRect sourceRect = mapRect(destRect, false);
112 FloatRect sourceClipRect = mapRect(destClipRect, false);
114 FloatRect boundaries = filter()->mapLocalRectToAbsoluteRect(effectBoundaries());
116 sourceClipRect.setX(boundaries.x());
118 sourceClipRect.setY(boundaries.y());
120 sourceClipRect.setWidth(boundaries.width());
122 sourceClipRect.setHeight(boundaries.height());
125 if (m_inputEffects.size() > 0) {
126 result = m_inputEffects.at(0)->getSourceRect(sourceRect, sourceClipRect);
127 for (unsigned i = 1; i < m_inputEffects.size(); ++i)
128 result.unite(m_inputEffects.at(i)->getSourceRect(sourceRect, sourceClipRect));
131 result.intersect(sourceClipRect);
136 FilterEffect* FilterEffect::inputEffect(unsigned number) const
138 ASSERT_WITH_SECURITY_IMPLICATION(number < m_inputEffects.size());
139 return m_inputEffects.at(number).get();
142 void FilterEffect::addAbsolutePaintRect(const FloatRect& paintRect)
144 IntRect intPaintRect(enclosingIntRect(paintRect));
145 if (m_absolutePaintRect.contains(intPaintRect))
147 intPaintRect.unite(m_absolutePaintRect);
148 // Make sure we are not holding on to a smaller rendering.
150 m_absolutePaintRect = intPaintRect;
153 void FilterEffect::clearResult()
155 m_absolutePaintRect = IntRect();
156 for (int i = 0; i < 4; i++) {
157 m_imageFilters[i] = nullptr;
161 void FilterEffect::clearResultsRecursive()
163 unsigned size = m_inputEffects.size();
164 for (unsigned i = 0; i < size; ++i)
165 m_inputEffects.at(i).get()->clearResultsRecursive();
168 Color FilterEffect::adaptColorToOperatingColorSpace(const Color& deviceColor)
170 // |deviceColor| is assumed to be DeviceRGB.
171 return ColorSpaceUtilities::convertColor(deviceColor, operatingColorSpace());
174 TextStream& FilterEffect::externalRepresentation(TextStream& ts, int) const
176 // FIXME: We should dump the subRegions of the filter primitives here later. This isn't
177 // possible at the moment, because we need more detailed informations from the target object.
181 FloatRect FilterEffect::determineFilterPrimitiveSubregion(DetermineSubregionFlags flags)
183 Filter* filter = this->filter();
186 // FETile, FETurbulence, FEFlood don't have input effects, take the filter region as unite rect.
188 if (unsigned numberOfInputEffects = inputEffects().size()) {
189 subregion = inputEffect(0)->determineFilterPrimitiveSubregion(flags);
190 for (unsigned i = 1; i < numberOfInputEffects; ++i)
191 subregion.unite(inputEffect(i)->determineFilterPrimitiveSubregion(flags));
193 subregion = filter->filterRegion();
196 // After calling determineFilterPrimitiveSubregion on the target effect, reset the subregion again for <feTile>.
197 if (filterEffectType() == FilterEffectTypeTile)
198 subregion = filter->filterRegion();
200 if (flags & MapRectForward) {
201 // mapRect works on absolute rectangles.
202 subregion = filter->mapAbsoluteRectToLocalRect(mapRect(
203 filter->mapLocalRectToAbsoluteRect(subregion)));
206 FloatRect boundaries = effectBoundaries();
208 subregion.setX(boundaries.x());
210 subregion.setY(boundaries.y());
212 subregion.setWidth(boundaries.width());
214 subregion.setHeight(boundaries.height());
216 setFilterPrimitiveSubregion(subregion);
218 FloatRect absoluteSubregion = filter->mapLocalRectToAbsoluteRect(subregion);
220 // Clip every filter effect to the filter region.
221 if (flags & ClipToFilterRegion) {
222 absoluteSubregion.intersect(filter->absoluteFilterRegion());
225 setMaxEffectRect(absoluteSubregion);
229 PassRefPtr<SkImageFilter> FilterEffect::createImageFilter(SkiaImageFilterBuilder* builder)
234 PassRefPtr<SkImageFilter> FilterEffect::createImageFilterWithoutValidation(SkiaImageFilterBuilder* builder)
236 return createImageFilter(builder);
239 SkImageFilter::CropRect FilterEffect::getCropRect(const FloatSize& cropOffset) const
241 FloatRect rect = filter()->filterRegion();
243 FloatRect boundaries = effectBoundaries();
244 boundaries.move(cropOffset);
246 rect.setX(boundaries.x());
247 flags |= SkImageFilter::CropRect::kHasLeft_CropEdge;
248 flags |= SkImageFilter::CropRect::kHasRight_CropEdge;
251 rect.setY(boundaries.y());
252 flags |= SkImageFilter::CropRect::kHasTop_CropEdge;
253 flags |= SkImageFilter::CropRect::kHasBottom_CropEdge;
256 rect.setWidth(boundaries.width());
257 flags |= SkImageFilter::CropRect::kHasRight_CropEdge;
260 rect.setHeight(boundaries.height());
261 flags |= SkImageFilter::CropRect::kHasBottom_CropEdge;
263 rect.scale(filter()->scale());
264 return SkImageFilter::CropRect(rect, flags);
267 static int getImageFilterIndex(ColorSpace colorSpace, bool requiresPMColorValidation)
269 // Map the (colorspace, bool) tuple to an integer index as follows:
270 // 0 == linear colorspace, no PM validation
271 // 1 == device colorspace, no PM validation
272 // 2 == linear colorspace, PM validation
273 // 3 == device colorspace, PM validation
274 return (colorSpace == ColorSpaceLinearRGB ? 0x1 : 0x0) | (requiresPMColorValidation ? 0x2 : 0x0);
277 SkImageFilter* FilterEffect::getImageFilter(ColorSpace colorSpace, bool requiresPMColorValidation) const
279 int index = getImageFilterIndex(colorSpace, requiresPMColorValidation);
280 return m_imageFilters[index].get();
283 void FilterEffect::setImageFilter(ColorSpace colorSpace, bool requiresPMColorValidation, PassRefPtr<SkImageFilter> imageFilter)
285 int index = getImageFilterIndex(colorSpace, requiresPMColorValidation);
286 m_imageFilters[index] = imageFilter;