Browse Source

LibWeb: Store background layers in ComputedValues

Instead of storing these as individual `background-foo` properties, we
combine them together into layers, since that is how they will be
painted. It also makes it more convenient to pass them around.
Sam Atkins 3 years ago
parent
commit
cdeac132dc

+ 9 - 0
Userland/Libraries/LibWeb/CSS/ComputedValues.h

@@ -39,6 +39,12 @@ public:
     static float opacity() { return 1.0f; }
     static float opacity() { return 1.0f; }
 };
 };
 
 
+struct BackgroundLayerData {
+    RefPtr<CSS::ImageStyleValue> image;
+    CSS::Repeat repeat_x;
+    CSS::Repeat repeat_y;
+};
+
 struct BorderData {
 struct BorderData {
 public:
 public:
     Color color { Color::Transparent };
     Color color { Color::Transparent };
@@ -119,6 +125,7 @@ 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; }
+    Vector<BackgroundLayerData> const& background_layers() const { return m_noninherited.background_layers; }
     BackgroundRepeatData background_repeat() const { return m_noninherited.background_repeat; }
     BackgroundRepeatData background_repeat() const { return m_noninherited.background_repeat; }
 
 
     CSS::ListStyleType list_style_type() const { return m_inherited.list_style_type; }
     CSS::ListStyleType list_style_type() const { return m_inherited.list_style_type; }
@@ -176,6 +183,7 @@ protected:
         Length border_top_left_radius;
         Length border_top_left_radius;
         Length border_top_right_radius;
         Length border_top_right_radius;
         Color background_color { InitialValues::background_color() };
         Color background_color { InitialValues::background_color() };
+        Vector<BackgroundLayerData> background_layers;
         BackgroundRepeatData background_repeat { InitialValues::background_repeat(), InitialValues::background_repeat() };
         BackgroundRepeatData background_repeat { InitialValues::background_repeat(), InitialValues::background_repeat() };
         CSS::FlexDirection flex_direction { InitialValues::flex_direction() };
         CSS::FlexDirection flex_direction { InitialValues::flex_direction() };
         CSS::FlexWrap flex_wrap { InitialValues::flex_wrap() };
         CSS::FlexWrap flex_wrap { InitialValues::flex_wrap() };
@@ -203,6 +211,7 @@ public:
     void set_pointer_events(CSS::PointerEvents value) { m_inherited.pointer_events = value; }
     void set_pointer_events(CSS::PointerEvents value) { m_inherited.pointer_events = value; }
     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(BackgroundRepeatData repeat) { m_noninherited.background_repeat = repeat; }
     void set_background_repeat(BackgroundRepeatData repeat) { m_noninherited.background_repeat = repeat; }
+    void set_background_layers(Vector<BackgroundLayerData>&& layers) { m_noninherited.background_layers = move(layers); }
     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; }

+ 13 - 0
Userland/Libraries/LibWeb/DOM/Document.cpp

@@ -353,6 +353,19 @@ Color Document::background_color(const Palette& palette) const
     return color;
     return color;
 }
 }
 
 
