Use "= default" to denote default constructor or destructor
[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/text/TextStream.h>
31
32 #if ENABLE(TREE_DEBUGGING)
33 #include <stdio.h>
34 #endif
35
36 namespace WebCore {
37
38 struct SameSizeAsInlineBox {
39     virtual ~SameSizeAsInlineBox() = default;
40     void* a[4];
41     FloatPoint b;
42     float c[2];
43     unsigned d : 23;
44 #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
45     unsigned s;
46     bool f;
47     bool i;
48 #endif
49 };
50
51 COMPILE_ASSERT(sizeof(InlineBox) == sizeof(SameSizeAsInlineBox), InlineBox_size_guard);
52
53 #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
54
55 void InlineBox::assertNotDeleted() const
56 {
57     ASSERT(m_deletionSentinel == deletionSentinelNotDeletedValue);
58 }
59
60 InlineBox::~InlineBox()
61 {
62     invalidateParentChildList();
63     m_deletionSentinel = deletionSentinelDeletedValue;
64 }
65
66 void InlineBox::setHasBadParent()
67 {
68     assertNotDeleted();
69     m_hasBadParent = true;
70 }
71
72 void InlineBox::invalidateParentChildList()
73 {
74     assertNotDeleted();
75     if (!m_hasBadParent && m_parent && m_isEverInChildList)
76         m_parent->setHasBadChildList();
77 }
78
79 #endif
80
81 void InlineBox::removeFromParent()
82
83     if (parent())
84         parent()->removeChild(this);
85 }
86
87 #if ENABLE(TREE_DEBUGGING)
88
89 const char* InlineBox::boxName() const
90 {
91     return "InlineBox";
92 }
93
94 void InlineBox::showNodeTreeForThis() const
95 {
96     m_renderer.showNodeTreeForThis();
97 }
98
99 void InlineBox::showLineTreeForThis() const
100 {
101     m_renderer.containingBlock()->showLineTreeForThis();
102 }
103
104 void InlineBox::outputLineTreeAndMark(TextStream& stream, const InlineBox* markedBox, int depth) const
105 {
106     outputLineBox(stream, markedBox == this, depth);
107 }
108
109 void InlineBox::outputLineBox(TextStream& stream, bool mark, int depth) const
110 {
111     stream << "-------- " << (isDirty() ? "D" : "-") << "-";
112     int printedCharacters = 0;
113     if (mark) {
114         stream << "*";
115         ++printedCharacters;
116     }
117     while (++printedCharacters <= depth * 2)
118         stream << " ";
119     stream << boxName() << " " << FloatRect(x(), y(), width(), height()) << " (" << this << ") renderer->(" << &renderer() << ")";
120     stream.nextLine();
121 }
122
123 #endif // ENABLE(TREE_DEBUGGING)
124
125 float InlineBox::logicalHeight() const
126 {
127     if (hasVirtualLogicalHeight())
128         return virtualLogicalHeight();
129
130     const RenderStyle& lineStyle = this->lineStyle();
131     if (renderer().isTextOrLineBreak())
132         return behavesLikeText() ? lineStyle.fontMetrics().height() : 0;
133     if (is<RenderBox>(renderer()) && parent())
134         return isHorizontal() ? downcast<RenderBox>(renderer()).height() : downcast<RenderBox>(renderer()).width();
135
136     ASSERT(isInlineFlowBox());
137     RenderBoxModelObject* flowObject = boxModelObject();
138     const FontMetrics& fontMetrics = lineStyle.fontMetrics();
139     float result = fontMetrics.height();
140     if (parent())
141         result += flowObject->borderAndPaddingLogicalHeight();
142     return result;
143 }
144
145 int InlineBox::baselinePosition(FontBaseline baselineType) const
146 {
147     if (renderer().isLineBreak() && !behavesLikeText())
148         return 0;
149     return boxModelObject()->baselinePosition(baselineType, m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
150 }
151
152 LayoutUnit InlineBox::lineHeight() const
153 {
154     if (renderer().isLineBreak() && !behavesLikeText())
155         return 0;
156     return boxModelObject()->lineHeight(m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
157 }
158
159 int InlineBox::caretMinOffset() const 
160
161     return m_renderer.caretMinOffset();
162 }
163
164 int InlineBox::caretMaxOffset() const 
165
166     return m_renderer.caretMaxOffset();
167 }
168
169 void InlineBox::dirtyLineBoxes()
170 {
171     markDirty();
172     for (InlineFlowBox* curr = parent(); curr && !curr->isDirty(); curr = curr->parent())
173         curr->markDirty();
174 }
175
176 void InlineBox::adjustPosition(float dx, float dy)
177 {
178     m_topLeft.move(dx, dy);
179
180     if (m_renderer.isOutOfFlowPositioned())
181         return;
182
183     if (m_renderer.isReplaced())
184         downcast<RenderBox>(renderer()).move(dx, dy);
185 }
186
187 const RootInlineBox& InlineBox::root() const
188
189     if (parent())
190         return parent()->root();
191     return downcast<RootInlineBox>(*this);
192 }
193
194 RootInlineBox& InlineBox::root()
195
196     if (parent())
197         return parent()->root();
198     return downcast<RootInlineBox>(*this);
199 }
200
201 bool InlineBox::nextOnLineExists() const
202 {
203     if (!m_bitfields.determinedIfNextOnLineExists()) {
204         m_bitfields.setDeterminedIfNextOnLineExists(true);
205
206         if (!parent())
207             m_bitfields.setNextOnLineExists(false);
208         else if (nextOnLine())
209             m_bitfields.setNextOnLineExists(true);
210         else
211             m_bitfields.setNextOnLineExists(parent()->nextOnLineExists());
212     }
213     return m_bitfields.nextOnLineExists();
214 }
215
216 bool InlineBox::previousOnLineExists() const
217 {
218     if (!parent())
219         return false;
220     if (prevOnLine())
221         return true;
222     return parent()->previousOnLineExists();
223 }
224
225 InlineBox* InlineBox::nextLeafChild() const
226 {
227     InlineBox* leaf = nullptr;
228     for (InlineBox* box = nextOnLine(); box && !leaf; box = box->nextOnLine())
229         leaf = box->isLeaf() ? box : downcast<InlineFlowBox>(*box).firstLeafChild();
230     if (!leaf && parent())
231         leaf = parent()->nextLeafChild();
232     return leaf;
233 }
234     
235 InlineBox* InlineBox::prevLeafChild() const
236 {
237     InlineBox* leaf = nullptr;
238     for (InlineBox* box = prevOnLine(); box && !leaf; box = box->prevOnLine())
239         leaf = box->isLeaf() ? box : downcast<InlineFlowBox>(*box).lastLeafChild();
240     if (!leaf && parent())
241         leaf = parent()->prevLeafChild();
242     return leaf;
243 }
244
245 InlineBox* InlineBox::nextLeafChildIgnoringLineBreak() const
246 {
247     InlineBox* leaf = nextLeafChild();
248     if (leaf && leaf->isLineBreak())
249         return nullptr;
250     return leaf;
251 }
252
253 InlineBox* InlineBox::prevLeafChildIgnoringLineBreak() const
254 {
255     InlineBox* leaf = prevLeafChild();
256     if (leaf && leaf->isLineBreak())
257         return nullptr;
258     return leaf;
259 }
260
261 RenderObject::SelectionState InlineBox::selectionState()
262 {
263     return m_renderer.selectionState();
264 }
265
266 bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const
267 {
268     // Non-replaced elements can always accommodate an ellipsis.
269     if (!m_renderer.isReplaced())
270         return true;
271     
272     IntRect boxRect(left(), 0, m_logicalWidth, 10);
273     IntRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10);
274     return !(boxRect.intersects(ellipsisRect));
275 }
276
277 float InlineBox::placeEllipsisBox(bool, float, float, float, float& truncatedWidth, bool&)
278 {
279     // Use -1 to mean "we didn't set the position."
280     truncatedWidth += logicalWidth();
281     return -1;
282 }
283
284 void InlineBox::clearKnownToHaveNoOverflow()
285
286     m_bitfields.setKnownToHaveNoOverflow(false);
287     if (parent() && parent()->knownToHaveNoOverflow())
288         parent()->clearKnownToHaveNoOverflow();
289 }
290
291 FloatPoint InlineBox::locationIncludingFlipping() const
292 {
293     if (!m_renderer.style().isFlippedBlocksWritingMode())
294         return topLeft();
295     RenderBlockFlow& block = root().blockFlow();
296     if (block.style().isHorizontalWritingMode())
297         return { x(), block.height() - height() - y() };
298     return { block.width() - width() - x(), y() };
299 }
300
301 void InlineBox::flipForWritingMode(FloatRect& rect) const
302 {
303     if (!m_renderer.style().isFlippedBlocksWritingMode())
304         return;
305     root().blockFlow().flipForWritingMode(rect);
306 }
307
308 FloatPoint InlineBox::flipForWritingMode(const FloatPoint& point) const
309 {
310     if (!m_renderer.style().isFlippedBlocksWritingMode())
311         return point;
312     return root().blockFlow().flipForWritingMode(point);
313 }
314
315 void InlineBox::flipForWritingMode(LayoutRect& rect) const
316 {
317     if (!m_renderer.style().isFlippedBlocksWritingMode())
318         return;
319     root().blockFlow().flipForWritingMode(rect);
320 }
321
322 LayoutPoint InlineBox::flipForWritingMode(const LayoutPoint& point) const
323 {
324     if (!m_renderer.style().isFlippedBlocksWritingMode())
325         return point;
326     return root().blockFlow().flipForWritingMode(point);
327 }
328
329 } // namespace WebCore
330
331 #if ENABLE(TREE_DEBUGGING)
332
333 void showNodeTree(const WebCore::InlineBox* inlineBox)
334 {
335     if (!inlineBox)
336         return;
337     inlineBox->showNodeTreeForThis();
338 }
339
340 void showLineTree(const WebCore::InlineBox* inlineBox)
341 {
342     if (!inlineBox)
343         return;
344     inlineBox->showLineTreeForThis();
345 }
346
347 #endif