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