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