blob: 51ff844e430eab7f3d2c0c2841428596886903f9 [file] [log] [blame]
/*
* Copyright (C) 2011, 2012 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_MATH_EXPRESSION_NODE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_MATH_EXPRESSION_NODE_H_
#include <optional>
#include "base/check_op.h"
#include "base/containers/enum_set.h"
#include "base/dcheck_is_on.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/css/css_anchor_query_enums.h"
#include "third_party/blink/renderer/core/css/css_length_resolver.h"
#include "third_party/blink/renderer/core/css/css_math_operator.h"
#include "third_party/blink/renderer/core/css/css_primitive_value.h"
#include "third_party/blink/renderer/core/css/css_value.h"
#include "third_party/blink/renderer/core/css/parser/css_parser_token_range.h"
#include "third_party/blink/renderer/core/css_value_keywords.h"
#include "third_party/blink/renderer/core/layout/geometry/axis.h"
#include "third_party/blink/renderer/platform/geometry/calculation_value.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
namespace blink {
static const int kMaxExpressionDepth = 100;
class CalculationExpressionNode;
class CSSNumericLiteralValue;
class CSSParserContext;
class TryTacticTransform;
class WritingDirectionMode;
// The order of this enum should not change since its elements are used as
// indices in the addSubtractResult matrix.
enum CalculationResultCategory {
kCalcNumber,
kCalcLength,
kCalcPercent,
// kCalcLengthFunction is used for calculated lengths that can't be resolved
// at style time. This includes mixes of length and percent, and also
// anchor queries and intrinsic size keywords in calc-size().
kCalcLengthFunction,
// kCalcIntrinsicSize is a special case of kCalcLengthFunction that is
// forbidden within most expression contexts.
kCalcIntrinsicSize,
kCalcAngle,
kCalcTime,
kCalcFrequency,
kCalcResolution,
kCalcIdent,
kCalcOther,
};
using CalculationResultCategorySet =
base::EnumSet<CalculationResultCategory,
CalculationResultCategory::kCalcNumber,
CalculationResultCategory::kCalcOther>;
class CORE_EXPORT CSSMathExpressionNode
: public GarbageCollected<CSSMathExpressionNode> {
public:
static CSSMathExpressionNode* Create(const CalculationValue& node);
static CSSMathExpressionNode* Create(PixelsAndPercent pixels_and_percent);
static CSSMathExpressionNode* Create(const CalculationExpressionNode& node);
enum class Flag : uint8_t {
AllowPercent,
AllowCalcSize,
AllowAutoInCalcSize,
MinValue = AllowPercent,
MaxValue = AllowAutoInCalcSize,
};
using Flags = base::EnumSet<Flag, Flag::MinValue, Flag::MaxValue>;
static CSSMathExpressionNode* ParseMathFunction(
CSSValueID function_id,
CSSParserTokenRange tokens,
const CSSParserContext&,
const Flags parsing_flags,
CSSAnchorQueryTypes allowed_anchor_queries,
// Variable substitutions for relative color syntax.
// https://www.w3.org/TR/css-color-5/#relative-colors
const HashMap<CSSValueID, double>& color_channel_keyword_values = {});
virtual CSSMathExpressionNode* Copy() const = 0;
virtual bool IsNumericLiteral() const { return false; }
virtual bool IsOperation() const { return false; }
virtual bool IsAnchorQuery() const { return false; }
virtual bool IsIdentifierLiteral() const { return false; }
virtual bool IsKeywordLiteral() const { return false; }
virtual bool IsMathFunction() const { return false; }
virtual bool IsZero() const = 0;
// Resolves the expression into one value *without doing any type conversion*.
// Hits DCHECK if type conversion is required.
virtual double DoubleValue() const = 0;
double ComputeNumber(const CSSLengthResolver& length_resolver) const {
return ComputeDouble(length_resolver);
}
virtual double ComputeLengthPx(const CSSLengthResolver&) const = 0;
virtual bool AccumulateLengthArray(CSSLengthArray&,
double multiplier) const = 0;
virtual void AccumulateLengthUnitTypes(
CSSPrimitiveValue::LengthTypeFlags& types) const = 0;
virtual scoped_refptr<const CalculationExpressionNode>
ToCalculationExpression(const CSSLengthResolver&) const = 0;
virtual std::optional<PixelsAndPercent> ToPixelsAndPercent(
const CSSLengthResolver&) const = 0;
scoped_refptr<const CalculationValue> ToCalcValue(
const CSSLengthResolver& length_resolver,
Length::ValueRange range,
bool allows_negative_percentage_reference) const;
// Evaluates the expression with type conversion (e.g., cm -> px) handled, and
// returns the result value in the canonical unit of the corresponding
// category (see https://www.w3.org/TR/css3-values/#canonical-unit).
// TODO(crbug.com/984372): We currently use 'ms' as the canonical unit of
// <time>. Switch to 's' to follow the spec.
// Returns |nullopt| on evaluation failures due to the following reasons:
// - The category doesn't have a canonical unit (e.g.,
// |kCalcLengthFunction|, |kCalcIntrinsicSize|).
// - A type conversion that doesn't have a fixed conversion ratio is needed
// (e.g., between 'px' and 'em').
// - There's an unsupported calculation, e.g., dividing two lengths.
virtual std::optional<double> ComputeValueInCanonicalUnit() const = 0;
virtual String CustomCSSText() const = 0;
virtual bool operator==(const CSSMathExpressionNode& other) const {
return category_ == other.category_;
}
virtual bool IsComputationallyIndependent() const = 0;
CalculationResultCategory Category() const { return category_; }
// HasPercentage returns whether the toplevel result type involves a
// percentage. In some cases a result type having a percentage requires
// different layout behavior (when there's nothing to resolve percentages
// against), so this needs to be tracked accurately. This examines the
// cases of kCalcLengthFunction or kCalcIntrinsicSize to determine whether
// it results from a percentage.
virtual bool HasPercentage() const { return Category() == kCalcPercent; }
// InvolvesLayout returns whether a percentage, an anchor query, or a
// calc-size() keyword is used anywhere in the value, including in contexts
// (such as the progress() function) that convert the result type of their
// arguments into a number.
virtual bool InvolvesLayout() const {
return Category() == kCalcPercent || Category() == kCalcLengthFunction ||
Category() == kCalcIntrinsicSize;
}
virtual bool InvolvesAnchorQueries() const { return IsAnchorQuery(); }
// Returns the unit type of the math expression *without doing any type
// conversion* (e.g., 1px + 1em needs type conversion to resolve).
// Returns |UnitType::kUnknown| if type conversion is required.
virtual CSSPrimitiveValue::UnitType ResolvedUnitType() const = 0;
bool IsNestedCalc() const { return is_nested_calc_; }
void SetIsNestedCalc() { is_nested_calc_ = true; }
bool HasComparisons() const { return has_comparisons_; }
bool IsScopedValue() const { return !needs_tree_scope_population_; }
const CSSMathExpressionNode& EnsureScopedValue(
const TreeScope* tree_scope) const {
if (!needs_tree_scope_population_) {
return *this;
}
return PopulateWithTreeScope(tree_scope);
}
virtual const CSSMathExpressionNode& PopulateWithTreeScope(
const TreeScope*) const = 0;
#if DCHECK_IS_ON()
// There's a subtle issue in comparing two percentages, e.g., min(10%, 20%).
// It doesn't always resolve into 10%, because the reference value may be
// negative. We use this to prevent comparing two percentages without knowing
// the sign of the reference value.
virtual bool InvolvesPercentageComparisons() const = 0;
#endif
// Rewrite this function according to the specified TryTacticTransform,
// e.g. anchor(left) -> anchor(right). If this function is not affected
// by the transform, returns `this`.
//
// See also TryTacticTransform.
virtual const CSSMathExpressionNode* TransformAnchors(
LogicalAxis,
const TryTacticTransform&,
const WritingDirectionMode&) const = 0;
virtual void Trace(Visitor* visitor) const {}
protected:
CSSMathExpressionNode(CalculationResultCategory category,
bool has_comparisons,
bool needs_tree_scope_population)
: category_(category),
has_comparisons_(has_comparisons),
needs_tree_scope_population_(needs_tree_scope_population) {
DCHECK_NE(category, kCalcOther);
}
virtual double ComputeDouble(
const CSSLengthResolver& length_resolver) const = 0;
static double ComputeDouble(const CSSMathExpressionNode* operand,
const CSSLengthResolver& length_resolver) {
return operand->ComputeDouble(length_resolver);
}
CalculationResultCategory category_;
bool is_nested_calc_ = false;
bool has_comparisons_;
bool needs_tree_scope_population_;
};
class CORE_EXPORT CSSMathExpressionNumericLiteral final
: public CSSMathExpressionNode {
public:
static CSSMathExpressionNumericLiteral* Create(
const CSSNumericLiteralValue* value);
static CSSMathExpressionNumericLiteral* Create(
double value,
CSSPrimitiveValue::UnitType type);
explicit CSSMathExpressionNumericLiteral(const CSSNumericLiteralValue* value);
CSSMathExpressionNode* Copy() const final { return Create(value_.Get()); }
const CSSNumericLiteralValue& GetValue() const { return *value_; }
bool IsNumericLiteral() const final { return true; }
const CSSMathExpressionNode& PopulateWithTreeScope(
const TreeScope* tree_scope) const final {
NOTREACHED();
return *this;
}
const CSSMathExpressionNode* TransformAnchors(
LogicalAxis,
const TryTacticTransform&,
const WritingDirectionMode&) const final {
return this;
}
bool IsZero() const final;
String CustomCSSText() const final;
scoped_refptr<const CalculationExpressionNode> ToCalculationExpression(
const CSSLengthResolver&) const final;
std::optional<PixelsAndPercent> ToPixelsAndPercent(
const CSSLengthResolver&) const final;
double DoubleValue() const final;
std::optional<double> ComputeValueInCanonicalUnit() const final;
double ComputeLengthPx(const CSSLengthResolver& length_resolver) const final;
bool AccumulateLengthArray(CSSLengthArray& length_array,
double multiplier) const final;
void AccumulateLengthUnitTypes(
CSSPrimitiveValue::LengthTypeFlags& types) const final;
bool IsComputationallyIndependent() const final;
bool operator==(const CSSMathExpressionNode& other) const final;
CSSPrimitiveValue::UnitType ResolvedUnitType() const final;
void Trace(Visitor* visitor) const final;
#if DCHECK_IS_ON()
bool InvolvesPercentageComparisons() const final;
#endif
protected:
double ComputeDouble(const CSSLengthResolver& length_resolver) const final;
private:
Member<const CSSNumericLiteralValue> value_;
};
template <>
struct DowncastTraits<CSSMathExpressionNumericLiteral> {
static bool AllowFrom(const CSSMathExpressionNode& node) {
return node.IsNumericLiteral();
}
};
// Used for container name in container-progress().
// Will possibly be used in container name for container units function.
class CORE_EXPORT CSSMathExpressionIdentifierLiteral final
: public CSSMathExpressionNode {
public:
static CSSMathExpressionIdentifierLiteral* Create(AtomicString identifier) {
return MakeGarbageCollected<CSSMathExpressionIdentifierLiteral>(
std::move(identifier));
}
explicit CSSMathExpressionIdentifierLiteral(AtomicString identifier);
CSSMathExpressionNode* Copy() const final { return Create(identifier_); }
const AtomicString& GetValue() const { return identifier_; }
bool IsIdentifierLiteral() const final { return true; }
const CSSMathExpressionNode& PopulateWithTreeScope(
const TreeScope* tree_scope) const final {
NOTREACHED();
return *this;
}
const CSSMathExpressionNode* TransformAnchors(
LogicalAxis,
const TryTacticTransform&,
const WritingDirectionMode&) const final {
return this;
}
bool IsZero() const final { return false; }
String CustomCSSText() const final { return identifier_; }
scoped_refptr<const CalculationExpressionNode> ToCalculationExpression(
const CSSLengthResolver&) const final;
std::optional<PixelsAndPercent> ToPixelsAndPercent(
const CSSLengthResolver&) const final {
return std::nullopt;
}
double DoubleValue() const final {
NOTREACHED();
return 0;
}
std::optional<double> ComputeValueInCanonicalUnit() const final {
return std::nullopt;
}
double ComputeLengthPx(const CSSLengthResolver& length_resolver) const final {
NOTREACHED();
return 0;
}
bool AccumulateLengthArray(CSSLengthArray& length_array,
double multiplier) const final {
return false;
}
void AccumulateLengthUnitTypes(
CSSPrimitiveValue::LengthTypeFlags& types) const final {}
bool IsComputationallyIndependent() const final { return true; }
bool operator==(const CSSMathExpressionNode& other) const final {
return other.IsIdentifierLiteral() &&
DynamicTo<CSSMathExpressionIdentifierLiteral>(other)->GetValue() ==
GetValue();
}
CSSPrimitiveValue::UnitType ResolvedUnitType() const final {
return CSSPrimitiveValue::UnitType::kIdent;
}
void Trace(Visitor* visitor) const final {
CSSMathExpressionNode::Trace(visitor);
}
#if DCHECK_IS_ON()
bool InvolvesPercentageComparisons() const final { return false; }
#endif
protected:
double ComputeDouble(const CSSLengthResolver& length_resolver) const final {
NOTREACHED();
return 0;
}
private:
AtomicString identifier_;
};
template <>
struct DowncastTraits<CSSMathExpressionIdentifierLiteral> {
static bool AllowFrom(const CSSMathExpressionNode& node) {
return node.IsIdentifierLiteral();
}
};
// Used for representation of the keywords, e.g. `size` keyword
// and intrinsic size keywords in calc-size(). Some of the keywords can
// be resolved to double with CSSLengthResolver.
class CORE_EXPORT CSSMathExpressionKeywordLiteral final
: public CSSMathExpressionNode {
public:
static CSSMathExpressionKeywordLiteral* Create(CSSValueID keyword,
CSSMathOperator op) {
return MakeGarbageCollected<CSSMathExpressionKeywordLiteral>(keyword, op);
}
CSSMathExpressionKeywordLiteral(CSSValueID keyword, CSSMathOperator op);
CSSMathExpressionNode* Copy() const final {
return Create(keyword_, operator_);
}
CSSValueID GetValue() const { return keyword_; }
CSSMathOperator GetOperator() const { return operator_; }
bool IsKeywordLiteral() const final { return true; }
const CSSMathExpressionNode& PopulateWithTreeScope(
const TreeScope* tree_scope) const final {
NOTREACHED();
return *this;
}
const CSSMathExpressionNode* TransformAnchors(
LogicalAxis,
const TryTacticTransform&,
const WritingDirectionMode&) const final {
return this;
}
bool IsZero() const final { return false; }
String CustomCSSText() const final { return getValueName(keyword_); }
scoped_refptr<const CalculationExpressionNode> ToCalculationExpression(
const CSSLengthResolver&) const final;
std::optional<PixelsAndPercent> ToPixelsAndPercent(
const CSSLengthResolver&) const final;
double DoubleValue() const final {
NOTREACHED();
return 0;
}
std::optional<double> ComputeValueInCanonicalUnit() const final {
return std::nullopt;
}
double ComputeLengthPx(const CSSLengthResolver& length_resolver) const final {
NOTREACHED();
return 0;
}
bool AccumulateLengthArray(CSSLengthArray& length_array,
double multiplier) const final {
return false;
}
void AccumulateLengthUnitTypes(
CSSPrimitiveValue::LengthTypeFlags& types) const final {}
bool IsComputationallyIndependent() const final { return true; }
bool operator==(const CSSMathExpressionNode& other) const final {
auto* other_keyword = DynamicTo<CSSMathExpressionKeywordLiteral>(other);
return other_keyword && other_keyword->GetValue() == GetValue() &&
other_keyword->GetOperator() == GetOperator();
}
CSSPrimitiveValue::UnitType ResolvedUnitType() const final {
return CSSPrimitiveValue::UnitType::kIdent;
}
void Trace(Visitor* visitor) const final {
CSSMathExpressionNode::Trace(visitor);
}
#if DCHECK_IS_ON()
bool InvolvesPercentageComparisons() const final { return false; }
#endif
protected:
double ComputeDouble(const CSSLengthResolver& length_resolver) const final;
private:
CSSValueID keyword_;
CSSMathOperator operator_;
};
template <>
struct DowncastTraits<CSSMathExpressionKeywordLiteral> {
static bool AllowFrom(const CSSMathExpressionNode& node) {
return node.IsKeywordLiteral();
}
};
class CORE_EXPORT CSSMathExpressionOperation final
: public CSSMathExpressionNode {
public:
using Operands = HeapVector<Member<const CSSMathExpressionNode>>;
static CSSMathExpressionNode* CreateArithmeticOperation(
const CSSMathExpressionNode* left_side,
const CSSMathExpressionNode* right_side,
CSSMathOperator op);
static CSSMathExpressionNode* CreateComparisonFunction(Operands&& operands,
CSSMathOperator op);
static CSSMathExpressionNode* CreateComparisonFunctionSimplified(
Operands&& operands,
CSSMathOperator op);
static CSSMathExpressionNode* CreateTrigonometricFunctionSimplified(
Operands&& operands,
CSSValueID function_id);
static CSSMathExpressionNode* CreateSteppedValueFunction(Operands&& operands,
CSSMathOperator op);
static CSSMathExpressionNode* CreateExponentialFunction(
Operands&& operands,
CSSValueID function_id);
static CSSMathExpressionNode* CreateArithmeticOperationSimplified(
const CSSMathExpressionNode* left_side,
const CSSMathExpressionNode* right_side,
CSSMathOperator op);
// In addition to the simplifications in
// CreateArithmeticOperationSimplified, this does simplifications of
// calc-size() that are invalid for parsing, but are useful for the
// animation code to do math on things involving calc-size() expressions
// while keeping the calc-size() expression at the top level. For example,
// calc(0.5 * calc-size(auto, size)) is not valid syntax, but this lets the
// animation code pass that multiplication to this function and have it turn
// into calc-size(auto, 0.5 * size).
static CSSMathExpressionNode* CreateArithmeticOperationAndSimplifyCalcSize(
const CSSMathExpressionNode* left_side,
const CSSMathExpressionNode* right_side,
CSSMathOperator op);
static CSSMathExpressionNode* CreateSignRelatedFunction(
Operands&& operands,
CSSValueID function_id);
static CSSMathExpressionNode* CreateCalcSizeOperation(
const CSSMathExpressionNode* left_side,
const CSSMathExpressionNode* right_side);
CSSMathExpressionOperation(const CSSMathExpressionNode* left_side,
const CSSMathExpressionNode* right_side,
CSSMathOperator op,
CalculationResultCategory category);
CSSMathExpressionOperation(CalculationResultCategory category,
Operands&& operands,
CSSMathOperator op);
CSSMathExpressionOperation(CalculationResultCategory category,
CSSMathOperator op);
CSSMathExpressionNode* Copy() const final {
Operands operands(operands_);
return MakeGarbageCollected<CSSMathExpressionOperation>(
category_, std::move(operands), operator_);
}
const Operands& GetOperands() const { return operands_; }
CSSMathOperator OperatorType() const { return operator_; }
bool IsOperation() const final { return true; }
bool IsAddOrSubtract() const {
return operator_ == CSSMathOperator::kAdd ||
operator_ == CSSMathOperator::kSubtract;
}
bool IsMultiplyOrDivide() const {
return operator_ == CSSMathOperator::kMultiply ||
operator_ == CSSMathOperator::kDivide;
}
bool AllOperandsAreNumeric() const;
bool IsMinOrMax() const {
return operator_ == CSSMathOperator::kMin ||
operator_ == CSSMathOperator::kMax;
}
bool IsClamp() const { return operator_ == CSSMathOperator::kClamp; }
bool IsRoundingStrategyKeyword() const {
return CSSMathOperator::kRoundNearest <= operator_ &&
operator_ <= CSSMathOperator::kRoundToZero && !operands_.size();
}
bool IsSteppedValueFunction() const {
return CSSMathOperator::kRoundNearest <= operator_ &&
operator_ <= CSSMathOperator::kRem;
}
bool IsTrigonometricFunction() const {
return operator_ == CSSMathOperator::kHypot;
}
bool IsSignRelatedFunction() const {
return operator_ == CSSMathOperator::kAbs ||
operator_ == CSSMathOperator::kSign;
}
bool IsCalcSize() const { return operator_ == CSSMathOperator::kCalcSize; }
bool IsProgressNotation() const {
return operator_ == CSSMathOperator::kProgress ||
operator_ == CSSMathOperator::kMediaProgress;
}
// TODO(crbug.com/1284199): Check other math functions too.
bool IsMathFunction() const final {
return IsMinOrMax() || IsClamp() || IsSteppedValueFunction() ||
IsTrigonometricFunction() || IsSignRelatedFunction() ||
IsCalcSize() || IsProgressNotation();
}
bool HasPercentage() const final;
bool InvolvesLayout() const final;
bool InvolvesAnchorQueries() const final;
String CSSTextAsClamp() const;
bool IsZero() const final;
scoped_refptr<const CalculationExpressionNode> ToCalculationExpression(
const CSSLengthResolver&) const final;
std::optional<PixelsAndPercent> ToPixelsAndPercent(
const CSSLengthResolver&) const final;
double DoubleValue() const final;
std::optional<double> ComputeValueInCanonicalUnit() const final;
double ComputeLengthPx(const CSSLengthResolver& length_resolver) const final;
bool AccumulateLengthArray(CSSLengthArray& length_array,
double multiplier) const final;
void AccumulateLengthUnitTypes(
CSSPrimitiveValue::LengthTypeFlags& types) const final;
bool IsComputationallyIndependent() const final;
String CustomCSSText() const final;
bool operator==(const CSSMathExpressionNode& exp) const final;
CSSPrimitiveValue::UnitType ResolvedUnitType() const final;
const CSSMathExpressionNode& PopulateWithTreeScope(
const TreeScope*) const final;
const CSSMathExpressionNode* TransformAnchors(
LogicalAxis,
const TryTacticTransform&,
const WritingDirectionMode&) const final;
void Trace(Visitor* visitor) const final;
#if DCHECK_IS_ON()
bool InvolvesPercentageComparisons() const final;
#endif
protected:
double ComputeDouble(const CSSLengthResolver& length_resolver) const final;
private:
static const CSSMathExpressionNode* GetNumericLiteralSide(
const CSSMathExpressionNode* left_side,
const CSSMathExpressionNode* right_side);
double Evaluate(const Vector<double>& operands) const {
return EvaluateOperator(operands, operator_);
}
static double EvaluateOperator(const Vector<double>& operands,
CSSMathOperator op);
// Helper for iterating from the 2nd to the last operands
base::span<const Member<const CSSMathExpressionNode>> SecondToLastOperands()
const {
return base::make_span(std::next(operands_.begin()), operands_.end());
}
Operands operands_;
const CSSMathOperator operator_;
};
template <>
struct DowncastTraits<CSSMathExpressionOperation> {
static bool AllowFrom(const CSSMathExpressionNode& node) {
return node.IsOperation();
}
};
// anchor() and anchor-size()
class CORE_EXPORT CSSMathExpressionAnchorQuery final
: public CSSMathExpressionNode {
public:
CSSMathExpressionAnchorQuery(CSSAnchorQueryType type,
const CSSValue* anchor_specifier,
const CSSValue& value,
const CSSPrimitiveValue* fallback);
CSSMathExpressionNode* Copy() const final {
return MakeGarbageCollected<CSSMathExpressionAnchorQuery>(
type_, anchor_specifier_, *value_, fallback_);
}
bool IsAnchor() const { return type_ == CSSAnchorQueryType::kAnchor; }
bool IsAnchorSize() const { return type_ == CSSAnchorQueryType::kAnchorSize; }
// TODO(crbug.com/1309178): This is not entirely correct, since "math
// function" should refer to functions defined in [1]. We may need to clean up
// the terminology in the code.
// [1] https://drafts.csswg.org/css-values-4/#math
bool IsMathFunction() const final { return true; }
bool IsAnchorQuery() const final { return true; }
bool IsZero() const final { return false; }
CSSPrimitiveValue::UnitType ResolvedUnitType() const final {
return CSSPrimitiveValue::UnitType::kUnknown;
}
std::optional<double> ComputeValueInCanonicalUnit() const final {
return std::nullopt;
}
std::optional<PixelsAndPercent> ToPixelsAndPercent(
const CSSLengthResolver&) const final {
return std::nullopt;
}
bool AccumulateLengthArray(CSSLengthArray& length_array,
double multiplier) const final {
return false;
}
bool IsComputationallyIndependent() const final { return false; }
double DoubleValue() const final;
double ComputeLengthPx(const CSSLengthResolver& length_resolver) const final;
void AccumulateLengthUnitTypes(
CSSPrimitiveValue::LengthTypeFlags& types) const final {
// AccumulateLengthUnitTypes() is only used when interpolating the
// 'transform' property, where anchor queries are not allowed.
NOTREACHED();
return;
}
String CustomCSSText() const final;
scoped_refptr<const CalculationExpressionNode> ToCalculationExpression(
const CSSLengthResolver&) const final;
bool operator==(const CSSMathExpressionNode& other) const final;
const CSSMathExpressionNode& PopulateWithTreeScope(
const TreeScope*) const final;
void Trace(Visitor* visitor) const final;
#if DCHECK_IS_ON()
bool InvolvesPercentageComparisons() const final { return false; }
#endif
const CSSMathExpressionNode* TransformAnchors(
LogicalAxis,
const TryTacticTransform&,
const WritingDirectionMode&) const final;
protected:
double ComputeDouble(const CSSLengthResolver&) const final;
private:
std::optional<LayoutUnit> EvaluateQuery(const AnchorQuery& query,
const CSSLengthResolver&) const;
AnchorQuery ToQuery(const CSSLengthResolver& length_resolver) const;
CSSAnchorQueryType type_;
Member<const CSSValue> anchor_specifier_;
Member<const CSSValue> value_;
Member<const CSSPrimitiveValue> fallback_;
};
template <>
struct DowncastTraits<CSSMathExpressionAnchorQuery> {
static bool AllowFrom(const CSSMathExpressionNode& node) {
return node.IsAnchorQuery();
}
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_MATH_EXPRESSION_NODE_H_