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"
9 #include "base/trace_event/trace_event_argument.h"
10 #include "base/values.h"
11 #include "cc/output/filter_operation.h"
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_
;
27 bool FilterOperations::operator==(const FilterOperations
& other
) const {
28 if (other
.size() != size())
30 for (size_t i
= 0; i
< size(); ++i
) {
31 if (other
.at(i
) != at(i
))
37 void FilterOperations::Append(const FilterOperation
& filter
) {
38 operations_
.push_back(filter
);
41 void FilterOperations::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
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
,
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);
68 bool result
= op
.image_filter()->filterBounds(src
, SkMatrix::I(), &dst
);
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());
75 if (op
.type() == FilterOperation::BLUR
||
76 op
.type() == FilterOperation::DROP_SHADOW
) {
77 int spread
= SpreadForStdDeviation(op
.amount());
78 if (op
.type() == FilterOperation::BLUR
) {
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
];
98 case FilterOperation::BLUR
:
99 case FilterOperation::DROP_SHADOW
:
100 case FilterOperation::ZOOM
:
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.
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
:
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.
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
:
136 case FilterOperation::COLOR_MATRIX
: {
137 const SkScalar
* matrix
= op
.matrix();
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
:
160 bool FilterOperations::HasReferenceFilter() const {
161 for (size_t i
= 0; i
< operations_
.size(); ++i
) {
162 if (operations_
[i
].type() == FilterOperation::REFERENCE
)
168 FilterOperations
FilterOperations::Blend(const FilterOperations
& from
,
169 double progress
) const {
170 if (HasReferenceFilter() || from
.HasReferenceFilter())
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();
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())
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
));
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();