- add sources.
[platform/framework/web/crosswalk.git] / src / cc / output / render_surface_filters.cc
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "cc/output/render_surface_filters.h"
6
7 #include <algorithm>
8
9 #include "base/logging.h"
10 #include "cc/output/filter_operation.h"
11 #include "cc/output/filter_operations.h"
12 #include "skia/ext/refptr.h"
13 #include "third_party/skia/include/core/SkCanvas.h"
14 #include "third_party/skia/include/core/SkFlattenableBuffers.h"
15 #include "third_party/skia/include/core/SkImageFilter.h"
16 #include "third_party/skia/include/effects/SkBlurImageFilter.h"
17 #include "third_party/skia/include/effects/SkColorFilterImageFilter.h"
18 #include "third_party/skia/include/effects/SkColorMatrixFilter.h"
19 #include "third_party/skia/include/effects/SkComposeImageFilter.h"
20 #include "third_party/skia/include/effects/SkDropShadowImageFilter.h"
21 #include "third_party/skia/include/effects/SkMagnifierImageFilter.h"
22 #include "third_party/skia/include/gpu/SkGpuDevice.h"
23 #include "third_party/skia/include/gpu/SkGrPixelRef.h"
24 #include "ui/gfx/size_f.h"
25
26 namespace cc {
27
28 namespace {
29
30 void GetBrightnessMatrix(float amount, SkScalar matrix[20]) {
31   // Spec implementation
32   // (http://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#brightnessEquivalent)
33   // <feFunc[R|G|B] type="linear" slope="[amount]">
34   memset(matrix, 0, 20 * sizeof(SkScalar));
35   matrix[0] = matrix[6] = matrix[12] = amount;
36   matrix[18] = 1.f;
37 }
38
39 void GetSaturatingBrightnessMatrix(float amount, SkScalar matrix[20]) {
40   // Legacy implementation used by internal clients.
41   // <feFunc[R|G|B] type="linear" intercept="[amount]"/>
42   memset(matrix, 0, 20 * sizeof(SkScalar));
43   matrix[0] = matrix[6] = matrix[12] = matrix[18] = 1.f;
44   matrix[4] = matrix[9] = matrix[14] = amount * 255.f;
45 }
46
47 void GetContrastMatrix(float amount, SkScalar matrix[20]) {
48   memset(matrix, 0, 20 * sizeof(SkScalar));
49   matrix[0] = matrix[6] = matrix[12] = amount;
50   matrix[4] = matrix[9] = matrix[14] = (-0.5f * amount + 0.5f) * 255.f;
51   matrix[18] = 1.f;
52 }
53
54 void GetSaturateMatrix(float amount, SkScalar matrix[20]) {
55   // Note, these values are computed to ensure MatrixNeedsClamping is false
56   // for amount in [0..1]
57   matrix[0] = 0.213f + 0.787f * amount;
58   matrix[1] = 0.715f - 0.715f * amount;
59   matrix[2] = 1.f - (matrix[0] + matrix[1]);
60   matrix[3] = matrix[4] = 0.f;
61   matrix[5] = 0.213f - 0.213f * amount;
62   matrix[6] = 0.715f + 0.285f * amount;
63   matrix[7] = 1.f - (matrix[5] + matrix[6]);
64   matrix[8] = matrix[9] = 0.f;
65   matrix[10] = 0.213f - 0.213f * amount;
66   matrix[11] = 0.715f - 0.715f * amount;
67   matrix[12] = 1.f - (matrix[10] + matrix[11]);
68   matrix[13] = matrix[14] = 0.f;
69   matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0.f;
70   matrix[18] = 1.f;
71 }
72
73 void GetHueRotateMatrix(float hue, SkScalar matrix[20]) {
74   const float kPi = 3.1415926535897932384626433832795f;
75
76   float cos_hue = cosf(hue * kPi / 180.f);
77   float sin_hue = sinf(hue * kPi / 180.f);
78   matrix[0] = 0.213f + cos_hue * 0.787f - sin_hue * 0.213f;
79   matrix[1] = 0.715f - cos_hue * 0.715f - sin_hue * 0.715f;
80   matrix[2] = 0.072f - cos_hue * 0.072f + sin_hue * 0.928f;
81   matrix[3] = matrix[4] = 0.f;
82   matrix[5] = 0.213f - cos_hue * 0.213f + sin_hue * 0.143f;
83   matrix[6] = 0.715f + cos_hue * 0.285f + sin_hue * 0.140f;
84   matrix[7] = 0.072f - cos_hue * 0.072f - sin_hue * 0.283f;
85   matrix[8] = matrix[9] = 0.f;
86   matrix[10] = 0.213f - cos_hue * 0.213f - sin_hue * 0.787f;
87   matrix[11] = 0.715f - cos_hue * 0.715f + sin_hue * 0.715f;
88   matrix[12] = 0.072f + cos_hue * 0.928f + sin_hue * 0.072f;
89   matrix[13] = matrix[14] = 0.f;
90   matrix[15] = matrix[16] = matrix[17] = 0.f;
91   matrix[18] = 1.f;
92   matrix[19] = 0.f;
93 }
94
95 void GetInvertMatrix(float amount, SkScalar matrix[20]) {
96   memset(matrix, 0, 20 * sizeof(SkScalar));
97   matrix[0] = matrix[6] = matrix[12] = 1.f - 2.f * amount;
98   matrix[4] = matrix[9] = matrix[14] = amount * 255.f;
99   matrix[18] = 1.f;
100 }
101
102 void GetOpacityMatrix(float amount, SkScalar matrix[20]) {
103   memset(matrix, 0, 20 * sizeof(SkScalar));
104   matrix[0] = matrix[6] = matrix[12] = 1.f;
105   matrix[18] = amount;
106 }
107
108 void GetGrayscaleMatrix(float amount, SkScalar matrix[20]) {
109   // Note, these values are computed to ensure MatrixNeedsClamping is false
110   // for amount in [0..1]
111   matrix[0] = 0.2126f + 0.7874f * amount;
112   matrix[1] = 0.7152f - 0.7152f * amount;
113   matrix[2] = 1.f - (matrix[0] + matrix[1]);
114   matrix[3] = matrix[4] = 0.f;
115
116   matrix[5] = 0.2126f - 0.2126f * amount;
117   matrix[6] = 0.7152f + 0.2848f * amount;
118   matrix[7] = 1.f - (matrix[5] + matrix[6]);
119   matrix[8] = matrix[9] = 0.f;
120
121   matrix[10] = 0.2126f - 0.2126f * amount;
122   matrix[11] = 0.7152f - 0.7152f * amount;
123   matrix[12] = 1.f - (matrix[10] + matrix[11]);
124   matrix[13] = matrix[14] = 0.f;
125
126   matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0.f;
127   matrix[18] = 1.f;
128 }
129
130 void GetSepiaMatrix(float amount, SkScalar matrix[20]) {
131   matrix[0] = 0.393f + 0.607f * amount;
132   matrix[1] = 0.769f - 0.769f * amount;
133   matrix[2] = 0.189f - 0.189f * amount;
134   matrix[3] = matrix[4] = 0.f;
135
136   matrix[5] = 0.349f - 0.349f * amount;
137   matrix[6] = 0.686f + 0.314f * amount;
138   matrix[7] = 0.168f - 0.168f * amount;
139   matrix[8] = matrix[9] = 0.f;
140
141   matrix[10] = 0.272f - 0.272f * amount;
142   matrix[11] = 0.534f - 0.534f * amount;
143   matrix[12] = 0.131f + 0.869f * amount;
144   matrix[13] = matrix[14] = 0.f;
145
146   matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0.f;
147   matrix[18] = 1.f;
148 }
149
150 skia::RefPtr<SkImageFilter> CreateMatrixImageFilter(
151     const SkScalar matrix[20],
152     const skia::RefPtr<SkImageFilter>& input) {
153   skia::RefPtr<SkColorFilter> color_filter =
154       skia::AdoptRef(new SkColorMatrixFilter(matrix));
155   return skia::AdoptRef(
156       SkColorFilterImageFilter::Create(color_filter.get(), input.get()));
157 }
158
159 }  // namespace
160
161 skia::RefPtr<SkImageFilter> RenderSurfaceFilters::BuildImageFilter(
162     const FilterOperations& filters,
163     gfx::SizeF size) {
164   skia::RefPtr<SkImageFilter> image_filter;
165   SkScalar matrix[20];
166   for (size_t i = 0; i < filters.size(); ++i) {
167     const FilterOperation& op = filters.at(i);
168     switch (op.type()) {
169       case FilterOperation::GRAYSCALE:
170         GetGrayscaleMatrix(1.f - op.amount(), matrix);
171         image_filter = CreateMatrixImageFilter(matrix, image_filter);
172         break;
173       case FilterOperation::SEPIA:
174         GetSepiaMatrix(1.f - op.amount(), matrix);
175         image_filter = CreateMatrixImageFilter(matrix, image_filter);
176         break;
177       case FilterOperation::SATURATE:
178         GetSaturateMatrix(op.amount(), matrix);
179         image_filter = CreateMatrixImageFilter(matrix, image_filter);
180         break;
181       case FilterOperation::HUE_ROTATE:
182         GetHueRotateMatrix(op.amount(), matrix);
183         image_filter = CreateMatrixImageFilter(matrix, image_filter);
184         break;
185       case FilterOperation::INVERT:
186         GetInvertMatrix(op.amount(), matrix);
187         image_filter = CreateMatrixImageFilter(matrix, image_filter);
188         break;
189       case FilterOperation::OPACITY:
190         GetOpacityMatrix(op.amount(), matrix);
191         image_filter = CreateMatrixImageFilter(matrix, image_filter);
192         break;
193       case FilterOperation::BRIGHTNESS:
194         GetBrightnessMatrix(op.amount(), matrix);
195         image_filter = CreateMatrixImageFilter(matrix, image_filter);
196         break;
197       case FilterOperation::CONTRAST:
198         GetContrastMatrix(op.amount(), matrix);
199         image_filter = CreateMatrixImageFilter(matrix, image_filter);
200         break;
201       case FilterOperation::BLUR:
202         image_filter = skia::AdoptRef(new SkBlurImageFilter(
203             op.amount(), op.amount(), image_filter.get()));
204         break;
205       case FilterOperation::DROP_SHADOW:
206         image_filter = skia::AdoptRef(new SkDropShadowImageFilter(
207             SkIntToScalar(op.drop_shadow_offset().x()),
208             SkIntToScalar(op.drop_shadow_offset().y()),
209             SkIntToScalar(op.amount()),
210             op.drop_shadow_color(),
211             image_filter.get()));
212         break;
213       case FilterOperation::COLOR_MATRIX:
214         image_filter = CreateMatrixImageFilter(op.matrix(), image_filter);
215         break;
216       case FilterOperation::ZOOM: {
217         skia::RefPtr<SkImageFilter> zoom_filter = skia::AdoptRef(
218             new SkMagnifierImageFilter(
219                 SkRect::MakeXYWH(
220                     (size.width() - (size.width() / op.amount())) / 2.f,
221                     (size.height() - (size.height() / op.amount())) / 2.f,
222                     size.width() / op.amount(),
223                     size.height() / op.amount()),
224                 op.zoom_inset()));
225         if (image_filter.get()) {
226           // TODO(ajuma): When there's a 1-input version of
227           // SkMagnifierImageFilter, use that to handle the input filter
228           // instead of using an SkComposeImageFilter.
229           image_filter = skia::AdoptRef(new SkComposeImageFilter(
230               zoom_filter.get(), image_filter.get()));
231         } else {
232           image_filter = zoom_filter;
233         }
234         break;
235       }
236       case FilterOperation::SATURATING_BRIGHTNESS:
237         GetSaturatingBrightnessMatrix(op.amount(), matrix);
238         image_filter = CreateMatrixImageFilter(matrix, image_filter);
239         break;
240       case FilterOperation::REFERENCE: {
241         if (!op.image_filter())
242           break;
243
244         skia::RefPtr<SkColorFilter> cf;
245
246         {
247           SkColorFilter* colorfilter_rawptr = NULL;
248           op.image_filter()->asColorFilter(&colorfilter_rawptr);
249           cf = skia::AdoptRef(colorfilter_rawptr);
250         }
251
252         if (cf && cf->asColorMatrix(matrix) &&
253             !op.image_filter()->getInput(0)) {
254           image_filter = CreateMatrixImageFilter(matrix, image_filter);
255         } else if (image_filter) {
256           image_filter = skia::AdoptRef(new SkComposeImageFilter(
257               op.image_filter().get(), image_filter.get()));
258         } else {
259           image_filter = op.image_filter();
260         }
261         break;
262       }
263     }
264   }
265   return image_filter;
266 }
267
268 }  // namespace cc