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