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.
5 #include "cc/output/render_surface_filters.h"
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"
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
;
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
;
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
;
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
;
73 void GetHueRotateMatrix(float hue
, SkScalar matrix
[20]) {
74 const float kPi
= 3.1415926535897932384626433832795f
;
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
;
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
;
102 void GetOpacityMatrix(float amount
, SkScalar matrix
[20]) {
103 memset(matrix
, 0, 20 * sizeof(SkScalar
));
104 matrix
[0] = matrix
[6] = matrix
[12] = 1.f
;
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
;
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
;
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
;
126 matrix
[15] = matrix
[16] = matrix
[17] = matrix
[19] = 0.f
;
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
;
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
;
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
;
146 matrix
[15] = matrix
[16] = matrix
[17] = matrix
[19] = 0.f
;
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()));
161 skia::RefPtr
<SkImageFilter
> RenderSurfaceFilters::BuildImageFilter(
162 const FilterOperations
& filters
,
163 const gfx::SizeF
& size
) {
164 skia::RefPtr
<SkImageFilter
> image_filter
;
166 for (size_t i
= 0; i
< filters
.size(); ++i
) {
167 const FilterOperation
& op
= filters
.at(i
);
169 case FilterOperation::GRAYSCALE
:
170 GetGrayscaleMatrix(1.f
- op
.amount(), matrix
);
171 image_filter
= CreateMatrixImageFilter(matrix
, image_filter
);
173 case FilterOperation::SEPIA
:
174 GetSepiaMatrix(1.f
- op
.amount(), matrix
);
175 image_filter
= CreateMatrixImageFilter(matrix
, image_filter
);
177 case FilterOperation::SATURATE
:
178 GetSaturateMatrix(op
.amount(), matrix
);
179 image_filter
= CreateMatrixImageFilter(matrix
, image_filter
);
181 case FilterOperation::HUE_ROTATE
:
182 GetHueRotateMatrix(op
.amount(), matrix
);
183 image_filter
= CreateMatrixImageFilter(matrix
, image_filter
);
185 case FilterOperation::INVERT
:
186 GetInvertMatrix(op
.amount(), matrix
);
187 image_filter
= CreateMatrixImageFilter(matrix
, image_filter
);
189 case FilterOperation::OPACITY
:
190 GetOpacityMatrix(op
.amount(), matrix
);
191 image_filter
= CreateMatrixImageFilter(matrix
, image_filter
);
193 case FilterOperation::BRIGHTNESS
:
194 GetBrightnessMatrix(op
.amount(), matrix
);
195 image_filter
= CreateMatrixImageFilter(matrix
, image_filter
);
197 case FilterOperation::CONTRAST
:
198 GetContrastMatrix(op
.amount(), matrix
);
199 image_filter
= CreateMatrixImageFilter(matrix
, image_filter
);
201 case FilterOperation::BLUR
:
202 image_filter
= skia::AdoptRef(new SkBlurImageFilter(
203 op
.amount(), op
.amount(), image_filter
.get()));
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()));
213 case FilterOperation::COLOR_MATRIX
:
214 image_filter
= CreateMatrixImageFilter(op
.matrix(), image_filter
);
216 case FilterOperation::ZOOM
: {
217 skia::RefPtr
<SkImageFilter
> zoom_filter
= skia::AdoptRef(
218 new SkMagnifierImageFilter(
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()),
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()));
232 image_filter
= zoom_filter
;
236 case FilterOperation::SATURATING_BRIGHTNESS
:
237 GetSaturatingBrightnessMatrix(op
.amount(), matrix
);
238 image_filter
= CreateMatrixImageFilter(matrix
, image_filter
);
240 case FilterOperation::REFERENCE
: {
241 if (!op
.image_filter())
244 skia::RefPtr
<SkColorFilter
> cf
;
247 SkColorFilter
* colorfilter_rawptr
= NULL
;
248 op
.image_filter()->asColorFilter(&colorfilter_rawptr
);
249 cf
= skia::AdoptRef(colorfilter_rawptr
);
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()));
259 image_filter
= op
.image_filter();