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