1 // Copyright 2013 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 <algorithm> 6 7 #include "base/values.h" 8 #include "cc/base/math_util.h" 9 #include "cc/output/filter_operation.h" 10 #include "third_party/skia/include/core/SkMath.h" 11 #include "ui/gfx/animation/tween.h" 12 13 namespace cc { 14 15 bool FilterOperation::operator==(const FilterOperation& other) const { 16 if (type_ != other.type_) 17 return false; 18 if (type_ == COLOR_MATRIX) 19 return !memcmp(matrix_, other.matrix_, sizeof(matrix_)); 20 if (type_ == DROP_SHADOW) { 21 return amount_ == other.amount_ && 22 drop_shadow_offset_ == other.drop_shadow_offset_ && 23 drop_shadow_color_ == other.drop_shadow_color_; 24 } 25 if (type_ == REFERENCE) 26 return image_filter_.get() == other.image_filter_.get(); 27 if (type_ == ALPHA_THRESHOLD) { 28 return region_ == other.region_ && 29 amount_ == other.amount_ && 30 outer_threshold_ == other.outer_threshold_; 31 } 32 return amount_ == other.amount_; 33 } 34 35 FilterOperation::FilterOperation(FilterType type, float amount) 36 : type_(type), 37 amount_(amount), 38 outer_threshold_(0), 39 drop_shadow_offset_(0, 0), 40 drop_shadow_color_(0), 41 zoom_inset_(0) { 42 DCHECK_NE(type_, DROP_SHADOW); 43 DCHECK_NE(type_, COLOR_MATRIX); 44 DCHECK_NE(type_, REFERENCE); 45 memset(matrix_, 0, sizeof(matrix_)); 46 } 47 48 FilterOperation::FilterOperation(FilterType type, 49 const gfx::Point& offset, 50 float stdDeviation, 51 SkColor color) 52 : type_(type), 53 amount_(stdDeviation), 54 outer_threshold_(0), 55 drop_shadow_offset_(offset), 56 drop_shadow_color_(color), 57 zoom_inset_(0) { 58 DCHECK_EQ(type_, DROP_SHADOW); 59 memset(matrix_, 0, sizeof(matrix_)); 60 } 61 62 FilterOperation::FilterOperation(FilterType type, SkScalar matrix[20]) 63 : type_(type), 64 amount_(0), 65 outer_threshold_(0), 66 drop_shadow_offset_(0, 0), 67 drop_shadow_color_(0), 68 zoom_inset_(0) { 69 DCHECK_EQ(type_, COLOR_MATRIX); 70 memcpy(matrix_, matrix, sizeof(matrix_)); 71 } 72 73 FilterOperation::FilterOperation(FilterType type, float amount, int inset) 74 : type_(type), 75 amount_(amount), 76 outer_threshold_(0), 77 drop_shadow_offset_(0, 0), 78 drop_shadow_color_(0), 79 zoom_inset_(inset) { 80 DCHECK_EQ(type_, ZOOM); 81 memset(matrix_, 0, sizeof(matrix_)); 82 } 83 84 FilterOperation::FilterOperation( 85 FilterType type, 86 const skia::RefPtr<SkImageFilter>& image_filter) 87 : type_(type), 88 amount_(0), 89 outer_threshold_(0), 90 drop_shadow_offset_(0, 0), 91 drop_shadow_color_(0), 92 image_filter_(image_filter), 93 zoom_inset_(0) { 94 DCHECK_EQ(type_, REFERENCE); 95 memset(matrix_, 0, sizeof(matrix_)); 96 } 97 98 FilterOperation::FilterOperation(FilterType type, 99 const SkRegion& region, 100 float inner_threshold, 101 float outer_threshold) 102 : type_(type), 103 amount_(inner_threshold), 104 outer_threshold_(outer_threshold), 105 drop_shadow_offset_(0, 0), 106 drop_shadow_color_(0), 107 zoom_inset_(0), 108 region_(region) { 109 DCHECK_EQ(type_, ALPHA_THRESHOLD); 110 memset(matrix_, 0, sizeof(matrix_)); 111 } 112 113 FilterOperation::FilterOperation(const FilterOperation& other) 114 : type_(other.type_), 115 amount_(other.amount_), 116 outer_threshold_(other.outer_threshold_), 117 drop_shadow_offset_(other.drop_shadow_offset_), 118 drop_shadow_color_(other.drop_shadow_color_), 119 image_filter_(other.image_filter_), 120 zoom_inset_(other.zoom_inset_), 121 region_(other.region_) { 122 memcpy(matrix_, other.matrix_, sizeof(matrix_)); 123 } 124 125 FilterOperation::~FilterOperation() { 126 } 127 128 static FilterOperation CreateNoOpFilter(FilterOperation::FilterType type) { 129 switch (type) { 130 case FilterOperation::GRAYSCALE: 131 return FilterOperation::CreateGrayscaleFilter(0.f); 132 case FilterOperation::SEPIA: 133 return FilterOperation::CreateSepiaFilter(0.f); 134 case FilterOperation::SATURATE: 135 return FilterOperation::CreateSaturateFilter(1.f); 136 case FilterOperation::HUE_ROTATE: 137 return FilterOperation::CreateHueRotateFilter(0.f); 138 case FilterOperation::INVERT: 139 return FilterOperation::CreateInvertFilter(0.f); 140 case FilterOperation::BRIGHTNESS: 141 return FilterOperation::CreateBrightnessFilter(1.f); 142 case FilterOperation::CONTRAST: 143 return FilterOperation::CreateContrastFilter(1.f); 144 case FilterOperation::OPACITY: 145 return FilterOperation::CreateOpacityFilter(1.f); 146 case FilterOperation::BLUR: 147 return FilterOperation::CreateBlurFilter(0.f); 148 case FilterOperation::DROP_SHADOW: 149 return FilterOperation::CreateDropShadowFilter( 150 gfx::Point(0, 0), 0.f, SK_ColorTRANSPARENT); 151 case FilterOperation::COLOR_MATRIX: { 152 SkScalar matrix[20]; 153 memset(matrix, 0, 20 * sizeof(SkScalar)); 154 matrix[0] = matrix[6] = matrix[12] = matrix[18] = 1.f; 155 return FilterOperation::CreateColorMatrixFilter(matrix); 156 } 157 case FilterOperation::ZOOM: 158 return FilterOperation::CreateZoomFilter(1.f, 0); 159 case FilterOperation::SATURATING_BRIGHTNESS: 160 return FilterOperation::CreateSaturatingBrightnessFilter(0.f); 161 case FilterOperation::REFERENCE: 162 return FilterOperation::CreateReferenceFilter( 163 skia::RefPtr<SkImageFilter>()); 164 case FilterOperation::ALPHA_THRESHOLD: 165 return FilterOperation::CreateAlphaThresholdFilter(SkRegion(), 1.f, 0.f); 166 } 167 NOTREACHED(); 168 return FilterOperation::CreateEmptyFilter(); 169 } 170 171 static float ClampAmountForFilterType(float amount, 172 FilterOperation::FilterType type) { 173 switch (type) { 174 case FilterOperation::GRAYSCALE: 175 case FilterOperation::SEPIA: 176 case FilterOperation::INVERT: 177 case FilterOperation::OPACITY: 178 case FilterOperation::ALPHA_THRESHOLD: 179 return MathUtil::ClampToRange(amount, 0.f, 1.f); 180 case FilterOperation::SATURATE: 181 case FilterOperation::BRIGHTNESS: 182 case FilterOperation::CONTRAST: 183 case FilterOperation::BLUR: 184 case FilterOperation::DROP_SHADOW: 185 return std::max(amount, 0.f); 186 case FilterOperation::ZOOM: 187 return std::max(amount, 1.f); 188 case FilterOperation::HUE_ROTATE: 189 case FilterOperation::SATURATING_BRIGHTNESS: 190 return amount; 191 case FilterOperation::COLOR_MATRIX: 192 case FilterOperation::REFERENCE: 193 NOTREACHED(); 194 return amount; 195 } 196 NOTREACHED(); 197 return amount; 198 } 199 200 // static 201 FilterOperation FilterOperation::Blend(const FilterOperation* from, 202 const FilterOperation* to, 203 double progress) { 204 FilterOperation blended_filter = FilterOperation::CreateEmptyFilter(); 205 206 if (!from && !to) 207 return blended_filter; 208 209 const FilterOperation& from_op = from ? *from : CreateNoOpFilter(to->type()); 210 const FilterOperation& to_op = to ? *to : CreateNoOpFilter(from->type()); 211 212 if (from_op.type() != to_op.type()) 213 return blended_filter; 214 215 DCHECK(to_op.type() != FilterOperation::COLOR_MATRIX); 216 blended_filter.set_type(to_op.type()); 217 218 if (to_op.type() == FilterOperation::REFERENCE) { 219 if (progress > 0.5) 220 blended_filter.set_image_filter(to_op.image_filter()); 221 else 222 blended_filter.set_image_filter(from_op.image_filter()); 223 return blended_filter; 224 } 225 226 blended_filter.set_amount(ClampAmountForFilterType( 227 gfx::Tween::FloatValueBetween(progress, from_op.amount(), to_op.amount()), 228 to_op.type())); 229 230 if (to_op.type() == FilterOperation::DROP_SHADOW) { 231 gfx::Point blended_offset( 232 gfx::Tween::LinearIntValueBetween(progress, 233 from_op.drop_shadow_offset().x(), 234 to_op.drop_shadow_offset().x()), 235 gfx::Tween::LinearIntValueBetween(progress, 236 from_op.drop_shadow_offset().y(), 237 to_op.drop_shadow_offset().y())); 238 blended_filter.set_drop_shadow_offset(blended_offset); 239 blended_filter.set_drop_shadow_color(gfx::Tween::ColorValueBetween( 240 progress, from_op.drop_shadow_color(), to_op.drop_shadow_color())); 241 } else if (to_op.type() == FilterOperation::ZOOM) { 242 blended_filter.set_zoom_inset( 243 std::max(gfx::Tween::LinearIntValueBetween( 244 from_op.zoom_inset(), to_op.zoom_inset(), progress), 245 0)); 246 } else if (to_op.type() == FilterOperation::ALPHA_THRESHOLD) { 247 blended_filter.set_outer_threshold(ClampAmountForFilterType( 248 gfx::Tween::FloatValueBetween(progress, 249 from_op.outer_threshold(), 250 to_op.outer_threshold()), 251 to_op.type())); 252 blended_filter.set_region(to_op.region()); 253 } 254 255 return blended_filter; 256 } 257 258 scoped_ptr<base::Value> FilterOperation::AsValue() const { 259 scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue); 260 value->SetInteger("type", type_); 261 switch (type_) { 262 case FilterOperation::GRAYSCALE: 263 case FilterOperation::SEPIA: 264 case FilterOperation::SATURATE: 265 case FilterOperation::HUE_ROTATE: 266 case FilterOperation::INVERT: 267 case FilterOperation::BRIGHTNESS: 268 case FilterOperation::CONTRAST: 269 case FilterOperation::OPACITY: 270 case FilterOperation::BLUR: 271 case FilterOperation::SATURATING_BRIGHTNESS: 272 value->SetDouble("amount", amount_); 273 break; 274 case FilterOperation::DROP_SHADOW: 275 value->SetDouble("std_deviation", amount_); 276 value->Set("offset", MathUtil::AsValue(drop_shadow_offset_).release()); 277 value->SetInteger("color", drop_shadow_color_); 278 break; 279 case FilterOperation::COLOR_MATRIX: { 280 scoped_ptr<base::ListValue> matrix(new base::ListValue); 281 for (size_t i = 0; i < arraysize(matrix_); ++i) 282 matrix->AppendDouble(matrix_[i]); 283 value->Set("matrix", matrix.release()); 284 break; 285 } 286 case FilterOperation::ZOOM: 287 value->SetDouble("amount", amount_); 288 value->SetDouble("inset", zoom_inset_); 289 break; 290 case FilterOperation::REFERENCE: { 291 int count_inputs = 0; 292 bool can_filter_image_gpu = false; 293 if (image_filter_) { 294 count_inputs = image_filter_->countInputs(); 295 can_filter_image_gpu = image_filter_->canFilterImageGPU(); 296 } 297 value->SetBoolean("is_null", !image_filter_); 298 value->SetInteger("count_inputs", count_inputs); 299 value->SetBoolean("can_filter_image_gpu", can_filter_image_gpu); 300 break; 301 } 302 case FilterOperation::ALPHA_THRESHOLD: { 303 value->SetDouble("inner_threshold", amount_); 304 value->SetDouble("outer_threshold", outer_threshold_); 305 scoped_ptr<base::ListValue> region_value(new base::ListValue()); 306 for (SkRegion::Iterator it(region_); !it.done(); it.next()) { 307 region_value->AppendInteger(it.rect().x()); 308 region_value->AppendInteger(it.rect().y()); 309 region_value->AppendInteger(it.rect().width()); 310 region_value->AppendInteger(it.rect().height()); 311 } 312 value->Set("region", region_value.release()); 313 } 314 break; 315 } 316 return value.PassAs<base::Value>(); 317 } 318 319 } // namespace cc 320