| OLD | NEW |
| (Empty) |
| 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 <stddef.h> | |
| 8 | |
| 9 #include <algorithm> | |
| 10 | |
| 11 #include "cc/output/filter_operation.h" | |
| 12 #include "cc/output/filter_operations.h" | |
| 13 #include "third_party/skia/include/core/SkImageFilter.h" | |
| 14 #include "third_party/skia/include/effects/SkAlphaThresholdFilter.h" | |
| 15 #include "third_party/skia/include/effects/SkBlurImageFilter.h" | |
| 16 #include "third_party/skia/include/effects/SkColorFilterImageFilter.h" | |
| 17 #include "third_party/skia/include/effects/SkColorMatrixFilter.h" | |
| 18 #include "third_party/skia/include/effects/SkComposeImageFilter.h" | |
| 19 #include "third_party/skia/include/effects/SkDropShadowImageFilter.h" | |
| 20 #include "third_party/skia/include/effects/SkMagnifierImageFilter.h" | |
| 21 #include "ui/gfx/geometry/size_f.h" | |
| 22 | |
| 23 namespace cc { | |
| 24 | |
| 25 namespace { | |
| 26 | |
| 27 void GetBrightnessMatrix(float amount, SkScalar matrix[20]) { | |
| 28 // Spec implementation | |
| 29 // (http://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#brightnessEquiv
alent) | |
| 30 // <feFunc[R|G|B] type="linear" slope="[amount]"> | |
| 31 memset(matrix, 0, 20 * sizeof(SkScalar)); | |
| 32 matrix[0] = matrix[6] = matrix[12] = amount; | |
| 33 matrix[18] = 1.f; | |
| 34 } | |
| 35 | |
| 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; | |
| 42 } | |
| 43 | |
| 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; | |
| 48 matrix[18] = 1.f; | |
| 49 } | |
| 50 | |
| 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; | |
| 67 matrix[18] = 1.f; | |
| 68 } | |
| 69 | |
| 70 void GetHueRotateMatrix(float hue, SkScalar matrix[20]) { | |
| 71 const float kPi = 3.1415926535897932384626433832795f; | |
| 72 | |
| 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; | |
| 88 matrix[18] = 1.f; | |
| 89 matrix[19] = 0.f; | |
| 90 } | |
| 91 | |
| 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; | |
| 96 matrix[18] = 1.f; | |
| 97 } | |
| 98 | |
| 99 void GetOpacityMatrix(float amount, SkScalar matrix[20]) { | |
| 100 memset(matrix, 0, 20 * sizeof(SkScalar)); | |
| 101 matrix[0] = matrix[6] = matrix[12] = 1.f; | |
| 102 matrix[18] = amount; | |
| 103 } | |
| 104 | |
| 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; | |
| 112 | |
| 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; | |
| 117 | |
| 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; | |
| 122 | |
| 123 matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0.f; | |
| 124 matrix[18] = 1.f; | |
| 125 } | |
| 126 | |
| 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; | |
| 132 | |
| 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; | |
| 137 | |
| 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; | |
| 142 | |
| 143 matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0.f; | |
| 144 matrix[18] = 1.f; | |
| 145 } | |
| 146 | |
| 147 sk_sp<SkImageFilter> CreateMatrixImageFilter(const SkScalar matrix[20], | |
| 148 sk_sp<SkImageFilter> input) { | |
| 149 return SkColorFilterImageFilter::Make( | |
| 150 SkColorFilter::MakeMatrixFilterRowMajor255(matrix), std::move(input)); | |
| 151 } | |
| 152 | |
| 153 } // namespace | |
| 154 | |
| 155 sk_sp<SkImageFilter> RenderSurfaceFilters::BuildImageFilter( | |
| 156 const FilterOperations& filters, | |
| 157 const gfx::SizeF& size, | |
| 158 const gfx::Vector2dF& offset) { | |
| 159 sk_sp<SkImageFilter> image_filter; | |
| 160 SkScalar matrix[20]; | |
| 161 for (size_t i = 0; i < filters.size(); ++i) { | |
| 162 const FilterOperation& op = filters.at(i); | |
| 163 switch (op.type()) { | |
| 164 case FilterOperation::GRAYSCALE: | |
| 165 GetGrayscaleMatrix(1.f - op.amount(), matrix); | |
| 166 image_filter = CreateMatrixImageFilter(matrix, std::move(image_filter)); | |
| 167 break; | |
| 168 case FilterOperation::SEPIA: | |
| 169 GetSepiaMatrix(1.f - op.amount(), matrix); | |
| 170 image_filter = CreateMatrixImageFilter(matrix, std::move(image_filter)); | |
| 171 break; | |
| 172 case FilterOperation::SATURATE: | |
| 173 GetSaturateMatrix(op.amount(), matrix); | |
| 174 image_filter = CreateMatrixImageFilter(matrix, std::move(image_filter)); | |
| 175 break; | |
| 176 case FilterOperation::HUE_ROTATE: | |
| 177 GetHueRotateMatrix(op.amount(), matrix); | |
| 178 image_filter = CreateMatrixImageFilter(matrix, std::move(image_filter)); | |
| 179 break; | |
| 180 case FilterOperation::INVERT: | |
| 181 GetInvertMatrix(op.amount(), matrix); | |
| 182 image_filter = CreateMatrixImageFilter(matrix, std::move(image_filter)); | |
| 183 break; | |
| 184 case FilterOperation::OPACITY: | |
| 185 GetOpacityMatrix(op.amount(), matrix); | |
| 186 image_filter = CreateMatrixImageFilter(matrix, std::move(image_filter)); | |
| 187 break; | |
| 188 case FilterOperation::BRIGHTNESS: | |
| 189 GetBrightnessMatrix(op.amount(), matrix); | |
| 190 image_filter = CreateMatrixImageFilter(matrix, std::move(image_filter)); | |
| 191 break; | |
| 192 case FilterOperation::CONTRAST: | |
| 193 GetContrastMatrix(op.amount(), matrix); | |
| 194 image_filter = CreateMatrixImageFilter(matrix, std::move(image_filter)); | |
| 195 break; | |
| 196 case FilterOperation::BLUR: | |
| 197 image_filter = SkBlurImageFilter::Make(op.amount(), op.amount(), | |
| 198 std::move(image_filter)); | |
| 199 break; | |
| 200 case FilterOperation::DROP_SHADOW: | |
| 201 image_filter = SkDropShadowImageFilter::Make( | |
| 202 SkIntToScalar(op.drop_shadow_offset().x()), | |
| 203 SkIntToScalar(op.drop_shadow_offset().y()), | |
| 204 SkIntToScalar(op.amount()), SkIntToScalar(op.amount()), | |
| 205 op.drop_shadow_color(), | |
| 206 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode, | |
| 207 std::move(image_filter)); | |
| 208 break; | |
| 209 case FilterOperation::COLOR_MATRIX: | |
| 210 image_filter = | |
| 211 CreateMatrixImageFilter(op.matrix(), std::move(image_filter)); | |
| 212 break; | |
| 213 case FilterOperation::ZOOM: { | |
| 214 // The center point, always the midpoint of the unclipped rectangle. | |
| 215 // When we go to either edge of the screen, the width/height will shrink | |
| 216 // at the same rate the offset changes. Use abs on the offset since we | |
| 217 // do not care about the offset direction. | |
| 218 gfx::Vector2dF center = | |
| 219 gfx::Vector2dF((size.width() + std::abs(offset.x())) / 2, | |
| 220 (size.height() + std::abs(offset.y())) / 2); | |
| 221 | |
| 222 // The dimensions of the source content. This shrinks as the texture | |
| 223 // rectangle gets clipped. | |
| 224 gfx::Vector2d src_dimensions = | |
| 225 gfx::Vector2d((size.width() + std::abs(offset.x())) / op.amount(), | |
| 226 (size.height() + std::abs(offset.y())) / op.amount()); | |
| 227 | |
| 228 // When the magnifier goes to the left/top border of the screen, we need | |
| 229 // to adjust the x/y position of the rect. The rate the position gets | |
| 230 // updated currently only works properly for a 2x magnification. | |
| 231 DCHECK_EQ(op.amount(), 2.f); | |
| 232 gfx::Vector2dF center_offset = gfx::Vector2dF(0, 0); | |
| 233 if (offset.x() >= 0) | |
| 234 center_offset.set_x(-offset.x() / op.amount()); | |
| 235 if (offset.y() <= 0) | |
| 236 center_offset.set_y(offset.y() / op.amount()); | |
| 237 | |
| 238 sk_sp<SkImageFilter> zoom_filter(SkMagnifierImageFilter::Make( | |
| 239 SkRect::MakeXYWH( | |
| 240 (center.x() - src_dimensions.x() / 2.f) + center_offset.x(), | |
| 241 (center.y() - src_dimensions.y() / 2.f) + center_offset.y(), | |
| 242 size.width() / op.amount(), size.height() / op.amount()), | |
| 243 op.zoom_inset(), nullptr)); | |
| 244 if (image_filter) { | |
| 245 // TODO(ajuma): When there's a 1-input version of | |
| 246 // SkMagnifierImageFilter, use that to handle the input filter | |
| 247 // instead of using an SkComposeImageFilter. | |
| 248 image_filter = SkComposeImageFilter::Make(std::move(zoom_filter), | |
| 249 std::move(image_filter)); | |
| 250 } else { | |
| 251 image_filter = std::move(zoom_filter); | |
| 252 } | |
| 253 break; | |
| 254 } | |
| 255 case FilterOperation::SATURATING_BRIGHTNESS: | |
| 256 GetSaturatingBrightnessMatrix(op.amount(), matrix); | |
| 257 image_filter = CreateMatrixImageFilter(matrix, std::move(image_filter)); | |
| 258 break; | |
| 259 case FilterOperation::REFERENCE: { | |
| 260 if (!op.image_filter()) | |
| 261 break; | |
| 262 | |
| 263 sk_sp<SkColorFilter> cf; | |
| 264 | |
| 265 { | |
| 266 SkColorFilter* colorfilter_rawptr = NULL; | |
| 267 op.image_filter()->asColorFilter(&colorfilter_rawptr); | |
| 268 cf.reset(colorfilter_rawptr); | |
| 269 } | |
| 270 | |
| 271 if (cf && cf->asColorMatrix(matrix) && | |
| 272 !op.image_filter()->getInput(0)) { | |
| 273 image_filter = | |
| 274 CreateMatrixImageFilter(matrix, std::move(image_filter)); | |
| 275 } else if (image_filter) { | |
| 276 image_filter = SkComposeImageFilter::Make(op.image_filter(), | |
| 277 std::move(image_filter)); | |
| 278 } else { | |
| 279 image_filter = op.image_filter(); | |
| 280 } | |
| 281 break; | |
| 282 } | |
| 283 case FilterOperation::ALPHA_THRESHOLD: { | |
| 284 sk_sp<SkImageFilter> alpha_filter = SkAlphaThresholdFilter::Make( | |
| 285 op.region(), op.amount(), op.outer_threshold(), nullptr); | |
| 286 if (image_filter) { | |
| 287 image_filter = SkComposeImageFilter::Make(std::move(alpha_filter), | |
| 288 std::move(image_filter)); | |
| 289 } else { | |
| 290 image_filter = std::move(alpha_filter); | |
| 291 } | |
| 292 break; | |
| 293 } | |
| 294 } | |
| 295 } | |
| 296 return image_filter; | |
| 297 } | |
| 298 | |
| 299 } // namespace cc | |
| OLD | NEW |