diff options
author | Egor Ananyin <ananinegor@gmail.com> | 2021-05-07 19:03:25 +0300 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-05-07 22:27:48 +0200 |
commit | d2b61487870073ad4aba150bf8e46f87ae807c85 (patch) | |
tree | 5515473356a2791c7347bdd131b9933cb6f3b5e7 /Userland/Libraries/LibWeb/Painting | |
parent | 33af7075e7624c1e30dc4a52039e2f6bf3fc5823 (diff) | |
download | serenity-d2b61487870073ad4aba150bf8e46f87ae807c85.zip |
LibWeb: Make painting order more spec-compliant
Now our painting order inside stacking contexts is closer to the
algorithm specified by CSS 2.1 (see section 9.9 and Appendix E)
Diffstat (limited to 'Userland/Libraries/LibWeb/Painting')
-rw-r--r-- | Userland/Libraries/LibWeb/Painting/StackingContext.cpp | 72 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Painting/StackingContext.h | 10 |
2 files changed, 73 insertions, 9 deletions
diff --git a/Userland/Libraries/LibWeb/Painting/StackingContext.cpp b/Userland/Libraries/LibWeb/Painting/StackingContext.cpp index 1d3565065d..bbd9e8ae76 100644 --- a/Userland/Libraries/LibWeb/Painting/StackingContext.cpp +++ b/Userland/Libraries/LibWeb/Painting/StackingContext.cpp @@ -22,24 +22,80 @@ StackingContext::StackingContext(Box& box, StackingContext* parent) m_parent->m_children.append(this); // FIXME: Don't sort on every append.. + // FIXME: Apparently this also breaks tree order inside layers quick_sort(m_parent->m_children, [](auto& a, auto& b) { return a->m_box.computed_values().z_index().value_or(0) < b->m_box.computed_values().z_index().value_or(0); }); } } -void StackingContext::paint(PaintContext& context, PaintPhase phase) +void StackingContext::paint_descendants(PaintContext& context, Node& box, StackingContextPaintPhase phase) { - if (!is<InitialContainingBlockBox>(m_box)) { - m_box.paint(context, phase); - } else { - // NOTE: InitialContainingBlockBox::paint() merely calls StackingContext::paint() - // so we call its base class instead. - downcast<InitialContainingBlockBox>(m_box).BlockBox::paint(context, phase); + box.for_each_child([&](auto& child) { + switch (phase) { + case StackingContextPaintPhase::BackgroundAndBorders: + if (!child.is_floating() && !child.is_positioned()) { + child.paint(context, PaintPhase::Background); + child.paint(context, PaintPhase::Border); + paint_descendants(context, child, phase); + } + break; + case StackingContextPaintPhase::Floats: + if (!child.is_positioned()) { + if (child.is_floating()) { + child.paint(context, PaintPhase::Background); + child.paint(context, PaintPhase::Border); + paint_descendants(context, child, StackingContextPaintPhase::BackgroundAndBorders); + } + paint_descendants(context, child, phase); + } + break; + case StackingContextPaintPhase::Foreground: + if (!child.is_positioned()) { + child.paint(context, PaintPhase::Foreground); + child.before_children_paint(context, PaintPhase::Foreground); + paint_descendants(context, child, phase); + child.after_children_paint(context, PaintPhase::Foreground); + } + break; + case StackingContextPaintPhase::FocusAndOverlay: + if (context.has_focus()) { + child.paint(context, PaintPhase::FocusOutline); + } + child.paint(context, PaintPhase::Overlay); + paint_descendants(context, child, phase); + break; + } + }); +} + +void StackingContext::paint(PaintContext& context) +{ + // For a more elaborate description of the algorithm, see CSS 2.1 Appendix E + // Draw the background and borders for the context root (steps 1, 2) + m_box.paint(context, PaintPhase::Background); + m_box.paint(context, PaintPhase::Border); + // Draw positioned descendants with negative z-indices (step 3) + for (auto* child : m_children) { + if (child->m_box.computed_values().z_index().has_value() && child->m_box.computed_values().z_index().value() < 0) + child->paint(context); } + // Draw the background and borders for block-level children (step 4) + paint_descendants(context, m_box, StackingContextPaintPhase::BackgroundAndBorders); + // Draw the non-positioned floats (step 5) + paint_descendants(context, m_box, StackingContextPaintPhase::Floats); + // Draw inline content, replaced content, etc. (steps 6, 7) + paint_descendants(context, m_box, StackingContextPaintPhase::Foreground); + // Draw other positioned descendants (steps 8, 9) for (auto* child : m_children) { - child->paint(context, phase); + if (child->m_box.computed_values().z_index().has_value() && child->m_box.computed_values().z_index().value() < 0) + continue; + child->paint(context); } + + m_box.paint(context, PaintPhase::FocusOutline); + m_box.paint(context, PaintPhase::Overlay); + paint_descendants(context, m_box, StackingContextPaintPhase::FocusAndOverlay); } HitTestResult StackingContext::hit_test(const Gfx::IntPoint& position, HitTestType type) const diff --git a/Userland/Libraries/LibWeb/Painting/StackingContext.h b/Userland/Libraries/LibWeb/Painting/StackingContext.h index 7dccd290d4..687e887b49 100644 --- a/Userland/Libraries/LibWeb/Painting/StackingContext.h +++ b/Userland/Libraries/LibWeb/Painting/StackingContext.h @@ -18,7 +18,15 @@ public: StackingContext* parent() { return m_parent; } const StackingContext* parent() const { return m_parent; } - void paint(PaintContext&, PaintPhase); + enum class StackingContextPaintPhase { + BackgroundAndBorders, + Floats, + Foreground, + FocusAndOverlay, + }; + + void paint_descendants(PaintContext&, Node&, StackingContextPaintPhase); + void paint(PaintContext&); HitTestResult hit_test(const Gfx::IntPoint&, HitTestType) const; void dump(int indent = 0) const; |