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 12namespace cc { 13 14FilterOperations::FilterOperations() {} 15 16FilterOperations::FilterOperations(const FilterOperations& other) 17 : operations_(other.operations_) {} 18 19FilterOperations::~FilterOperations() {} 20 21FilterOperations& FilterOperations::operator=(const FilterOperations& other) { 22 operations_ = other.operations_; 23 return *this; 24} 25 26bool 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 36void FilterOperations::Append(const FilterOperation& filter) { 37 operations_.push_back(filter); 38} 39 40void FilterOperations::Clear() { 41 operations_.clear(); 42} 43 44bool FilterOperations::IsEmpty() const { 45 return operations_.empty(); 46} 47 48static 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 56void 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 84bool 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 case FilterOperation::ALPHA_THRESHOLD: 106 break; 107 } 108 } 109 return false; 110} 111 112bool FilterOperations::HasFilterThatAffectsOpacity() const { 113 for (size_t i = 0; i < operations_.size(); ++i) { 114 const FilterOperation& op = operations_[i]; 115 // TODO(ajuma): Make this smarter for reference filters. Once SkImageFilter 116 // can report affectsOpacity(), call that. 117 switch (op.type()) { 118 case FilterOperation::OPACITY: 119 case FilterOperation::BLUR: 120 case FilterOperation::DROP_SHADOW: 121 case FilterOperation::ZOOM: 122 case FilterOperation::REFERENCE: 123 case FilterOperation::ALPHA_THRESHOLD: 124 return true; 125 case FilterOperation::COLOR_MATRIX: { 126 const SkScalar* matrix = op.matrix(); 127 if (matrix[15] || 128 matrix[16] || 129 matrix[17] || 130 matrix[18] != 1 || 131 matrix[19]) 132 return true; 133 break; 134 } 135 case FilterOperation::GRAYSCALE: 136 case FilterOperation::SEPIA: 137 case FilterOperation::SATURATE: 138 case FilterOperation::HUE_ROTATE: 139 case FilterOperation::INVERT: 140 case FilterOperation::BRIGHTNESS: 141 case FilterOperation::CONTRAST: 142 case FilterOperation::SATURATING_BRIGHTNESS: 143 break; 144 } 145 } 146 return false; 147} 148 149bool FilterOperations::HasReferenceFilter() const { 150 for (size_t i = 0; i < operations_.size(); ++i) { 151 if (operations_[i].type() == FilterOperation::REFERENCE) 152 return true; 153 } 154 return false; 155} 156 157FilterOperations FilterOperations::Blend(const FilterOperations& from, 158 double progress) const { 159 if (HasReferenceFilter() || from.HasReferenceFilter()) 160 return *this; 161 162 bool from_is_longer = from.size() > size(); 163 164 size_t shorter_size, longer_size; 165 if (size() == from.size()) { 166 shorter_size = longer_size = size(); 167 } else if (from_is_longer) { 168 longer_size = from.size(); 169 shorter_size = size(); 170 } else { 171 longer_size = size(); 172 shorter_size = from.size(); 173 } 174 175 for (size_t i = 0; i < shorter_size; i++) { 176 if (from.at(i).type() != at(i).type()) 177 return *this; 178 } 179 180 FilterOperations blended_filters; 181 for (size_t i = 0; i < shorter_size; i++) { 182 blended_filters.Append( 183 FilterOperation::Blend(&from.at(i), &at(i), progress)); 184 } 185 186 if (from_is_longer) { 187 for (size_t i = shorter_size; i < longer_size; i++) { 188 blended_filters.Append( 189 FilterOperation::Blend(&from.at(i), NULL, progress)); 190 } 191 } else { 192 for (size_t i = shorter_size; i < longer_size; i++) 193 blended_filters.Append(FilterOperation::Blend(NULL, &at(i), progress)); 194 } 195 196 return blended_filters; 197} 198 199scoped_ptr<base::Value> FilterOperations::AsValue() const { 200 scoped_ptr<base::ListValue> value(new base::ListValue); 201 for (size_t i = 0; i < operations_.size(); ++i) 202 value->Append(operations_[i].AsValue().release()); 203 return value.PassAs<base::Value>(); 204} 205 206} // namespace cc 207