LibWeb: Parse multiple backgrounds :^)

Like the `background-foo` longhand properties (except
`background-color`), `background` allows multiple layers to be defined,
separated by commas. A layer does not necessarily contain something to
actually draw!

This parses as a `BackgroundStyleValue`, holding a `StyleValueList` for
each property. This is mostly to make expansion into longhands simpler -
if we had a list of `BackgroundStyleValue`s instead, one per layer, then
we would have to break it up per-property anyway when computing styles.
This commit is contained in:
Sam Atkins 2021-11-11 11:12:06 +00:00 committed by Andreas Kling
parent 8fd4678e79
commit 72d080b4ba
Notes: sideshowbarker 2024-07-18 01:02:39 +09:00

View File

@ -2383,7 +2383,16 @@ RefPtr<StyleValue> Parser::parse_simple_comma_separated_value_list(Vector<StyleC
RefPtr<StyleValue> Parser::parse_background_value(Vector<StyleComponentValueRule> const& component_values)
{
NonnullRefPtrVector<StyleValue> background_images;
NonnullRefPtrVector<StyleValue> background_positions;
NonnullRefPtrVector<StyleValue> background_sizes;
NonnullRefPtrVector<StyleValue> background_repeats;
NonnullRefPtrVector<StyleValue> background_attachments;
NonnullRefPtrVector<StyleValue> background_clips;
NonnullRefPtrVector<StyleValue> background_origins;
RefPtr<StyleValue> background_color;
// Per-layer values
RefPtr<StyleValue> background_image;
RefPtr<StyleValue> background_position;
RefPtr<StyleValue> background_size;
@ -2392,14 +2401,54 @@ RefPtr<StyleValue> Parser::parse_background_value(Vector<StyleComponentValueRule
RefPtr<StyleValue> background_clip;
RefPtr<StyleValue> background_origin;
bool has_multiple_layers = false;
auto background_layer_is_valid = [&](bool allow_background_color) -> bool {
if (allow_background_color) {
if (background_color)
return true;
} else {
if (background_color)
return false;
}
return background_image || background_position || background_size || background_repeat || background_attachment || background_clip || background_origin;
};
auto complete_background_layer = [&]() {
background_images.append(background_image ? background_image.release_nonnull() : property_initial_value(PropertyID::BackgroundImage));
background_positions.append(background_position ? background_position.release_nonnull() : property_initial_value(PropertyID::BackgroundPosition));
background_sizes.append(background_size ? background_size.release_nonnull() : property_initial_value(PropertyID::BackgroundSize));
background_repeats.append(background_repeat ? background_repeat.release_nonnull() : property_initial_value(PropertyID::BackgroundRepeat));
background_attachments.append(background_attachment ? background_attachment.release_nonnull() : property_initial_value(PropertyID::BackgroundAttachment));
if (!background_origin && !background_clip) {
background_origin = property_initial_value(PropertyID::BackgroundOrigin);
background_clip = property_initial_value(PropertyID::BackgroundClip);
} else if (!background_clip) {
background_clip = background_origin;
}
background_origins.append(background_origin.release_nonnull());
background_clips.append(background_clip.release_nonnull());
background_image = nullptr;
background_position = nullptr;
background_size = nullptr;
background_repeat = nullptr;
background_attachment = nullptr;
background_clip = nullptr;
background_origin = nullptr;
};
auto tokens = TokenStream { component_values };
while (tokens.has_next_token()) {
auto& part = tokens.next_token();
// FIXME: Handle multiple backgrounds, by returning a List of BackgroundStyleValues.
if (part.is(Token::Type::Comma)) {
dbgln("CSS Parser does not yet support multiple comma-separated values for background.");
break;
has_multiple_layers = true;
if (!background_layer_is_valid(false))
return nullptr;
complete_background_layer();
continue;
}
auto value = parse_css_value(part);
@ -2478,6 +2527,27 @@ RefPtr<StyleValue> Parser::parse_background_value(Vector<StyleComponentValueRule
return nullptr;
}
if (!background_layer_is_valid(true))
return nullptr;
// We only need to create StyleValueLists if there are multiple layers.
// Otherwise, we can pass the single StyleValues directly.
if (has_multiple_layers) {
complete_background_layer();
if (!background_color)
background_color = property_initial_value(PropertyID::BackgroundColor);
return BackgroundStyleValue::create(
background_color.release_nonnull(),
StyleValueList::create(move(background_images)),
StyleValueList::create(move(background_positions)),
StyleValueList::create(move(background_sizes)),
StyleValueList::create(move(background_repeats)),
StyleValueList::create(move(background_attachments)),
StyleValueList::create(move(background_origins)),
StyleValueList::create(move(background_clips)));
}
if (!background_color)
background_color = property_initial_value(PropertyID::BackgroundColor);
if (!background_image)