mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-22 20:45:14 +00:00
WIP: Use PSVs to cascade unresolved properties' longhands
This is broken because we don't keep the shorthand's value around, so we can never expand it out to replace the PSVs.
This commit is contained in:
parent
cc02778ef6
commit
6cbc4c3007
6 changed files with 116 additions and 27 deletions
|
@ -861,11 +861,17 @@ WebIDL::ExceptionOr<void> KeyframeEffect::set_keyframes(Optional<GC::Root<JS::Ob
|
|||
auto key = static_cast<u64>(keyframe.computed_offset.value() * 100 * AnimationKeyFrameKeyScaleFactor);
|
||||
|
||||
for (auto [property_id, property_value] : keyframe.parsed_properties()) {
|
||||
if (property_value->is_unresolved() && target)
|
||||
if (property_value->is_unresolved() && target) {
|
||||
property_value = CSS::Parser::Parser::resolve_unresolved_style_value(CSS::Parser::ParsingParams { target->document() }, *target, pseudo_element_type(), property_id, property_value->as_unresolved());
|
||||
CSS::StyleComputer::for_each_property_expanding_shorthands(property_id, property_value, CSS::StyleComputer::AllowUnresolved::Yes, [&](CSS::PropertyID shorthand_id, CSS::CSSStyleValue const& shorthand_value) {
|
||||
m_target_properties.set(shorthand_id);
|
||||
resolved_keyframe.properties.set(shorthand_id, NonnullRefPtr<CSS::CSSStyleValue const> { shorthand_value });
|
||||
dbgln("Resolving unresolved {} in set_keyframes(); got `{}`", CSS::string_from_property_id(property_id), property_value->to_string(CSS::CSSStyleValue::SerializationMode::Normal));
|
||||
}
|
||||
CSS::StyleComputer::for_each_property_expanding_shorthands(property_id, property_value, CSS::StyleComputer::AllowUnresolved::Yes, [&](CSS::PropertyID longhand_id, CSS::CSSStyleValue const& longhand_value) {
|
||||
dbgln("expanding shorthands in set_keyframes");
|
||||
VERIFY(!longhand_value.is_guaranteed_invalid());
|
||||
VERIFY(!longhand_value.is_pending_substitution());
|
||||
VERIFY(!longhand_value.is_unresolved());
|
||||
m_target_properties.set(longhand_id);
|
||||
resolved_keyframe.properties.set(longhand_id, NonnullRefPtr<CSS::CSSStyleValue const> { longhand_value });
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@ void CascadedProperties::resolve_unresolved_properties(GC::Ref<DOM::Element> ele
|
|||
if (!entry.property.value->is_unresolved())
|
||||
continue;
|
||||
entry.property.value = Parser::Parser::resolve_unresolved_style_value(Parser::ParsingParams { element->document() }, element, pseudo_element, property_id, entry.property.value->as_unresolved());
|
||||
dbgln("Resolving unresolved {} in resolve_unresolved_properties(); got `{}`", string_from_property_id(property_id), entry.property.value->to_string(CSSStyleValue::SerializationMode::Normal));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1200,6 +1200,7 @@ Optional<FlyString> ComputedProperties::font_language_override() const
|
|||
Optional<Gfx::FontVariantAlternates> ComputedProperties::font_variant_alternates() const
|
||||
{
|
||||
auto const& value = property(PropertyID::FontVariantAlternates);
|
||||
dbgln("font-variant-alternates is: {}", value.to_string(CSSStyleValue::SerializationMode::Normal));
|
||||
switch (keyword_to_font_variant_alternates(value.to_keyword()).value()) {
|
||||
case FontVariantAlternates::Normal:
|
||||
return {};
|
||||
|
|
|
@ -43,14 +43,27 @@ static T interpolate_raw(T from, T to, float delta)
|
|||
|
||||
static NonnullRefPtr<CSSStyleValue const> with_keyword_values_resolved(DOM::Element& element, PropertyID property_id, CSSStyleValue const& value)
|
||||
{
|
||||
if (value.is_guaranteed_invalid()) {
|
||||
// At the moment, we're only dealing with "real" properties, so this behaves the same as `unset`.
|
||||
// https://drafts.csswg.org/css-values-5/#invalid-at-computed-value-time
|
||||
return property_initial_value(property_id);
|
||||
}
|
||||
|
||||
if (value.is_pending_substitution()) {
|
||||
dbgln("OH NO got pensubval in with_keyword_values_resolved(). Property {}", string_from_property_id(property_id));
|
||||
}
|
||||
if (value.is_unresolved()) {
|
||||
dbgln("OH NO got unresolved in with_keyword_values_resolved(). Property {}", string_from_property_id(property_id));
|
||||
}
|
||||
|
||||
if (!value.is_keyword())
|
||||
return value;
|
||||
switch (value.as_keyword().keyword()) {
|
||||
case CSS::Keyword::Initial:
|
||||
case CSS::Keyword::Unset:
|
||||
case Keyword::Initial:
|
||||
case Keyword::Unset:
|
||||
return property_initial_value(property_id);
|
||||
case CSS::Keyword::Inherit:
|
||||
return CSS::StyleComputer::get_inherit_value(property_id, &element);
|
||||
case Keyword::Inherit:
|
||||
return StyleComputer::get_inherit_value(property_id, &element);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include <LibWeb/CSS/StyleValues/FrequencyStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/GridTrackPlacementStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/GridTrackSizeListStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/GuaranteedInvalidStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/ImageStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/IntegerStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/LengthStyleValue.h>
|
||||
|
@ -3637,8 +3638,6 @@ NonnullRefPtr<CSSStyleValue> Parser::resolve_unresolved_style_value(ParsingParam
|
|||
// to produce a different CSSStyleValue from it.
|
||||
VERIFY(unresolved.contains_var_or_attr());
|
||||
|
||||
// If the value is invalid, we fall back to `unset`: https://www.w3.org/TR/css-variables-1/#invalid-at-computed-value-time
|
||||
|
||||
auto parser = Parser::create(context, ""sv);
|
||||
return parser.resolve_unresolved_style_value(element, pseudo_element, property_id, unresolved);
|
||||
}
|
||||
|
@ -3701,18 +3700,18 @@ NonnullRefPtr<CSSStyleValue> Parser::resolve_unresolved_style_value(DOM::Element
|
|||
}
|
||||
};
|
||||
if (!expand_variables(element, pseudo_element, string_from_property_id(property_id), dependencies, unresolved_values_without_variables_expanded, values_with_variables_expanded))
|
||||
return CSSKeywordValue::create(Keyword::Unset);
|
||||
return GuaranteedInvalidStyleValue::create();
|
||||
|
||||
TokenStream unresolved_values_with_variables_expanded { values_with_variables_expanded };
|
||||
Vector<ComponentValue> expanded_values;
|
||||
if (!expand_unresolved_values(element, string_from_property_id(property_id), unresolved_values_with_variables_expanded, expanded_values))
|
||||
return CSSKeywordValue::create(Keyword::Unset);
|
||||
return GuaranteedInvalidStyleValue::create();
|
||||
|
||||
auto expanded_value_tokens = TokenStream { expanded_values };
|
||||
if (auto parsed_value = parse_css_value(property_id, expanded_value_tokens); !parsed_value.is_error())
|
||||
return parsed_value.release_value();
|
||||
|
||||
return CSSKeywordValue::create(Keyword::Unset);
|
||||
return GuaranteedInvalidStyleValue::create();
|
||||
}
|
||||
|
||||
static RefPtr<CSSStyleValue const> get_custom_property(DOM::Element const& element, Optional<CSS::PseudoElement> pseudo_element, FlyString const& custom_property_name)
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
#include <LibWeb/CSS/StyleValues/LengthStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/MathDepthStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/NumberStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/PendingSubstitutionStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/PercentageStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/PositionStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/RatioStyleValue.h>
|
||||
|
@ -707,6 +708,24 @@ void StyleComputer::for_each_property_expanding_shorthands(PropertyID property_i
|
|||
return;
|
||||
}
|
||||
|
||||
if (property_is_shorthand(property_id) && (value.is_unresolved() || value.is_pending_substitution())) {
|
||||
// If a shorthand property contains an arbitrary substitution function in its value, the longhand properties
|
||||
// it’s associated with must instead be filled in with a special, unobservable-to-authors pending-substitution
|
||||
// value that indicates the shorthand contains an arbitrary substitution function, and thus the longhand’s
|
||||
// value can’t be determined until after substituted.
|
||||
// https://drafts.csswg.org/css-values-5/#pending-substitution-value
|
||||
dbgln("Assigning pensubval for longhands of {}", string_from_property_id(property_id));
|
||||
auto pending_substitution_value = PendingSubstitutionStyleValue::create();
|
||||
for (auto longhand_id : longhands_for_shorthand(property_id)) {
|
||||
for_each_property_expanding_shorthands(longhand_id, pending_substitution_value, allow_unresolved, set_longhand_property);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (value.is_guaranteed_invalid()) {
|
||||
dbgln("{} is guaranteed-invalid! We should probably do something.", string_from_property_id(property_id));
|
||||
}
|
||||
|
||||
auto assign_edge_values = [&](PropertyID top_property, PropertyID right_property, PropertyID bottom_property, PropertyID left_property, auto const& values) {
|
||||
if (values.size() == 4) {
|
||||
set_longhand_property(top_property, values[0]);
|
||||
|
@ -948,12 +967,12 @@ void StyleComputer::for_each_property_expanding_shorthands(PropertyID property_i
|
|||
}
|
||||
|
||||
if (property_is_shorthand(property_id)) {
|
||||
// ShorthandStyleValue was handled already.
|
||||
// That means if we got here, that `value` must be a CSS-wide keyword, which we should apply to our longhand properties.
|
||||
// ShorthandStyleValue was handled already, as were unresolved shorthands.
|
||||
// That means the only values we should see are the CSS-wide keywords, or the guaranteed-invalid value.
|
||||
// Both should be applied to our longhand properties.
|
||||
// We don't directly call `set_longhand_property()` because the longhands might have longhands of their own.
|
||||
// (eg `grid` -> `grid-template` -> `grid-template-areas` & `grid-template-rows` & `grid-template-columns`)
|
||||
// Forget this requirement if we're ignoring unresolved values and the value is unresolved.
|
||||
VERIFY(value.is_css_wide_keyword() || (allow_unresolved == AllowUnresolved::Yes && value.is_unresolved()));
|
||||
VERIFY(value.is_css_wide_keyword() || value.is_guaranteed_invalid());
|
||||
for (auto longhand : longhands_for_shorthand(property_id))
|
||||
for_each_property_expanding_shorthands(longhand, value, allow_unresolved, set_longhand_property);
|
||||
return;
|
||||
|
@ -1007,8 +1026,10 @@ void StyleComputer::set_all_properties(
|
|||
}
|
||||
|
||||
NonnullRefPtr<CSSStyleValue> property_value = value;
|
||||
if (property_value->is_unresolved())
|
||||
if (property_value->is_unresolved()) {
|
||||
property_value = Parser::Parser::resolve_unresolved_style_value(Parser::ParsingParams { document }, element, pseudo_element, property_id, property_value->as_unresolved());
|
||||
dbgln("Resolving unresolved {} in set_all_properties(); got `{}`", string_from_property_id(property_id), property_value->to_string(CSSStyleValue::SerializationMode::Normal));
|
||||
}
|
||||
set_property_expanding_shorthands(cascaded_properties, property_id, property_value, declaration, cascade_origin, important, layer_name);
|
||||
}
|
||||
}
|
||||
|
@ -1024,22 +1045,48 @@ void StyleComputer::cascade_declarations(
|
|||
{
|
||||
auto cascade_style_declaration = [&](CSSStyleProperties const& declaration) {
|
||||
for (auto const& property : declaration.properties()) {
|
||||
dbgln("Cascading {}", string_from_property_id(property.property_id));
|
||||
dbgln("-> value: `{}`, psv? {}, giv? {}", property.value->to_string(CSSStyleValue::SerializationMode::Normal), property.value->is_pending_substitution(), property.value->is_guaranteed_invalid());
|
||||
if (important != property.important)
|
||||
continue;
|
||||
|
||||
if (pseudo_element.has_value() && !pseudo_element_supports_property(*pseudo_element, property.property_id))
|
||||
continue;
|
||||
|
||||
if (property.property_id == CSS::PropertyID::All) {
|
||||
set_all_properties(cascaded_properties, element, pseudo_element, property.value, m_document, &declaration, cascade_origin, important, layer_name);
|
||||
auto property_value = property.value;
|
||||
|
||||
if (property_value->is_unresolved()) {
|
||||
property_value = Parser::Parser::resolve_unresolved_style_value(Parser::ParsingParams { element.document() }, element, pseudo_element, property.property_id, property_value->as_unresolved());
|
||||
dbgln("Resolving unresolved {} in cascade_declarations(); got `{}`", string_from_property_id(property.property_id), property_value->to_string(CSSStyleValue::SerializationMode::Normal));
|
||||
}
|
||||
|
||||
if (property_value->is_guaranteed_invalid()) {
|
||||
dbgln("Resolving guaranteed-invalid {} in cascade_declarations()", string_from_property_id(property.property_id));
|
||||
// https://drafts.csswg.org/css-values-5/#invalid-at-computed-value-time
|
||||
// When substitution results in a property’s value containing the guaranteed-invalid value, this makes the
|
||||
// declaration invalid at computed-value time. When this happens, the computed value is one of the
|
||||
// following depending on the property’s type:
|
||||
|
||||
// -> The property is a non-registered custom property
|
||||
// -> The property is a registered custom property with universal syntax
|
||||
// FIXME: Process custom properties here?
|
||||
if (false) {
|
||||
// The computed value is the guaranteed-invalid value.
|
||||
}
|
||||
// -> Otherwise
|
||||
else {
|
||||
// Either the property’s inherited value or its initial value depending on whether the property is
|
||||
// inherited or not, respectively, as if the property’s value had been specified as the unset keyword.
|
||||
property_value = CSSKeywordValue::create(Keyword::Unset);
|
||||
}
|
||||
}
|
||||
|
||||
if (property.property_id == PropertyID::All) {
|
||||
set_all_properties(cascaded_properties, element, pseudo_element, property_value, m_document, &declaration, cascade_origin, important, layer_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto property_value = property.value;
|
||||
if (property.value->is_unresolved())
|
||||
property_value = Parser::Parser::resolve_unresolved_style_value(Parser::ParsingParams { document() }, element, pseudo_element, property.property_id, property.value->as_unresolved());
|
||||
if (!property_value->is_unresolved())
|
||||
set_property_expanding_shorthands(cascaded_properties, property.property_id, property_value, &declaration, cascade_origin, important, layer_name);
|
||||
set_property_expanding_shorthands(cascaded_properties, property.property_id, property_value, &declaration, cascade_origin, important, layer_name);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1134,6 +1181,24 @@ void StyleComputer::collect_animation_into(DOM::Element& element, Optional<CSS::
|
|||
dbgln("Animation {} contains {} properties to interpolate, progress = {}%", animation->id(), valid_properties, progress_in_keyframe * 100);
|
||||
}
|
||||
|
||||
// FIXME: I think I need to expand out any unresolved shorthands here somehow.
|
||||
// See: https://drafts.csswg.org/web-animations-1/#ref-for-computed-keyframes
|
||||
for (auto const& [property_id, value] : keyframe_values.properties) {
|
||||
value.visit(
|
||||
[&](RefPtr<CSSStyleValue const> value) -> RefPtr<CSSStyleValue const> {
|
||||
if (value->is_revert() || value->is_revert_layer())
|
||||
return computed_properties.property(property_id);
|
||||
if (value->is_unresolved()) {
|
||||
auto property_value = Parser::Parser::resolve_unresolved_style_value(Parser::ParsingParams { element.document() }, element, pseudo_element, property_id, value->as_unresolved());
|
||||
|
||||
dbgln("Resolving unresolved {} in collect_animation_into(); got `{}`", string_from_property_id(property_id), property_value->to_string(CSSStyleValue::SerializationMode::Normal));
|
||||
return property_value;
|
||||
}
|
||||
return value;
|
||||
},
|
||||
[](auto const&) {});
|
||||
}
|
||||
|
||||
for (auto const& it : keyframe_values.properties) {
|
||||
auto resolve_property = [&](auto& property) {
|
||||
return property.visit(
|
||||
|
@ -1145,8 +1210,12 @@ void StyleComputer::collect_animation_into(DOM::Element& element, Optional<CSS::
|
|||
[&](RefPtr<CSSStyleValue const> value) -> RefPtr<CSSStyleValue const> {
|
||||
if (value->is_revert() || value->is_revert_layer())
|
||||
return computed_properties.property(it.key);
|
||||
if (value->is_unresolved())
|
||||
return Parser::Parser::resolve_unresolved_style_value(Parser::ParsingParams { element.document() }, element, pseudo_element, it.key, value->as_unresolved());
|
||||
if (value->is_unresolved()) {
|
||||
auto property_value = Parser::Parser::resolve_unresolved_style_value(Parser::ParsingParams { element.document() }, element, pseudo_element, it.key, value->as_unresolved());
|
||||
|
||||
dbgln("Resolving unresolved {} in collect_animation_into(); got `{}`", string_from_property_id(it.key), property_value->to_string(CSSStyleValue::SerializationMode::Normal));
|
||||
return property_value;
|
||||
}
|
||||
return value;
|
||||
});
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue