2 * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
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.
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.
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.
21 #include "InlineBox.h"
24 #include "HitTestResult.h"
25 #include "InlineFlowBox.h"
27 #include "PaintInfo.h"
28 #include "RenderArena.h"
29 #include "RenderBlock.h"
30 #include "RootInlineBox.h"
40 struct SameSizeAsInlineBox {
41 virtual ~SameSizeAsInlineBox() { }
51 COMPILE_ASSERT(sizeof(InlineBox) == sizeof(SameSizeAsInlineBox), InlineBox_size_guard);
54 static bool inInlineBoxDetach;
59 InlineBox::~InlineBox()
61 if (!m_hasBadParent && m_parent)
62 m_parent->setHasBadChildList();
67 void InlineBox::remove()
70 parent()->removeChild(this);
73 void InlineBox::destroy(RenderArena* renderArena)
76 inInlineBoxDetach = true;
80 inInlineBoxDetach = false;
83 // Recover the size left there for us by operator delete and free the memory.
84 renderArena->free(*(size_t *)this, this);
87 void* InlineBox::operator new(size_t sz, RenderArena* renderArena)
89 return renderArena->allocate(sz);
92 void InlineBox::operator delete(void* ptr, size_t sz)
94 ASSERT(inInlineBoxDetach);
96 // Stash size where destroy can find it.
101 const char* InlineBox::boxName() const
106 void InlineBox::showTreeForThis() const
109 m_renderer->showTreeForThis();
112 void InlineBox::showLineTreeForThis() const
115 m_renderer->containingBlock()->showLineTreeAndMark(this, "*");
118 void InlineBox::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj, int depth) const
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++)
130 showBox(printedCharacters);
133 void InlineBox::showBox(int printedCharacters) const
135 printedCharacters += fprintf(stderr, "%s\t%p", boxName(), this);
136 for (; printedCharacters < showTreeCharacterOffset; printedCharacters++)
138 fprintf(stderr, "\t%s %p\n", renderer() ? renderer()->renderName() : "No Renderer", renderer());
142 float InlineBox::logicalHeight() const
144 if (hasVirtualLogicalHeight())
145 return virtualLogicalHeight();
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();
152 ASSERT(isInlineFlowBox());
153 RenderBoxModelObject* flowObject = boxModelObject();
154 const FontMetrics& fontMetrics = renderer()->style(isFirstLineStyle())->fontMetrics();
155 float result = fontMetrics.height();
157 result += flowObject->borderAndPaddingLogicalHeight();
161 LayoutUnit InlineBox::baselinePosition(FontBaseline baselineType) const
163 return boxModelObject()->baselinePosition(baselineType, m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
166 LayoutUnit InlineBox::lineHeight() const
168 return boxModelObject()->lineHeight(m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
171 int InlineBox::caretMinOffset() const
173 return m_renderer->caretMinOffset();
176 int InlineBox::caretMaxOffset() const
178 return m_renderer->caretMaxOffset();
181 void InlineBox::dirtyLineBoxes()
184 for (InlineFlowBox* curr = parent(); curr && !curr->isDirty(); curr = curr->parent())
188 void InlineBox::deleteLine(RenderArena* arena)
190 if (!m_bitfields.extracted() && m_renderer->isBox())
191 toRenderBox(m_renderer)->setInlineBoxWrapper(0);
195 void InlineBox::extractLine()
197 m_bitfields.setExtracted(true);
198 if (m_renderer->isBox())
199 toRenderBox(m_renderer)->setInlineBoxWrapper(0);
202 void InlineBox::attachLine()
204 m_bitfields.setExtracted(false);
205 if (m_renderer->isBox())
206 toRenderBox(m_renderer)->setInlineBoxWrapper(this);
209 void InlineBox::adjustPosition(float dx, float dy)
211 m_topLeft.move(dx, dy);
213 if (m_renderer->isReplaced())
214 toRenderBox(m_renderer)->move(dx, dy);
217 void InlineBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/)
219 if (!paintInfo.shouldPaintWithinRoot(renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
222 LayoutPoint childPoint = paintOffset;
223 if (parent()->renderer()->style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock().
224 childPoint = renderer()->containingBlock()->flipForWritingModeForChild(toRenderBox(renderer()), childPoint);
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
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);
245 bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/)
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
250 return renderer()->hitTest(request, result, pointInContainer, accumulatedOffset);
253 const RootInlineBox* InlineBox::root() const
256 return m_parent->root();
257 ASSERT(isRootInlineBox());
258 return static_cast<const RootInlineBox*>(this);
261 RootInlineBox* InlineBox::root()
264 return m_parent->root();
265 ASSERT(isRootInlineBox());
266 return static_cast<RootInlineBox*>(this);
269 bool InlineBox::nextOnLineExists() const
271 if (!m_bitfields.determinedIfNextOnLineExists()) {
272 m_bitfields.setDeterminedIfNextOnLineExists(true);
275 m_bitfields.setNextOnLineExists(false);
276 else if (nextOnLine())
277 m_bitfields.setNextOnLineExists(true);
279 m_bitfields.setNextOnLineExists(parent()->nextOnLineExists());
281 return m_bitfields.nextOnLineExists();
284 InlineBox* InlineBox::nextLeafChild() const
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();
294 InlineBox* InlineBox::prevLeafChild() const
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();
304 InlineBox* InlineBox::nextLeafChildIgnoringLineBreak() const
306 InlineBox* leaf = nextLeafChild();
307 if (leaf && leaf->isLineBreak())
312 InlineBox* InlineBox::prevLeafChildIgnoringLineBreak() const
314 InlineBox* leaf = prevLeafChild();
315 if (leaf && leaf->isLineBreak())
320 RenderObject::SelectionState InlineBox::selectionState()
322 return renderer()->selectionState();
325 bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const
327 // Non-replaced elements can always accommodate an ellipsis.
328 if (!m_renderer || !m_renderer->isReplaced())
331 IntRect boxRect(left(), 0, m_logicalWidth, 10);
332 IntRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10);
333 return !(boxRect.intersects(ellipsisRect));
336 float InlineBox::placeEllipsisBox(bool, float, float, float, float& truncatedWidth, bool&)
338 // Use -1 to mean "we didn't set the position."
339 truncatedWidth += logicalWidth();
343 void InlineBox::clearKnownToHaveNoOverflow()
345 m_bitfields.setKnownToHaveNoOverflow(false);
346 if (parent() && parent()->knownToHaveNoOverflow())
347 parent()->clearKnownToHaveNoOverflow();
350 FloatPoint InlineBox::locationIncludingFlipping()
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());
358 return FloatPoint(block->width() - width() - x(), y());
361 void InlineBox::flipForWritingMode(FloatRect& rect)
363 if (!renderer()->style()->isFlippedBlocksWritingMode())
365 root()->block()->flipForWritingMode(rect);
368 FloatPoint InlineBox::flipForWritingMode(const FloatPoint& point)
370 if (!renderer()->style()->isFlippedBlocksWritingMode())
372 return root()->block()->flipForWritingMode(point);
375 void InlineBox::flipForWritingMode(LayoutRect& rect)
377 if (!renderer()->style()->isFlippedBlocksWritingMode())
379 root()->block()->flipForWritingMode(rect);
382 LayoutPoint InlineBox::flipForWritingMode(const LayoutPoint& point)
384 if (!renderer()->style()->isFlippedBlocksWritingMode())
386 return root()->block()->flipForWritingMode(point);
389 } // namespace WebCore
393 void showTree(const WebCore::InlineBox* b)
396 b->showTreeForThis();
399 void showLineTree(const WebCore::InlineBox* b)
402 b->showLineTreeForThis();