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
36namespace blink {
37
38static const float kMaxFilterArea = 4096 * 4096;
39
40FilterEffect::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
54FilterEffect::~FilterEffect()
55{
56}
57
58float FilterEffect::maxFilterArea()
59{
60    return kMaxFilterArea;
61}
62
63bool 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
72FloatRect 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
103FloatRect 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
115FloatRect 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
142IntRect 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
150IntRect 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
156FilterEffect* FilterEffect::inputEffect(unsigned number) const
157{
158    ASSERT_WITH_SECURITY_IMPLICATION(number < m_inputEffects.size());
159    return m_inputEffects.at(number).get();
160}
161
162void 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
173void 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
181void 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 (!mayProduceInvalidPreMultipliedPixels()) {
202        for (unsigned i = 0; i < size; ++i)
203            inputEffect(i)->correctFilterResultIfNeeded();
204    }
205
206    applySoftware();
207}
208
209void FilterEffect::forceValidPreMultipliedPixels()
210{
211    // Must operate on pre-multiplied results; other formats cannot have invalid pixels.
212    if (!m_premultipliedImageResult)
213        return;
214
215    Uint8ClampedArray* imageArray = m_premultipliedImageResult.get();
216    unsigned char* pixelData = imageArray->data();
217    int pixelArrayLength = imageArray->length();
218
219    // We must have four bytes per pixel, and complete pixels
220    ASSERT(!(pixelArrayLength % 4));
221
222#if HAVE(ARM_NEON_INTRINSICS)
223    if (pixelArrayLength >= 64) {
224        unsigned char* lastPixel = pixelData + (pixelArrayLength & ~0x3f);
225        do {
226            // Increments pixelData by 64.
227            uint8x16x4_t sixteenPixels = vld4q_u8(pixelData);
228            sixteenPixels.val[0] = vminq_u8(sixteenPixels.val[0], sixteenPixels.val[3]);
229            sixteenPixels.val[1] = vminq_u8(sixteenPixels.val[1], sixteenPixels.val[3]);
230            sixteenPixels.val[2] = vminq_u8(sixteenPixels.val[2], sixteenPixels.val[3]);
231            vst4q_u8(pixelData, sixteenPixels);
232            pixelData += 64;
233        } while (pixelData < lastPixel);
234
235        pixelArrayLength &= 0x3f;
236        if (!pixelArrayLength)
237            return;
238    }
239#endif
240
241    int numPixels = pixelArrayLength / 4;
242
243    // Iterate over each pixel, checking alpha and adjusting color components if necessary
244    while (--numPixels >= 0) {
245        // Alpha is the 4th byte in a pixel
246        unsigned char a = *(pixelData + 3);
247        // Clamp each component to alpha, and increment the pixel location
248        for (int i = 0; i < 3; ++i) {
249            if (*pixelData > a)
250                *pixelData = a;
251            ++pixelData;
252        }
253        // Increment for alpha
254        ++pixelData;
255    }
256}
257
258void FilterEffect::clearResult()
259{
260    if (m_imageBufferResult)
261        m_imageBufferResult.clear();
262    if (m_unmultipliedImageResult)
263        m_unmultipliedImageResult.clear();
264    if (m_premultipliedImageResult)
265        m_premultipliedImageResult.clear();
266
267    m_absolutePaintRect = IntRect();
268    for (int i = 0; i < 4; i++) {
269        m_imageFilters[i] = nullptr;
270    }
271}
272
273void 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
285ImageBuffer* 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
305PassRefPtr<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
313PassRefPtr<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
321inline 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
365void 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->getImageData(Unmultiplied, 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
399void 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->getImageData(Premultiplied, 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
427ImageBuffer* FilterEffect::createImageBufferResult()
428{
429    // Only one result type is allowed.
430    ASSERT(!hasResult());
431    ASSERT(isFilterSizeValid(m_absolutePaintRect));
432
433    OwnPtr<ImageBufferSurface> surface;
434    surface = adoptPtr(new UnacceleratedImageBufferSurface(m_absolutePaintRect.size()));
435    m_imageBufferResult = ImageBuffer::create(surface.release());
436    return m_imageBufferResult.get();
437}
438
439Uint8ClampedArray* FilterEffect::createUnmultipliedImageResult()
440{
441    // Only one result type is allowed.
442    ASSERT(!hasResult());
443    ASSERT(isFilterSizeValid(m_absolutePaintRect));
444
445    if (m_absolutePaintRect.isEmpty())
446        return 0;
447    m_unmultipliedImageResult = Uint8ClampedArray::createUninitialized(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
448    return m_unmultipliedImageResult.get();
449}
450
451Uint8ClampedArray* FilterEffect::createPremultipliedImageResult()
452{
453    // Only one result type is allowed.
454    ASSERT(!hasResult());
455    ASSERT(isFilterSizeValid(m_absolutePaintRect));
456
457    if (m_absolutePaintRect.isEmpty())
458        return 0;
459    m_premultipliedImageResult = Uint8ClampedArray::createUninitialized(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
460    return m_premultipliedImageResult.get();
461}
462
463Color FilterEffect::adaptColorToOperatingColorSpace(const Color& deviceColor)
464{
465    // |deviceColor| is assumed to be DeviceRGB.
466    return ColorSpaceUtilities::convertColor(deviceColor, operatingColorSpace());
467}
468
469void FilterEffect::transformResultColorSpace(ColorSpace dstColorSpace)
470{
471    if (!hasResult() || dstColorSpace == m_resultColorSpace)
472        return;
473
474    // FIXME: We can avoid this potentially unnecessary ImageBuffer conversion by adding
475    // color space transform support for the {pre,un}multiplied arrays.
476    asImageBuffer()->transformColorSpace(m_resultColorSpace, dstColorSpace);
477
478    m_resultColorSpace = dstColorSpace;
479
480    if (m_unmultipliedImageResult)
481        m_unmultipliedImageResult.clear();
482    if (m_premultipliedImageResult)
483        m_premultipliedImageResult.clear();
484}
485
486TextStream& FilterEffect::externalRepresentation(TextStream& ts, int) const
487{
488    // FIXME: We should dump the subRegions of the filter primitives here later. This isn't
489    // possible at the moment, because we need more detailed informations from the target object.
490    return ts;
491}
492
493FloatRect FilterEffect::determineFilterPrimitiveSubregion(DetermineSubregionFlags flags)
494{
495    Filter* filter = this->filter();
496    ASSERT(filter);
497
498    // FETile, FETurbulence, FEFlood don't have input effects, take the filter region as unite rect.
499    FloatRect subregion;
500    if (unsigned numberOfInputEffects = inputEffects().size()) {
501        subregion = inputEffect(0)->determineFilterPrimitiveSubregion(flags);
502        for (unsigned i = 1; i < numberOfInputEffects; ++i)
503            subregion.unite(inputEffect(i)->determineFilterPrimitiveSubregion(flags));
504    } else {
505        subregion = filter->filterRegion();
506    }
507
508    // After calling determineFilterPrimitiveSubregion on the target effect, reset the subregion again for <feTile>.
509    if (filterEffectType() == FilterEffectTypeTile)
510        subregion = filter->filterRegion();
511
512    if (flags & MapRectForward) {
513        // mapRect works on absolute rectangles.
514        subregion = filter->mapAbsoluteRectToLocalRect(mapRect(
515            filter->mapLocalRectToAbsoluteRect(subregion)));
516    }
517
518    FloatRect boundaries = effectBoundaries();
519    if (hasX())
520        subregion.setX(boundaries.x());
521    if (hasY())
522        subregion.setY(boundaries.y());
523    if (hasWidth())
524        subregion.setWidth(boundaries.width());
525    if (hasHeight())
526        subregion.setHeight(boundaries.height());
527
528    setFilterPrimitiveSubregion(subregion);
529
530    FloatRect absoluteSubregion = filter->mapLocalRectToAbsoluteRect(subregion);
531
532    // Clip every filter effect to the filter region.
533    if (flags & ClipToFilterRegion) {
534        absoluteSubregion.intersect(filter->absoluteFilterRegion());
535    }
536
537    setMaxEffectRect(absoluteSubregion);
538    return subregion;
539}
540
541PassRefPtr<SkImageFilter> FilterEffect::createImageFilter(SkiaImageFilterBuilder* builder)
542{
543    return nullptr;
544}
545
546PassRefPtr<SkImageFilter> FilterEffect::createImageFilterWithoutValidation(SkiaImageFilterBuilder* builder)
547{
548    return createImageFilter(builder);
549}
550
551SkImageFilter::CropRect FilterEffect::getCropRect(const FloatSize& cropOffset) const
552{
553    FloatRect rect = filter()->filterRegion();
554    uint32_t flags = 0;
555    FloatRect boundaries = effectBoundaries();
556    boundaries.move(cropOffset);
557    if (hasX()) {
558        rect.setX(boundaries.x());
559        flags |= SkImageFilter::CropRect::kHasLeft_CropEdge;
560        flags |= SkImageFilter::CropRect::kHasRight_CropEdge;
561    }
562    if (hasY()) {
563        rect.setY(boundaries.y());
564        flags |= SkImageFilter::CropRect::kHasTop_CropEdge;
565        flags |= SkImageFilter::CropRect::kHasBottom_CropEdge;
566    }
567    if (hasWidth()) {
568        rect.setWidth(boundaries.width());
569        flags |= SkImageFilter::CropRect::kHasRight_CropEdge;
570    }
571    if (hasHeight()) {
572        rect.setHeight(boundaries.height());
573        flags |= SkImageFilter::CropRect::kHasBottom_CropEdge;
574    }
575    rect.scale(filter()->absoluteTransform().a(), filter()->absoluteTransform().d());
576    return SkImageFilter::CropRect(rect, flags);
577}
578
579static int getImageFilterIndex(ColorSpace colorSpace, bool requiresPMColorValidation)
580{
581    // Map the (colorspace, bool) tuple to an integer index as follows:
582    // 0 == linear colorspace, no PM validation
583    // 1 == device colorspace, no PM validation
584    // 2 == linear colorspace, PM validation
585    // 3 == device colorspace, PM validation
586    return (colorSpace == ColorSpaceLinearRGB ? 0x1 : 0x0) | (requiresPMColorValidation ? 0x2 : 0x0);
587}
588
589SkImageFilter* FilterEffect::getImageFilter(ColorSpace colorSpace, bool requiresPMColorValidation) const
590{
591    int index = getImageFilterIndex(colorSpace, requiresPMColorValidation);
592    return m_imageFilters[index].get();
593}
594
595void FilterEffect::setImageFilter(ColorSpace colorSpace, bool requiresPMColorValidation, PassRefPtr<SkImageFilter> imageFilter)
596{
597    int index = getImageFilterIndex(colorSpace, requiresPMColorValidation);
598    m_imageFilters[index] = imageFilter;
599}
600
601} // namespace blink
602