2 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "platform/graphics/filters/SkiaImageFilterBuilder.h"
29 #include "SkBlurImageFilter.h"
30 #include "SkColorFilterImageFilter.h"
31 #include "SkColorMatrixFilter.h"
32 #include "SkDropShadowImageFilter.h"
33 #include "SkResizeImageFilter.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 "public/platform/WebPoint.h"
43 PassRefPtr<SkImageFilter> createMatrixImageFilter(SkScalar matrix[20], SkImageFilter* input)
45 RefPtr<SkColorFilter> colorFilter(adoptRef(new SkColorMatrixFilter(matrix)));
46 return adoptRef(SkColorFilterImageFilter::Create(colorFilter.get(), input));
53 SkiaImageFilterBuilder::SkiaImageFilterBuilder()
58 SkiaImageFilterBuilder::SkiaImageFilterBuilder(GraphicsContext* context)
63 SkiaImageFilterBuilder::~SkiaImageFilterBuilder()
67 PassRefPtr<SkImageFilter> SkiaImageFilterBuilder::build(FilterEffect* effect, ColorSpace colorSpace)
72 FilterColorSpacePair key(effect, colorSpace);
73 FilterBuilderHashMap::iterator it = m_map.find(key);
74 if (it != m_map.end()) {
77 // Note that we may still need the color transform even if the filter is null
78 RefPtr<SkImageFilter> origFilter = effect->createImageFilter(this);
79 RefPtr<SkImageFilter> filter = transformColorSpace(origFilter.get(), effect->operatingColorSpace(), colorSpace);
80 m_map.set(key, filter);
81 return filter.release();
85 PassRefPtr<SkImageFilter> SkiaImageFilterBuilder::transformColorSpace(
86 SkImageFilter* input, ColorSpace srcColorSpace, ColorSpace dstColorSpace) {
88 RefPtr<SkColorFilter> colorFilter = ImageBuffer::createColorSpaceFilter(srcColorSpace, dstColorSpace);
92 return adoptRef(SkColorFilterImageFilter::Create(colorFilter.get(), input));
95 bool SkiaImageFilterBuilder::buildFilterOperations(const FilterOperations& operations, blink::WebFilterOperations* filters)
100 ColorSpace currentColorSpace = ColorSpaceDeviceRGB;
102 RefPtr<SkImageFilter> noopFilter;
104 memset(matrix, 0, 20 * sizeof(SkScalar));
105 matrix[0] = matrix[6] = matrix[12] = matrix[18] = 1.f;
106 noopFilter = createMatrixImageFilter(matrix, 0);
108 for (size_t i = 0; i < operations.size(); ++i) {
109 const FilterOperation& op = *operations.at(i);
111 case FilterOperation::REFERENCE: {
112 RefPtr<SkImageFilter> filter;
113 ReferenceFilter* referenceFilter = toReferenceFilterOperation(op).filter();
114 if (referenceFilter && referenceFilter->lastEffect()) {
115 FilterEffect* filterEffect = referenceFilter->lastEffect();
116 // Link SourceGraphic to a noop filter that serves as a placholder for
117 // the previous filter in the chain. We don't know what color space the
118 // interior nodes will request, so we have to populate the map with both
119 // options. (Only one of these will actually have a color transform on it.)
120 FilterColorSpacePair deviceKey(referenceFilter->sourceGraphic(), ColorSpaceDeviceRGB);
121 FilterColorSpacePair linearKey(referenceFilter->sourceGraphic(), ColorSpaceLinearRGB);
122 m_map.set(deviceKey, transformColorSpace(noopFilter.get(), currentColorSpace, ColorSpaceDeviceRGB));
123 m_map.set(linearKey, transformColorSpace(noopFilter.get(), currentColorSpace, ColorSpaceLinearRGB));
125 currentColorSpace = filterEffect->operatingColorSpace();
126 filter = SkiaImageFilterBuilder::build(filterEffect, currentColorSpace);
127 // We might have no reference to the SourceGraphic's Skia filter now, so make
128 // sure we don't keep it in the map anymore.
129 m_map.remove(deviceKey);
130 m_map.remove(linearKey);
131 filters->appendReferenceFilter(filter.get());
135 case FilterOperation::GRAYSCALE:
136 case FilterOperation::SEPIA:
137 case FilterOperation::SATURATE:
138 case FilterOperation::HUE_ROTATE: {
139 float amount = toBasicColorMatrixFilterOperation(op).amount();
141 case FilterOperation::GRAYSCALE:
142 filters->appendGrayscaleFilter(amount);
144 case FilterOperation::SEPIA:
145 filters->appendSepiaFilter(amount);
147 case FilterOperation::SATURATE:
148 filters->appendSaturateFilter(amount);
150 case FilterOperation::HUE_ROTATE:
151 filters->appendHueRotateFilter(amount);
154 ASSERT_NOT_REACHED();
158 case FilterOperation::INVERT:
159 case FilterOperation::OPACITY:
160 case FilterOperation::BRIGHTNESS:
161 case FilterOperation::CONTRAST: {
162 float amount = toBasicComponentTransferFilterOperation(op).amount();
164 case FilterOperation::INVERT:
165 filters->appendInvertFilter(amount);
167 case FilterOperation::OPACITY:
168 filters->appendOpacityFilter(amount);
170 case FilterOperation::BRIGHTNESS:
171 filters->appendBrightnessFilter(amount);
173 case FilterOperation::CONTRAST:
174 filters->appendContrastFilter(amount);
177 ASSERT_NOT_REACHED();
181 case FilterOperation::BLUR: {
182 float pixelRadius = toBlurFilterOperation(op).stdDeviation().getFloatValue();
183 filters->appendBlurFilter(pixelRadius);
186 case FilterOperation::DROP_SHADOW: {
187 const DropShadowFilterOperation& drop = toDropShadowFilterOperation(op);
188 filters->appendDropShadowFilter(blink::WebPoint(drop.x(), drop.y()), drop.stdDeviation(), drop.color().rgb());
191 case FilterOperation::VALIDATED_CUSTOM:
192 case FilterOperation::CUSTOM:
193 return false; // Not supported.
194 case FilterOperation::NONE:
198 if (currentColorSpace != ColorSpaceDeviceRGB) {
199 // Transform to device color space at the end of processing, if required
200 RefPtr<SkImageFilter> filter;
201 filter = transformColorSpace(noopFilter.get(), currentColorSpace, ColorSpaceDeviceRGB);
202 if (filter != noopFilter)
203 filters->appendReferenceFilter(filter.get());
208 PassRefPtr<SkImageFilter> SkiaImageFilterBuilder::buildResize(float scaleX, float scaleY, SkImageFilter* input)
210 return adoptRef(new SkResizeImageFilter(scaleX, scaleY, SkPaint::kHigh_FilterLevel, input));