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 13namespace cc { 14 15FilterOperations::FilterOperations() {} 16 17FilterOperations::FilterOperations(const FilterOperations& other) 18 : operations_(other.operations_) {} 19 20FilterOperations::~FilterOperations() {} 21 22FilterOperations& FilterOperations::operator=(const FilterOperations& other) { 23 operations_ = other.operations_; 24 return *this; 25} 26 27bool 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 37void FilterOperations::Append(const FilterOperation& filter) { 38 operations_.push_back(filter); 39} 40 41void FilterOperations::Clear() { 42 operations_.clear(); 43} 44 45bool FilterOperations::IsEmpty() const { 46 return operations_.empty(); 47} 48 49static 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 57void 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 85bool 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 113bool 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 150bool 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 158FilterOperations 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 200void 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