Rename InlineBox::nextLeafChild to nextLeafOnLine
[WebKit-https.git] / Source / WebCore / rendering / InlineBox.cpp
1 /*
2  * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include "config.h"
21 #include "InlineBox.h"
22
23 #include "FontMetrics.h"
24 #include "Frame.h"
25 #include "HitTestResult.h"
26 #include "InlineFlowBox.h"
27 #include "RenderBlockFlow.h"
28 #include "RenderLineBreak.h"
29 #include "RootInlineBox.h"
30 #include <wtf/IsoMallocInlines.h>
31 #include <wtf/text/TextStream.h>
32
33 #if ENABLE(TREE_DEBUGGING)
34 #include <stdio.h>
35 #endif
36
37 namespace WebCore {
38
39 WTF_MAKE_ISO_ALLOCATED_IMPL(InlineBox);
40
41 struct SameSizeAsInlineBox {
42     virtual ~SameSizeAsInlineBox() = default;
43     void* a[4];
44     FloatPoint b;
45     float c[2];
46     unsigned d : 23;
47 #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
48     unsigned s;
49     bool f;
50     bool i;
51 #endif
52 };
53
54 COMPILE_ASSERT(sizeof(InlineBox) == sizeof(SameSizeAsInlineBox), InlineBox_size_guard);
55
56 #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
57
58 void InlineBox::assertNotDeleted() const
59 {
60     ASSERT(m_deletionSentinel == deletionSentinelNotDeletedValue);
61 }
62
63 InlineBox::~InlineBox()
64 {
65     invalidateParentChildList();
66     m_deletionSentinel = deletionSentinelDeletedValue;
67 }
68
69 void InlineBox::setHasBadParent()
70 {
71     assertNotDeleted();
72     m_hasBadParent = true;
73 }
74
75 void InlineBox::invalidateParentChildList()
76 {
77     assertNotDeleted();
78     if (!m_hasBadParent && m_parent && m_isEverInChildList)
79         m_parent->setHasBadChildList();
80 }
81
82 #endif
83
84 void InlineBox::removeFromParent()
85
86     if (parent())
87         parent()->removeChild(this);
88 }
89
90 #if ENABLE(TREE_DEBUGGING)
91
92 const char* InlineBox::boxName() const
93 {
94     return "InlineBox";
95 }
96
97 void InlineBox::showNodeTreeForThis() const
98 {
99     m_renderer.showNodeTreeForThis();
100 }
101
102 void InlineBox::showLineTreeForThis() const
103 {
104     m_renderer.containingBlock()->showLineTreeForThis();
105 }
106
107 void InlineBox::outputLineTreeAndMark(TextStream& stream, const InlineBox* markedBox, int depth) const
108 {
109     outputLineBox(stream, markedBox == this, depth);
110 }
111
112 void InlineBox::outputLineBox(TextStream& stream, bool mark, int depth) const
113 {
114     stream << "-------- " << (isDirty() ? "D" : "-") << "-";
115     int printedCharacters = 0;
116     if (mark) {
117         stream << "*";
118         ++printedCharacters;
119     }
120     while (++printedCharacters <= depth * 2)
121         stream << " ";
122     stream << boxName() << " " << FloatRect(x(), y(), width(), height()) << " (" << this << ") renderer->(" << &renderer() << ")";
123     stream.nextLine();
124 }
125
126 #endif // ENABLE(TREE_DEBUGGING)
127
128 float InlineBox::logicalHeight() const
129 {
130     if (hasVirtualLogicalHeight())
131         return virtualLogicalHeight();
132
133     const RenderStyle& lineStyle = this->lineStyle();
134     if (renderer().isTextOrLineBreak())
135         return behavesLikeText() ? lineStyle.fontMetrics().height() : 0;
136     if (is<RenderBox>(renderer()) && parent())
137         return isHorizontal() ? downcast<RenderBox>(renderer()).height() : downcast<RenderBox>(renderer()).width();
138
139     ASSERT(isInlineFlowBox());
140     RenderBoxModelObject* flowObject = boxModelObject();
141     const FontMetrics& fontMetrics = lineStyle.fontMetrics();
142     float result = fontMetrics.height();
143     if (parent())
144         result += flowObject->borderAndPaddingLogicalHeight();
145     return result;
146 }
147
148 int InlineBox::baselinePosition(FontBaseline baselineType) const
149 {
150     if (renderer().isLineBreak() && !behavesLikeText())
151         return 0;
152     return boxModelObject()->baselinePosition(baselineType, m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
153 }
154
155 LayoutUnit InlineBox::lineHeight() const
156 {
157     if (renderer().isLineBreak() && !behavesLikeText())
158         return 0;
159     return boxModelObject()->lineHeight(m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
160 }
161
162 int InlineBox::caretMinOffset() const 
163
164     return m_renderer.caretMinOffset();
165 }
166
167 int InlineBox::caretMaxOffset() const 
168
169     return m_renderer.caretMaxOffset();
170 }
171
172 void InlineBox::dirtyLineBoxes()
173 {
174     markDirty();
175     for (InlineFlowBox* curr = parent(); curr && !curr->isDirty(); curr = curr->parent())
176         curr->markDirty();
177 }
178
179 void InlineBox::adjustPosition(float dx, float dy)
180 {
181     m_topLeft.move(dx, dy);
182
183     if (m_renderer.isOutOfFlowPositioned())
184         return;
185
186     if (m_renderer.isReplaced())
187         downcast<RenderBox>(renderer()).move(LayoutUnit(dx), LayoutUnit(dy));
188 }
189
190 const RootInlineBox& InlineBox::root() const
191
192     if (parent())
193         return parent()->root();
194     return downcast<RootInlineBox>(*this);
195 }
196
197 RootInlineBox& InlineBox::root()
198
199     if (parent())
200         return parent()->root();
201     return downcast<RootInlineBox>(*this);
202 }
203
204 bool InlineBox::nextOnLineExists() const
205 {
206     if (!m_bitfields.determinedIfNextOnLineExists()) {
207         m_bitfields.setDeterminedIfNextOnLineExists(true);
208
209         if (!parent())
210             m_bitfields.setNextOnLineExists(false);
211         else if (nextOnLine())
212             m_bitfields.setNextOnLineExists(true);
213         else
214             m_bitfields.setNextOnLineExists(parent()->nextOnLineExists());
215     }
216     return m_bitfields.nextOnLineExists();
217 }
218
219 bool InlineBox::previousOnLineExists() const
220 {
221     if (!parent())
222         return false;
223     if (previousOnLine())
224         return true;
225     return parent()->previousOnLineExists();
226 }
227
228 InlineBox* InlineBox::nextLeafOnLine() const
229 {
230     InlineBox* leaf = nullptr;
231     for (InlineBox* box = nextOnLine(); box && !leaf; box = box->nextOnLine())
232         leaf = box->isLeaf() ? box : downcast<InlineFlowBox>(*box).firstLeafDescendant();
233     if (!leaf && parent())
234         leaf = parent()->nextLeafOnLine();
235     return leaf;
236 }
237     
238 InlineBox* InlineBox::previousLeafOnLine() const
239 {
240     InlineBox* leaf = nullptr;
241     for (InlineBox* box = previousOnLine(); box && !leaf; box = box->previousOnLine())
242         leaf = box->isLeaf() ? box : downcast<InlineFlowBox>(*box).lastLeafDescendant();
243     if (!leaf && parent())
244         leaf = parent()->previousLeafOnLine();
245     return leaf;
246 }
247
248 InlineBox* InlineBox::nextLeafOnLineIgnoringLineBreak() const
249 {
250     InlineBox* leaf = nextLeafOnLine();
251     if (leaf && leaf->isLineBreak())
252         return nullptr;
253     return leaf;
254 }
255
256 InlineBox* InlineBox::previousLeafOnLineIgnoringLineBreak() const
257 {
258     InlineBox* leaf = previousLeafOnLine();
259     if (leaf && leaf->isLineBreak())
260         return nullptr;
261     return leaf;
262 }
263
264 RenderObject::SelectionState InlineBox::selectionState()
265 {
266     return m_renderer.selectionState();
267 }
268
269 bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const
270 {
271     // Non-replaced elements can always accommodate an ellipsis.
272     if (!m_renderer.isReplaced())
273         return true;
274     
275     IntRect boxRect(left(), 0, m_logicalWidth, 10);
276     IntRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10);
277     return !(boxRect.intersects(ellipsisRect));
278 }
279
280 float InlineBox::placeEllipsisBox(bool, float, float, float, float& truncatedWidth, bool&)
281 {
282     // Use -1 to mean "we didn't set the position."
283     truncatedWidth += logicalWidth();
284     return -1;
285 }
286
287 void InlineBox::clearKnownToHaveNoOverflow()
288
289     m_bitfields.setKnownToHaveNoOverflow(false);
290     if (parent() && parent()->knownToHaveNoOverflow())
291         parent()->clearKnownToHaveNoOverflow();
292 }
293
294 FloatPoint InlineBox::locationIncludingFlipping() const
295 {
296     if (!m_renderer.style().isFlippedBlocksWritingMode())
297         return topLeft();
298     RenderBlockFlow& block = root().blockFlow();
299     if (block.style().isHorizontalWritingMode())
300         return { x(), block.height() - height() - y() };
301     return { block.width() - width() - x(), y() };
302 }
303
304 void InlineBox::flipForWritingMode(FloatRect& rect) const
305 {
306     if (!m_renderer.style().isFlippedBlocksWritingMode())
307         return;
308     root().blockFlow().flipForWritingMode(rect);
309 }
310
311 FloatPoint InlineBox::flipForWritingMode(const FloatPoint& point) const
312 {
313     if (!m_renderer.style().isFlippedBlocksWritingMode())
314         return point;
315     return root().blockFlow().flipForWritingMode(point);
316 }
317
318 void InlineBox::flipForWritingMode(LayoutRect& rect) const
319 {
320     if (!m_renderer.style().isFlippedBlocksWritingMode())
321         return;
322     root().blockFlow().flipForWritingMode(rect);
323 }
324
325 LayoutPoint InlineBox::flipForWritingMode(const LayoutPoint& point) const
326 {
327     if (!m_renderer.style().isFlippedBlocksWritingMode())
328         return point;
329     return root().blockFlow().flipForWritingMode(point);
330 }
331
332 } // namespace WebCore
333
334 #if ENABLE(TREE_DEBUGGING)
335
336 void showNodeTree(const WebCore::InlineBox* inlineBox)
337 {
338     if (!inlineBox)
339         return;
340     inlineBox->showNodeTreeForThis();
341 }
342
343 void showLineTree(const WebCore::InlineBox* inlineBox)
344 {
345     if (!inlineBox)
346         return;
347     inlineBox->showLineTreeForThis();
348 }
349
350 #endif