Use "= default" to denote default constructor or destructor
[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 "RenderRuby.h"
36 #include "RenderRubyBase.h"
37 #include "RenderRubyText.h"
38 #include "RenderText.h"
39 #include "RenderView.h"
40 #include "StyleInheritedData.h"
41 #include <wtf/StackStats.h>
42
43 namespace WebCore {
44
45 using namespace std;
46
47 RenderRubyRun::RenderRubyRun(Document& document, RenderStyle&& style)
48     : RenderBlockFlow(document, WTFMove(style))
49     , m_lastCharacter(0)
50     , m_secondToLastCharacter(0)
51 {
52     setReplaced(true);
53     setInline(true);
54 }
55
56 RenderRubyRun::~RenderRubyRun() = default;
57
58 bool RenderRubyRun::hasRubyText() const
59 {
60     // The only place where a ruby text can be is in the first position
61     // Note: As anonymous blocks, ruby runs do not have ':before' or ':after' content themselves.
62     return firstChild() && firstChild()->isRubyText();
63 }
64
65 bool RenderRubyRun::hasRubyBase() const
66 {
67     // The only place where a ruby base can be is in the last position
68     // Note: As anonymous blocks, ruby runs do not have ':before' or ':after' content themselves.
69     return lastChild() && lastChild()->isRubyBase();
70 }
71
72 RenderRubyText* RenderRubyRun::rubyText() const
73 {
74     RenderObject* child = firstChild();
75     // If in future it becomes necessary to support floating or positioned ruby text,
76     // layout will have to be changed to handle them properly.
77     ASSERT(!child || !child->isRubyText() || !child->isFloatingOrOutOfFlowPositioned());
78     return child && child->isRubyText() ? static_cast<RenderRubyText*>(child) : 0;
79 }
80
81 RenderRubyBase* RenderRubyRun::rubyBase() const
82 {
83     RenderObject* child = lastChild();
84     return child && child->isRubyBase() ? static_cast<RenderRubyBase*>(child) : 0;
85 }
86
87 RenderRubyBase* RenderRubyRun::rubyBaseSafe()
88 {
89     RenderRubyBase* base = rubyBase();
90     if (!base) {
91         auto newBase = createRubyBase();
92         base = newBase.get();
93         RenderBlockFlow::addChild(WTFMove(newBase));
94     }
95     return base;
96 }
97
98 RenderBlock* RenderRubyRun::firstLineBlock() const
99 {
100     return 0;
101 }
102
103 bool RenderRubyRun::isChildAllowed(const RenderObject& child, const RenderStyle&) const
104 {
105     return child.isInline() || child.isRubyText();
106 }
107
108 void RenderRubyRun::addChild(RenderPtr<RenderObject> child, RenderObject* beforeChild)
109 {
110     ASSERT(child);
111
112     if (child->isRubyText()) {
113         if (!beforeChild) {
114             // RenderRuby has already ascertained that we can add the child here.
115             ASSERT(!hasRubyText());
116             // prepend ruby texts as first child
117             RenderBlockFlow::addChild(WTFMove(child), firstChild());
118         }  else if (beforeChild->isRubyText()) {
119             // New text is inserted just before another.
120             // In this case the new text takes the place of the old one, and
121             // the old text goes into a new run that is inserted as next sibling.
122             ASSERT(beforeChild->parent() == this);
123             RenderElement* ruby = parent();
124             ASSERT(isRuby(ruby));
125             auto newRun = staticCreateRubyRun(ruby);
126             ruby->addChild(WTFMove(newRun), nextSibling());
127             // Add the new ruby text and move the old one to the new run
128             // Note: Doing it in this order and not using RenderRubyRun's methods,
129             // in order to avoid automatic removal of the ruby run in case there is no
130             // other child besides the old ruby text.
131             RenderBlockFlow::addChild(WTFMove(child), beforeChild);
132             auto takenBeforeChild = RenderBlockFlow::takeChild(*beforeChild);
133             newRun->addChild(WTFMove(takenBeforeChild));
134         } else if (hasRubyBase()) {
135             // Insertion before a ruby base object.
136             // In this case we need insert a new run before the current one and split the base.
137             RenderElement* ruby = parent();
138             auto newRun = staticCreateRubyRun(ruby);
139             auto& run = *newRun;
140             ruby->addChild(WTFMove(newRun), this);
141             run.addChild(WTFMove(child));
142             rubyBaseSafe()->moveChildren(run.rubyBaseSafe(), beforeChild);
143         }
144     } else {
145         // child is not a text -> insert it into the base
146         // (append it instead if beforeChild is the ruby text)
147         if (beforeChild && beforeChild->isRubyText())
148             beforeChild = 0;
149         rubyBaseSafe()->addChild(WTFMove(child), beforeChild);
150     }
151 }
152
153 RenderPtr<RenderObject> RenderRubyRun::takeChild(RenderObject& child)
154 {
155     // If the child is a ruby text, then merge the ruby base with the base of
156     // the right sibling run, if possible.
157     if (!beingDestroyed() && !renderTreeBeingDestroyed() && child.isRubyText()) {
158         RenderRubyBase* base = rubyBase();
159         RenderObject* rightNeighbour = nextSibling();
160         if (base && is<RenderRubyRun>(rightNeighbour)) {
161             // Ruby run without a base can happen only at the first run.
162             RenderRubyRun& rightRun = downcast<RenderRubyRun>(*rightNeighbour);
163             if (rightRun.hasRubyBase()) {
164                 RenderRubyBase* rightBase = rightRun.rubyBaseSafe();
165                 // Collect all children in a single base, then swap the bases.
166                 rightBase->mergeChildrenWithBase(*base);
167                 moveChildTo(&rightRun, base);
168                 rightRun.moveChildTo(this, rightBase);
169                 // The now empty ruby base will be removed below.
170                 ASSERT(!rubyBase()->firstChild());
171             }
172         }
173     }
174
175     auto takenChild = RenderBlockFlow::takeChild(child);
176
177     if (!beingDestroyed() && !renderTreeBeingDestroyed()) {
178         // Check if our base (if any) is now empty. If so, destroy it.
179         RenderBlock* base = rubyBase();
180         if (base && !base->firstChild()) {
181             auto takenBase = RenderBlockFlow::takeChild(*base);
182             base->deleteLines();
183         }
184
185         // If any of the above leaves the run empty, destroy it as well.
186         if (!hasRubyText() && !hasRubyBase()) {
187             auto takenThis = parent()->takeChild(*this);
188             deleteLines();
189         }
190     }
191
192     return takenChild;
193 }
194
195 RenderPtr<RenderRubyBase> RenderRubyRun::createRubyBase() const
196 {
197     auto newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK);
198     newStyle.setTextAlign(CENTER); // FIXME: use WEBKIT_CENTER?
199     auto renderer = createRenderer<RenderRubyBase>(document(), WTFMove(newStyle));
200     renderer->initializeStyle();
201     return renderer;
202 }
203
204 RenderPtr<RenderRubyRun> RenderRubyRun::staticCreateRubyRun(const RenderObject* parentRuby)
205 {
206     ASSERT(isRuby(parentRuby));
207     auto renderer = createRenderer<RenderRubyRun>(parentRuby->document(), RenderStyle::createAnonymousStyleWithDisplay(parentRuby->style(), INLINE_BLOCK));
208     renderer->initializeStyle();
209     return renderer;
210 }
211
212 void RenderRubyRun::layoutExcludedChildren(bool relayoutChildren)
213 {
214     RenderBlockFlow::layoutExcludedChildren(relayoutChildren);
215
216     StackStats::LayoutCheckPoint layoutCheckPoint;
217     // Don't bother positioning the RenderRubyRun yet.
218     RenderRubyText* rt = rubyText();
219     if (!rt)
220         return;
221     rt->setIsExcludedFromNormalLayout(true);
222     if (relayoutChildren)
223         rt->setChildNeedsLayout(MarkOnlyThis);
224     rt->layoutIfNeeded();
225 }
226
227 void RenderRubyRun::layout()
228 {
229     if (RenderRubyBase* base = rubyBase())
230         base->reset();
231     RenderBlockFlow::layout();
232 }
233
234 void RenderRubyRun::layoutBlock(bool relayoutChildren, LayoutUnit pageHeight)
235 {
236     if (!relayoutChildren) {
237         // Since the extra relayout in RenderBlockFlow::updateRubyForJustifiedText() causes the size of the RenderRubyText/RenderRubyBase
238         // dependent on the line's current expansion, whenever we relayout the RenderRubyRun, we need to relayout the RenderRubyBase/RenderRubyText as well.
239         // FIXME: We should take the expansion opportunities into account if possible.
240         relayoutChildren = style().textAlign() == JUSTIFY;
241     }
242
243     RenderBlockFlow::layoutBlock(relayoutChildren, pageHeight);
244
245     RenderRubyText* rt = rubyText();
246     if (!rt)
247         return;
248
249     rt->setLogicalLeft(0);
250
251     // Place the RenderRubyText such that its bottom is flush with the lineTop of the first line of the RenderRubyBase.
252     LayoutUnit lastLineRubyTextBottom = rt->logicalHeight();
253     LayoutUnit firstLineRubyTextTop = 0;
254     RootInlineBox* rootBox = rt->lastRootBox();
255     if (rootBox) {
256         // In order to align, we have to ignore negative leading.
257         firstLineRubyTextTop = rt->firstRootBox()->logicalTopLayoutOverflow();
258         lastLineRubyTextBottom = rootBox->logicalBottomLayoutOverflow();
259     }
260     
261     if (isHorizontalWritingMode() && rt->style().rubyPosition() == RubyPositionInterCharacter) {
262         // Bopomofo. We need to move the RenderRubyText over to the right side and center it
263         // vertically relative to the base.
264         const FontCascade& font = style().fontCascade();
265         float distanceBetweenBase = max(font.letterSpacing(), 2.0f * rt->style().fontCascade().fontMetrics().height());
266         setWidth(width() + distanceBetweenBase - font.letterSpacing());
267         if (RenderRubyBase* rb = rubyBase()) {
268             LayoutUnit firstLineTop = 0;
269             LayoutUnit lastLineBottom = logicalHeight();
270             RootInlineBox* rootBox = rb->firstRootBox();
271             if (rootBox)
272                 firstLineTop = rootBox->logicalTopLayoutOverflow();
273             firstLineTop += rb->logicalTop();
274             if (rootBox)
275                 lastLineBottom = rootBox->logicalBottomLayoutOverflow();
276             lastLineBottom += rb->logicalTop();
277             rt->setX(rb->x() + rb->width() - font.letterSpacing());
278             LayoutUnit extent = lastLineBottom - firstLineTop;
279             rt->setY(firstLineTop + (extent - rt->height()) / 2);
280         }
281     } else if (style().isFlippedLinesWritingMode() == (style().rubyPosition() == RubyPositionAfter)) {
282         LayoutUnit firstLineTop = 0;
283         if (RenderRubyBase* rb = rubyBase()) {
284             RootInlineBox* rootBox = rb->firstRootBox();
285             if (rootBox)
286                 firstLineTop = rootBox->logicalTopLayoutOverflow();
287             firstLineTop += rb->logicalTop();
288         }
289         
290         rt->setLogicalTop(-lastLineRubyTextBottom + firstLineTop);
291     } else {
292         LayoutUnit lastLineBottom = logicalHeight();
293         if (RenderRubyBase* rb = rubyBase()) {
294             RootInlineBox* rootBox = rb->lastRootBox();
295             if (rootBox)
296                 lastLineBottom = rootBox->logicalBottomLayoutOverflow();
297             lastLineBottom += rb->logicalTop();
298         }
299
300         rt->setLogicalTop(-firstLineRubyTextTop + lastLineBottom);
301     }
302
303     // Update our overflow to account for the new RenderRubyText position.
304     computeOverflow(clientLogicalBottom());
305 }
306
307 static bool shouldOverhang(bool firstLine, const RenderObject* renderer, const RenderRubyBase& rubyBase)
308 {
309     if (!renderer || !renderer->isText())
310         return false;
311     const RenderStyle& rubyBaseStyle = firstLine ? rubyBase.firstLineStyle() : rubyBase.style();
312     const RenderStyle& style = firstLine ? renderer->firstLineStyle() : renderer->style();
313     return style.computedFontPixelSize() <= rubyBaseStyle.computedFontPixelSize();
314 }
315
316 void RenderRubyRun::getOverhang(bool firstLine, RenderObject* startRenderer, RenderObject* endRenderer, float& startOverhang, float& endOverhang) const
317 {
318     ASSERT(!needsLayout());
319
320     startOverhang = 0;
321     endOverhang = 0;
322
323     RenderRubyBase* rubyBase = this->rubyBase();
324     RenderRubyText* rubyText = this->rubyText();
325
326     if (!rubyBase || !rubyText)
327         return;
328
329     if (!rubyBase->firstRootBox())
330         return;
331
332     LayoutUnit logicalWidth = this->logicalWidth();
333     float logicalLeftOverhang = std::numeric_limits<float>::max();
334     float logicalRightOverhang = std::numeric_limits<float>::max();
335     for (RootInlineBox* rootInlineBox = rubyBase->firstRootBox(); rootInlineBox; rootInlineBox = rootInlineBox->nextRootBox()) {
336         logicalLeftOverhang = std::min<float>(logicalLeftOverhang, rootInlineBox->logicalLeft());
337         logicalRightOverhang = std::min<float>(logicalRightOverhang, logicalWidth - rootInlineBox->logicalRight());
338     }
339
340     startOverhang = style().isLeftToRightDirection() ? logicalLeftOverhang : logicalRightOverhang;
341     endOverhang = style().isLeftToRightDirection() ? logicalRightOverhang : logicalLeftOverhang;
342
343     if (!shouldOverhang(firstLine, startRenderer, *rubyBase))
344         startOverhang = 0;
345     if (!shouldOverhang(firstLine, endRenderer, *rubyBase))
346         endOverhang = 0;
347
348     // We overhang a ruby only if the neighboring render object is a text.
349     // We can overhang the ruby by no more than half the width of the neighboring text
350     // and no more than half the font size.
351     const RenderStyle& rubyTextStyle = firstLine ? rubyText->firstLineStyle() : rubyText->style();
352     float halfWidthOfFontSize = rubyTextStyle.computedFontPixelSize() / 2.;
353     if (startOverhang)
354         startOverhang = std::min(startOverhang, std::min(downcast<RenderText>(*startRenderer).minLogicalWidth(), halfWidthOfFontSize));
355     if (endOverhang)
356         endOverhang = std::min(endOverhang, std::min(downcast<RenderText>(*endRenderer).minLogicalWidth(), halfWidthOfFontSize));
357 }
358
359 void RenderRubyRun::updatePriorContextFromCachedBreakIterator(LazyLineBreakIterator& iterator) const
360 {
361     iterator.setPriorContext(m_lastCharacter, m_secondToLastCharacter);
362 }
363
364 bool RenderRubyRun::canBreakBefore(const LazyLineBreakIterator& iterator) const
365 {
366     RenderRubyText* rubyText = this->rubyText();
367     if (!rubyText)
368         return true;
369     return rubyText->canBreakBefore(iterator);
370 }
371
372 } // namespace WebCore