1 /* 2 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 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/InlineFlowBox.h" 22 23 #include "core/CSSPropertyNames.h" 24 #include "core/dom/Document.h" 25 #include "core/paint/BoxPainter.h" 26 #include "core/paint/InlineFlowBoxPainter.h" 27 #include "core/rendering/HitTestResult.h" 28 #include "core/rendering/InlineTextBox.h" 29 #include "core/rendering/RenderBlock.h" 30 #include "core/rendering/RenderInline.h" 31 #include "core/rendering/RenderLayer.h" 32 #include "core/rendering/RenderListMarker.h" 33 #include "core/rendering/RenderObjectInlines.h" 34 #include "core/rendering/RenderRubyBase.h" 35 #include "core/rendering/RenderRubyRun.h" 36 #include "core/rendering/RenderRubyText.h" 37 #include "core/rendering/RenderView.h" 38 #include "core/rendering/RootInlineBox.h" 39 #include "platform/fonts/Font.h" 40 #include "platform/graphics/GraphicsContextStateSaver.h" 41 42 #include <math.h> 43 44 namespace blink { 45 46 struct SameSizeAsInlineFlowBox : public InlineBox { 47 void* pointers[5]; 48 uint32_t bitfields : 23; 49 }; 50 51 COMPILE_ASSERT(sizeof(InlineFlowBox) == sizeof(SameSizeAsInlineFlowBox), InlineFlowBox_should_stay_small); 52 53 #if ENABLE(ASSERT) 54 55 InlineFlowBox::~InlineFlowBox() 56 { 57 if (!m_hasBadChildList) 58 for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) 59 child->setHasBadParent(); 60 } 61 62 #endif 63 64 LayoutUnit InlineFlowBox::getFlowSpacingLogicalWidth() 65 { 66 LayoutUnit totWidth = marginBorderPaddingLogicalLeft() + marginBorderPaddingLogicalRight(); 67 for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { 68 if (curr->isInlineFlowBox()) 69 totWidth += toInlineFlowBox(curr)->getFlowSpacingLogicalWidth(); 70 } 71 return totWidth; 72 } 73 74 IntRect InlineFlowBox::roundedFrameRect() const 75 { 76 // Begin by snapping the x and y coordinates to the nearest pixel. 77 int snappedX = lroundf(x()); 78 int snappedY = lroundf(y()); 79 80 int snappedMaxX = lroundf(x() + width()); 81 int snappedMaxY = lroundf(y() + height()); 82 83 return IntRect(snappedX, snappedY, snappedMaxX - snappedX, snappedMaxY - snappedY); 84 } 85 86 static void setHasTextDescendantsOnAncestors(InlineFlowBox* box) 87 { 88 while (box && !box->hasTextDescendants()) { 89 box->setHasTextDescendants(); 90 box = box->parent(); 91 } 92 } 93 94 void InlineFlowBox::addToLine(InlineBox* child) 95 { 96 ASSERT(!child->parent()); 97 ASSERT(!child->nextOnLine()); 98 ASSERT(!child->prevOnLine()); 99 checkConsistency(); 100 101 child->setParent(this); 102 if (!m_firstChild) { 103 m_firstChild = child; 104 m_lastChild = child; 105 } else { 106 m_lastChild->setNextOnLine(child); 107 child->setPrevOnLine(m_lastChild); 108 m_lastChild = child; 109 } 110 child->setFirstLineStyleBit(isFirstLineStyle()); 111 child->setIsHorizontal(isHorizontal()); 112 if (child->isText()) { 113 if (child->renderer().parent() == renderer()) 114 m_hasTextChildren = true; 115 setHasTextDescendantsOnAncestors(this); 116 } else if (child->isInlineFlowBox()) { 117 if (toInlineFlowBox(child)->hasTextDescendants()) 118 setHasTextDescendantsOnAncestors(this); 119 } 120 121 if (descendantsHaveSameLineHeightAndBaseline() && !child->renderer().isOutOfFlowPositioned()) { 122 RenderStyle* parentStyle = renderer().style(isFirstLineStyle()); 123 RenderStyle* childStyle = child->renderer().style(isFirstLineStyle()); 124 bool shouldClearDescendantsHaveSameLineHeightAndBaseline = false; 125 if (child->renderer().isReplaced()) 126 shouldClearDescendantsHaveSameLineHeightAndBaseline = true; 127 else if (child->isText()) { 128 if (child->renderer().isBR() || child->renderer().parent() != renderer()) { 129 if (!parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics()) 130 || parentStyle->lineHeight() != childStyle->lineHeight() 131 || (parentStyle->verticalAlign() != BASELINE && !isRootInlineBox()) || childStyle->verticalAlign() != BASELINE) 132 shouldClearDescendantsHaveSameLineHeightAndBaseline = true; 133 } 134 if (childStyle->hasTextCombine() || childStyle->textEmphasisMark() != TextEmphasisMarkNone) 135 shouldClearDescendantsHaveSameLineHeightAndBaseline = true; 136 } else { 137 if (child->renderer().isBR()) { 138 // FIXME: This is dumb. We only turn off because current layout test results expect the <br> to be 0-height on the baseline. 139 // Other than making a zillion tests have to regenerate results, there's no reason to ditch the optimization here. 140 shouldClearDescendantsHaveSameLineHeightAndBaseline = true; 141 } else { 142 ASSERT(isInlineFlowBox()); 143 InlineFlowBox* childFlowBox = toInlineFlowBox(child); 144 // Check the child's bit, and then also check for differences in font, line-height, vertical-align 145 if (!childFlowBox->descendantsHaveSameLineHeightAndBaseline() 146 || !parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics()) 147 || parentStyle->lineHeight() != childStyle->lineHeight() 148 || (parentStyle->verticalAlign() != BASELINE && !isRootInlineBox()) || childStyle->verticalAlign() != BASELINE 149 || childStyle->hasBorder() || childStyle->hasPadding() || childStyle->hasTextCombine()) 150 shouldClearDescendantsHaveSameLineHeightAndBaseline = true; 151 } 152 } 153 154 if (shouldClearDescendantsHaveSameLineHeightAndBaseline) 155 clearDescendantsHaveSameLineHeightAndBaseline(); 156 } 157 158 if (!child->renderer().isOutOfFlowPositioned()) { 159 if (child->isText()) { 160 RenderStyle* childStyle = child->renderer().style(isFirstLineStyle()); 161 if (childStyle->letterSpacing() < 0 || childStyle->textShadow() || childStyle->textEmphasisMark() != TextEmphasisMarkNone || childStyle->textStrokeWidth()) 162 child->clearKnownToHaveNoOverflow(); 163 } else if (child->renderer().isReplaced()) { 164 RenderBox& box = toRenderBox(child->renderer()); 165 if (box.hasRenderOverflow() || box.hasSelfPaintingLayer()) 166 child->clearKnownToHaveNoOverflow(); 167 } else if (!child->renderer().isBR() && (child->renderer().style(isFirstLineStyle())->boxShadow() || child->boxModelObject()->hasSelfPaintingLayer() 168 || (child->renderer().isListMarker() && !toRenderListMarker(child->renderer()).isInside()) 169 || child->renderer().style(isFirstLineStyle())->hasBorderImageOutsets() 170 || child->renderer().style(isFirstLineStyle())->hasOutline())) { 171 child->clearKnownToHaveNoOverflow(); 172 } 173 174 if (knownToHaveNoOverflow() && child->isInlineFlowBox() && !toInlineFlowBox(child)->knownToHaveNoOverflow()) 175 clearKnownToHaveNoOverflow(); 176 } 177 178 checkConsistency(); 179 } 180 181 void InlineFlowBox::removeChild(InlineBox* child, MarkLineBoxes markDirty) 182 { 183 checkConsistency(); 184 185 if (markDirty == MarkLineBoxesDirty && !isDirty()) 186 dirtyLineBoxes(); 187 188 root().childRemoved(child); 189 190 if (child == m_firstChild) 191 m_firstChild = child->nextOnLine(); 192 if (child == m_lastChild) 193 m_lastChild = child->prevOnLine(); 194 if (child->nextOnLine()) 195 child->nextOnLine()->setPrevOnLine(child->prevOnLine()); 196 if (child->prevOnLine()) 197 child->prevOnLine()->setNextOnLine(child->nextOnLine()); 198 199 child->setParent(0); 200 201 checkConsistency(); 202 } 203 204 void InlineFlowBox::deleteLine() 205 { 206 InlineBox* child = firstChild(); 207 InlineBox* next = 0; 208 while (child) { 209 ASSERT(this == child->parent()); 210 next = child->nextOnLine(); 211 #if ENABLE(ASSERT) 212 child->setParent(0); 213 #endif 214 child->deleteLine(); 215 child = next; 216 } 217 #if ENABLE(ASSERT) 218 m_firstChild = 0; 219 m_lastChild = 0; 220 #endif 221 222 removeLineBoxFromRenderObject(); 223 destroy(); 224 } 225 226 void InlineFlowBox::removeLineBoxFromRenderObject() 227 { 228 rendererLineBoxes()->removeLineBox(this); 229 } 230 231 void InlineFlowBox::extractLine() 232 { 233 if (!extracted()) 234 extractLineBoxFromRenderObject(); 235 for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) 236 child->extractLine(); 237 } 238 239 void InlineFlowBox::extractLineBoxFromRenderObject() 240 { 241 rendererLineBoxes()->extractLineBox(this); 242 } 243 244 void InlineFlowBox::attachLine() 245 { 246 if (extracted()) 247 attachLineBoxToRenderObject(); 248 for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) 249 child->attachLine(); 250 } 251 252 void InlineFlowBox::attachLineBoxToRenderObject() 253 { 254 rendererLineBoxes()->attachLineBox(this); 255 } 256 257 void InlineFlowBox::adjustPosition(float dx, float dy) 258 { 259 InlineBox::adjustPosition(dx, dy); 260 for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) 261 child->adjustPosition(dx, dy); 262 if (m_overflow) 263 m_overflow->move(dx, dy); // FIXME: Rounding error here since overflow was pixel snapped, but nobody other than list markers passes non-integral values here. 264 } 265 266 RenderLineBoxList* InlineFlowBox::rendererLineBoxes() const 267 { 268 return toRenderInline(renderer()).lineBoxes(); 269 } 270 271 static inline bool isLastChildForRenderer(RenderObject* ancestor, RenderObject* child) 272 { 273 if (!child) 274 return false; 275 276 if (child == ancestor) 277 return true; 278 279 RenderObject* curr = child; 280 RenderObject* parent = curr->parent(); 281 while (parent && (!parent->isRenderBlock() || parent->isInline())) { 282 if (parent->slowLastChild() != curr) 283 return false; 284 if (parent == ancestor) 285 return true; 286 287 curr = parent; 288 parent = curr->parent(); 289 } 290 291 return true; 292 } 293 294 static bool isAnsectorAndWithinBlock(RenderObject* ancestor, RenderObject* child) 295 { 296 RenderObject* object = child; 297 while (object && (!object->isRenderBlock() || object->isInline())) { 298 if (object == ancestor) 299 return true; 300 object = object->parent(); 301 } 302 return false; 303 } 304 305 void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, bool isLogicallyLastRunWrapped, RenderObject* logicallyLastRunRenderer) 306 { 307 // All boxes start off open. They will not apply any margins/border/padding on 308 // any side. 309 bool includeLeftEdge = false; 310 bool includeRightEdge = false; 311 312 // The root inline box never has borders/margins/padding. 313 if (parent()) { 314 bool ltr = renderer().style()->isLeftToRightDirection(); 315 316 // Check to see if all initial lines are unconstructed. If so, then 317 // we know the inline began on this line (unless we are a continuation). 318 RenderLineBoxList* lineBoxList = rendererLineBoxes(); 319 if (!lineBoxList->firstLineBox()->isConstructed() && !renderer().isInlineElementContinuation()) { 320 if (renderer().style()->boxDecorationBreak() == DCLONE) 321 includeLeftEdge = includeRightEdge = true; 322 else if (ltr && lineBoxList->firstLineBox() == this) 323 includeLeftEdge = true; 324 else if (!ltr && lineBoxList->lastLineBox() == this) 325 includeRightEdge = true; 326 } 327 328 if (!lineBoxList->lastLineBox()->isConstructed()) { 329 RenderInline& inlineFlow = toRenderInline(renderer()); 330 bool isLastObjectOnLine = !isAnsectorAndWithinBlock(&renderer(), logicallyLastRunRenderer) || (isLastChildForRenderer(&renderer(), logicallyLastRunRenderer) && !isLogicallyLastRunWrapped); 331 332 // We include the border under these conditions: 333 // (1) The next line was not created, or it is constructed. We check the previous line for rtl. 334 // (2) The logicallyLastRun is not a descendant of this renderer. 335 // (3) The logicallyLastRun is a descendant of this renderer, but it is the last child of this renderer and it does not wrap to the next line. 336 // (4) The decoration break is set to clone therefore there will be borders on every sides. 337 if (renderer().style()->boxDecorationBreak() == DCLONE) 338 includeLeftEdge = includeRightEdge = true; 339 else if (ltr) { 340 if (!nextLineBox() 341 && ((lastLine || isLastObjectOnLine) && !inlineFlow.continuation())) 342 includeRightEdge = true; 343 } else { 344 if ((!prevLineBox() || prevLineBox()->isConstructed()) 345 && ((lastLine || isLastObjectOnLine) && !inlineFlow.continuation())) 346 includeLeftEdge = true; 347 } 348 } 349 } 350 351 setEdges(includeLeftEdge, includeRightEdge); 352 353 // Recur into our children. 354 for (InlineBox* currChild = firstChild(); currChild; currChild = currChild->nextOnLine()) { 355 if (currChild->isInlineFlowBox()) { 356 InlineFlowBox* currFlow = toInlineFlowBox(currChild); 357 currFlow->determineSpacingForFlowBoxes(lastLine, isLogicallyLastRunWrapped, logicallyLastRunRenderer); 358 } 359 } 360 } 361 362 float InlineFlowBox::placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing) 363 { 364 // Set our x position. 365 beginPlacingBoxRangesInInlineDirection(logicalLeft); 366 367 float startLogicalLeft = logicalLeft; 368 logicalLeft += borderLogicalLeft() + paddingLogicalLeft(); 369 370 float minLogicalLeft = startLogicalLeft; 371 float maxLogicalRight = logicalLeft; 372 373 placeBoxRangeInInlineDirection(firstChild(), 0, logicalLeft, minLogicalLeft, maxLogicalRight, needsWordSpacing); 374 375 logicalLeft += borderLogicalRight() + paddingLogicalRight(); 376 endPlacingBoxRangesInInlineDirection(startLogicalLeft, logicalLeft, minLogicalLeft, maxLogicalRight); 377 return logicalLeft; 378 } 379 380 float InlineFlowBox::placeBoxRangeInInlineDirection(InlineBox* firstChild, InlineBox* lastChild, 381 float& logicalLeft, float& minLogicalLeft, float& maxLogicalRight, bool& needsWordSpacing) 382 { 383 for (InlineBox* curr = firstChild; curr && curr != lastChild; curr = curr->nextOnLine()) { 384 if (curr->renderer().isText()) { 385 InlineTextBox* text = toInlineTextBox(curr); 386 RenderText& rt = text->renderer(); 387 float space = 0; 388 if (rt.textLength()) { 389 if (needsWordSpacing && isSpaceOrNewline(rt.characterAt(text->start()))) 390 space = rt.style(isFirstLineStyle())->font().fontDescription().wordSpacing(); 391 needsWordSpacing = !isSpaceOrNewline(rt.characterAt(text->end())); 392 } 393 if (isLeftToRightDirection()) { 394 logicalLeft += space; 395 text->setLogicalLeft(logicalLeft); 396 } else { 397 text->setLogicalLeft(logicalLeft); 398 logicalLeft += space; 399 } 400 if (knownToHaveNoOverflow()) 401 minLogicalLeft = std::min(logicalLeft, minLogicalLeft); 402 logicalLeft += text->logicalWidth(); 403 if (knownToHaveNoOverflow()) 404 maxLogicalRight = std::max(logicalLeft, maxLogicalRight); 405 } else { 406 if (curr->renderer().isOutOfFlowPositioned()) { 407 if (curr->renderer().parent()->style()->isLeftToRightDirection()) { 408 curr->setLogicalLeft(logicalLeft); 409 } else { 410 // Our offset that we cache needs to be from the edge of the right border box and 411 // not the left border box. We have to subtract |x| from the width of the block 412 // (which can be obtained from the root line box). 413 curr->setLogicalLeft(root().block().logicalWidth() - logicalLeft); 414 } 415 continue; // The positioned object has no effect on the width. 416 } 417 if (curr->renderer().isRenderInline()) { 418 InlineFlowBox* flow = toInlineFlowBox(curr); 419 logicalLeft += flow->marginLogicalLeft(); 420 if (knownToHaveNoOverflow()) 421 minLogicalLeft = std::min(logicalLeft, minLogicalLeft); 422 logicalLeft = flow->placeBoxesInInlineDirection(logicalLeft, needsWordSpacing); 423 if (knownToHaveNoOverflow()) 424 maxLogicalRight = std::max(logicalLeft, maxLogicalRight); 425 logicalLeft += flow->marginLogicalRight(); 426 } else if (!curr->renderer().isListMarker() || toRenderListMarker(curr->renderer()).isInside()) { 427 // The box can have a different writing-mode than the overall line, so this is a bit complicated. 428 // Just get all the physical margin and overflow values by hand based off |isVertical|. 429 LayoutUnit logicalLeftMargin = isHorizontal() ? curr->boxModelObject()->marginLeft() : curr->boxModelObject()->marginTop(); 430 LayoutUnit logicalRightMargin = isHorizontal() ? curr->boxModelObject()->marginRight() : curr->boxModelObject()->marginBottom(); 431 432 logicalLeft += logicalLeftMargin; 433 curr->setLogicalLeft(logicalLeft); 434 if (knownToHaveNoOverflow()) 435 minLogicalLeft = std::min(logicalLeft, minLogicalLeft); 436 logicalLeft += curr->logicalWidth(); 437 if (knownToHaveNoOverflow()) 438 maxLogicalRight = std::max(logicalLeft, maxLogicalRight); 439 logicalLeft += logicalRightMargin; 440 // If we encounter any space after this inline block then ensure it is treated as the space between two words. 441 needsWordSpacing = true; 442 } 443 } 444 } 445 return logicalLeft; 446 } 447 448 bool InlineFlowBox::requiresIdeographicBaseline(const GlyphOverflowAndFallbackFontsMap& textBoxDataMap) const 449 { 450 if (isHorizontal()) 451 return false; 452 453 if (renderer().style(isFirstLineStyle())->fontDescription().nonCJKGlyphOrientation() == NonCJKGlyphOrientationUpright 454 || renderer().style(isFirstLineStyle())->font().primaryFont()->hasVerticalGlyphs()) 455 return true; 456 457 for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { 458 if (curr->renderer().isOutOfFlowPositioned()) 459 continue; // Positioned placeholders don't affect calculations. 460 461 if (curr->isInlineFlowBox()) { 462 if (toInlineFlowBox(curr)->requiresIdeographicBaseline(textBoxDataMap)) 463 return true; 464 } else { 465 if (curr->renderer().style(isFirstLineStyle())->font().primaryFont()->hasVerticalGlyphs()) 466 return true; 467 468 const Vector<const SimpleFontData*>* usedFonts = 0; 469 if (curr->isInlineTextBox()) { 470 GlyphOverflowAndFallbackFontsMap::const_iterator it = textBoxDataMap.find(toInlineTextBox(curr)); 471 usedFonts = it == textBoxDataMap.end() ? 0 : &it->value.first; 472 } 473 474 if (usedFonts) { 475 for (size_t i = 0; i < usedFonts->size(); ++i) { 476 if (usedFonts->at(i)->hasVerticalGlyphs()) 477 return true; 478 } 479 } 480 } 481 } 482 483 return false; 484 } 485 486 void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, int maxPositionTop, int maxPositionBottom) 487 { 488 for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { 489 // The computed lineheight needs to be extended for the 490 // positioned elements 491 if (curr->renderer().isOutOfFlowPositioned()) 492 continue; // Positioned placeholders don't affect calculations. 493 if (curr->verticalAlign() == TOP || curr->verticalAlign() == BOTTOM) { 494 int lineHeight = curr->lineHeight(); 495 if (curr->verticalAlign() == TOP) { 496 if (maxAscent + maxDescent < lineHeight) 497 maxDescent = lineHeight - maxAscent; 498 } 499 else { 500 if (maxAscent + maxDescent < lineHeight) 501 maxAscent = lineHeight - maxDescent; 502 } 503 504 if (maxAscent + maxDescent >= std::max(maxPositionTop, maxPositionBottom)) 505 break; 506 } 507 508 if (curr->isInlineFlowBox()) 509 toInlineFlowBox(curr)->adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom); 510 } 511 } 512 513 void InlineFlowBox::computeLogicalBoxHeights(RootInlineBox* rootBox, LayoutUnit& maxPositionTop, LayoutUnit& maxPositionBottom, 514 int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent, 515 bool strictMode, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, 516 FontBaseline baselineType, VerticalPositionCache& verticalPositionCache) 517 { 518 // The primary purpose of this function is to compute the maximal ascent and descent values for 519 // a line. These values are computed based off the block's line-box-contain property, which indicates 520 // what parts of descendant boxes have to fit within the line. 521 // 522 // The maxAscent value represents the distance of the highest point of any box (typically including line-height) from 523 // the root box's baseline. The maxDescent value represents the distance of the lowest point of any box 524 // (also typically including line-height) from the root box baseline. These values can be negative. 525 // 526 // A secondary purpose of this function is to store the offset of every box's baseline from the root box's 527 // baseline. This information is cached in the logicalTop() of every box. We're effectively just using 528 // the logicalTop() as scratch space. 529 // 530 // Because a box can be positioned such that it ends up fully above or fully below the 531 // root line box, we only consider it to affect the maxAscent and maxDescent values if some 532 // part of the box (EXCLUDING leading) is above (for ascent) or below (for descent) the root box's baseline. 533 bool affectsAscent = false; 534 bool affectsDescent = false; 535 bool checkChildren = !descendantsHaveSameLineHeightAndBaseline(); 536 537 if (isRootInlineBox()) { 538 // Examine our root box. 539 int ascent = 0; 540 int descent = 0; 541 rootBox->ascentAndDescentForBox(rootBox, textBoxDataMap, ascent, descent, affectsAscent, affectsDescent); 542 if (strictMode || hasTextChildren() || (!checkChildren && hasTextDescendants())) { 543 if (maxAscent < ascent || !setMaxAscent) { 544 maxAscent = ascent; 545 setMaxAscent = true; 546 } 547 if (maxDescent < descent || !setMaxDescent) { 548 maxDescent = descent; 549 setMaxDescent = true; 550 } 551 } 552 } 553 554 if (!checkChildren) 555 return; 556 557 for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { 558 if (curr->renderer().isOutOfFlowPositioned()) 559 continue; // Positioned placeholders don't affect calculations. 560 561 InlineFlowBox* inlineFlowBox = curr->isInlineFlowBox() ? toInlineFlowBox(curr) : 0; 562 563 bool affectsAscent = false; 564 bool affectsDescent = false; 565 566 // The verticalPositionForBox function returns the distance between the child box's baseline 567 // and the root box's baseline. The value is negative if the child box's baseline is above the 568 // root box's baseline, and it is positive if the child box's baseline is below the root box's baseline. 569 curr->setLogicalTop(rootBox->verticalPositionForBox(curr, verticalPositionCache).toFloat()); 570 571 int ascent = 0; 572 int descent = 0; 573 rootBox->ascentAndDescentForBox(curr, textBoxDataMap, ascent, descent, affectsAscent, affectsDescent); 574 575 LayoutUnit boxHeight = ascent + descent; 576 if (curr->verticalAlign() == TOP) { 577 if (maxPositionTop < boxHeight) 578 maxPositionTop = boxHeight; 579 } else if (curr->verticalAlign() == BOTTOM) { 580 if (maxPositionBottom < boxHeight) 581 maxPositionBottom = boxHeight; 582 } else if (!inlineFlowBox || strictMode || inlineFlowBox->hasTextChildren() || (inlineFlowBox->descendantsHaveSameLineHeightAndBaseline() && inlineFlowBox->hasTextDescendants()) 583 || inlineFlowBox->boxModelObject()->hasInlineDirectionBordersOrPadding()) { 584 // Note that these values can be negative. Even though we only affect the maxAscent and maxDescent values 585 // if our box (excluding line-height) was above (for ascent) or below (for descent) the root baseline, once you factor in line-height 586 // the final box can end up being fully above or fully below the root box's baseline! This is ok, but what it 587 // means is that ascent and descent (including leading), can end up being negative. The setMaxAscent and 588 // setMaxDescent booleans are used to ensure that we're willing to initially set maxAscent/Descent to negative 589 // values. 590 ascent -= curr->logicalTop(); 591 descent += curr->logicalTop(); 592 if (affectsAscent && (maxAscent < ascent || !setMaxAscent)) { 593 maxAscent = ascent; 594 setMaxAscent = true; 595 } 596 597 if (affectsDescent && (maxDescent < descent || !setMaxDescent)) { 598 maxDescent = descent; 599 setMaxDescent = true; 600 } 601 } 602 603 if (inlineFlowBox) 604 inlineFlowBox->computeLogicalBoxHeights(rootBox, maxPositionTop, maxPositionBottom, maxAscent, maxDescent, 605 setMaxAscent, setMaxDescent, strictMode, textBoxDataMap, 606 baselineType, verticalPositionCache); 607 } 608 } 609 610 void InlineFlowBox::placeBoxesInBlockDirection(LayoutUnit top, LayoutUnit maxHeight, int maxAscent, bool strictMode, LayoutUnit& lineTop, LayoutUnit& lineBottom, LayoutUnit& selectionBottom, bool& setLineTop, 611 LayoutUnit& lineTopIncludingMargins, LayoutUnit& lineBottomIncludingMargins, bool& hasAnnotationsBefore, bool& hasAnnotationsAfter, FontBaseline baselineType) 612 { 613 bool isRootBox = isRootInlineBox(); 614 if (isRootBox) { 615 const FontMetrics& fontMetrics = renderer().style(isFirstLineStyle())->fontMetrics(); 616 // RootInlineBoxes are always placed on at pixel boundaries in their logical y direction. Not doing 617 // so results in incorrect rendering of text decorations, most notably underlines. 618 setLogicalTop(roundToInt(top + maxAscent - fontMetrics.ascent(baselineType))); 619 } 620 621 LayoutUnit adjustmentForChildrenWithSameLineHeightAndBaseline = 0; 622 if (descendantsHaveSameLineHeightAndBaseline()) { 623 adjustmentForChildrenWithSameLineHeightAndBaseline = logicalTop(); 624 if (parent()) 625 adjustmentForChildrenWithSameLineHeightAndBaseline += (boxModelObject()->borderBefore() + boxModelObject()->paddingBefore()); 626 } 627 628 for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { 629 if (curr->renderer().isOutOfFlowPositioned()) 630 continue; // Positioned placeholders don't affect calculations. 631 632 if (descendantsHaveSameLineHeightAndBaseline()) { 633 curr->adjustBlockDirectionPosition(adjustmentForChildrenWithSameLineHeightAndBaseline.toFloat()); 634 continue; 635 } 636 637 InlineFlowBox* inlineFlowBox = curr->isInlineFlowBox() ? toInlineFlowBox(curr) : 0; 638 bool childAffectsTopBottomPos = true; 639 if (curr->verticalAlign() == TOP) 640 curr->setLogicalTop(top.toFloat()); 641 else if (curr->verticalAlign() == BOTTOM) 642 curr->setLogicalTop((top + maxHeight - curr->lineHeight()).toFloat()); 643 else { 644 if (!strictMode && inlineFlowBox && !inlineFlowBox->hasTextChildren() && !curr->boxModelObject()->hasInlineDirectionBordersOrPadding() 645 && !(inlineFlowBox->descendantsHaveSameLineHeightAndBaseline() && inlineFlowBox->hasTextDescendants())) 646 childAffectsTopBottomPos = false; 647 LayoutUnit posAdjust = maxAscent - curr->baselinePosition(baselineType); 648 curr->setLogicalTop(curr->logicalTop() + top + posAdjust); 649 } 650 651 LayoutUnit newLogicalTop = curr->logicalTop(); 652 LayoutUnit newLogicalTopIncludingMargins = newLogicalTop; 653 LayoutUnit boxHeight = curr->logicalHeight(); 654 LayoutUnit boxHeightIncludingMargins = boxHeight; 655 LayoutUnit borderPaddingHeight = 0; 656 if (curr->isText() || curr->isInlineFlowBox()) { 657 const FontMetrics& fontMetrics = curr->renderer().style(isFirstLineStyle())->fontMetrics(); 658 newLogicalTop += curr->baselinePosition(baselineType) - fontMetrics.ascent(baselineType); 659 if (curr->isInlineFlowBox()) { 660 RenderBoxModelObject& boxObject = toRenderBoxModelObject(curr->renderer()); 661 newLogicalTop -= boxObject.style(isFirstLineStyle())->isHorizontalWritingMode() ? boxObject.borderTop() + boxObject.paddingTop() : 662 boxObject.borderRight() + boxObject.paddingRight(); 663 borderPaddingHeight = boxObject.borderAndPaddingLogicalHeight(); 664 } 665 newLogicalTopIncludingMargins = newLogicalTop; 666 } else if (!curr->renderer().isBR()) { 667 RenderBox& box = toRenderBox(curr->renderer()); 668 newLogicalTopIncludingMargins = newLogicalTop; 669 LayoutUnit overSideMargin = curr->isHorizontal() ? box.marginTop() : box.marginRight(); 670 LayoutUnit underSideMargin = curr->isHorizontal() ? box.marginBottom() : box.marginLeft(); 671 newLogicalTop += overSideMargin; 672 boxHeightIncludingMargins += overSideMargin + underSideMargin; 673 } 674 675 curr->setLogicalTop(newLogicalTop.toFloat()); 676 677 if (childAffectsTopBottomPos) { 678 if (curr->renderer().isRubyRun()) { 679 // Treat the leading on the first and last lines of ruby runs as not being part of the overall lineTop/lineBottom. 680 // Really this is a workaround hack for the fact that ruby should have been done as line layout and not done using 681 // inline-block. 682 if (renderer().style()->isFlippedLinesWritingMode() == (curr->renderer().style()->rubyPosition() == RubyPositionAfter)) 683 hasAnnotationsBefore = true; 684 else 685 hasAnnotationsAfter = true; 686 687 RenderRubyRun& rubyRun = toRenderRubyRun(curr->renderer()); 688 if (RenderRubyBase* rubyBase = rubyRun.rubyBase()) { 689 LayoutUnit bottomRubyBaseLeading = (curr->logicalHeight() - rubyBase->logicalBottom()) + rubyBase->logicalHeight() - (rubyBase->lastRootBox() ? rubyBase->lastRootBox()->lineBottom() : LayoutUnit()); 690 LayoutUnit topRubyBaseLeading = rubyBase->logicalTop() + (rubyBase->firstRootBox() ? rubyBase->firstRootBox()->lineTop() : LayoutUnit()); 691 newLogicalTop += !renderer().style()->isFlippedLinesWritingMode() ? topRubyBaseLeading : bottomRubyBaseLeading; 692 boxHeight -= (topRubyBaseLeading + bottomRubyBaseLeading); 693 } 694 } 695 if (curr->isInlineTextBox()) { 696 TextEmphasisPosition emphasisMarkPosition; 697 if (toInlineTextBox(curr)->getEmphasisMarkPosition(curr->renderer().style(isFirstLineStyle()), emphasisMarkPosition)) { 698 bool emphasisMarkIsOver = emphasisMarkPosition == TextEmphasisPositionOver; 699 if (emphasisMarkIsOver != curr->renderer().style(isFirstLineStyle())->isFlippedLinesWritingMode()) 700 hasAnnotationsBefore = true; 701 else 702 hasAnnotationsAfter = true; 703 } 704 } 705 706 if (!setLineTop) { 707 setLineTop = true; 708 lineTop = newLogicalTop; 709 lineTopIncludingMargins = std::min(lineTop, newLogicalTopIncludingMargins); 710 } else { 711 lineTop = std::min(lineTop, newLogicalTop); 712 lineTopIncludingMargins = std::min(lineTop, std::min(lineTopIncludingMargins, newLogicalTopIncludingMargins)); 713 } 714 selectionBottom = std::max(selectionBottom, newLogicalTop + boxHeight - borderPaddingHeight); 715 lineBottom = std::max(lineBottom, newLogicalTop + boxHeight); 716 lineBottomIncludingMargins = std::max(lineBottom, std::max(lineBottomIncludingMargins, newLogicalTopIncludingMargins + boxHeightIncludingMargins)); 717 } 718 719 // Adjust boxes to use their real box y/height and not the logical height (as dictated by 720 // line-height). 721 if (inlineFlowBox) 722 inlineFlowBox->placeBoxesInBlockDirection(top, maxHeight, maxAscent, strictMode, lineTop, lineBottom, selectionBottom, setLineTop, 723 lineTopIncludingMargins, lineBottomIncludingMargins, hasAnnotationsBefore, hasAnnotationsAfter, baselineType); 724 } 725 726 if (isRootBox) { 727 if (strictMode || hasTextChildren() || (descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants())) { 728 if (!setLineTop) { 729 setLineTop = true; 730 lineTop = pixelSnappedLogicalTop(); 731 lineTopIncludingMargins = lineTop; 732 } else { 733 lineTop = std::min<LayoutUnit>(lineTop, pixelSnappedLogicalTop()); 734 lineTopIncludingMargins = std::min(lineTop, lineTopIncludingMargins); 735 } 736 selectionBottom = std::max<LayoutUnit>(selectionBottom, pixelSnappedLogicalBottom()); 737 lineBottom = std::max<LayoutUnit>(lineBottom, pixelSnappedLogicalBottom()); 738 lineBottomIncludingMargins = std::max(lineBottom, lineBottomIncludingMargins); 739 } 740 741 if (renderer().style()->isFlippedLinesWritingMode()) 742 flipLinesInBlockDirection(lineTopIncludingMargins, lineBottomIncludingMargins); 743 } 744 } 745 746 void InlineFlowBox::computeMaxLogicalTop(float& maxLogicalTop) const 747 { 748 for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { 749 if (curr->renderer().isOutOfFlowPositioned()) 750 continue; // Positioned placeholders don't affect calculations. 751 752 if (descendantsHaveSameLineHeightAndBaseline()) 753 continue; 754 755 maxLogicalTop = std::max<float>(maxLogicalTop, curr->y()); 756 float localMaxLogicalTop = 0; 757 if (curr->isInlineFlowBox()) 758 toInlineFlowBox(curr)->computeMaxLogicalTop(localMaxLogicalTop); 759 maxLogicalTop = std::max<float>(maxLogicalTop, localMaxLogicalTop); 760 } 761 } 762 763 void InlineFlowBox::flipLinesInBlockDirection(LayoutUnit lineTop, LayoutUnit lineBottom) 764 { 765 // Flip the box on the line such that the top is now relative to the lineBottom instead of the lineTop. 766 setLogicalTop(lineBottom - (logicalTop() - lineTop) - logicalHeight()); 767 768 for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { 769 if (curr->renderer().isOutOfFlowPositioned()) 770 continue; // Positioned placeholders aren't affected here. 771 772 if (curr->isInlineFlowBox()) 773 toInlineFlowBox(curr)->flipLinesInBlockDirection(lineTop, lineBottom); 774 else 775 curr->setLogicalTop(lineBottom - (curr->logicalTop() - lineTop) - curr->logicalHeight()); 776 } 777 } 778 779 inline void InlineFlowBox::addBoxShadowVisualOverflow(LayoutRect& logicalVisualOverflow) 780 { 781 // box-shadow on root line boxes is applying to the block and not to the lines. 782 if (!parent()) 783 return; 784 785 RenderStyle* style = renderer().style(isFirstLineStyle()); 786 if (!style->boxShadow()) 787 return; 788 789 LayoutUnit boxShadowLogicalTop; 790 LayoutUnit boxShadowLogicalBottom; 791 style->getBoxShadowBlockDirectionExtent(boxShadowLogicalTop, boxShadowLogicalBottom); 792 793 // Similar to how glyph overflow works, if our lines are flipped, then it's actually the opposite shadow that applies, since 794 // the line is "upside down" in terms of block coordinates. 795 LayoutUnit shadowLogicalTop = style->isFlippedLinesWritingMode() ? -boxShadowLogicalBottom : boxShadowLogicalTop; 796 LayoutUnit shadowLogicalBottom = style->isFlippedLinesWritingMode() ? -boxShadowLogicalTop : boxShadowLogicalBottom; 797 798 LayoutUnit logicalTopVisualOverflow = std::min(pixelSnappedLogicalTop() + shadowLogicalTop, logicalVisualOverflow.y()); 799 LayoutUnit logicalBottomVisualOverflow = std::max(pixelSnappedLogicalBottom() + shadowLogicalBottom, logicalVisualOverflow.maxY()); 800 801 LayoutUnit boxShadowLogicalLeft; 802 LayoutUnit boxShadowLogicalRight; 803 style->getBoxShadowInlineDirectionExtent(boxShadowLogicalLeft, boxShadowLogicalRight); 804 805 LayoutUnit logicalLeftVisualOverflow = std::min(pixelSnappedLogicalLeft() + boxShadowLogicalLeft, logicalVisualOverflow.x()); 806 LayoutUnit logicalRightVisualOverflow = std::max(pixelSnappedLogicalRight() + boxShadowLogicalRight, logicalVisualOverflow.maxX()); 807 808 logicalVisualOverflow = LayoutRect(logicalLeftVisualOverflow, logicalTopVisualOverflow, 809 logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow); 810 } 811 812 inline void InlineFlowBox::addBorderOutsetVisualOverflow(LayoutRect& logicalVisualOverflow) 813 { 814 // border-image-outset on root line boxes is applying to the block and not to the lines. 815 if (!parent()) 816 return; 817 818 RenderStyle* style = renderer().style(isFirstLineStyle()); 819 if (!style->hasBorderImageOutsets()) 820 return; 821 822 LayoutBoxExtent borderOutsets = style->borderImageOutsets(); 823 824 LayoutUnit borderOutsetLogicalTop = borderOutsets.logicalTop(style->writingMode()); 825 LayoutUnit borderOutsetLogicalBottom = borderOutsets.logicalBottom(style->writingMode()); 826 LayoutUnit borderOutsetLogicalLeft = borderOutsets.logicalLeft(style->writingMode()); 827 LayoutUnit borderOutsetLogicalRight = borderOutsets.logicalRight(style->writingMode()); 828 829 // Similar to how glyph overflow works, if our lines are flipped, then it's actually the opposite border that applies, since 830 // the line is "upside down" in terms of block coordinates. vertical-rl and horizontal-bt are the flipped line modes. 831 LayoutUnit outsetLogicalTop = style->isFlippedLinesWritingMode() ? borderOutsetLogicalBottom : borderOutsetLogicalTop; 832 LayoutUnit outsetLogicalBottom = style->isFlippedLinesWritingMode() ? borderOutsetLogicalTop : borderOutsetLogicalBottom; 833 834 LayoutUnit logicalTopVisualOverflow = std::min(pixelSnappedLogicalTop() - outsetLogicalTop, logicalVisualOverflow.y()); 835 LayoutUnit logicalBottomVisualOverflow = std::max(pixelSnappedLogicalBottom() + outsetLogicalBottom, logicalVisualOverflow.maxY()); 836 837 LayoutUnit outsetLogicalLeft = includeLogicalLeftEdge() ? borderOutsetLogicalLeft : LayoutUnit(); 838 LayoutUnit outsetLogicalRight = includeLogicalRightEdge() ? borderOutsetLogicalRight : LayoutUnit(); 839 840 LayoutUnit logicalLeftVisualOverflow = std::min(pixelSnappedLogicalLeft() - outsetLogicalLeft, logicalVisualOverflow.x()); 841 LayoutUnit logicalRightVisualOverflow = std::max(pixelSnappedLogicalRight() + outsetLogicalRight, logicalVisualOverflow.maxX()); 842 843 logicalVisualOverflow = LayoutRect(logicalLeftVisualOverflow, logicalTopVisualOverflow, 844 logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow); 845 } 846 847 inline void InlineFlowBox::addOutlineVisualOverflow(LayoutRect& logicalVisualOverflow) 848 { 849 // Outline on root line boxes is applied to the block and not to the lines. 850 if (!parent()) 851 return; 852 853 RenderStyle* style = renderer().style(isFirstLineStyle()); 854 if (!style->hasOutline()) 855 return; 856 857 logicalVisualOverflow.inflate(style->outlineSize()); 858 } 859 860 inline void InlineFlowBox::addTextBoxVisualOverflow(InlineTextBox* textBox, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, LayoutRect& logicalVisualOverflow) 861 { 862 if (textBox->knownToHaveNoOverflow()) 863 return; 864 865 RenderStyle* style = textBox->renderer().style(isFirstLineStyle()); 866 867 GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.find(textBox); 868 GlyphOverflow* glyphOverflow = it == textBoxDataMap.end() ? 0 : &it->value.second; 869 bool isFlippedLine = style->isFlippedLinesWritingMode(); 870 871 int topGlyphEdge = glyphOverflow ? (isFlippedLine ? glyphOverflow->bottom : glyphOverflow->top) : 0; 872 int bottomGlyphEdge = glyphOverflow ? (isFlippedLine ? glyphOverflow->top : glyphOverflow->bottom) : 0; 873 int leftGlyphEdge = glyphOverflow ? glyphOverflow->left : 0; 874 int rightGlyphEdge = glyphOverflow ? glyphOverflow->right : 0; 875 876 int strokeOverflow = static_cast<int>(ceilf(style->textStrokeWidth() / 2.0f)); 877 int topGlyphOverflow = -strokeOverflow - topGlyphEdge; 878 int bottomGlyphOverflow = strokeOverflow + bottomGlyphEdge; 879 int leftGlyphOverflow = -strokeOverflow - leftGlyphEdge; 880 int rightGlyphOverflow = strokeOverflow + rightGlyphEdge; 881 882 TextEmphasisPosition emphasisMarkPosition; 883 if (style->textEmphasisMark() != TextEmphasisMarkNone && textBox->getEmphasisMarkPosition(style, emphasisMarkPosition)) { 884 int emphasisMarkHeight = style->font().emphasisMarkHeight(style->textEmphasisMarkString()); 885 if ((emphasisMarkPosition == TextEmphasisPositionOver) == (!style->isFlippedLinesWritingMode())) 886 topGlyphOverflow = std::min(topGlyphOverflow, -emphasisMarkHeight); 887 else 888 bottomGlyphOverflow = std::max(bottomGlyphOverflow, emphasisMarkHeight); 889 } 890 891 // If letter-spacing is negative, we should factor that into right layout overflow. (Even in RTL, letter-spacing is 892 // applied to the right, so this is not an issue with left overflow. 893 rightGlyphOverflow -= std::min(0, (int)style->font().fontDescription().letterSpacing()); 894 895 LayoutUnit textShadowLogicalTop; 896 LayoutUnit textShadowLogicalBottom; 897 style->getTextShadowBlockDirectionExtent(textShadowLogicalTop, textShadowLogicalBottom); 898 899 LayoutUnit childOverflowLogicalTop = std::min<LayoutUnit>(textShadowLogicalTop + topGlyphOverflow, topGlyphOverflow); 900 LayoutUnit childOverflowLogicalBottom = std::max<LayoutUnit>(textShadowLogicalBottom + bottomGlyphOverflow, bottomGlyphOverflow); 901 902 LayoutUnit textShadowLogicalLeft; 903 LayoutUnit textShadowLogicalRight; 904 style->getTextShadowInlineDirectionExtent(textShadowLogicalLeft, textShadowLogicalRight); 905 906 LayoutUnit childOverflowLogicalLeft = std::min<LayoutUnit>(textShadowLogicalLeft + leftGlyphOverflow, leftGlyphOverflow); 907 LayoutUnit childOverflowLogicalRight = std::max<LayoutUnit>(textShadowLogicalRight + rightGlyphOverflow, rightGlyphOverflow); 908 909 LayoutUnit logicalTopVisualOverflow = std::min(textBox->pixelSnappedLogicalTop() + childOverflowLogicalTop, logicalVisualOverflow.y()); 910 LayoutUnit logicalBottomVisualOverflow = std::max(textBox->pixelSnappedLogicalBottom() + childOverflowLogicalBottom, logicalVisualOverflow.maxY()); 911 LayoutUnit logicalLeftVisualOverflow = std::min(textBox->pixelSnappedLogicalLeft() + childOverflowLogicalLeft, logicalVisualOverflow.x()); 912 LayoutUnit logicalRightVisualOverflow = std::max(textBox->pixelSnappedLogicalRight() + childOverflowLogicalRight, logicalVisualOverflow.maxX()); 913 914 logicalVisualOverflow = LayoutRect(logicalLeftVisualOverflow, logicalTopVisualOverflow, 915 logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow); 916 917 textBox->setLogicalOverflowRect(logicalVisualOverflow); 918 } 919 920 inline void InlineFlowBox::addReplacedChildOverflow(const InlineBox* inlineBox, LayoutRect& logicalLayoutOverflow, LayoutRect& logicalVisualOverflow) 921 { 922 RenderBox& box = toRenderBox(inlineBox->renderer()); 923 924 // Visual overflow only propagates if the box doesn't have a self-painting layer. This rectangle does not include 925 // transforms or relative positioning (since those objects always have self-painting layers), but it does need to be adjusted 926 // for writing-mode differences. 927 if (!box.hasSelfPaintingLayer()) { 928 LayoutRect childLogicalVisualOverflow = box.logicalVisualOverflowRectForPropagation(renderer().style()); 929 childLogicalVisualOverflow.move(inlineBox->logicalLeft(), inlineBox->logicalTop()); 930 logicalVisualOverflow.unite(childLogicalVisualOverflow); 931 } 932 933 // Layout overflow internal to the child box only propagates if the child box doesn't have overflow clip set. 934 // Otherwise the child border box propagates as layout overflow. This rectangle must include transforms and relative positioning 935 // and be adjusted for writing-mode differences. 936 LayoutRect childLogicalLayoutOverflow = box.logicalLayoutOverflowRectForPropagation(renderer().style()); 937 childLogicalLayoutOverflow.move(inlineBox->logicalLeft(), inlineBox->logicalTop()); 938 logicalLayoutOverflow.unite(childLogicalLayoutOverflow); 939 } 940 941 void InlineFlowBox::computeOverflow(LayoutUnit lineTop, LayoutUnit lineBottom, GlyphOverflowAndFallbackFontsMap& textBoxDataMap) 942 { 943 // If we know we have no overflow, we can just bail. 944 if (knownToHaveNoOverflow()) { 945 ASSERT(!m_overflow); 946 return; 947 } 948 949 if (m_overflow) 950 m_overflow.clear(); 951 952 // Visual overflow just includes overflow for stuff we need to issues paint invalidations for ourselves. Self-painting layers are ignored. 953 // Layout overflow is used to determine scrolling extent, so it still includes child layers and also factors in 954 // transforms, relative positioning, etc. 955 LayoutRect logicalLayoutOverflow(enclosingLayoutRect(logicalFrameRectIncludingLineHeight(lineTop, lineBottom))); 956 LayoutRect logicalVisualOverflow(logicalLayoutOverflow); 957 958 addBoxShadowVisualOverflow(logicalVisualOverflow); 959 addBorderOutsetVisualOverflow(logicalVisualOverflow); 960 addOutlineVisualOverflow(logicalVisualOverflow); 961 962 for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { 963 if (curr->renderer().isOutOfFlowPositioned()) 964 continue; // Positioned placeholders don't affect calculations. 965 966 if (curr->renderer().isText()) { 967 InlineTextBox* text = toInlineTextBox(curr); 968 RenderText& rt = text->renderer(); 969 if (rt.isBR()) 970 continue; 971 LayoutRect textBoxOverflow(enclosingLayoutRect(text->logicalFrameRect())); 972 addTextBoxVisualOverflow(text, textBoxDataMap, textBoxOverflow); 973 logicalVisualOverflow.unite(textBoxOverflow); 974 } else if (curr->renderer().isRenderInline()) { 975 InlineFlowBox* flow = toInlineFlowBox(curr); 976 flow->computeOverflow(lineTop, lineBottom, textBoxDataMap); 977 if (!flow->boxModelObject()->hasSelfPaintingLayer()) 978 logicalVisualOverflow.unite(flow->logicalVisualOverflowRect(lineTop, lineBottom)); 979 LayoutRect childLayoutOverflow = flow->logicalLayoutOverflowRect(lineTop, lineBottom); 980 childLayoutOverflow.move(flow->boxModelObject()->relativePositionLogicalOffset()); 981 logicalLayoutOverflow.unite(childLayoutOverflow); 982 } else { 983 addReplacedChildOverflow(curr, logicalLayoutOverflow, logicalVisualOverflow); 984 } 985 } 986 987 setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow, lineTop, lineBottom); 988 } 989 990 void InlineFlowBox::setLayoutOverflow(const LayoutRect& rect, const LayoutRect& frameBox) 991 { 992 if (frameBox.contains(rect) || rect.isEmpty()) 993 return; 994 995 if (!m_overflow) 996 m_overflow = adoptPtr(new RenderOverflow(frameBox, frameBox)); 997 998 m_overflow->setLayoutOverflow(rect); 999 } 1000 1001 void InlineFlowBox::setVisualOverflow(const LayoutRect& rect, const LayoutRect& frameBox) 1002 { 1003 if (frameBox.contains(rect) || rect.isEmpty()) 1004 return; 1005 1006 if (!m_overflow) 1007 m_overflow = adoptPtr(new RenderOverflow(frameBox, frameBox)); 1008 1009 m_overflow->setVisualOverflow(rect); 1010 } 1011 1012 void InlineFlowBox::setOverflowFromLogicalRects(const LayoutRect& logicalLayoutOverflow, const LayoutRect& logicalVisualOverflow, LayoutUnit lineTop, LayoutUnit lineBottom) 1013 { 1014 LayoutRect frameBox = enclosingLayoutRect(frameRectIncludingLineHeight(lineTop, lineBottom)); 1015 1016 LayoutRect layoutOverflow(isHorizontal() ? logicalLayoutOverflow : logicalLayoutOverflow.transposedRect()); 1017 setLayoutOverflow(layoutOverflow, frameBox); 1018 1019 LayoutRect visualOverflow(isHorizontal() ? logicalVisualOverflow : logicalVisualOverflow.transposedRect()); 1020 setVisualOverflow(visualOverflow, frameBox); 1021 } 1022 1023 bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) 1024 { 1025 LayoutRect overflowRect(visualOverflowRect(lineTop, lineBottom)); 1026 flipForWritingMode(overflowRect); 1027 overflowRect.moveBy(accumulatedOffset); 1028 if (!locationInContainer.intersects(overflowRect)) 1029 return false; 1030 1031 // Check children first. 1032 // We need to account for culled inline parents of the hit-tested nodes, so that they may also get included in area-based hit-tests. 1033 RenderObject* culledParent = 0; 1034 for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) { 1035 if (curr->renderer().isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) { 1036 RenderObject* newParent = 0; 1037 // Culled parents are only relevant for area-based hit-tests, so ignore it in point-based ones. 1038 if (locationInContainer.isRectBasedTest()) { 1039 newParent = curr->renderer().parent(); 1040 if (newParent == renderer()) 1041 newParent = 0; 1042 } 1043 // Check the culled parent after all its children have been checked, to do this we wait until 1044 // we are about to test an element with a different parent. 1045 if (newParent != culledParent) { 1046 if (!newParent || !newParent->isDescendantOf(culledParent)) { 1047 while (culledParent && culledParent != renderer() && culledParent != newParent) { 1048 if (culledParent->isRenderInline() && toRenderInline(culledParent)->hitTestCulledInline(request, result, locationInContainer, accumulatedOffset)) 1049 return true; 1050 culledParent = culledParent->parent(); 1051 } 1052 } 1053 culledParent = newParent; 1054 } 1055 if (curr->nodeAtPoint(request, result, locationInContainer, accumulatedOffset, lineTop, lineBottom)) { 1056 renderer().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); 1057 return true; 1058 } 1059 } 1060 } 1061 // Check any culled ancestor of the final children tested. 1062 while (culledParent && culledParent != renderer()) { 1063 if (culledParent->isRenderInline() && toRenderInline(culledParent)->hitTestCulledInline(request, result, locationInContainer, accumulatedOffset)) 1064 return true; 1065 culledParent = culledParent->parent(); 1066 } 1067 1068 // Now check ourselves. Pixel snap hit testing. 1069 LayoutRect frameRect = roundedFrameRect(); 1070 LayoutUnit minX = frameRect.x(); 1071 LayoutUnit minY = frameRect.y(); 1072 LayoutUnit width = frameRect.width(); 1073 LayoutUnit height = frameRect.height(); 1074 1075 // Constrain our hit testing to the line top and bottom if necessary. 1076 bool noQuirksMode = renderer().document().inNoQuirksMode(); 1077 if (!noQuirksMode && !hasTextChildren() && !(descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants())) { 1078 RootInlineBox& rootBox = root(); 1079 LayoutUnit& top = isHorizontal() ? minY : minX; 1080 LayoutUnit& logicalHeight = isHorizontal() ? height : width; 1081 LayoutUnit bottom = std::min(rootBox.lineBottom(), top + logicalHeight); 1082 top = std::max(rootBox.lineTop(), top); 1083 logicalHeight = bottom - top; 1084 } 1085 1086 // Move x/y to our coordinates. 1087 LayoutRect rect(minX, minY, width, height); 1088 flipForWritingMode(rect); 1089 rect.moveBy(accumulatedOffset); 1090 1091 if (visibleToHitTestRequest(request) && locationInContainer.intersects(rect)) { 1092 renderer().updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(accumulatedOffset))); // Don't add in m_x or m_y here, we want coords in the containing block's space. 1093 if (!result.addNodeToRectBasedTestResult(renderer().node(), request, locationInContainer, rect)) 1094 return true; 1095 } 1096 1097 return false; 1098 } 1099 1100 void InlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom) 1101 { 1102 InlineFlowBoxPainter(*this).paint(paintInfo, paintOffset, lineTop, lineBottom); 1103 } 1104 1105 bool InlineFlowBox::boxShadowCanBeAppliedToBackground(const FillLayer& lastBackgroundLayer) const 1106 { 1107 // The checks here match how paintFillLayer() decides whether to clip (if it does, the shadow 1108 // would be clipped out, so it has to be drawn separately). 1109 StyleImage* image = lastBackgroundLayer.image(); 1110 bool hasFillImage = image && image->canRender(renderer(), renderer().style()->effectiveZoom()); 1111 return (!hasFillImage && !renderer().style()->hasBorderRadius()) || (!prevLineBox() && !nextLineBox()) || !parent(); 1112 } 1113 1114 void InlineFlowBox::constrainToLineTopAndBottomIfNeeded(LayoutRect& rect) const 1115 { 1116 bool noQuirksMode = renderer().document().inNoQuirksMode(); 1117 if (!noQuirksMode && !hasTextChildren() && !(descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants())) { 1118 const RootInlineBox& rootBox = root(); 1119 LayoutUnit logicalTop = isHorizontal() ? rect.y() : rect.x(); 1120 LayoutUnit logicalHeight = isHorizontal() ? rect.height() : rect.width(); 1121 LayoutUnit bottom = std::min(rootBox.lineBottom(), logicalTop + logicalHeight); 1122 logicalTop = std::max(rootBox.lineTop(), logicalTop); 1123 logicalHeight = bottom - logicalTop; 1124 if (isHorizontal()) { 1125 rect.setY(logicalTop); 1126 rect.setHeight(logicalHeight); 1127 } else { 1128 rect.setX(logicalTop); 1129 rect.setWidth(logicalHeight); 1130 } 1131 } 1132 } 1133 1134 InlineBox* InlineFlowBox::firstLeafChild() const 1135 { 1136 InlineBox* leaf = 0; 1137 for (InlineBox* child = firstChild(); child && !leaf; child = child->nextOnLine()) 1138 leaf = child->isLeaf() ? child : toInlineFlowBox(child)->firstLeafChild(); 1139 return leaf; 1140 } 1141 1142 InlineBox* InlineFlowBox::lastLeafChild() const 1143 { 1144 InlineBox* leaf = 0; 1145 for (InlineBox* child = lastChild(); child && !leaf; child = child->prevOnLine()) 1146 leaf = child->isLeaf() ? child : toInlineFlowBox(child)->lastLeafChild(); 1147 return leaf; 1148 } 1149 1150 RenderObject::SelectionState InlineFlowBox::selectionState() const 1151 { 1152 return RenderObject::SelectionNone; 1153 } 1154 1155 bool InlineFlowBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const 1156 { 1157 for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) { 1158 if (!box->canAccommodateEllipsis(ltr, blockEdge, ellipsisWidth)) 1159 return false; 1160 } 1161 return true; 1162 } 1163 1164 float InlineFlowBox::placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, float &truncatedWidth, bool& foundBox) 1165 { 1166 float result = -1; 1167 // We iterate over all children, the foundBox variable tells us when we've found the 1168 // box containing the ellipsis. All boxes after that one in the flow are hidden. 1169 // If our flow is ltr then iterate over the boxes from left to right, otherwise iterate 1170 // from right to left. Varying the order allows us to correctly hide the boxes following the ellipsis. 1171 InlineBox* box = ltr ? firstChild() : lastChild(); 1172 1173 // NOTE: these will cross after foundBox = true. 1174 int visibleLeftEdge = blockLeftEdge; 1175 int visibleRightEdge = blockRightEdge; 1176 1177 while (box) { 1178 int currResult = box->placeEllipsisBox(ltr, visibleLeftEdge, visibleRightEdge, ellipsisWidth, truncatedWidth, foundBox); 1179 if (currResult != -1 && result == -1) 1180 result = currResult; 1181 1182 if (ltr) { 1183 visibleLeftEdge += box->logicalWidth(); 1184 box = box->nextOnLine(); 1185 } 1186 else { 1187 visibleRightEdge -= box->logicalWidth(); 1188 box = box->prevOnLine(); 1189 } 1190 } 1191 return result; 1192 } 1193 1194 void InlineFlowBox::clearTruncation() 1195 { 1196 for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) 1197 box->clearTruncation(); 1198 } 1199 1200 LayoutUnit InlineFlowBox::computeOverAnnotationAdjustment(LayoutUnit allowedPosition) const 1201 { 1202 LayoutUnit result = 0; 1203 for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { 1204 if (curr->renderer().isOutOfFlowPositioned()) 1205 continue; // Positioned placeholders don't affect calculations. 1206 1207 if (curr->isInlineFlowBox()) 1208 result = std::max(result, toInlineFlowBox(curr)->computeOverAnnotationAdjustment(allowedPosition)); 1209 1210 if (curr->renderer().isReplaced() && curr->renderer().isRubyRun() && curr->renderer().style()->rubyPosition() == RubyPositionBefore) { 1211 RenderRubyRun& rubyRun = toRenderRubyRun(curr->renderer()); 1212 RenderRubyText* rubyText = rubyRun.rubyText(); 1213 if (!rubyText) 1214 continue; 1215 1216 if (!rubyRun.style()->isFlippedLinesWritingMode()) { 1217 LayoutUnit topOfFirstRubyTextLine = rubyText->logicalTop() + (rubyText->firstRootBox() ? rubyText->firstRootBox()->lineTop() : LayoutUnit()); 1218 if (topOfFirstRubyTextLine >= 0) 1219 continue; 1220 topOfFirstRubyTextLine += curr->logicalTop(); 1221 result = std::max(result, allowedPosition - topOfFirstRubyTextLine); 1222 } else { 1223 LayoutUnit bottomOfLastRubyTextLine = rubyText->logicalTop() + (rubyText->lastRootBox() ? rubyText->lastRootBox()->lineBottom() : rubyText->logicalHeight()); 1224 if (bottomOfLastRubyTextLine <= curr->logicalHeight()) 1225 continue; 1226 bottomOfLastRubyTextLine += curr->logicalTop(); 1227 result = std::max(result, bottomOfLastRubyTextLine - allowedPosition); 1228 } 1229 } 1230 1231 if (curr->isInlineTextBox()) { 1232 RenderStyle* style = curr->renderer().style(isFirstLineStyle()); 1233 TextEmphasisPosition emphasisMarkPosition; 1234 if (style->textEmphasisMark() != TextEmphasisMarkNone && toInlineTextBox(curr)->getEmphasisMarkPosition(style, emphasisMarkPosition) && emphasisMarkPosition == TextEmphasisPositionOver) { 1235 if (!style->isFlippedLinesWritingMode()) { 1236 int topOfEmphasisMark = curr->logicalTop() - style->font().emphasisMarkHeight(style->textEmphasisMarkString()); 1237 result = std::max(result, allowedPosition - topOfEmphasisMark); 1238 } else { 1239 int bottomOfEmphasisMark = curr->logicalBottom() + style->font().emphasisMarkHeight(style->textEmphasisMarkString()); 1240 result = std::max(result, bottomOfEmphasisMark - allowedPosition); 1241 } 1242 } 1243 } 1244 } 1245 return result; 1246 } 1247 1248 LayoutUnit InlineFlowBox::computeUnderAnnotationAdjustment(LayoutUnit allowedPosition) const 1249 { 1250 LayoutUnit result = 0; 1251 for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { 1252 if (curr->renderer().isOutOfFlowPositioned()) 1253 continue; // Positioned placeholders don't affect calculations. 1254 1255 if (curr->isInlineFlowBox()) 1256 result = std::max(result, toInlineFlowBox(curr)->computeUnderAnnotationAdjustment(allowedPosition)); 1257 1258 if (curr->renderer().isReplaced() && curr->renderer().isRubyRun() && curr->renderer().style()->rubyPosition() == RubyPositionAfter) { 1259 RenderRubyRun& rubyRun = toRenderRubyRun(curr->renderer()); 1260 RenderRubyText* rubyText = rubyRun.rubyText(); 1261 if (!rubyText) 1262 continue; 1263 1264 if (rubyRun.style()->isFlippedLinesWritingMode()) { 1265 LayoutUnit topOfFirstRubyTextLine = rubyText->logicalTop() + (rubyText->firstRootBox() ? rubyText->firstRootBox()->lineTop() : LayoutUnit()); 1266 if (topOfFirstRubyTextLine >= 0) 1267 continue; 1268 topOfFirstRubyTextLine += curr->logicalTop(); 1269 result = std::max(result, allowedPosition - topOfFirstRubyTextLine); 1270 } else { 1271 LayoutUnit bottomOfLastRubyTextLine = rubyText->logicalTop() + (rubyText->lastRootBox() ? rubyText->lastRootBox()->lineBottom() : rubyText->logicalHeight()); 1272 if (bottomOfLastRubyTextLine <= curr->logicalHeight()) 1273 continue; 1274 bottomOfLastRubyTextLine += curr->logicalTop(); 1275 result = std::max(result, bottomOfLastRubyTextLine - allowedPosition); 1276 } 1277 } 1278 1279 if (curr->isInlineTextBox()) { 1280 RenderStyle* style = curr->renderer().style(isFirstLineStyle()); 1281 if (style->textEmphasisMark() != TextEmphasisMarkNone && style->textEmphasisPosition() == TextEmphasisPositionUnder) { 1282 if (!style->isFlippedLinesWritingMode()) { 1283 LayoutUnit bottomOfEmphasisMark = curr->logicalBottom() + style->font().emphasisMarkHeight(style->textEmphasisMarkString()); 1284 result = std::max(result, bottomOfEmphasisMark - allowedPosition); 1285 } else { 1286 LayoutUnit topOfEmphasisMark = curr->logicalTop() - style->font().emphasisMarkHeight(style->textEmphasisMarkString()); 1287 result = std::max(result, allowedPosition - topOfEmphasisMark); 1288 } 1289 } 1290 } 1291 } 1292 return result; 1293 } 1294 1295 void InlineFlowBox::collectLeafBoxesInLogicalOrder(Vector<InlineBox*>& leafBoxesInLogicalOrder, CustomInlineBoxRangeReverse customReverseImplementation, void* userData) const 1296 { 1297 InlineBox* leaf = firstLeafChild(); 1298 1299 // FIXME: The reordering code is a copy of parts from BidiResolver::createBidiRunsForLine, operating directly on InlineBoxes, instead of BidiRuns. 1300 // Investigate on how this code could possibly be shared. 1301 unsigned char minLevel = 128; 1302 unsigned char maxLevel = 0; 1303 1304 // First find highest and lowest levels, and initialize leafBoxesInLogicalOrder with the leaf boxes in visual order. 1305 for (; leaf; leaf = leaf->nextLeafChild()) { 1306 minLevel = std::min(minLevel, leaf->bidiLevel()); 1307 maxLevel = std::max(maxLevel, leaf->bidiLevel()); 1308 leafBoxesInLogicalOrder.append(leaf); 1309 } 1310 1311 if (renderer().style()->rtlOrdering() == VisualOrder) 1312 return; 1313 1314 // Reverse of reordering of the line (L2 according to Bidi spec): 1315 // L2. From the highest level found in the text to the lowest odd level on each line, 1316 // reverse any contiguous sequence of characters that are at that level or higher. 1317 1318 // Reversing the reordering of the line is only done up to the lowest odd level. 1319 if (!(minLevel % 2)) 1320 ++minLevel; 1321 1322 Vector<InlineBox*>::iterator end = leafBoxesInLogicalOrder.end(); 1323 while (minLevel <= maxLevel) { 1324 Vector<InlineBox*>::iterator it = leafBoxesInLogicalOrder.begin(); 1325 while (it != end) { 1326 while (it != end) { 1327 if ((*it)->bidiLevel() >= minLevel) 1328 break; 1329 ++it; 1330 } 1331 Vector<InlineBox*>::iterator first = it; 1332 while (it != end) { 1333 if ((*it)->bidiLevel() < minLevel) 1334 break; 1335 ++it; 1336 } 1337 Vector<InlineBox*>::iterator last = it; 1338 if (customReverseImplementation) { 1339 ASSERT(userData); 1340 (*customReverseImplementation)(userData, first, last); 1341 } else 1342 std::reverse(first, last); 1343 } 1344 ++minLevel; 1345 } 1346 } 1347 1348 #ifndef NDEBUG 1349 1350 const char* InlineFlowBox::boxName() const 1351 { 1352 return "InlineFlowBox"; 1353 } 1354 1355 void InlineFlowBox::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj, int depth) const 1356 { 1357 InlineBox::showLineTreeAndMark(markedBox1, markedLabel1, markedBox2, markedLabel2, obj, depth); 1358 for (const InlineBox* box = firstChild(); box; box = box->nextOnLine()) 1359 box->showLineTreeAndMark(markedBox1, markedLabel1, markedBox2, markedLabel2, obj, depth + 1); 1360 } 1361 1362 #endif 1363 1364 #if ENABLE(ASSERT) 1365 void InlineFlowBox::checkConsistency() const 1366 { 1367 #ifdef CHECK_CONSISTENCY 1368 ASSERT(!m_hasBadChildList); 1369 const InlineBox* prev = 0; 1370 for (const InlineBox* child = m_firstChild; child; child = child->nextOnLine()) { 1371 ASSERT(child->parent() == this); 1372 ASSERT(child->prevOnLine() == prev); 1373 prev = child; 1374 } 1375 ASSERT(prev == m_lastChild); 1376 #endif 1377 } 1378 1379 #endif 1380 1381 } // namespace blink 1382