initial import
[vuplus_webkit] / 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 "HitTestResult.h"
24 #include "InlineFlowBox.h"
25 #include "PaintInfo.h"
26 #include "RenderArena.h"
27 #include "RenderBlock.h"
28 #include "RootInlineBox.h"
29
30 #ifndef NDEBUG
31 #include <stdio.h>
32 #endif
33
34 using namespace std;
35
36 namespace WebCore {
37     
38 #ifndef NDEBUG
39 static bool inInlineBoxDetach;
40 #endif
41
42 #ifndef NDEBUG
43
44 InlineBox::~InlineBox()
45 {
46     if (!m_hasBadParent && m_parent)
47         m_parent->setHasBadChildList();
48 }
49
50 #endif
51
52 void InlineBox::remove()
53
54     if (parent())
55         parent()->removeChild(this);
56 }
57
58 void InlineBox::destroy(RenderArena* renderArena)
59 {
60 #ifndef NDEBUG
61     inInlineBoxDetach = true;
62 #endif
63     delete this;
64 #ifndef NDEBUG
65     inInlineBoxDetach = false;
66 #endif
67
68     // Recover the size left there for us by operator delete and free the memory.
69     renderArena->free(*(size_t *)this, this);
70 }
71
72 void* InlineBox::operator new(size_t sz, RenderArena* renderArena) throw()
73 {
74     return renderArena->allocate(sz);
75 }
76
77 void InlineBox::operator delete(void* ptr, size_t sz)
78 {
79     ASSERT(inInlineBoxDetach);
80
81     // Stash size where destroy can find it.
82     *(size_t *)ptr = sz;
83 }
84
85 #ifndef NDEBUG
86 const char* InlineBox::boxName() const
87 {
88     return "InlineBox";
89 }
90
91 void InlineBox::showTreeForThis() const
92 {
93     if (m_renderer)
94         m_renderer->showTreeForThis();
95 }
96
97 void InlineBox::showLineTreeForThis() const
98 {
99     if (m_renderer)
100         m_renderer->containingBlock()->showLineTreeAndMark(this, "*");
101 }
102
103 void InlineBox::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj, int depth) const
104 {
105     int printedCharacters = 0;
106     if (this == markedBox1)
107         printedCharacters += fprintf(stderr, "%s", markedLabel1);
108     if (this == markedBox2)
109         printedCharacters += fprintf(stderr, "%s", markedLabel2);
110     if (renderer() == obj)
111         printedCharacters += fprintf(stderr, "*");
112     for (; printedCharacters < depth * 2; printedCharacters++)
113         fputc(' ', stderr);
114
115     showBox(printedCharacters);
116 }
117
118 void InlineBox::showBox(int printedCharacters) const
119 {
120     printedCharacters += fprintf(stderr, "%s\t%p", boxName(), this);
121     for (; printedCharacters < showTreeCharacterOffset; printedCharacters++)
122         fputc(' ', stderr);
123     fprintf(stderr, "\t%s %p\n", renderer() ? renderer()->renderName() : "No Renderer", renderer());
124 }
125 #endif
126
127 LayoutUnit InlineBox::logicalHeight() const
128 {
129 #if ENABLE(SVG)
130     if (hasVirtualLogicalHeight())
131         return virtualLogicalHeight();
132 #endif
133     
134     if (renderer()->isText())
135         return m_isText ? renderer()->style(m_firstLine)->fontMetrics().height() : 0;
136     if (renderer()->isBox() && parent())
137         return isHorizontal() ? toRenderBox(m_renderer)->height() : toRenderBox(m_renderer)->width();
138
139     ASSERT(isInlineFlowBox());
140     RenderBoxModelObject* flowObject = boxModelObject();
141     const FontMetrics& fontMetrics = renderer()->style(m_firstLine)->fontMetrics();
142     LayoutUnit result = fontMetrics.height();
143     if (parent())
144         result += flowObject->borderAndPaddingLogicalHeight();
145     return result;
146 }
147
148 int InlineBox::caretMinOffset() const 
149
150     return m_renderer->caretMinOffset(); 
151 }
152
153 int InlineBox::caretMaxOffset() const 
154
155     return m_renderer->caretMaxOffset(); 
156 }
157
158 unsigned InlineBox::caretMaxRenderedOffset() const 
159
160     return 1; 
161 }
162
163 void InlineBox::dirtyLineBoxes()
164 {
165     markDirty();
166     for (InlineFlowBox* curr = parent(); curr && !curr->isDirty(); curr = curr->parent())
167         curr->markDirty();
168 }
169
170 void InlineBox::deleteLine(RenderArena* arena)
171 {
172     if (!m_extracted && m_renderer->isBox())
173         toRenderBox(m_renderer)->setInlineBoxWrapper(0);
174     destroy(arena);
175 }
176
177 void InlineBox::extractLine()
178 {
179     m_extracted = true;
180     if (m_renderer->isBox())
181         toRenderBox(m_renderer)->setInlineBoxWrapper(0);
182 }
183
184 void InlineBox::attachLine()
185 {
186     m_extracted = false;
187     if (m_renderer->isBox())
188         toRenderBox(m_renderer)->setInlineBoxWrapper(this);
189 }
190
191 void InlineBox::adjustPosition(float dx, float dy)
192 {
193     m_topLeft.move(dx, dy);
194
195     if (m_renderer->isReplaced()) 
196         toRenderBox(m_renderer)->move(dx, dy); 
197 }
198
199 void InlineBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/)
200 {
201     if (!paintInfo.shouldPaintWithinRoot(renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
202         return;
203
204     LayoutPoint childPoint = paintOffset;
205     if (parent()->renderer()->style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock().
206         childPoint = renderer()->containingBlock()->flipForWritingMode(toRenderBox(renderer()), childPoint, RenderBox::ParentToChildFlippingAdjustment);
207     
208     // Paint all phases of replaced elements atomically, as though the replaced element established its
209     // own stacking context.  (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
210     // specification.)
211     bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip;
212     PaintInfo info(paintInfo);
213     info.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
214     renderer()->paint(info, childPoint);
215     if (!preservePhase) {
216         info.phase = PaintPhaseChildBlockBackgrounds;
217         renderer()->paint(info, childPoint);
218         info.phase = PaintPhaseFloat;
219         renderer()->paint(info, childPoint);
220         info.phase = PaintPhaseForeground;
221         renderer()->paint(info, childPoint);
222         info.phase = PaintPhaseOutline;
223         renderer()->paint(info, childPoint);
224     }
225 }
226
227 bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/)
228 {
229     // Hit test all phases of replaced elements atomically, as though the replaced element established its
230     // own stacking context.  (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
231     // specification.)
232     return renderer()->hitTest(request, result, pointInContainer, accumulatedOffset);
233 }
234
235 const RootInlineBox* InlineBox::root() const
236
237     if (m_parent)
238         return m_parent->root(); 
239     ASSERT(isRootInlineBox());
240     return static_cast<const RootInlineBox*>(this);
241 }
242
243 RootInlineBox* InlineBox::root()
244
245     if (m_parent)
246         return m_parent->root(); 
247     ASSERT(isRootInlineBox());
248     return static_cast<RootInlineBox*>(this);
249 }
250
251 bool InlineBox::nextOnLineExists() const
252 {
253     if (!m_determinedIfNextOnLineExists) {
254         m_determinedIfNextOnLineExists = true;
255
256         if (!parent())
257             m_nextOnLineExists = false;
258         else if (nextOnLine())
259             m_nextOnLineExists = true;
260         else
261             m_nextOnLineExists = parent()->nextOnLineExists();
262     }
263     return m_nextOnLineExists;
264 }
265
266 bool InlineBox::prevOnLineExists() const
267 {
268     if (!m_determinedIfPrevOnLineExists) {
269         m_determinedIfPrevOnLineExists = true;
270         
271         if (!parent())
272             m_prevOnLineExists = false;
273         else if (prevOnLine())
274             m_prevOnLineExists = true;
275         else
276             m_prevOnLineExists = parent()->prevOnLineExists();
277     }
278     return m_prevOnLineExists;
279 }
280
281 InlineBox* InlineBox::nextLeafChild() const
282 {
283     InlineBox* leaf = 0;
284     for (InlineBox* box = nextOnLine(); box && !leaf; box = box->nextOnLine())
285         leaf = box->isLeaf() ? box : toInlineFlowBox(box)->firstLeafChild();
286     if (!leaf && parent())
287         leaf = parent()->nextLeafChild();
288     return leaf;
289 }
290     
291 InlineBox* InlineBox::prevLeafChild() const
292 {
293     InlineBox* leaf = 0;
294     for (InlineBox* box = prevOnLine(); box && !leaf; box = box->prevOnLine())
295         leaf = box->isLeaf() ? box : toInlineFlowBox(box)->lastLeafChild();
296     if (!leaf && parent())
297         leaf = parent()->prevLeafChild();
298     return leaf;
299 }
300     
301 RenderObject::SelectionState InlineBox::selectionState()
302 {
303     return renderer()->selectionState();
304 }
305
306 bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth)
307 {
308     // Non-replaced elements can always accommodate an ellipsis.
309     if (!m_renderer || !m_renderer->isReplaced())
310         return true;
311     
312     IntRect boxRect(left(), 0, m_logicalWidth, 10);
313     IntRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10);
314     return !(boxRect.intersects(ellipsisRect));
315 }
316
317 float InlineBox::placeEllipsisBox(bool, float, float, float, bool&)
318 {
319     // Use -1 to mean "we didn't set the position."
320     return -1;
321 }
322
323 void InlineBox::clearKnownToHaveNoOverflow()
324
325     m_knownToHaveNoOverflow = false;
326     if (parent() && parent()->knownToHaveNoOverflow())
327         parent()->clearKnownToHaveNoOverflow();
328 }
329
330 FloatPoint InlineBox::locationIncludingFlipping()
331 {
332     if (!renderer()->style()->isFlippedBlocksWritingMode())
333         return FloatPoint(x(), y());
334     RenderBlock* block = root()->block();
335     if (block->style()->isHorizontalWritingMode())
336         return FloatPoint(x(), block->height() - height() - y());
337     else
338         return FloatPoint(block->width() - width() - x(), y());
339 }
340
341 void InlineBox::flipForWritingMode(FloatRect& rect)
342 {
343     if (!renderer()->style()->isFlippedBlocksWritingMode())
344         return;
345     root()->block()->flipForWritingMode(rect);
346 }
347
348 FloatPoint InlineBox::flipForWritingMode(const FloatPoint& point)
349 {
350     if (!renderer()->style()->isFlippedBlocksWritingMode())
351         return point;
352     return root()->block()->flipForWritingMode(point);
353 }
354
355 void InlineBox::flipForWritingMode(IntRect& rect)
356 {
357     if (!renderer()->style()->isFlippedBlocksWritingMode())
358         return;
359     root()->block()->flipForWritingMode(rect);
360 }
361
362 IntPoint InlineBox::flipForWritingMode(const IntPoint& point)
363 {
364     if (!renderer()->style()->isFlippedBlocksWritingMode())
365         return point;
366     return root()->block()->flipForWritingMode(point);
367 }
368
369 } // namespace WebCore
370
371 #ifndef NDEBUG
372
373 void showTree(const WebCore::InlineBox* b)
374 {
375     if (b)
376         b->showTreeForThis();
377 }
378
379 void showLineTree(const WebCore::InlineBox* b)
380 {
381     if (b)
382         b->showLineTreeForThis();
383 }
384
385 #endif