Introduce RenderTreeBuilder
[WebKit-https.git] / Source / WebCore / rendering / RenderTreeBuilder.cpp
1 /*
2  * Copyright (C) 2017 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 "RenderTreeBuilder.h"
28
29 #include "RenderElement.h"
30 #include "RenderRuby.h"
31 #include "RenderRubyBase.h"
32 #include "RenderRubyRun.h"
33 #include "RenderText.h"
34 #include "RenderTreeUpdater.h"
35
36 namespace WebCore {
37
38 RenderTreeBuilder* RenderTreeBuilder::m_current;
39
40 RenderTreeBuilder::RenderTreeBuilder()
41 {
42     RELEASE_ASSERT(!m_current);
43     m_current = this;
44 }
45
46 RenderTreeBuilder::~RenderTreeBuilder()
47 {
48     m_current = nullptr;
49 }
50
51 void RenderTreeBuilder::insertChild(RenderElement& parent, RenderPtr<RenderObject> child, RenderObject* beforeChild)
52 {
53     // We don't yet have any local access, ensure we are still called with non-null this ptr.
54     ASSERT(this);
55
56     if (is<RenderText>(beforeChild)) {
57         if (auto* wrapperInline = downcast<RenderText>(*beforeChild).inlineWrapperForDisplayContents())
58             beforeChild = wrapperInline;
59     }
60
61     if (is<RenderRubyRun>(parent)) {
62         rubyRunInsertChild(downcast<RenderRubyRun>(parent), WTFMove(child), beforeChild);
63         return;
64     }
65
66     parent.addChild(*this, WTFMove(child), beforeChild);
67 }
68
69 void RenderTreeBuilder::insertChild(RenderTreePosition& position, RenderPtr<RenderObject> child)
70 {
71     insertChild(position.parent(), WTFMove(child), position.nextSibling());
72 }
73
74 void RenderTreeBuilder::rubyRunInsertChild(RenderRubyRun& parent, RenderPtr<RenderObject> child, RenderObject* beforeChild)
75 {
76     if (child->isRubyText()) {
77         if (!beforeChild) {
78             // RenderRuby has already ascertained that we can add the child here.
79             ASSERT(!parent.hasRubyText());
80             // prepend ruby texts as first child
81             parent.addChild(*this, WTFMove(child), parent.firstChild());
82             return;
83         }
84         if (beforeChild->isRubyText()) {
85             // New text is inserted just before another.
86             // In this case the new text takes the place of the old one, and
87             // the old text goes into a new run that is inserted as next sibling.
88             ASSERT(beforeChild->parent() == &parent);
89             RenderElement* ruby = parent.parent();
90             ASSERT(isRuby(ruby));
91             auto newRun = RenderRubyRun::staticCreateRubyRun(ruby);
92             insertChild(*ruby, WTFMove(newRun), parent.nextSibling());
93             // Add the new ruby text and move the old one to the new run
94             // Note: Doing it in this order and not using RenderRubyRun's methods,
95             // in order to avoid automatic removal of the ruby run in case there is no
96             // other child besides the old ruby text.
97             parent.addChild(*this, WTFMove(child), beforeChild);
98             auto takenBeforeChild = parent.RenderBlockFlow::takeChild(*beforeChild);
99             insertChild(*newRun, WTFMove(takenBeforeChild));
100             return;
101         }
102         if (parent.hasRubyBase()) {
103             // Insertion before a ruby base object.
104             // In this case we need insert a new run before the current one and split the base.
105             RenderElement* ruby = parent.parent();
106             auto newRun = RenderRubyRun::staticCreateRubyRun(ruby);
107             auto& run = *newRun;
108             insertChild(*ruby, WTFMove(newRun), &parent);
109             insertChild(run, WTFMove(child));
110             parent.rubyBaseSafe()->moveChildren(run.rubyBaseSafe(), beforeChild);
111         }
112         return;
113     }
114     // child is not a text -> insert it into the base
115     // (append it instead if beforeChild is the ruby text)
116     if (beforeChild && beforeChild->isRubyText())
117         beforeChild = nullptr;
118     insertChild(*parent.rubyBaseSafe(), WTFMove(child), beforeChild);
119 }
120
121 }