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 "core/rendering/InlineBox.h" 22 23 #include "core/rendering/InlineFlowBox.h" 24 #include "core/rendering/PaintInfo.h" 25 #include "core/rendering/RenderBlockFlow.h" 26 #include "core/rendering/RootInlineBox.h" 27 #include "platform/Partitions.h" 28 #include "platform/fonts/FontMetrics.h" 29 30 #ifndef NDEBUG 31 #include <stdio.h> 32 #endif 33 34 using namespace std; 35 36 namespace WebCore { 37 38 struct SameSizeAsInlineBox { 39 virtual ~SameSizeAsInlineBox() { } 40 void* a[4]; 41 FloatPoint b; 42 float c; 43 uint32_t d : 32; 44 #ifndef NDEBUG 45 bool f; 46 #endif 47 }; 48 49 COMPILE_ASSERT(sizeof(InlineBox) == sizeof(SameSizeAsInlineBox), InlineBox_size_guard); 50 51 #ifndef NDEBUG 52 53 InlineBox::~InlineBox() 54 { 55 if (!m_hasBadParent && m_parent) 56 m_parent->setHasBadChildList(); 57 } 58 59 #endif 60 61 void InlineBox::remove() 62 { 63 if (parent()) 64 parent()->removeChild(this); 65 } 66 67 void* InlineBox::operator new(size_t sz) 68 { 69 return partitionAlloc(Partitions::getRenderingPartition(), sz); 70 } 71 72 void InlineBox::operator delete(void* ptr) 73 { 74 partitionFree(ptr); 75 } 76 77 #ifndef NDEBUG 78 const char* InlineBox::boxName() const 79 { 80 return "InlineBox"; 81 } 82 83 void InlineBox::showTreeForThis() const 84 { 85 if (m_renderer) 86 m_renderer->showTreeForThis(); 87 } 88 89 void InlineBox::showLineTreeForThis() const 90 { 91 if (m_renderer) 92 m_renderer->containingBlock()->showLineTreeAndMark(this, "*"); 93 } 94 95 void InlineBox::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj, int depth) const 96 { 97 int printedCharacters = 0; 98 if (this == markedBox1) 99 printedCharacters += fprintf(stderr, "%s", markedLabel1); 100 if (this == markedBox2) 101 printedCharacters += fprintf(stderr, "%s", markedLabel2); 102 if (renderer() == obj) 103 printedCharacters += fprintf(stderr, "*"); 104 for (; printedCharacters < depth * 2; printedCharacters++) 105 fputc(' ', stderr); 106 107 showBox(printedCharacters); 108 } 109 110 void InlineBox::showBox(int printedCharacters) const 111 { 112 printedCharacters += fprintf(stderr, "%s\t%p", boxName(), this); 113 for (; printedCharacters < showTreeCharacterOffset; printedCharacters++) 114 fputc(' ', stderr); 115 fprintf(stderr, "\t%s %p\n", renderer() ? renderer()->renderName() : "No Renderer", renderer()); 116 } 117 #endif 118 119 float InlineBox::logicalHeight() const 120 { 121 if (hasVirtualLogicalHeight()) 122 return virtualLogicalHeight(); 123 124 if (renderer()->isText()) 125 return m_bitfields.isText() ? renderer()->style(isFirstLineStyle())->fontMetrics().height() : 0; 126 if (renderer()->isBox() && parent()) 127 return isHorizontal() ? toRenderBox(m_renderer)->height() : toRenderBox(m_renderer)->width(); 128 129 ASSERT(isInlineFlowBox()); 130 RenderBoxModelObject* flowObject = boxModelObject(); 131 const FontMetrics& fontMetrics = renderer()->style(isFirstLineStyle())->fontMetrics(); 132 float result = fontMetrics.height(); 133 if (parent()) 134 result += flowObject->borderAndPaddingLogicalHeight(); 135 return result; 136 } 137 138 int InlineBox::baselinePosition(FontBaseline baselineType) const 139 { 140 return boxModelObject()->baselinePosition(baselineType, m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); 141 } 142 143 LayoutUnit InlineBox::lineHeight() const 144 { 145 return boxModelObject()->lineHeight(m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); 146 } 147 148 int InlineBox::caretMinOffset() const 149 { 150 return m_renderer->caretMinOffset(); 151 } 152 153 int InlineBox::caretMaxOffset() const 154 { 155 return m_renderer->caretMaxOffset(); 156 } 157 158 void InlineBox::dirtyLineBoxes() 159 { 160 markDirty(); 161 for (InlineFlowBox* curr = parent(); curr && !curr->isDirty(); curr = curr->parent()) 162 curr->markDirty(); 163 } 164 165 void InlineBox::deleteLine() 166 { 167 if (!m_bitfields.extracted() && m_renderer->isBox()) 168 toRenderBox(m_renderer)->setInlineBoxWrapper(0); 169 destroy(); 170 } 171 172 void InlineBox::extractLine() 173 { 174 m_bitfields.setExtracted(true); 175 if (m_renderer->isBox()) 176 toRenderBox(m_renderer)->setInlineBoxWrapper(0); 177 } 178 179 void InlineBox::attachLine() 180 { 181 m_bitfields.setExtracted(false); 182 if (m_renderer->isBox()) 183 toRenderBox(m_renderer)->setInlineBoxWrapper(this); 184 } 185 186 void InlineBox::adjustPosition(float dx, float dy) 187 { 188 m_topLeft.move(dx, dy); 189 190 if (m_renderer->isReplaced()) 191 toRenderBox(m_renderer)->move(dx, dy); 192 } 193 194 void InlineBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/) 195 { 196 if (!paintInfo.shouldPaintWithinRoot(renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)) 197 return; 198 199 LayoutPoint childPoint = paintOffset; 200 if (parent()->renderer()->style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock(). 201 childPoint = renderer()->containingBlock()->flipForWritingModeForChild(toRenderBox(renderer()), childPoint); 202 203 RenderBlock::paintAsInlineBlock(renderer(), paintInfo, childPoint); 204 } 205 206 bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/) 207 { 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 210 // specification.) 211 LayoutPoint childPoint = accumulatedOffset; 212 if (parent()->renderer()->style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock(). 213 childPoint = renderer()->containingBlock()->flipForWritingModeForChild(toRenderBox(renderer()), childPoint); 214 215 return renderer()->hitTest(request, result, locationInContainer, childPoint); 216 } 217 218 const RootInlineBox* InlineBox::root() const 219 { 220 if (m_parent) 221 return m_parent->root(); 222 ASSERT(isRootInlineBox()); 223 return static_cast<const RootInlineBox*>(this); 224 } 225 226 RootInlineBox* InlineBox::root() 227 { 228 if (m_parent) 229 return m_parent->root(); 230 ASSERT(isRootInlineBox()); 231 return static_cast<RootInlineBox*>(this); 232 } 233 234 bool InlineBox::nextOnLineExists() const 235 { 236 if (!m_bitfields.determinedIfNextOnLineExists()) { 237 m_bitfields.setDeterminedIfNextOnLineExists(true); 238 239 if (!parent()) 240 m_bitfields.setNextOnLineExists(false); 241 else if (nextOnLine()) 242 m_bitfields.setNextOnLineExists(true); 243 else 244 m_bitfields.setNextOnLineExists(parent()->nextOnLineExists()); 245 } 246 return m_bitfields.nextOnLineExists(); 247 } 248 249 InlineBox* InlineBox::nextLeafChild() const 250 { 251 InlineBox* leaf = 0; 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(); 256 return leaf; 257 } 258 259 InlineBox* InlineBox::prevLeafChild() const 260 { 261 InlineBox* leaf = 0; 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(); 266 return leaf; 267 } 268 269 InlineBox* InlineBox::nextLeafChildIgnoringLineBreak() const 270 { 271 InlineBox* leaf = nextLeafChild(); 272 if (leaf && leaf->isLineBreak()) 273 return 0; 274 return leaf; 275 } 276 277 InlineBox* InlineBox::prevLeafChildIgnoringLineBreak() const 278 { 279 InlineBox* leaf = prevLeafChild(); 280 if (leaf && leaf->isLineBreak()) 281 return 0; 282 return leaf; 283 } 284 285 RenderObject::SelectionState InlineBox::selectionState() 286 { 287 return renderer()->selectionState(); 288 } 289 290 bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const 291 { 292 // Non-replaced elements can always accommodate an ellipsis. 293 if (!m_renderer || !m_renderer->isReplaced()) 294 return true; 295 296 IntRect boxRect(left(), 0, m_logicalWidth, 10); 297 IntRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10); 298 return !(boxRect.intersects(ellipsisRect)); 299 } 300 301 float InlineBox::placeEllipsisBox(bool, float, float, float, float& truncatedWidth, bool&) 302 { 303 // Use -1 to mean "we didn't set the position." 304 truncatedWidth += logicalWidth(); 305 return -1; 306 } 307 308 void InlineBox::clearKnownToHaveNoOverflow() 309 { 310 m_bitfields.setKnownToHaveNoOverflow(false); 311 if (parent() && parent()->knownToHaveNoOverflow()) 312 parent()->clearKnownToHaveNoOverflow(); 313 } 314 315 FloatPoint InlineBox::locationIncludingFlipping() 316 { 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()); 322 else 323 return FloatPoint(block->width() - width() - x(), y()); 324 } 325 326 void InlineBox::flipForWritingMode(FloatRect& rect) 327 { 328 if (!renderer()->style()->isFlippedBlocksWritingMode()) 329 return; 330 root()->block()->flipForWritingMode(rect); 331 } 332 333 FloatPoint InlineBox::flipForWritingMode(const FloatPoint& point) 334 { 335 if (!renderer()->style()->isFlippedBlocksWritingMode()) 336 return point; 337 return root()->block()->flipForWritingMode(point); 338 } 339 340 void InlineBox::flipForWritingMode(LayoutRect& rect) 341 { 342 if (!renderer()->style()->isFlippedBlocksWritingMode()) 343 return; 344 root()->block()->flipForWritingMode(rect); 345 } 346 347 LayoutPoint InlineBox::flipForWritingMode(const LayoutPoint& point) 348 { 349 if (!renderer()->style()->isFlippedBlocksWritingMode()) 350 return point; 351 return root()->block()->flipForWritingMode(point); 352 } 353 354 } // namespace WebCore 355 356 #ifndef NDEBUG 357 358 void showTree(const WebCore::InlineBox* b) 359 { 360 if (b) 361 b->showTreeForThis(); 362 } 363 364 void showLineTree(const WebCore::InlineBox* b) 365 { 366 if (b) 367 b->showLineTreeForThis(); 368 } 369 370 #endif 371