Unreviewed, rolling out r224494.
[WebKit-https.git] / Source / WebCore / style / RenderTreeUpdaterListItem.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 "RenderTreeUpdaterListItem.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 void RenderTreeUpdater::ListItem::updateMarker(RenderListItem& listItemRenderer)
73 {
74     ASSERT_WITH_SECURITY_IMPLICATION(!listItemRenderer.view().layoutState());
75
76     auto& style = listItemRenderer.style();
77
78     if (style.listStyleType() == NoneListStyle && (!style.listStyleImage() || style.listStyleImage()->errorOccurred())) {
79         if (auto* marker = listItemRenderer.markerRenderer())
80             marker->removeFromParentAndDestroy();
81         return;
82     }
83
84     auto newStyle = listItemRenderer.computeMarkerStyle();
85     RenderPtr<RenderListMarker> newMarkerRenderer;
86     auto* markerRenderer = listItemRenderer.markerRenderer();
87     if (markerRenderer)
88         markerRenderer->setStyle(WTFMove(newStyle));
89     else {
90         newMarkerRenderer = WebCore::createRenderer<RenderListMarker>(listItemRenderer, WTFMove(newStyle));
91         newMarkerRenderer->initializeStyle();
92         markerRenderer = newMarkerRenderer.get();
93         listItemRenderer.setMarkerRenderer(*markerRenderer);
94     }
95
96     RenderElement* currentParent = markerRenderer->parent();
97     RenderBlock* newParent = getParentOfFirstLineBox(listItemRenderer, *markerRenderer);
98     if (!newParent) {
99         // If the marker is currently contained inside an anonymous box,
100         // then we are the only item in that anonymous box (since no line box
101         // parent was found). It's ok to just leave the marker where it is
102         // in this case.
103         if (currentParent && currentParent->isAnonymousBlock())
104             return;
105         if (auto* multiColumnFlow = listItemRenderer.multiColumnFlow())
106             newParent = multiColumnFlow;
107         else
108             newParent = &listItemRenderer;
109     }
110
111     if (newParent != currentParent) {
112         if (currentParent)
113             newParent->addChild(currentParent->takeChild(*markerRenderer), firstNonMarkerChild(*newParent));
114         else
115             newParent->addChild(WTFMove(newMarkerRenderer), firstNonMarkerChild(*newParent));
116
117         // If current parent is an anonymous block that has lost all its children, destroy it.
118         if (currentParent && currentParent->isAnonymousBlock() && !currentParent->firstChild() && !downcast<RenderBlock>(*currentParent).continuation())
119             currentParent->removeFromParentAndDestroy();
120     }
121 }
122
123 }