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