+Vector<CSS::BackgroundLayerData> const* Document::background_layers() const
+{
+    auto* body_element = body();
+    if (!body_element)
+        return {};
+
+    auto* body_layout_node = body_element->layout_node();
+    if (!body_layout_node)
+        return {};
+
+    return &body_layout_node->background_layers();
+}
+
 RefPtr<Gfx::Bitmap> Document::background_image() const
 RefPtr<Gfx::Bitmap> Document::background_image() const
 {
 {
     auto* body_element = body();
     auto* body_element = body();

+ 1 - 0
Userland/Libraries/LibWeb/DOM/Document.h

@@ -130,6 +130,7 @@ public:
     const Page* page() const;
     const Page* page() const;
 
 
     Color background_color(const Gfx::Palette&) const;
     Color background_color(const Gfx::Palette&) const;
+    Vector<CSS::BackgroundLayerData> const* background_layers() const;
     RefPtr<Gfx::Bitmap> background_image() const;
     RefPtr<Gfx::Bitmap> background_image() const;
     CSS::Repeat background_repeat_x() const;
     CSS::Repeat background_repeat_x() const;
     CSS::Repeat background_repeat_y() const;
     CSS::Repeat background_repeat_y() const;

+ 2 - 0
Userland/Libraries/LibWeb/Layout/Box.cpp

@@ -72,6 +72,7 @@ void Box::paint_background(PaintContext& context)
 
 
     Gfx::IntRect background_rect;
     Gfx::IntRect background_rect;
     Color background_color = computed_values().background_color();
     Color background_color = computed_values().background_color();
+    auto* background_layers = &computed_values().background_layers();
     const Gfx::Bitmap* background_image = this->background_image() ? this->background_image()->bitmap() : nullptr;
     const Gfx::Bitmap* background_image = this->background_image() ? this->background_image()->bitmap() : nullptr;
     CSS::BackgroundRepeatData background_repeat = computed_values().background_repeat();
     CSS::BackgroundRepeatData background_repeat = computed_values().background_repeat();
 
 
@@ -82,6 +83,7 @@ void Box::paint_background(PaintContext& context)
         // Section 2.11.2: If the computed value of background-image on the root element is none and its background-color is transparent,
         // Section 2.11.2: If the computed value of background-image on the root element is none and its background-color is transparent,
         // user agents must instead propagate the computed values of the background properties from that element’s first HTML BODY child element.
         // user agents must instead propagate the computed values of the background properties from that element’s first HTML BODY child element.
         if (document().html_element()->should_use_body_background_properties()) {
         if (document().html_element()->should_use_body_background_properties()) {
+            background_layers = document().background_layers();
             background_color = document().background_color(context.palette());
             background_color = document().background_color(context.palette());
             background_image = document().background_image();
             background_image = document().background_image();
             background_repeat = { document().background_repeat_x(), document().background_repeat_y() };
             background_repeat = { document().background_repeat_x(), document().background_repeat_y() };

+ 60 - 1
Userland/Libraries/LibWeb/Layout/Node.cpp

@@ -215,6 +215,66 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& specified_style)
             m_font_size = default_font_size;
             m_font_size = default_font_size;
     }
     }
 
 
+    {
+        auto attachments = specified_style.property(CSS::PropertyID::BackgroundAttachment);
+        auto clips = specified_style.property(CSS::PropertyID::BackgroundClip);
+        auto images = specified_style.property(CSS::PropertyID::BackgroundImage);
+        auto origins = specified_style.property(CSS::PropertyID::BackgroundOrigin);
+        auto positions = specified_style.property(CSS::PropertyID::BackgroundPosition);
+        auto repeats = specified_style.property(CSS::PropertyID::BackgroundRepeat);
+        auto sizes = specified_style.property(CSS::PropertyID::BackgroundSize);
+
+        auto count_layers = [](auto maybe_style_value) -> size_t {
+            if (maybe_style_value.has_value() && maybe_style_value.value()->is_value_list())
+                return maybe_style_value.value()->as_value_list().size();
+            else
+                return 1;
+        };
+
+        auto value_for_layer = [](auto maybe_style_value, size_t layer_index) -> RefPtr<CSS::StyleValue> {
+            if (!maybe_style_value.has_value())
+                return nullptr;
+            auto& style_value = maybe_style_value.value();
+            if (style_value->is_value_list())
+                return style_value->as_value_list().value_at(layer_index, true);
+            return style_value;
+        };
+
+        size_t layer_count = 1;
+        layer_count = max(layer_count, count_layers(attachments));
+        layer_count = max(layer_count, count_layers(clips));
+        layer_count = max(layer_count, count_layers(images));
+        layer_count = max(layer_count, count_layers(origins));
+        layer_count = max(layer_count, count_layers(positions));
+        layer_count = max(layer_count, count_layers(repeats));
+        layer_count = max(layer_count, count_layers(sizes));
+
+        Vector<CSS::BackgroundLayerData> layers;
+        layers.ensure_capacity(layer_count);
+
+        for (size_t layer_index = 0; layer_index < layer_count; layer_index++) {
+            CSS::BackgroundLayerData layer;
+
+            // TODO: Other properties
+
+            if (auto image_value = value_for_layer(images, layer_index); image_value && image_value->is_image()) {
+                layer.image = image_value->as_image();
+                layer.image->load_bitmap(document());
+            }
+
+            if (auto repeat_value = value_for_layer(repeats, layer_index); repeat_value && repeat_value->is_background_repeat()) {
+                layer.repeat_x = repeat_value->as_background_repeat().repeat_x();
+                layer.repeat_y = repeat_value->as_background_repeat().repeat_y();
+            }
+
+            layers.append(move(layer));
+        }
+
+        computed_values.set_background_layers(move(layers));
+    }
+    computed_values.set_background_color(specified_style.color_or_fallback(CSS::PropertyID::BackgroundColor, *this, CSS::InitialValues::background_color()));
+
+    // FIXME: Remove this
     auto bgimage = specified_style.property(CSS::PropertyID::BackgroundImage);
     auto bgimage = specified_style.property(CSS::PropertyID::BackgroundImage);
     if (bgimage.has_value() && bgimage.value()->is_image()) {
     if (bgimage.has_value() && bgimage.value()->is_image()) {
         m_background_image = bgimage.value()->as_image();
         m_background_image = bgimage.value()->as_image();
@@ -323,7 +383,6 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& specified_style)
     }
     }
 
 
     computed_values.set_color(specified_style.color_or_fallback(CSS::PropertyID::Color, *this, CSS::InitialValues::color()));
     computed_values.set_color(specified_style.color_or_fallback(CSS::PropertyID::Color, *this, CSS::InitialValues::color()));
-    computed_values.set_background_color(specified_style.color_or_fallback(CSS::PropertyID::BackgroundColor, *this, CSS::InitialValues::background_color()));
 
 
     computed_values.set_z_index(specified_style.z_index());
     computed_values.set_z_index(specified_style.z_index());
     computed_values.set_opacity(specified_style.opacity());
     computed_values.set_opacity(specified_style.opacity());

+ 1 - 0
Userland/Libraries/LibWeb/Layout/Node.h

@@ -206,6 +206,7 @@ public:
     float line_height() const { return m_line_height; }
     float line_height() const { return m_line_height; }
     float font_size() const { return m_font_size; }
     float font_size() const { return m_font_size; }
     const CSS::ImageStyleValue* background_image() const { return m_background_image; }
     const CSS::ImageStyleValue* background_image() const { return m_background_image; }
+    Vector<CSS::BackgroundLayerData> const& background_layers() const { return computed_values().background_layers(); }
     const CSS::ImageStyleValue* list_style_image() const { return m_list_style_image; }
     const CSS::ImageStyleValue* list_style_image() const { return m_list_style_image; }
 
 
     NonnullRefPtr<NodeWithStyle> create_anonymous_wrapper() const;
     NonnullRefPtr<NodeWithStyle> create_anonymous_wrapper() const;