| Index: cc/output/filter_operations.cc
|
| diff --git a/cc/output/filter_operations.cc b/cc/output/filter_operations.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..92423de9b594b340130a1993557846408828145d
|
| --- /dev/null
|
| +++ b/cc/output/filter_operations.cc
|
| @@ -0,0 +1,209 @@
|
| +// Copyright 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "cc/output/filter_operations.h"
|
| +
|
| +#include <cmath>
|
| +
|
| +#include "base/trace_event/trace_event_argument.h"
|
| +#include "base/values.h"
|
| +#include "cc/output/filter_operation.h"
|
| +
|
| +namespace cc {
|
| +
|
| +FilterOperations::FilterOperations() {}
|
| +
|
| +FilterOperations::FilterOperations(const FilterOperations& other)
|
| + : operations_(other.operations_) {}
|
| +
|
| +FilterOperations::~FilterOperations() {}
|
| +
|
| +FilterOperations& FilterOperations::operator=(const FilterOperations& other) {
|
| + operations_ = other.operations_;
|
| + return *this;
|
| +}
|
| +
|
| +bool FilterOperations::operator==(const FilterOperations& other) const {
|
| + if (other.size() != size())
|
| + return false;
|
| + for (size_t i = 0; i < size(); ++i) {
|
| + if (other.at(i) != at(i))
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +void FilterOperations::Append(const FilterOperation& filter) {
|
| + operations_.push_back(filter);
|
| +}
|
| +
|
| +void FilterOperations::Clear() {
|
| + operations_.clear();
|
| +}
|
| +
|
| +bool FilterOperations::IsEmpty() const {
|
| + return operations_.empty();
|
| +}
|
| +
|
| +static int SpreadForStdDeviation(float std_deviation) {
|
| + // https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#feGaussianBlurElement
|
| + // provides this approximation for evaluating a gaussian blur by a triple box
|
| + // filter.
|
| + float d = floorf(std_deviation * 3.f * sqrt(8.f * atan(1.f)) / 4.f + 0.5f);
|
| + return static_cast<int>(ceilf(d * 3.f / 2.f));
|
| +}
|
| +
|
| +void FilterOperations::GetOutsets(int* top,
|
| + int* right,
|
| + int* bottom,
|
| + int* left) const {
|
| + *top = *right = *bottom = *left = 0;
|
| + for (size_t i = 0; i < operations_.size(); ++i) {
|
| + const FilterOperation& op = operations_[i];
|
| + // TODO(ajuma): Add support for reference filters once SkImageFilter
|
| + // reports its outsets.
|
| + DCHECK(op.type() != FilterOperation::REFERENCE);
|
| + if (op.type() == FilterOperation::BLUR ||
|
| + op.type() == FilterOperation::DROP_SHADOW) {
|
| + int spread = SpreadForStdDeviation(op.amount());
|
| + if (op.type() == FilterOperation::BLUR) {
|
| + *top += spread;
|
| + *right += spread;
|
| + *bottom += spread;
|
| + *left += spread;
|
| + } else {
|
| + *top += spread - op.drop_shadow_offset().y();
|
| + *right += spread + op.drop_shadow_offset().x();
|
| + *bottom += spread + op.drop_shadow_offset().y();
|
| + *left += spread - op.drop_shadow_offset().x();
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +bool FilterOperations::HasFilterThatMovesPixels() const {
|
| + for (size_t i = 0; i < operations_.size(); ++i) {
|
| + const FilterOperation& op = operations_[i];
|
| + // TODO(ajuma): Once SkImageFilter reports its outsets, use those here to
|
| + // determine whether a reference filter really moves pixels.
|
| + switch (op.type()) {
|
| + case FilterOperation::BLUR:
|
| + case FilterOperation::DROP_SHADOW:
|
| + case FilterOperation::ZOOM:
|
| + case FilterOperation::REFERENCE:
|
| + return true;
|
| + case FilterOperation::OPACITY:
|
| + case FilterOperation::COLOR_MATRIX:
|
| + case FilterOperation::GRAYSCALE:
|
| + case FilterOperation::SEPIA:
|
| + case FilterOperation::SATURATE:
|
| + case FilterOperation::HUE_ROTATE:
|
| + case FilterOperation::INVERT:
|
| + case FilterOperation::BRIGHTNESS:
|
| + case FilterOperation::CONTRAST:
|
| + case FilterOperation::SATURATING_BRIGHTNESS:
|
| + case FilterOperation::ALPHA_THRESHOLD:
|
| + break;
|
| + }
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +bool FilterOperations::HasFilterThatAffectsOpacity() const {
|
| + for (size_t i = 0; i < operations_.size(); ++i) {
|
| + const FilterOperation& op = operations_[i];
|
| + // TODO(ajuma): Make this smarter for reference filters. Once SkImageFilter
|
| + // can report affectsOpacity(), call that.
|
| + switch (op.type()) {
|
| + case FilterOperation::OPACITY:
|
| + case FilterOperation::BLUR:
|
| + case FilterOperation::DROP_SHADOW:
|
| + case FilterOperation::ZOOM:
|
| + case FilterOperation::REFERENCE:
|
| + case FilterOperation::ALPHA_THRESHOLD:
|
| + return true;
|
| + case FilterOperation::COLOR_MATRIX: {
|
| + const SkScalar* matrix = op.matrix();
|
| + if (matrix[15] ||
|
| + matrix[16] ||
|
| + matrix[17] ||
|
| + matrix[18] != 1 ||
|
| + matrix[19])
|
| + return true;
|
| + break;
|
| + }
|
| + case FilterOperation::GRAYSCALE:
|
| + case FilterOperation::SEPIA:
|
| + case FilterOperation::SATURATE:
|
| + case FilterOperation::HUE_ROTATE:
|
| + case FilterOperation::INVERT:
|
| + case FilterOperation::BRIGHTNESS:
|
| + case FilterOperation::CONTRAST:
|
| + case FilterOperation::SATURATING_BRIGHTNESS:
|
| + break;
|
| + }
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +bool FilterOperations::HasReferenceFilter() const {
|
| + for (size_t i = 0; i < operations_.size(); ++i) {
|
| + if (operations_[i].type() == FilterOperation::REFERENCE)
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +FilterOperations FilterOperations::Blend(const FilterOperations& from,
|
| + double progress) const {
|
| + if (HasReferenceFilter() || from.HasReferenceFilter())
|
| + return *this;
|
| +
|
| + bool from_is_longer = from.size() > size();
|
| +
|
| + size_t shorter_size, longer_size;
|
| + if (size() == from.size()) {
|
| + shorter_size = longer_size = size();
|
| + } else if (from_is_longer) {
|
| + longer_size = from.size();
|
| + shorter_size = size();
|
| + } else {
|
| + longer_size = size();
|
| + shorter_size = from.size();
|
| + }
|
| +
|
| + for (size_t i = 0; i < shorter_size; i++) {
|
| + if (from.at(i).type() != at(i).type())
|
| + return *this;
|
| + }
|
| +
|
| + FilterOperations blended_filters;
|
| + for (size_t i = 0; i < shorter_size; i++) {
|
| + blended_filters.Append(
|
| + FilterOperation::Blend(&from.at(i), &at(i), progress));
|
| + }
|
| +
|
| + if (from_is_longer) {
|
| + for (size_t i = shorter_size; i < longer_size; i++) {
|
| + blended_filters.Append(
|
| + FilterOperation::Blend(&from.at(i), NULL, progress));
|
| + }
|
| + } else {
|
| + for (size_t i = shorter_size; i < longer_size; i++)
|
| + blended_filters.Append(FilterOperation::Blend(NULL, &at(i), progress));
|
| + }
|
| +
|
| + return blended_filters;
|
| +}
|
| +
|
| +void FilterOperations::AsValueInto(
|
| + base::trace_event::TracedValue* value) const {
|
| + for (size_t i = 0; i < operations_.size(); ++i) {
|
| + value->BeginDictionary();
|
| + operations_[i].AsValueInto(value);
|
| + value->EndDictionary();
|
| + }
|
| +}
|
| +
|
| +} // namespace cc
|
|
|