Browse Source

LibWeb: Paint line box fragments during all paint phases

Fragment painting was very limited by only being called during the
foreground paint phase. We now paint fragments as part of every phase
(and the phase is passed to paint_fragment() of course!)
Andreas Kling 4 years ago
parent
commit
311e1039b5

+ 6 - 8
Libraries/LibWeb/Layout/BlockBox.cpp

@@ -57,17 +57,15 @@ void BlockBox::paint(PaintContext& context, PaintPhase phase)
     if (!children_are_inline())
         return;
 
-    // FIXME: Inline backgrounds etc.
-    if (phase == PaintPhase::Foreground) {
-        for (auto& line_box : m_line_boxes) {
-            for (auto& fragment : line_box.fragments()) {
-                if (context.should_show_line_box_borders())
-                    context.painter().draw_rect(enclosing_int_rect(fragment.absolute_rect()), Color::Green);
-                fragment.paint(context);
-            }
+    for (auto& line_box : m_line_boxes) {
+        for (auto& fragment : line_box.fragments()) {
+            if (context.should_show_line_box_borders())
+                context.painter().draw_rect(enclosing_int_rect(fragment.absolute_rect()), Color::Green);
+            fragment.paint(context, phase);
         }
     }
 
+    // FIXME: Merge this loop with the above somehow..
     if (phase == PaintPhase::FocusOutline) {
         for (auto& line_box : m_line_boxes) {
             for (auto& fragment : line_box.fragments()) {

+ 2 - 2
Libraries/LibWeb/Layout/LineBoxFragment.cpp

@@ -34,7 +34,7 @@
 
 namespace Web::Layout {
 
-void LineBoxFragment::paint(PaintContext& context)
+void LineBoxFragment::paint(PaintContext& context, PaintPhase phase)
 {
     for (auto* ancestor = layout_node().parent(); ancestor; ancestor = ancestor->parent()) {
         if (!ancestor->is_visible())
@@ -42,7 +42,7 @@ void LineBoxFragment::paint(PaintContext& context)
     }
 
     if (is<TextNode>(layout_node()))
-        downcast<TextNode>(layout_node()).paint_fragment(context, *this);
+        downcast<TextNode>(layout_node()).paint_fragment(context, *this, phase);
 }
 
 bool LineBoxFragment::ends_in_whitespace() const

+ 1 - 1
Libraries/LibWeb/Layout/LineBoxFragment.h

@@ -61,7 +61,7 @@ public:
 
     float absolute_x() const { return absolute_rect().x(); }
 
-    void paint(PaintContext&);
+    void paint(PaintContext&, PaintPhase);
 
     bool ends_in_whitespace() const;
     bool is_justifiable_whitespace() const;

+ 38 - 34
Libraries/LibWeb/Layout/TextNode.cpp

@@ -66,44 +66,48 @@ const String& TextNode::text_for_style(const CSS::StyleProperties& style) const
     return dom_node().data();
 }
 
-void TextNode::paint_fragment(PaintContext& context, const LineBoxFragment& fragment) const
+void TextNode::paint_fragment(PaintContext& context, const LineBoxFragment& fragment, PaintPhase phase) const
 {
     auto& painter = context.painter();
-    painter.set_font(specified_style().font());
-
-    auto background_color = specified_style().property(CSS::PropertyID::BackgroundColor);
-    if (background_color.has_value() && background_color.value()->is_color())
-        painter.fill_rect(enclosing_int_rect(fragment.absolute_rect()), background_color.value()->to_color(document()));
-
-    auto color = specified_style().color_or_fallback(CSS::PropertyID::Color, document(), context.palette().base_text());
-    auto text_decoration = specified_style().string_or_fallback(CSS::PropertyID::TextDecoration, "none");
-
-    if (document().inspected_node() == &dom_node())
-        context.painter().draw_rect(enclosing_int_rect(fragment.absolute_rect()), Color::Magenta);
-
-    bool is_underline = text_decoration == "underline";
-    if (is_underline)
-        painter.draw_line(enclosing_int_rect(fragment.absolute_rect()).bottom_left().translated(0, 1), enclosing_int_rect(fragment.absolute_rect()).bottom_right().translated(0, 1), color);
-
-    // FIXME: text-transform should be done already in layout, since uppercase glyphs may be wider than lowercase, etc.
-    auto text = m_text_for_rendering;
-    auto text_transform = specified_style().string_or_fallback(CSS::PropertyID::TextTransform, "none");
-    if (text_transform == "uppercase")
-        text = m_text_for_rendering.to_uppercase();
-    if (text_transform == "lowercase")
-        text = m_text_for_rendering.to_lowercase();
-
-    painter.draw_text(enclosing_int_rect(fragment.absolute_rect()), text.substring_view(fragment.start(), fragment.length()), Gfx::TextAlignment::TopLeft, color);
-
-    auto selection_rect = fragment.selection_rect(specified_style().font());
-    if (!selection_rect.is_empty()) {
-        painter.fill_rect(enclosing_int_rect(selection_rect), context.palette().selection());
-        Gfx::PainterStateSaver saver(painter);
-        painter.add_clip_rect(enclosing_int_rect(selection_rect));
-        painter.draw_text(enclosing_int_rect(fragment.absolute_rect()), text.substring_view(fragment.start(), fragment.length()), Gfx::TextAlignment::TopLeft, context.palette().selection_text());
+
+    if (phase == PaintPhase::Background) {
+        auto background_color = specified_style().property(CSS::PropertyID::BackgroundColor);
+        if (background_color.has_value() && background_color.value()->is_color())
+            painter.fill_rect(enclosing_int_rect(fragment.absolute_rect()), background_color.value()->to_color(document()));
     }
 
-    paint_cursor_if_needed(context, fragment);
+    if (phase == PaintPhase::Foreground) {
+        painter.set_font(specified_style().font());
+        auto color = specified_style().color_or_fallback(CSS::PropertyID::Color, document(), context.palette().base_text());
+        auto text_decoration = specified_style().string_or_fallback(CSS::PropertyID::TextDecoration, "none");
+
+        if (document().inspected_node() == &dom_node())
+            context.painter().draw_rect(enclosing_int_rect(fragment.absolute_rect()), Color::Magenta);
+
+        bool is_underline = text_decoration == "underline";
+        if (is_underline)
+            painter.draw_line(enclosing_int_rect(fragment.absolute_rect()).bottom_left().translated(0, 1), enclosing_int_rect(fragment.absolute_rect()).bottom_right().translated(0, 1), color);
+
+        // FIXME: text-transform should be done already in layout, since uppercase glyphs may be wider than lowercase, etc.
+        auto text = m_text_for_rendering;
+        auto text_transform = specified_style().string_or_fallback(CSS::PropertyID::TextTransform, "none");
+        if (text_transform == "uppercase")
+            text = m_text_for_rendering.to_uppercase();
+        if (text_transform == "lowercase")
+            text = m_text_for_rendering.to_lowercase();
+
+        painter.draw_text(enclosing_int_rect(fragment.absolute_rect()), text.substring_view(fragment.start(), fragment.length()), Gfx::TextAlignment::CenterLeft, color);
+
+        auto selection_rect = fragment.selection_rect(specified_style().font());
+        if (!selection_rect.is_empty()) {
+            painter.fill_rect(enclosing_int_rect(selection_rect), context.palette().selection());
+            Gfx::PainterStateSaver saver(painter);
+            painter.add_clip_rect(enclosing_int_rect(selection_rect));
+            painter.draw_text(enclosing_int_rect(fragment.absolute_rect()), text.substring_view(fragment.start(), fragment.length()), Gfx::TextAlignment::CenterLeft, context.palette().selection_text());
+        }
+
+        paint_cursor_if_needed(context, fragment);
+    }
 }
 
 void TextNode::paint_cursor_if_needed(PaintContext& context, const LineBoxFragment& fragment) const

+ 1 - 1
Libraries/LibWeb/Layout/TextNode.h

@@ -46,7 +46,7 @@ public:
     virtual const char* class_name() const override { return "TextNode"; }
     virtual bool is_text() const final { return true; }
 
-    void paint_fragment(PaintContext&, const LineBoxFragment&) const;
+    void paint_fragment(PaintContext&, const LineBoxFragment&, PaintPhase) const;
 
     virtual void split_into_lines(BlockBox& container, LayoutMode) override;