blob: 93c16c8d2525f4c06952f803662dbbba64c19562 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// 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/platform/geometry/calculation_value.h"
#include "base/memory/values_equivalent.h"
#include "third_party/blink/renderer/platform/geometry/blend.h"
#include "third_party/blink/renderer/platform/geometry/calculation_expression_node.h"
#include "third_party/blink/renderer/platform/wtf/size_assertions.h"
namespace blink {
// static
const CalculationValue* CalculationValue::CreateSimplified(
const CalculationExpressionNode* expression,
Length::ValueRange range) {
if (expression->IsPixelsAndPercent()) {
return MakeGarbageCollected<CalculationValue>(
To<CalculationExpressionPixelsAndPercentNode>(*expression)
.GetPixelsAndPercent(),
range);
}
return MakeGarbageCollected<CalculationValue>(PassKey(), expression, range);
}
CalculationValue::CalculationValue(PassKey,
const CalculationExpressionNode* expression,
Length::ValueRange range)
: expression_(expression),
is_non_negative_(range == Length::ValueRange::kNonNegative) {
CHECK(expression);
}
CalculationValue::~CalculationValue() = default;
void CalculationValue::Trace(Visitor* visitor) const {
visitor->Trace(expression_);
}
float CalculationValue::Evaluate(float max_value,
const EvaluationInput& input) const {
float value =
ClampTo<float>(expression_ ? expression_->Evaluate(max_value, input)
: Pixels() + Percent() / 100 * max_value);
return (IsNonNegative() && value < 0) ? 0 : value;
}
bool CalculationValue::operator==(const CalculationValue& other) const {
return value_.pixels == other.value_.pixels &&
value_.percent == other.value_.percent &&
base::ValuesEquivalent(expression_, other.expression_) &&
is_non_negative_ == other.is_non_negative_;
}
const CalculationExpressionNode* CalculationValue::GetOrCreateExpression()
const {
if (expression_) {
return expression_.Get();
}
return MakeGarbageCollected<CalculationExpressionPixelsAndPercentNode>(
GetPixelsAndPercent());
}
const CalculationValue* CalculationValue::Blend(
const CalculationValue& from,
double progress,
Length::ValueRange range) const {
if (!IsExpression() && !from.IsExpression()) {
PixelsAndPercent from_pixels_and_percent = from.GetPixelsAndPercent();
PixelsAndPercent to_pixels_and_percent = GetPixelsAndPercent();
const float pixels = blink::Blend(from_pixels_and_percent.pixels,
to_pixels_and_percent.pixels, progress);
const float percent = blink::Blend(from_pixels_and_percent.percent,
to_pixels_and_percent.percent, progress);
bool has_explicit_pixels = from_pixels_and_percent.has_explicit_pixels |
to_pixels_and_percent.has_explicit_pixels;
bool has_explicit_percent = from_pixels_and_percent.has_explicit_percent |
to_pixels_and_percent.has_explicit_percent;
return MakeGarbageCollected<CalculationValue>(
PixelsAndPercent(pixels, percent, has_explicit_pixels,
has_explicit_percent),
range);
}
const auto* blended_from =
CalculationExpressionOperationNode::CreateSimplified(
CalculationExpressionOperationNode::Children(
{from.GetOrCreateExpression(),
MakeGarbageCollected<CalculationExpressionNumberNode>(
1.0 - progress)}),
CalculationOperator::kMultiply);
const auto* blended_to = CalculationExpressionOperationNode::CreateSimplified(
CalculationExpressionOperationNode::Children(
{GetOrCreateExpression(),
MakeGarbageCollected<CalculationExpressionNumberNode>(progress)}),
CalculationOperator::kMultiply);
const auto* result_expression =
CalculationExpressionOperationNode::CreateSimplified(
{blended_from, blended_to}, CalculationOperator::kAdd);
return CreateSimplified(result_expression, range);
}
const CalculationValue* CalculationValue::SubtractFromOneHundredPercent()
const {
if (!IsExpression()) {
PixelsAndPercent result(-Pixels(), 100 - Percent(), HasExplicitPixels(),
/*has_explicit_percent=*/true);
return MakeGarbageCollected<CalculationValue>(result,
Length::ValueRange::kAll);
}
const auto* hundred_percent =
MakeGarbageCollected<CalculationExpressionPixelsAndPercentNode>(
PixelsAndPercent(0, 100, false, true));
const auto* result_expression =
CalculationExpressionOperationNode::CreateSimplified(
CalculationExpressionOperationNode::Children(
{hundred_percent, GetOrCreateExpression()}),
CalculationOperator::kSubtract);
return CreateSimplified(result_expression, Length::ValueRange::kAll);
}
const CalculationValue* CalculationValue::Add(
const CalculationValue& other) const {
const auto* result_expression =
CalculationExpressionOperationNode::CreateSimplified(
{GetOrCreateExpression(), other.GetOrCreateExpression()},
CalculationOperator::kAdd);
return CreateSimplified(result_expression, Length::ValueRange::kAll);
}
const CalculationValue* CalculationValue::Zoom(double factor) const {
if (expression_) {
return CreateSimplified(expression_->Zoom(factor), GetValueRange());
}
PixelsAndPercent result(Pixels() * factor, Percent(), HasExplicitPixels(),
HasExplicitPercent());
return MakeGarbageCollected<CalculationValue>(result, GetValueRange());
}
bool CalculationValue::HasAuto() const {
return expression_ && expression_->HasAuto();
}
bool CalculationValue::HasContentOrIntrinsicSize() const {
return expression_ && expression_->HasContentOrIntrinsicSize();
}
bool CalculationValue::HasAutoOrContentOrIntrinsicSize() const {
return expression_ && expression_->HasAutoOrContentOrIntrinsicSize();
}
bool CalculationValue::HasPercent() const {
if (expression_) {
return expression_->HasPercent();
}
return HasExplicitPercent();
}
bool CalculationValue::HasPercentOrStretch() const {
if (expression_) {
return expression_->HasPercentOrStretch();
}
return HasExplicitPercent();
}
bool CalculationValue::HasStretch() const {
return expression_ && expression_->HasStretch();
}
bool CalculationValue::HasMinContent() const {
// `HasContentOrIntrinsicSize` is comparatively faster than `HasMinContent`.
return expression_ && expression_->HasContentOrIntrinsicSize() &&
expression_->HasMinContent();
}
bool CalculationValue::HasMaxContent() const {
// `HasContentOrIntrinsicSize` is comparatively faster than `HasMaxContent`.
return expression_ && expression_->HasContentOrIntrinsicSize() &&
expression_->HasMaxContent();
}
bool CalculationValue::HasFitContent() const {
// `HasContentOrIntrinsicSize` is comparatively faster than `HasFitContent`.
return expression_ && expression_->HasContentOrIntrinsicSize() &&
expression_->HasFitContent();
}
bool CalculationValue::HasOnlyFixedAndPercent() const {
if (expression_) {
return !expression_->HasAutoOrContentOrIntrinsicSize() &&
!expression_->HasStretch();
}
return true;
}
} // namespace blink