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"
23 #include "HitTestResult.h"
24 #include "InlineFlowBox.h"
25 #include "RenderArena.h"
26 #include "RenderBlock.h"
27 #include "RootInlineBox.h"
34 static bool inInlineBoxDetach;
39 InlineBox::~InlineBox()
41 if (!m_hasBadParent && m_parent)
42 m_parent->setHasBadChildList();
47 void InlineBox::remove()
50 parent()->removeChild(this);
53 void InlineBox::destroy(RenderArena* renderArena)
56 inInlineBoxDetach = true;
60 inInlineBoxDetach = false;
63 // Recover the size left there for us by operator delete and free the memory.
64 renderArena->free(*(size_t *)this, this);
67 void* InlineBox::operator new(size_t sz, RenderArena* renderArena) throw()
69 return renderArena->allocate(sz);
72 void InlineBox::operator delete(void* ptr, size_t sz)
74 ASSERT(inInlineBoxDetach);
76 // Stash size where destroy can find it.
81 void InlineBox::showTreeForThis() const
84 m_renderer->showTreeForThis();
88 int InlineBox::logicalHeight() const
91 if (hasVirtualLogicalHeight())
92 return virtualLogicalHeight();
95 if (renderer()->isText())
96 return m_isText ? renderer()->style(m_firstLine)->font().height() : 0;
97 if (renderer()->isBox() && parent())
98 return isHorizontal() ? toRenderBox(m_renderer)->height() : toRenderBox(m_renderer)->width();
100 ASSERT(isInlineFlowBox());
101 RenderBoxModelObject* flowObject = boxModelObject();
102 const Font& font = renderer()->style(m_firstLine)->font();
103 int result = font.height();
105 result += flowObject->borderAndPaddingLogicalHeight();
109 int InlineBox::caretMinOffset() const
111 return m_renderer->caretMinOffset();
114 int InlineBox::caretMaxOffset() const
116 return m_renderer->caretMaxOffset();
119 unsigned InlineBox::caretMaxRenderedOffset() const
124 void InlineBox::dirtyLineBoxes()
127 for (InlineFlowBox* curr = parent(); curr && !curr->isDirty(); curr = curr->parent())
131 void InlineBox::deleteLine(RenderArena* arena)
133 if (!m_extracted && m_renderer->isBox())
134 toRenderBox(m_renderer)->setInlineBoxWrapper(0);
138 void InlineBox::extractLine()
141 if (m_renderer->isBox())
142 toRenderBox(m_renderer)->setInlineBoxWrapper(0);
145 void InlineBox::attachLine()
148 if (m_renderer->isBox())
149 toRenderBox(m_renderer)->setInlineBoxWrapper(this);
152 void InlineBox::adjustPosition(int dx, int dy)
156 if (m_renderer->isReplaced()) {
157 RenderBox* box = toRenderBox(m_renderer);
162 void InlineBox::paint(PaintInfo& paintInfo, int tx, int ty)
164 if (!paintInfo.shouldPaintWithinRoot(renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
167 // Paint all phases of replaced elements atomically, as though the replaced element established its
168 // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
170 bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip;
171 PaintInfo info(paintInfo);
172 info.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
173 renderer()->paint(info, tx, ty);
174 if (!preservePhase) {
175 info.phase = PaintPhaseChildBlockBackgrounds;
176 renderer()->paint(info, tx, ty);
177 info.phase = PaintPhaseFloat;
178 renderer()->paint(info, tx, ty);
179 info.phase = PaintPhaseForeground;
180 renderer()->paint(info, tx, ty);
181 info.phase = PaintPhaseOutline;
182 renderer()->paint(info, tx, ty);
186 bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty)
188 // Hit test all phases of replaced elements atomically, as though the replaced element established its
189 // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
191 return renderer()->hitTest(request, result, IntPoint(x, y), tx, ty);
194 const RootInlineBox* InlineBox::root() const
197 return m_parent->root();
198 ASSERT(isRootInlineBox());
199 return static_cast<const RootInlineBox*>(this);
202 RootInlineBox* InlineBox::root()
205 return m_parent->root();
206 ASSERT(isRootInlineBox());
207 return static_cast<RootInlineBox*>(this);
210 bool InlineBox::nextOnLineExists() const
212 if (!m_determinedIfNextOnLineExists) {
213 m_determinedIfNextOnLineExists = true;
216 m_nextOnLineExists = false;
217 else if (nextOnLine())
218 m_nextOnLineExists = true;
220 m_nextOnLineExists = parent()->nextOnLineExists();
222 return m_nextOnLineExists;
225 bool InlineBox::prevOnLineExists() const
227 if (!m_determinedIfPrevOnLineExists) {
228 m_determinedIfPrevOnLineExists = true;
231 m_prevOnLineExists = false;
232 else if (prevOnLine())
233 m_prevOnLineExists = true;
235 m_prevOnLineExists = parent()->prevOnLineExists();
237 return m_prevOnLineExists;
240 InlineBox* InlineBox::nextLeafChild() const
243 for (InlineBox* box = nextOnLine(); box && !leaf; box = box->nextOnLine())
244 leaf = box->isLeaf() ? box : static_cast<InlineFlowBox*>(box)->firstLeafChild();
245 if (!leaf && parent())
246 leaf = parent()->nextLeafChild();
250 InlineBox* InlineBox::prevLeafChild() const
253 for (InlineBox* box = prevOnLine(); box && !leaf; box = box->prevOnLine())
254 leaf = box->isLeaf() ? box : static_cast<InlineFlowBox*>(box)->lastLeafChild();
255 if (!leaf && parent())
256 leaf = parent()->prevLeafChild();
260 RenderObject::SelectionState InlineBox::selectionState()
262 return renderer()->selectionState();
265 bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth)
267 // Non-replaced elements can always accommodate an ellipsis.
268 if (!m_renderer || !m_renderer->isReplaced())
271 IntRect boxRect(m_x, 0, m_logicalWidth, 10);
272 IntRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10);
273 return !(boxRect.intersects(ellipsisRect));
276 int InlineBox::placeEllipsisBox(bool, int, int, int, bool&)
278 // Use -1 to mean "we didn't set the position."
282 IntPoint InlineBox::locationIncludingFlipping()
284 if (!renderer()->style()->isFlippedBlocksWritingMode())
285 return IntPoint(x(), y());
286 RenderBlock* block = root()->block();
287 if (block->style()->isHorizontalWritingMode())
288 return IntPoint(x(), block->height() - height() - y());
290 return IntPoint(block->width() - width() - x(), y());
293 void InlineBox::flipForWritingMode(IntRect& rect)
295 if (!renderer()->style()->isFlippedBlocksWritingMode())
297 root()->block()->flipForWritingMode(rect);
300 IntPoint InlineBox::flipForWritingMode(const IntPoint& point)
302 if (!renderer()->style()->isFlippedBlocksWritingMode())
304 return root()->block()->flipForWritingMode(point);
307 } // namespace WebCore
311 void showTree(const WebCore::InlineBox* b)
314 b->showTreeForThis();