Landing Recent QUIC changes until 8/19/2015 17:00 UTC.
[chromium-blink-merge.git] / cc / output / filter_operations.cc
blob659acae64b0fa41e02080dce910e01bc3aa4ed9f
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.
5 #include "cc/output/filter_operations.h"
7 #include <cmath>
9 #include "base/trace_event/trace_event_argument.h"
10 #include "base/values.h"
11 #include "cc/output/filter_operation.h"
13 namespace cc {
15 FilterOperations::FilterOperations() {}
17 FilterOperations::FilterOperations(const FilterOperations& other)
18 : operations_(other.operations_) {}
20 FilterOperations::~FilterOperations() {}
22 FilterOperations& FilterOperations::operator=(const FilterOperations& other) {
23 operations_ = other.operations_;
24 return *this;
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;
34 return true;
37 void FilterOperations::Append(const FilterOperation& filter) {
38 operations_.push_back(filter);
41 void FilterOperations::Clear() {
42 operations_.clear();
45 bool FilterOperations::IsEmpty() const {
46 return operations_.empty();
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));
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(hendrikw): We should refactor some of this. See crbug.com/523534.
65 if (op.type() == FilterOperation::REFERENCE) {
66 SkIRect src = SkIRect::MakeWH(0, 0);
67 SkIRect dst;
68 bool result = op.image_filter()->filterBounds(src, SkMatrix::I(), &dst);
69 DCHECK(result);
70 *top += std::max(0, -dst.top());
71 *right += std::max(0, dst.right());
72 *bottom += std::max(0, dst.bottom());
73 *left += std::max(0, -dst.left());
74 } else {
75 if (op.type() == FilterOperation::BLUR ||
76 op.type() == FilterOperation::DROP_SHADOW) {
77 int spread = SpreadForStdDeviation(op.amount());
78 if (op.type() == FilterOperation::BLUR) {
79 *top += spread;
80 *right += spread;
81 *bottom += spread;
82 *left += spread;
83 } else {
84 *top += spread - op.drop_shadow_offset().y();
85 *right += spread + op.drop_shadow_offset().x();
86 *bottom += spread + op.drop_shadow_offset().y();
87 *left += spread - op.drop_shadow_offset().x();
94 bool FilterOperations::HasFilterThatMovesPixels() const {
95 for (size_t i = 0; i < operations_.size(); ++i) {
96 const FilterOperation& op = operations_[i];
97 switch (op.type()) {
98 case FilterOperation::BLUR:
99 case FilterOperation::DROP_SHADOW:
100 case FilterOperation::ZOOM:
101 return true;
102 case FilterOperation::REFERENCE:
103 // TODO(hendrikw): SkImageFilter needs a function that tells us if the
104 // filter can move pixels. See crbug.com/523538.
105 return true;
106 case FilterOperation::OPACITY:
107 case FilterOperation::COLOR_MATRIX:
108 case FilterOperation::GRAYSCALE:
109 case FilterOperation::SEPIA:
110 case FilterOperation::SATURATE:
111 case FilterOperation::HUE_ROTATE:
112 case FilterOperation::INVERT:
113 case FilterOperation::BRIGHTNESS:
114 case FilterOperation::CONTRAST:
115 case FilterOperation::SATURATING_BRIGHTNESS:
116 case FilterOperation::ALPHA_THRESHOLD:
117 break;
120 return false;
123 bool FilterOperations::HasFilterThatAffectsOpacity() const {
124 for (size_t i = 0; i < operations_.size(); ++i) {
125 const FilterOperation& op = operations_[i];
126 // TODO(ajuma): Make this smarter for reference filters. Once SkImageFilter
127 // can report affectsOpacity(), call that.
128 switch (op.type()) {
129 case FilterOperation::OPACITY:
130 case FilterOperation::BLUR:
131 case FilterOperation::DROP_SHADOW:
132 case FilterOperation::ZOOM:
133 case FilterOperation::REFERENCE:
134 case FilterOperation::ALPHA_THRESHOLD:
135 return true;
136 case FilterOperation::COLOR_MATRIX: {
137 const SkScalar* matrix = op.matrix();
138 if (matrix[15] ||
139 matrix[16] ||
140 matrix[17] ||
141 matrix[18] != 1 ||
142 matrix[19])
143 return true;
144 break;
146 case FilterOperation::GRAYSCALE:
147 case FilterOperation::SEPIA:
148 case FilterOperation::SATURATE:
149 case FilterOperation::HUE_ROTATE:
150 case FilterOperation::INVERT:
151 case FilterOperation::BRIGHTNESS:
152 case FilterOperation::CONTRAST:
153 case FilterOperation::SATURATING_BRIGHTNESS:
154 break;
157 return false;
160 bool FilterOperations::HasReferenceFilter() const {
161 for (size_t i = 0; i < operations_.size(); ++i) {
162 if (operations_[i].type() == FilterOperation::REFERENCE)
163 return true;
165 return false;
168 FilterOperations FilterOperations::Blend(const FilterOperations& from,
169 double progress) const {
170 if (HasReferenceFilter() || from.HasReferenceFilter())
171 return *this;
173 bool from_is_longer = from.size() > size();
175 size_t shorter_size, longer_size;
176 if (size() == from.size()) {
177 shorter_size = longer_size = size();
178 } else if (from_is_longer) {
179 longer_size = from.size();
180 shorter_size = size();
181 } else {
182 longer_size = size();
183 shorter_size = from.size();
186 for (size_t i = 0; i < shorter_size; i++) {
187 if (from.at(i).type() != at(i).type())
188 return *this;
191 FilterOperations blended_filters;
192 for (size_t i = 0; i < shorter_size; i++) {
193 blended_filters.Append(
194 FilterOperation::Blend(&from.at(i), &at(i), progress));
197 if (from_is_longer) {
198 for (size_t i = shorter_size; i < longer_size; i++) {
199 blended_filters.Append(
200 FilterOperation::Blend(&from.at(i), NULL, progress));
202 } else {
203 for (size_t i = shorter_size; i < longer_size; i++)
204 blended_filters.Append(FilterOperation::Blend(NULL, &at(i), progress));
207 return blended_filters;
210 void FilterOperations::AsValueInto(
211 base::trace_event::TracedValue* value) const {
212 for (size_t i = 0; i < operations_.size(); ++i) {
213 value->BeginDictionary();
214 operations_[i].AsValueInto(value);
215 value->EndDictionary();
219 } // namespace cc