Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(285)

Side by Side Diff: cc/render_surface_filters.cc

Issue 12912006: Part 4 of cc/ directory shuffles: output (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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/render_surface_filters.h"
6
7 #include "base/logging.h"
8 #include "skia/ext/refptr.h"
9 #include "third_party/WebKit/Source/Platform/chromium/public/WebFilterOperation. h"
10 #include "third_party/WebKit/Source/Platform/chromium/public/WebFilterOperations .h"
11 #include "third_party/skia/include/core/SkCanvas.h"
12 #include "third_party/skia/include/effects/SkBlurImageFilter.h"
13 #include "third_party/skia/include/effects/SkColorMatrixFilter.h"
14 #include "third_party/skia/include/effects/SkMagnifierImageFilter.h"
15 #include "third_party/skia/include/gpu/SkGpuDevice.h"
16 #include "third_party/skia/include/gpu/SkGrPixelRef.h"
17 #include "ui/gfx/size_f.h"
18
19 namespace cc {
20
21 namespace {
22
23 void GetBrightnessMatrix(float amount, SkScalar matrix[20]) {
24 // Spec implementation
25 // (http://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#brightnessEquiv alent)
26 // <feFunc[R|G|B] type="linear" slope="[amount]">
27 memset(matrix, 0, 20 * sizeof(SkScalar));
28 matrix[0] = matrix[6] = matrix[12] = amount;
29 matrix[18] = 1.f;
30 }
31
32 void GetSaturatingBrightnessMatrix(float amount, SkScalar matrix[20]) {
33 // Legacy implementation used by internal clients.
34 // <feFunc[R|G|B] type="linear" intercept="[amount]"/>
35 memset(matrix, 0, 20 * sizeof(SkScalar));
36 matrix[0] = matrix[6] = matrix[12] = matrix[18] = 1.f;
37 matrix[4] = matrix[9] = matrix[14] = amount * 255.f;
38 }
39
40 void GetContrastMatrix(float amount, SkScalar matrix[20]) {
41 memset(matrix, 0, 20 * sizeof(SkScalar));
42 matrix[0] = matrix[6] = matrix[12] = amount;
43 matrix[4] = matrix[9] = matrix[14] = (-0.5f * amount + 0.5f) * 255.f;
44 matrix[18] = 1.f;
45 }
46
47 void GetSaturateMatrix(float amount, SkScalar matrix[20]) {
48 // Note, these values are computed to ensure matrixNeedsClamping is false
49 // for amount in [0..1]
50 matrix[0] = 0.213f + 0.787f * amount;
51 matrix[1] = 0.715f - 0.715f * amount;
52 matrix[2] = 1.f - (matrix[0] + matrix[1]);
53 matrix[3] = matrix[4] = 0.f;
54 matrix[5] = 0.213f - 0.213f * amount;
55 matrix[6] = 0.715f + 0.285f * amount;
56 matrix[7] = 1.f - (matrix[5] + matrix[6]);
57 matrix[8] = matrix[9] = 0.f;
58 matrix[10] = 0.213f - 0.213f * amount;
59 matrix[11] = 0.715f - 0.715f * amount;
60 matrix[12] = 1.f - (matrix[10] + matrix[11]);
61 matrix[13] = matrix[14] = 0.f;
62 matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0.f;
63 matrix[18] = 1.f;
64 }
65
66 void GetHueRotateMatrix(float hue, SkScalar matrix[20]) {
67 const float kPi = 3.1415926535897932384626433832795f;
68
69 float cos_hue = cosf(hue * kPi / 180.f);
70 float sin_hue = sinf(hue * kPi / 180.f);
71 matrix[0] = 0.213f + cos_hue * 0.787f - sin_hue * 0.213f;
72 matrix[1] = 0.715f - cos_hue * 0.715f - sin_hue * 0.715f;
73 matrix[2] = 0.072f - cos_hue * 0.072f + sin_hue * 0.928f;
74 matrix[3] = matrix[4] = 0.f;
75 matrix[5] = 0.213f - cos_hue * 0.213f + sin_hue * 0.143f;
76 matrix[6] = 0.715f + cos_hue * 0.285f + sin_hue * 0.140f;
77 matrix[7] = 0.072f - cos_hue * 0.072f - sin_hue * 0.283f;
78 matrix[8] = matrix[9] = 0.f;
79 matrix[10] = 0.213f - cos_hue * 0.213f - sin_hue * 0.787f;
80 matrix[11] = 0.715f - cos_hue * 0.715f + sin_hue * 0.715f;
81 matrix[12] = 0.072f + cos_hue * 0.928f + sin_hue * 0.072f;
82 matrix[13] = matrix[14] = 0.f;
83 matrix[15] = matrix[16] = matrix[17] = 0.f;
84 matrix[18] = 1.f;
85 matrix[19] = 0.f;
86 }
87
88 void GetInvertMatrix(float amount, SkScalar matrix[20]) {
89 memset(matrix, 0, 20 * sizeof(SkScalar));
90 matrix[0] = matrix[6] = matrix[12] = 1.f - 2.f * amount;
91 matrix[4] = matrix[9] = matrix[14] = amount * 255.f;
92 matrix[18] = 1.f;
93 }
94
95 void GetOpacityMatrix(float amount, SkScalar matrix[20]) {
96 memset(matrix, 0, 20 * sizeof(SkScalar));
97 matrix[0] = matrix[6] = matrix[12] = 1.f;
98 matrix[18] = amount;
99 }
100
101 void GetGrayscaleMatrix(float amount, SkScalar matrix[20]) {
102 // Note, these values are computed to ensure matrixNeedsClamping is false
103 // for amount in [0..1]
104 matrix[0] = 0.2126f + 0.7874f * amount;
105 matrix[1] = 0.7152f - 0.7152f * amount;
106 matrix[2] = 1.f - (matrix[0] + matrix[1]);
107 matrix[3] = matrix[4] = 0.f;
108
109 matrix[5] = 0.2126f - 0.2126f * amount;
110 matrix[6] = 0.7152f + 0.2848f * amount;
111 matrix[7] = 1.f - (matrix[5] + matrix[6]);
112 matrix[8] = matrix[9] = 0.f;
113
114 matrix[10] = 0.2126f - 0.2126f * amount;
115 matrix[11] = 0.7152f - 0.7152f * amount;
116 matrix[12] = 1.f - (matrix[10] + matrix[11]);
117 matrix[13] = matrix[14] = 0.f;
118
119 matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0.f;
120 matrix[18] = 1.f;
121 }
122
123 void GetSepiaMatrix(float amount, SkScalar matrix[20]) {
124 matrix[0] = 0.393f + 0.607f * amount;
125 matrix[1] = 0.769f - 0.769f * amount;
126 matrix[2] = 0.189f - 0.189f * amount;
127 matrix[3] = matrix[4] = 0.f;
128
129 matrix[5] = 0.349f - 0.349f * amount;
130 matrix[6] = 0.686f + 0.314f * amount;
131 matrix[7] = 0.168f - 0.168f * amount;
132 matrix[8] = matrix[9] = 0.f;
133
134 matrix[10] = 0.272f - 0.272f * amount;
135 matrix[11] = 0.534f - 0.534f * amount;
136 matrix[12] = 0.131f + 0.869f * amount;
137 matrix[13] = matrix[14] = 0.f;
138
139 matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0.f;
140 matrix[18] = 1.f;
141 }
142
143 // The 5x4 matrix is really a "compressed" version of a 5x5 matrix that'd have
144 // (0 0 0 0 1) as a last row, and that would be applied to a 5-vector extended
145 // from the 4-vector color with a 1.
146 void MultColorMatrix(SkScalar a[20], SkScalar b[20], SkScalar out[20]) {
147 for (int j = 0; j < 4; ++j) {
148 for (int i = 0; i < 5; ++i) {
149 out[i+j*5] = i == 4 ? a[4+j*5] : 0.f;
150 for (int k = 0; k < 4; ++k)
151 out[i+j*5] += a[k+j*5] * b[i+k*5];
152 }
153 }
154 }
155
156 // To detect if we need to apply clamping after applying a matrix, we check if
157 // any output component might go outside of [0, 255] for any combination of
158 // input components in [0..255].
159 // Each output component is an affine transformation of the input component, so
160 // the minimum and maximum values are for any combination of minimum or maximum
161 // values of input components (i.e. 0 or 255).
162 // E.g. if R' = x*R + y*G + z*B + w*A + t
163 // Then the maximum value will be for R=255 if x>0 or R=0 if x<0, and the
164 // minimum value will be for R=0 if x>0 or R=255 if x<0.
165 // Same goes for all components.
166 bool ComponentNeedsClamping(SkScalar row[5]) {
167 SkScalar max_value = row[4] / 255.f;
168 SkScalar min_value = row[4] / 255.f;
169 for (int i = 0; i < 4; ++i) {
170 if (row[i] > 0)
171 max_value += row[i];
172 else
173 min_value += row[i];
174 }
175 return (max_value > 1.f) || (min_value < 0.f);
176 }
177
178 bool MatrixNeedsClamping(SkScalar matrix[20]) {
179 return ComponentNeedsClamping(matrix)
180 || ComponentNeedsClamping(matrix+5)
181 || ComponentNeedsClamping(matrix+10)
182 || ComponentNeedsClamping(matrix+15);
183 }
184
185 bool GetColorMatrix(const WebKit::WebFilterOperation& op, SkScalar matrix[20]) {
186 switch (op.type()) {
187 case WebKit::WebFilterOperation::FilterTypeBrightness: {
188 GetBrightnessMatrix(op.amount(), matrix);
189 return true;
190 }
191 case WebKit::WebFilterOperation::FilterTypeSaturatingBrightness: {
192 GetSaturatingBrightnessMatrix(op.amount(), matrix);
193 return true;
194 }
195 case WebKit::WebFilterOperation::FilterTypeContrast: {
196 GetContrastMatrix(op.amount(), matrix);
197 return true;
198 }
199 case WebKit::WebFilterOperation::FilterTypeGrayscale: {
200 GetGrayscaleMatrix(1.f - op.amount(), matrix);
201 return true;
202 }
203 case WebKit::WebFilterOperation::FilterTypeSepia: {
204 GetSepiaMatrix(1.f - op.amount(), matrix);
205 return true;
206 }
207 case WebKit::WebFilterOperation::FilterTypeSaturate: {
208 GetSaturateMatrix(op.amount(), matrix);
209 return true;
210 }
211 case WebKit::WebFilterOperation::FilterTypeHueRotate: {
212 GetHueRotateMatrix(op.amount(), matrix);
213 return true;
214 }
215 case WebKit::WebFilterOperation::FilterTypeInvert: {
216 GetInvertMatrix(op.amount(), matrix);
217 return true;
218 }
219 case WebKit::WebFilterOperation::FilterTypeOpacity: {
220 GetOpacityMatrix(op.amount(), matrix);
221 return true;
222 }
223 case WebKit::WebFilterOperation::FilterTypeColorMatrix: {
224 memcpy(matrix, op.matrix(), sizeof(SkScalar[20]));
225 return true;
226 }
227 default:
228 return false;
229 }
230 }
231
232 class FilterBufferState {
233 public:
234 FilterBufferState(GrContext* gr_context,
235 gfx::SizeF size,
236 unsigned texture_id)
237 : gr_context_(gr_context),
238 current_texture_(0) {
239 // Wrap the source texture in a Ganesh platform texture.
240 GrBackendTextureDesc backend_texture_description;
241 backend_texture_description.fWidth = size.width();
242 backend_texture_description.fHeight = size.height();
243 backend_texture_description.fConfig = kSkia8888_GrPixelConfig;
244 backend_texture_description.fTextureHandle = texture_id;
245 skia::RefPtr<GrTexture> texture = skia::AdoptRef(
246 gr_context->wrapBackendTexture(backend_texture_description));
247 // Place the platform texture inside an SkBitmap.
248 source_.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
249 skia::RefPtr<SkGrPixelRef> pixel_ref =
250 skia::AdoptRef(new SkGrPixelRef(texture.get()));
251 source_.setPixelRef(pixel_ref.get());
252 }
253
254 ~FilterBufferState() {}
255
256 bool Init(int filter_count) {
257 int scratch_count = std::min(2, filter_count);
258 GrTextureDesc desc;
259 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
260 desc.fSampleCnt = 0;
261 desc.fWidth = source_.width();
262 desc.fHeight = source_.height();
263 desc.fConfig = kSkia8888_GrPixelConfig;
264 for (int i = 0; i < scratch_count; ++i) {
265 GrAutoScratchTexture scratch_texture(
266 gr_context_, desc, GrContext::kExact_ScratchTexMatch);
267 scratch_textures_[i] = skia::AdoptRef(scratch_texture.detach());
268 if (!scratch_textures_[i])
269 return false;
270 }
271 return true;
272 }
273
274 SkCanvas* Canvas() {
275 if (!canvas_.get())
276 CreateCanvas();
277 return canvas_.get();
278 }
279
280 const SkBitmap& Source() { return source_; }
281
282 void Swap() {
283 canvas_->flush();
284 canvas_.clear();
285 device_.clear();
286
287 skia::RefPtr<SkGrPixelRef> pixel_ref = skia::AdoptRef(
288 new SkGrPixelRef(scratch_textures_[current_texture_].get()));
289 source_.setPixelRef(pixel_ref.get());
290 current_texture_ = 1 - current_texture_;
291 }
292
293 private:
294 void CreateCanvas() {
295 DCHECK(scratch_textures_[current_texture_].get());
296 device_ = skia::AdoptRef(new SkGpuDevice(
297 gr_context_, scratch_textures_[current_texture_].get()));
298 canvas_ = skia::AdoptRef(new SkCanvas(device_.get()));
299 canvas_->clear(0x0);
300 }
301
302 GrContext* gr_context_;
303 SkBitmap source_;
304 skia::RefPtr<GrTexture> scratch_textures_[2];
305 int current_texture_;
306 skia::RefPtr<SkGpuDevice> device_;
307 skia::RefPtr<SkCanvas> canvas_;
308 };
309
310 } // namespace
311
312 WebKit::WebFilterOperations RenderSurfaceFilters::Optimize(
313 const WebKit::WebFilterOperations& filters) {
314 WebKit::WebFilterOperations new_list;
315
316 SkScalar accumulated_color_matrix[20];
317 bool have_accumulated_color_matrix = false;
318 for (unsigned i = 0; i < filters.size(); ++i) {
319 const WebKit::WebFilterOperation& op = filters.at(i);
320
321 // If the filter is a color matrix, we may be able to combine it with
322 // following Filter(s) that also are color matrices.
323 SkScalar matrix[20];
324 if (GetColorMatrix(op, matrix)) {
325 if (have_accumulated_color_matrix) {
326 SkScalar newMatrix[20];
327 MultColorMatrix(matrix, accumulated_color_matrix, newMatrix);
328 memcpy(accumulated_color_matrix,
329 newMatrix,
330 sizeof(accumulated_color_matrix));
331 } else {
332 memcpy(accumulated_color_matrix,
333 matrix,
334 sizeof(accumulated_color_matrix));
335 have_accumulated_color_matrix = true;
336 }
337
338 // We can only combine matrices if clamping of color components
339 // would have no effect.
340 if (!MatrixNeedsClamping(accumulated_color_matrix))
341 continue;
342 }
343
344 if (have_accumulated_color_matrix) {
345 new_list.append(WebKit::WebFilterOperation::createColorMatrixFilter(
346 accumulated_color_matrix));
347 }
348 have_accumulated_color_matrix = false;
349
350 switch (op.type()) {
351 case WebKit::WebFilterOperation::FilterTypeBlur:
352 case WebKit::WebFilterOperation::FilterTypeDropShadow:
353 case WebKit::WebFilterOperation::FilterTypeZoom:
354 new_list.append(op);
355 break;
356 case WebKit::WebFilterOperation::FilterTypeBrightness:
357 case WebKit::WebFilterOperation::FilterTypeSaturatingBrightness:
358 case WebKit::WebFilterOperation::FilterTypeContrast:
359 case WebKit::WebFilterOperation::FilterTypeGrayscale:
360 case WebKit::WebFilterOperation::FilterTypeSepia:
361 case WebKit::WebFilterOperation::FilterTypeSaturate:
362 case WebKit::WebFilterOperation::FilterTypeHueRotate:
363 case WebKit::WebFilterOperation::FilterTypeInvert:
364 case WebKit::WebFilterOperation::FilterTypeOpacity:
365 case WebKit::WebFilterOperation::FilterTypeColorMatrix:
366 break;
367 }
368 }
369 if (have_accumulated_color_matrix) {
370 new_list.append(WebKit::WebFilterOperation::createColorMatrixFilter(
371 accumulated_color_matrix));
372 }
373 return new_list;
374 }
375
376 SkBitmap RenderSurfaceFilters::Apply(const WebKit::WebFilterOperations& filters,
377 unsigned texture_id,
378 gfx::SizeF size,
379 GrContext* gr_context) {
380 DCHECK(gr_context);
381
382 WebKit::WebFilterOperations optimized_filters = Optimize(filters);
383 FilterBufferState state(gr_context, size, texture_id);
384 if (!state.Init(optimized_filters.size()))
385 return SkBitmap();
386
387 for (unsigned i = 0; i < optimized_filters.size(); ++i) {
388 const WebKit::WebFilterOperation& op = optimized_filters.at(i);
389 SkCanvas* canvas = state.Canvas();
390 switch (op.type()) {
391 case WebKit::WebFilterOperation::FilterTypeColorMatrix: {
392 SkPaint paint;
393 skia::RefPtr<SkColorMatrixFilter> filter =
394 skia::AdoptRef(new SkColorMatrixFilter(op.matrix()));
395 paint.setColorFilter(filter.get());
396 canvas->drawBitmap(state.Source(), 0, 0, &paint);
397 break;
398 }
399 case WebKit::WebFilterOperation::FilterTypeBlur: {
400 float std_deviation = op.amount();
401 skia::RefPtr<SkImageFilter> filter =
402 skia::AdoptRef(new SkBlurImageFilter(std_deviation, std_deviation));
403 SkPaint paint;
404 paint.setImageFilter(filter.get());
405 canvas->drawSprite(state.Source(), 0, 0, &paint);
406 break;
407 }
408 case WebKit::WebFilterOperation::FilterTypeDropShadow: {
409 skia::RefPtr<SkImageFilter> blur_filter =
410 skia::AdoptRef(new SkBlurImageFilter(op.amount(), op.amount()));
411 skia::RefPtr<SkColorFilter> color_filter =
412 skia::AdoptRef(SkColorFilter::CreateModeFilter(
413 op.dropShadowColor(), SkXfermode::kSrcIn_Mode));
414 SkPaint paint;
415 paint.setImageFilter(blur_filter.get());
416 paint.setColorFilter(color_filter.get());
417 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
418 canvas->saveLayer(NULL, &paint);
419 canvas->drawBitmap(state.Source(),
420 op.dropShadowOffset().x,
421 -op.dropShadowOffset().y);
422 canvas->restore();
423 canvas->drawBitmap(state.Source(), 0, 0);
424 break;
425 }
426 case WebKit::WebFilterOperation::FilterTypeZoom: {
427 SkPaint paint;
428 int width = state.Source().width();
429 int height = state.Source().height();
430 skia::RefPtr<SkImageFilter> zoom_filter = skia::AdoptRef(
431 new SkMagnifierImageFilter(
432 SkRect::MakeXYWH(
433 (width - (width / op.amount())) / 2.f,
434 (height - (height / op.amount())) / 2.f,
435 width / op.amount(),
436 height / op.amount()),
437 op.zoomInset()));
438 paint.setImageFilter(zoom_filter.get());
439 canvas->saveLayer(NULL, &paint);
440 canvas->drawBitmap(state.Source(), 0, 0);
441 canvas->restore();
442 break;
443 }
444 case WebKit::WebFilterOperation::FilterTypeBrightness:
445 case WebKit::WebFilterOperation::FilterTypeSaturatingBrightness:
446 case WebKit::WebFilterOperation::FilterTypeContrast:
447 case WebKit::WebFilterOperation::FilterTypeGrayscale:
448 case WebKit::WebFilterOperation::FilterTypeSepia:
449 case WebKit::WebFilterOperation::FilterTypeSaturate:
450 case WebKit::WebFilterOperation::FilterTypeHueRotate:
451 case WebKit::WebFilterOperation::FilterTypeInvert:
452 case WebKit::WebFilterOperation::FilterTypeOpacity:
453 NOTREACHED();
454 break;
455 }
456 state.Swap();
457 }
458 return state.Source();
459 }
460
461 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698