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 <cmath> 6 7 #include "cc/output/filter_operations.h" 8 9 #include "base/values.h" 10 #include "cc/output/filter_operation.h" 11 12 namespace cc { 13 14 FilterOperations::FilterOperations() {} 15 16 FilterOperations::FilterOperations(const FilterOperations& other) 17 : operations_(other.operations_) {} 18 19 FilterOperations::~FilterOperations() {} 20 21 FilterOperations& FilterOperations::operator=(const FilterOperations& other) { 22 operations_ = other.operations_; 23 return *this; 24 } 25 26 bool FilterOperations::operator==(const FilterOperations& other) const { 27 if (other.size() != size()) 28 return false; 29 for (size_t i = 0; i < size(); ++i) { 30 if (other.at(i) != at(i)) 31 return false; 32 } 33 return true; 34 } 35 36 void FilterOperations::Append(const FilterOperation& filter) { 37 operations_.push_back(filter); 38 } 39 40 void FilterOperations::Clear() { 41 operations_.clear(); 42 } 43 44 bool FilterOperations::IsEmpty() const { 45 return operations_.empty(); 46 } 47 48 static int SpreadForStdDeviation(float std_deviation) { 49 // https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#feGaussianBlurElement 50 // provides this approximation for evaluating a gaussian blur by a triple box 51 // filter. 52 float d = floorf(std_deviation * 3.f * sqrt(8.f * atan(1.f)) / 4.f + 0.5f); 53 return static_cast<int>(ceilf(d * 3.f / 2.f)); 54 } 55 56 void FilterOperations::GetOutsets(int* top, 57 int* right, 58 int* bottom, 59 int* left) const { 60 *top = *right = *bottom = *left = 0; 61 for (size_t i = 0; i < operations_.size(); ++i) { 62 const FilterOperation& op = operations_[i]; 63 // TODO(ajuma): Add support for reference filters once SkImageFilter 64 // reports its outsets. 65 DCHECK(op.type() != FilterOperation::REFERENCE); 66 if (op.type() == FilterOperation::BLUR || 67 op.type() == FilterOperation::DROP_SHADOW) { 68 int spread = SpreadForStdDeviation(op.amount()); 69 if (op.type() == FilterOperation::BLUR) { 70 *top += spread; 71 *right += spread; 72 *bottom += spread; 73 *left += spread; 74 } else { 75 *top += spread - op.drop_shadow_offset().y(); 76 *right += spread + op.drop_shadow_offset().x(); 77 *bottom += spread + op.drop_shadow_offset().y(); 78 *left += spread - op.drop_shadow_offset().x(); 79 } 80 } 81 } 82 } 83 84 bool FilterOperations::HasFilterThatMovesPixels() const { 85 for (size_t i = 0; i < operations_.size(); ++i) { 86 const FilterOperation& op = operations_[i]; 87 // TODO(ajuma): Once SkImageFilter reports its outsets, use those here to 88 // determine whether a reference filter really moves pixels. 89 switch (op.type()) { 90 case FilterOperation::BLUR: 91 case FilterOperation::DROP_SHADOW: 92 case FilterOperation::ZOOM: 93 case FilterOperation::REFERENCE: 94 return true; 95 case FilterOperation::OPACITY: 96 case FilterOperation::COLOR_MATRIX: 97 case FilterOperation::GRAYSCALE: 98 case FilterOperation::SEPIA: 99 case FilterOperation::SATURATE: 100 case FilterOperation::HUE_ROTATE: 101 case FilterOperation::INVERT: 102 case FilterOperation::BRIGHTNESS: 103 case FilterOperation::CONTRAST: 104 case FilterOperation::SATURATING_BRIGHTNESS: 105 break; 106 } 107 } 108 return false; 109 } 110 111 bool FilterOperations::HasFilterThatAffectsOpacity() const { 112 for (size_t i = 0; i < operations_.size(); ++i) { 113 const FilterOperation& op = operations_[i]; 114 // TODO(ajuma): Make this smarter for reference filters. Once SkImageFilter 115 // can report affectsOpacity(), call that. 116 switch (op.type()) { 117 case FilterOperation::OPACITY: 118 case FilterOperation::BLUR: 119 case FilterOperation::DROP_SHADOW: 120 case FilterOperation::ZOOM: 121 case FilterOperation::REFERENCE: 122 return true; 123 case FilterOperation::COLOR_MATRIX: { 124 const SkScalar* matrix = op.matrix(); 125 if (matrix[15] || 126 matrix[16] || 127 matrix[17] || 128 matrix[18] != 1 || 129 matrix[19]) 130 return true; 131 break; 132 } 133 case FilterOperation::GRAYSCALE: 134 case FilterOperation::SEPIA: 135 case FilterOperation::SATURATE: 136 case FilterOperation::HUE_ROTATE: 137 case FilterOperation::INVERT: 138 case FilterOperation::BRIGHTNESS: 139 case FilterOperation::CONTRAST: 140 case FilterOperation::SATURATING_BRIGHTNESS: 141 break; 142 } 143 } 144 return false; 145 } 146 147 bool FilterOperations::HasReferenceFilter() const { 148 for (size_t i = 0; i < operations_.size(); ++i) { 149 if (operations_[i].type() == FilterOperation::REFERENCE) 150 return true; 151 } 152 return false; 153 } 154 155 FilterOperations FilterOperations::Blend(const FilterOperations& from, 156 double progress) const { 157 if (HasReferenceFilter() || from.HasReferenceFilter()) 158 return *this; 159 160 bool from_is_longer = from.size() > size(); 161 162 size_t shorter_size, longer_size; 163 if (size() == from.size()) { 164 shorter_size = longer_size = size(); 165 } else if (from_is_longer) { 166 longer_size = from.size(); 167 shorter_size = size(); 168 } else { 169 longer_size = size(); 170 shorter_size = from.size(); 171 } 172 173 for (size_t i = 0; i < shorter_size; i++) { 174 if (from.at(i).type() != at(i).type()) 175 return *this; 176 } 177 178 FilterOperations blended_filters; 179 for (size_t i = 0; i < shorter_size; i++) { 180 blended_filters.Append( 181 FilterOperation::Blend(&from.at(i), &at(i), progress)); 182 } 183 184 if (from_is_longer) { 185 for (size_t i = shorter_size; i < longer_size; i++) { 186 blended_filters.Append( 187 FilterOperation::Blend(&from.at(i), NULL, progress)); 188 } 189 } else { 190 for (size_t i = shorter_size; i < longer_size; i++) 191 blended_filters.Append(FilterOperation::Blend(NULL, &at(i), progress)); 192 } 193 194 return blended_filters; 195 } 196 197 scoped_ptr<base::Value> FilterOperations::AsValue() const { 198 scoped_ptr<base::ListValue> value(new ListValue); 199 for (size_t i = 0; i < operations_.size(); ++i) 200 value->Append(operations_[i].AsValue().release()); 201 return value.PassAs<base::Value>(); 202 } 203 204 } // namespace cc 205