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 42namespace blink { 43 44SkiaImageFilterBuilder::SkiaImageFilterBuilder() 45 : m_context(0) 46 , m_sourceGraphic(0) 47{ 48} 49 50SkiaImageFilterBuilder::SkiaImageFilterBuilder(GraphicsContext* context) 51 : m_context(context) 52 , m_sourceGraphic(0) 53{ 54} 55 56SkiaImageFilterBuilder::~SkiaImageFilterBuilder() 57{ 58} 59 60PassRefPtr<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 79PassRefPtr<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 89void 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 189PassRefPtr<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