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 "SkMatrixImageFilter.h"
     34 #include "SkTableColorFilter.h"
     35 #include "platform/graphics/ImageBuffer.h"
     36 #include "platform/graphics/filters/FilterEffect.h"
     37 #include "platform/graphics/filters/FilterOperations.h"
     38 #include "platform/graphics/filters/SourceGraphic.h"
     39 #include "platform/graphics/skia/SkiaUtils.h"
     40 #include "public/platform/WebPoint.h"
     41 
     42 namespace blink {
     43 
     44 SkiaImageFilterBuilder::SkiaImageFilterBuilder()
     45     : m_context(0)
     46     , m_sourceGraphic(0)
     47 {
     48 }
     49 
     50 SkiaImageFilterBuilder::SkiaImageFilterBuilder(GraphicsContext* context)
     51     : m_context(context)
     52     , m_sourceGraphic(0)
     53 {
     54 }
     55 
     56 SkiaImageFilterBuilder::~SkiaImageFilterBuilder()
     57 {
     58 }
     59 
     60 PassRefPtr<SkImageFilter> SkiaImageFilterBuilder::build(FilterEffect* effect, ColorSpace colorSpace, bool destinationRequiresValidPreMultipliedPixels)
     61 {
     62     if (!effect)
     63         return nullptr;
     64 
     65     bool requiresPMColorValidation = effect->mayProduceInvalidPreMultipliedPixels() && destinationRequiresValidPreMultipliedPixels;
     66 
     67     if (SkImageFilter* filter = effect->getImageFilter(colorSpace, requiresPMColorValidation))
     68         return filter;
     69 
     70     // Note that we may still need the color transform even if the filter is null
     71     RefPtr<SkImageFilter> origFilter = requiresPMColorValidation ? effect->createImageFilter(this) : effect->createImageFilterWithoutValidation(this);
     72     RefPtr<SkImageFilter> filter = transformColorSpace(origFilter.get(), effect->operatingColorSpace(), colorSpace);
     73     effect->setImageFilter(colorSpace, requiresPMColorValidation, filter.get());
     74     if (filter.get() != origFilter.get())
     75         effect->setImageFilter(effect->operatingColorSpace(), requiresPMColorValidation, origFilter.get());
     76     return filter.release();
     77 }
     78 
     79 PassRefPtr<SkImageFilter> SkiaImageFilterBuilder::transformColorSpace(
     80     SkImageFilter* input, ColorSpace srcColorSpace, ColorSpace dstColorSpace) {
     81 
     82     RefPtr<SkColorFilter> colorFilter = ImageBuffer::createColorSpaceFilter(srcColorSpace, dstColorSpace);
     83     if (!colorFilter)
     84         return input;
     85 
     86     return adoptRef(SkColorFilterImageFilter::Create(colorFilter.get(), input));
     87 }
     88 
     89 void SkiaImageFilterBuilder::buildFilterOperations(const FilterOperations& operations, WebFilterOperations* filters)
     90 {
     91     ColorSpace currentColorSpace = ColorSpaceDeviceRGB;
     92     SkImageFilter* const nullFilter = 0;
     93 
     94     for (size_t i = 0; i < operations.size(); ++i) {
     95         const FilterOperation& op = *operations.at(i);
     96         switch (op.type()) {
     97         case FilterOperation::REFERENCE: {
     98             RefPtr<SkImageFilter> filter;
     99             ReferenceFilter* referenceFilter = toReferenceFilterOperation(op).filter();
    100             if (referenceFilter && referenceFilter->lastEffect()) {
    101                 FilterEffect* filterEffect = referenceFilter->lastEffect();
    102                 // Prepopulate SourceGraphic with two image filters: one with a null image
    103                 // filter, and the other with a colorspace conversion filter.
    104                 // We don't know what color space the interior nodes will request, so we have to
    105                 // initialize SourceGraphic with both options.
    106                 // Since we know SourceGraphic is always PM-valid, we also use
    107                 // these for the PM-validated options.
    108                 RefPtr<SkImageFilter> deviceFilter = transformColorSpace(nullFilter, currentColorSpace, ColorSpaceDeviceRGB);
    109                 RefPtr<SkImageFilter> linearFilter = transformColorSpace(nullFilter, currentColorSpace, ColorSpaceLinearRGB);
    110                 FilterEffect* sourceGraphic = referenceFilter->sourceGraphic();
    111                 sourceGraphic->setImageFilter(ColorSpaceDeviceRGB, false, deviceFilter.get());
    112                 sourceGraphic->setImageFilter(ColorSpaceLinearRGB, false, linearFilter.get());
    113                 sourceGraphic->setImageFilter(ColorSpaceDeviceRGB, true, deviceFilter.get());
    114                 sourceGraphic->setImageFilter(ColorSpaceLinearRGB, true, linearFilter.get());
    115 
    116                 currentColorSpace = filterEffect->operatingColorSpace();
    117                 filter = SkiaImageFilterBuilder::build(filterEffect, currentColorSpace);
    118                 filters->appendReferenceFilter(filter.get());
    119             }
    120             break;
    121         }
    122         case FilterOperation::GRAYSCALE:
    123         case FilterOperation::SEPIA:
    124         case FilterOperation::SATURATE:
    125         case FilterOperation::HUE_ROTATE: {
    126             float amount = toBasicColorMatrixFilterOperation(op).amount();
    127             switch (op.type()) {
    128             case FilterOperation::GRAYSCALE:
    129                 filters->appendGrayscaleFilter(amount);
    130                 break;
    131             case FilterOperation::SEPIA:
    132                 filters->appendSepiaFilter(amount);
    133                 break;
    134             case FilterOperation::SATURATE:
    135                 filters->appendSaturateFilter(amount);
    136                 break;
    137             case FilterOperation::HUE_ROTATE:
    138                 filters->appendHueRotateFilter(amount);
    139                 break;
    140             default:
    141                 ASSERT_NOT_REACHED();
    142             }
    143             break;
    144         }
    145         case FilterOperation::INVERT:
    146         case FilterOperation::OPACITY:
    147         case FilterOperation::BRIGHTNESS:
    148         case FilterOperation::CONTRAST: {
    149             float amount = toBasicComponentTransferFilterOperation(op).amount();
    150             switch (op.type()) {
    151             case FilterOperation::INVERT:
    152                 filters->appendInvertFilter(amount);
    153                 break;
    154             case FilterOperation::OPACITY:
    155                 filters->appendOpacityFilter(amount);
    156                 break;
    157             case FilterOperation::BRIGHTNESS:
    158                 filters->appendBrightnessFilter(amount);
    159                 break;
    160             case FilterOperation::CONTRAST:
    161                 filters->appendContrastFilter(amount);
    162                 break;
    163             default:
    164                 ASSERT_NOT_REACHED();
    165             }
    166             break;
    167         }
    168         case FilterOperation::BLUR: {
    169             float pixelRadius = toBlurFilterOperation(op).stdDeviation().getFloatValue();
    170             filters->appendBlurFilter(pixelRadius);
    171             break;
    172         }
    173         case FilterOperation::DROP_SHADOW: {
    174             const DropShadowFilterOperation& drop = toDropShadowFilterOperation(op);
    175             filters->appendDropShadowFilter(WebPoint(drop.x(), drop.y()), drop.stdDeviation(), drop.color().rgb());
    176             break;
    177         }
    178         case FilterOperation::NONE:
    179             break;
    180         }
    181     }
    182     if (currentColorSpace != ColorSpaceDeviceRGB) {
    183         // Transform to device color space at the end of processing, if required
    184         RefPtr<SkImageFilter> filter = transformColorSpace(nullFilter, currentColorSpace, ColorSpaceDeviceRGB);
    185         filters->appendReferenceFilter(filter.get());
    186     }
    187 }
    188 
    189 PassRefPtr<SkImageFilter> SkiaImageFilterBuilder::buildTransform(const AffineTransform& transform, SkImageFilter* input)
    190 {
    191     return adoptRef(SkMatrixImageFilter::Create(affineTransformToSkMatrix(transform), SkPaint::kHigh_FilterLevel, input));
    192 }
    193 
    194 } // namespace blink
    195