diff options
author | ajuma@chromium.org <ajuma@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-17 04:45:58 +0000 |
---|---|---|
committer | ajuma@chromium.org <ajuma@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-17 04:45:58 +0000 |
commit | 0449fc3ffdf27f391052e2f3ec2510c101c7b5b0 (patch) | |
tree | 62a87cad3918baac72c4382d1650ceafc5f6d3f5 /cc | |
parent | fed734a145c6defbf1063b3b9a497aee88db720d (diff) | |
download | chromium_src-0449fc3ffdf27f391052e2f3ec2510c101c7b5b0.zip chromium_src-0449fc3ffdf27f391052e2f3ec2510c101c7b5b0.tar.gz chromium_src-0449fc3ffdf27f391052e2f3ec2510c101c7b5b0.tar.bz2 |
Make cc::FilterOperations blendable
This adds the ability to interpolate between pairs of
cc::FilterOperations. This is needed for threading filter
animations.
BUG=181613
Review URL: https://chromiumcodereview.appspot.com/18690006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@211937 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc')
-rw-r--r-- | cc/base/math_util.h | 5 | ||||
-rw-r--r-- | cc/output/filter_operation.cc | 154 | ||||
-rw-r--r-- | cc/output/filter_operation.h | 10 | ||||
-rw-r--r-- | cc/output/filter_operations.cc | 33 | ||||
-rw-r--r-- | cc/output/filter_operations.h | 15 | ||||
-rw-r--r-- | cc/output/filter_operations_unittest.cc | 486 |
6 files changed, 702 insertions, 1 deletions
diff --git a/cc/base/math_util.h b/cc/base/math_util.h index 69dd8d8..cb158dd 100644 --- a/cc/base/math_util.h +++ b/cc/base/math_util.h @@ -5,6 +5,7 @@ #ifndef CC_BASE_MATH_UTIL_H_ #define CC_BASE_MATH_UTIL_H_ +#include <algorithm> #include <cmath> #include "base/logging.h" @@ -79,6 +80,10 @@ class CC_EXPORT MathUtil { return (d > 0.0) ? std::floor(d + 0.5) : std::ceil(d - 0.5); } + template <typename T> static T ClampToRange(T value, T min, T max) { + return std::min(std::max(value, min), max); + } + // Background: Existing transform code does not do the right thing in // MapRect / MapQuad / ProjectQuad when there is a perspective projection that // causes one of the transformed vertices to go to w < 0. In those cases, it diff --git a/cc/output/filter_operation.cc b/cc/output/filter_operation.cc index c3a76dc..de59cfc 100644 --- a/cc/output/filter_operation.cc +++ b/cc/output/filter_operation.cc @@ -2,7 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <algorithm> + +#include "cc/base/math_util.h" #include "cc/output/filter_operation.h" +#include "third_party/skia/include/core/SkMath.h" namespace cc { @@ -63,4 +67,154 @@ FilterOperation::FilterOperation(FilterType type, float amount, int inset) memset(matrix_, 0, sizeof(matrix_)); } +// TODO(ajuma): Define a version of ui::Tween::ValueBetween for floats, and use +// that instead. +static float BlendFloats(float from, float to, double progress) { + return from * (1.0 - progress) + to * progress; +} + +static int BlendInts(int from, int to, double progress) { + return static_cast<int>( + MathUtil::Round(from * (1.0 - progress) + to * progress)); +} + +static uint8_t BlendColorComponents(uint8_t from, + uint8_t to, + uint8_t from_alpha, + uint8_t to_alpha, + uint8_t blended_alpha, + double progress) { + // Since progress can be outside [0, 1], blending can produce a value outside + // [0, 255]. + int blended_premultiplied = BlendInts(SkMulDiv255Round(from, from_alpha), + SkMulDiv255Round(to, to_alpha), + progress); + int blended = static_cast<int>( + MathUtil::Round(blended_premultiplied * 255.f / blended_alpha)); + return static_cast<uint8_t>(MathUtil::ClampToRange(blended, 0, 255)); +} + +static SkColor BlendSkColors(SkColor from, SkColor to, double progress) { + int from_a = SkColorGetA(from); + int to_a = SkColorGetA(to); + int blended_a = BlendInts(from_a, to_a, progress); + if (blended_a <= 0) + return SkColorSetARGB(0, 0, 0, 0); + blended_a = std::min(blended_a, 255); + + // TODO(ajuma): Use SkFourByteInterp once http://crbug.com/260369 is fixed. + uint8_t blended_r = BlendColorComponents( + SkColorGetR(from), SkColorGetR(to), from_a, to_a, blended_a, progress); + uint8_t blended_g = BlendColorComponents( + SkColorGetG(from), SkColorGetG(to), from_a, to_a, blended_a, progress); + uint8_t blended_b = BlendColorComponents( + SkColorGetB(from), SkColorGetB(to), from_a, to_a, blended_a, progress); + + return SkColorSetARGB(blended_a, blended_r, blended_g, blended_b); +} + +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); + default: + 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: + 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: + default: + 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()); + + blended_filter.set_amount(ClampAmountForFilterType( + BlendFloats(from_op.amount(), to_op.amount(), progress), to_op.type())); + + if (to_op.type() == FilterOperation::DROP_SHADOW) { + gfx::Point blended_offset(BlendInts(from_op.drop_shadow_offset().x(), + to_op.drop_shadow_offset().x(), + progress), + BlendInts(from_op.drop_shadow_offset().y(), + to_op.drop_shadow_offset().y(), + progress)); + blended_filter.set_drop_shadow_offset(blended_offset); + blended_filter.set_drop_shadow_color(BlendSkColors( + from_op.drop_shadow_color(), to_op.drop_shadow_color(), progress)); + } else if (to_op.type() == FilterOperation::ZOOM) { + blended_filter.set_zoom_inset(std::max( + BlendInts(from_op.zoom_inset(), to_op.zoom_inset(), progress), 0)); + } + + return blended_filter; +} + } // namespace cc diff --git a/cc/output/filter_operation.h b/cc/output/filter_operation.h index 2168695..ad25cf4 100644 --- a/cc/output/filter_operation.h +++ b/cc/output/filter_operation.h @@ -151,6 +151,16 @@ class CC_EXPORT FilterOperation { zoom_inset_ = inset; } + // Given two filters of the same type, returns a filter operation created by + // linearly interpolating a |progress| fraction from |from| to |to|. If either + // |from| or |to| (but not both) is null, it is treated as a no-op filter of + // the same type as the other given filter. If both |from| and |to| are null, + // or if |from| and |to| are non-null but of different types, returns a + // no-op filter. + static FilterOperation Blend(const FilterOperation* from, + const FilterOperation* to, + double progress); + private: FilterOperation(FilterType type, float amount); diff --git a/cc/output/filter_operations.cc b/cc/output/filter_operations.cc index c722963..4331527 100644 --- a/cc/output/filter_operations.cc +++ b/cc/output/filter_operations.cc @@ -112,4 +112,37 @@ bool FilterOperations::HasFilterThatAffectsOpacity() const { return false; } +FilterOperations FilterOperations::Blend(const FilterOperations& from, + double progress) const { + FilterOperations blended_filters; + if (from.size() == 0) { + for (size_t i = 0; i < size(); i++) + blended_filters.Append(FilterOperation::Blend(NULL, &at(i), progress)); + return blended_filters; + } + + if (size() == 0) { + for (size_t i = 0; i < from.size(); i++) { + blended_filters.Append( + FilterOperation::Blend(&from.at(i), NULL, progress)); + } + return blended_filters; + } + + if (from.size() != size()) + return *this; + + for (size_t i = 0; i < size(); i++) { + if (from.at(i).type() != at(i).type()) + return *this; + } + + for (size_t i = 0; i < size(); i++) { + blended_filters.Append( + FilterOperation::Blend(&from.at(i), &at(i), progress)); + } + + return blended_filters; +} + } // namespace cc diff --git a/cc/output/filter_operations.h b/cc/output/filter_operations.h index 1b48662..d7198d1 100644 --- a/cc/output/filter_operations.h +++ b/cc/output/filter_operations.h @@ -44,11 +44,24 @@ class CC_EXPORT FilterOperations { return operations_.size(); } - FilterOperation at(size_t index) const { + const FilterOperation& at(size_t index) const { DCHECK_LT(index, size()); return operations_[index]; } + // If |from| is of the same size as this, where in each position, the filter + // in |from| is of the same type as the filter in this, returns a + // FilterOperations formed by linearly interpolating at each position a + // |progress| fraction of the way from the filter in |from| + // to the filter in this. If either |from| or this is an empty sequence, + // it is treated as a sequence of the same length as the other sequence, + // where the filter at each position is a no-op filter of the same type + // as the filter in that position in the other sequence. Otherwise, if + // both |from| and this are non-empty sequences but are either of different + // lengths or if there is a type mismatch at some position, returns a copy + // of this. + FilterOperations Blend(const FilterOperations& from, double progress) const; + private: std::vector<FilterOperation> operations_; }; diff --git a/cc/output/filter_operations_unittest.cc b/cc/output/filter_operations_unittest.cc index 4f88cae..dbf3736 100644 --- a/cc/output/filter_operations_unittest.cc +++ b/cc/output/filter_operations_unittest.cc @@ -138,5 +138,491 @@ TEST(FilterOperationsTest, SaveAndRestore) { SAVE_RESTORE_AMOUNT_INSET(Zoom, ZOOM, 0.5f, 32); } +TEST(FilterOperationsTest, BlendGrayscaleFilters) { + FilterOperation from = FilterOperation::CreateGrayscaleFilter(0.25f); + FilterOperation to = FilterOperation::CreateGrayscaleFilter(0.75f); + + FilterOperation blended = FilterOperation::Blend(&from, &to, -0.75); + FilterOperation expected = FilterOperation::CreateGrayscaleFilter(0.f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 0.75); + expected = FilterOperation::CreateGrayscaleFilter(0.625f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 1.8); + expected = FilterOperation::CreateGrayscaleFilter(1.f); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendGrayscaleWithNull) { + FilterOperation filter = FilterOperation::CreateGrayscaleFilter(1.f); + + FilterOperation blended = FilterOperation::Blend(&filter, NULL, 0.25); + FilterOperation expected = FilterOperation::CreateGrayscaleFilter(0.75f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(NULL, &filter, 0.25); + expected = FilterOperation::CreateGrayscaleFilter(0.25f); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendSepiaFilters) { + FilterOperation from = FilterOperation::CreateSepiaFilter(0.25f); + FilterOperation to = FilterOperation::CreateSepiaFilter(0.75f); + + FilterOperation blended = FilterOperation::Blend(&from, &to, -0.75); + FilterOperation expected = FilterOperation::CreateSepiaFilter(0.f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 0.75); + expected = FilterOperation::CreateSepiaFilter(0.625f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 1.8); + expected = FilterOperation::CreateSepiaFilter(1.f); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendSepiaWithNull) { + FilterOperation filter = FilterOperation::CreateSepiaFilter(1.f); + + FilterOperation blended = FilterOperation::Blend(&filter, NULL, 0.25); + FilterOperation expected = FilterOperation::CreateSepiaFilter(0.75f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(NULL, &filter, 0.25); + expected = FilterOperation::CreateSepiaFilter(0.25f); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendSaturateFilters) { + FilterOperation from = FilterOperation::CreateSaturateFilter(0.25f); + FilterOperation to = FilterOperation::CreateSaturateFilter(0.75f); + + FilterOperation blended = FilterOperation::Blend(&from, &to, -0.75); + FilterOperation expected = FilterOperation::CreateSaturateFilter(0.f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 0.75); + expected = FilterOperation::CreateSaturateFilter(0.625f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 2.0); + expected = FilterOperation::CreateSaturateFilter(1.25f); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendSaturateWithNull) { + FilterOperation filter = FilterOperation::CreateSaturateFilter(0.f); + + FilterOperation blended = FilterOperation::Blend(&filter, NULL, 0.25); + FilterOperation expected = FilterOperation::CreateSaturateFilter(0.25f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(NULL, &filter, 0.25); + expected = FilterOperation::CreateSaturateFilter(0.75f); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendHueRotateFilters) { + FilterOperation from = FilterOperation::CreateHueRotateFilter(3.f); + FilterOperation to = FilterOperation::CreateHueRotateFilter(7.f); + + FilterOperation blended = FilterOperation::Blend(&from, &to, -0.75); + FilterOperation expected = FilterOperation::CreateHueRotateFilter(0.f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 0.75); + expected = FilterOperation::CreateHueRotateFilter(6.f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 1.5); + expected = FilterOperation::CreateHueRotateFilter(9.f); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendHueRotateWithNull) { + FilterOperation filter = FilterOperation::CreateHueRotateFilter(1.f); + + FilterOperation blended = FilterOperation::Blend(&filter, NULL, 0.25); + FilterOperation expected = FilterOperation::CreateHueRotateFilter(0.75f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(NULL, &filter, 0.25); + expected = FilterOperation::CreateHueRotateFilter(0.25f); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendInvertFilters) { + FilterOperation from = FilterOperation::CreateInvertFilter(0.25f); + FilterOperation to = FilterOperation::CreateInvertFilter(0.75f); + + FilterOperation blended = FilterOperation::Blend(&from, &to, -0.75); + FilterOperation expected = FilterOperation::CreateInvertFilter(0.f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 0.75); + expected = FilterOperation::CreateInvertFilter(0.625f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 1.8); + expected = FilterOperation::CreateInvertFilter(1.f); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendInvertWithNull) { + FilterOperation filter = FilterOperation::CreateInvertFilter(1.f); + + FilterOperation blended = FilterOperation::Blend(&filter, NULL, 0.25); + FilterOperation expected = FilterOperation::CreateInvertFilter(0.75f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(NULL, &filter, 0.25); + expected = FilterOperation::CreateInvertFilter(0.25f); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendBrightnessFilters) { + FilterOperation from = FilterOperation::CreateBrightnessFilter(3.f); + FilterOperation to = FilterOperation::CreateBrightnessFilter(7.f); + + FilterOperation blended = FilterOperation::Blend(&from, &to, -0.9); + FilterOperation expected = FilterOperation::CreateBrightnessFilter(0.f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 0.75); + expected = FilterOperation::CreateBrightnessFilter(6.f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 1.5); + expected = FilterOperation::CreateBrightnessFilter(9.f); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendBrightnessWithNull) { + FilterOperation filter = FilterOperation::CreateBrightnessFilter(0.f); + + FilterOperation blended = FilterOperation::Blend(&filter, NULL, 0.25); + FilterOperation expected = FilterOperation::CreateBrightnessFilter(0.25f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(NULL, &filter, 0.25); + expected = FilterOperation::CreateBrightnessFilter(0.75f); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendContrastFilters) { + FilterOperation from = FilterOperation::CreateContrastFilter(3.f); + FilterOperation to = FilterOperation::CreateContrastFilter(7.f); + + FilterOperation blended = FilterOperation::Blend(&from, &to, -0.9); + FilterOperation expected = FilterOperation::CreateContrastFilter(0.f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 0.75); + expected = FilterOperation::CreateContrastFilter(6.f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 1.5); + expected = FilterOperation::CreateContrastFilter(9.f); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendContrastWithNull) { + FilterOperation filter = FilterOperation::CreateContrastFilter(0.f); + + FilterOperation blended = FilterOperation::Blend(&filter, NULL, 0.25); + FilterOperation expected = FilterOperation::CreateContrastFilter(0.25f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(NULL, &filter, 0.25); + expected = FilterOperation::CreateContrastFilter(0.75f); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendOpacityFilters) { + FilterOperation from = FilterOperation::CreateOpacityFilter(0.25f); + FilterOperation to = FilterOperation::CreateOpacityFilter(0.75f); + + FilterOperation blended = FilterOperation::Blend(&from, &to, -0.75); + FilterOperation expected = FilterOperation::CreateOpacityFilter(0.f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 0.75); + expected = FilterOperation::CreateOpacityFilter(0.625f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 1.8); + expected = FilterOperation::CreateOpacityFilter(1.f); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendOpacityWithNull) { + FilterOperation filter = FilterOperation::CreateOpacityFilter(0.f); + + FilterOperation blended = FilterOperation::Blend(&filter, NULL, 0.25); + FilterOperation expected = FilterOperation::CreateOpacityFilter(0.25f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(NULL, &filter, 0.25); + expected = FilterOperation::CreateOpacityFilter(0.75f); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendBlurFilters) { + FilterOperation from = FilterOperation::CreateBlurFilter(3.f); + FilterOperation to = FilterOperation::CreateBlurFilter(7.f); + + FilterOperation blended = FilterOperation::Blend(&from, &to, -0.9); + FilterOperation expected = FilterOperation::CreateBlurFilter(0.f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 0.75); + expected = FilterOperation::CreateBlurFilter(6.f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 1.5); + expected = FilterOperation::CreateBlurFilter(9.f); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendBlurWithNull) { + FilterOperation filter = FilterOperation::CreateBlurFilter(1.f); + + FilterOperation blended = FilterOperation::Blend(&filter, NULL, 0.25); + FilterOperation expected = FilterOperation::CreateBlurFilter(0.75f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(NULL, &filter, 0.25); + expected = FilterOperation::CreateBlurFilter(0.25f); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendDropShadowFilters) { + FilterOperation from = FilterOperation::CreateDropShadowFilter( + gfx::Point(0, 0), 2.f, SkColorSetARGB(15, 34, 68, 136)); + FilterOperation to = FilterOperation::CreateDropShadowFilter( + gfx::Point(3, 5), 6.f, SkColorSetARGB(51, 30, 60, 120)); + + FilterOperation blended = FilterOperation::Blend(&from, &to, -0.75); + FilterOperation expected = FilterOperation::CreateDropShadowFilter( + gfx::Point(-2, -4), 0.f, SkColorSetARGB(0, 0, 0, 0)); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 0.75); + expected = FilterOperation::CreateDropShadowFilter( + gfx::Point(2, 4), 5.f, SkColorSetARGB(42, 30, 61, 121)); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 1.5); + expected = FilterOperation::CreateDropShadowFilter( + gfx::Point(5, 8), 8.f, SkColorSetARGB(69, 30, 59, 118)); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendDropShadowWithNull) { + FilterOperation filter = FilterOperation::CreateDropShadowFilter( + gfx::Point(4, 4), 4.f, SkColorSetARGB(255, 40, 0, 0)); + + FilterOperation blended = FilterOperation::Blend(&filter, NULL, 0.25); + FilterOperation expected = FilterOperation::CreateDropShadowFilter( + gfx::Point(3, 3), 3.f, SkColorSetARGB(191, 40, 0, 0)); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(NULL, &filter, 0.25); + expected = FilterOperation::CreateDropShadowFilter( + gfx::Point(1, 1), 1.f, SkColorSetARGB(64, 40, 0, 0)); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendZoomFilters) { + FilterOperation from = FilterOperation::CreateZoomFilter(2.f, 3); + FilterOperation to = FilterOperation::CreateZoomFilter(6.f, 0); + + FilterOperation blended = FilterOperation::Blend(&from, &to, -0.75); + FilterOperation expected = FilterOperation::CreateZoomFilter(1.f, 5); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 0.75); + expected = FilterOperation::CreateZoomFilter(5.f, 1); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 1.5); + expected = FilterOperation::CreateZoomFilter(8.f, 0); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendZoomWithNull) { + FilterOperation filter = FilterOperation::CreateZoomFilter(2.f, 1); + + FilterOperation blended = FilterOperation::Blend(&filter, NULL, 0.25); + FilterOperation expected = FilterOperation::CreateZoomFilter(1.75f, 1); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(NULL, &filter, 0.25); + expected = FilterOperation::CreateZoomFilter(1.25f, 0); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendSaturatingBrightnessFilters) { + FilterOperation from = FilterOperation::CreateSaturatingBrightnessFilter(3.f); + FilterOperation to = FilterOperation::CreateSaturatingBrightnessFilter(7.f); + + FilterOperation blended = FilterOperation::Blend(&from, &to, -0.75); + FilterOperation expected = + FilterOperation::CreateSaturatingBrightnessFilter(0.f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 0.75); + expected = FilterOperation::CreateSaturatingBrightnessFilter(6.f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(&from, &to, 1.5); + expected = FilterOperation::CreateSaturatingBrightnessFilter(9.f); + EXPECT_EQ(expected, blended); +} + +TEST(FilterOperationsTest, BlendSaturatingBrightnessWithNull) { + FilterOperation filter = + FilterOperation::CreateSaturatingBrightnessFilter(1.f); + + FilterOperation blended = FilterOperation::Blend(&filter, NULL, 0.25); + FilterOperation expected = + FilterOperation::CreateSaturatingBrightnessFilter(0.75f); + EXPECT_EQ(expected, blended); + + blended = FilterOperation::Blend(NULL, &filter, 0.25); + expected = FilterOperation::CreateSaturatingBrightnessFilter(0.25f); + EXPECT_EQ(expected, blended); +} + +// Tests blending non-empty sequences that have the same length and matching +// operations. +TEST(FilterOperationsTest, BlendMatchingSequences) { + FilterOperations from; + FilterOperations to; + + from.Append(FilterOperation::CreateBlurFilter(0.f)); + to.Append(FilterOperation::CreateBlurFilter(2.f)); + + from.Append(FilterOperation::CreateSaturateFilter(4.f)); + to.Append(FilterOperation::CreateSaturateFilter(0.f)); + + from.Append(FilterOperation::CreateZoomFilter(2.0f, 1)); + to.Append(FilterOperation::CreateZoomFilter(10.f, 9)); + + FilterOperations blended = to.Blend(from, -0.75); + FilterOperations expected; + expected.Append(FilterOperation::CreateBlurFilter(0.f)); + expected.Append(FilterOperation::CreateSaturateFilter(7.f)); + expected.Append(FilterOperation::CreateZoomFilter(1.f, 0)); + EXPECT_EQ(blended, expected); + + blended = to.Blend(from, 0.75); + expected.Clear(); + expected.Append(FilterOperation::CreateBlurFilter(1.5f)); + expected.Append(FilterOperation::CreateSaturateFilter(1.f)); + expected.Append(FilterOperation::CreateZoomFilter(8.f, 7)); + EXPECT_EQ(blended, expected); + + blended = to.Blend(from, 1.5); + expected.Clear(); + expected.Append(FilterOperation::CreateBlurFilter(3.f)); + expected.Append(FilterOperation::CreateSaturateFilter(0.f)); + expected.Append(FilterOperation::CreateZoomFilter(14.f, 13)); + EXPECT_EQ(blended, expected); +} + +TEST(FilterOperationsTest, BlendEmptyAndNonEmptySequences) { + FilterOperations empty; + FilterOperations filters; + + filters.Append(FilterOperation::CreateGrayscaleFilter(0.75f)); + filters.Append(FilterOperation::CreateBrightnessFilter(2.f)); + filters.Append(FilterOperation::CreateHueRotateFilter(10.0f)); + + FilterOperations blended = empty.Blend(filters, -0.75); + FilterOperations expected; + expected.Append(FilterOperation::CreateGrayscaleFilter(1.f)); + expected.Append(FilterOperation::CreateBrightnessFilter(2.75f)); + expected.Append(FilterOperation::CreateHueRotateFilter(17.5f)); + EXPECT_EQ(blended, expected); + + blended = empty.Blend(filters, 0.75); + expected.Clear(); + expected.Append(FilterOperation::CreateGrayscaleFilter(0.1875f)); + expected.Append(FilterOperation::CreateBrightnessFilter(1.25f)); + expected.Append(FilterOperation::CreateHueRotateFilter(2.5f)); + EXPECT_EQ(blended, expected); + + blended = empty.Blend(filters, 1.5); + expected.Clear(); + expected.Append(FilterOperation::CreateGrayscaleFilter(0.f)); + expected.Append(FilterOperation::CreateBrightnessFilter(0.5f)); + expected.Append(FilterOperation::CreateHueRotateFilter(-5.f)); + EXPECT_EQ(blended, expected); + + blended = filters.Blend(empty, -0.75); + expected.Clear(); + expected.Append(FilterOperation::CreateGrayscaleFilter(0.f)); + expected.Append(FilterOperation::CreateBrightnessFilter(0.25f)); + expected.Append(FilterOperation::CreateHueRotateFilter(-7.5f)); + EXPECT_EQ(blended, expected); + + blended = filters.Blend(empty, 0.75); + expected.Clear(); + expected.Append(FilterOperation::CreateGrayscaleFilter(0.5625f)); + expected.Append(FilterOperation::CreateBrightnessFilter(1.75f)); + expected.Append(FilterOperation::CreateHueRotateFilter(7.5f)); + EXPECT_EQ(blended, expected); + + blended = filters.Blend(empty, 1.5); + expected.Clear(); + expected.Append(FilterOperation::CreateGrayscaleFilter(1.f)); + expected.Append(FilterOperation::CreateBrightnessFilter(2.5f)); + expected.Append(FilterOperation::CreateHueRotateFilter(15.f)); + EXPECT_EQ(blended, expected); +} + +TEST(FilterOperationsTest, BlendEmptySequences) { + FilterOperations empty; + + FilterOperations blended = empty.Blend(empty, -0.75); + EXPECT_EQ(blended, empty); + + blended = empty.Blend(empty, 0.75); + EXPECT_EQ(blended, empty); + + blended = empty.Blend(empty, 1.5); + EXPECT_EQ(blended, empty); +} + +// Tests blending non-empty sequences that either have different lengths or +// have non-matching operations. +TEST(FilterOperationsTest, BlendNonMatchingSequences) { + FilterOperations from; + FilterOperations to; + + from.Append(FilterOperation::CreateSaturateFilter(3.f)); + from.Append(FilterOperation::CreateBlurFilter(2.f)); + to.Append(FilterOperation::CreateSaturateFilter(4.f)); + + FilterOperations blended = to.Blend(from, -0.75); + EXPECT_EQ(to, blended); + blended = to.Blend(from, 0.75); + EXPECT_EQ(to, blended); + blended = to.Blend(from, 1.5); + EXPECT_EQ(to, blended); + + to.Append(FilterOperation::CreateHueRotateFilter(0.5f)); + blended = to.Blend(from, -0.75); + EXPECT_EQ(to, blended); + blended = to.Blend(from, 0.75); + EXPECT_EQ(to, blended); + blended = to.Blend(from, 1.5); + EXPECT_EQ(to, blended); +} + } // namespace } // namespace cc |