Add WTF::move()
[WebKit-https.git] / Source / WebCore / rendering / RenderRubyRun.cpp
1 /*
2  * Copyright (C) 2009 Google 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32
33 #include "RenderRubyRun.h"
34
35 #include "RenderRubyBase.h"
36 #include "RenderRubyText.h"
37 #include "RenderText.h"
38 #include "RenderView.h"
39 #include "StyleInheritedData.h"
40 #include <wtf/StackStats.h>
41
42 namespace WebCore {
43
44 RenderRubyRun::RenderRubyRun(Document& document, PassRef<RenderStyle> style)
45     : RenderBlockFlow(document, WTF::move(style))
46 {
47     setReplaced(true);
48     setInline(true);
49 }
50
51 RenderRubyRun::~RenderRubyRun()
52 {
53 }
54
55 bool RenderRubyRun::hasRubyText() const
56 {
57     // The only place where a ruby text can be is in the first position
58     // Note: As anonymous blocks, ruby runs do not have ':before' or ':after' content themselves.
59     return firstChild() && firstChild()->isRubyText();
60 }
61
62 bool RenderRubyRun::hasRubyBase() const
63 {
64     // The only place where a ruby base can be is in the last position
65     // Note: As anonymous blocks, ruby runs do not have ':before' or ':after' content themselves.
66     return lastChild() && lastChild()->isRubyBase();
67 }
68
69 bool RenderRubyRun::isEmpty() const
70 {
71     return !hasRubyText() && !hasRubyBase();
72 }
73
74 RenderRubyText* RenderRubyRun::rubyText() const
75 {
76     RenderObject* child = firstChild();
77     // If in future it becomes necessary to support floating or positioned ruby text,
78     // layout will have to be changed to handle them properly.
79     ASSERT(!child || !child->isRubyText() || !child->isFloatingOrOutOfFlowPositioned());
80     return child && child->isRubyText() ? static_cast<RenderRubyText*>(child) : 0;
81 }
82
83 RenderRubyBase* RenderRubyRun::rubyBase() const
84 {
85     RenderObject* child = lastChild();
86     return child && child->isRubyBase() ? static_cast<RenderRubyBase*>(child) : 0;
87 }
88
89 RenderRubyBase* RenderRubyRun::rubyBaseSafe()
90 {
91     RenderRubyBase* base = rubyBase();
92     if (!base) {
93         base = createRubyBase();
94         RenderBlockFlow::addChild(base);
95     }
96     return base;
97 }
98
99 RenderBlock* RenderRubyRun::firstLineBlock() const
100 {
101     return 0;
102 }
103
104 void RenderRubyRun::updateFirstLetter()
105 {
106 }
107
108 bool RenderRubyRun::isChildAllowed(const RenderObject& child, const RenderStyle&) const
109 {
110     return child.isInline() || child.isRubyText();
111 }
112
113 void RenderRubyRun::addChild(RenderObject* child, RenderObject* beforeChild)
114 {
115     ASSERT(child);
116
117     if (child->isRubyText()) {
118         if (!beforeChild) {
119             // RenderRuby has already ascertained that we can add the child here.
120             ASSERT(!hasRubyText());
121             // prepend ruby texts as first child
122             RenderBlockFlow::addChild(child, firstChild());
123         }  else if (beforeChild->isRubyText()) {
124             // New text is inserted just before another.
125             // In this case the new text takes the place of the old one, and
126             // the old text goes into a new run that is inserted as next sibling.
127             ASSERT(beforeChild->parent() == this);
128             RenderElement* ruby = parent();
129             ASSERT(ruby->isRuby());
130             RenderBlock* newRun = staticCreateRubyRun(ruby);
131             ruby->addChild(newRun, nextSibling());
132             // Add the new ruby text and move the old one to the new run
133             // Note: Doing it in this order and not using RenderRubyRun's methods,
134             // in order to avoid automatic removal of the ruby run in case there is no
135             // other child besides the old ruby text.
136             RenderBlockFlow::addChild(child, beforeChild);
137             RenderBlockFlow::removeChild(*beforeChild);
138             newRun->addChild(beforeChild);
139         } else if (hasRubyBase()) {
140             // Insertion before a ruby base object.
141             // In this case we need insert a new run before the current one and split the base.
142             RenderElement* ruby = parent();
143             RenderRubyRun* newRun = staticCreateRubyRun(ruby);
144             ruby->addChild(newRun, this);
145             newRun->addChild(child);
146             rubyBaseSafe()->moveChildren(newRun->rubyBaseSafe(), beforeChild);
147         }
148     } else {
149         // child is not a text -> insert it into the base
150         // (append it instead if beforeChild is the ruby text)
151         if (beforeChild && beforeChild->isRubyText())
152             beforeChild = 0;
153         rubyBaseSafe()->addChild(child, beforeChild);
154     }
155 }
156
157 RenderObject* RenderRubyRun::removeChild(RenderObject& child)
158 {
159     // If the child is a ruby text, then merge the ruby base with the base of
160     // the right sibling run, if possible.
161     if (!beingDestroyed() && !documentBeingDestroyed() && child.isRubyText()) {
162         RenderRubyBase* base = rubyBase();
163         RenderObject* rightNeighbour = nextSibling();
164         if (base && rightNeighbour && rightNeighbour->isRubyRun()) {
165             // Ruby run without a base can happen only at the first run.
166             RenderRubyRun* rightRun = toRenderRubyRun(rightNeighbour);
167             if (rightRun->hasRubyBase()) {
168                 RenderRubyBase* rightBase = rightRun->rubyBaseSafe();
169                 // Collect all children in a single base, then swap the bases.
170                 rightBase->mergeChildrenWithBase(base);
171                 moveChildTo(rightRun, base);
172                 rightRun->moveChildTo(this, rightBase);
173                 // The now empty ruby base will be removed below.
174                 ASSERT(!rubyBase()->firstChild());
175             }
176         }
177     }
178
179     RenderObject* next = RenderBlockFlow::removeChild(child);
180
181     if (!beingDestroyed() && !documentBeingDestroyed()) {
182         // Check if our base (if any) is now empty. If so, destroy it.
183         RenderBlock* base = rubyBase();
184         if (base && !base->firstChild()) {
185             next = RenderBlockFlow::removeChild(*base);
186             base->deleteLines();
187             base->destroy();
188         }
189
190         // If any of the above leaves the run empty, destroy it as well.
191         if (isEmpty()) {
192             parent()->removeChild(*this);
193             deleteLines();
194             destroy();
195             next = nullptr;
196         }
197     }
198     
199     return next;
200 }
201
202 RenderRubyBase* RenderRubyRun::createRubyBase() const
203 {
204     auto newStyle = RenderStyle::createAnonymousStyleWithDisplay(&style(), BLOCK);
205     newStyle.get().setTextAlign(CENTER); // FIXME: use WEBKIT_CENTER?
206     auto renderer = new RenderRubyBase(document(), WTF::move(newStyle));
207     renderer->initializeStyle();
208     return renderer;
209 }
210
211 RenderRubyRun* RenderRubyRun::staticCreateRubyRun(const RenderObject* parentRuby)
212 {
213     ASSERT(parentRuby && parentRuby->isRuby());
214     auto renderer = new RenderRubyRun(parentRuby->document(), RenderStyle::createAnonymousStyleWithDisplay(&parentRuby->style(), INLINE_BLOCK));
215     renderer->initializeStyle();
216     return renderer;
217 }
218
219 RenderObject* RenderRubyRun::layoutSpecialExcludedChild(bool relayoutChildren)
220 {
221     StackStats::LayoutCheckPoint layoutCheckPoint;
222     // Don't bother positioning the RenderRubyRun yet.
223     RenderRubyText* rt = rubyText();
224     if (!rt)
225         return 0;
226     if (relayoutChildren)
227         rt->setChildNeedsLayout(MarkOnlyThis);
228     rt->layoutIfNeeded();
229     return rt;
230 }
231
232 void RenderRubyRun::layout()
233 {
234     RenderBlockFlow::layout();
235     
236     RenderRubyText* rt = rubyText();
237     if (!rt)
238         return;
239
240     rt->setLogicalLeft(0);
241     
242     // Place the RenderRubyText such that its bottom is flush with the lineTop of the first line of the RenderRubyBase.
243     LayoutUnit lastLineRubyTextBottom = rt->logicalHeight();
244     LayoutUnit firstLineRubyTextTop = 0;
245     RootInlineBox* rootBox = rt->lastRootBox();
246     if (rootBox) {
247         // In order to align, we have to ignore negative leading.
248         firstLineRubyTextTop = rt->firstRootBox()->logicalTopLayoutOverflow();
249         lastLineRubyTextBottom = rootBox->logicalBottomLayoutOverflow();
250     }
251
252     if (style().isFlippedLinesWritingMode() == (style().rubyPosition() == RubyPositionAfter)) {
253         LayoutUnit firstLineTop = 0;
254         if (RenderRubyBase* rb = rubyBase()) {
255             RootInlineBox* rootBox = rb->firstRootBox();
256             if (rootBox)
257                 firstLineTop = rootBox->logicalTopLayoutOverflow();
258             firstLineTop += rb->logicalTop();
259         }
260         
261         rt->setLogicalTop(-lastLineRubyTextBottom + firstLineTop);
262     } else {
263         LayoutUnit lastLineBottom = logicalHeight();
264         if (RenderRubyBase* rb = rubyBase()) {
265             RootInlineBox* rootBox = rb->lastRootBox();
266             if (rootBox)
267                 lastLineBottom = rootBox->logicalBottomLayoutOverflow();
268             lastLineBottom += rb->logicalTop();
269         }
270
271         rt->setLogicalTop(-firstLineRubyTextTop + lastLineBottom);
272     }
273
274     // Update our overflow to account for the new RenderRubyText position.
275     computeOverflow(clientLogicalBottom());
276 }
277
278 static bool shouldOverhang(bool firstLine, const RenderObject* renderer, const RenderRubyBase& rubyBase)
279 {
280     if (!renderer || !renderer->isText())
281         return false;
282     const RenderStyle& rubyBaseStyle = firstLine ? rubyBase.firstLineStyle() : rubyBase.style();
283     const RenderStyle& style = firstLine ? renderer->firstLineStyle() : renderer->style();
284     return style.fontSize() <= rubyBaseStyle.fontSize();
285 }
286
287 void RenderRubyRun::getOverhang(bool firstLine, RenderObject* startRenderer, RenderObject* endRenderer, int& startOverhang, int& endOverhang) const
288 {
289     ASSERT(!needsLayout());
290
291     startOverhang = 0;
292     endOverhang = 0;
293
294     RenderRubyBase* rubyBase = this->rubyBase();
295     RenderRubyText* rubyText = this->rubyText();
296
297     if (!rubyBase || !rubyText)
298         return;
299
300     if (!rubyBase->firstRootBox())
301         return;
302
303     int logicalWidth = this->logicalWidth();
304     int logicalLeftOverhang = std::numeric_limits<int>::max();
305     int logicalRightOverhang = std::numeric_limits<int>::max();
306     for (RootInlineBox* rootInlineBox = rubyBase->firstRootBox(); rootInlineBox; rootInlineBox = rootInlineBox->nextRootBox()) {
307         logicalLeftOverhang = std::min<int>(logicalLeftOverhang, rootInlineBox->logicalLeft());
308         logicalRightOverhang = std::min<int>(logicalRightOverhang, logicalWidth - rootInlineBox->logicalRight());
309     }
310
311     startOverhang = style().isLeftToRightDirection() ? logicalLeftOverhang : logicalRightOverhang;
312     endOverhang = style().isLeftToRightDirection() ? logicalRightOverhang : logicalLeftOverhang;
313
314     if (!shouldOverhang(firstLine, startRenderer, *rubyBase))
315         startOverhang = 0;
316     if (!shouldOverhang(firstLine, endRenderer, *rubyBase))
317         endOverhang = 0;
318
319     // We overhang a ruby only if the neighboring render object is a text.
320     // We can overhang the ruby by no more than half the width of the neighboring text
321     // and no more than half the font size.
322     const RenderStyle& rubyTextStyle = firstLine ? rubyText->firstLineStyle() : rubyText->style();
323     int halfWidthOfFontSize = rubyTextStyle.fontSize() / 2;
324     if (startOverhang)
325         startOverhang = std::min<int>(startOverhang, std::min<int>(toRenderText(startRenderer)->minLogicalWidth(), halfWidthOfFontSize));
326     if (endOverhang)
327         endOverhang = std::min<int>(endOverhang, std::min<int>(toRenderText(endRenderer)->minLogicalWidth(), halfWidthOfFontSize));
328 }
329
330 } // namespace WebCore