f521f054e352fdd1cca2fdd000fa7000a34f26cf
[WebKit-https.git] / Tools / LayoutReloaded / FormattingContext / FormattingContext.js
1 /*
2  * Copyright (C) 2018 Apple Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 class FormattingContext {
27     constructor(formattingState) {
28         this.m_formattingState = formattingState;
29         this.m_floatingContext = new FloatingContext(formattingState.floatingState(), this);
30         this.m_layoutStack = new Array();
31     }
32
33     formattingRoot() {
34         return this.m_formattingState.formattingRoot();
35     }
36
37     formattingState() {
38         return this.m_formattingState;
39     }
40
41     layoutState() {
42         return this.formattingState().layoutState();
43     }
44
45     floatingContext() {
46         return this.m_floatingContext;
47     }
48
49     layout() {
50         ASSERT_NOT_REACHED();
51     }
52
53     computeWidth(layoutBox) {
54     }
55
56     computeHeight(layoutBox) {
57     }
58
59     marginTop(layoutBox) {
60         return Utils.computedMarginTop(layoutBox.node());
61     }
62     
63     marginLeft(layoutBox) {
64         return Utils.computedMarginLeft(layoutBox.node());
65     }
66     
67     marginBottom(layoutBox) {
68         return Utils.computedMarginBottom(layoutBox.node());
69     }
70     
71     marginRight(layoutBox) {
72         return Utils.computedMarginRight(layoutBox.node());
73     }
74
75     _descendantNeedsLayout() {
76         return this.m_layoutStack.length;
77     }
78
79     _addToLayoutQueue(layoutBox) {
80         // Initialize the corresponding display box.
81         let displayBox = this.formattingState().createDisplayBox(layoutBox, this);
82         if (layoutBox.node()) {
83             displayBox.setMarginTop(this.marginTop(layoutBox));
84             displayBox.setMarginLeft(this.marginLeft(layoutBox));
85             displayBox.setMarginBottom(this.marginBottom(layoutBox));
86             displayBox.setMarginRight(this.marginRight(layoutBox));
87         }
88
89         this.m_layoutStack.push(layoutBox);
90     }
91
92     _nextInLayoutQueue() {
93         ASSERT(this.m_layoutStack.length);
94         return this.m_layoutStack[this.m_layoutStack.length - 1];
95     }
96
97     _removeFromLayoutQueue(layoutBox) {
98         // With the current layout logic, the layoutBox should be at the top (this.m_layoutStack.pop() should do).
99         ASSERT(this.m_layoutStack.length);
100         ASSERT(this.m_layoutStack[this.m_layoutStack.length - 1] == layoutBox);
101         this.m_layoutStack.splice(this.m_layoutStack.indexOf(layoutBox), 1);
102     }
103
104     displayBox(layoutBox) {
105         return this.formattingState().displayBox(layoutBox);
106     }
107
108     _outOfFlowDescendants() {
109         // FIXME: This is highly inefficient but will do for now.
110         // 1. Collect all the out-of-flow descendants first.
111         // 2. Check if they are all belong to this formatting context.
112         //    - either the root container is the containing block.
113         //    - or a descendant of the root container is the containing block
114         //      and there is not other formatting context inbetween.
115         let allOutOfFlowBoxes = new Array();
116         let descendants = new Array();
117         for (let child = this.formattingRoot().firstChild(); child; child = child.nextSibling())
118             descendants.push(child);
119         while (descendants.length) {
120             let descendant = descendants.pop();
121             if (descendant.isOutOfFlowPositioned())
122                 allOutOfFlowBoxes.push(descendant);
123             if (!descendant.isContainer())
124                 continue;
125             for (let child = descendant.lastChild(); child; child = child.previousSibling())
126                 descendants.push(child);
127         }
128         let outOfFlowBoxes = new Array();
129         for (let outOfFlowBox of allOutOfFlowBoxes) {
130             let containingBlock = outOfFlowBox.containingBlock();
131             // Collect the out-of-flow descendant that belong to this formatting context.
132             if (containingBlock == this.formattingRoot())
133                 outOfFlowBoxes.push(outOfFlowBox);
134             else if (containingBlock.isDescendantOf(this.formattingRoot())) {
135                 if (!containingBlock.establishesFormattingContext() || !containingBlock.isPositioned())
136                     outOfFlowBoxes.push(outOfFlowBox);
137             }
138         }
139         return outOfFlowBoxes;
140     }
141
142 }