b087d4b8344f57e054162a25395ded57f70ec39d
[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 "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 "public/platform/WebPoint.h"
40
41 namespace WebCore {
42
43 SkiaImageFilterBuilder::SkiaImageFilterBuilder()
44     : m_context(0)
45 {
46 }
47
48 SkiaImageFilterBuilder::SkiaImageFilterBuilder(GraphicsContext* context)
49     : m_context(context)
50 {
51 }
52
53 SkiaImageFilterBuilder::~SkiaImageFilterBuilder()
54 {
55 }
56
57 PassRefPtr<SkImageFilter> SkiaImageFilterBuilder::build(FilterEffect* effect, ColorSpace colorSpace, bool destinationRequiresValidPreMultipliedPixels)
58 {
59     if (!effect)
60         return nullptr;
61
62     bool requiresPMColorValidation = effect->mayProduceInvalidPreMultipliedPixels() && destinationRequiresValidPreMultipliedPixels;
63
64     if (SkImageFilter* filter = effect->getImageFilter(colorSpace, requiresPMColorValidation))
65         return filter;
66
67     // Note that we may still need the color transform even if the filter is null
68     RefPtr<SkImageFilter> origFilter = requiresPMColorValidation ? effect->createImageFilter(this) : effect->createImageFilterWithoutValidation(this);
69     RefPtr<SkImageFilter> filter = transformColorSpace(origFilter.get(), effect->operatingColorSpace(), colorSpace);
70     effect->setImageFilter(colorSpace, requiresPMColorValidation, filter.get());
71     if (filter.get() != origFilter.get())
72         effect->setImageFilter(effect->operatingColorSpace(), requiresPMColorValidation, origFilter.get());
73     return filter.release();
74 }
75
76 PassRefPtr<SkImageFilter> SkiaImageFilterBuilder::transformColorSpace(
77     SkImageFilter* input, ColorSpace srcColorSpace, ColorSpace dstColorSpace) {
78
79     RefPtr<SkColorFilter> colorFilter = ImageBuffer::createColorSpaceFilter(srcColorSpace, dstColorSpace);
80     if (!colorFilter)
81         return input;
82
83     return adoptRef(SkColorFilterImageFilter::Create(colorFilter.get(), input));
84 }
85
86 bool SkiaImageFilterBuilder::buildFilterOperations(const FilterOperations& operations, blink::WebFilterOperations* filters)
87 {
88     if (!filters)
89         return false;
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(blink::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     return true;
188 }
189
190 PassRefPtr<SkImageFilter> SkiaImageFilterBuilder::buildTransform(const AffineTransform& transform, SkImageFilter* input)
191 {
192     return adoptRef(SkMatrixImageFilter::Create(affineTransformToSkMatrix(transform), SkPaint::kHigh_FilterLevel, input));
193 }
194
195 };