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