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