InlineBox.cpp revision cad810f21b803229eb11403f9209855525a25d57
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 "RenderArena.h" 26#include "RenderBlock.h" 27#include "RootInlineBox.h" 28 29using namespace std; 30 31namespace WebCore { 32 33#ifndef NDEBUG 34static bool inInlineBoxDetach; 35#endif 36 37#ifndef NDEBUG 38 39InlineBox::~InlineBox() 40{ 41 if (!m_hasBadParent && m_parent) 42 m_parent->setHasBadChildList(); 43} 44 45#endif 46 47void InlineBox::remove() 48{ 49 if (parent()) 50 parent()->removeChild(this); 51} 52 53void InlineBox::destroy(RenderArena* renderArena) 54{ 55#ifndef NDEBUG 56 inInlineBoxDetach = true; 57#endif 58 delete this; 59#ifndef NDEBUG 60 inInlineBoxDetach = false; 61#endif 62 63 // Recover the size left there for us by operator delete and free the memory. 64 renderArena->free(*(size_t *)this, this); 65} 66 67void* InlineBox::operator new(size_t sz, RenderArena* renderArena) throw() 68{ 69 return renderArena->allocate(sz); 70} 71 72void InlineBox::operator delete(void* ptr, size_t sz) 73{ 74 ASSERT(inInlineBoxDetach); 75 76 // Stash size where destroy can find it. 77 *(size_t *)ptr = sz; 78} 79 80#ifndef NDEBUG 81void InlineBox::showTreeForThis() const 82{ 83 if (m_renderer) 84 m_renderer->showTreeForThis(); 85} 86#endif 87 88int InlineBox::logicalHeight() const 89{ 90#if ENABLE(SVG) 91 if (hasVirtualLogicalHeight()) 92 return virtualLogicalHeight(); 93#endif 94 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(); 99 100 ASSERT(isInlineFlowBox()); 101 RenderBoxModelObject* flowObject = boxModelObject(); 102 const Font& font = renderer()->style(m_firstLine)->font(); 103 int result = font.height(); 104 if (parent()) 105 result += flowObject->borderAndPaddingLogicalHeight(); 106 return result; 107} 108 109int InlineBox::caretMinOffset() const 110{ 111 return m_renderer->caretMinOffset(); 112} 113 114int InlineBox::caretMaxOffset() const 115{ 116 return m_renderer->caretMaxOffset(); 117} 118 119unsigned InlineBox::caretMaxRenderedOffset() const 120{ 121 return 1; 122} 123 124void InlineBox::dirtyLineBoxes() 125{ 126 markDirty(); 127 for (InlineFlowBox* curr = parent(); curr && !curr->isDirty(); curr = curr->parent()) 128 curr->markDirty(); 129} 130 131void InlineBox::deleteLine(RenderArena* arena) 132{ 133 if (!m_extracted && m_renderer->isBox()) 134 toRenderBox(m_renderer)->setInlineBoxWrapper(0); 135 destroy(arena); 136} 137 138void InlineBox::extractLine() 139{ 140 m_extracted = true; 141 if (m_renderer->isBox()) 142 toRenderBox(m_renderer)->setInlineBoxWrapper(0); 143} 144 145void InlineBox::attachLine() 146{ 147 m_extracted = false; 148 if (m_renderer->isBox()) 149 toRenderBox(m_renderer)->setInlineBoxWrapper(this); 150} 151 152void InlineBox::adjustPosition(int dx, int dy) 153{ 154 m_x += dx; 155 m_y += dy; 156 if (m_renderer->isReplaced()) { 157 RenderBox* box = toRenderBox(m_renderer); 158 box->move(dx, dy); 159 } 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 280int InlineBox::placeEllipsisBox(bool, int, int, int, bool&) 281{ 282 // Use -1 to mean "we didn't set the position." 283 return -1; 284} 285 286IntPoint InlineBox::locationIncludingFlipping() 287{ 288 if (!renderer()->style()->isFlippedBlocksWritingMode()) 289 return IntPoint(x(), y()); 290 RenderBlock* block = root()->block(); 291 if (block->style()->isHorizontalWritingMode()) 292 return IntPoint(x(), block->height() - height() - y()); 293 else 294 return IntPoint(block->width() - width() - x(), y()); 295} 296 297void InlineBox::flipForWritingMode(IntRect& rect) 298{ 299 if (!renderer()->style()->isFlippedBlocksWritingMode()) 300 return; 301 root()->block()->flipForWritingMode(rect); 302} 303 304IntPoint InlineBox::flipForWritingMode(const IntPoint& point) 305{ 306 if (!renderer()->style()->isFlippedBlocksWritingMode()) 307 return point; 308 return root()->block()->flipForWritingMode(point); 309} 310 311} // namespace WebCore 312 313#ifndef NDEBUG 314 315void showTree(const WebCore::InlineBox* b) 316{ 317 if (b) 318 b->showTreeForThis(); 319} 320 321#endif 322