InlineBox.cpp revision 2bde8e466a4451c7319e3a072d118917957d6554
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(float dx, float dy) 154{ 155 m_x += dx; 156 m_y += dy; 157 158 if (m_renderer->isReplaced()) 159 toRenderBox(m_renderer)->move(dx, dy); 160} 161 162void InlineBox::paint(PaintInfo& paintInfo, int tx, int ty) 163{ 164 if (!paintInfo.shouldPaintWithinRoot(renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)) 165 return; 166 167 IntPoint childPoint = IntPoint(tx, ty); 168 if (parent()->renderer()->style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock(). 169 childPoint = renderer()->containingBlock()->flipForWritingMode(toRenderBox(renderer()), childPoint, RenderBox::ParentToChildFlippingAdjustment); 170 171 // Paint all phases of replaced elements atomically, as though the replaced element established its 172 // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1 173 // specification.) 174 bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip; 175 PaintInfo info(paintInfo); 176 info.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground; 177 renderer()->paint(info, childPoint.x(), childPoint.y()); 178 if (!preservePhase) { 179 info.phase = PaintPhaseChildBlockBackgrounds; 180 renderer()->paint(info, childPoint.x(), childPoint.y()); 181 info.phase = PaintPhaseFloat; 182 renderer()->paint(info, childPoint.x(), childPoint.y()); 183 info.phase = PaintPhaseForeground; 184 renderer()->paint(info, childPoint.x(), childPoint.y()); 185 info.phase = PaintPhaseOutline; 186 renderer()->paint(info, childPoint.x(), childPoint.y()); 187 } 188} 189 190bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty) 191{ 192 // Hit test all phases of replaced elements atomically, as though the replaced element established its 193 // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1 194 // specification.) 195 return renderer()->hitTest(request, result, IntPoint(x, y), tx, ty); 196} 197 198const RootInlineBox* InlineBox::root() const 199{ 200 if (m_parent) 201 return m_parent->root(); 202 ASSERT(isRootInlineBox()); 203 return static_cast<const RootInlineBox*>(this); 204} 205 206RootInlineBox* InlineBox::root() 207{ 208 if (m_parent) 209 return m_parent->root(); 210 ASSERT(isRootInlineBox()); 211 return static_cast<RootInlineBox*>(this); 212} 213 214bool InlineBox::nextOnLineExists() const 215{ 216 if (!m_determinedIfNextOnLineExists) { 217 m_determinedIfNextOnLineExists = true; 218 219 if (!parent()) 220 m_nextOnLineExists = false; 221 else if (nextOnLine()) 222 m_nextOnLineExists = true; 223 else 224 m_nextOnLineExists = parent()->nextOnLineExists(); 225 } 226 return m_nextOnLineExists; 227} 228 229bool InlineBox::prevOnLineExists() const 230{ 231 if (!m_determinedIfPrevOnLineExists) { 232 m_determinedIfPrevOnLineExists = true; 233 234 if (!parent()) 235 m_prevOnLineExists = false; 236 else if (prevOnLine()) 237 m_prevOnLineExists = true; 238 else 239 m_prevOnLineExists = parent()->prevOnLineExists(); 240 } 241 return m_prevOnLineExists; 242} 243 244InlineBox* InlineBox::nextLeafChild() const 245{ 246 InlineBox* leaf = 0; 247 for (InlineBox* box = nextOnLine(); box && !leaf; box = box->nextOnLine()) 248 leaf = box->isLeaf() ? box : static_cast<InlineFlowBox*>(box)->firstLeafChild(); 249 if (!leaf && parent()) 250 leaf = parent()->nextLeafChild(); 251 return leaf; 252} 253 254InlineBox* InlineBox::prevLeafChild() const 255{ 256 InlineBox* leaf = 0; 257 for (InlineBox* box = prevOnLine(); box && !leaf; box = box->prevOnLine()) 258 leaf = box->isLeaf() ? box : static_cast<InlineFlowBox*>(box)->lastLeafChild(); 259 if (!leaf && parent()) 260 leaf = parent()->prevLeafChild(); 261 return leaf; 262} 263 264RenderObject::SelectionState InlineBox::selectionState() 265{ 266 return renderer()->selectionState(); 267} 268 269bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) 270{ 271 // Non-replaced elements can always accommodate an ellipsis. 272 if (!m_renderer || !m_renderer->isReplaced()) 273 return true; 274 275 IntRect boxRect(m_x, 0, m_logicalWidth, 10); 276 IntRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10); 277 return !(boxRect.intersects(ellipsisRect)); 278} 279 280float InlineBox::placeEllipsisBox(bool, float, float, float, bool&) 281{ 282 // Use -1 to mean "we didn't set the position." 283 return -1; 284} 285 286FloatPoint InlineBox::locationIncludingFlipping() 287{ 288 if (!renderer()->style()->isFlippedBlocksWritingMode()) 289 return FloatPoint(x(), y()); 290 RenderBlock* block = root()->block(); 291 if (block->style()->isHorizontalWritingMode()) 292 return FloatPoint(x(), block->height() - height() - y()); 293 else 294 return FloatPoint(block->width() - width() - x(), y()); 295} 296 297void InlineBox::flipForWritingMode(FloatRect& rect) 298{ 299 if (!renderer()->style()->isFlippedBlocksWritingMode()) 300 return; 301 root()->block()->flipForWritingMode(rect); 302} 303 304FloatPoint InlineBox::flipForWritingMode(const FloatPoint& point) 305{ 306 if (!renderer()->style()->isFlippedBlocksWritingMode()) 307 return point; 308 return root()->block()->flipForWritingMode(point); 309} 310 311void InlineBox::flipForWritingMode(IntRect& rect) 312{ 313 if (!renderer()->style()->isFlippedBlocksWritingMode()) 314 return; 315 root()->block()->flipForWritingMode(rect); 316} 317 318IntPoint InlineBox::flipForWritingMode(const IntPoint& point) 319{ 320 if (!renderer()->style()->isFlippedBlocksWritingMode()) 321 return point; 322 return root()->block()->flipForWritingMode(point); 323} 324 325} // namespace WebCore 326 327#ifndef NDEBUG 328 329void showTree(const WebCore::InlineBox* b) 330{ 331 if (b) 332 b->showTreeForThis(); 333} 334 335#endif 336