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