GPU workaround to simulate Out of Memory errors with large textures
[chromium-blink-merge.git] / cc / output / filter_operation.cc
blob1579e554a04be67b14c3565890c284e88fa3c365
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 <algorithm>
7 #include "base/trace_event/trace_event_argument.h"
8 #include "base/values.h"
9 #include "cc/base/math_util.h"
10 #include "cc/output/filter_operation.h"
11 #include "ui/gfx/animation/tween.h"
13 namespace cc {
15 bool FilterOperation::operator==(const FilterOperation& other) const {
16 if (type_ != other.type_)
17 return false;
18 if (type_ == COLOR_MATRIX)
19 return !memcmp(matrix_, other.matrix_, sizeof(matrix_));
20 if (type_ == DROP_SHADOW) {
21 return amount_ == other.amount_ &&
22 drop_shadow_offset_ == other.drop_shadow_offset_ &&
23 drop_shadow_color_ == other.drop_shadow_color_;
25 if (type_ == REFERENCE)
26 return image_filter_.get() == other.image_filter_.get();
27 if (type_ == ALPHA_THRESHOLD) {
28 return region_ == other.region_ &&
29 amount_ == other.amount_ &&
30 outer_threshold_ == other.outer_threshold_;
32 return amount_ == other.amount_;
35 FilterOperation::FilterOperation(FilterType type, float amount)
36 : type_(type),
37 amount_(amount),
38 outer_threshold_(0),
39 drop_shadow_offset_(0, 0),
40 drop_shadow_color_(0),
41 zoom_inset_(0) {
42 DCHECK_NE(type_, DROP_SHADOW);
43 DCHECK_NE(type_, COLOR_MATRIX);
44 DCHECK_NE(type_, REFERENCE);
45 memset(matrix_, 0, sizeof(matrix_));
48 FilterOperation::FilterOperation(FilterType type,
49 const gfx::Point& offset,
50 float stdDeviation,
51 SkColor color)
52 : type_(type),
53 amount_(stdDeviation),
54 outer_threshold_(0),
55 drop_shadow_offset_(offset),
56 drop_shadow_color_(color),
57 zoom_inset_(0) {
58 DCHECK_EQ(type_, DROP_SHADOW);
59 memset(matrix_, 0, sizeof(matrix_));
62 FilterOperation::FilterOperation(FilterType type, SkScalar matrix[20])
63 : type_(type),
64 amount_(0),
65 outer_threshold_(0),
66 drop_shadow_offset_(0, 0),
67 drop_shadow_color_(0),
68 zoom_inset_(0) {
69 DCHECK_EQ(type_, COLOR_MATRIX);
70 memcpy(matrix_, matrix, sizeof(matrix_));
73 FilterOperation::FilterOperation(FilterType type, float amount, int inset)
74 : type_(type),
75 amount_(amount),
76 outer_threshold_(0),
77 drop_shadow_offset_(0, 0),
78 drop_shadow_color_(0),
79 zoom_inset_(inset) {
80 DCHECK_EQ(type_, ZOOM);
81 memset(matrix_, 0, sizeof(matrix_));
84 FilterOperation::FilterOperation(
85 FilterType type,
86 const skia::RefPtr<SkImageFilter>& image_filter)
87 : type_(type),
88 amount_(0),
89 outer_threshold_(0),
90 drop_shadow_offset_(0, 0),
91 drop_shadow_color_(0),
92 image_filter_(image_filter),
93 zoom_inset_(0) {
94 DCHECK_EQ(type_, REFERENCE);
95 memset(matrix_, 0, sizeof(matrix_));
98 FilterOperation::FilterOperation(FilterType type,
99 const SkRegion& region,
100 float inner_threshold,
101 float outer_threshold)
102 : type_(type),
103 amount_(inner_threshold),
104 outer_threshold_(outer_threshold),
105 drop_shadow_offset_(0, 0),
106 drop_shadow_color_(0),
107 zoom_inset_(0),
108 region_(region) {
109 DCHECK_EQ(type_, ALPHA_THRESHOLD);
110 memset(matrix_, 0, sizeof(matrix_));
113 FilterOperation::FilterOperation(const FilterOperation& other)
114 : type_(other.type_),
115 amount_(other.amount_),
116 outer_threshold_(other.outer_threshold_),
117 drop_shadow_offset_(other.drop_shadow_offset_),
118 drop_shadow_color_(other.drop_shadow_color_),
119 image_filter_(other.image_filter_),
120 zoom_inset_(other.zoom_inset_),
121 region_(other.region_) {
122 memcpy(matrix_, other.matrix_, sizeof(matrix_));
125 FilterOperation::~FilterOperation() {
128 static FilterOperation CreateNoOpFilter(FilterOperation::FilterType type) {
129 switch (type) {
130 case FilterOperation::GRAYSCALE:
131 return FilterOperation::CreateGrayscaleFilter(0.f);
132 case FilterOperation::SEPIA:
133 return FilterOperation::CreateSepiaFilter(0.f);
134 case FilterOperation::SATURATE:
135 return FilterOperation::CreateSaturateFilter(1.f);
136 case FilterOperation::HUE_ROTATE:
137 return FilterOperation::CreateHueRotateFilter(0.f);
138 case FilterOperation::INVERT:
139 return FilterOperation::CreateInvertFilter(0.f);
140 case FilterOperation::BRIGHTNESS:
141 return FilterOperation::CreateBrightnessFilter(1.f);
142 case FilterOperation::CONTRAST:
143 return FilterOperation::CreateContrastFilter(1.f);
144 case FilterOperation::OPACITY:
145 return FilterOperation::CreateOpacityFilter(1.f);
146 case FilterOperation::BLUR:
147 return FilterOperation::CreateBlurFilter(0.f);
148 case FilterOperation::DROP_SHADOW:
149 return FilterOperation::CreateDropShadowFilter(
150 gfx::Point(0, 0), 0.f, SK_ColorTRANSPARENT);
151 case FilterOperation::COLOR_MATRIX: {
152 SkScalar matrix[20];
153 memset(matrix, 0, 20 * sizeof(SkScalar));
154 matrix[0] = matrix[6] = matrix[12] = matrix[18] = 1.f;
155 return FilterOperation::CreateColorMatrixFilter(matrix);
157 case FilterOperation::ZOOM:
158 return FilterOperation::CreateZoomFilter(1.f, 0);
159 case FilterOperation::SATURATING_BRIGHTNESS:
160 return FilterOperation::CreateSaturatingBrightnessFilter(0.f);
161 case FilterOperation::REFERENCE:
162 return FilterOperation::CreateReferenceFilter(
163 skia::RefPtr<SkImageFilter>());
164 case FilterOperation::ALPHA_THRESHOLD:
165 return FilterOperation::CreateAlphaThresholdFilter(SkRegion(), 1.f, 0.f);
167 NOTREACHED();
168 return FilterOperation::CreateEmptyFilter();
171 static float ClampAmountForFilterType(float amount,
172 FilterOperation::FilterType type) {
173 switch (type) {
174 case FilterOperation::GRAYSCALE:
175 case FilterOperation::SEPIA:
176 case FilterOperation::INVERT:
177 case FilterOperation::OPACITY:
178 case FilterOperation::ALPHA_THRESHOLD:
179 return MathUtil::ClampToRange(amount, 0.f, 1.f);
180 case FilterOperation::SATURATE:
181 case FilterOperation::BRIGHTNESS:
182 case FilterOperation::CONTRAST:
183 case FilterOperation::BLUR:
184 case FilterOperation::DROP_SHADOW:
185 return std::max(amount, 0.f);
186 case FilterOperation::ZOOM:
187 return std::max(amount, 1.f);
188 case FilterOperation::HUE_ROTATE:
189 case FilterOperation::SATURATING_BRIGHTNESS:
190 return amount;
191 case FilterOperation::COLOR_MATRIX:
192 case FilterOperation::REFERENCE:
193 NOTREACHED();
194 return amount;
196 NOTREACHED();
197 return amount;
200 // static
201 FilterOperation FilterOperation::Blend(const FilterOperation* from,
202 const FilterOperation* to,
203 double progress) {
204 FilterOperation blended_filter = FilterOperation::CreateEmptyFilter();
206 if (!from && !to)
207 return blended_filter;
209 const FilterOperation& from_op = from ? *from : CreateNoOpFilter(to->type());
210 const FilterOperation& to_op = to ? *to : CreateNoOpFilter(from->type());
212 if (from_op.type() != to_op.type())
213 return blended_filter;
215 DCHECK(to_op.type() != FilterOperation::COLOR_MATRIX);
216 blended_filter.set_type(to_op.type());
218 if (to_op.type() == FilterOperation::REFERENCE) {
219 if (progress > 0.5)
220 blended_filter.set_image_filter(to_op.image_filter());
221 else
222 blended_filter.set_image_filter(from_op.image_filter());
223 return blended_filter;
226 blended_filter.set_amount(ClampAmountForFilterType(
227 gfx::Tween::FloatValueBetween(progress, from_op.amount(), to_op.amount()),
228 to_op.type()));
230 if (to_op.type() == FilterOperation::DROP_SHADOW) {
231 gfx::Point blended_offset(
232 gfx::Tween::LinearIntValueBetween(progress,
233 from_op.drop_shadow_offset().x(),
234 to_op.drop_shadow_offset().x()),
235 gfx::Tween::LinearIntValueBetween(progress,
236 from_op.drop_shadow_offset().y(),
237 to_op.drop_shadow_offset().y()));
238 blended_filter.set_drop_shadow_offset(blended_offset);
239 blended_filter.set_drop_shadow_color(gfx::Tween::ColorValueBetween(
240 progress, from_op.drop_shadow_color(), to_op.drop_shadow_color()));
241 } else if (to_op.type() == FilterOperation::ZOOM) {
242 blended_filter.set_zoom_inset(
243 std::max(gfx::Tween::LinearIntValueBetween(
244 from_op.zoom_inset(), to_op.zoom_inset(), progress),
245 0));
246 } else if (to_op.type() == FilterOperation::ALPHA_THRESHOLD) {
247 blended_filter.set_outer_threshold(ClampAmountForFilterType(
248 gfx::Tween::FloatValueBetween(progress,
249 from_op.outer_threshold(),
250 to_op.outer_threshold()),
251 to_op.type()));
252 blended_filter.set_region(to_op.region());
255 return blended_filter;
258 void FilterOperation::AsValueInto(base::trace_event::TracedValue* value) const {
259 value->SetInteger("type", type_);
260 switch (type_) {
261 case FilterOperation::GRAYSCALE:
262 case FilterOperation::SEPIA:
263 case FilterOperation::SATURATE:
264 case FilterOperation::HUE_ROTATE:
265 case FilterOperation::INVERT:
266 case FilterOperation::BRIGHTNESS:
267 case FilterOperation::CONTRAST:
268 case FilterOperation::OPACITY:
269 case FilterOperation::BLUR:
270 case FilterOperation::SATURATING_BRIGHTNESS:
271 value->SetDouble("amount", amount_);
272 break;
273 case FilterOperation::DROP_SHADOW:
274 value->SetDouble("std_deviation", amount_);
275 MathUtil::AddToTracedValue("offset", drop_shadow_offset_, value);
276 value->SetInteger("color", drop_shadow_color_);
277 break;
278 case FilterOperation::COLOR_MATRIX: {
279 value->BeginArray("matrix");
280 for (size_t i = 0; i < arraysize(matrix_); ++i)
281 value->AppendDouble(matrix_[i]);
282 value->EndArray();
283 break;
285 case FilterOperation::ZOOM:
286 value->SetDouble("amount", amount_);
287 value->SetDouble("inset", zoom_inset_);
288 break;
289 case FilterOperation::REFERENCE: {
290 int count_inputs = 0;
291 bool can_filter_image_gpu = false;
292 if (image_filter_) {
293 count_inputs = image_filter_->countInputs();
294 can_filter_image_gpu = image_filter_->canFilterImageGPU();
296 value->SetBoolean("is_null", !image_filter_);
297 value->SetInteger("count_inputs", count_inputs);
298 value->SetBoolean("can_filter_image_gpu", can_filter_image_gpu);
299 break;
301 case FilterOperation::ALPHA_THRESHOLD: {
302 value->SetDouble("inner_threshold", amount_);
303 value->SetDouble("outer_threshold", outer_threshold_);
304 scoped_ptr<base::ListValue> region_value(new base::ListValue());
305 value->BeginArray("region");
306 for (SkRegion::Iterator it(region_); !it.done(); it.next()) {
307 value->AppendInteger(it.rect().x());
308 value->AppendInteger(it.rect().y());
309 value->AppendInteger(it.rect().width());
310 value->AppendInteger(it.rect().height());
312 value->EndArray();
314 break;
318 } // namespace cc