blob: 91a602f957e9e596df5a4fc27d2782df7a042565 [file] [log] [blame]
// Copyright 2019 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 "third_party/blink/renderer/core/animation/interpolable_filter.h"
#include "third_party/blink/renderer/core/animation/interpolable_length.h"
#include "third_party/blink/renderer/core/animation/interpolable_shadow.h"
#include "third_party/blink/renderer/core/css/css_function_value.h"
#include "third_party/blink/renderer/core/css/css_identifier_value.h"
#include "third_party/blink/renderer/core/css/css_shadow_value.h"
#include "third_party/blink/renderer/core/css/css_value.h"
#include "third_party/blink/renderer/core/css/resolver/filter_operation_resolver.h"
#include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
namespace blink {
namespace {
double ClampParameter(double value, FilterOperation::OperationType type) {
switch (type) {
case FilterOperation::BRIGHTNESS:
case FilterOperation::CONTRAST:
case FilterOperation::SATURATE:
return clampTo<double>(value, 0);
case FilterOperation::GRAYSCALE:
case FilterOperation::INVERT:
case FilterOperation::OPACITY:
case FilterOperation::SEPIA:
return clampTo<double>(value, 0, 1);
case FilterOperation::HUE_ROTATE:
return value;
default:
NOTREACHED();
return 0;
}
}
} // namespace
// static
std::unique_ptr<InterpolableFilter> InterpolableFilter::MaybeCreate(
const FilterOperation& filter,
double zoom) {
std::unique_ptr<InterpolableValue> value = nullptr;
FilterOperation::OperationType type = filter.GetType();
switch (type) {
case FilterOperation::GRAYSCALE:
case FilterOperation::HUE_ROTATE:
case FilterOperation::SATURATE:
case FilterOperation::SEPIA:
value = std::make_unique<InterpolableNumber>(
To<BasicColorMatrixFilterOperation>(filter).Amount());
break;
case FilterOperation::BRIGHTNESS:
case FilterOperation::CONTRAST:
case FilterOperation::INVERT:
case FilterOperation::OPACITY:
value = std::make_unique<InterpolableNumber>(
To<BasicComponentTransferFilterOperation>(filter).Amount());
break;
case FilterOperation::BLUR:
value = InterpolableLength::MaybeConvertLength(
To<BlurFilterOperation>(filter).StdDeviation(), zoom);
break;
case FilterOperation::DROP_SHADOW:
value = InterpolableShadow::Create(
To<DropShadowFilterOperation>(filter).Shadow(), zoom);
break;
case FilterOperation::REFERENCE:
return nullptr;
default:
NOTREACHED();
return nullptr;
}
if (!value)
return nullptr;
return std::make_unique<InterpolableFilter>(std::move(value), type);
}
// static
std::unique_ptr<InterpolableFilter> InterpolableFilter::MaybeConvertCSSValue(
const CSSValue& css_value) {
if (css_value.IsURIValue())
return nullptr;
const auto& filter = To<CSSFunctionValue>(css_value);
DCHECK_LE(filter.length(), 1u);
std::unique_ptr<InterpolableValue> value = nullptr;
FilterOperation::OperationType type =
FilterOperationResolver::FilterOperationForType(filter.FunctionType());
switch (type) {
case FilterOperation::BRIGHTNESS:
case FilterOperation::CONTRAST:
case FilterOperation::GRAYSCALE:
case FilterOperation::INVERT:
case FilterOperation::OPACITY:
case FilterOperation::SATURATE:
case FilterOperation::SEPIA:
case FilterOperation::HUE_ROTATE:
value = std::make_unique<InterpolableNumber>(
FilterOperationResolver::ResolveNumericArgumentForFunction(filter));
break;
case FilterOperation::BLUR:
value = filter.length() > 0
? InterpolableLength::MaybeConvertCSSValue(filter.Item(0))
: InterpolableLength::CreateNeutral();
break;
case FilterOperation::DROP_SHADOW:
value = InterpolableShadow::MaybeConvertCSSValue(filter.Item(0));
break;
default:
NOTREACHED();
return nullptr;
}
if (!value)
return nullptr;
return std::make_unique<InterpolableFilter>(std::move(value), type);
}
// static
std::unique_ptr<InterpolableFilter> InterpolableFilter::CreateInitialValue(
FilterOperation::OperationType type) {
// See https://drafts.fxtf.org/filter-effects-1/#filter-functions for the
// mapping of OperationType to initial value.
std::unique_ptr<InterpolableValue> value = nullptr;
switch (type) {
case FilterOperation::GRAYSCALE:
case FilterOperation::INVERT:
case FilterOperation::SEPIA:
case FilterOperation::HUE_ROTATE:
value = std::make_unique<InterpolableNumber>(0);
break;
case FilterOperation::BRIGHTNESS:
case FilterOperation::CONTRAST:
case FilterOperation::OPACITY:
case FilterOperation::SATURATE:
value = std::make_unique<InterpolableNumber>(1);
break;
case FilterOperation::BLUR:
value = InterpolableLength::CreateNeutral();
break;
case FilterOperation::DROP_SHADOW:
value = InterpolableShadow::CreateNeutral();
break;
default:
NOTREACHED();
return nullptr;
}
return std::make_unique<InterpolableFilter>(std::move(value), type);
}
FilterOperation* InterpolableFilter::CreateFilterOperation(
const StyleResolverState& state) const {
switch (type_) {
case FilterOperation::GRAYSCALE:
case FilterOperation::HUE_ROTATE:
case FilterOperation::SATURATE:
case FilterOperation::SEPIA: {
double value =
ClampParameter(To<InterpolableNumber>(*value_).Value(), type_);
return MakeGarbageCollected<BasicColorMatrixFilterOperation>(value,
type_);
}
case FilterOperation::BRIGHTNESS:
case FilterOperation::CONTRAST:
case FilterOperation::INVERT:
case FilterOperation::OPACITY: {
double value =
ClampParameter(To<InterpolableNumber>(*value_).Value(), type_);
return MakeGarbageCollected<BasicComponentTransferFilterOperation>(value,
type_);
}
case FilterOperation::BLUR: {
Length std_deviation = To<InterpolableLength>(*value_).CreateLength(
state.CssToLengthConversionData(), kValueRangeNonNegative);
return MakeGarbageCollected<BlurFilterOperation>(std_deviation);
}
case FilterOperation::DROP_SHADOW: {
ShadowData shadow_data =
To<InterpolableShadow>(*value_).CreateShadowData(state);
if (shadow_data.GetColor().IsCurrentColor())
shadow_data.OverrideColor(Color::kBlack);
return MakeGarbageCollected<DropShadowFilterOperation>(shadow_data);
}
default:
NOTREACHED();
return nullptr;
}
}
void InterpolableFilter::Add(const InterpolableValue& other) {
value_->Add(*To<InterpolableFilter>(other).value_);
// The following types have an initial value of 1, so addition for them is
// one-based: result = value_ + other.value_ - 1
switch (type_) {
case FilterOperation::BRIGHTNESS:
case FilterOperation::CONTRAST:
case FilterOperation::GRAYSCALE:
case FilterOperation::INVERT:
case FilterOperation::OPACITY:
case FilterOperation::SATURATE:
case FilterOperation::SEPIA:
value_->Add(*std::make_unique<InterpolableNumber>(-1));
break;
default:
break;
}
}
void InterpolableFilter::AssertCanInterpolateWith(
const InterpolableValue& other) const {
const InterpolableFilter& other_filter = To<InterpolableFilter>(other);
value_->AssertCanInterpolateWith(*other_filter.value_);
DCHECK_EQ(type_, other_filter.type_);
}
void InterpolableFilter::Interpolate(const InterpolableValue& to,
const double progress,
InterpolableValue& result) const {
const InterpolableFilter& filter_to = To<InterpolableFilter>(to);
InterpolableFilter& filter_result = To<InterpolableFilter>(result);
value_->Interpolate(*filter_to.value_, progress, *filter_result.value_);
}
} // namespace blink