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 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 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 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 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 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 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 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 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 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 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 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