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 "cc/output/filter_operation.h"
10 #include "cc/output/filter_operations.h"
11 #include "skia/ext/refptr.h"
12 #include "third_party/skia/include/core/SkImageFilter.h"
13 #include "third_party/skia/include/effects/SkAlphaThresholdFilter.h"
14 #include "third_party/skia/include/effects/SkBlurImageFilter.h"
15 #include "third_party/skia/include/effects/SkColorFilterImageFilter.h"
16 #include "third_party/skia/include/effects/SkColorMatrixFilter.h"
17 #include "third_party/skia/include/effects/SkComposeImageFilter.h"
18 #include "third_party/skia/include/effects/SkDropShadowImageFilter.h"
19 #include "third_party/skia/include/effects/SkMagnifierImageFilter.h"
20 #include "third_party/skia/include/effects/SkRectShaderImageFilter.h"
21 #include "ui/gfx/geometry/size_f.h"
27 void GetBrightnessMatrix(float amount
, SkScalar matrix
[20]) {
28 // Spec implementation
29 // (http://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#brightnessEquivalent)
30 // <feFunc[R|G|B] type="linear" slope="[amount]">
31 memset(matrix
, 0, 20 * sizeof(SkScalar
));
32 matrix
[0] = matrix
[6] = matrix
[12] = amount
;
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
;
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
;
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
;
70 void GetHueRotateMatrix(float hue
, SkScalar matrix
[20]) {
71 const float kPi
= 3.1415926535897932384626433832795f
;
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
;
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
;
99 void GetOpacityMatrix(float amount
, SkScalar matrix
[20]) {
100 memset(matrix
, 0, 20 * sizeof(SkScalar
));
101 matrix
[0] = matrix
[6] = matrix
[12] = 1.f
;
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
;
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
;
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
;
123 matrix
[15] = matrix
[16] = matrix
[17] = matrix
[19] = 0.f
;
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
;
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
;
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
;
143 matrix
[15] = matrix
[16] = matrix
[17] = matrix
[19] = 0.f
;
147 skia::RefPtr
<SkImageFilter
> CreateMatrixImageFilter(
148 const SkScalar matrix
[20],
149 const skia::RefPtr
<SkImageFilter
>& input
) {
150 skia::RefPtr
<SkColorFilter
> color_filter
=
151 skia::AdoptRef(SkColorMatrixFilter::Create(matrix
));
152 return skia::AdoptRef(
153 SkColorFilterImageFilter::Create(color_filter
.get(), input
.get()));
158 skia::RefPtr
<SkImageFilter
> RenderSurfaceFilters::BuildImageFilter(
159 const FilterOperations
& filters
,
160 const gfx::SizeF
& size
) {
161 skia::RefPtr
<SkImageFilter
> image_filter
;
163 for (size_t i
= 0; i
< filters
.size(); ++i
) {
164 const FilterOperation
& op
= filters
.at(i
);
166 case FilterOperation::GRAYSCALE
:
167 GetGrayscaleMatrix(1.f
- op
.amount(), matrix
);
168 image_filter
= CreateMatrixImageFilter(matrix
, image_filter
);
170 case FilterOperation::SEPIA
:
171 GetSepiaMatrix(1.f
- op
.amount(), matrix
);
172 image_filter
= CreateMatrixImageFilter(matrix
, image_filter
);
174 case FilterOperation::SATURATE
:
175 GetSaturateMatrix(op
.amount(), matrix
);
176 image_filter
= CreateMatrixImageFilter(matrix
, image_filter
);
178 case FilterOperation::HUE_ROTATE
:
179 GetHueRotateMatrix(op
.amount(), matrix
);
180 image_filter
= CreateMatrixImageFilter(matrix
, image_filter
);
182 case FilterOperation::INVERT
:
183 GetInvertMatrix(op
.amount(), matrix
);
184 image_filter
= CreateMatrixImageFilter(matrix
, image_filter
);
186 case FilterOperation::OPACITY
:
187 GetOpacityMatrix(op
.amount(), matrix
);
188 image_filter
= CreateMatrixImageFilter(matrix
, image_filter
);
190 case FilterOperation::BRIGHTNESS
:
191 GetBrightnessMatrix(op
.amount(), matrix
);
192 image_filter
= CreateMatrixImageFilter(matrix
, image_filter
);
194 case FilterOperation::CONTRAST
:
195 GetContrastMatrix(op
.amount(), matrix
);
196 image_filter
= CreateMatrixImageFilter(matrix
, image_filter
);
198 case FilterOperation::BLUR
:
199 image_filter
= skia::AdoptRef(SkBlurImageFilter::Create(
200 op
.amount(), op
.amount(), image_filter
.get()));
202 case FilterOperation::DROP_SHADOW
:
203 image_filter
= skia::AdoptRef(SkDropShadowImageFilter::Create(
204 SkIntToScalar(op
.drop_shadow_offset().x()),
205 SkIntToScalar(op
.drop_shadow_offset().y()),
206 SkIntToScalar(op
.amount()),
207 SkIntToScalar(op
.amount()),
208 op
.drop_shadow_color(),
209 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode
,
210 image_filter
.get()));
212 case FilterOperation::COLOR_MATRIX
:
213 image_filter
= CreateMatrixImageFilter(op
.matrix(), image_filter
);
215 case FilterOperation::ZOOM
: {
216 skia::RefPtr
<SkImageFilter
> zoom_filter
=
217 skia::AdoptRef(SkMagnifierImageFilter::Create(
219 (size
.width() - (size
.width() / op
.amount())) / 2.f
,
220 (size
.height() - (size
.height() / op
.amount())) / 2.f
,
221 size
.width() / op
.amount(),
222 size
.height() / op
.amount()),
224 if (image_filter
.get()) {
225 // TODO(ajuma): When there's a 1-input version of
226 // SkMagnifierImageFilter, use that to handle the input filter
227 // instead of using an SkComposeImageFilter.
228 image_filter
= skia::AdoptRef(SkComposeImageFilter::Create(
229 zoom_filter
.get(), image_filter
.get()));
231 image_filter
= zoom_filter
;
235 case FilterOperation::SATURATING_BRIGHTNESS
:
236 GetSaturatingBrightnessMatrix(op
.amount(), matrix
);
237 image_filter
= CreateMatrixImageFilter(matrix
, image_filter
);
239 case FilterOperation::REFERENCE
: {
240 if (!op
.image_filter())
243 skia::RefPtr
<SkColorFilter
> cf
;
246 SkColorFilter
* colorfilter_rawptr
= NULL
;
247 op
.image_filter()->asColorFilter(&colorfilter_rawptr
);
248 cf
= skia::AdoptRef(colorfilter_rawptr
);
251 if (cf
&& cf
->asColorMatrix(matrix
) &&
252 !op
.image_filter()->getInput(0)) {
253 image_filter
= CreateMatrixImageFilter(matrix
, image_filter
);
254 } else if (image_filter
) {
255 image_filter
= skia::AdoptRef(SkComposeImageFilter::Create(
256 op
.image_filter().get(), image_filter
.get()));
258 image_filter
= op
.image_filter();
262 case FilterOperation::ALPHA_THRESHOLD
: {
263 skia::RefPtr
<SkImageFilter
> alpha_filter
= skia::AdoptRef(
264 SkAlphaThresholdFilter::Create(
265 op
.region(), op
.amount(), op
.outer_threshold()));
266 if (image_filter
.get()) {
267 image_filter
= skia::AdoptRef(SkComposeImageFilter::Create(
268 alpha_filter
.get(), image_filter
.get()));
270 image_filter
= alpha_filter
;