// 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 #include "base/values.h" #include "cc/base/math_util.h" #include "cc/output/filter_operation.h" #include "third_party/skia/include/core/SkMath.h" #include "ui/gfx/animation/tween.h" namespace cc { bool FilterOperation::operator==(const FilterOperation& other) const { if (type_ != other.type_) return false; if (type_ == COLOR_MATRIX) return !memcmp(matrix_, other.matrix_, sizeof(matrix_)); if (type_ == DROP_SHADOW) { return amount_ == other.amount_ && drop_shadow_offset_ == other.drop_shadow_offset_ && drop_shadow_color_ == other.drop_shadow_color_; } if (type_ == REFERENCE) return image_filter_.get() == other.image_filter_.get(); if (type_ == ALPHA_THRESHOLD) { return region_ == other.region_ && amount_ == other.amount_ && outer_threshold_ == other.outer_threshold_; } return amount_ == other.amount_; } FilterOperation::FilterOperation(FilterType type, float amount) : type_(type), amount_(amount), outer_threshold_(0), drop_shadow_offset_(0, 0), drop_shadow_color_(0), zoom_inset_(0) { DCHECK_NE(type_, DROP_SHADOW); DCHECK_NE(type_, COLOR_MATRIX); DCHECK_NE(type_, REFERENCE); memset(matrix_, 0, sizeof(matrix_)); } FilterOperation::FilterOperation(FilterType type, const gfx::Point& offset, float stdDeviation, SkColor color) : type_(type), amount_(stdDeviation), outer_threshold_(0), drop_shadow_offset_(offset), drop_shadow_color_(color), zoom_inset_(0) { DCHECK_EQ(type_, DROP_SHADOW); memset(matrix_, 0, sizeof(matrix_)); } FilterOperation::FilterOperation(FilterType type, SkScalar matrix[20]) : type_(type), amount_(0), outer_threshold_(0), drop_shadow_offset_(0, 0), drop_shadow_color_(0), zoom_inset_(0) { DCHECK_EQ(type_, COLOR_MATRIX); memcpy(matrix_, matrix, sizeof(matrix_)); } FilterOperation::FilterOperation(FilterType type, float amount, int inset) : type_(type), amount_(amount), outer_threshold_(0), drop_shadow_offset_(0, 0), drop_shadow_color_(0), zoom_inset_(inset) { DCHECK_EQ(type_, ZOOM); memset(matrix_, 0, sizeof(matrix_)); } FilterOperation::FilterOperation( FilterType type, const skia::RefPtr& image_filter) : type_(type), amount_(0), outer_threshold_(0), drop_shadow_offset_(0, 0), drop_shadow_color_(0), image_filter_(image_filter), zoom_inset_(0) { DCHECK_EQ(type_, REFERENCE); memset(matrix_, 0, sizeof(matrix_)); } FilterOperation::FilterOperation(FilterType type, const SkRegion& region, float inner_threshold, float outer_threshold) : type_(type), amount_(inner_threshold), outer_threshold_(outer_threshold), drop_shadow_offset_(0, 0), drop_shadow_color_(0), zoom_inset_(0), region_(region) { DCHECK_EQ(type_, ALPHA_THRESHOLD); memset(matrix_, 0, sizeof(matrix_)); } FilterOperation::FilterOperation(const FilterOperation& other) : type_(other.type_), amount_(other.amount_), outer_threshold_(other.outer_threshold_), drop_shadow_offset_(other.drop_shadow_offset_), drop_shadow_color_(other.drop_shadow_color_), image_filter_(other.image_filter_), zoom_inset_(other.zoom_inset_), region_(other.region_) { memcpy(matrix_, other.matrix_, sizeof(matrix_)); } FilterOperation::~FilterOperation() { } static FilterOperation CreateNoOpFilter(FilterOperation::FilterType type) { switch (type) { case FilterOperation::GRAYSCALE: return FilterOperation::CreateGrayscaleFilter(0.f); case FilterOperation::SEPIA: return FilterOperation::CreateSepiaFilter(0.f); case FilterOperation::SATURATE: return FilterOperation::CreateSaturateFilter(1.f); case FilterOperation::HUE_ROTATE: return FilterOperation::CreateHueRotateFilter(0.f); case FilterOperation::INVERT: return FilterOperation::CreateInvertFilter(0.f); case FilterOperation::BRIGHTNESS: return FilterOperation::CreateBrightnessFilter(1.f); case FilterOperation::CONTRAST: return FilterOperation::CreateContrastFilter(1.f); case FilterOperation::OPACITY: return FilterOperation::CreateOpacityFilter(1.f); case FilterOperation::BLUR: return FilterOperation::CreateBlurFilter(0.f); case FilterOperation::DROP_SHADOW: return FilterOperation::CreateDropShadowFilter( gfx::Point(0, 0), 0.f, SK_ColorTRANSPARENT); case FilterOperation::COLOR_MATRIX: { SkScalar matrix[20]; memset(matrix, 0, 20 * sizeof(SkScalar)); matrix[0] = matrix[6] = matrix[12] = matrix[18] = 1.f; return FilterOperation::CreateColorMatrixFilter(matrix); } case FilterOperation::ZOOM: return FilterOperation::CreateZoomFilter(1.f, 0); case FilterOperation::SATURATING_BRIGHTNESS: return FilterOperation::CreateSaturatingBrightnessFilter(0.f); case FilterOperation::REFERENCE: return FilterOperation::CreateReferenceFilter( skia::RefPtr()); case FilterOperation::ALPHA_THRESHOLD: return FilterOperation::CreateAlphaThresholdFilter(SkRegion(), 1.f, 0.f); } NOTREACHED(); return FilterOperation::CreateEmptyFilter(); } static float ClampAmountForFilterType(float amount, FilterOperation::FilterType type) { switch (type) { case FilterOperation::GRAYSCALE: case FilterOperation::SEPIA: case FilterOperation::INVERT: case FilterOperation::OPACITY: case FilterOperation::ALPHA_THRESHOLD: return MathUtil::ClampToRange(amount, 0.f, 1.f); case FilterOperation::SATURATE: case FilterOperation::BRIGHTNESS: case FilterOperation::CONTRAST: case FilterOperation::BLUR: case FilterOperation::DROP_SHADOW: return std::max(amount, 0.f); case FilterOperation::ZOOM: return std::max(amount, 1.f); case FilterOperation::HUE_ROTATE: case FilterOperation::SATURATING_BRIGHTNESS: return amount; case FilterOperation::COLOR_MATRIX: case FilterOperation::REFERENCE: NOTREACHED(); return amount; } NOTREACHED(); return amount; } // static FilterOperation FilterOperation::Blend(const FilterOperation* from, const FilterOperation* to, double progress) { FilterOperation blended_filter = FilterOperation::CreateEmptyFilter(); if (!from && !to) return blended_filter; const FilterOperation& from_op = from ? *from : CreateNoOpFilter(to->type()); const FilterOperation& to_op = to ? *to : CreateNoOpFilter(from->type()); if (from_op.type() != to_op.type()) return blended_filter; DCHECK(to_op.type() != FilterOperation::COLOR_MATRIX); blended_filter.set_type(to_op.type()); if (to_op.type() == FilterOperation::REFERENCE) { if (progress > 0.5) blended_filter.set_image_filter(to_op.image_filter()); else blended_filter.set_image_filter(from_op.image_filter()); return blended_filter; } blended_filter.set_amount(ClampAmountForFilterType( gfx::Tween::FloatValueBetween(progress, from_op.amount(), to_op.amount()), to_op.type())); if (to_op.type() == FilterOperation::DROP_SHADOW) { gfx::Point blended_offset( gfx::Tween::LinearIntValueBetween(progress, from_op.drop_shadow_offset().x(), to_op.drop_shadow_offset().x()), gfx::Tween::LinearIntValueBetween(progress, from_op.drop_shadow_offset().y(), to_op.drop_shadow_offset().y())); blended_filter.set_drop_shadow_offset(blended_offset); blended_filter.set_drop_shadow_color(gfx::Tween::ColorValueBetween( progress, from_op.drop_shadow_color(), to_op.drop_shadow_color())); } else if (to_op.type() == FilterOperation::ZOOM) { blended_filter.set_zoom_inset( std::max(gfx::Tween::LinearIntValueBetween( from_op.zoom_inset(), to_op.zoom_inset(), progress), 0)); } else if (to_op.type() == FilterOperation::ALPHA_THRESHOLD) { blended_filter.set_outer_threshold(ClampAmountForFilterType( gfx::Tween::FloatValueBetween(progress, from_op.outer_threshold(), to_op.outer_threshold()), to_op.type())); blended_filter.set_region(to_op.region()); } return blended_filter; } scoped_ptr FilterOperation::AsValue() const { scoped_ptr value(new base::DictionaryValue); value->SetInteger("type", type_); switch (type_) { case FilterOperation::GRAYSCALE: case FilterOperation::SEPIA: case FilterOperation::SATURATE: case FilterOperation::HUE_ROTATE: case FilterOperation::INVERT: case FilterOperation::BRIGHTNESS: case FilterOperation::CONTRAST: case FilterOperation::OPACITY: case FilterOperation::BLUR: case FilterOperation::SATURATING_BRIGHTNESS: value->SetDouble("amount", amount_); break; case FilterOperation::DROP_SHADOW: value->SetDouble("std_deviation", amount_); value->Set("offset", MathUtil::AsValue(drop_shadow_offset_).release()); value->SetInteger("color", drop_shadow_color_); break; case FilterOperation::COLOR_MATRIX: { scoped_ptr matrix(new base::ListValue); for (size_t i = 0; i < arraysize(matrix_); ++i) matrix->AppendDouble(matrix_[i]); value->Set("matrix", matrix.release()); break; } case FilterOperation::ZOOM: value->SetDouble("amount", amount_); value->SetDouble("inset", zoom_inset_); break; case FilterOperation::REFERENCE: { int count_inputs = 0; bool can_filter_image_gpu = false; if (image_filter_) { count_inputs = image_filter_->countInputs(); can_filter_image_gpu = image_filter_->canFilterImageGPU(); } value->SetBoolean("is_null", !image_filter_); value->SetInteger("count_inputs", count_inputs); value->SetBoolean("can_filter_image_gpu", can_filter_image_gpu); break; } case FilterOperation::ALPHA_THRESHOLD: { value->SetDouble("inner_threshold", amount_); value->SetDouble("outer_threshold", outer_threshold_); scoped_ptr region_value(new base::ListValue()); for (SkRegion::Iterator it(region_); !it.done(); it.next()) { region_value->AppendInteger(it.rect().x()); region_value->AppendInteger(it.rect().y()); region_value->AppendInteger(it.rect().width()); region_value->AppendInteger(it.rect().height()); } value->Set("region", region_value.release()); } break; } return value.PassAs(); } } // namespace cc