[RenderTreeBuilder] Move RenderElement::insertChildInternal() to RenderTreeBuilder
[WebKit-https.git] / Source / WebCore / rendering / updating / RenderTreeBuilderRuby.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 "RenderTreeBuilderRuby.h"
28
29 #include "RenderRuby.h"
30 #include "RenderRubyBase.h"
31 #include "RenderRubyRun.h"
32 #include "RenderTreeBuilder.h"
33 #include "RenderTreeBuilderBlock.h"
34 #include "RenderTreeBuilderBlockFlow.h"
35 #include "RenderTreeBuilderInline.h"
36
37 namespace WebCore {
38
39 static inline RenderRubyRun& findRubyRunParent(RenderObject& child)
40 {
41     return *lineageOfType<RenderRubyRun>(child).first();
42 }
43
44 static inline bool isAnonymousRubyInlineBlock(const RenderObject* object)
45 {
46     ASSERT(!object
47         || !isRuby(object->parent())
48         || is<RenderRubyRun>(*object)
49         || (object->isInline() && (object->isBeforeContent() || object->isAfterContent()))
50         || (object->isAnonymous() && is<RenderBlock>(*object) && object->style().display() == INLINE_BLOCK));
51
52     return object
53         && isRuby(object->parent())
54         && is<RenderBlock>(*object)
55         && !is<RenderRubyRun>(*object);
56 }
57
58 static inline bool isRubyBeforeBlock(const RenderObject* object)
59 {
60     return isAnonymousRubyInlineBlock(object)
61         && !object->previousSibling()
62         && downcast<RenderBlock>(*object).firstChild()
63         && downcast<RenderBlock>(*object).firstChild()->style().styleType() == BEFORE;
64 }
65
66 static inline bool isRubyAfterBlock(const RenderObject* object)
67 {
68     return isAnonymousRubyInlineBlock(object)
69         && !object->nextSibling()
70         && downcast<RenderBlock>(*object).firstChild()
71         && downcast<RenderBlock>(*object).firstChild()->style().styleType() == AFTER;
72 }
73
74 #ifndef ASSERT_DISABLED
75 static inline bool isRubyChildForNormalRemoval(const RenderObject& object)
76 {
77     return object.isRubyRun()
78     || object.isBeforeContent()
79     || object.isAfterContent()
80     || object.isRenderMultiColumnFlow()
81     || object.isRenderMultiColumnSet()
82     || isAnonymousRubyInlineBlock(&object);
83 }
84 #endif
85
86 static inline RenderBlock* rubyBeforeBlock(const RenderElement* ruby)
87 {
88     RenderObject* child = ruby->firstChild();
89     return isRubyBeforeBlock(child) ? downcast<RenderBlock>(child) : nullptr;
90 }
91
92 static inline RenderBlock* rubyAfterBlock(const RenderElement* ruby)
93 {
94     RenderObject* child = ruby->lastChild();
95     return isRubyAfterBlock(child) ? downcast<RenderBlock>(child) : nullptr;
96 }
97
98 static auto createAnonymousRubyInlineBlock(RenderObject& ruby)
99 {
100     auto newBlock = createRenderer<RenderBlockFlow>(ruby.document(), RenderStyle::createAnonymousStyleWithDisplay(ruby.style(), INLINE_BLOCK));
101     newBlock->initializeStyle();
102     return newBlock;
103 }
104
105 static RenderRubyRun* lastRubyRun(const RenderElement* ruby)
106 {
107     RenderObject* child = ruby->lastChild();
108     if (child && !is<RenderRubyRun>(*child))
109         child = child->previousSibling();
110     if (!is<RenderRubyRun>(child)) {
111         ASSERT(!child || child->isBeforeContent() || child == rubyBeforeBlock(ruby));
112         return nullptr;
113     }
114     return downcast<RenderRubyRun>(child);
115 }
116
117 RenderTreeBuilder::Ruby::Ruby(RenderTreeBuilder& builder)
118     : m_builder(builder)
119 {
120 }
121
122 void RenderTreeBuilder::Ruby::moveInlineChildren(RenderRubyBase& from, RenderRubyBase& to, RenderObject* beforeChild)
123 {
124     ASSERT(from.childrenInline());
125
126     if (!from.firstChild())
127         return;
128
129     RenderBlock* toBlock = nullptr;
130     if (to.childrenInline()) {
131         // The standard and easy case: move the children into the target base
132         toBlock = &to;
133     } else {
134         // We need to wrap the inline objects into an anonymous block.
135         // If toBase has a suitable block, we re-use it, otherwise create a new one.
136         auto* lastChild = to.lastChild();
137         if (lastChild && lastChild->isAnonymousBlock() && lastChild->childrenInline())
138             toBlock = downcast<RenderBlock>(lastChild);
139         else {
140             auto newToBlock = to.createAnonymousBlock();
141             toBlock = newToBlock.get();
142             m_builder.insertChildToRenderElementInternal(to, WTFMove(newToBlock));
143         }
144     }
145     // Move our inline children into the target block we determined above.
146     from.moveChildrenTo(m_builder, toBlock, from.firstChild(), beforeChild, RenderBoxModelObject::NormalizeAfterInsertion::No);
147 }
148
149 void RenderTreeBuilder::Ruby::moveBlockChildren(RenderRubyBase& from, RenderRubyBase& to, RenderObject* beforeChild)
150 {
151     ASSERT(!from.childrenInline());
152
153     if (!from.firstChild())
154         return;
155
156     if (to.childrenInline())
157         m_builder.makeChildrenNonInline(to);
158
159     // If an anonymous block would be put next to another such block, then merge those.
160     auto* firstChildHere = from.firstChild();
161     auto* lastChildThere = to.lastChild();
162     if (firstChildHere->isAnonymousBlock() && firstChildHere->childrenInline()
163         && lastChildThere && lastChildThere->isAnonymousBlock() && lastChildThere->childrenInline()) {
164         auto* anonBlockHere = downcast<RenderBlock>(firstChildHere);
165         auto* anonBlockThere = downcast<RenderBlock>(lastChildThere);
166         anonBlockHere->moveAllChildrenTo(m_builder, anonBlockThere, RenderBoxModelObject::NormalizeAfterInsertion::Yes);
167         anonBlockHere->deleteLines();
168         anonBlockHere->removeFromParentAndDestroy(m_builder);
169     }
170     // Move all remaining children normally.
171     from.moveChildrenTo(m_builder, &to, from.firstChild(), beforeChild, RenderBoxModelObject::NormalizeAfterInsertion::No);
172 }
173
174 void RenderTreeBuilder::Ruby::moveChildren(RenderRubyBase& from, RenderRubyBase& to)
175 {
176     moveChildrenInternal(from, to);
177     from.addFloatsToNewParent(to);
178 }
179
180 void RenderTreeBuilder::Ruby::moveChildrenInternal(RenderRubyBase& from, RenderRubyBase& to, RenderObject* beforeChild)
181 {
182     // This function removes all children that are before (!) beforeChild
183     // and appends them to toBase.
184     if (beforeChild && beforeChild->parent() != &from)
185         beforeChild = m_builder.splitAnonymousBoxesAroundChild(from, beforeChild);
186
187     if (from.childrenInline())
188         moveInlineChildren(from, to, beforeChild);
189     else
190         moveBlockChildren(from, to, beforeChild);
191
192     from.setNeedsLayoutAndPrefWidthsRecalc();
193     to.setNeedsLayoutAndPrefWidthsRecalc();
194 }
195
196 void RenderTreeBuilder::Ruby::insertChild(RenderRubyRun& parent, RenderPtr<RenderObject> child, RenderObject* beforeChild)
197 {
198     if (child->isRubyText()) {
199         if (!beforeChild) {
200             // RenderRuby has already ascertained that we can add the child here.
201             ASSERT(!parent.hasRubyText());
202             // prepend ruby texts as first child
203             m_builder.blockFlowBuilder().insertChild(parent, WTFMove(child), parent.firstChild());
204             return;
205         }
206         if (beforeChild->isRubyText()) {
207             // New text is inserted just before another.
208             // In this case the new text takes the place of the old one, and
209             // the old text goes into a new run that is inserted as next sibling.
210             ASSERT(beforeChild->parent() == &parent);
211             RenderElement* ruby = parent.parent();
212             ASSERT(isRuby(ruby));
213             auto newRun = RenderRubyRun::staticCreateRubyRun(ruby);
214             m_builder.insertChild(*ruby, WTFMove(newRun), parent.nextSibling());
215             // Add the new ruby text and move the old one to the new run
216             // Note: Doing it in this order and not using RenderRubyRun's methods,
217             // in order to avoid automatic removal of the ruby run in case there is no
218             // other child besides the old ruby text.
219             m_builder.blockFlowBuilder().insertChild(parent, WTFMove(child), beforeChild);
220             auto takenBeforeChild = m_builder.blockBuilder().takeChild(parent, *beforeChild);
221
222             m_builder.insertChild(*newRun, WTFMove(takenBeforeChild));
223             return;
224         }
225         if (parent.hasRubyBase()) {
226             // Insertion before a ruby base object.
227             // In this case we need insert a new run before the current one and split the base.
228             RenderElement* ruby = parent.parent();
229             auto newRun = RenderRubyRun::staticCreateRubyRun(ruby);
230             auto& run = *newRun;
231             m_builder.insertChild(*ruby, WTFMove(newRun), &parent);
232             m_builder.insertChild(run, WTFMove(child));
233             moveChildrenInternal(rubyBaseSafe(parent), rubyBaseSafe(run), beforeChild);
234         }
235         return;
236     }
237     // child is not a text -> insert it into the base
238     // (append it instead if beforeChild is the ruby text)
239     if (beforeChild && beforeChild->isRubyText())
240         beforeChild = nullptr;
241     m_builder.insertChild(rubyBaseSafe(parent), WTFMove(child), beforeChild);
242 }
243
244 RenderElement& RenderTreeBuilder::Ruby::findOrCreateParentForChild(RenderRubyAsBlock& parent, const RenderObject& child, RenderObject*& beforeChild)
245 {
246     // Insert :before and :after content before/after the RenderRubyRun(s)
247     if (child.isBeforeContent()) {
248         // Add generated inline content normally
249         if (child.isInline())
250             return parent;
251         // Wrap non-inline content in an anonymous inline-block.
252         auto* beforeBlock = rubyBeforeBlock(&parent);
253         if (!beforeBlock) {
254             auto newBlock = createAnonymousRubyInlineBlock(parent);
255             beforeBlock = newBlock.get();
256             m_builder.blockFlowBuilder().insertChild(parent, WTFMove(newBlock), parent.firstChild());
257         }
258         beforeChild = nullptr;
259         return *beforeBlock;
260     }
261
262     if (child.isAfterContent()) {
263         // Add generated inline content normally
264         if (child.isInline())
265             return parent;
266         // Wrap non-inline content with an anonymous inline-block.
267         auto* afterBlock = rubyAfterBlock(&parent);
268         if (!afterBlock) {
269             auto newBlock = createAnonymousRubyInlineBlock(parent);
270             afterBlock = newBlock.get();
271             m_builder.blockFlowBuilder().insertChild(parent, WTFMove(newBlock), nullptr);
272         }
273         beforeChild = nullptr;
274         return *afterBlock;
275     }
276
277     // If the child is a ruby run, just add it normally.
278     if (child.isRubyRun())
279         return parent;
280
281     if (beforeChild && !parent.isAfterContent(beforeChild)) {
282         // insert child into run
283         ASSERT(!beforeChild->isRubyRun());
284         auto* run = beforeChild->parent();
285         while (run && !run->isRubyRun())
286             run = run->parent();
287         if (run)
288             return *run;
289         ASSERT_NOT_REACHED(); // beforeChild should always have a run as parent!
290         // Emergency fallback: fall through and just append.
291     }
292
293     // If the new child would be appended, try to add the child to the previous run
294     // if possible, or create a new run otherwise.
295     // (The RenderRubyRun object will handle the details)
296     auto* lastRun = lastRubyRun(&parent);
297     if (!lastRun || lastRun->hasRubyText()) {
298         auto newRun = RenderRubyRun::staticCreateRubyRun(&parent);
299         lastRun = newRun.get();
300         m_builder.blockFlowBuilder().insertChild(parent, WTFMove(newRun), beforeChild);
301     }
302     beforeChild = nullptr;
303     return *lastRun;
304 }
305
306 RenderElement& RenderTreeBuilder::Ruby::findOrCreateParentForChild(RenderRubyAsInline& parent, const RenderObject& child, RenderObject*& beforeChild)
307 {
308     // Insert :before and :after content before/after the RenderRubyRun(s)
309     if (child.isBeforeContent()) {
310         // Add generated inline content normally
311         if (child.isInline())
312             return parent;
313         // Wrap non-inline content with an anonymous inline-block.
314         auto* beforeBlock = rubyBeforeBlock(&parent);
315         if (!beforeBlock) {
316             auto newBlock = createAnonymousRubyInlineBlock(parent);
317             beforeBlock = newBlock.get();
318             m_builder.inlineBuilder().insertChild(parent, WTFMove(newBlock), parent.firstChild());
319         }
320         beforeChild = nullptr;
321         return *beforeBlock;
322     }
323
324     if (child.isAfterContent()) {
325         // Add generated inline content normally
326         if (child.isInline())
327             return parent;
328         // Wrap non-inline content with an anonymous inline-block.
329         auto* afterBlock = rubyAfterBlock(&parent);
330         if (!afterBlock) {
331             auto newBlock = createAnonymousRubyInlineBlock(parent);
332             afterBlock = newBlock.get();
333             m_builder.inlineBuilder().insertChild(parent, WTFMove(newBlock), nullptr);
334         }
335         beforeChild = nullptr;
336         return *afterBlock;
337     }
338
339     // If the child is a ruby run, just add it normally.
340     if (child.isRubyRun())
341         return parent;
342
343     if (beforeChild && !parent.isAfterContent(beforeChild)) {
344         // insert child into run
345         ASSERT(!beforeChild->isRubyRun());
346         auto* run = beforeChild->parent();
347         while (run && !run->isRubyRun())
348             run = run->parent();
349         if (run)
350             return *run;
351         ASSERT_NOT_REACHED(); // beforeChild should always have a run as parent!
352         // Emergency fallback: fall through and just append.
353     }
354
355     // If the new child would be appended, try to add the child to the previous run
356     // if possible, or create a new run otherwise.
357     // (The RenderRubyRun object will handle the details)
358     auto* lastRun = lastRubyRun(&parent);
359     if (!lastRun || lastRun->hasRubyText()) {
360         auto newRun = RenderRubyRun::staticCreateRubyRun(&parent);
361         lastRun = newRun.get();
362         m_builder.inlineBuilder().insertChild(parent, WTFMove(newRun), beforeChild);
363     }
364     beforeChild = nullptr;
365     return *lastRun;
366 }
367
368 RenderRubyBase& RenderTreeBuilder::Ruby::rubyBaseSafe(RenderRubyRun& rubyRun)
369 {
370     auto* base = rubyRun.rubyBase();
371     if (!base) {
372         auto newBase = rubyRun.createRubyBase();
373         base = newBase.get();
374         m_builder.blockFlowBuilder().insertChild(rubyRun, WTFMove(newBase), nullptr);
375     }
376     return *base;
377 }
378
379 RenderPtr<RenderObject> RenderTreeBuilder::Ruby::takeChild(RenderRubyAsInline& parent, RenderObject& child)
380 {
381     // If the child's parent is *this (must be a ruby run or generated content or anonymous block),
382     // just use the normal remove method.
383     if (child.parent() == &parent) {
384 #ifndef ASSERT_DISABLED
385         ASSERT(isRubyChildForNormalRemoval(child));
386 #endif
387         return m_builder.takeChildFromRenderElement(parent, child);
388     }
389     // If the child's parent is an anoymous block (must be generated :before/:after content)
390     // just use the block's remove method.
391     if (isAnonymousRubyInlineBlock(child.parent())) {
392         ASSERT(child.isBeforeContent() || child.isAfterContent());
393         auto& parent = *child.parent();
394         auto takenChild = m_builder.takeChild(parent, child);
395         parent.removeFromParentAndDestroy(m_builder);
396         return takenChild;
397     }
398
399     // Otherwise find the containing run and remove it from there.
400     return m_builder.takeChild(findRubyRunParent(child), child);
401 }
402
403 RenderPtr<RenderObject> RenderTreeBuilder::Ruby::takeChild(RenderRubyAsBlock& parent, RenderObject& child)
404 {
405     // If the child's parent is *this (must be a ruby run or generated content or anonymous block),
406     // just use the normal remove method.
407     if (child.parent() == &parent) {
408 #ifndef ASSERT_DISABLED
409         ASSERT(isRubyChildForNormalRemoval(child));
410 #endif
411         return m_builder.blockBuilder().takeChild(parent, child);
412     }
413     // If the child's parent is an anoymous block (must be generated :before/:after content)
414     // just use the block's remove method.
415     if (isAnonymousRubyInlineBlock(child.parent())) {
416         ASSERT(child.isBeforeContent() || child.isAfterContent());
417         auto& parent = *child.parent();
418         auto takenChild = m_builder.takeChild(parent, child);
419         parent.removeFromParentAndDestroy(m_builder);
420         return takenChild;
421     }
422
423     // Otherwise find the containing run and remove it from there.
424     return m_builder.takeChild(findRubyRunParent(child), child);
425 }
426
427 RenderPtr<RenderObject> RenderTreeBuilder::Ruby::takeChild(RenderRubyRun& parent, RenderObject& child)
428 {
429     // If the child is a ruby text, then merge the ruby base with the base of
430     // the right sibling run, if possible.
431     if (!parent.beingDestroyed() && !parent.renderTreeBeingDestroyed() && child.isRubyText()) {
432         RenderRubyBase* base = parent.rubyBase();
433         RenderObject* rightNeighbour = parent.nextSibling();
434         if (base && is<RenderRubyRun>(rightNeighbour)) {
435             // Ruby run without a base can happen only at the first run.
436             RenderRubyRun& rightRun = downcast<RenderRubyRun>(*rightNeighbour);
437             if (rightRun.hasRubyBase()) {
438                 RenderRubyBase* rightBase = rightRun.rubyBase();
439                 // Collect all children in a single base, then swap the bases.
440                 moveChildren(*rightBase, *base);
441                 parent.moveChildTo(m_builder, &rightRun, base, RenderBoxModelObject::NormalizeAfterInsertion::No);
442                 rightRun.moveChildTo(m_builder, &parent, rightBase, RenderBoxModelObject::NormalizeAfterInsertion::No);
443                 // The now empty ruby base will be removed below.
444                 ASSERT(!parent.rubyBase()->firstChild());
445             }
446         }
447     }
448
449     auto takenChild = m_builder.blockBuilder().takeChild(parent, child);
450
451     if (!parent.beingDestroyed() && !parent.renderTreeBeingDestroyed()) {
452         // Check if our base (if any) is now empty. If so, destroy it.
453         RenderBlock* base = parent.rubyBase();
454         if (base && !base->firstChild()) {
455             auto takenBase = m_builder.blockBuilder().takeChild(parent, *base);
456             base->deleteLines();
457         }
458     }
459     return takenChild;
460 }
461
462 }