Files
ladybird/Libraries/LibWeb/CSS/CSSMathClamp.cpp
Shannon Booth fd44da6829 LibWeb/Bindings: Emit one bindings header and cpp per IDL
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.
2026-04-21 07:36:13 +02:00

157 lines
6.0 KiB
C++

/*
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "CSSMathClamp.h"
#include <LibWeb/Bindings/CSSMathClamp.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/CSS/CSSMathNegate.h>
#include <LibWeb/CSS/CSSNumericArray.h>
#include <LibWeb/CSS/StyleValues/CalculatedStyleValue.h>
#include <LibWeb/WebIDL/DOMException.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
namespace Web::CSS {
GC_DEFINE_ALLOCATOR(CSSMathClamp);
GC::Ref<CSSMathClamp> CSSMathClamp::create(JS::Realm& realm, NumericType type, GC::Ref<CSSNumericValue> lower, GC::Ref<CSSNumericValue> value, GC::Ref<CSSNumericValue> upper)
{
return realm.create<CSSMathClamp>(realm, move(type), move(lower), move(value), move(upper));
}
// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssmathclamp-cssmathclamp
WebIDL::ExceptionOr<GC::Ref<CSSMathClamp>> CSSMathClamp::construct_impl(JS::Realm& realm, CSSNumberish lower, CSSNumberish value, CSSNumberish upper)
{
// The CSSMathClamp(lower, value, upper) constructor must, when called, perform the following steps:
// 1. Replace lower, value, and upper with the result of rectifying a numberish value for each.
auto lower_rectified = rectify_a_numberish_value(realm, lower);
auto value_rectified = rectify_a_numberish_value(realm, value);
auto upper_rectified = rectify_a_numberish_value(realm, upper);
// 2. Let type be the result of adding the types of lower, value, and upper. If type is failure, throw a TypeError.
auto type = lower_rectified->type()
.added_to(value_rectified->type())
.map([&](auto&& type) { return type.added_to(upper_rectified->type()); });
if (!type.has_value()) {
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Cannot create a CSSMathClamp with values of incompatible types"sv };
}
// 3. Return a new CSSMathClamp whose lower, value, and upper internal slots are set to lower, value, and upper, respectively.
return CSSMathClamp::create(realm, type->release_value(), move(lower_rectified), move(value_rectified), move(upper_rectified));
}
CSSMathClamp::CSSMathClamp(JS::Realm& realm, NumericType type, GC::Ref<CSSNumericValue> lower, GC::Ref<CSSNumericValue> value, GC::Ref<CSSNumericValue> upper)
: CSSMathValue(realm, Bindings::CSSMathOperator::Clamp, move(type))
, m_lower(move(lower))
, m_value(move(value))
, m_upper(move(upper))
{
}
CSSMathClamp::~CSSMathClamp() = default;
void CSSMathClamp::initialize(JS::Realm& realm)
{
WEB_SET_PROTOTYPE_FOR_INTERFACE(CSSMathClamp);
Base::initialize(realm);
}
void CSSMathClamp::visit_edges(Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_lower);
visitor.visit(m_value);
visitor.visit(m_upper);
}
// https://drafts.css-houdini.org/css-typed-om-1/#serialize-a-cssmathvalue
void CSSMathClamp::serialize_math_value(StringBuilder& s, Nested, Parens) const
{
// AD-HOC: The spec is missing serialization rules for CSSMathClamp: https://github.com/w3c/css-houdini-drafts/issues/1152
s.append("clamp("sv);
m_lower->serialize(s, { .nested = true, .parenless = true });
s.append(", "sv);
m_value->serialize(s, { .nested = true, .parenless = true });
s.append(", "sv);
m_upper->serialize(s, { .nested = true, .parenless = true });
s.append(')');
}
// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssmathclamp-lower
GC::Ref<CSSNumericValue> CSSMathClamp::lower() const
{
// AD-HOC: No spec definition.
return m_lower;
}
// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssmathclamp-value
GC::Ref<CSSNumericValue> CSSMathClamp::value() const
{
// AD-HOC: No spec definition.
return m_value;
}
// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssmathclamp-upper
GC::Ref<CSSNumericValue> CSSMathClamp::upper() const
{
// AD-HOC: No spec definition.
return m_upper;
}
// https://drafts.css-houdini.org/css-typed-om-1/#equal-numeric-value
bool CSSMathClamp::is_equal_numeric_value(GC::Ref<CSSNumericValue> other) const
{
// AD-HOC: Spec doesn't handle clamp(). https://github.com/w3c/css-houdini-drafts/issues/1152
// 1. If value1 and value2 are not members of the same interface, return false.
auto* other_clamp = as_if<CSSMathClamp>(*other);
if (!other_clamp)
return false;
return m_lower->is_equal_numeric_value(other_clamp->m_lower)
&& m_value->is_equal_numeric_value(other_clamp->m_value)
&& m_upper->is_equal_numeric_value(other_clamp->m_upper);
}
// https://drafts.css-houdini.org/css-typed-om-1/#create-a-sum-value
Optional<SumValue> CSSMathClamp::create_a_sum_value() const
{
// AD-HOC: There is no spec for this. https://github.com/w3c/css-houdini-drafts/issues/1152
// So, basing it on the spec for CSSMathMin.
// Create sum values from lower, value, and upper.
auto lower = m_lower->create_a_sum_value();
auto value = m_value->create_a_sum_value();
auto upper = m_upper->create_a_sum_value();
// If any of those are failure, or has a length greater than one, return failure.
if (!lower.has_value() || lower->size() > 1
|| !value.has_value() || value->size() > 1
|| !upper.has_value() || upper->size() > 1)
return {};
// If not all their unit maps are identical, return failure.
if (lower->first().unit_map != value->first().unit_map || value->first().unit_map != upper->first().unit_map)
return {};
// Return value clamped between lower and upper.
return SumValue {
SumValueItem {
clamp(value->first().value, lower->first().value, upper->first().value),
value->first().unit_map,
}
};
}
WebIDL::ExceptionOr<NonnullRefPtr<CalculationNode const>> CSSMathClamp::create_calculation_node(CalculationContext const& context) const
{
auto lower = TRY(m_lower->create_calculation_node(context));
auto value = TRY(m_value->create_calculation_node(context));
auto upper = TRY(m_upper->create_calculation_node(context));
return ClampCalculationNode::create(move(lower), move(value), move(upper));
}
}