Improve "bad parent" and "bad child list" assertions in line boxes
[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 "Page.h"
28 #include "PaintInfo.h"
29 #include "RenderBlockFlow.h"
30 #include "RenderLineBreak.h"
31 #include "RootInlineBox.h"
32
33 #ifndef NDEBUG
34 #include <stdio.h>
35 #endif
36
37 namespace WebCore {
38
39 struct SameSizeAsInlineBox {
40     virtual ~SameSizeAsInlineBox() { }
41     void* a[4];
42     FloatPoint b;
43     float c;
44     uint32_t d : 32;
45 #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
46     unsigned s;
47     bool f;
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)
76         m_parent->setHasBadChildList();
77 }
78
79 #endif
80
81 void InlineBox::removeFromParent()
82
83     if (parent())
84         parent()->removeChild(this);
85 }
86
87 #ifndef NDEBUG
88
89 const char* InlineBox::boxName() const
90 {
91     return "InlineBox";
92 }
93
94 void InlineBox::showTreeForThis() const
95 {
96     m_renderer.showTreeForThis();
97 }
98
99 void InlineBox::showLineTreeForThis() const
100 {
101     m_renderer.containingBlock()->showLineTreeAndMark(this, "*");
102 }
103
104 void InlineBox::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj, int depth) const
105 {
106     int printedCharacters = 0;
107     if (this == markedBox1)
108         printedCharacters += fprintf(stderr, "%s", markedLabel1);
109     if (this == markedBox2)
110         printedCharacters += fprintf(stderr, "%s", markedLabel2);
111     if (&m_renderer == obj)
112         printedCharacters += fprintf(stderr, "*");
113     for (; printedCharacters < depth * 2; printedCharacters++)
114         fputc(' ', stderr);
115
116     showBox(printedCharacters);
117 }
118
119 void InlineBox::showBox(int printedCharacters) const
120 {
121     printedCharacters += fprintf(stderr, "%s\t%p", boxName(), this);
122     for (; printedCharacters < showTreeCharacterOffset; printedCharacters++)
123         fputc(' ', stderr);
124     fprintf(stderr, "\t%s %p\n", renderer().renderName(), &renderer());
125 }
126
127 #endif
128
129 float InlineBox::logicalHeight() const
130 {
131     if (hasVirtualLogicalHeight())
132         return virtualLogicalHeight();
133
134     const RenderStyle& lineStyle = this->lineStyle();
135     if (renderer().isTextOrLineBreak())
136         return behavesLikeText() ? lineStyle.fontMetrics().height() : 0;
137     if (renderer().isBox() && parent())
138         return isHorizontal() ? toRenderBox(renderer()).height() : toRenderBox(renderer()).width();
139
140     ASSERT(isInlineFlowBox());
141     RenderBoxModelObject* flowObject = boxModelObject();
142     const FontMetrics& fontMetrics = lineStyle.fontMetrics();
143     float result = fontMetrics.height();
144     if (parent())
145         result += flowObject->borderAndPaddingLogicalHeight();
146     return result;
147 }
148
149 int InlineBox::baselinePosition(FontBaseline baselineType) const
150 {
151     if (renderer().isLineBreak() && !behavesLikeText())
152         return 0;
153     return boxModelObject()->baselinePosition(baselineType, m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
154 }
155
156 LayoutUnit InlineBox::lineHeight() const
157 {
158     if (renderer().isLineBreak() && !behavesLikeText())
159         return 0;
160     return boxModelObject()->lineHeight(m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
161 }
162
163 int InlineBox::caretMinOffset() const 
164
165     return m_renderer.caretMinOffset();
166 }
167
168 int InlineBox::caretMaxOffset() const 
169
170     return m_renderer.caretMaxOffset();
171 }
172
173 void InlineBox::dirtyLineBoxes()
174 {
175     markDirty();
176     for (InlineFlowBox* curr = parent(); curr && !curr->isDirty(); curr = curr->parent())
177         curr->markDirty();
178 }
179
180 void InlineBox::adjustPosition(float dx, float dy)
181 {
182     m_topLeft.move(dx, dy);
183
184     if (m_renderer.isReplaced())
185         toRenderBox(renderer()).move(dx, dy);
186 }
187
188 const RootInlineBox& InlineBox::root() const
189
190     if (parent())
191         return parent()->root();
192     ASSERT_WITH_SECURITY_IMPLICATION(isRootInlineBox());
193     return toRootInlineBox(*this);
194 }
195
196 RootInlineBox& InlineBox::root()
197
198     if (parent())
199         return parent()->root();
200     ASSERT_WITH_SECURITY_IMPLICATION(isRootInlineBox());
201     return toRootInlineBox(*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 (prevOnLine())
224         return true;
225     return parent()->previousOnLineExists();
226 }
227
228 InlineBox* InlineBox::nextLeafChild() const
229 {
230     InlineBox* leaf = 0;
231     for (InlineBox* box = nextOnLine(); box && !leaf; box = box->nextOnLine())
232         leaf = box->isLeaf() ? box : toInlineFlowBox(box)->firstLeafChild();
233     if (!leaf && parent())
234         leaf = parent()->nextLeafChild();
235     return leaf;
236 }
237     
238 InlineBox* InlineBox::prevLeafChild() const
239 {
240     InlineBox* leaf = 0;
241     for (InlineBox* box = prevOnLine(); box && !leaf; box = box->prevOnLine())
242         leaf = box->isLeaf() ? box : toInlineFlowBox(box)->lastLeafChild();
243     if (!leaf && parent())
244         leaf = parent()->prevLeafChild();
245     return leaf;
246 }
247
248 InlineBox* InlineBox::nextLeafChildIgnoringLineBreak() const
249 {
250     InlineBox* leaf = nextLeafChild();
251     if (leaf && leaf->isLineBreak())
252         return 0;
253     return leaf;
254 }
255
256 InlineBox* InlineBox::prevLeafChildIgnoringLineBreak() const
257 {
258     InlineBox* leaf = prevLeafChild();
259     if (leaf && leaf->isLineBreak())
260         return 0;
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()
295 {
296     if (!m_renderer.style().isFlippedBlocksWritingMode())
297         return FloatPoint(x(), y());
298     RenderBlockFlow& block = root().blockFlow();
299     if (block.style().isHorizontalWritingMode())
300         return FloatPoint(x(), block.height() - height() - y());
301     else
302         return FloatPoint(block.width() - width() - x(), y());
303 }
304
305 void InlineBox::flipForWritingMode(FloatRect& rect)
306 {
307     if (!m_renderer.style().isFlippedBlocksWritingMode())
308         return;
309     root().blockFlow().flipForWritingMode(rect);
310 }
311
312 FloatPoint InlineBox::flipForWritingMode(const FloatPoint& point)
313 {
314     if (!m_renderer.style().isFlippedBlocksWritingMode())
315         return point;
316     return root().blockFlow().flipForWritingMode(point);
317 }
318
319 void InlineBox::flipForWritingMode(LayoutRect& rect)
320 {
321     if (!m_renderer.style().isFlippedBlocksWritingMode())
322         return;
323     root().blockFlow().flipForWritingMode(rect);
324 }
325
326 LayoutPoint InlineBox::flipForWritingMode(const LayoutPoint& point)
327 {
328     if (!m_renderer.style().isFlippedBlocksWritingMode())
329         return point;
330     return root().blockFlow().flipForWritingMode(point);
331 }
332
333 } // namespace WebCore
334
335 #ifndef NDEBUG
336
337 void showTree(const WebCore::InlineBox* b)
338 {
339     if (b)
340         b->showTreeForThis();
341 }
342
343 void showLineTree(const WebCore::InlineBox* b)
344 {
345     if (b)
346         b->showLineTreeForThis();
347 }
348
349 #endif