Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / cc / output / filter_operations.cc
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
12 namespace cc {
13
14 FilterOperations::FilterOperations() {}
15
16 FilterOperations::FilterOperations(const FilterOperations& other)
17     : operations_(other.operations_) {}
18
19 FilterOperations::~FilterOperations() {}
20
21 FilterOperations& FilterOperations::operator=(const FilterOperations& other) {
22   operations_ = other.operations_;
23   return *this;
24 }
25
26 bool 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
36 void FilterOperations::Append(const FilterOperation& filter) {
37   operations_.push_back(filter);
38 }
39
40 void FilterOperations::Clear() {
41   operations_.clear();
42 }
43
44 bool FilterOperations::IsEmpty() const {
45   return operations_.empty();
46 }
47
48 static 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
56 void 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
84 bool 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
112 bool 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
149 bool 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
157 FilterOperations 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
199 scoped_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