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