mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 05:47:35 +00:00
LibWeb: Support two-value background-repeat
The background-repeat value may be specified as either one- or two-value identifiers (to be interpreted as horizontal and vertical repeat). This adds two pseudo-properties, background-repeat-x and background-repeat-y, to handle this. One-value identifiers are mapped to two-value in accordance with the spec.
This commit is contained in:
parent
0794d879f3
commit
5de0e0068c
12 changed files with 152 additions and 35 deletions
|
@ -92,7 +92,8 @@ public:
|
||||||
|
|
||||||
Color color() const { return m_inherited.color; }
|
Color color() const { return m_inherited.color; }
|
||||||
Color background_color() const { return m_noninherited.background_color; }
|
Color background_color() const { return m_noninherited.background_color; }
|
||||||
CSS::Repeat background_repeat() const { return m_noninherited.background_repeat; }
|
CSS::Repeat background_repeat_x() const { return m_noninherited.background_repeat_x; }
|
||||||
|
CSS::Repeat background_repeat_y() const { return m_noninherited.background_repeat_y; }
|
||||||
|
|
||||||
CSS::ListStyleType list_style_type() const { return m_inherited.list_style_type; }
|
CSS::ListStyleType list_style_type() const { return m_inherited.list_style_type; }
|
||||||
|
|
||||||
|
@ -134,7 +135,8 @@ protected:
|
||||||
BorderData border_right;
|
BorderData border_right;
|
||||||
BorderData border_bottom;
|
BorderData border_bottom;
|
||||||
Color background_color { InitialValues::background_color() };
|
Color background_color { InitialValues::background_color() };
|
||||||
CSS::Repeat background_repeat { InitialValues::background_repeat() };
|
CSS::Repeat background_repeat_x { InitialValues::background_repeat() };
|
||||||
|
CSS::Repeat background_repeat_y { InitialValues::background_repeat() };
|
||||||
CSS::FlexDirection flex_direction { InitialValues::flex_direction() };
|
CSS::FlexDirection flex_direction { InitialValues::flex_direction() };
|
||||||
CSS::Overflow overflow_x { InitialValues::overflow() };
|
CSS::Overflow overflow_x { InitialValues::overflow() };
|
||||||
CSS::Overflow overflow_y { InitialValues::overflow() };
|
CSS::Overflow overflow_y { InitialValues::overflow() };
|
||||||
|
@ -149,7 +151,8 @@ public:
|
||||||
void set_color(const Color& color) { m_inherited.color = color; }
|
void set_color(const Color& color) { m_inherited.color = color; }
|
||||||
void set_cursor(CSS::Cursor cursor) { m_inherited.cursor = cursor; }
|
void set_cursor(CSS::Cursor cursor) { m_inherited.cursor = cursor; }
|
||||||
void set_background_color(const Color& color) { m_noninherited.background_color = color; }
|
void set_background_color(const Color& color) { m_noninherited.background_color = color; }
|
||||||
void set_background_repeat(CSS::Repeat repeat) { m_noninherited.background_repeat = repeat; }
|
void set_background_repeat_x(CSS::Repeat repeat) { m_noninherited.background_repeat_x = repeat; }
|
||||||
|
void set_background_repeat_y(CSS::Repeat repeat) { m_noninherited.background_repeat_y = repeat; }
|
||||||
void set_float(CSS::Float value) { m_noninherited.float_ = value; }
|
void set_float(CSS::Float value) { m_noninherited.float_ = value; }
|
||||||
void set_clear(CSS::Clear value) { m_noninherited.clear = value; }
|
void set_clear(CSS::Clear value) { m_noninherited.clear = value; }
|
||||||
void set_z_index(Optional<int> value) { m_noninherited.z_index = value; }
|
void set_z_index(Optional<int> value) { m_noninherited.z_index = value; }
|
||||||
|
|
|
@ -18,8 +18,20 @@
|
||||||
"initial": "0% 0%"
|
"initial": "0% 0%"
|
||||||
},
|
},
|
||||||
"background-repeat": {
|
"background-repeat": {
|
||||||
|
"longhands": [
|
||||||
|
"background-repeat-x",
|
||||||
|
"background-repeat-y"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"background-repeat-x": {
|
||||||
"inherited": false,
|
"inherited": false,
|
||||||
"initial": "repeat"
|
"initial": "repeat",
|
||||||
|
"pseudo": true
|
||||||
|
},
|
||||||
|
"background-repeat-y": {
|
||||||
|
"inherited": false,
|
||||||
|
"initial": "repeat",
|
||||||
|
"pseudo": true
|
||||||
},
|
},
|
||||||
"border": {
|
"border": {
|
||||||
"longhands": [
|
"longhands": [
|
||||||
|
|
|
@ -612,9 +612,29 @@ Optional<CSS::Overflow> StyleProperties::overflow(CSS::PropertyID property_id) c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<CSS::Repeat> StyleProperties::background_repeat() const
|
Optional<CSS::Repeat> StyleProperties::background_repeat_x() const
|
||||||
{
|
{
|
||||||
auto value = property(CSS::PropertyID::BackgroundRepeat);
|
auto value = property(CSS::PropertyID::BackgroundRepeatX);
|
||||||
|
if (!value.has_value())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
switch (value.value()->to_identifier()) {
|
||||||
|
case CSS::ValueID::NoRepeat:
|
||||||
|
return CSS::Repeat::NoRepeat;
|
||||||
|
case CSS::ValueID::Repeat:
|
||||||
|
return CSS::Repeat::Repeat;
|
||||||
|
case CSS::ValueID::Round:
|
||||||
|
return CSS::Repeat::Round;
|
||||||
|
case CSS::ValueID::Space:
|
||||||
|
return CSS::Repeat::Space;
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<CSS::Repeat> StyleProperties::background_repeat_y() const
|
||||||
|
{
|
||||||
|
auto value = property(CSS::PropertyID::BackgroundRepeatY);
|
||||||
if (!value.has_value())
|
if (!value.has_value())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
@ -623,10 +643,6 @@ Optional<CSS::Repeat> StyleProperties::background_repeat() const
|
||||||
return CSS::Repeat::NoRepeat;
|
return CSS::Repeat::NoRepeat;
|
||||||
case CSS::ValueID::Repeat:
|
case CSS::ValueID::Repeat:
|
||||||
return CSS::Repeat::Repeat;
|
return CSS::Repeat::Repeat;
|
||||||
case CSS::ValueID::RepeatX:
|
|
||||||
return CSS::Repeat::RepeatX;
|
|
||||||
case CSS::ValueID::RepeatY:
|
|
||||||
return CSS::Repeat::RepeatY;
|
|
||||||
case CSS::ValueID::Round:
|
case CSS::ValueID::Round:
|
||||||
return CSS::Repeat::Round;
|
return CSS::Repeat::Round;
|
||||||
case CSS::ValueID::Space:
|
case CSS::ValueID::Space:
|
||||||
|
|
|
@ -73,7 +73,8 @@ public:
|
||||||
Optional<CSS::FlexDirection> flex_direction() const;
|
Optional<CSS::FlexDirection> flex_direction() const;
|
||||||
Optional<CSS::Overflow> overflow_x() const;
|
Optional<CSS::Overflow> overflow_x() const;
|
||||||
Optional<CSS::Overflow> overflow_y() const;
|
Optional<CSS::Overflow> overflow_y() const;
|
||||||
Optional<CSS::Repeat> background_repeat() const;
|
Optional<CSS::Repeat> background_repeat_x() const;
|
||||||
|
Optional<CSS::Repeat> background_repeat_y() const;
|
||||||
|
|
||||||
const Gfx::Font& font() const
|
const Gfx::Font& font() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -229,6 +229,24 @@ static inline void set_property_border_style(StyleProperties& style, const Style
|
||||||
style.set_property(CSS::PropertyID::BorderLeftStyle, value);
|
style.set_property(CSS::PropertyID::BorderLeftStyle, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool is_background_repeat_property(const StyleValue& value)
|
||||||
|
{
|
||||||
|
if (!value.is_identifier())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (value.to_identifier()) {
|
||||||
|
case CSS::ValueID::NoRepeat:
|
||||||
|
case CSS::ValueID::Repeat:
|
||||||
|
case CSS::ValueID::RepeatX:
|
||||||
|
case CSS::ValueID::RepeatY:
|
||||||
|
case CSS::ValueID::Round:
|
||||||
|
case CSS::ValueID::Space:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void set_property_expanding_shorthands(StyleProperties& style, CSS::PropertyID property_id, const StyleValue& value, DOM::Document& document, bool is_internally_generated_pseudo_property = false)
|
static void set_property_expanding_shorthands(StyleProperties& style, CSS::PropertyID property_id, const StyleValue& value, DOM::Document& document, bool is_internally_generated_pseudo_property = false)
|
||||||
{
|
{
|
||||||
CSS::ParsingContext context(document);
|
CSS::ParsingContext context(document);
|
||||||
|
@ -433,12 +451,22 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope
|
||||||
if (values[0].is_color() && color_value_count == 1)
|
if (values[0].is_color() && color_value_count == 1)
|
||||||
style.set_property(CSS::PropertyID::BackgroundColor, values[0]);
|
style.set_property(CSS::PropertyID::BackgroundColor, values[0]);
|
||||||
|
|
||||||
for (auto& value : values) {
|
for (auto it = values.begin(); it != values.end(); ++it) {
|
||||||
if (value.is_identifier())
|
auto& value = *it;
|
||||||
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeat, value, document);
|
|
||||||
|
if (is_background_repeat_property(value)) {
|
||||||
|
if ((it + 1 != values.end()) && is_background_repeat_property(*(it + 1))) {
|
||||||
|
++it;
|
||||||
|
|
||||||
|
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeatX, value, document, true);
|
||||||
|
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeatY, *it, document, true);
|
||||||
|
} else {
|
||||||
|
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeat, value, document);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!value.is_string())
|
if (!value.is_string())
|
||||||
continue;
|
continue;
|
||||||
auto string = value.to_string();
|
|
||||||
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundImage, value, document);
|
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundImage, value, document);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -464,7 +492,40 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope
|
||||||
}
|
}
|
||||||
|
|
||||||
if (property_id == CSS::PropertyID::BackgroundRepeat) {
|
if (property_id == CSS::PropertyID::BackgroundRepeat) {
|
||||||
style.set_property(CSS::PropertyID::BackgroundRepeat, value);
|
auto parts = split_on_whitespace(value.to_string());
|
||||||
|
NonnullRefPtrVector<StyleValue> values;
|
||||||
|
for (auto& part : parts) {
|
||||||
|
auto value = parse_css_value(context, part);
|
||||||
|
if (!value || !is_background_repeat_property(*value))
|
||||||
|
return;
|
||||||
|
values.append(value.release_nonnull());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.size() == 1) {
|
||||||
|
auto value_id = values[0].to_identifier();
|
||||||
|
if (value_id == CSS::ValueID::RepeatX || value_id == CSS::ValueID::RepeatY) {
|
||||||
|
auto repeat_x = IdentifierStyleValue::create(value_id == CSS::ValueID::RepeatX ? CSS::ValueID::Repeat : CSS::ValueID::NoRepeat);
|
||||||
|
auto repeat_y = IdentifierStyleValue::create(value_id == CSS::ValueID::RepeatX ? CSS::ValueID::NoRepeat : CSS::ValueID::Repeat);
|
||||||
|
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeatX, repeat_x, document, true);
|
||||||
|
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeatY, repeat_y, document, true);
|
||||||
|
} else {
|
||||||
|
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeatX, values[0], document, true);
|
||||||
|
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeatY, values[0], document, true);
|
||||||
|
}
|
||||||
|
} else if (values.size() == 2) {
|
||||||
|
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeatX, values[0], document, true);
|
||||||
|
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeatY, values[1], document, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (property_id == CSS::PropertyID::BackgroundRepeatX || property_id == CSS::PropertyID::BackgroundRepeatY) {
|
||||||
|
auto value_id = value.to_identifier();
|
||||||
|
if (value_id == CSS::ValueID::RepeatX || value_id == CSS::ValueID::RepeatY)
|
||||||
|
return;
|
||||||
|
|
||||||
|
style.set_property(property_id, value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -192,8 +192,6 @@ enum class Overflow : u8 {
|
||||||
enum class Repeat : u8 {
|
enum class Repeat : u8 {
|
||||||
NoRepeat,
|
NoRepeat,
|
||||||
Repeat,
|
Repeat,
|
||||||
RepeatX,
|
|
||||||
RepeatY,
|
|
||||||
Round,
|
Round,
|
||||||
Space,
|
Space,
|
||||||
};
|
};
|
||||||
|
|
|
@ -362,7 +362,7 @@ RefPtr<Gfx::Bitmap> Document::background_image() const
|
||||||
return background_image->bitmap();
|
return background_image->bitmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
CSS::Repeat Document::background_repeat() const
|
CSS::Repeat Document::background_repeat_x() const
|
||||||
{
|
{
|
||||||
auto* body_element = body();
|
auto* body_element = body();
|
||||||
if (!body_element)
|
if (!body_element)
|
||||||
|
@ -372,7 +372,20 @@ CSS::Repeat Document::background_repeat() const
|
||||||
if (!body_layout_node)
|
if (!body_layout_node)
|
||||||
return CSS::Repeat::Repeat;
|
return CSS::Repeat::Repeat;
|
||||||
|
|
||||||
return body_layout_node->computed_values().background_repeat();
|
return body_layout_node->computed_values().background_repeat_x();
|
||||||
|
}
|
||||||
|
|
||||||
|
CSS::Repeat Document::background_repeat_y() const
|
||||||
|
{
|
||||||
|
auto* body_element = body();
|
||||||
|
if (!body_element)
|
||||||
|
return CSS::Repeat::Repeat;
|
||||||
|
|
||||||
|
auto* body_layout_node = body_element->layout_node();
|
||||||
|
if (!body_layout_node)
|
||||||
|
return CSS::Repeat::Repeat;
|
||||||
|
|
||||||
|
return body_layout_node->computed_values().background_repeat_y();
|
||||||
}
|
}
|
||||||
|
|
||||||
URL Document::complete_url(const String& string) const
|
URL Document::complete_url(const String& string) const
|
||||||
|
|
|
@ -129,7 +129,8 @@ public:
|
||||||
|
|
||||||
Color background_color(const Gfx::Palette&) const;
|
Color background_color(const Gfx::Palette&) const;
|
||||||
RefPtr<Gfx::Bitmap> background_image() const;
|
RefPtr<Gfx::Bitmap> background_image() const;
|
||||||
CSS::Repeat background_repeat() const;
|
CSS::Repeat background_repeat_x() const;
|
||||||
|
CSS::Repeat background_repeat_y() const;
|
||||||
|
|
||||||
Color link_color() const;
|
Color link_color() const;
|
||||||
void set_link_color(Color);
|
void set_link_color(Color);
|
||||||
|
|
|
@ -50,7 +50,7 @@ void Box::paint(PaintContext& context, PaintPhase phase)
|
||||||
context.painter().fill_rect(background_rect, computed_values().background_color());
|
context.painter().fill_rect(background_rect, computed_values().background_color());
|
||||||
|
|
||||||
if (background_image() && background_image()->bitmap()) {
|
if (background_image() && background_image()->bitmap()) {
|
||||||
paint_background_image(context, *background_image()->bitmap(), computed_values().background_repeat(), move(background_rect));
|
paint_background_image(context, *background_image()->bitmap(), computed_values().background_repeat_x(), computed_values().background_repeat_y(), move(background_rect));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,22 +87,30 @@ void Box::paint(PaintContext& context, PaintPhase phase)
|
||||||
void Box::paint_background_image(
|
void Box::paint_background_image(
|
||||||
PaintContext& context,
|
PaintContext& context,
|
||||||
const Gfx::Bitmap& background_image,
|
const Gfx::Bitmap& background_image,
|
||||||
CSS::Repeat background_repeat,
|
CSS::Repeat background_repeat_x,
|
||||||
|
CSS::Repeat background_repeat_y,
|
||||||
Gfx::IntRect background_rect)
|
Gfx::IntRect background_rect)
|
||||||
{
|
{
|
||||||
switch (background_repeat) {
|
switch (background_repeat_x) {
|
||||||
|
case CSS::Repeat::Round:
|
||||||
|
case CSS::Repeat::Space:
|
||||||
|
// FIXME: Support 'round' and 'space'. Fall through to 'repeat' since that most closely resembles these.
|
||||||
case CSS::Repeat::Repeat:
|
case CSS::Repeat::Repeat:
|
||||||
// The background rect is already sized to align with 'repeat'.
|
// The background rect is already sized to align with 'repeat'.
|
||||||
break;
|
break;
|
||||||
case CSS::Repeat::RepeatX:
|
case CSS::Repeat::NoRepeat:
|
||||||
background_rect.set_height(background_image.height());
|
|
||||||
break;
|
|
||||||
case CSS::Repeat::RepeatY:
|
|
||||||
background_rect.set_width(background_image.width());
|
background_rect.set_width(background_image.width());
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (background_repeat_y) {
|
||||||
|
case CSS::Repeat::Round:
|
||||||
|
case CSS::Repeat::Space:
|
||||||
|
// FIXME: Support 'round' and 'space'. Fall through to 'repeat' since that most closely resembles these.
|
||||||
|
case CSS::Repeat::Repeat:
|
||||||
|
// The background rect is already sized to align with 'repeat'.
|
||||||
|
break;
|
||||||
case CSS::Repeat::NoRepeat:
|
case CSS::Repeat::NoRepeat:
|
||||||
default: // FIXME: Support 'round' and 'square'
|
|
||||||
background_rect.set_width(background_image.width());
|
|
||||||
background_rect.set_height(background_image.height());
|
background_rect.set_height(background_image.height());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,7 +153,7 @@ protected:
|
||||||
|
|
||||||
virtual void did_set_rect() { }
|
virtual void did_set_rect() { }
|
||||||
|
|
||||||
void paint_background_image(PaintContext&, const Gfx::Bitmap&, CSS::Repeat, Gfx::IntRect);
|
void paint_background_image(PaintContext&, const Gfx::Bitmap&, CSS::Repeat, CSS::Repeat, Gfx::IntRect);
|
||||||
|
|
||||||
Vector<LineBox> m_line_boxes;
|
Vector<LineBox> m_line_boxes;
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ void InitialContainingBlockBox::paint_document_background(PaintContext& context)
|
||||||
|
|
||||||
if (auto background_bitmap = document().background_image()) {
|
if (auto background_bitmap = document().background_image()) {
|
||||||
Gfx::IntRect background_rect = { 0, 0, context.viewport_rect().x() + context.viewport_rect().width(), context.viewport_rect().y() + context.viewport_rect().height() };
|
Gfx::IntRect background_rect = { 0, 0, context.viewport_rect().x() + context.viewport_rect().width(), context.viewport_rect().y() + context.viewport_rect().height() };
|
||||||
paint_background_image(context, *background_bitmap, document().background_repeat(), move(background_rect));
|
paint_background_image(context, *background_bitmap, document().background_repeat_x(), document().background_repeat_y(), move(background_rect));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -234,9 +234,13 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& specified_style)
|
||||||
m_background_image = static_ptr_cast<CSS::ImageStyleValue>(bgimage.value());
|
m_background_image = static_ptr_cast<CSS::ImageStyleValue>(bgimage.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto background_repeat = specified_style.background_repeat();
|
auto background_repeat_x = specified_style.background_repeat_x();
|
||||||
if (background_repeat.has_value())
|
if (background_repeat_x.has_value())
|
||||||
computed_values.set_background_repeat(background_repeat.value());
|
computed_values.set_background_repeat_x(background_repeat_x.value());
|
||||||
|
|
||||||
|
auto background_repeat_y = specified_style.background_repeat_y();
|
||||||
|
if (background_repeat_y.has_value())
|
||||||
|
computed_values.set_background_repeat_y(background_repeat_y.value());
|
||||||
|
|
||||||
computed_values.set_display(specified_style.display());
|
computed_values.set_display(specified_style.display());
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue