Upstream version 6.35.121.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/ImageBuffer.h"
29 #include "platform/graphics/UnacceleratedImageBufferSurface.h"
30 #include "platform/graphics/filters/Filter.h"
31
32 #if HAVE(ARM_NEON_INTRINSICS)
33 #include <arm_neon.h>
34 #endif
35
36 namespace WebCore {
37
38 static const float kMaxFilterArea = 4096 * 4096;
39
40 FilterEffect::FilterEffect(Filter* filter)
41     : m_alphaImage(false)
42     , m_filter(filter)
43     , m_hasX(false)
44     , m_hasY(false)
45     , m_hasWidth(false)
46     , m_hasHeight(false)
47     , m_clipsToBounds(true)
48     , m_operatingColorSpace(ColorSpaceLinearRGB)
49     , m_resultColorSpace(ColorSpaceDeviceRGB)
50 {
51     ASSERT(m_filter);
52 }
53
54 FilterEffect::~FilterEffect()
55 {
56 }
57
58 float FilterEffect::maxFilterArea()
59 {
60     return kMaxFilterArea;
61 }
62
63 bool FilterEffect::isFilterSizeValid(const FloatRect& rect)
64 {
65     if (rect.width() < 0 || rect.height() < 0
66         ||  (rect.height() * rect.width() > kMaxFilterArea))
67         return false;
68
69     return true;
70 }
71
72 FloatRect FilterEffect::determineAbsolutePaintRect(const FloatRect& originalRequestedRect)
73 {
74     FloatRect requestedRect = originalRequestedRect;
75     // Filters in SVG clip to primitive subregion, while CSS doesn't.
76     if (m_clipsToBounds)
77         requestedRect.intersect(maxEffectRect());
78
79     // We may be called multiple times if result is used more than once. Return
80     // quickly if if nothing new is required.
81     if (absolutePaintRect().contains(enclosingIntRect(requestedRect)))
82         return requestedRect;
83
84     FloatRect inputRect = mapPaintRect(requestedRect, false);
85     FloatRect inputUnion;
86     unsigned size = m_inputEffects.size();
87
88     for (unsigned i = 0; i < size; ++i)
89         inputUnion.unite(m_inputEffects.at(i)->determineAbsolutePaintRect(inputRect));
90     inputUnion = mapPaintRect(inputUnion, true);
91
92     if (affectsTransparentPixels() || !size) {
93         inputUnion = requestedRect;
94     } else {
95         // Rect may have inflated. Re-intersect with request.
96         inputUnion.intersect(requestedRect);
97     }
98
99     addAbsolutePaintRect(inputUnion);
100     return inputUnion;
101 }
102
103 FloatRect FilterEffect::mapRectRecursive(const FloatRect& rect)
104 {
105     FloatRect result;
106     if (m_inputEffects.size() > 0) {
107         result = m_inputEffects.at(0)->mapRectRecursive(rect);
108         for (unsigned i = 1; i < m_inputEffects.size(); ++i)
109             result.unite(m_inputEffects.at(i)->mapRectRecursive(rect));
110     } else
111         result = rect;
112     return mapRect(result);
113 }
114
115 FloatRect FilterEffect::getSourceRect(const FloatRect& destRect, const FloatRect& destClipRect)
116 {
117     FloatRect sourceRect = mapRect(destRect, false);
118     FloatRect sourceClipRect = mapRect(destClipRect, false);
119
120     FloatRect boundaries = filter()->mapLocalRectToAbsoluteRect(effectBoundaries());
121     if (hasX())
122         sourceClipRect.setX(boundaries.x());
123     if (hasY())
124         sourceClipRect.setY(boundaries.y());
125     if (hasWidth())
126         sourceClipRect.setWidth(boundaries.width());
127     if (hasHeight())
128         sourceClipRect.setHeight(boundaries.height());
129
130     FloatRect result;
131     if (m_inputEffects.size() > 0) {
132         result = m_inputEffects.at(0)->getSourceRect(sourceRect, sourceClipRect);
133         for (unsigned i = 1; i < m_inputEffects.size(); ++i)
134             result.unite(m_inputEffects.at(i)->getSourceRect(sourceRect, sourceClipRect));
135     } else {
136         result = sourceRect;
137         result.intersect(sourceClipRect);
138     }
139     return result;
140 }
141
142 IntRect FilterEffect::requestedRegionOfInputImageData(const IntRect& effectRect) const
143 {
144     ASSERT(hasResult());
145     IntPoint location = m_absolutePaintRect.location();
146     location.moveBy(-effectRect.location());
147     return IntRect(location, m_absolutePaintRect.size());
148 }
149
150 IntRect FilterEffect::drawingRegionOfInputImage(const IntRect& srcRect) const
151 {
152     return IntRect(IntPoint(srcRect.x() - m_absolutePaintRect.x(),
153                             srcRect.y() - m_absolutePaintRect.y()), srcRect.size());
154 }
155
156 FilterEffect* FilterEffect::inputEffect(unsigned number) const
157 {
158     ASSERT_WITH_SECURITY_IMPLICATION(number < m_inputEffects.size());
159     return m_inputEffects.at(number).get();
160 }
161
162 void FilterEffect::addAbsolutePaintRect(const FloatRect& paintRect)
163 {
164     IntRect intPaintRect(enclosingIntRect(paintRect));
165     if (m_absolutePaintRect.contains(intPaintRect))
166         return;
167     intPaintRect.unite(m_absolutePaintRect);
168     // Make sure we are not holding on to a smaller rendering.
169     clearResult();
170     m_absolutePaintRect = intPaintRect;
171 }
172
173 void FilterEffect::apply()
174 {
175     // Recursively determine paint rects first, so that we don't redraw images
176     // if a smaller section is requested first.
177     determineAbsolutePaintRect(maxEffectRect());
178     applyRecursive();
179 }
180
181 void FilterEffect::applyRecursive()
182 {
183     if (hasResult())
184         return;
185     unsigned size = m_inputEffects.size();
186     for (unsigned i = 0; i < size; ++i) {
187         FilterEffect* in = m_inputEffects.at(i).get();
188         in->applyRecursive();
189         if (!in->hasResult())
190             return;
191
192         // Convert input results to the current effect's color space.
193         transformResultColorSpace(in, i);
194     }
195
196     setResultColorSpace(m_operatingColorSpace);
197
198     if (!isFilterSizeValid(m_absolutePaintRect))
199         return;
200
201     if (requiresValidPreMultipliedPixels()) {
202         for (unsigned i = 0; i < size; ++i)
203             inputEffect(i)->correctFilterResultIfNeeded();
204     }
205
206     if (applySkia())
207         return;
208
209     applySoftware();
210 }
211
212 void FilterEffect::forceValidPreMultipliedPixels()
213 {
214     // Must operate on pre-multiplied results; other formats cannot have invalid pixels.
215     if (!m_premultipliedImageResult)
216         return;
217
218     Uint8ClampedArray* imageArray = m_premultipliedImageResult.get();
219     unsigned char* pixelData = imageArray->data();
220     int pixelArrayLength = imageArray->length();
221
222     // We must have four bytes per pixel, and complete pixels
223     ASSERT(!(pixelArrayLength % 4));
224
225 #if HAVE(ARM_NEON_INTRINSICS)
226     if (pixelArrayLength >= 64) {
227         unsigned char* lastPixel = pixelData + (pixelArrayLength & ~0x3f);
228         do {
229             // Increments pixelData by 64.
230             uint8x16x4_t sixteenPixels = vld4q_u8(pixelData);
231             sixteenPixels.val[0] = vminq_u8(sixteenPixels.val[0], sixteenPixels.val[3]);
232             sixteenPixels.val[1] = vminq_u8(sixteenPixels.val[1], sixteenPixels.val[3]);
233             sixteenPixels.val[2] = vminq_u8(sixteenPixels.val[2], sixteenPixels.val[3]);
234             vst4q_u8(pixelData, sixteenPixels);
235             pixelData += 64;
236         } while (pixelData < lastPixel);
237
238         pixelArrayLength &= 0x3f;
239         if (!pixelArrayLength)
240             return;
241     }
242 #endif
243
244     int numPixels = pixelArrayLength / 4;
245
246     // Iterate over each pixel, checking alpha and adjusting color components if necessary
247     while (--numPixels >= 0) {
248         // Alpha is the 4th byte in a pixel
249         unsigned char a = *(pixelData + 3);
250         // Clamp each component to alpha, and increment the pixel location
251         for (int i = 0; i < 3; ++i) {
252             if (*pixelData > a)
253                 *pixelData = a;
254             ++pixelData;
255         }
256         // Increment for alpha
257         ++pixelData;
258     }
259 }
260
261 void FilterEffect::clearResult()
262 {
263     if (m_imageBufferResult)
264         m_imageBufferResult.clear();
265     if (m_unmultipliedImageResult)
266         m_unmultipliedImageResult.clear();
267     if (m_premultipliedImageResult)
268         m_premultipliedImageResult.clear();
269
270     m_absolutePaintRect = IntRect();
271 }
272
273 void FilterEffect::clearResultsRecursive()
274 {
275     // Clear all results, regardless that the current effect has
276     // a result. Can be used if an effect is in an erroneous state.
277     if (hasResult())
278         clearResult();
279
280     unsigned size = m_inputEffects.size();
281     for (unsigned i = 0; i < size; ++i)
282         m_inputEffects.at(i).get()->clearResultsRecursive();
283 }
284
285 ImageBuffer* FilterEffect::asImageBuffer()
286 {
287     if (!hasResult())
288         return 0;
289     if (m_imageBufferResult)
290         return m_imageBufferResult.get();
291     OwnPtr<ImageBufferSurface> surface;
292     surface = adoptPtr(new UnacceleratedImageBufferSurface(m_absolutePaintRect.size()));
293     m_imageBufferResult = ImageBuffer::create(surface.release());
294     if (!m_imageBufferResult)
295         return 0;
296
297     IntRect destinationRect(IntPoint(), m_absolutePaintRect.size());
298     if (m_premultipliedImageResult)
299         m_imageBufferResult->putByteArray(Premultiplied, m_premultipliedImageResult.get(), destinationRect.size(), destinationRect, IntPoint());
300     else
301         m_imageBufferResult->putByteArray(Unmultiplied, m_unmultipliedImageResult.get(), destinationRect.size(), destinationRect, IntPoint());
302     return m_imageBufferResult.get();
303 }
304
305 PassRefPtr<Uint8ClampedArray> FilterEffect::asUnmultipliedImage(const IntRect& rect)
306 {
307     ASSERT(isFilterSizeValid(rect));
308     RefPtr<Uint8ClampedArray> imageData = Uint8ClampedArray::createUninitialized(rect.width() * rect.height() * 4);
309     copyUnmultipliedImage(imageData.get(), rect);
310     return imageData.release();
311 }
312
313 PassRefPtr<Uint8ClampedArray> FilterEffect::asPremultipliedImage(const IntRect& rect)
314 {
315     ASSERT(isFilterSizeValid(rect));
316     RefPtr<Uint8ClampedArray> imageData = Uint8ClampedArray::createUninitialized(rect.width() * rect.height() * 4);
317     copyPremultipliedImage(imageData.get(), rect);
318     return imageData.release();
319 }
320
321 inline void FilterEffect::copyImageBytes(Uint8ClampedArray* source, Uint8ClampedArray* destination, const IntRect& rect)
322 {
323     // Initialize the destination to transparent black, if not entirely covered by the source.
324     if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > m_absolutePaintRect.width() || rect.maxY() > m_absolutePaintRect.height())
325         memset(destination->data(), 0, destination->length());
326
327     // Early return if the rect does not intersect with the source.
328     if (rect.maxX() <= 0 || rect.maxY() <= 0 || rect.x() >= m_absolutePaintRect.width() || rect.y() >= m_absolutePaintRect.height())
329         return;
330
331     int xOrigin = rect.x();
332     int xDest = 0;
333     if (xOrigin < 0) {
334         xDest = -xOrigin;
335         xOrigin = 0;
336     }
337     int xEnd = rect.maxX();
338     if (xEnd > m_absolutePaintRect.width())
339         xEnd = m_absolutePaintRect.width();
340
341     int yOrigin = rect.y();
342     int yDest = 0;
343     if (yOrigin < 0) {
344         yDest = -yOrigin;
345         yOrigin = 0;
346     }
347     int yEnd = rect.maxY();
348     if (yEnd > m_absolutePaintRect.height())
349         yEnd = m_absolutePaintRect.height();
350
351     int size = (xEnd - xOrigin) * 4;
352     int destinationScanline = rect.width() * 4;
353     int sourceScanline = m_absolutePaintRect.width() * 4;
354     unsigned char *destinationPixel = destination->data() + ((yDest * rect.width()) + xDest) * 4;
355     unsigned char *sourcePixel = source->data() + ((yOrigin * m_absolutePaintRect.width()) + xOrigin) * 4;
356
357     while (yOrigin < yEnd) {
358         memcpy(destinationPixel, sourcePixel, size);
359         destinationPixel += destinationScanline;
360         sourcePixel += sourceScanline;
361         ++yOrigin;
362     }
363 }
364
365 void FilterEffect::copyUnmultipliedImage(Uint8ClampedArray* destination, const IntRect& rect)
366 {
367     ASSERT(hasResult());
368
369     if (!m_unmultipliedImageResult) {
370         // We prefer a conversion from the image buffer.
371         if (m_imageBufferResult)
372             m_unmultipliedImageResult = m_imageBufferResult->getUnmultipliedImageData(IntRect(IntPoint(), m_absolutePaintRect.size()));
373         else {
374             ASSERT(isFilterSizeValid(m_absolutePaintRect));
375             m_unmultipliedImageResult = Uint8ClampedArray::createUninitialized(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
376             unsigned char* sourceComponent = m_premultipliedImageResult->data();
377             unsigned char* destinationComponent = m_unmultipliedImageResult->data();
378             unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
379             while (sourceComponent < end) {
380                 int alpha = sourceComponent[3];
381                 if (alpha) {
382                     destinationComponent[0] = static_cast<int>(sourceComponent[0]) * 255 / alpha;
383                     destinationComponent[1] = static_cast<int>(sourceComponent[1]) * 255 / alpha;
384                     destinationComponent[2] = static_cast<int>(sourceComponent[2]) * 255 / alpha;
385                 } else {
386                     destinationComponent[0] = 0;
387                     destinationComponent[1] = 0;
388                     destinationComponent[2] = 0;
389                 }
390                 destinationComponent[3] = alpha;
391                 sourceComponent += 4;
392                 destinationComponent += 4;
393             }
394         }
395     }
396     copyImageBytes(m_unmultipliedImageResult.get(), destination, rect);
397 }
398
399 void FilterEffect::copyPremultipliedImage(Uint8ClampedArray* destination, const IntRect& rect)
400 {
401     ASSERT(hasResult());
402
403     if (!m_premultipliedImageResult) {
404         // We prefer a conversion from the image buffer.
405         if (m_imageBufferResult)
406             m_premultipliedImageResult = m_imageBufferResult->getPremultipliedImageData(IntRect(IntPoint(), m_absolutePaintRect.size()));
407         else {
408             ASSERT(isFilterSizeValid(m_absolutePaintRect));
409             m_premultipliedImageResult = Uint8ClampedArray::createUninitialized(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
410             unsigned char* sourceComponent = m_unmultipliedImageResult->data();
411             unsigned char* destinationComponent = m_premultipliedImageResult->data();
412             unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
413             while (sourceComponent < end) {
414                 int alpha = sourceComponent[3];
415                 destinationComponent[0] = static_cast<int>(sourceComponent[0]) * alpha / 255;
416                 destinationComponent[1] = static_cast<int>(sourceComponent[1]) * alpha / 255;
417                 destinationComponent[2] = static_cast<int>(sourceComponent[2]) * alpha / 255;
418                 destinationComponent[3] = alpha;
419                 sourceComponent += 4;
420                 destinationComponent += 4;
421             }
422         }
423     }
424     copyImageBytes(m_premultipliedImageResult.get(), destination, rect);
425 }
426
427 ImageBuffer* FilterEffect::createImageBufferResult()
428 {
429     // Only one result type is allowed.
430     if (m_absolutePaintRect.isEmpty())
431         return 0;
432     OwnPtr<ImageBufferSurface> surface;
433     surface = adoptPtr(new UnacceleratedImageBufferSurface(m_absolutePaintRect.size()));
434     m_imageBufferResult = ImageBuffer::create(surface.release());
435     return m_imageBufferResult.get();
436 }
437
438 Uint8ClampedArray* FilterEffect::createUnmultipliedImageResult()
439 {
440     // Only one result type is allowed.
441     ASSERT(!hasResult());
442     ASSERT(isFilterSizeValid(m_absolutePaintRect));
443
444     if (m_absolutePaintRect.isEmpty())
445         return 0;
446     m_unmultipliedImageResult = Uint8ClampedArray::createUninitialized(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
447     return m_unmultipliedImageResult.get();
448 }
449
450 Uint8ClampedArray* FilterEffect::createPremultipliedImageResult()
451 {
452     // Only one result type is allowed.
453     ASSERT(!hasResult());
454     ASSERT(isFilterSizeValid(m_absolutePaintRect));
455
456     if (m_absolutePaintRect.isEmpty())
457         return 0;
458     m_premultipliedImageResult = Uint8ClampedArray::createUninitialized(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
459     return m_premultipliedImageResult.get();
460 }
461
462 Color FilterEffect::adaptColorToOperatingColorSpace(const Color& deviceColor)
463 {
464     // |deviceColor| is assumed to be DeviceRGB.
465     return ColorSpaceUtilities::convertColor(deviceColor, operatingColorSpace());
466 }
467
468 void FilterEffect::transformResultColorSpace(ColorSpace dstColorSpace)
469 {
470     if (!hasResult() || dstColorSpace == m_resultColorSpace)
471         return;
472
473     // FIXME: We can avoid this potentially unnecessary ImageBuffer conversion by adding
474     // color space transform support for the {pre,un}multiplied arrays.
475     asImageBuffer()->transformColorSpace(m_resultColorSpace, dstColorSpace);
476
477     m_resultColorSpace = dstColorSpace;
478
479     if (m_unmultipliedImageResult)
480         m_unmultipliedImageResult.clear();
481     if (m_premultipliedImageResult)
482         m_premultipliedImageResult.clear();
483 }
484
485 TextStream& FilterEffect::externalRepresentation(TextStream& ts, int) const
486 {
487     // FIXME: We should dump the subRegions of the filter primitives here later. This isn't
488     // possible at the moment, because we need more detailed informations from the target object.
489     return ts;
490 }
491
492 FloatRect FilterEffect::determineFilterPrimitiveSubregion(DetermineSubregionFlags flags)
493 {
494     Filter* filter = this->filter();
495     ASSERT(filter);
496
497     // FETile, FETurbulence, FEFlood don't have input effects, take the filter region as unite rect.
498     FloatRect subregion;
499     if (unsigned numberOfInputEffects = inputEffects().size()) {
500         subregion = inputEffect(0)->determineFilterPrimitiveSubregion(flags);
501         for (unsigned i = 1; i < numberOfInputEffects; ++i)
502             subregion.unite(inputEffect(i)->determineFilterPrimitiveSubregion(flags));
503     } else {
504         subregion = filter->filterRegion();
505     }
506
507     // After calling determineFilterPrimitiveSubregion on the target effect, reset the subregion again for <feTile>.
508     if (filterEffectType() == FilterEffectTypeTile)
509         subregion = filter->filterRegion();
510
511     if (flags & MapRectForward) {
512         // mapRect works on absolute rectangles.
513         subregion = filter->mapAbsoluteRectToLocalRect(mapRect(
514             filter->mapLocalRectToAbsoluteRect(subregion)));
515     }
516
517     FloatRect boundaries = effectBoundaries();
518     if (hasX())
519         subregion.setX(boundaries.x());
520     if (hasY())
521         subregion.setY(boundaries.y());
522     if (hasWidth())
523         subregion.setWidth(boundaries.width());
524     if (hasHeight())
525         subregion.setHeight(boundaries.height());
526
527     setFilterPrimitiveSubregion(subregion);
528
529     FloatRect absoluteSubregion = filter->mapLocalRectToAbsoluteRect(subregion);
530
531     // Clip every filter effect to the filter region.
532     if (flags & ClipToFilterRegion) {
533         absoluteSubregion.intersect(filter->absoluteFilterRegion());
534     }
535
536     setMaxEffectRect(absoluteSubregion);
537     return subregion;
538 }
539
540 PassRefPtr<SkImageFilter> FilterEffect::createImageFilter(SkiaImageFilterBuilder* builder)
541 {
542     return nullptr;
543 }
544
545 SkImageFilter::CropRect FilterEffect::getCropRect(const FloatSize& cropOffset) const
546 {
547     FloatRect rect = filter()->filterRegion();
548     uint32_t flags = 0;
549     FloatRect boundaries = effectBoundaries();
550     boundaries.move(cropOffset);
551     if (hasX()) {
552         rect.setX(boundaries.x());
553         flags |= SkImageFilter::CropRect::kHasLeft_CropEdge;
554         flags |= SkImageFilter::CropRect::kHasRight_CropEdge;
555     }
556     if (hasY()) {
557         rect.setY(boundaries.y());
558         flags |= SkImageFilter::CropRect::kHasTop_CropEdge;
559         flags |= SkImageFilter::CropRect::kHasBottom_CropEdge;
560     }
561     if (hasWidth()) {
562         rect.setWidth(boundaries.width());
563         flags |= SkImageFilter::CropRect::kHasRight_CropEdge;
564     }
565     if (hasHeight()) {
566         rect.setHeight(boundaries.height());
567         flags |= SkImageFilter::CropRect::kHasBottom_CropEdge;
568     }
569     rect = filter()->mapLocalRectToAbsoluteRect(rect);
570     return SkImageFilter::CropRect(rect, flags);
571 }
572
573 } // namespace WebCore