• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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