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