ladybird/Libraries/LibWeb/CSS/CSSStyleValue.cpp
Sam Atkins 5178d1ebe3 LibWeb/CSS: Add flag to disable create-internal-rep type checking
CSSTransformComponents hold other CSSStyleValues as their parameters. We
want to be able to create internal representations from those parameters
without them caring if they would be valid when directly assigned to the
property.

This is a temporary solution to make transform functions work. To be
completely correct, we need to know what is allowed in that context,
along with value ranges - a combination of the contexts we create when
parsing, and when computing calculations. For transform functions, this
doesn't matter, as there's no limit to the range of allowed values.
2025-10-14 13:41:47 +01:00

135 lines
6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "CSSStyleValue.h"
#include <LibWeb/Bindings/CSSStyleValuePrototype.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/CSS/Parser/Parser.h>
#include <LibWeb/CSS/PropertyNameAndID.h>
#include <LibWeb/CSS/StyleValues/StyleValue.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
namespace Web::CSS {
GC_DEFINE_ALLOCATOR(CSSStyleValue);
GC::Ref<CSSStyleValue> CSSStyleValue::create(JS::Realm& realm, FlyString associated_property, NonnullRefPtr<StyleValue const> source_value)
{
return realm.create<CSSStyleValue>(realm, move(associated_property), move(source_value));
}
CSSStyleValue::CSSStyleValue(JS::Realm& realm)
: PlatformObject(realm)
{
}
CSSStyleValue::CSSStyleValue(JS::Realm& realm, NonnullRefPtr<StyleValue const> source_value)
: PlatformObject(realm)
, m_source_value(move(source_value))
{
}
CSSStyleValue::CSSStyleValue(JS::Realm& realm, FlyString associated_property, NonnullRefPtr<StyleValue const> source_value)
: PlatformObject(realm)
, m_associated_property(move(associated_property))
, m_source_value(move(source_value))
{
}
void CSSStyleValue::initialize(JS::Realm& realm)
{
WEB_SET_PROTOTYPE_FOR_INTERFACE(CSSStyleValue);
Base::initialize(realm);
}
CSSStyleValue::~CSSStyleValue() = default;
// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssstylevalue-parse
WebIDL::ExceptionOr<GC::Ref<CSSStyleValue>> CSSStyleValue::parse(JS::VM& vm, FlyString const& property, String css_text)
{
// The parse(property, cssText) method, when invoked, must parse a CSSStyleValue with property property, cssText
// cssText, and parseMultiple set to false, and return the result.
auto result = parse_a_css_style_value(vm, property, css_text, ParseMultiple::No);
if (result.is_exception())
return result.release_error();
return result.value().get<GC::Ref<CSSStyleValue>>();
}
// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssstylevalue-parseall
WebIDL::ExceptionOr<GC::RootVector<GC::Ref<CSSStyleValue>>> CSSStyleValue::parse_all(JS::VM& vm, FlyString const& property, String css_text)
{
// The parseAll(property, cssText) method, when invoked, must parse a CSSStyleValue with property property, cssText
// cssText, and parseMultiple set to true, and return the result.
auto result = parse_a_css_style_value(vm, property, css_text, ParseMultiple::Yes);
if (result.is_exception())
return result.release_error();
return result.value().get<GC::RootVector<GC::Ref<CSSStyleValue>>>();
}
// https://drafts.css-houdini.org/css-typed-om-1/#parse-a-cssstylevalue
WebIDL::ExceptionOr<Variant<GC::Ref<CSSStyleValue>, GC::RootVector<GC::Ref<CSSStyleValue>>>> CSSStyleValue::parse_a_css_style_value(JS::VM& vm, FlyString property_name, String css_text, ParseMultiple parse_multiple)
{
// 1. If property is not a custom property name string, set property to property ASCII lowercased.
// 2. If property is not a valid CSS property, throw a TypeError.
auto property = PropertyNameAndID::from_name(property_name);
if (!property.has_value())
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, MUST(String::formatted("'{}' is not a valid CSS property", property_name)) };
// 3. Attempt to parse cssText according to propertys grammar.
// If this fails, throw a TypeError.
// Otherwise, let whole value be the parsed result.
auto whole_value = parse_css_value(Parser::ParsingParams {}, css_text, property->id());
if (!whole_value)
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, MUST(String::formatted("Failed to parse '{}' as a value for '{}' property", css_text, property->name())) };
// FIXME: 4. Subdivide into iterations whole value, according to property, and let values be the result.
// 5. For each value in values, replace it with the result of reifying value for property.
GC::RootVector<GC::Ref<CSSStyleValue>> reified_values { vm.heap() };
reified_values.append(whole_value->reify(*vm.current_realm(), property->name()));
// 6. If parseMultiple is false, return values[0]. Otherwise, return values.
// FIXME: We need to somehow store the source css_text on the returned CSSStyleValue.
// https://github.com/w3c/css-houdini-drafts/issues/1156
if (parse_multiple == ParseMultiple::No)
return reified_values.take_first();
return reified_values;
}
// https://drafts.css-houdini.org/css-typed-om-1/#stylevalue-serialization
WebIDL::ExceptionOr<String> CSSStyleValue::to_string() const
{
// FIXME: if the value was constructed from a USVString
// NB: Basically, if this was constructed with "parse a CSSStyleValue", regardless of what CSSStyleValue type it is now.
{
// the serialization is the USVString from which the value was constructed.
}
// otherwise, if the value was constructed using an IDL constructor
{
// the serialization is specified in the sections below.
// NB: This is handled by subclasses overriding this to_string() method.
}
// FIXME: otherwise, if the value was extracted from the CSSOM
// NB: For CSSStyleValue itself, we use the source value we were created from.
if (m_source_value)
return m_source_value->to_string(SerializationMode::Normal);
{
// the serialization is specified in §6.7 Serialization from CSSOM Values below.
}
return String {};
}
// https://drafts.css-houdini.org/css-typed-om-1/#create-an-internal-representation
WebIDL::ExceptionOr<NonnullRefPtr<StyleValue const>> CSSStyleValue::create_an_internal_representation(PropertyNameAndID const&, PerformTypeCheck) const
{
// If value is a direct CSSStyleValue,
// Return values associated value.
if (!m_source_value)
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, MUST(String::formatted("Missing {}::create_an_internal_representation() overload", class_name())) };
return NonnullRefPtr { *m_source_value };
}
}