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 "core/rendering/InlineBox.h"
23 #include "core/rendering/InlineFlowBox.h"
24 #include "core/rendering/PaintInfo.h"
25 #include "core/rendering/RenderBlockFlow.h"
26 #include "core/rendering/RenderObjectInlines.h"
27 #include "core/rendering/RootInlineBox.h"
28 #include "platform/Partitions.h"
29 #include "platform/fonts/FontMetrics.h"
37 struct SameSizeAsInlineBox {
38 virtual ~SameSizeAsInlineBox() { }
48 COMPILE_ASSERT(sizeof(InlineBox) == sizeof(SameSizeAsInlineBox), InlineBox_size_guard);
52 InlineBox::~InlineBox()
54 if (!m_hasBadParent && m_parent)
55 m_parent->setHasBadChildList();
60 void InlineBox::remove(MarkLineBoxes markLineBoxes)
63 parent()->removeChild(this, markLineBoxes);
66 void* InlineBox::operator new(size_t sz)
68 return partitionAlloc(Partitions::getRenderingPartition(), sz);
71 void InlineBox::operator delete(void* ptr)
77 const char* InlineBox::boxName() const
82 void InlineBox::showTreeForThis() const
84 renderer().showTreeForThis();
87 void InlineBox::showLineTreeForThis() const
89 renderer().containingBlock()->showLineTreeAndMark(this, "*");
92 void InlineBox::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj, int depth) const
94 int printedCharacters = 0;
95 if (this == markedBox1)
96 printedCharacters += fprintf(stderr, "%s", markedLabel1);
97 if (this == markedBox2)
98 printedCharacters += fprintf(stderr, "%s", markedLabel2);
99 if (&renderer() == obj)
100 printedCharacters += fprintf(stderr, "*");
101 for (; printedCharacters < depth * 2; printedCharacters++)
104 showBox(printedCharacters);
107 void InlineBox::showBox(int printedCharacters) const
109 printedCharacters += fprintf(stderr, "%s\t%p", boxName(), this);
110 for (; printedCharacters < showTreeCharacterOffset; printedCharacters++)
112 fprintf(stderr, "\t%s %p {pos=%g,%g size=%g,%g} baseline=%i/%i\n",
113 renderer().renderName(), &renderer(), x(), y(), width(), height(),
114 baselinePosition(AlphabeticBaseline),
115 baselinePosition(IdeographicBaseline));
119 float InlineBox::logicalHeight() const
121 if (hasVirtualLogicalHeight())
122 return virtualLogicalHeight();
124 if (renderer().isText())
125 return m_bitfields.isText() ? renderer().style(isFirstLineStyle())->fontMetrics().height() : 0;
126 if (renderer().isBox() && parent())
127 return isHorizontal() ? toRenderBox(renderer()).height().toFloat() : toRenderBox(renderer()).width().toFloat();
129 ASSERT(isInlineFlowBox());
130 RenderBoxModelObject* flowObject = boxModelObject();
131 const FontMetrics& fontMetrics = renderer().style(isFirstLineStyle())->fontMetrics();
132 float result = fontMetrics.height();
134 result += flowObject->borderAndPaddingLogicalHeight();
138 int InlineBox::baselinePosition(FontBaseline baselineType) const
140 return boxModelObject()->baselinePosition(baselineType, m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
143 LayoutUnit InlineBox::lineHeight() const
145 return boxModelObject()->lineHeight(m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
148 int InlineBox::caretMinOffset() const
150 return renderer().caretMinOffset();
153 int InlineBox::caretMaxOffset() const
155 return renderer().caretMaxOffset();
158 void InlineBox::dirtyLineBoxes()
161 for (InlineFlowBox* curr = parent(); curr && !curr->isDirty(); curr = curr->parent())
165 void InlineBox::deleteLine()
167 if (!m_bitfields.extracted() && renderer().isBox())
168 toRenderBox(renderer()).setInlineBoxWrapper(0);
172 void InlineBox::extractLine()
174 m_bitfields.setExtracted(true);
175 if (renderer().isBox())
176 toRenderBox(renderer()).setInlineBoxWrapper(0);
179 void InlineBox::attachLine()
181 m_bitfields.setExtracted(false);
182 if (renderer().isBox())
183 toRenderBox(renderer()).setInlineBoxWrapper(this);
186 void InlineBox::adjustPosition(float dx, float dy)
188 m_topLeft.move(dx, dy);
190 if (renderer().isReplaced())
191 toRenderBox(renderer()).move(dx, dy);
194 void InlineBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/)
196 if (!paintInfo.shouldPaintWithinRoot(&renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
199 LayoutPoint childPoint = paintOffset;
200 if (parent()->renderer().style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock().
201 childPoint = renderer().containingBlock()->flipForWritingModeForChild(&toRenderBox(renderer()), childPoint);
203 RenderBlock::paintAsInlineBlock(&renderer(), paintInfo, childPoint);
206 bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/)
208 // Hit test 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
211 LayoutPoint childPoint = accumulatedOffset;
212 if (parent()->renderer().style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock().
213 childPoint = renderer().containingBlock()->flipForWritingModeForChild(&toRenderBox(renderer()), childPoint);
215 return renderer().hitTest(request, result, locationInContainer, childPoint);
218 const RootInlineBox& InlineBox::root() const
221 return m_parent->root();
222 ASSERT(isRootInlineBox());
223 return static_cast<const RootInlineBox&>(*this);
226 RootInlineBox& InlineBox::root()
229 return m_parent->root();
230 ASSERT(isRootInlineBox());
231 return static_cast<RootInlineBox&>(*this);
234 bool InlineBox::nextOnLineExists() const
236 if (!m_bitfields.determinedIfNextOnLineExists()) {
237 m_bitfields.setDeterminedIfNextOnLineExists(true);
240 m_bitfields.setNextOnLineExists(false);
241 else if (nextOnLine())
242 m_bitfields.setNextOnLineExists(true);
244 m_bitfields.setNextOnLineExists(parent()->nextOnLineExists());
246 return m_bitfields.nextOnLineExists();
249 InlineBox* InlineBox::nextLeafChild() const
252 for (InlineBox* box = nextOnLine(); box && !leaf; box = box->nextOnLine())
253 leaf = box->isLeaf() ? box : toInlineFlowBox(box)->firstLeafChild();
254 if (!leaf && parent())
255 leaf = parent()->nextLeafChild();
259 InlineBox* InlineBox::prevLeafChild() const
262 for (InlineBox* box = prevOnLine(); box && !leaf; box = box->prevOnLine())
263 leaf = box->isLeaf() ? box : toInlineFlowBox(box)->lastLeafChild();
264 if (!leaf && parent())
265 leaf = parent()->prevLeafChild();
269 InlineBox* InlineBox::nextLeafChildIgnoringLineBreak() const
271 InlineBox* leaf = nextLeafChild();
272 if (leaf && leaf->isLineBreak())
277 InlineBox* InlineBox::prevLeafChildIgnoringLineBreak() const
279 InlineBox* leaf = prevLeafChild();
280 if (leaf && leaf->isLineBreak())
285 RenderObject::SelectionState InlineBox::selectionState()
287 return renderer().selectionState();
290 bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const
292 // Non-replaced elements can always accommodate an ellipsis.
293 if (!renderer().isReplaced())
296 IntRect boxRect(left(), 0, m_logicalWidth, 10);
297 IntRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10);
298 return !(boxRect.intersects(ellipsisRect));
301 float InlineBox::placeEllipsisBox(bool, float, float, float, float& truncatedWidth, bool&)
303 // Use -1 to mean "we didn't set the position."
304 truncatedWidth += logicalWidth();
308 void InlineBox::clearKnownToHaveNoOverflow()
310 m_bitfields.setKnownToHaveNoOverflow(false);
311 if (parent() && parent()->knownToHaveNoOverflow())
312 parent()->clearKnownToHaveNoOverflow();
315 FloatPoint InlineBox::locationIncludingFlipping()
317 if (!renderer().style()->isFlippedBlocksWritingMode())
318 return FloatPoint(x(), y());
319 RenderBlockFlow& block = root().block();
320 if (block.style()->isHorizontalWritingMode())
321 return FloatPoint(x(), block.height() - height() - y());
323 return FloatPoint(block.width() - width() - x(), y());
326 void InlineBox::flipForWritingMode(FloatRect& rect)
328 if (!renderer().style()->isFlippedBlocksWritingMode())
330 root().block().flipForWritingMode(rect);
333 FloatPoint InlineBox::flipForWritingMode(const FloatPoint& point)
335 if (!renderer().style()->isFlippedBlocksWritingMode())
337 return root().block().flipForWritingMode(point);
340 void InlineBox::flipForWritingMode(LayoutRect& rect)
342 if (!renderer().style()->isFlippedBlocksWritingMode())
344 root().block().flipForWritingMode(rect);
347 LayoutPoint InlineBox::flipForWritingMode(const LayoutPoint& point)
349 if (!renderer().style()->isFlippedBlocksWritingMode())
351 return root().block().flipForWritingMode(point);
358 void showTree(const blink::InlineBox* b)
361 b->showTreeForThis();
364 void showLineTree(const blink::InlineBox* b)
367 b->showLineTreeForThis();