Title: [253631] trunk/Source/WebCore
Revision
253631
Author
za...@apple.com
Date
2019-12-17 10:31:30 -0800 (Tue, 17 Dec 2019)

Log Message

[LFC][Painting] Add basic support for z-index based painting
https://bugs.webkit.org/show_bug.cgi?id=205345
<rdar://problem/58010942>

Reviewed by Antti Koivisto.

This is just a very simple z-index based painting to be able to run WPT where
z-index is heavily used to hide/reveal red/green boxes.

* layout/displaytree/DisplayPainter.cpp:
(WebCore::Display::absoluteDisplayBox):
(WebCore::Display::isPaintRootCandidate):
(WebCore::Display::paintSubtree):
(WebCore::Display::collectPaintRootsAndContentRect):
(WebCore::Display::Painter::paint):
(WebCore::Display::paintBoxDecorationAndChildren): Deleted.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (253630 => 253631)


--- trunk/Source/WebCore/ChangeLog	2019-12-17 16:17:42 UTC (rev 253630)
+++ trunk/Source/WebCore/ChangeLog	2019-12-17 18:31:30 UTC (rev 253631)
@@ -1,3 +1,22 @@
+2019-12-17  Zalan Bujtas  <za...@apple.com>
+
+        [LFC][Painting] Add basic support for z-index based painting
+        https://bugs.webkit.org/show_bug.cgi?id=205345
+        <rdar://problem/58010942>
+
+        Reviewed by Antti Koivisto.
+
+        This is just a very simple z-index based painting to be able to run WPT where
+        z-index is heavily used to hide/reveal red/green boxes.
+
+        * layout/displaytree/DisplayPainter.cpp:
+        (WebCore::Display::absoluteDisplayBox):
+        (WebCore::Display::isPaintRootCandidate):
+        (WebCore::Display::paintSubtree):
+        (WebCore::Display::collectPaintRootsAndContentRect):
+        (WebCore::Display::Painter::paint):
+        (WebCore::Display::paintBoxDecorationAndChildren): Deleted.
+
 2019-12-17  youenn fablet  <you...@apple.com>
 
         Update session category in MockAudioSharedUnit as done in CoreAudioSharedUnit

Modified: trunk/Source/WebCore/layout/displaytree/DisplayPainter.cpp (253630 => 253631)


--- trunk/Source/WebCore/layout/displaytree/DisplayPainter.cpp	2019-12-17 16:17:42 UTC (rev 253630)
+++ trunk/Source/WebCore/layout/displaytree/DisplayPainter.cpp	2019-12-17 18:31:30 UTC (rev 253631)
@@ -146,6 +146,8 @@
     // Should never really happen but table code is way too incomplete.
     if (!layoutState.hasDisplayBox(layoutBox))
         return { };
+    if (layoutBox.isInitialContainingBlock())
+        return layoutState.displayBoxForLayoutBox(layoutBox);
 
     auto absoluteBox = Box { layoutState.displayBoxForLayoutBox(layoutBox) };
     for (auto* container = layoutBox.containingBlock(); container != &layoutBox.initialContainingBlock(); container = container->containingBlock())
@@ -153,50 +155,132 @@
     return absoluteBox;
 }
 
