Home | History | Annotate | Download | only in filters
      1 /*
      2  * Copyright (C) 2012 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *
      8  * 1.  Redistributions of source code must retain the above copyright
      9  *     notice, this list of conditions and the following disclaimer.
     10  * 2.  Redistributions in binary form must reproduce the above copyright
     11  *     notice, this list of conditions and the following disclaimer in the
     12  *     documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 #include "config.h"
     26 
     27 #include "platform/graphics/filters/SkiaImageFilterBuilder.h"
     28 
     29 #include "SkBlurImageFilter.h"
     30 #include "SkColorFilterImageFilter.h"
     31 #include "SkColorMatrixFilter.h"
     32 #include "SkDropShadowImageFilter.h"
     33 #include "SkTableColorFilter.h"
     34 #include "platform/graphics/ImageBuffer.h"
     35 #include "platform/graphics/filters/FilterEffect.h"
     36 #include "platform/graphics/filters/FilterOperations.h"
     37 #include "platform/graphics/filters/SourceGraphic.h"
     38 #include "public/platform/WebPoint.h"
     39 
     40 namespace {
     41 
     42 PassRefPtr<SkImageFilter> createMatrixImageFilter(SkScalar matrix[20], SkImageFilter* input)
     43 {
     44     RefPtr<SkColorFilter> colorFilter(adoptRef(new SkColorMatrixFilter(matrix)));
     45     return adoptRef(SkColorFilterImageFilter::Create(colorFilter.get(), input));
     46 }
     47 
     48 };
     49 
     50 namespace WebCore {
     51 
     52 SkiaImageFilterBuilder::SkiaImageFilterBuilder()
     53 {
     54 }
     55 
     56 SkiaImageFilterBuilder::~SkiaImageFilterBuilder()
     57 {
     58 }
     59 
     60 PassRefPtr<SkImageFilter> SkiaImageFilterBuilder::build(FilterEffect* effect, ColorSpace colorSpace)
     61 {
     62     if (!effect)
     63         return 0;
     64 
     65     FilterColorSpacePair key(effect, colorSpace);
     66     FilterBuilderHashMap::iterator it = m_map.find(key);
     67     if (it != m_map.end()) {
     68         return it->value;
     69     } else {
     70         // Note that we may still need the color transform even if the filter is null
     71         RefPtr<SkImageFilter> origFilter = effect->createImageFilter(this);
     72         RefPtr<SkImageFilter> filter = transformColorSpace(origFilter.get(), effect->operatingColorSpace(), colorSpace);
     73         m_map.set(key, filter);
     74         return filter.release();
     75     }
     76 }
     77 
     78 PassRefPtr<SkImageFilter> SkiaImageFilterBuilder::transformColorSpace(
     79     SkImageFilter* input, ColorSpace srcColorSpace, ColorSpace dstColorSpace) {
     80 
     81     RefPtr<SkColorFilter> colorFilter = ImageBuffer::createColorSpaceFilter(srcColorSpace, dstColorSpace);
     82     if (!colorFilter)
     83         return input;
     84 
     85     return adoptRef(SkColorFilterImageFilter::Create(colorFilter.get(), input));
     86 }
     87 
     88 bool SkiaImageFilterBuilder::buildFilterOperations(const FilterOperations& operations, blink::WebFilterOperations* filters)
     89 {
     90     if (!filters)
     91         return false;
     92 
     93     ColorSpace currentColorSpace = ColorSpaceDeviceRGB;
     94 
     95     RefPtr<SkImageFilter> noopFilter;
     96     SkScalar matrix[20];
     97     memset(matrix, 0, 20 * sizeof(SkScalar));
     98     matrix[0] = matrix[6] = matrix[12] = matrix[18] = 1.f;
     99     noopFilter = createMatrixImageFilter(matrix, 0);
    100 
    101     for (size_t i = 0; i < operations.size(); ++i) {
    102         const FilterOperation& op = *operations.at(i);
    103         switch (op.type()) {
    104         case FilterOperation::REFERENCE: {
    105             RefPtr<SkImageFilter> filter;
    106             ReferenceFilter* referenceFilter = toReferenceFilterOperation(op).filter();
    107             if (referenceFilter && referenceFilter->lastEffect()) {
    108                 FilterEffect* filterEffect = referenceFilter->lastEffect();
    109                 // Link SourceGraphic to a noop filter that serves as a placholder for
    110                 // the previous filter in the chain. We don't know what color space the
    111                 // interior nodes will request, so we have to populate the map with both
    112                 // options. (Only one of these will actually have a color transform on it.)
    113                 FilterColorSpacePair deviceKey(referenceFilter->sourceGraphic(), ColorSpaceDeviceRGB);
    114                 FilterColorSpacePair linearKey(referenceFilter->sourceGraphic(), ColorSpaceLinearRGB);
    115                 m_map.set(deviceKey, transformColorSpace(noopFilter.get(), currentColorSpace, ColorSpaceDeviceRGB));
    116                 m_map.set(linearKey, transformColorSpace(noopFilter.get(), currentColorSpace, ColorSpaceLinearRGB));
    117 
    118                 currentColorSpace = filterEffect->operatingColorSpace();
    119                 filter = SkiaImageFilterBuilder::build(filterEffect, currentColorSpace);
    120                 // We might have no reference to the SourceGraphic's Skia filter now, so make
    121                 // sure we don't keep it in the map anymore.
    122                 m_map.remove(deviceKey);
    123                 m_map.remove(linearKey);
    124                 filters->appendReferenceFilter(filter.get());
    125             }
    126             break;
    127         }
    128         case FilterOperation::GRAYSCALE:
    129         case FilterOperation::SEPIA:
    130         case FilterOperation::SATURATE:
    131         case FilterOperation::HUE_ROTATE: {
    132             float amount = toBasicColorMatrixFilterOperation(op).amount();
    133             switch (op.type()) {
    134             case FilterOperation::GRAYSCALE:
    135                 filters->appendGrayscaleFilter(amount);
    136                 break;
    137             case FilterOperation::SEPIA:
    138                 filters->appendSepiaFilter(amount);
    139                 break;
    140             case FilterOperation::SATURATE:
    141                 filters->appendSaturateFilter(amount);
    142                 break;
    143             case FilterOperation::HUE_ROTATE:
    144                 filters->appendHueRotateFilter(amount);
    145                 break;
    146             default:
    147                 ASSERT_NOT_REACHED();
    148             }
    149             break;
    150         }
    151         case FilterOperation::INVERT:
    152         case FilterOperation::OPACITY:
    153         case FilterOperation::BRIGHTNESS:
    154         case FilterOperation::CONTRAST: {
    155             float amount = toBasicComponentTransferFilterOperation(op).amount();
    156             switch (op.type()) {
    157             case FilterOperation::INVERT:
    158                 filters->appendInvertFilter(amount);
    159                 break;
    160             case FilterOperation::OPACITY:
    161                 filters->appendOpacityFilter(amount);
    162                 break;
    163             case FilterOperation::BRIGHTNESS:
    164                 filters->appendBrightnessFilter(amount);
    165                 break;
    166             case FilterOperation::CONTRAST:
    167                 filters->appendContrastFilter(amount);
    168                 break;
    169             default:
    170                 ASSERT_NOT_REACHED();
    171             }
    172             break;
    173         }
    174         case FilterOperation::BLUR: {
    175             float pixelRadius = toBlurFilterOperation(op).stdDeviation().getFloatValue();
    176             filters->appendBlurFilter(pixelRadius);
    177             break;
    178         }
    179         case FilterOperation::DROP_SHADOW: {
    180             const DropShadowFilterOperation& drop = toDropShadowFilterOperation(op);
    181             filters->appendDropShadowFilter(blink::WebPoint(drop.x(), drop.y()), drop.stdDeviation(), drop.color().rgb());
    182             break;
    183         }
    184         case FilterOperation::VALIDATED_CUSTOM:
    185         case FilterOperation::CUSTOM:
    186             return false; // Not supported.
    187         case FilterOperation::NONE:
    188             break;
    189         }
    190     }
    191     if (currentColorSpace != ColorSpaceDeviceRGB) {
    192         // Transform to device color space at the end of processing, if required
    193         RefPtr<SkImageFilter> filter;
    194         filter = transformColorSpace(noopFilter.get(), currentColorSpace, ColorSpaceDeviceRGB);
    195         if (filter != noopFilter)
    196             filters->appendReferenceFilter(filter.get());
    197     }
    198     return true;
    199 }
    200 
    201 };
    202