[LFC] Miscellaneous fixes to fix simple absolute positioning.
[WebKit-https.git] / Source / WebCore / layout / layouttree / LayoutTreeBuilder.cpp
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. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "LayoutTreeBuilder.h"
28
29 #if ENABLE(LAYOUT_FORMATTING_CONTEXT)
30
31 #include "DisplayBox.h"
32 #include "LayoutBlockContainer.h"
33 #include "LayoutBox.h"
34 #include "LayoutChildIterator.h"
35 #include "LayoutContainer.h"
36 #include "LayoutContext.h"
37 #include "LayoutInlineBox.h"
38 #include "LayoutInlineContainer.h"
39 #include "RenderBlock.h"
40 #include "RenderChildIterator.h"
41 #include "RenderElement.h"
42 #include "RenderInline.h"
43 #include "RenderStyle.h"
44 #include "RenderView.h"
45 #include <wtf/text/TextStream.h>
46
47 namespace WebCore {
48 namespace Layout {
49
50 std::unique_ptr<Container> TreeBuilder::createLayoutTree(const RenderView& renderView)
51 {
52     std::unique_ptr<Container> initialContainingBlock(new BlockContainer(std::nullopt, RenderStyle::clone(renderView.style())));
53     TreeBuilder::createSubTree(renderView, *initialContainingBlock);
54     return initialContainingBlock;
55 }
56
57 void TreeBuilder::createSubTree(const RenderElement& rootRenderer, Container& rootContainer)
58 {
59     auto elementAttributes = [] (const RenderElement& renderer) -> std::optional<Box::ElementAttributes> {
60         if (renderer.isDocumentElementRenderer())
61             return Box::ElementAttributes { Box::ElementType::Document };
62         if (auto* element = renderer.element()) {
63             if (element->hasTagName(HTMLNames::bodyTag))
64                 return Box::ElementAttributes { Box::ElementType::Body };
65             if (element->hasTagName(HTMLNames::colTag))
66                 return Box::ElementAttributes { Box::ElementType::TableColumn };
67             if (element->hasTagName(HTMLNames::trTag))
68                 return Box::ElementAttributes { Box::ElementType::TableRow };
69             if (element->hasTagName(HTMLNames::colgroupTag))
70                 return Box::ElementAttributes { Box::ElementType::TableColumnGroup };
71             if (element->hasTagName(HTMLNames::tbodyTag))
72                 return Box::ElementAttributes { Box::ElementType::TableRowGroup };
73             if (element->hasTagName(HTMLNames::theadTag))
74                 return Box::ElementAttributes { Box::ElementType::TableHeaderGroup };
75             if (element->hasTagName(HTMLNames::tfootTag))
76                 return Box::ElementAttributes { Box::ElementType::TableFooterGroup };
77             if (element->hasTagName(HTMLNames::tfootTag))
78                 return Box::ElementAttributes { Box::ElementType::TableFooterGroup };
79             return Box::ElementAttributes { Box::ElementType::GenericElement };
80         }
81         return std::nullopt;
82     };
83
84     // Skip RenderText (and some others) for now.
85     for (auto& child : childrenOfType<RenderElement>(rootRenderer)) {
86         Box* box = nullptr;
87
88         if (is<RenderBlock>(child))
89             box = new BlockContainer(elementAttributes(child), RenderStyle::clone(child.style()));
90         else if (is<RenderInline>(child))
91             box = new InlineContainer(elementAttributes(child), RenderStyle::clone(child.style()));
92         else
93             ASSERT_NOT_IMPLEMENTED_YET();
94
95         if (!rootContainer.hasChild()) {
96             rootContainer.setFirstChild(*box);
97             rootContainer.setLastChild(*box);
98         } else {
99             auto* lastChild = const_cast<Box*>(rootContainer.lastChild());
100             box->setPreviousSibling(*lastChild);
101             lastChild->setNextSibling(*box);
102             rootContainer.setLastChild(*box);
103         }
104         box->setParent(rootContainer);
105
106         if (box->isOutOfFlowPositioned()) {
107             // Not efficient, but this is temporary anyway.
108             // Collect the out-of-flow descendants at the formatting root lever (as opposed to at the containing block level, though they might be the same).
109             const_cast<Container&>(box->formattingContextRoot()).addOutOfFlowDescendant(*box);
110         }
111         createSubTree(child, downcast<Container>(*box));
112     }
113 }
114
115 #if ENABLE(TREE_DEBUGGING)
116 static void outputLayoutBox(TextStream& stream, const Box& layoutBox, const Display::Box& displayBox, unsigned depth)
117 {
118     unsigned printedCharacters = 0;
119     while (++printedCharacters <= depth * 2)
120         stream << " ";
121
122     if (is<InlineContainer>(layoutBox))
123         stream << "inline container";
124     else if (is<InlineBox>(layoutBox))
125         stream << "inline box";
126     else if (is<BlockContainer>(layoutBox)) {
127         if (!layoutBox.parent())
128             stream << "initial ";
129         stream << "block container";
130     } else
131         stream << "box";
132     stream << " at [" << displayBox.left() << " " << displayBox.top() << "] size [" << displayBox.width() << " " << displayBox.height() << "]";
133     stream << " object [" << &layoutBox << "]";
134
135     stream.nextLine();
136 }
137
138 static void outputLayoutTree(const LayoutContext& layoutContext, TextStream& stream, const Container& rootContainer, unsigned depth)
139 {
140     for (auto& child : childrenOfType<Box>(rootContainer)) {
141         outputLayoutBox(stream, child, *layoutContext.displayBoxForLayoutBox(child), depth);
142         if (is<Container>(child))
143             outputLayoutTree(layoutContext, stream, downcast<Container>(child), depth + 1);
144     }
145 }
146
147 void TreeBuilder::showLayoutTree(const LayoutContext& layoutContext, const Container& layoutBox)
148 {
149     TextStream stream(TextStream::LineMode::MultipleLine, TextStream::Formatting::SVGStyleRect);
150     outputLayoutBox(stream, layoutBox, *layoutContext.displayBoxForLayoutBox(layoutBox), 0);
151     outputLayoutTree(layoutContext, stream, layoutBox, 1);
152     WTFLogAlways("%s", stream.release().utf8().data());
153 }
154
155 void printLayoutTreeForLiveDocuments()
156 {
157     for (const auto* document : Document::allDocuments()) {
158         if (!document->renderView())
159             continue;
160         if (document->frame() && document->frame()->isMainFrame())
161             fprintf(stderr, "----------------------main frame--------------------------\n");
162         fprintf(stderr, "%s\n", document->url().string().utf8().data());
163         // FIXME: Need to find a way to output geometry without layout context.
164         // Layout::TreeBuilder::showLayoutTree(*TreeBuilder::createLayoutTree(*document->renderView()));
165     }
166 }
167 #endif
168
169 }
170 }
171
172 #endif