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