Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / graphics / filters / FilterEffect.cpp
1 /*
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.
7  *
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.
12  *
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.
17  *
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.
22  */
23
24 #include "config.h"
25
26 #include "platform/graphics/filters/FilterEffect.h"
27
28 #include "platform/graphics/filters/Filter.h"
29
30 namespace blink {
31
32 static const float kMaxFilterArea = 4096 * 4096;
33
34 FilterEffect::FilterEffect(Filter* filter)
35     : m_alphaImage(false)
36     , m_filter(filter)
37     , m_hasX(false)
38     , m_hasY(false)
39     , m_hasWidth(false)
40     , m_hasHeight(false)
41     , m_clipsToBounds(true)
42     , m_operatingColorSpace(ColorSpaceLinearRGB)
43     , m_resultColorSpace(ColorSpaceDeviceRGB)
44 {
45     ASSERT(m_filter);
46 }
47
48 FilterEffect::~FilterEffect()
49 {
50 }
51
52 float FilterEffect::maxFilterArea()
53 {
54     return kMaxFilterArea;
55 }
56
57 bool FilterEffect::isFilterSizeValid(const FloatRect& rect)
58 {
59     if (rect.width() < 0 || rect.height() < 0
60         ||  (rect.height() * rect.width() > kMaxFilterArea))
61         return false;
62
63     return true;
64 }
65
66 FloatRect FilterEffect::determineAbsolutePaintRect(const FloatRect& originalRequestedRect)
67 {
68     FloatRect requestedRect = originalRequestedRect;
69     // Filters in SVG clip to primitive subregion, while CSS doesn't.
70     if (m_clipsToBounds)
71         requestedRect.intersect(maxEffectRect());
72
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)))
76         return requestedRect;
77
78     FloatRect inputRect = mapPaintRect(requestedRect, false);
79     FloatRect inputUnion;
80     unsigned size = m_inputEffects.size();
81
82     for (unsigned i = 0; i < size; ++i)
83         inputUnion.unite(m_inputEffects.at(i)->determineAbsolutePaintRect(inputRect));
84     inputUnion = mapPaintRect(inputUnion, true);
85
86     if (affectsTransparentPixels() || !size) {
87         inputUnion = requestedRect;
88     } else {
89         // Rect may have inflated. Re-intersect with request.
90         inputUnion.intersect(requestedRect);
91     }
92
93     addAbsolutePaintRect(inputUnion);
94     return inputUnion;
95 }
96
97 FloatRect FilterEffect::mapRectRecursive(const FloatRect& rect)
98 {
99     FloatRect result;
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));
104     } else
105         result = rect;
106     return mapRect(result);
107 }
108
109 FloatRect FilterEffect::getSourceRect(const FloatRect& destRect, const FloatRect& destClipRect)
110 {
111     FloatRect sourceRect = mapRect(destRect, false);
112     FloatRect sourceClipRect = mapRect(destClipRect, false);
113
114     FloatRect boundaries = filter()->mapLocalRectToAbsoluteRect(effectBoundaries());
115     if (hasX())
116         sourceClipRect.setX(boundaries.x());
117     if (hasY())
118         sourceClipRect.setY(boundaries.y());
119     if (hasWidth())
120         sourceClipRect.setWidth(boundaries.width());
121     if (hasHeight())
122         sourceClipRect.setHeight(boundaries.height());
123
124     FloatRect result;
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));
129     } else {
130         result = sourceRect;
131         result.intersect(sourceClipRect);
132     }
133     return result;
134 }
135
136 FilterEffect* FilterEffect::inputEffect(unsigned number) const
137 {
138     ASSERT_WITH_SECURITY_IMPLICATION(number < m_inputEffects.size());
139     return m_inputEffects.at(number).get();
140 }
141
142 void FilterEffect::addAbsolutePaintRect(const FloatRect& paintRect)
143 {
144     IntRect intPaintRect(enclosingIntRect(paintRect));
145     if (m_absolutePaintRect.contains(intPaintRect))
146         return;
147     intPaintRect.unite(m_absolutePaintRect);
148     // Make sure we are not holding on to a smaller rendering.
149     clearResult();
150     m_absolutePaintRect = intPaintRect;
151 }
152
153 void FilterEffect::clearResult()
154 {
155     m_absolutePaintRect = IntRect();
156     for (int i = 0; i < 4; i++) {
157         m_imageFilters[i] = nullptr;
158     }
159 }
160
161 void FilterEffect::clearResultsRecursive()
162 {
163     unsigned size = m_inputEffects.size();
164     for (unsigned i = 0; i < size; ++i)
165         m_inputEffects.at(i).get()->clearResultsRecursive();
166 }
167
168 Color FilterEffect::adaptColorToOperatingColorSpace(const Color& deviceColor)
169 {
170     // |deviceColor| is assumed to be DeviceRGB.
171     return ColorSpaceUtilities::convertColor(deviceColor, operatingColorSpace());
172 }
173
174 TextStream& FilterEffect::externalRepresentation(TextStream& ts, int) const
175 {
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.
178     return ts;
179 }
180
181 FloatRect FilterEffect::determineFilterPrimitiveSubregion(DetermineSubregionFlags flags)
182 {
183     Filter* filter = this->filter();
184     ASSERT(filter);
185
186     // FETile, FETurbulence, FEFlood don't have input effects, take the filter region as unite rect.
187     FloatRect subregion;
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));
192     } else {
193         subregion = filter->filterRegion();
194     }
195
196     // After calling determineFilterPrimitiveSubregion on the target effect, reset the subregion again for <feTile>.
197     if (filterEffectType() == FilterEffectTypeTile)
198         subregion = filter->filterRegion();
199
200     if (flags & MapRectForward) {
201         // mapRect works on absolute rectangles.
202         subregion = filter->mapAbsoluteRectToLocalRect(mapRect(
203             filter->mapLocalRectToAbsoluteRect(subregion)));
204     }
205
206     FloatRect boundaries = effectBoundaries();
207     if (hasX())
208         subregion.setX(boundaries.x());
209     if (hasY())
210         subregion.setY(boundaries.y());
211     if (hasWidth())
212         subregion.setWidth(boundaries.width());
213     if (hasHeight())
214         subregion.setHeight(boundaries.height());
215
216     setFilterPrimitiveSubregion(subregion);
217
218     FloatRect absoluteSubregion = filter->mapLocalRectToAbsoluteRect(subregion);
219
220     // Clip every filter effect to the filter region.
221     if (flags & ClipToFilterRegion) {
222         absoluteSubregion.intersect(filter->absoluteFilterRegion());
223     }
224
225     setMaxEffectRect(absoluteSubregion);
226     return subregion;
227 }
228
229 PassRefPtr<SkImageFilter> FilterEffect::createImageFilter(SkiaImageFilterBuilder* builder)
230 {
231     return nullptr;
232 }
233
234 PassRefPtr<SkImageFilter> FilterEffect::createImageFilterWithoutValidation(SkiaImageFilterBuilder* builder)
235 {
236     return createImageFilter(builder);
237 }
238
239 SkImageFilter::CropRect FilterEffect::getCropRect(const FloatSize& cropOffset) const
240 {
241     FloatRect rect = filter()->filterRegion();
242     uint32_t flags = 0;
243     FloatRect boundaries = effectBoundaries();
244     boundaries.move(cropOffset);
245     if (hasX()) {
246         rect.setX(boundaries.x());
247         flags |= SkImageFilter::CropRect::kHasLeft_CropEdge;
248         flags |= SkImageFilter::CropRect::kHasRight_CropEdge;
249     }
250     if (hasY()) {
251         rect.setY(boundaries.y());
252         flags |= SkImageFilter::CropRect::kHasTop_CropEdge;
253         flags |= SkImageFilter::CropRect::kHasBottom_CropEdge;
254     }
255     if (hasWidth()) {
256         rect.setWidth(boundaries.width());
257         flags |= SkImageFilter::CropRect::kHasRight_CropEdge;
258     }
259     if (hasHeight()) {
260         rect.setHeight(boundaries.height());
261         flags |= SkImageFilter::CropRect::kHasBottom_CropEdge;
262     }
263     rect.scale(filter()->scale());
264     return SkImageFilter::CropRect(rect, flags);
265 }
266
267 static int getImageFilterIndex(ColorSpace colorSpace, bool requiresPMColorValidation)
268 {
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);
275 }
276
277 SkImageFilter* FilterEffect::getImageFilter(ColorSpace colorSpace, bool requiresPMColorValidation) const
278 {
279     int index = getImageFilterIndex(colorSpace, requiresPMColorValidation);
280     return m_imageFilters[index].get();
281 }
282
283 void FilterEffect::setImageFilter(ColorSpace colorSpace, bool requiresPMColorValidation, PassRefPtr<SkImageFilter> imageFilter)
284 {
285     int index = getImageFilterIndex(colorSpace, requiresPMColorValidation);
286     m_imageFilters[index] = imageFilter;
287 }
288
289 } // namespace blink