3c196c63b31a33b1d49e8403312d7cc80946cbe1
[WebKit-https.git] / Source / WebCore / rendering / updating / RenderTreeBuilderList.cpp
1 /**
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  * Copyright (C) 2003-2006, 2010, 2017 Apple Inc. All rights reserved.
5  * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  */
23
24 #include "config.h"
25 #include "RenderTreeBuilderList.h"
26
27 #include "RenderChildIterator.h"
28 #include "RenderListMarker.h"
29 #include "RenderMultiColumnFlow.h"
30 #include "RenderRuby.h"
31 #include "RenderTable.h"
32
33 namespace WebCore {
34
35 static RenderBlock* getParentOfFirstLineBox(RenderBlock& current, RenderObject& marker)
36 {
37     bool inQuirksMode = current.document().inQuirksMode();
38     for (auto& child : childrenOfType<RenderObject>(current)) {
39         if (&child == &marker)
40             continue;
41
42         if (child.isInline() && (!is<RenderInline>(child) || current.generatesLineBoxesForInlineChild(&child)))
43             return &current;
44
45         if (child.isFloating() || child.isOutOfFlowPositioned())
46             continue;
47
48         if (!is<RenderBlock>(child) || is<RenderTable>(child) || is<RenderRubyAsBlock>(child))
49             break;
50
51         if (is<RenderBox>(child) && downcast<RenderBox>(child).isWritingModeRoot())
52             break;
53
54         if (is<RenderListItem>(current) && inQuirksMode && child.node() && isHTMLListElement(*child.node()))
55             break;
56
57         if (RenderBlock* lineBox = getParentOfFirstLineBox(downcast<RenderBlock>(child), marker))
58             return lineBox;
59     }
60
61     return nullptr;
62 }
63
64 static RenderObject* firstNonMarkerChild(RenderBlock& parent)
65 {
66     RenderObject* child = parent.firstChild();
67     while (is<RenderListMarker>(child))
68         child = child->nextSibling();
69     return child;
70 }
71
72 RenderTreeBuilder::List::List(RenderTreeBuilder& builder)
73     : m_builder(builder)
74 {
75 }
76
77 void RenderTreeBuilder::List::updateItemMarker(RenderListItem& listItemRenderer)
78 {
79     auto& style = listItemRenderer.style();
80
81     if (style.listStyleType() == NoneListStyle && (!style.listStyleImage() || style.listStyleImage()->errorOccurred())) {
82         if (auto* marker = listItemRenderer.markerRenderer())
83             marker->removeFromParentAndDestroy(m_builder);
84         return;
85     }
86
87     auto newStyle = listItemRenderer.computeMarkerStyle();
88     RenderPtr<RenderListMarker> newMarkerRenderer;
89     auto* markerRenderer = listItemRenderer.markerRenderer();
90     if (markerRenderer)
91         markerRenderer->setStyle(WTFMove(newStyle));
92     else {
93         newMarkerRenderer = WebCore::createRenderer<RenderListMarker>(listItemRenderer, WTFMove(newStyle));
94         newMarkerRenderer->initializeStyle();
95         markerRenderer = newMarkerRenderer.get();
96         listItemRenderer.setMarkerRenderer(*markerRenderer);
97     }
98
99     RenderElement* currentParent = markerRenderer->parent();
100     RenderBlock* newParent = getParentOfFirstLineBox(listItemRenderer, *markerRenderer);
101     if (!newParent) {
102         // If the marker is currently contained inside an anonymous box,
103         // then we are the only item in that anonymous box (since no line box
104         // parent was found). It's ok to just leave the marker where it is
105         // in this case.
106         if (currentParent && currentParent->isAnonymousBlock())
107             return;
108         if (auto* multiColumnFlow = listItemRenderer.multiColumnFlow())
109             newParent = multiColumnFlow;
110         else
111             newParent = &listItemRenderer;
112     }
113
114     if (newParent == currentParent)
115         return;
116
117     if (currentParent)
118         m_builder.insertChild(*newParent, currentParent->takeChild(m_builder, *markerRenderer), firstNonMarkerChild(*newParent));
119     else
120         m_builder.insertChild(*newParent, WTFMove(newMarkerRenderer), firstNonMarkerChild(*newParent));
121
122     // If current parent is an anonymous block that has lost all its children, destroy it.
123     if (currentParent && currentParent->isAnonymousBlock() && !currentParent->firstChild() && !downcast<RenderBlock>(*currentParent).continuation())
124         currentParent->removeFromParentAndDestroy(m_builder);
125 }
126
127 }