mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-26 01:35:08 +02:00
Previously, the LibWeb bindings generator would output multiple per interface files like Prototype/Constructor/Namespace/GlobalMixin depending on the contents of that IDL file. This complicates the build system as it means that it does not know what files will be generated without knowledge of the contents of that IDL file. Instead, for each IDL file only generate a single Bindings/<IDLFile>.h and Bindings/<IDLFile>.cpp.
171 lines
7.0 KiB
C++
171 lines
7.0 KiB
C++
/*
|
||
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
|
||
*
|
||
* SPDX-License-Identifier: BSD-2-Clause
|
||
*/
|
||
|
||
#include "CSSPerspective.h"
|
||
#include <LibWeb/Bindings/CSSPerspective.h>
|
||
#include <LibWeb/Bindings/Intrinsics.h>
|
||
#include <LibWeb/CSS/CSSNumericValue.h>
|
||
#include <LibWeb/CSS/CSSUnitValue.h>
|
||
#include <LibWeb/CSS/PropertyNameAndID.h>
|
||
#include <LibWeb/CSS/StyleValues/TransformationStyleValue.h>
|
||
#include <LibWeb/Geometry/DOMMatrix.h>
|
||
#include <LibWeb/WebIDL/ExceptionOr.h>
|
||
|
||
namespace Web::CSS {
|
||
|
||
GC_DEFINE_ALLOCATOR(CSSPerspective);
|
||
|
||
static WebIDL::ExceptionOr<CSSPerspectiveValueInternal> to_internal(JS::Realm& realm, CSSPerspectiveValue const& value)
|
||
{
|
||
// Steps 1 and 2 of The CSSPerspective(length) constructor:
|
||
// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssperspective-cssperspective
|
||
return value.visit(
|
||
// 1. If length is a CSSNumericValue:
|
||
[](GC::Root<CSSNumericValue> const& numeric_value) -> WebIDL::ExceptionOr<CSSPerspectiveValueInternal> {
|
||
// 1. If length does not match <length>, throw a TypeError.
|
||
if (!numeric_value->type().matches_length({})) {
|
||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "CSSPerspective length component doesn't match <length>"sv };
|
||
}
|
||
return { GC::Ref { *numeric_value } };
|
||
},
|
||
// 2. Otherwise (that is, if length is not a CSSNumericValue):
|
||
[&realm](CSSKeywordish const& keywordish) -> WebIDL::ExceptionOr<CSSPerspectiveValueInternal> {
|
||
// 1. Rectify a keywordish value from length, then set length to the result’s value.
|
||
auto rectified_length = rectify_a_keywordish_value(realm, keywordish);
|
||
|
||
// 2. If length does not represent a value that is an ASCII case-insensitive match for the keyword none,
|
||
// throw a TypeError.
|
||
if (!rectified_length->value().equals_ignoring_ascii_case("none"_fly_string)) {
|
||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "CSSPerspective length component is a keyword other than `none`"sv };
|
||
}
|
||
|
||
return { rectified_length };
|
||
});
|
||
}
|
||
|
||
GC::Ref<CSSPerspective> CSSPerspective::create(JS::Realm& realm, CSSPerspectiveValueInternal length)
|
||
{
|
||
return realm.create<CSSPerspective>(realm, length);
|
||
}
|
||
|
||
// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssperspective-cssperspective
|
||
WebIDL::ExceptionOr<GC::Ref<CSSPerspective>> CSSPerspective::construct_impl(JS::Realm& realm, CSSPerspectiveValue length)
|
||
{
|
||
// The CSSPerspective(length) constructor must, when invoked, perform the following steps:
|
||
// NB: Steps 1 and 2 are implemented in to_internal().
|
||
auto internal_length = TRY(to_internal(realm, length));
|
||
|
||
// 3. Return a new CSSPerspective object with its length internal slot set to length, and its is2D internal slot
|
||
// set to false.
|
||
return CSSPerspective::create(realm, internal_length);
|
||
}
|
||
|
||
CSSPerspective::CSSPerspective(JS::Realm& realm, CSSPerspectiveValueInternal length)
|
||
: CSSTransformComponent(realm, Is2D::No)
|
||
, m_length(length)
|
||
{
|
||
}
|
||
|
||
CSSPerspective::~CSSPerspective() = default;
|
||
|
||
void CSSPerspective::initialize(JS::Realm& realm)
|
||
{
|
||
WEB_SET_PROTOTYPE_FOR_INTERFACE(CSSPerspective);
|
||
Base::initialize(realm);
|
||
}
|
||
|
||
void CSSPerspective::visit_edges(Visitor& visitor)
|
||
{
|
||
Base::visit_edges(visitor);
|
||
m_length.visit([&visitor](auto const& it) { visitor.visit(it); });
|
||
}
|
||
|
||
// https://drafts.css-houdini.org/css-typed-om-1/#serialize-a-cssperspective
|
||
WebIDL::ExceptionOr<Utf16String> CSSPerspective::to_string() const
|
||
{
|
||
// 1. Let s initially be "perspective(".
|
||
StringBuilder builder { StringBuilder::Mode::UTF16 };
|
||
builder.append("perspective("sv);
|
||
|
||
// 2. Serialize this’s length internal slot, with a minimum of 0px, and append it to s.
|
||
auto serialized_length = TRY(m_length.visit(
|
||
[](GC::Ref<CSSNumericValue> const& numeric_value) -> WebIDL::ExceptionOr<String> {
|
||
return numeric_value->to_string({ .minimum = 0 });
|
||
},
|
||
[](GC::Ref<CSSKeywordValue> const& keyword_value) -> WebIDL::ExceptionOr<String> {
|
||
return keyword_value->to_string();
|
||
}));
|
||
builder.append(serialized_length);
|
||
|
||
// 3. Append ")" to s, and return s.
|
||
builder.append(")"sv);
|
||
return builder.to_utf16_string();
|
||
}
|
||
|
||
WebIDL::ExceptionOr<GC::Ref<Geometry::DOMMatrix>> CSSPerspective::to_matrix() const
|
||
{
|
||
// 1. Let matrix be a new DOMMatrix object, initialized to this’s equivalent 4x4 transform matrix, as defined in
|
||
// CSS Transforms 1 § 12. Mathematical Description of Transform Functions, and with its is2D internal slot set
|
||
// to the same value as this’s is2D internal slot.
|
||
// NOTE: Recall that the is2D flag affects what transform, and thus what equivalent matrix, a
|
||
// CSSTransformComponent represents.
|
||
// As the entries of such a matrix are defined relative to the px unit, if any <length>s in this involved in
|
||
// generating the matrix are not compatible units with px (such as relative lengths or percentages), throw a
|
||
// TypeError.
|
||
auto matrix = Geometry::DOMMatrix::create(realm());
|
||
|
||
TRY(m_length.visit(
|
||
[&matrix](GC::Ref<CSSNumericValue> const& numeric_value) -> WebIDL::ExceptionOr<void> {
|
||
// NB: to() throws a TypeError if the conversion can't be done.
|
||
auto distance = TRY(numeric_value->to("px"_fly_string))->value();
|
||
matrix->set_m34(-1 / max(distance, 1));
|
||
return {};
|
||
},
|
||
[](GC::Ref<CSSKeywordValue> const&) -> WebIDL::ExceptionOr<void> {
|
||
// NB: This is `none`, so do nothing.
|
||
return {};
|
||
}));
|
||
|
||
// 2. Return matrix.
|
||
return matrix;
|
||
}
|
||
|
||
CSSPerspectiveValue CSSPerspective::length() const
|
||
{
|
||
return m_length.visit(
|
||
[](GC::Ref<CSSNumericValue> const& numeric_value) -> CSSPerspectiveValue {
|
||
return GC::Root { numeric_value };
|
||
},
|
||
[](GC::Ref<CSSKeywordValue> const& keyword_value) -> CSSPerspectiveValue {
|
||
return CSSKeywordish { keyword_value };
|
||
});
|
||
}
|
||
|
||
WebIDL::ExceptionOr<void> CSSPerspective::set_length(CSSPerspectiveValue value)
|
||
{
|
||
// AD-HOC: Not specced. https://github.com/w3c/css-houdini-drafts/issues/1153
|
||
// WPT expects this to throw for invalid values, so just reuse the constructor code.
|
||
auto length = TRY(to_internal(realm(), value));
|
||
m_length = length;
|
||
return {};
|
||
}
|
||
|
||
// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssperspective-is2d
|
||
void CSSPerspective::set_is_2d(bool)
|
||
{
|
||
// The is2D attribute of a CSSPerspective object must, on setting, do nothing.
|
||
}
|
||
|
||
WebIDL::ExceptionOr<NonnullRefPtr<TransformationStyleValue const>> CSSPerspective::create_style_value(PropertyNameAndID const& property) const
|
||
{
|
||
auto length = TRY(m_length.visit([&](auto const& value) {
|
||
return value->create_an_internal_representation(property, CSSStyleValue::PerformTypeCheck::No);
|
||
}));
|
||
return TransformationStyleValue::create(property.id(), TransformFunction::Perspective, { move(length) });
|
||
}
|
||
|
||
}
|