[LayoutReloaded] Introduce Display.Box
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Mar 2018 17:12:24 +0000 (17:12 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Mar 2018 17:12:24 +0000 (17:12 +0000)
https://bugs.webkit.org/show_bug.cgi?id=183700

Reviewed by Antti Koivisto.

Display.Box objects will end up in the display(box) tree. Currently
they are just hanging off of the Layout.Box objects.

* LayoutReloaded/DisplayTree/Box.js: Added.
(Display.Box):
(Display.Box.prototype.rect):
(Display.Box.prototype.top):
(Display.Box.prototype.left):
(Display.Box.prototype.bottom):
(Display.Box.prototype.right):
(Display.Box.prototype.topLeft):
(Display.Box.prototype.bottomRight):
(Display.Box.prototype.setTopLeft):
(Display.Box.prototype.setSize):
(Display.Box.prototype.setWidth):
(Display.Box.prototype.setHeight):
(Display.Box.prototype.borderBox):
(Display.Box.prototype.paddingBox):
(Display.Box.prototype.contentBox):
* LayoutReloaded/FormattingContext/BlockFormatting/BlockFormattingContext.js:
(BlockFormattingContext):
(BlockFormattingContext.prototype.layout):
(BlockFormattingContext.prototype._toAbsolutePosition):
(BlockFormattingContext.prototype._needsLayout):
(BlockFormattingContext.prototype._addToLayoutQueue):
(BlockFormattingContext.prototype._nextInLayoutQueue):
(BlockFormattingContext.prototype._removeFromLayoutQueue):
(BlockFormattingContext.prototype._createDisplayBox):
(BlockFormattingContext.prototype._toDisplayBox):
(BlockFormattingContext.prototype._toLayoutBox):
* LayoutReloaded/Layout.js:
(layout):
* LayoutReloaded/LayoutReloaded.xcworkspace/contents.xcworkspacedata:
* LayoutReloaded/LayoutTree/Box.js:
(Layout.Box):
(Layout.Box.prototype.setDisplayBox):
(Layout.Box.prototype.displayBox):
(Layout.Box.prototype.rect):
(Layout.Box.prototype.setTopLeft):
(Layout.Box.prototype.setSize):
(Layout.Box.prototype.setWidth):
(Layout.Box.prototype.setHeight):
(Layout.Box.prototype.borderBox):
(Layout.Box.prototype.paddingBox):
(Layout.Box.prototype.contentBox):
* LayoutReloaded/test/index.html:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229671 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Tools/ChangeLog
Tools/LayoutReloaded/DisplayTree/Box.js [new file with mode: 0644]
Tools/LayoutReloaded/FormattingContext/BlockFormatting/BlockFormattingContext.js
Tools/LayoutReloaded/Layout.js
Tools/LayoutReloaded/LayoutReloaded.xcworkspace/contents.xcworkspacedata
Tools/LayoutReloaded/LayoutTree/Box.js
Tools/LayoutReloaded/test/index.html

index 94a2a57b69a600b7bb7fdde02d74956d30597a63..e5684b4486af3119ba58cab3fd5c89893f2edb94 100644 (file)
@@ -1,3 +1,57 @@
+2018-03-16  Zalan Bujtas  <zalan@apple.com>
+
+        [LayoutReloaded] Introduce Display.Box
+        https://bugs.webkit.org/show_bug.cgi?id=183700
+
+        Reviewed by Antti Koivisto.
+
+        Display.Box objects will end up in the display(box) tree. Currently
+        they are just hanging off of the Layout.Box objects.
+
+        * LayoutReloaded/DisplayTree/Box.js: Added.
+        (Display.Box):
+        (Display.Box.prototype.rect):
+        (Display.Box.prototype.top):
+        (Display.Box.prototype.left):
+        (Display.Box.prototype.bottom):
+        (Display.Box.prototype.right):
+        (Display.Box.prototype.topLeft):
+        (Display.Box.prototype.bottomRight):
+        (Display.Box.prototype.setTopLeft):
+        (Display.Box.prototype.setSize):
+        (Display.Box.prototype.setWidth):
+        (Display.Box.prototype.setHeight):
+        (Display.Box.prototype.borderBox):
+        (Display.Box.prototype.paddingBox):
+        (Display.Box.prototype.contentBox):
+        * LayoutReloaded/FormattingContext/BlockFormatting/BlockFormattingContext.js:
+        (BlockFormattingContext):
+        (BlockFormattingContext.prototype.layout):
+        (BlockFormattingContext.prototype._toAbsolutePosition):
+        (BlockFormattingContext.prototype._needsLayout):
+        (BlockFormattingContext.prototype._addToLayoutQueue):
+        (BlockFormattingContext.prototype._nextInLayoutQueue):
+        (BlockFormattingContext.prototype._removeFromLayoutQueue):
+        (BlockFormattingContext.prototype._createDisplayBox):
+        (BlockFormattingContext.prototype._toDisplayBox):
+        (BlockFormattingContext.prototype._toLayoutBox):
+        * LayoutReloaded/Layout.js:
+        (layout):
+        * LayoutReloaded/LayoutReloaded.xcworkspace/contents.xcworkspacedata:
+        * LayoutReloaded/LayoutTree/Box.js:
+        (Layout.Box):
+        (Layout.Box.prototype.setDisplayBox):
+        (Layout.Box.prototype.displayBox):
+        (Layout.Box.prototype.rect):
+        (Layout.Box.prototype.setTopLeft):
+        (Layout.Box.prototype.setSize):
+        (Layout.Box.prototype.setWidth):
+        (Layout.Box.prototype.setHeight):
+        (Layout.Box.prototype.borderBox):
+        (Layout.Box.prototype.paddingBox):
+        (Layout.Box.prototype.contentBox):
+        * LayoutReloaded/test/index.html:
+
 2018-03-16  Chris Dumez  <cdumez@apple.com>
 
         URLSchemeHandler.Basic API test fails with async policy delegates
diff --git a/Tools/LayoutReloaded/DisplayTree/Box.js b/Tools/LayoutReloaded/DisplayTree/Box.js
new file mode 100644 (file)
index 0000000..8136d63
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+var Display = { }
+
+Display.Box = class Box {
+    constructor(node) {
+        this.m_node = node;
+        this.m_rect = new LayoutRect(new LayoutPoint(0, 0), new LayoutSize(0, 0));
+    }
+
+    rect() {
+        return this.m_rect.clone();
+    }
+    
+    top() {
+        return this.rect().top();
+    }
+    
+    left() {
+        return this.rect().left();
+    }
+    
+    bottom() {
+        return this.rect().bottom();
+    }
+    
+    right() {
+        return this.rect().right();
+    }
+
+    topLeft() {
+        return this.rect().topLeft();
+    }
+
+    bottomRight() {
+        return this.rect().bottomRight();
+    }
+
+    setTopLeft(topLeft) {
+        this.m_rect.setTopLeft(topLeft);
+    }
+
+    setSize(size) {
+        this.m_rect.setSize(size);
+    }
+
+    setWidth(width) {
+        this.m_rect.setWidth(width);
+    }
+
+    setHeight(height) {
+        this.m_rect.setHeight(height);
+    }
+
+    borderBox() {
+        return new LayoutRect(new LayoutPoint(0, 0), this.rect().size());
+    }
+
+    paddingBox() {
+        let paddingBox = this.borderBox();
+        let borderSize = Utils.computedBorderTopLeft(this.m_node);
+        paddingBox.moveBy(borderSize);
+        paddingBox.shrinkBy(borderSize);
+        paddingBox.shrinkBy(Utils.computedBorderBottomRight(this.m_node));
+        return paddingBox;
+    }
+
+    contentBox() {
+        let contentBox = this.paddingBox();
+        let paddingSize = Utils.computedPaddingTopLeft(this.m_node);
+        contentBox.moveBy(paddingSize);
+        contentBox.shrinkBy(paddingSize);
+        contentBox.shrinkBy(Utils.computedPaddingBottomRight(this.m_node));
+        return contentBox;
+    }
+}
index 5b767a02af8b99fac39bad56e91bef17e60a8b3d..04e050823ec57d80380ddf5158c550a8b3662859 100644 (file)
@@ -27,6 +27,9 @@ class BlockFormattingContext extends FormattingContext {
         super(root);
         // New block formatting context always establishes a new floating context.
         this.m_floatingContext = new FloatingContext(this);
+        this.m_displayToLayout = new Map();
+        this.m_layoutToDisplay = new Map();
+        this.m_layoutStack = new Array();
     }
 
     layout(layoutContext) {
@@ -37,17 +40,16 @@ class BlockFormattingContext extends FormattingContext {
         if (!this.rootContainer().firstChild())
             return;
         // This is a post-order tree traversal layout.
-        let layoutStack = new Array();
         // The root container layout is done in the formatting context it lives in, not that one it creates, so let's start with the first child.
-        layoutStack.push(this.rootContainer().firstChild());
+        this._addToLayoutQueue(this.rootContainer().firstChild());
         // 1. Go all the way down to the leaf node
         // 2. Compute static position and width as we travers down
         // 3. As we climb back on the tree, compute height and finialize position
         // (Any subtrees with new formatting contexts need to layout synchronously)
-        while (layoutStack.length) {
+        while (this._needsLayout()) {
             // Travers down on the descendants until we find a leaf node.
             while (true) {
-                let layoutBox = layoutStack[layoutStack.length - 1];
+                let layoutBox = this._nextInLayoutQueue();
                 this.computeWidth(layoutBox);
                 this._computeStaticPosition(layoutBox);
                 if (layoutBox.establishesFormattingContext()) {
@@ -56,13 +58,13 @@ class BlockFormattingContext extends FormattingContext {
                 }
                 if (!layoutBox.isContainer() || !layoutBox.hasChild())
                     break;
-                layoutStack.push(layoutBox.firstChild());
+                this._addToLayoutQueue(layoutBox.firstChild());
             }
 
             // Climb back on the ancestors and compute height/final position.
-            while (layoutStack.length) {
+            while (this._needsLayout()) {
                 // All inflow descendants (if there are any) are laid out by now. Let's compute the box's height.
-                let layoutBox = layoutStack.pop();
+                let layoutBox = this._nextInLayoutQueue();
                 this.computeHeight(layoutBox);
                 // Adjust position now that we have all the previous floats placed in this context -if needed.
                 this.floatingContext().computePosition(layoutBox);
@@ -72,8 +74,10 @@ class BlockFormattingContext extends FormattingContext {
                     // Place the out of flow content.
                     this._placeOutOfFlowDescendants(layoutBox);
                 }
+                // We are done with laying out this box.
+                this._removeFromLayoutQueue(layoutBox);
                 if (layoutBox.nextSibling()) {
-                    layoutStack.push(layoutBox.nextSibling());
+                    this._addToLayoutQueue(layoutBox.nextSibling());
                     break;
                 }
             }
@@ -340,5 +344,46 @@ class BlockFormattingContext extends FormattingContext {
         }
         return new LayoutRect(topLeft, layoutBox.rect().size());
     }
-}
 
+    _needsLayout() {
+        return this.m_layoutStack.length;
+    }
+
+    _addToLayoutQueue(layoutBox) {
+        // Initialize the corresponding display box.
+        this._createDisplayBox(layoutBox);
+        this.m_layoutStack.push(layoutBox);
+    }
+
+    _nextInLayoutQueue() {
+        ASSERT(this.m_layoutStack.length);
+        return this.m_layoutStack[this.m_layoutStack.length - 1];
+    }
+
+    _removeFromLayoutQueue(layoutBox) {
+        // With the current layout logic, the layoutBox should be at the top (this.m_layoutStack.pop() should do).
+        ASSERT(this.m_layoutStack.length);
+        ASSERT(this.m_layoutStack[this.m_layoutStack.length - 1] == layoutBox);
+        this.m_layoutStack.splice(this.m_layoutStack.indexOf(layoutBox), 1);
+    }
+
+    _createDisplayBox(layoutBox) {
+        let displayBox = new Display.Box(layoutBox.node());
+        this.m_displayToLayout.set(displayBox, layoutBox);
+        this.m_layoutToDisplay.set(layoutBox, displayBox);
+        // This is temporary.
+        layoutBox.setDisplayBox(displayBox);
+    }
+
+    _toDisplayBox(layoutBox) {
+        ASSERT(layoutBox);
+        ASSERT(this.m_layoutToDisplay.has(layoutBox));
+        return this.m_layoutToDisplay.get(layout);
+    }
+
+    _toLayoutBox(displayBox) {
+        ASSERT(displayBox);
+        ASSERT(this.m_displayToLayout.has(displayBox));
+        return this.m_displayToLayout.get(layout);
+    }
+}
index 5b984a4ddb9bc515b0e274196bb5dbeb18a2331f..0bec697fe78d8a6332d3ed7f2124a5e8d370497e 100644 (file)
@@ -26,6 +26,7 @@
 function layout(window, viewportSize) {
     let treeBuilder = new TreeBuilder();
     let initialContainingBlock = treeBuilder.createTree(window.document, window.renderTreeStructure);
+    initialContainingBlock.setDisplayBox(new Display.Box());
     initialContainingBlock.setSize(viewportSize);
 
     let layoutContext = new LayoutContext(initialContainingBlock);
index 15b769eec09944970abb9c077709ee89e315c9cd..6783fbb828e9ece8f82db6cbefceee1532a6e06b 100644 (file)
@@ -1,6 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Workspace
    version = "1.0">
+   <FileRef
+      location = "group:DisplayTree">
+   </FileRef>
    <FileRef
       location = "group:test">
    </FileRef>
index 5f282bbb80d90e176366f4c3194cb3b9e2d3c53b..2161ff98bbf5eb89d81aa40bb231e14fa32769aa 100644 (file)
@@ -34,8 +34,8 @@ Layout.Box = class Box {
         this.m_nextSibling = null;
         this.m_previousSibling = null;
         this.m_isAnonymous = false;
-        this.m_rect = new LayoutRect(new LayoutPoint(0, 0), new LayoutSize(0, 0));
         this.m_establishedFormattingContext = null;
+        this.m_displayBox = null;
     }
 
     id() {
@@ -98,8 +98,18 @@ Layout.Box = class Box {
         this.m_previousSibling = previousSibling;
     }
 
+    setDisplayBox(displayBox) {
+        ASSERT(!this.m_displayBox);
+        this.m_displayBox = displayBox;
+    }
+
+    displayBox() {
+        ASSERT(this.m_displayBox);
+        return this.m_displayBox;
+    }
+
     rect() {
-        return this.m_rect.clone();
+        return this.displayBox().rect();
     }
 
     topLeft() {
@@ -111,19 +121,19 @@ Layout.Box = class Box {
     }
 
     setTopLeft(topLeft) {
-        this.m_rect.setTopLeft(topLeft);
+        this.displayBox().setTopLeft(topLeft);
     }
 
     setSize(size) {
-        this.m_rect.setSize(size);
+        this.displayBox().setSize(size);
     }
 
     setWidth(width) {
-        this.m_rect.setWidth(width);
+        this.displayBox().setWidth(width);
     }
 
     setHeight(height) {
-        this.m_rect.setHeight(height);
+        this.displayBox().setHeight(height);
     }
 
     isContainer() {
@@ -234,24 +244,14 @@ Layout.Box = class Box {
     }
 
     borderBox() {
-        return new LayoutRect(new LayoutPoint(0, 0), this.rect().size());
+        return this.displayBox().borderBox();
     }
 
     paddingBox() {
-        let paddingBox = this.borderBox();
-        let borderSize = Utils.computedBorderTopLeft(this.node());
-        paddingBox.moveBy(borderSize);
-        paddingBox.shrinkBy(borderSize);
-        paddingBox.shrinkBy(Utils.computedBorderBottomRight(this.node()));
-        return paddingBox;
+        return this.displayBox().paddingBox();
     }
 
     contentBox() {
-        let contentBox = this.paddingBox();
-        let paddingSize = Utils.computedPaddingTopLeft(this.node());
-        contentBox.moveBy(paddingSize);
-        contentBox.shrinkBy(paddingSize);
-        contentBox.shrinkBy(Utils.computedPaddingBottomRight(this.node()));
-        return contentBox;
+        return this.displayBox().contentBox();
     }
 }
index b52f9279665f1fa3b15e884394a275fc1b23fa70..fef9173c63cab48d052d3711f7454feba6adaaff 100644 (file)
@@ -81,6 +81,7 @@ addJS("../LayoutTree/BlockContainer.js");
 addJS("../LayoutTree/InitialBlockContainer.js");
 addJS("../LayoutTree/InlineBox.js");
 addJS("../LayoutTree/Text.js");
+addJS("../DisplayTree/Box.js");
 addJS("../FormattingContext/FormattingContext.js");
 addJS("../FormattingContext/FloatingContext.js");
 addJS("../FormattingContext/BlockFormatting/BlockFormattingContext.js");