summaryrefslogtreecommitdiffstats
path: root/cc
diff options
context:
space:
mode:
authorajuma@chromium.org <ajuma@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-17 04:45:58 +0000
committerajuma@chromium.org <ajuma@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-17 04:45:58 +0000
commit0449fc3ffdf27f391052e2f3ec2510c101c7b5b0 (patch)
tree62a87cad3918baac72c4382d1650ceafc5f6d3f5 /cc
parentfed734a145c6defbf1063b3b9a497aee88db720d (diff)
downloadchromium_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.h5
-rw-r--r--cc/output/filter_operation.cc154
-rw-r--r--cc/output/filter_operation.h10
-rw-r--r--cc/output/filter_operations.cc33
-rw-r--r--cc/output/filter_operations.h15
-rw-r--r--cc/output/filter_operations_unittest.cc486
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