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