blob: de49729d87b2abdd9911027971ef9f05678ec687 [file]
/*
* (C) 1999-2003 Lars Knoll (knoll@kde.org)
* Copyright (C) 2004-2023 Apple Inc. All rights reserved.
* Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
* Copyright (C) 2026 Samuel Weinig <sam@webkit.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include <WebCore/CSSPrimitiveNumericRaw.h>
#include <WebCore/CSSUnevaluatedCalc.h>
#include <WebCore/CSSValue.h>
#include <utility>
#include <wtf/Forward.h>
namespace WebCore {
class CSSToLengthConversionData;
class DeprecatedCSSOMPrimitiveValue;
class FontCascade;
class RenderView;
template<typename> class ExceptionOr;
class CSSPrimitiveValue final : public CSSValue {
public:
// FIXME: Some of these use primitiveUnitType() and some use NODELETE primitiveType(). Many that use primitiveUnitType() are likely broken with calc().
bool isAngle() const { return unitCategory(primitiveType()) == CSSUnitCategory::Angle; }
bool isFontIndependentLength() const { return isFontIndependentLength(primitiveUnitType()); }
bool isFontRelativeLength() const { return isFontRelativeLength(primitiveUnitType()); }
bool isParentFontRelativeLength() const { return isParentFontRelativeLength(primitiveUnitType()); }
bool isPercentageOrParentFontRelativeLength() const { return isPercentage() || isParentFontRelativeLength(); }
bool isRootFontRelativeLength() const { return isRootFontRelativeLength(primitiveUnitType()); }
bool isLength() const { return isLength(static_cast<CSSUnitType>(primitiveType())); }
bool isNumber() const { return primitiveType() == CSSUnitType::Number; }
bool isInteger() const { return primitiveType() == CSSUnitType::Integer; }
bool isNumberOrInteger() const { return isNumber() || isInteger(); }
bool isPercentage() const { return primitiveType() == CSSUnitType::Percentage; }
bool isPx() const { return primitiveType() == CSSUnitType::Px; }
bool isCalculated() const { return primitiveUnitType() == CSSUnitType::Calc; }
bool isCalculatedPercentageWithLength() const { return primitiveType() == CSSUnitType::CalcPercentageWithLength; }
bool isFlex() const { return primitiveType() == CSSUnitType::Fr; }
static Ref<CSSPrimitiveValue> create(double);
static Ref<CSSPrimitiveValue> create(double, CSSUnitType);
static Ref<CSSPrimitiveValue> NODELETE createInteger(double);
static Ref<CSSPrimitiveValue> create(CSS::UnevaluatedCalcBase);
~CSSPrimitiveValue();
CSSUnitType primitiveType() const;
using Calc = CSS::UnevaluatedCalcBase;
using Raw = CSS::UnconstrainedPrimitiveNumericRaw;
template<typename... F> decltype(auto) switchOn(F&&... f) const
{
auto visitor = WTF::makeVisitor(std::forward<F>(f)...);
if (isCalculated())
SUPPRESS_FORWARD_DECL_ARG return visitor(Calc { const_cast<CSSCalc::Value&>(*m_value.calc) });
return visitor(Raw { primitiveUnitType(), m_value.number });
}
std::optional<Raw> raw() const { return !isCalculated() ? std::optional { Raw { primitiveUnitType(), m_value.number } } : std::nullopt; }
// These return nullopt for calc, for which range checking is not done at parse time: <https://www.w3.org/TR/css3-values/#calc-range>.
std::optional<bool> NODELETE isZero() const;
std::optional<bool> NODELETE isOne() const;
std::optional<bool> NODELETE isPositive() const;
std::optional<bool> NODELETE isNegative() const;
String customCSSText(const CSS::SerializationContext&) const;
bool equals(const CSSPrimitiveValue&) const;
void collectComputedStyleDependencies(ComputedStyleDependencies&) const;
Ref<DeprecatedCSSOMValue> customCreateDeprecatedCSSOMWrapper(CSSStyleDeclaration&) const;
private:
friend class CSSValuePool;
friend class StaticCSSValuePool;
friend LazyNeverDestroyed<CSSPrimitiveValue>;
friend bool CSSValue::addHash(Hasher&) const;
CSSPrimitiveValue(const String&, CSSUnitType);
CSSPrimitiveValue(double, CSSUnitType);
CSSPrimitiveValue(StaticCSSValueTag, double, CSSUnitType);
CSSPrimitiveValue(CSS::UnevaluatedCalcBase&&);
CSSUnitType primitiveUnitType() const { return static_cast<CSSUnitType>(m_primitiveUnitType); }
void setPrimitiveUnitType(CSSUnitType type) { m_primitiveUnitType = std::to_underlying(type); }
bool NODELETE addDerivedHash(Hasher&) const;
ALWAYS_INLINE String serializeInternal(const CSS::SerializationContext&) const;
NEVER_INLINE String formatNumberValue(ASCIILiteral suffix) const;
NEVER_INLINE String formatIntegerValue(ASCIILiteral suffix) const;
static constexpr bool isLength(CSSUnitType);
static constexpr bool isFontIndependentLength(CSSUnitType);
static constexpr bool isFontRelativeLength(CSSUnitType);
static constexpr bool isParentFontRelativeLength(CSSUnitType);
static constexpr bool isRootFontRelativeLength(CSSUnitType);
static constexpr bool isContainerPercentageLength(CSSUnitType);
static constexpr bool isViewportPercentageLength(CSSUnitType);
const CSSCalc::Value* cssCalcValue() const { return isCalculated() ? m_value.calc : nullptr; }
union {
double number;
const CSSCalc::Value* calc;
} m_value;
};
constexpr bool CSSPrimitiveValue::isFontIndependentLength(CSSUnitType type)
{
return type == CSSUnitType::Px
|| type == CSSUnitType::Cm
|| type == CSSUnitType::Mm
|| type == CSSUnitType::In
|| type == CSSUnitType::Pt
|| type == CSSUnitType::Pc;
}
constexpr bool CSSPrimitiveValue::isParentFontRelativeLength(CSSUnitType type)
{
return type == CSSUnitType::Em
|| type == CSSUnitType::Ex
|| type == CSSUnitType::Lh
|| type == CSSUnitType::Cap
|| type == CSSUnitType::Ch
|| type == CSSUnitType::Ic
|| type == CSSUnitType::QuirkyEm;
}
constexpr bool CSSPrimitiveValue::isRootFontRelativeLength(CSSUnitType type)
{
return type == CSSUnitType::Rcap
|| type == CSSUnitType::Rch
|| type == CSSUnitType::Rem
|| type == CSSUnitType::Rex
|| type == CSSUnitType::Ric
|| type == CSSUnitType::Rlh;
}
constexpr bool CSSPrimitiveValue::isFontRelativeLength(CSSUnitType type)
{
return isParentFontRelativeLength(type)
|| isRootFontRelativeLength(type);
}
constexpr bool CSSPrimitiveValue::isContainerPercentageLength(CSSUnitType type)
{
return type == CSSUnitType::Cqw
|| type == CSSUnitType::Cqh
|| type == CSSUnitType::Cqi
|| type == CSSUnitType::Cqb
|| type == CSSUnitType::Cqmin
|| type == CSSUnitType::Cqmax;
}
constexpr bool CSSPrimitiveValue::isLength(CSSUnitType type)
{
return type == CSSUnitType::Em
|| type == CSSUnitType::Ex
|| type == CSSUnitType::Px
|| type == CSSUnitType::Cm
|| type == CSSUnitType::Mm
|| type == CSSUnitType::In
|| type == CSSUnitType::Pt
|| type == CSSUnitType::Pc
|| type == CSSUnitType::Q
|| isFontRelativeLength(type)
|| isViewportPercentageLength(type)
|| isContainerPercentageLength(type)
|| type == CSSUnitType::QuirkyEm;
}
constexpr bool CSSPrimitiveValue::isViewportPercentageLength(CSSUnitType type)
{
return type >= CSSUnitType::FirstViewportCSSUnitType && type <= CSSUnitType::LastViewportCSSUnitType;
}
void add(Hasher&, const CSSPrimitiveValue&);
} // namespace WebCore
SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSPrimitiveValue, isPrimitiveValue())