Repository: LadybirdBrowser/ladybird
File: Libraries/LibWeb/CSS/CSSStyleProperties.cpp (C++)

Code before:
            // 2. For each longhand property longhand that property maps to, in canonical order, follow these substeps:
            Vector<PropertyID> longhand_ids = longhands_for_shorthand(property.id());
            for (auto longhand_property_id : longhand_ids) {
                // 1. If longhand is a case-sensitive match for a property name of a CSS declaration in the declarations,
                //    let declaration be that CSS declaration, or null otherwise.
                auto declaration = get_property_internal(PropertyNameAndID::from_id(longhand_property_id));

                // 2. If declaration is null, then return the empty string.
                if (!declaration.has_value())
                    return {};

                // 3. Append the declaration to list.
                list.append(declaration->value);

                if (last_important_flag.has_value() && declaration->important != *last_important_flag)
                    return {};
                last_important_flag = declaration->important;
            }

            // https://www.w3.org/TR/css-variables-1/#variables-in-shorthands
            // If all of the component longhand properties for a given shorthand are pending-substitution values from
            // the same original shorthand value, the shorthand property must serialize to that original
            // (var()-containing) value.
            // Otherwise, if any of the component longhand properties for a given shorthand are pending-substitution
            // values, or contain var() functions of their own that have not yet been substituted, the shorthand
            // property must serialize to the empty string.
            if (list.first()->is_pending_substitution()) {
                auto const& original_shorthand_value = list.first()->as_pending_substitution().original_shorthand_value();
                auto all_from_same_original = all_of(list, [&](auto const& value) {
                    return value->is_pending_substitution()
                        && &value->as_pending_substitution().original_shorthand_value() == &original_shorthand_value;
                });
                if (all_from_same_original) {
                    return StyleProperty {
                        .important = last_important_flag.value(),
                        .property_id = property.id(),
                        .value = original_shorthand_value,
                    };
                }
            }
            if (any_of(list, [](auto const& value) { return value->is_pending_substitution() || value->is_unresolved(); }))
                return {};

            // 3. If important flags of all declarations in list are same, then return the serialization of list.
            // NOTE: Currently we implement property-specific shorthand serialization in ShorthandStyleValue::to_string().
            return StyleProperty {
                .important = last_important_flag.value(),
                .property_id = property.id(),
                .value = ShorthandStyleValue::create(property.id(), longhand_ids, list),
            };


Review comment (suggestion):
I couldn't find this text in the current draft spec at: https://drafts.csswg.org/css-values-5/#pending-substitution-value. I'm not sure of the current spec would expect a test like the one I added here: `Tests/LibWeb/Text/input/css/getPropertyValue-shorthand-with-var.html` to output the empty string but this doesn't seem to be how other engines behave.

Code after:
            // 2. For each longhand property longhand that property maps to, in canonical order, follow these substeps:
            Vector<PropertyID> longhand_ids = longhands_for_shorthand(property.id());
            for (auto longhand_property_id : longhand_ids) {
                // 1. If longhand is a case-sensitive match for a property name of a CSS declaration in the declarations,
                //    let declaration be that CSS declaration, or null otherwise.
                auto declaration = get_property_internal(PropertyNameAndID::from_id(longhand_property_id));

                // 2. If declaration is null, then return the empty string.
                if (!declaration.has_value())
                    return {};

                // 3. Append the declaration to list.
                list.append(declaration->value);

                if (last_important_flag.has_value() && declaration->important != *last_important_flag)
                    return {};
                last_important_flag = declaration->important;
            }

            // https://drafts.csswg.org/css-values-5/#pending-substitution-value
            // If all of the component longhand properties for a given shorthand are pending-substitution values from
            // the same original shorthand value, the shorthand property must serialize to that original
            // (arbitrary substitution function-containing) value.
            // Otherwise, if any of the component longhand properties for a given shorthand are pending-substitution
            // values, or contain arbitrary substitution functions of their own that have not yet been substituted, the
            // shorthand property must serialize to the empty string.
            if (list.first()->is_pending_substitution()) {
                auto const& original_shorthand_value = list.first()->as_pending_substitution().original_shorthand_value();
                auto all_from_same_original = all_of(list, [&](auto const& value) {
                    return value->is_pending_substitution()
                        && &value->as_pending_substitution().original_shorthand_value() == &original_shorthand_value;
                });
                if (all_from_same_original) {
                    return StyleProperty {
                        .important = last_important_flag.value(),
                        .property_id = property.id(),
                        .value = original_shorthand_value,
                    };
                }
            }
            if (any_of(list, [](auto const& value) { return value->is_pending_substitution() || value->is_unresolved(); }))
                return {};

            // 3. If important flags of all declarations in list are same, then return the serialization of list.
            // NOTE: Currently we implement property-specific shorthand serialization in ShorthandStyleValue::to_string().
            return StyleProperty {
                .important = last_important_flag.value(),
                .property_id = property.id(),
                .value = ShorthandStyleValue::create(property.id(), longhand_ids, list),
            };