-static void paintBoxDecorationAndChildren(GraphicsContext& context, const Layout::LayoutState& layoutState, const Layout::Box& layoutBox, const IntRect& dirtyRect)
+static bool isPaintRootCandidate(const Layout::Box& layoutBox)
 {
-    if (!layoutBox.isAnonymous()) {
+    return layoutBox.isPositioned();
+}
+
+using LayoutBoxList = Vector<const Layout::Box*>;
+
+enum PaintPhase { Decoration, Content };
+static void paintSubtree(GraphicsContext& context, const Layout::LayoutState& layoutState, const Layout::Box& paintRootBox, const IntRect& dirtyRect, PaintPhase paintPhase)
+{
+    auto paint = [&] (auto& layoutBox) {
+        if (layoutBox.style().visibility() != Visibility::Visible)
+            return;
         auto absoluteDisplayBox = Display::absoluteDisplayBox(layoutState, layoutBox);
-        if (dirtyRect.intersects(snappedIntRect(absoluteDisplayBox.rect())))
+        if (!dirtyRect.intersects(snappedIntRect(absoluteDisplayBox.rect())))
+            return;
+
+        if (paintPhase == PaintPhase::Decoration) {
+            if (layoutBox.isAnonymous())
+                return;
             paintBoxDecoration(context, absoluteDisplayBox, layoutBox.style(), layoutBox.isBodyBox());
-    }
+            return;
+        }
+        // Only inline content for now.
+        if (layoutBox.establishesInlineFormattingContext()) {
+            auto& container = downcast<Layout::Container>(layoutBox);
+            paintInlineContent(context, absoluteDisplayBox.topLeft(), downcast<Layout::InlineFormattingState>(layoutState.establishedFormattingState(container)));
+        }
+    };
 
-    if (!is<Layout::Container>(layoutBox))
+    paint(paintRootBox);
+    if (!is<Layout::Container>(paintRootBox) || !downcast<Layout::Container>(paintRootBox).hasChild())
         return;
-    for (auto& childLayoutBox : Layout::childrenOfType<Layout::Box>(downcast<Layout::Container>(layoutBox))) {
-        if (childLayoutBox.style().visibility() != Visibility::Visible)
-            continue;
-        paintBoxDecorationAndChildren(context, layoutState, childLayoutBox, dirtyRect);
+
+    LayoutBoxList layoutBoxList;
+    layoutBoxList.append(downcast<Layout::Container>(paintRootBox).firstChild());
+    while (!layoutBoxList.isEmpty()) {
+        while (true) {
+            auto& layoutBox = *layoutBoxList.last();
+            if (isPaintRootCandidate(layoutBox))
+                break;
+            paint(layoutBox);
+            if (!is<Layout::Container>(layoutBox) || !downcast<Layout::Container>(layoutBox).hasChild())
+                break;
+            layoutBoxList.append(downcast<Layout::Container>(layoutBox).firstChild());
+        }
+        while (!layoutBoxList.isEmpty()) {
+            auto& layoutBox = *layoutBoxList.takeLast();
+            // Stay within.
+            if (&layoutBox == &paintRootBox)
+                return;
+            if (auto* nextSibling = layoutBox.nextSibling()) {
+                layoutBoxList.append(nextSibling);
+                break;
+            }
+        }
     }
 }
 
+static LayoutRect collectPaintRootsAndContentRect(const Layout::LayoutState& layoutState, const Layout::Box& rootLayoutBox, LayoutBoxList& positiveZOrderList, LayoutBoxList& negativeZOrderList)
+{
+    auto appendPaintRoot = [&] (const auto& layoutBox) {
+        if (layoutBox.style().usedZIndex() < 0) {
+            negativeZOrderList.append(&layoutBox);
+            return;
+        }
+        positiveZOrderList.append(&layoutBox);
+    };
+
+    auto contentRect = LayoutRect { layoutState.displayBoxForLayoutBox(rootLayoutBox).rect() };
+
+    // Initial BFC is always a paint root.
+    appendPaintRoot(rootLayoutBox);
+    LayoutBoxList layoutBoxList;
+    layoutBoxList.append(&rootLayoutBox);
+    while (!layoutBoxList.isEmpty()) {
+        while (true) {
+            auto& layoutBox = *layoutBoxList.last();
+            if (layoutBox.style().visibility() != Visibility::Visible)
+                break;
+            if (isPaintRootCandidate(layoutBox))
+                appendPaintRoot(layoutBox);
+            contentRect.uniteIfNonZero(Display::absoluteDisplayBox(layoutState, layoutBox).rect());
+            if (!is<Layout::Container>(layoutBox) || !downcast<Layout::Container>(layoutBox).hasChild())
+                break;
+            layoutBoxList.append(downcast<Layout::Container>(layoutBox).firstChild());
+        }
+        while (!layoutBoxList.isEmpty()) {
+            auto& layoutBox = *layoutBoxList.takeLast();
+            if (auto* nextSibling = layoutBox.nextSibling()) {
+                layoutBoxList.append(nextSibling);
+                break;
+            }
+        }
+    }
+
+    auto compareZIndex = [] (const Layout::Box* a, const Layout::Box* b) {
+        return a->style().usedZIndex() < b->style().usedZIndex();
+    };
+
+    std::stable_sort(positiveZOrderList.begin(), positiveZOrderList.end(), compareZIndex);
+    std::stable_sort(negativeZOrderList.begin(), negativeZOrderList.end(), compareZIndex);
+    return contentRect;
+}
+
 void Painter::paint(const Layout::LayoutState& layoutState, GraphicsContext& context, const IntRect& dirtyRect)
 {
-    auto& layoutRoot = layoutState.root();
-    if (!layoutRoot.firstChild())
+    auto& rootLayoutBox = layoutState.root();
+    if (!rootLayoutBox.firstChild())
         return;
+
+    Vector<const Layout::Box*> negativeZOrderList;
+    Vector<const Layout::Box*> positiveZOrderList;
+    auto contentRect = collectPaintRootsAndContentRect(layoutState, rootLayoutBox, positiveZOrderList, negativeZOrderList);
+
     // Fill the entire content area.
-    auto rootRect = LayoutRect { layoutState.displayBoxForLayoutBox(layoutRoot).rect() };
-    for (auto& layoutBox : Layout::descendantsOfType<Layout::Box>(layoutRoot))
-        rootRect.uniteIfNonZero(Display::absoluteDisplayBox(layoutState, layoutBox).rect());
-    context.fillRect(rootRect, Color::white);
+    context.fillRect(contentRect, Color::white);
 
-    // 1. Paint box decoration (both block and inline).
-    paintBoxDecorationAndChildren(context, layoutState, *layoutRoot.firstChild(), dirtyRect);
+    for (auto& paintRootBox : negativeZOrderList) {
+        paintSubtree(context, layoutState, *paintRootBox, dirtyRect, PaintPhase::Decoration);
+        paintSubtree(context, layoutState, *paintRootBox, dirtyRect, PaintPhase::Content);
+    }
 
-    // 2. Paint content
-    for (auto& layoutBox : Layout::descendantsOfType<Layout::Box>(layoutRoot)) {
-        auto absoluteDisplayBox = Display::absoluteDisplayBox(layoutState, layoutBox);
-        // FIXME: This is the best we can do with no layout overflow support.
-        if (!dirtyRect.intersects(snappedIntRect(absoluteDisplayBox.rect())))
-            continue;
-        if (layoutBox.style().visibility() != Visibility::Visible)
-            continue;
-        if (layoutBox.establishesInlineFormattingContext()) {
-            auto& container = downcast<Layout::Container>(layoutBox);
-            paintInlineContent(context, absoluteDisplayBox.topLeft(), downcast<Layout::InlineFormattingState>(layoutState.establishedFormattingState(container)));
-            continue;
-        }
+    for (auto& paintRootBox : positiveZOrderList) {
+        paintSubtree(context, layoutState, *paintRootBox, dirtyRect, PaintPhase::Decoration);
+        paintSubtree(context, layoutState, *paintRootBox, dirtyRect, PaintPhase::Content);
     }
 }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to