Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / graphics / filters / SkiaImageFilterBuilder.cpp
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 "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"
40
41 namespace {
42
43 PassRefPtr<SkImageFilter> createMatrixImageFilter(SkScalar matrix[20], SkImageFilter* input)
44 {
45     RefPtr<SkColorFilter> colorFilter(adoptRef(new SkColorMatrixFilter(matrix)));
46     return adoptRef(SkColorFilterImageFilter::Create(colorFilter.get(), input));
47 }
48
49 };
50
51 namespace WebCore {
52
53 SkiaImageFilterBuilder::SkiaImageFilterBuilder()
54     : m_context(0)
55 {
56 }
57
58 SkiaImageFilterBuilder::SkiaImageFilterBuilder(GraphicsContext* context)
59     : m_context(context)
60 {
61 }
62
63 SkiaImageFilterBuilder::~SkiaImageFilterBuilder()
64 {
65 }
66
67 PassRefPtr<SkImageFilter> SkiaImageFilterBuilder::build(FilterEffect* effect, ColorSpace colorSpace)
68 {
69     if (!effect)
70         return 0;
71
72     FilterColorSpacePair key(effect, colorSpace);
73     FilterBuilderHashMap::iterator it = m_map.find(key);
74     if (it != m_map.end()) {
75         return it->value;
76     } else {
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();
82     }
83 }
84
85 PassRefPtr<SkImageFilter> SkiaImageFilterBuilder::transformColorSpace(
86     SkImageFilter* input, ColorSpace srcColorSpace, ColorSpace dstColorSpace) {
87
88     RefPtr<SkColorFilter> colorFilter = ImageBuffer::createColorSpaceFilter(srcColorSpace, dstColorSpace);
89     if (!colorFilter)
90         return input;
91
92     return adoptRef(SkColorFilterImageFilter::Create(colorFilter.get(), input));
93 }
94
95 bool SkiaImageFilterBuilder::buildFilterOperations(const FilterOperations& operations, blink::WebFilterOperations* filters)
96 {
97     if (!filters)
98         return false;
99
100     ColorSpace currentColorSpace = ColorSpaceDeviceRGB;
101
102     RefPtr<SkImageFilter> noopFilter;
103     SkScalar matrix[20];
104     memset(matrix, 0, 20 * sizeof(SkScalar));
105     matrix[0] = matrix[6] = matrix[12] = matrix[18] = 1.f;
106     noopFilter = createMatrixImageFilter(matrix, 0);
107
108     for (size_t i = 0; i < operations.size(); ++i) {
109         const FilterOperation& op = *operations.at(i);
110         switch (op.type()) {
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));
124
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());
132             }
133             break;
134         }
135         case FilterOperation::GRAYSCALE:
136         case FilterOperation::SEPIA:
137         case FilterOperation::SATURATE:
138         case FilterOperation::HUE_ROTATE: {
139             float amount = toBasicColorMatrixFilterOperation(op).amount();
140             switch (op.type()) {
141             case FilterOperation::GRAYSCALE:
142                 filters->appendGrayscaleFilter(amount);
143                 break;
144             case FilterOperation::SEPIA:
145                 filters->appendSepiaFilter(amount);
146                 break;
147             case FilterOperation::SATURATE:
148                 filters->appendSaturateFilter(amount);
149                 break;
150             case FilterOperation::HUE_ROTATE:
151                 filters->appendHueRotateFilter(amount);
152                 break;
153             default:
154                 ASSERT_NOT_REACHED();
155             }
156             break;
157         }
158         case FilterOperation::INVERT:
159         case FilterOperation::OPACITY:
160         case FilterOperation::BRIGHTNESS:
161         case FilterOperation::CONTRAST: {
162             float amount = toBasicComponentTransferFilterOperation(op).amount();
163             switch (op.type()) {
164             case FilterOperation::INVERT:
165                 filters->appendInvertFilter(amount);
166                 break;
167             case FilterOperation::OPACITY:
168                 filters->appendOpacityFilter(amount);
169                 break;
170             case FilterOperation::BRIGHTNESS:
171                 filters->appendBrightnessFilter(amount);
172                 break;
173             case FilterOperation::CONTRAST:
174                 filters->appendContrastFilter(amount);
175                 break;
176             default:
177                 ASSERT_NOT_REACHED();
178             }
179             break;
180         }
181         case FilterOperation::BLUR: {
182             float pixelRadius = toBlurFilterOperation(op).stdDeviation().getFloatValue();
183             filters->appendBlurFilter(pixelRadius);
184             break;
185         }
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());
189             break;
190         }
191         case FilterOperation::VALIDATED_CUSTOM:
192         case FilterOperation::CUSTOM:
193             return false; // Not supported.
194         case FilterOperation::NONE:
195             break;
196         }
197     }
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());
204     }
205     return true;
206 }
207
208 PassRefPtr<SkImageFilter> SkiaImageFilterBuilder::buildResize(float scaleX, float scaleY, SkImageFilter* input)
209 {
210     return adoptRef(new SkResizeImageFilter(scaleX, scaleY, SkPaint::kHigh_FilterLevel, input));
211 }
212
213 };