1 /* 2 * Copyright (C) 2000 Lars Knoll (knoll (at) kde.org) 3 * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All right reserved. 4 * Copyright (C) 2010 Google Inc. All rights reserved. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public License 17 * along with this library; see the file COPYING.LIB. If not, write to 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #include "config.h" 24 25 #include "core/accessibility/AXObjectCache.h" 26 #include "core/rendering/RenderCounter.h" 27 #include "core/rendering/RenderFlowThread.h" 28 #include "core/rendering/RenderLayer.h" 29 #include "core/rendering/RenderListMarker.h" 30 #include "core/rendering/RenderRegion.h" 31 #include "core/rendering/RenderRubyRun.h" 32 #include "core/rendering/RenderView.h" 33 #include "core/rendering/TrailingFloatsRootInlineBox.h" 34 #include "core/rendering/VerticalPositionCache.h" 35 #include "core/rendering/line/BreakingContextInlineHeaders.h" 36 #include "core/rendering/line/LineLayoutState.h" 37 #include "core/rendering/line/LineWidth.h" 38 #include "core/rendering/line/RenderTextInfo.h" 39 #include "core/rendering/line/WordMeasurement.h" 40 #include "core/rendering/svg/SVGRootInlineBox.h" 41 #include "platform/fonts/Character.h" 42 #include "platform/text/BidiResolver.h" 43 #include "wtf/RefCountedLeakCounter.h" 44 #include "wtf/StdLibExtras.h" 45 #include "wtf/Vector.h" 46 #include "wtf/unicode/CharacterNames.h" 47 48 namespace WebCore { 49 50 using namespace std; 51 using namespace WTF::Unicode; 52 53 static RenderObject* firstRenderObjectForDirectionalityDetermination(RenderObject* root, RenderObject* current = 0) 54 { 55 RenderObject* next = current; 56 while (current) { 57 if (isIsolated(current->style()->unicodeBidi()) 58 && (current->isRenderInline() || current->isRenderBlock())) { 59 if (current != root) 60 current = 0; 61 else 62 current = next; 63 break; 64 } 65 current = current->parent(); 66 } 67 68 if (!current) 69 current = root->slowFirstChild(); 70 71 while (current) { 72 next = 0; 73 if (isIteratorTarget(current) && !(current->isText() && toRenderText(current)->isAllCollapsibleWhitespace())) 74 break; 75 76 if (!isIteratorTarget(current) && !isIsolated(current->style()->unicodeBidi())) 77 next = current->slowFirstChild(); 78 79 if (!next) { 80 while (current && current != root) { 81 next = current->nextSibling(); 82 if (next) 83 break; 84 current = current->parent(); 85 } 86 } 87 88 if (!next) 89 break; 90 91 current = next; 92 } 93 94 return current; 95 } 96 97 static TextDirection determinePlaintextDirectionality(RenderObject* root, RenderObject* current = 0, unsigned pos = 0) 98 { 99 InlineIterator iter(root, firstRenderObjectForDirectionalityDetermination(root, current), pos); 100 InlineBidiResolver observer; 101 observer.setStatus(BidiStatus(root->style()->direction(), isOverride(root->style()->unicodeBidi()))); 102 observer.setPositionIgnoringNestedIsolates(iter); 103 return observer.determineParagraphDirectionality(); 104 } 105 106 static inline InlineBox* createInlineBoxForRenderer(RenderObject* obj, bool isRootLineBox, bool isOnlyRun = false) 107 { 108 if (isRootLineBox) 109 return toRenderBlockFlow(obj)->createAndAppendRootInlineBox(); 110 111 if (obj->isText()) { 112 InlineTextBox* textBox = toRenderText(obj)->createInlineTextBox(); 113 // We only treat a box as text for a <br> if we are on a line by ourself or in strict mode 114 // (Note the use of strict mode. In "almost strict" mode, we don't treat the box for <br> as text.) 115 if (obj->isBR()) 116 textBox->setIsText(isOnlyRun || obj->document().inNoQuirksMode()); 117 return textBox; 118 } 119 120 if (obj->isBox()) 121 return toRenderBox(obj)->createInlineBox(); 122 123 return toRenderInline(obj)->createAndAppendInlineFlowBox(); 124 } 125 126 static inline void dirtyLineBoxesForRenderer(RenderObject* o, bool fullLayout) 127 { 128 if (o->isText()) { 129 RenderText* renderText = toRenderText(o); 130 renderText->dirtyLineBoxes(fullLayout); 131 } else 132 toRenderInline(o)->dirtyLineBoxes(fullLayout); 133 } 134 135 static bool parentIsConstructedOrHaveNext(InlineFlowBox* parentBox) 136 { 137 do { 138 if (parentBox->isConstructed() || parentBox->nextOnLine()) 139 return true; 140 parentBox = parentBox->parent(); 141 } while (parentBox); 142 return false; 143 } 144 145 InlineFlowBox* RenderBlockFlow::createLineBoxes(RenderObject* obj, const LineInfo& lineInfo, InlineBox* childBox) 146 { 147 // See if we have an unconstructed line box for this object that is also 148 // the last item on the line. 149 unsigned lineDepth = 1; 150 InlineFlowBox* parentBox = 0; 151 InlineFlowBox* result = 0; 152 bool hasDefaultLineBoxContain = style()->lineBoxContain() == RenderStyle::initialLineBoxContain(); 153 do { 154 ASSERT_WITH_SECURITY_IMPLICATION(obj->isRenderInline() || obj == this); 155 156 RenderInline* inlineFlow = (obj != this) ? toRenderInline(obj) : 0; 157 158 // Get the last box we made for this render object. 159 parentBox = inlineFlow ? inlineFlow->lastLineBox() : toRenderBlock(obj)->lastLineBox(); 160 161 // If this box or its ancestor is constructed then it is from a previous line, and we need 162 // to make a new box for our line. If this box or its ancestor is unconstructed but it has 163 // something following it on the line, then we know we have to make a new box 164 // as well. In this situation our inline has actually been split in two on 165 // the same line (this can happen with very fancy language mixtures). 166 bool constructedNewBox = false; 167 bool allowedToConstructNewBox = !hasDefaultLineBoxContain || !inlineFlow || inlineFlow->alwaysCreateLineBoxes(); 168 bool canUseExistingParentBox = parentBox && !parentIsConstructedOrHaveNext(parentBox); 169 if (allowedToConstructNewBox && !canUseExistingParentBox) { 170 // We need to make a new box for this render object. Once 171 // made, we need to place it at the end of the current line. 172 InlineBox* newBox = createInlineBoxForRenderer(obj, obj == this); 173 ASSERT_WITH_SECURITY_IMPLICATION(newBox->isInlineFlowBox()); 174 parentBox = toInlineFlowBox(newBox); 175 parentBox->setFirstLineStyleBit(lineInfo.isFirstLine()); 176 parentBox->setIsHorizontal(isHorizontalWritingMode()); 177 if (!hasDefaultLineBoxContain) 178 parentBox->clearDescendantsHaveSameLineHeightAndBaseline(); 179 constructedNewBox = true; 180 } 181 182 if (constructedNewBox || canUseExistingParentBox) { 183 if (!result) 184 result = parentBox; 185 186 // If we have hit the block itself, then |box| represents the root 187 // inline box for the line, and it doesn't have to be appended to any parent 188 // inline. 189 if (childBox) 190 parentBox->addToLine(childBox); 191 192 if (!constructedNewBox || obj == this) 193 break; 194 195 childBox = parentBox; 196 } 197 198 // If we've exceeded our line depth, then jump straight to the root and skip all the remaining 199 // intermediate inline flows. 200 obj = (++lineDepth >= cMaxLineDepth) ? this : obj->parent(); 201 202 } while (true); 203 204 return result; 205 } 206 207 template <typename CharacterType> 208 static inline bool endsWithASCIISpaces(const CharacterType* characters, unsigned pos, unsigned end) 209 { 210 while (isASCIISpace(characters[pos])) { 211 pos++; 212 if (pos >= end) 213 return true; 214 } 215 return false; 216 } 217 218 static bool reachedEndOfTextRenderer(const BidiRunList<BidiRun>& bidiRuns) 219 { 220 BidiRun* run = bidiRuns.logicallyLastRun(); 221 if (!run) 222 return true; 223 unsigned pos = run->stop(); 224 RenderObject* r = run->m_object; 225 if (!r->isText() || r->isBR()) 226 return false; 227 RenderText* renderText = toRenderText(r); 228 unsigned length = renderText->textLength(); 229 if (pos >= length) 230 return true; 231 232 if (renderText->is8Bit()) 233 return endsWithASCIISpaces(renderText->characters8(), pos, length); 234 return endsWithASCIISpaces(renderText->characters16(), pos, length); 235 } 236 237 RootInlineBox* RenderBlockFlow::constructLine(BidiRunList<BidiRun>& bidiRuns, const LineInfo& lineInfo) 238 { 239 ASSERT(bidiRuns.firstRun()); 240 241 bool rootHasSelectedChildren = false; 242 InlineFlowBox* parentBox = 0; 243 int runCount = bidiRuns.runCount() - lineInfo.runsFromLeadingWhitespace(); 244 for (BidiRun* r = bidiRuns.firstRun(); r; r = r->next()) { 245 // Create a box for our object. 246 bool isOnlyRun = (runCount == 1); 247 if (runCount == 2 && !r->m_object->isListMarker()) 248 isOnlyRun = (!style()->isLeftToRightDirection() ? bidiRuns.lastRun() : bidiRuns.firstRun())->m_object->isListMarker(); 249 250 if (lineInfo.isEmpty()) 251 continue; 252 253 InlineBox* box = createInlineBoxForRenderer(r->m_object, false, isOnlyRun); 254 r->m_box = box; 255 256 ASSERT(box); 257 if (!box) 258 continue; 259 260 if (!rootHasSelectedChildren && box->renderer().selectionState() != RenderObject::SelectionNone) 261 rootHasSelectedChildren = true; 262 263 // If we have no parent box yet, or if the run is not simply a sibling, 264 // then we need to construct inline boxes as necessary to properly enclose the 265 // run's inline box. Segments can only be siblings at the root level, as 266 // they are positioned separately. 267 if (!parentBox || parentBox->renderer() != r->m_object->parent()) { 268 // Create new inline boxes all the way back to the appropriate insertion point. 269 parentBox = createLineBoxes(r->m_object->parent(), lineInfo, box); 270 } else { 271 // Append the inline box to this line. 272 parentBox->addToLine(box); 273 } 274 275 bool visuallyOrdered = r->m_object->style()->rtlOrdering() == VisualOrder; 276 box->setBidiLevel(r->level()); 277 278 if (box->isInlineTextBox()) { 279 InlineTextBox* text = toInlineTextBox(box); 280 text->setStart(r->m_start); 281 text->setLen(r->m_stop - r->m_start); 282 text->setDirOverride(r->dirOverride(visuallyOrdered)); 283 if (r->m_hasHyphen) 284 text->setHasHyphen(true); 285 286 if (AXObjectCache* cache = document().existingAXObjectCache()) 287 cache->inlineTextBoxesUpdated(r->m_object); 288 } 289 } 290 291 // We should have a root inline box. It should be unconstructed and 292 // be the last continuation of our line list. 293 ASSERT(lastLineBox() && !lastLineBox()->isConstructed()); 294 295 // Set the m_selectedChildren flag on the root inline box if one of the leaf inline box 296 // from the bidi runs walk above has a selection state. 297 if (rootHasSelectedChildren) 298 lastLineBox()->root().setHasSelectedChildren(true); 299 300 // Set bits on our inline flow boxes that indicate which sides should 301 // paint borders/margins/padding. This knowledge will ultimately be used when 302 // we determine the horizontal positions and widths of all the inline boxes on 303 // the line. 304 bool isLogicallyLastRunWrapped = bidiRuns.logicallyLastRun()->m_object && bidiRuns.logicallyLastRun()->m_object->isText() ? !reachedEndOfTextRenderer(bidiRuns) : true; 305 lastLineBox()->determineSpacingForFlowBoxes(lineInfo.isLastLine(), isLogicallyLastRunWrapped, bidiRuns.logicallyLastRun()->m_object); 306 307 // Now mark the line boxes as being constructed. 308 lastLineBox()->setConstructed(); 309 310 // Return the last line. 311 return lastRootBox(); 312 } 313 314 ETextAlign RenderBlockFlow::textAlignmentForLine(bool endsWithSoftBreak) const 315 { 316 ETextAlign alignment = style()->textAlign(); 317 if (endsWithSoftBreak) 318 return alignment; 319 320 if (!RuntimeEnabledFeatures::css3TextEnabled()) 321 return (alignment == JUSTIFY) ? TASTART : alignment; 322 323 TextAlignLast alignmentLast = style()->textAlignLast(); 324 switch (alignmentLast) { 325 case TextAlignLastStart: 326 return TASTART; 327 case TextAlignLastEnd: 328 return TAEND; 329 case TextAlignLastLeft: 330 return LEFT; 331 case TextAlignLastRight: 332 return RIGHT; 333 case TextAlignLastCenter: 334 return CENTER; 335 case TextAlignLastJustify: 336 return JUSTIFY; 337 case TextAlignLastAuto: 338 if (alignment != JUSTIFY) 339 return alignment; 340 if (style()->textJustify() == TextJustifyDistribute) 341 return JUSTIFY; 342 return TASTART; 343 } 344 345 return alignment; 346 } 347 348 static void updateLogicalWidthForLeftAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth) 349 { 350 // The direction of the block should determine what happens with wide lines. 351 // In particular with RTL blocks, wide lines should still spill out to the left. 352 if (isLeftToRightDirection) { 353 if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun) 354 trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth)); 355 return; 356 } 357 358 if (trailingSpaceRun) 359 trailingSpaceRun->m_box->setLogicalWidth(0); 360 else if (totalLogicalWidth > availableLogicalWidth) 361 logicalLeft -= (totalLogicalWidth - availableLogicalWidth); 362 } 363 364 static void updateLogicalWidthForRightAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth) 365 { 366 // Wide lines spill out of the block based off direction. 367 // So even if text-align is right, if direction is LTR, wide lines should overflow out of the right 368 // side of the block. 369 if (isLeftToRightDirection) { 370 if (trailingSpaceRun) { 371 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth(); 372 trailingSpaceRun->m_box->setLogicalWidth(0); 373 } 374 if (totalLogicalWidth < availableLogicalWidth) 375 logicalLeft += availableLogicalWidth - totalLogicalWidth; 376 return; 377 } 378 379 if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun) { 380 trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth)); 381 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth(); 382 } else 383 logicalLeft += availableLogicalWidth - totalLogicalWidth; 384 } 385 386 static void updateLogicalWidthForCenterAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth) 387 { 388 float trailingSpaceWidth = 0; 389 if (trailingSpaceRun) { 390 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth(); 391 trailingSpaceWidth = min(trailingSpaceRun->m_box->logicalWidth(), (availableLogicalWidth - totalLogicalWidth + 1) / 2); 392 trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceWidth)); 393 } 394 if (isLeftToRightDirection) 395 logicalLeft += max<float>((availableLogicalWidth - totalLogicalWidth) / 2, 0); 396 else 397 logicalLeft += totalLogicalWidth > availableLogicalWidth ? (availableLogicalWidth - totalLogicalWidth) : (availableLogicalWidth - totalLogicalWidth) / 2 - trailingSpaceWidth; 398 } 399 400 void RenderBlockFlow::setMarginsForRubyRun(BidiRun* run, RenderRubyRun* renderer, RenderObject* previousObject, const LineInfo& lineInfo) 401 { 402 int startOverhang; 403 int endOverhang; 404 RenderObject* nextObject = 0; 405 for (BidiRun* runWithNextObject = run->next(); runWithNextObject; runWithNextObject = runWithNextObject->next()) { 406 if (!runWithNextObject->m_object->isOutOfFlowPositioned() && !runWithNextObject->m_box->isLineBreak()) { 407 nextObject = runWithNextObject->m_object; 408 break; 409 } 410 } 411 renderer->getOverhang(lineInfo.isFirstLine(), renderer->style()->isLeftToRightDirection() ? previousObject : nextObject, renderer->style()->isLeftToRightDirection() ? nextObject : previousObject, startOverhang, endOverhang); 412 setMarginStartForChild(renderer, -startOverhang); 413 setMarginEndForChild(renderer, -endOverhang); 414 } 415 416 static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* run, RenderText* renderer, float xPos, const LineInfo& lineInfo, 417 GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, WordMeasurements& wordMeasurements) 418 { 419 HashSet<const SimpleFontData*> fallbackFonts; 420 GlyphOverflow glyphOverflow; 421 422 const Font& font = renderer->style(lineInfo.isFirstLine())->font(); 423 // Always compute glyph overflow if the block's line-box-contain value is "glyphs". 424 if (lineBox->fitsToGlyphs()) { 425 // If we don't stick out of the root line's font box, then don't bother computing our glyph overflow. This optimization 426 // will keep us from computing glyph bounds in nearly all cases. 427 bool includeRootLine = lineBox->includesRootLineBoxFontOrLeading(); 428 int baselineShift = lineBox->verticalPositionForBox(run->m_box, verticalPositionCache); 429 int rootDescent = includeRootLine ? font.fontMetrics().descent() : 0; 430 int rootAscent = includeRootLine ? font.fontMetrics().ascent() : 0; 431 int boxAscent = font.fontMetrics().ascent() - baselineShift; 432 int boxDescent = font.fontMetrics().descent() + baselineShift; 433 if (boxAscent > rootDescent || boxDescent > rootAscent) 434 glyphOverflow.computeBounds = true; 435 } 436 437 LayoutUnit hyphenWidth = 0; 438 if (toInlineTextBox(run->m_box)->hasHyphen()) { 439 const Font& font = renderer->style(lineInfo.isFirstLine())->font(); 440 hyphenWidth = measureHyphenWidth(renderer, font, run->direction()); 441 } 442 float measuredWidth = 0; 443 444 bool kerningIsEnabled = font.fontDescription().typesettingFeatures() & Kerning; 445 446 #if OS(MACOSX) 447 // FIXME: Having any font feature settings enabled can lead to selection gaps on 448 // Chromium-mac. https://bugs.webkit.org/show_bug.cgi?id=113418 449 bool canUseSimpleFontCodePath = renderer->canUseSimpleFontCodePath() && !font.fontDescription().featureSettings(); 450 #else 451 bool canUseSimpleFontCodePath = renderer->canUseSimpleFontCodePath(); 452 #endif 453 454 // Since we don't cache glyph overflows, we need to re-measure the run if 455 // the style is linebox-contain: glyph. 456 457 if (!lineBox->fitsToGlyphs() && canUseSimpleFontCodePath) { 458 int lastEndOffset = run->m_start; 459 for (size_t i = 0, size = wordMeasurements.size(); i < size && lastEndOffset < run->m_stop; ++i) { 460 const WordMeasurement& wordMeasurement = wordMeasurements[i]; 461 if (wordMeasurement.width <=0 || wordMeasurement.startOffset == wordMeasurement.endOffset) 462 continue; 463 if (wordMeasurement.renderer != renderer || wordMeasurement.startOffset != lastEndOffset || wordMeasurement.endOffset > run->m_stop) 464 continue; 465 466 lastEndOffset = wordMeasurement.endOffset; 467 if (kerningIsEnabled && lastEndOffset == run->m_stop) { 468 int wordLength = lastEndOffset - wordMeasurement.startOffset; 469 measuredWidth += renderer->width(wordMeasurement.startOffset, wordLength, xPos, run->direction(), lineInfo.isFirstLine()); 470 if (i > 0 && wordLength == 1 && renderer->characterAt(wordMeasurement.startOffset) == ' ') 471 measuredWidth += renderer->style()->wordSpacing(); 472 } else 473 measuredWidth += wordMeasurement.width; 474 if (!wordMeasurement.fallbackFonts.isEmpty()) { 475 HashSet<const SimpleFontData*>::const_iterator end = wordMeasurement.fallbackFonts.end(); 476 for (HashSet<const SimpleFontData*>::const_iterator it = wordMeasurement.fallbackFonts.begin(); it != end; ++it) 477 fallbackFonts.add(*it); 478 } 479 } 480 if (measuredWidth && lastEndOffset != run->m_stop) { 481 // If we don't have enough cached data, we'll measure the run again. 482 measuredWidth = 0; 483 fallbackFonts.clear(); 484 } 485 } 486 487 if (!measuredWidth) 488 measuredWidth = renderer->width(run->m_start, run->m_stop - run->m_start, xPos, run->direction(), lineInfo.isFirstLine(), &fallbackFonts, &glyphOverflow); 489 490 run->m_box->setLogicalWidth(measuredWidth + hyphenWidth); 491 if (!fallbackFonts.isEmpty()) { 492 ASSERT(run->m_box->isText()); 493 GlyphOverflowAndFallbackFontsMap::ValueType* it = textBoxDataMap.add(toInlineTextBox(run->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).storedValue; 494 ASSERT(it->value.first.isEmpty()); 495 copyToVector(fallbackFonts, it->value.first); 496 run->m_box->parent()->clearDescendantsHaveSameLineHeightAndBaseline(); 497 } 498 if ((glyphOverflow.top || glyphOverflow.bottom || glyphOverflow.left || glyphOverflow.right)) { 499 ASSERT(run->m_box->isText()); 500 GlyphOverflowAndFallbackFontsMap::ValueType* it = textBoxDataMap.add(toInlineTextBox(run->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).storedValue; 501 it->value.second = glyphOverflow; 502 run->m_box->clearKnownToHaveNoOverflow(); 503 } 504 } 505 506 static inline void computeExpansionForJustifiedText(BidiRun* firstRun, BidiRun* trailingSpaceRun, Vector<unsigned, 16>& expansionOpportunities, unsigned expansionOpportunityCount, float& totalLogicalWidth, float availableLogicalWidth) 507 { 508 if (!expansionOpportunityCount || availableLogicalWidth <= totalLogicalWidth) 509 return; 510 511 size_t i = 0; 512 for (BidiRun* r = firstRun; r; r = r->next()) { 513 if (!r->m_box || r == trailingSpaceRun) 514 continue; 515 516 if (r->m_object->isText()) { 517 unsigned opportunitiesInRun = expansionOpportunities[i++]; 518 519 ASSERT(opportunitiesInRun <= expansionOpportunityCount); 520 521 // Don't justify for white-space: pre. 522 if (r->m_object->style()->whiteSpace() != PRE) { 523 InlineTextBox* textBox = toInlineTextBox(r->m_box); 524 int expansion = (availableLogicalWidth - totalLogicalWidth) * opportunitiesInRun / expansionOpportunityCount; 525 textBox->setExpansion(expansion); 526 totalLogicalWidth += expansion; 527 } 528 expansionOpportunityCount -= opportunitiesInRun; 529 if (!expansionOpportunityCount) 530 break; 531 } 532 } 533 } 534 535 void RenderBlockFlow::updateLogicalWidthForAlignment(const ETextAlign& textAlign, const RootInlineBox* rootInlineBox, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float& availableLogicalWidth, unsigned expansionOpportunityCount) 536 { 537 TextDirection direction; 538 if (rootInlineBox && rootInlineBox->renderer().style()->unicodeBidi() == Plaintext) 539 direction = rootInlineBox->direction(); 540 else 541 direction = style()->direction(); 542 543 // Armed with the total width of the line (without justification), 544 // we now examine our text-align property in order to determine where to position the 545 // objects horizontally. The total width of the line can be increased if we end up 546 // justifying text. 547 switch (textAlign) { 548 case LEFT: 549 case WEBKIT_LEFT: 550 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth); 551 break; 552 case RIGHT: 553 case WEBKIT_RIGHT: 554 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth); 555 break; 556 case CENTER: 557 case WEBKIT_CENTER: 558 updateLogicalWidthForCenterAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth); 559 break; 560 case JUSTIFY: 561 adjustInlineDirectionLineBounds(expansionOpportunityCount, logicalLeft, availableLogicalWidth); 562 if (expansionOpportunityCount) { 563 if (trailingSpaceRun) { 564 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth(); 565 trailingSpaceRun->m_box->setLogicalWidth(0); 566 } 567 break; 568 } 569 // Fall through 570 case TASTART: 571 if (direction == LTR) 572 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth); 573 else 574 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth); 575 break; 576 case TAEND: 577 if (direction == LTR) 578 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth); 579 else 580 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth); 581 break; 582 } 583 if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) 584 logicalLeft += verticalScrollbarWidth(); 585 } 586 587 static void updateLogicalInlinePositions(RenderBlockFlow* block, float& lineLogicalLeft, float& lineLogicalRight, float& availableLogicalWidth, bool firstLine, IndentTextOrNot shouldIndentText, LayoutUnit boxLogicalHeight) 588 { 589 LayoutUnit lineLogicalHeight = block->minLineHeightForReplacedRenderer(firstLine, boxLogicalHeight); 590 lineLogicalLeft = block->logicalLeftOffsetForLine(block->logicalHeight(), shouldIndentText == IndentText, lineLogicalHeight).toFloat(); 591 lineLogicalRight = block->logicalRightOffsetForLine(block->logicalHeight(), shouldIndentText == IndentText, lineLogicalHeight).toFloat(); 592 availableLogicalWidth = lineLogicalRight - lineLogicalLeft; 593 } 594 595 void RenderBlockFlow::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, const LineInfo& lineInfo, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd, 596 GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, WordMeasurements& wordMeasurements) 597 { 598 ETextAlign textAlign = textAlignmentForLine(!reachedEnd && !lineBox->endsWithBreak()); 599 600 // CSS 2.1: "'Text-indent' only affects a line if it is the first formatted line of an element. For example, the first line of an anonymous block 601 // box is only affected if it is the first child of its parent element." 602 // CSS3 "text-indent", "each-line" affects the first line of the block container as well as each line after a forced line break, 603 // but does not affect lines after a soft wrap break. 604 bool isFirstLine = lineInfo.isFirstLine() && !(isAnonymousBlock() && parent()->slowFirstChild() != this); 605 bool isAfterHardLineBreak = lineBox->prevRootBox() && lineBox->prevRootBox()->endsWithBreak(); 606 IndentTextOrNot shouldIndentText = requiresIndent(isFirstLine, isAfterHardLineBreak, style()); 607 float lineLogicalLeft; 608 float lineLogicalRight; 609 float availableLogicalWidth; 610 updateLogicalInlinePositions(this, lineLogicalLeft, lineLogicalRight, availableLogicalWidth, isFirstLine, shouldIndentText, 0); 611 bool needsWordSpacing; 612 613 if (firstRun && firstRun->m_object->isReplaced()) { 614 RenderBox* renderBox = toRenderBox(firstRun->m_object); 615 updateLogicalInlinePositions(this, lineLogicalLeft, lineLogicalRight, availableLogicalWidth, isFirstLine, shouldIndentText, renderBox->logicalHeight()); 616 } 617 618 computeInlineDirectionPositionsForSegment(lineBox, lineInfo, textAlign, lineLogicalLeft, availableLogicalWidth, firstRun, trailingSpaceRun, textBoxDataMap, verticalPositionCache, wordMeasurements); 619 // The widths of all runs are now known. We can now place every inline box (and 620 // compute accurate widths for the inline flow boxes). 621 needsWordSpacing = false; 622 lineBox->placeBoxesInInlineDirection(lineLogicalLeft, needsWordSpacing, textBoxDataMap); 623 } 624 625 BidiRun* RenderBlockFlow::computeInlineDirectionPositionsForSegment(RootInlineBox* lineBox, const LineInfo& lineInfo, ETextAlign textAlign, float& logicalLeft, 626 float& availableLogicalWidth, BidiRun* firstRun, BidiRun* trailingSpaceRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, 627 WordMeasurements& wordMeasurements) 628 { 629 bool needsWordSpacing = true; 630 float totalLogicalWidth = lineBox->getFlowSpacingLogicalWidth().toFloat(); 631 unsigned expansionOpportunityCount = 0; 632 bool isAfterExpansion = true; 633 Vector<unsigned, 16> expansionOpportunities; 634 RenderObject* previousObject = 0; 635 TextJustify textJustify = style()->textJustify(); 636 637 BidiRun* r = firstRun; 638 for (; r; r = r->next()) { 639 if (!r->m_box || r->m_object->isOutOfFlowPositioned() || r->m_box->isLineBreak()) 640 continue; // Positioned objects are only participating to figure out their 641 // correct static x position. They have no effect on the width. 642 // Similarly, line break boxes have no effect on the width. 643 if (r->m_object->isText()) { 644 RenderText* rt = toRenderText(r->m_object); 645 if (textAlign == JUSTIFY && r != trailingSpaceRun && textJustify != TextJustifyNone) { 646 if (!isAfterExpansion) 647 toInlineTextBox(r->m_box)->setCanHaveLeadingExpansion(true); 648 unsigned opportunitiesInRun; 649 if (rt->is8Bit()) 650 opportunitiesInRun = Character::expansionOpportunityCount(rt->characters8() + r->m_start, r->m_stop - r->m_start, r->m_box->direction(), isAfterExpansion); 651 else 652 opportunitiesInRun = Character::expansionOpportunityCount(rt->characters16() + r->m_start, r->m_stop - r->m_start, r->m_box->direction(), isAfterExpansion); 653 expansionOpportunities.append(opportunitiesInRun); 654 expansionOpportunityCount += opportunitiesInRun; 655 } 656 657 if (rt->textLength()) { 658 if (!r->m_start && needsWordSpacing && isSpaceOrNewline(rt->characterAt(r->m_start))) 659 totalLogicalWidth += rt->style(lineInfo.isFirstLine())->font().fontDescription().wordSpacing(); 660 needsWordSpacing = !isSpaceOrNewline(rt->characterAt(r->m_stop - 1)); 661 } 662 663 setLogicalWidthForTextRun(lineBox, r, rt, totalLogicalWidth, lineInfo, textBoxDataMap, verticalPositionCache, wordMeasurements); 664 } else { 665 isAfterExpansion = false; 666 if (!r->m_object->isRenderInline()) { 667 RenderBox* renderBox = toRenderBox(r->m_object); 668 if (renderBox->isRubyRun()) 669 setMarginsForRubyRun(r, toRenderRubyRun(renderBox), previousObject, lineInfo); 670 r->m_box->setLogicalWidth(logicalWidthForChild(renderBox).toFloat()); 671 totalLogicalWidth += marginStartForChild(renderBox) + marginEndForChild(renderBox); 672 } 673 } 674 675 totalLogicalWidth += r->m_box->logicalWidth(); 676 previousObject = r->m_object; 677 } 678 679 if (isAfterExpansion && !expansionOpportunities.isEmpty()) { 680 expansionOpportunities.last()--; 681 expansionOpportunityCount--; 682 } 683 684 updateLogicalWidthForAlignment(textAlign, lineBox, trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth, expansionOpportunityCount); 685 686 computeExpansionForJustifiedText(firstRun, trailingSpaceRun, expansionOpportunities, expansionOpportunityCount, totalLogicalWidth, availableLogicalWidth); 687 688 return r; 689 } 690 691 void RenderBlockFlow::computeBlockDirectionPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, 692 VerticalPositionCache& verticalPositionCache) 693 { 694 setLogicalHeight(lineBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache)); 695 696 // Now make sure we place replaced render objects correctly. 697 for (BidiRun* r = firstRun; r; r = r->next()) { 698 ASSERT(r->m_box); 699 if (!r->m_box) 700 continue; // Skip runs with no line boxes. 701 702 // Align positioned boxes with the top of the line box. This is 703 // a reasonable approximation of an appropriate y position. 704 if (r->m_object->isOutOfFlowPositioned()) 705 r->m_box->setLogicalTop(logicalHeight().toFloat()); 706 707 // Position is used to properly position both replaced elements and 708 // to update the static normal flow x/y of positioned elements. 709 if (r->m_object->isText()) 710 toRenderText(r->m_object)->positionLineBox(r->m_box); 711 else if (r->m_object->isBox()) 712 toRenderBox(r->m_object)->positionLineBox(r->m_box); 713 } 714 } 715 716 void RenderBlockFlow::appendFloatingObjectToLastLine(FloatingObject* floatingObject) 717 { 718 ASSERT(!floatingObject->originatingLine()); 719 floatingObject->setOriginatingLine(lastRootBox()); 720 lastRootBox()->appendFloat(floatingObject->renderer()); 721 } 722 723 // FIXME: This should be a BidiStatus constructor or create method. 724 static inline BidiStatus statusWithDirection(TextDirection textDirection, bool isOverride) 725 { 726 WTF::Unicode::Direction direction = textDirection == LTR ? LeftToRight : RightToLeft; 727 RefPtr<BidiContext> context = BidiContext::create(textDirection == LTR ? 0 : 1, direction, isOverride, FromStyleOrDOM); 728 729 // This copies BidiStatus and may churn the ref on BidiContext I doubt it matters. 730 return BidiStatus(direction, direction, direction, context.release()); 731 } 732 733 static inline void setupResolverToResumeInIsolate(InlineBidiResolver& resolver, RenderObject* root, RenderObject* startObject) 734 { 735 if (root != startObject) { 736 RenderObject* parent = startObject->parent(); 737 setupResolverToResumeInIsolate(resolver, root, parent); 738 notifyObserverEnteredObject(&resolver, startObject); 739 } 740 } 741 742 static void restoreIsolatedMidpointStates(InlineBidiResolver& topResolver, InlineBidiResolver& isolatedResolver) 743 { 744 while (!isolatedResolver.isolatedRuns().isEmpty()) { 745 BidiRun* run = isolatedResolver.isolatedRuns().last(); 746 isolatedResolver.isolatedRuns().removeLast(); 747 topResolver.setMidpointStateForIsolatedRun(run, isolatedResolver.midpointStateForIsolatedRun(run)); 748 } 749 } 750 751 // FIXME: BidiResolver should have this logic. 752 static inline void constructBidiRunsForLine(const RenderBlockFlow* block, InlineBidiResolver& topResolver, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& endOfLine, VisualDirectionOverride override, bool previousLineBrokeCleanly, bool isNewUBAParagraph) 753 { 754 // FIXME: We should pass a BidiRunList into createBidiRunsForLine instead 755 // of the resolver owning the runs. 756 ASSERT(&topResolver.runs() == &bidiRuns); 757 ASSERT(topResolver.position() != endOfLine); 758 RenderObject* currentRoot = topResolver.position().root(); 759 topResolver.createBidiRunsForLine(endOfLine, override, previousLineBrokeCleanly); 760 761 while (!topResolver.isolatedRuns().isEmpty()) { 762 // It does not matter which order we resolve the runs as long as we resolve them all. 763 BidiRun* isolatedRun = topResolver.isolatedRuns().last(); 764 topResolver.isolatedRuns().removeLast(); 765 766 RenderObject* startObj = isolatedRun->object(); 767 768 // Only inlines make sense with unicode-bidi: isolate (blocks are already isolated). 769 // FIXME: Because enterIsolate is not passed a RenderObject, we have to crawl up the 770 // tree to see which parent inline is the isolate. We could change enterIsolate 771 // to take a RenderObject and do this logic there, but that would be a layering 772 // violation for BidiResolver (which knows nothing about RenderObject). 773 RenderInline* isolatedInline = toRenderInline(highestContainingIsolateWithinRoot(startObj, currentRoot)); 774 ASSERT(isolatedInline); 775 776 InlineBidiResolver isolatedResolver; 777 LineMidpointState& isolatedLineMidpointState = isolatedResolver.midpointState(); 778 isolatedLineMidpointState = topResolver.midpointStateForIsolatedRun(isolatedRun); 779 EUnicodeBidi unicodeBidi = isolatedInline->style()->unicodeBidi(); 780 TextDirection direction; 781 if (unicodeBidi == Plaintext) { 782 if (isNewUBAParagraph) 783 direction = determinePlaintextDirectionality(isolatedInline, startObj); 784 else 785 direction = determinePlaintextDirectionality(isolatedInline); 786 } else { 787 ASSERT(unicodeBidi == Isolate || unicodeBidi == IsolateOverride); 788 direction = isolatedInline->style()->direction(); 789 } 790 isolatedResolver.setStatus(statusWithDirection(direction, isOverride(unicodeBidi))); 791 792 setupResolverToResumeInIsolate(isolatedResolver, isolatedInline, startObj); 793 794 // The starting position is the beginning of the first run within the isolate that was identified 795 // during the earlier call to createBidiRunsForLine. This can be but is not necessarily the 796 // first run within the isolate. 797 InlineIterator iter = InlineIterator(isolatedInline, startObj, isolatedRun->m_start); 798 isolatedResolver.setPositionIgnoringNestedIsolates(iter); 799 // We stop at the next end of line; we may re-enter this isolate in the next call to constructBidiRuns(). 800 // FIXME: What should end and previousLineBrokeCleanly be? 801 // rniwa says previousLineBrokeCleanly is just a WinIE hack and could always be false here? 802 isolatedResolver.createBidiRunsForLine(endOfLine, NoVisualOverride, previousLineBrokeCleanly); 803 804 ASSERT(isolatedResolver.runs().runCount()); 805 if (isolatedResolver.runs().runCount()) 806 bidiRuns.replaceRunWithRuns(isolatedRun, isolatedResolver.runs()); 807 808 // If we encountered any nested isolate runs, just move them 809 // to the top resolver's list for later processing. 810 if (!isolatedResolver.isolatedRuns().isEmpty()) { 811 topResolver.isolatedRuns().appendVector(isolatedResolver.isolatedRuns()); 812 currentRoot = isolatedInline; 813 restoreIsolatedMidpointStates(topResolver, isolatedResolver); 814 } 815 } 816 } 817 818 // This function constructs line boxes for all of the text runs in the resolver and computes their position. 819 RootInlineBox* RenderBlockFlow::createLineBoxesFromBidiRuns(unsigned bidiLevel, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& end, LineInfo& lineInfo, VerticalPositionCache& verticalPositionCache, BidiRun* trailingSpaceRun, WordMeasurements& wordMeasurements) 820 { 821 if (!bidiRuns.runCount()) 822 return 0; 823 824 // FIXME: Why is this only done when we had runs? 825 lineInfo.setLastLine(!end.object()); 826 827 RootInlineBox* lineBox = constructLine(bidiRuns, lineInfo); 828 if (!lineBox) 829 return 0; 830 831 lineBox->setBidiLevel(bidiLevel); 832 lineBox->setEndsWithBreak(lineInfo.previousLineBrokeCleanly()); 833 834 bool isSVGRootInlineBox = lineBox->isSVGRootInlineBox(); 835 836 GlyphOverflowAndFallbackFontsMap textBoxDataMap; 837 838 // Now we position all of our text runs horizontally. 839 if (!isSVGRootInlineBox) 840 computeInlineDirectionPositionsForLine(lineBox, lineInfo, bidiRuns.firstRun(), trailingSpaceRun, end.atEnd(), textBoxDataMap, verticalPositionCache, wordMeasurements); 841 842 // Now position our text runs vertically. 843 computeBlockDirectionPositionsForLine(lineBox, bidiRuns.firstRun(), textBoxDataMap, verticalPositionCache); 844 845 // SVG text layout code computes vertical & horizontal positions on its own. 846 // Note that we still need to execute computeVerticalPositionsForLine() as 847 // it calls InlineTextBox::positionLineBox(), which tracks whether the box 848 // contains reversed text or not. If we wouldn't do that editing and thus 849 // text selection in RTL boxes would not work as expected. 850 if (isSVGRootInlineBox) { 851 ASSERT(isSVGText()); 852 toSVGRootInlineBox(lineBox)->computePerCharacterLayoutInformation(); 853 } 854 855 // Compute our overflow now. 856 lineBox->computeOverflow(lineBox->lineTop(), lineBox->lineBottom(), textBoxDataMap); 857 858 return lineBox; 859 } 860 861 static void deleteLineRange(LineLayoutState& layoutState, RootInlineBox* startLine, RootInlineBox* stopLine = 0) 862 { 863 RootInlineBox* boxToDelete = startLine; 864 while (boxToDelete && boxToDelete != stopLine) { 865 layoutState.updateRepaintRangeFromBox(boxToDelete); 866 // Note: deleteLineRange(firstRootBox()) is not identical to deleteLineBoxTree(). 867 // deleteLineBoxTree uses nextLineBox() instead of nextRootBox() when traversing. 868 RootInlineBox* next = boxToDelete->nextRootBox(); 869 boxToDelete->deleteLine(); 870 boxToDelete = next; 871 } 872 } 873 874 void RenderBlockFlow::layoutRunsAndFloats(LineLayoutState& layoutState) 875 { 876 // We want to skip ahead to the first dirty line 877 InlineBidiResolver resolver; 878 RootInlineBox* startLine = determineStartPosition(layoutState, resolver); 879 880 unsigned consecutiveHyphenatedLines = 0; 881 if (startLine) { 882 for (RootInlineBox* line = startLine->prevRootBox(); line && line->isHyphenated(); line = line->prevRootBox()) 883 consecutiveHyphenatedLines++; 884 } 885 886 if (containsFloats()) 887 layoutState.setLastFloat(m_floatingObjects->set().last().get()); 888 889 // We also find the first clean line and extract these lines. We will add them back 890 // if we determine that we're able to synchronize after handling all our dirty lines. 891 InlineIterator cleanLineStart; 892 BidiStatus cleanLineBidiStatus; 893 if (!layoutState.isFullLayout() && startLine) 894 determineEndPosition(layoutState, startLine, cleanLineStart, cleanLineBidiStatus); 895 896 if (startLine) { 897 if (!layoutState.usesRepaintBounds()) 898 layoutState.setRepaintRange(logicalHeight()); 899 deleteLineRange(layoutState, startLine); 900 } 901 902 if (!layoutState.isFullLayout() && lastRootBox() && lastRootBox()->endsWithBreak()) { 903 // If the last line before the start line ends with a line break that clear floats, 904 // adjust the height accordingly. 905 // A line break can be either the first or the last object on a line, depending on its direction. 906 if (InlineBox* lastLeafChild = lastRootBox()->lastLeafChild()) { 907 RenderObject* lastObject = &lastLeafChild->renderer(); 908 if (!lastObject->isBR()) 909 lastObject = &lastRootBox()->firstLeafChild()->renderer(); 910 if (lastObject->isBR()) { 911 EClear clear = lastObject->style()->clear(); 912 if (clear != CNONE) 913 clearFloats(clear); 914 } 915 } 916 } 917 918 layoutRunsAndFloatsInRange(layoutState, resolver, cleanLineStart, cleanLineBidiStatus, consecutiveHyphenatedLines); 919 linkToEndLineIfNeeded(layoutState); 920 repaintDirtyFloats(layoutState.floats()); 921 } 922 923 // Before restarting the layout loop with a new logicalHeight, remove all floats that were added and reset the resolver. 924 inline const InlineIterator& RenderBlockFlow::restartLayoutRunsAndFloatsInRange(LayoutUnit oldLogicalHeight, LayoutUnit newLogicalHeight, FloatingObject* lastFloatFromPreviousLine, InlineBidiResolver& resolver, const InlineIterator& oldEnd) 925 { 926 removeFloatingObjectsBelow(lastFloatFromPreviousLine, oldLogicalHeight); 927 setLogicalHeight(newLogicalHeight); 928 resolver.setPositionIgnoringNestedIsolates(oldEnd); 929 return oldEnd; 930 } 931 932 void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, InlineBidiResolver& resolver, const InlineIterator& cleanLineStart, const BidiStatus& cleanLineBidiStatus, unsigned consecutiveHyphenatedLines) 933 { 934 RenderStyle* styleToUse = style(); 935 bool paginated = view()->layoutState() && view()->layoutState()->isPaginated(); 936 LineMidpointState& lineMidpointState = resolver.midpointState(); 937 InlineIterator endOfLine = resolver.position(); 938 bool checkForEndLineMatch = layoutState.endLine(); 939 RenderTextInfo renderTextInfo; 940 VerticalPositionCache verticalPositionCache; 941 942 LineBreaker lineBreaker(this); 943 944 LayoutSize logicalOffsetFromShapeContainer; 945 946 while (!endOfLine.atEnd()) { 947 // FIXME: Is this check necessary before the first iteration or can it be moved to the end? 948 if (checkForEndLineMatch) { 949 layoutState.setEndLineMatched(matchedEndLine(layoutState, resolver, cleanLineStart, cleanLineBidiStatus)); 950 if (layoutState.endLineMatched()) { 951 resolver.setPosition(InlineIterator(resolver.position().root(), 0, 0), 0); 952 break; 953 } 954 } 955 956 lineMidpointState.reset(); 957 958 layoutState.lineInfo().setEmpty(true); 959 layoutState.lineInfo().resetRunsFromLeadingWhitespace(); 960 961 const InlineIterator previousEndofLine = endOfLine; 962 bool isNewUBAParagraph = layoutState.lineInfo().previousLineBrokeCleanly(); 963 FloatingObject* lastFloatFromPreviousLine = (containsFloats()) ? m_floatingObjects->set().last().get() : 0; 964 965 WordMeasurements wordMeasurements; 966 endOfLine = lineBreaker.nextLineBreak(resolver, layoutState.lineInfo(), renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements); 967 renderTextInfo.m_lineBreakIterator.resetPriorContext(); 968 if (resolver.position().atEnd()) { 969 // FIXME: We shouldn't be creating any runs in nextLineBreak to begin with! 970 // Once BidiRunList is separated from BidiResolver this will not be needed. 971 resolver.runs().deleteRuns(); 972 resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed). 973 layoutState.setCheckForFloatsFromLastLine(true); 974 resolver.setPosition(InlineIterator(resolver.position().root(), 0, 0), 0); 975 break; 976 } 977 978 ASSERT(endOfLine != resolver.position()); 979 980 // This is a short-cut for empty lines. 981 if (layoutState.lineInfo().isEmpty()) { 982 if (lastRootBox()) 983 lastRootBox()->setLineBreakInfo(endOfLine.object(), endOfLine.offset(), resolver.status()); 984 } else { 985 VisualDirectionOverride override = (styleToUse->rtlOrdering() == VisualOrder ? (styleToUse->direction() == LTR ? VisualLeftToRightOverride : VisualRightToLeftOverride) : NoVisualOverride); 986 if (isNewUBAParagraph && styleToUse->unicodeBidi() == Plaintext && !resolver.context()->parent()) { 987 TextDirection direction = determinePlaintextDirectionality(resolver.position().root(), resolver.position().object(), resolver.position().offset()); 988 resolver.setStatus(BidiStatus(direction, isOverride(styleToUse->unicodeBidi()))); 989 } 990 // FIXME: This ownership is reversed. We should own the BidiRunList and pass it to createBidiRunsForLine. 991 BidiRunList<BidiRun>& bidiRuns = resolver.runs(); 992 constructBidiRunsForLine(this, resolver, bidiRuns, endOfLine, override, layoutState.lineInfo().previousLineBrokeCleanly(), isNewUBAParagraph); 993 ASSERT(resolver.position() == endOfLine); 994 995 BidiRun* trailingSpaceRun = resolver.trailingSpaceRun(); 996 997 if (bidiRuns.runCount() && lineBreaker.lineWasHyphenated()) { 998 bidiRuns.logicallyLastRun()->m_hasHyphen = true; 999 consecutiveHyphenatedLines++; 1000 } else 1001 consecutiveHyphenatedLines = 0; 1002 1003 // Now that the runs have been ordered, we create the line boxes. 1004 // At the same time we figure out where border/padding/margin should be applied for 1005 // inline flow boxes. 1006 1007 LayoutUnit oldLogicalHeight = logicalHeight(); 1008 RootInlineBox* lineBox = createLineBoxesFromBidiRuns(resolver.status().context->level(), bidiRuns, endOfLine, layoutState.lineInfo(), verticalPositionCache, trailingSpaceRun, wordMeasurements); 1009 1010 bidiRuns.deleteRuns(); 1011 resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed). 1012 1013 if (lineBox) { 1014 lineBox->setLineBreakInfo(endOfLine.object(), endOfLine.offset(), resolver.status()); 1015 if (layoutState.usesRepaintBounds()) 1016 layoutState.updateRepaintRangeFromBox(lineBox); 1017 1018 if (paginated) { 1019 LayoutUnit adjustment = 0; 1020 adjustLinePositionForPagination(lineBox, adjustment, layoutState.flowThread()); 1021 if (adjustment) { 1022 LayoutUnit oldLineWidth = availableLogicalWidthForLine(oldLogicalHeight, layoutState.lineInfo().isFirstLine()); 1023 lineBox->adjustBlockDirectionPosition(adjustment.toFloat()); 1024 if (layoutState.usesRepaintBounds()) 1025 layoutState.updateRepaintRangeFromBox(lineBox); 1026 1027 if (availableLogicalWidthForLine(oldLogicalHeight + adjustment, layoutState.lineInfo().isFirstLine()) != oldLineWidth) { 1028 // We have to delete this line, remove all floats that got added, and let line layout re-run. 1029 lineBox->deleteLine(); 1030 endOfLine = restartLayoutRunsAndFloatsInRange(oldLogicalHeight, oldLogicalHeight + adjustment, lastFloatFromPreviousLine, resolver, previousEndofLine); 1031 continue; 1032 } 1033 1034 setLogicalHeight(lineBox->lineBottomWithLeading()); 1035 } 1036 } 1037 } 1038 } 1039 1040 for (size_t i = 0; i < lineBreaker.positionedObjects().size(); ++i) 1041 setStaticPositions(this, lineBreaker.positionedObjects()[i]); 1042 1043 if (!layoutState.lineInfo().isEmpty()) { 1044 layoutState.lineInfo().setFirstLine(false); 1045 clearFloats(lineBreaker.clear()); 1046 } 1047 1048 if (m_floatingObjects && lastRootBox()) { 1049 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 1050 FloatingObjectSetIterator it = floatingObjectSet.begin(); 1051 FloatingObjectSetIterator end = floatingObjectSet.end(); 1052 if (layoutState.lastFloat()) { 1053 FloatingObjectSetIterator lastFloatIterator = floatingObjectSet.find(layoutState.lastFloat()); 1054 ASSERT(lastFloatIterator != end); 1055 ++lastFloatIterator; 1056 it = lastFloatIterator; 1057 } 1058 for (; it != end; ++it) { 1059 FloatingObject* f = it->get(); 1060 appendFloatingObjectToLastLine(f); 1061 ASSERT(f->renderer() == layoutState.floats()[layoutState.floatIndex()].object); 1062 // If a float's geometry has changed, give up on syncing with clean lines. 1063 if (layoutState.floats()[layoutState.floatIndex()].rect != f->frameRect()) 1064 checkForEndLineMatch = false; 1065 layoutState.setFloatIndex(layoutState.floatIndex() + 1); 1066 } 1067 layoutState.setLastFloat(!floatingObjectSet.isEmpty() ? floatingObjectSet.last().get() : 0); 1068 } 1069 1070 lineMidpointState.reset(); 1071 resolver.setPosition(endOfLine, numberOfIsolateAncestors(endOfLine)); 1072 } 1073 1074 // In case we already adjusted the line positions during this layout to avoid widows 1075 // then we need to ignore the possibility of having a new widows situation. 1076 // Otherwise, we risk leaving empty containers which is against the block fragmentation principles. 1077 if (paginated && !style()->hasAutoWidows() && !didBreakAtLineToAvoidWidow()) { 1078 // Check the line boxes to make sure we didn't create unacceptable widows. 1079 // However, we'll prioritize orphans - so nothing we do here should create 1080 // a new orphan. 1081 1082 RootInlineBox* lineBox = lastRootBox(); 1083 1084 // Count from the end of the block backwards, to see how many hanging 1085 // lines we have. 1086 RootInlineBox* firstLineInBlock = firstRootBox(); 1087 int numLinesHanging = 1; 1088 while (lineBox && lineBox != firstLineInBlock && !lineBox->isFirstAfterPageBreak()) { 1089 ++numLinesHanging; 1090 lineBox = lineBox->prevRootBox(); 1091 } 1092 1093 // If there were no breaks in the block, we didn't create any widows. 1094 if (!lineBox || !lineBox->isFirstAfterPageBreak() || lineBox == firstLineInBlock) 1095 return; 1096 1097 if (numLinesHanging < style()->widows()) { 1098 // We have detected a widow. Now we need to work out how many 1099 // lines there are on the previous page, and how many we need 1100 // to steal. 1101 int numLinesNeeded = style()->widows() - numLinesHanging; 1102 RootInlineBox* currentFirstLineOfNewPage = lineBox; 1103 1104 // Count the number of lines in the previous page. 1105 lineBox = lineBox->prevRootBox(); 1106 int numLinesInPreviousPage = 1; 1107 while (lineBox && lineBox != firstLineInBlock && !lineBox->isFirstAfterPageBreak()) { 1108 ++numLinesInPreviousPage; 1109 lineBox = lineBox->prevRootBox(); 1110 } 1111 1112 // If there was an explicit value for orphans, respect that. If not, we still 1113 // shouldn't create a situation where we make an orphan bigger than the initial value. 1114 // This means that setting widows implies we also care about orphans, but given 1115 // the specification says the initial orphan value is non-zero, this is ok. The 1116 // author is always free to set orphans explicitly as well. 1117 int orphans = style()->hasAutoOrphans() ? style()->initialOrphans() : style()->orphans(); 1118 int numLinesAvailable = numLinesInPreviousPage - orphans; 1119 if (numLinesAvailable <= 0) 1120 return; 1121 1122 int numLinesToTake = min(numLinesAvailable, numLinesNeeded); 1123 // Wind back from our first widowed line. 1124 lineBox = currentFirstLineOfNewPage; 1125 for (int i = 0; i < numLinesToTake; ++i) 1126 lineBox = lineBox->prevRootBox(); 1127 1128 // We now want to break at this line. Remember for next layout and trigger relayout. 1129 setBreakAtLineToAvoidWidow(lineCount(lineBox)); 1130 markLinesDirtyInBlockRange(lastRootBox()->lineBottomWithLeading(), lineBox->lineBottomWithLeading(), lineBox); 1131 } 1132 } 1133 1134 clearDidBreakAtLineToAvoidWidow(); 1135 } 1136 1137 void RenderBlockFlow::linkToEndLineIfNeeded(LineLayoutState& layoutState) 1138 { 1139 if (layoutState.endLine()) { 1140 if (layoutState.endLineMatched()) { 1141 bool paginated = view()->layoutState() && view()->layoutState()->isPaginated(); 1142 // Attach all the remaining lines, and then adjust their y-positions as needed. 1143 LayoutUnit delta = logicalHeight() - layoutState.endLineLogicalTop(); 1144 for (RootInlineBox* line = layoutState.endLine(); line; line = line->nextRootBox()) { 1145 line->attachLine(); 1146 if (paginated) { 1147 delta -= line->paginationStrut(); 1148 adjustLinePositionForPagination(line, delta, layoutState.flowThread()); 1149 } 1150 if (delta) { 1151 layoutState.updateRepaintRangeFromBox(line, delta); 1152 line->adjustBlockDirectionPosition(delta.toFloat()); 1153 } 1154 if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) { 1155 Vector<RenderBox*>::iterator end = cleanLineFloats->end(); 1156 for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) { 1157 FloatingObject* floatingObject = insertFloatingObject(*f); 1158 ASSERT(!floatingObject->originatingLine()); 1159 floatingObject->setOriginatingLine(line); 1160 setLogicalHeight(logicalTopForChild(*f) - marginBeforeForChild(*f) + delta); 1161 positionNewFloats(); 1162 } 1163 } 1164 } 1165 setLogicalHeight(lastRootBox()->lineBottomWithLeading()); 1166 } else { 1167 // Delete all the remaining lines. 1168 deleteLineRange(layoutState, layoutState.endLine()); 1169 } 1170 } 1171 1172 if (m_floatingObjects && (layoutState.checkForFloatsFromLastLine() || positionNewFloats()) && lastRootBox()) { 1173 // In case we have a float on the last line, it might not be positioned up to now. 1174 // This has to be done before adding in the bottom border/padding, or the float will 1175 // include the padding incorrectly. -dwh 1176 if (layoutState.checkForFloatsFromLastLine()) { 1177 LayoutUnit bottomVisualOverflow = lastRootBox()->logicalBottomVisualOverflow(); 1178 LayoutUnit bottomLayoutOverflow = lastRootBox()->logicalBottomLayoutOverflow(); 1179 TrailingFloatsRootInlineBox* trailingFloatsLineBox = new TrailingFloatsRootInlineBox(*this); 1180 m_lineBoxes.appendLineBox(trailingFloatsLineBox); 1181 trailingFloatsLineBox->setConstructed(); 1182 GlyphOverflowAndFallbackFontsMap textBoxDataMap; 1183 VerticalPositionCache verticalPositionCache; 1184 LayoutUnit blockLogicalHeight = logicalHeight(); 1185 trailingFloatsLineBox->alignBoxesInBlockDirection(blockLogicalHeight, textBoxDataMap, verticalPositionCache); 1186 trailingFloatsLineBox->setLineTopBottomPositions(blockLogicalHeight, blockLogicalHeight, blockLogicalHeight, blockLogicalHeight); 1187 trailingFloatsLineBox->setPaginatedLineWidth(availableLogicalWidthForContent()); 1188 LayoutRect logicalLayoutOverflow(0, blockLogicalHeight, 1, bottomLayoutOverflow - blockLogicalHeight); 1189 LayoutRect logicalVisualOverflow(0, blockLogicalHeight, 1, bottomVisualOverflow - blockLogicalHeight); 1190 trailingFloatsLineBox->setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow, trailingFloatsLineBox->lineTop(), trailingFloatsLineBox->lineBottom()); 1191 } 1192 1193 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 1194 FloatingObjectSetIterator it = floatingObjectSet.begin(); 1195 FloatingObjectSetIterator end = floatingObjectSet.end(); 1196 if (layoutState.lastFloat()) { 1197 FloatingObjectSetIterator lastFloatIterator = floatingObjectSet.find(layoutState.lastFloat()); 1198 ASSERT(lastFloatIterator != end); 1199 ++lastFloatIterator; 1200 it = lastFloatIterator; 1201 } 1202 for (; it != end; ++it) 1203 appendFloatingObjectToLastLine(it->get()); 1204 layoutState.setLastFloat(!floatingObjectSet.isEmpty() ? floatingObjectSet.last().get() : 0); 1205 } 1206 } 1207 1208 void RenderBlockFlow::repaintDirtyFloats(Vector<FloatWithRect>& floats) 1209 { 1210 size_t floatCount = floats.size(); 1211 // Floats that did not have layout did not paint invalidations when we laid them out. They would have 1212 // painted by now if they had moved, but if they stayed at (0, 0), they still need to be 1213 // painted. 1214 for (size_t i = 0; i < floatCount; ++i) { 1215 if (!floats[i].everHadLayout) { 1216 RenderBox* f = floats[i].object; 1217 if (!f->x() && !f->y() && f->checkForPaintInvalidation()) { 1218 if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) 1219 f->setShouldDoFullPaintInvalidationAfterLayout(true); 1220 else 1221 f->paintInvalidationForWholeRenderer(); 1222 } 1223 } 1224 } 1225 } 1226 1227 struct InlineMinMaxIterator { 1228 /* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to 1229 inline min/max width calculations. Note the following about the way it walks: 1230 (1) Positioned content is skipped (since it does not contribute to min/max width of a block) 1231 (2) We do not drill into the children of floats or replaced elements, since you can't break 1232 in the middle of such an element. 1233 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have 1234 distinct borders/margin/padding that contribute to the min/max width. 1235 */ 1236 RenderObject* parent; 1237 RenderObject* current; 1238 bool endOfInline; 1239 1240 InlineMinMaxIterator(RenderObject* p, bool end = false) 1241 : parent(p), current(p), endOfInline(end) 1242 { 1243 1244 } 1245 1246 RenderObject* next(); 1247 }; 1248 1249 RenderObject* InlineMinMaxIterator::next() 1250 { 1251 RenderObject* result = 0; 1252 bool oldEndOfInline = endOfInline; 1253 endOfInline = false; 1254 while (current || current == parent) { 1255 if (!oldEndOfInline && (current == parent || (!current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned()))) 1256 result = current->slowFirstChild(); 1257 1258 if (!result) { 1259 // We hit the end of our inline. (It was empty, e.g., <span></span>.) 1260 if (!oldEndOfInline && current->isRenderInline()) { 1261 result = current; 1262 endOfInline = true; 1263 break; 1264 } 1265 1266 while (current && current != parent) { 1267 result = current->nextSibling(); 1268 if (result) 1269 break; 1270 current = current->parent(); 1271 if (current && current != parent && current->isRenderInline()) { 1272 result = current; 1273 endOfInline = true; 1274 break; 1275 } 1276 } 1277 } 1278 1279 if (!result) 1280 break; 1281 1282 if (!result->isOutOfFlowPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isRenderInline())) 1283 break; 1284 1285 current = result; 1286 result = 0; 1287 } 1288 1289 // Update our position. 1290 current = result; 1291 return current; 1292 } 1293 1294 static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit) 1295 { 1296 if (cssUnit.type() != Auto) 1297 return (cssUnit.isFixed() ? static_cast<LayoutUnit>(cssUnit.value()) : childValue); 1298 return 0; 1299 } 1300 1301 static LayoutUnit getBorderPaddingMargin(RenderBoxModelObject* child, bool endOfInline) 1302 { 1303 RenderStyle* childStyle = child->style(); 1304 if (endOfInline) { 1305 return getBPMWidth(child->marginEnd(), childStyle->marginEnd()) + 1306 getBPMWidth(child->paddingEnd(), childStyle->paddingEnd()) + 1307 child->borderEnd(); 1308 } 1309 return getBPMWidth(child->marginStart(), childStyle->marginStart()) + 1310 getBPMWidth(child->paddingStart(), childStyle->paddingStart()) + 1311 child->borderStart(); 1312 } 1313 1314 static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, RenderObject* trailingSpaceChild) 1315 { 1316 if (trailingSpaceChild && trailingSpaceChild->isText()) { 1317 // Collapse away the trailing space at the end of a block. 1318 RenderText* t = toRenderText(trailingSpaceChild); 1319 const UChar space = ' '; 1320 const Font& font = t->style()->font(); // FIXME: This ignores first-line. 1321 float spaceWidth = font.width(RenderBlockFlow::constructTextRun(t, font, &space, 1, t->style(), LTR)); 1322 inlineMax -= spaceWidth + font.fontDescription().wordSpacing(); 1323 if (inlineMin > inlineMax) 1324 inlineMin = inlineMax; 1325 } 1326 } 1327 1328 static inline void updatePreferredWidth(LayoutUnit& preferredWidth, float& result) 1329 { 1330 LayoutUnit snappedResult = LayoutUnit::fromFloatCeil(result); 1331 preferredWidth = max(snappedResult, preferredWidth); 1332 } 1333 1334 // When converting between floating point and LayoutUnits we risk losing precision 1335 // with each conversion. When this occurs while accumulating our preferred widths, 1336 // we can wind up with a line width that's larger than our maxPreferredWidth due to 1337 // pure float accumulation. 1338 static inline LayoutUnit adjustFloatForSubPixelLayout(float value) 1339 { 1340 return LayoutUnit::fromFloatCeil(value); 1341 } 1342 1343 // FIXME: This function should be broken into something less monolithic. 1344 // FIXME: The main loop here is very similar to LineBreaker::nextSegmentBreak. They can probably reuse code. 1345 void RenderBlockFlow::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) 1346 { 1347 float inlineMax = 0; 1348 float inlineMin = 0; 1349 1350 RenderStyle* styleToUse = style(); 1351 RenderBlock* containingBlock = this->containingBlock(); 1352 LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit(); 1353 1354 // If we are at the start of a line, we want to ignore all white-space. 1355 // Also strip spaces if we previously had text that ended in a trailing space. 1356 bool stripFrontSpaces = true; 1357 RenderObject* trailingSpaceChild = 0; 1358 1359 // Firefox and Opera will allow a table cell to grow to fit an image inside it under 1360 // very specific cirucumstances (in order to match common WinIE renderings). 1361 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.) 1362 bool allowImagesToBreak = !document().inQuirksMode() || !isTableCell() || !styleToUse->logicalWidth().isIntrinsicOrAuto(); 1363 1364 bool autoWrap, oldAutoWrap; 1365 autoWrap = oldAutoWrap = styleToUse->autoWrap(); 1366 1367 InlineMinMaxIterator childIterator(this); 1368 1369 // Only gets added to the max preffered width once. 1370 bool addedTextIndent = false; 1371 // Signals the text indent was more negative than the min preferred width 1372 bool hasRemainingNegativeTextIndent = false; 1373 1374 LayoutUnit textIndent = minimumValueForLength(styleToUse->textIndent(), cw); 1375 RenderObject* prevFloat = 0; 1376 bool isPrevChildInlineFlow = false; 1377 bool shouldBreakLineAfterText = false; 1378 while (RenderObject* child = childIterator.next()) { 1379 autoWrap = child->isReplaced() ? child->parent()->style()->autoWrap() : 1380 child->style()->autoWrap(); 1381 1382 if (!child->isBR()) { 1383 // Step One: determine whether or not we need to go ahead and 1384 // terminate our current line. Each discrete chunk can become 1385 // the new min-width, if it is the widest chunk seen so far, and 1386 // it can also become the max-width. 1387 1388 // Children fall into three categories: 1389 // (1) An inline flow object. These objects always have a min/max of 0, 1390 // and are included in the iteration solely so that their margins can 1391 // be added in. 1392 // 1393 // (2) An inline non-text non-flow object, e.g., an inline replaced element. 1394 // These objects can always be on a line by themselves, so in this situation 1395 // we need to go ahead and break the current line, and then add in our own 1396 // margins and min/max width on its own line, and then terminate the line. 1397 // 1398 // (3) A text object. Text runs can have breakable characters at the start, 1399 // the middle or the end. They may also lose whitespace off the front if 1400 // we're already ignoring whitespace. In order to compute accurate min-width 1401 // information, we need three pieces of information. 1402 // (a) the min-width of the first non-breakable run. Should be 0 if the text string 1403 // starts with whitespace. 1404 // (b) the min-width of the last non-breakable run. Should be 0 if the text string 1405 // ends with whitespace. 1406 // (c) the min/max width of the string (trimmed for whitespace). 1407 // 1408 // If the text string starts with whitespace, then we need to go ahead and 1409 // terminate our current line (unless we're already in a whitespace stripping 1410 // mode. 1411 // 1412 // If the text string has a breakable character in the middle, but didn't start 1413 // with whitespace, then we add the width of the first non-breakable run and 1414 // then end the current line. We then need to use the intermediate min/max width 1415 // values (if any of them are larger than our current min/max). We then look at 1416 // the width of the last non-breakable run and use that to start a new line 1417 // (unless we end in whitespace). 1418 RenderStyle* childStyle = child->style(); 1419 float childMin = 0; 1420 float childMax = 0; 1421 1422 if (!child->isText()) { 1423 // Case (1) and (2). Inline replaced and inline flow elements. 1424 if (child->isRenderInline()) { 1425 // Add in padding/border/margin from the appropriate side of 1426 // the element. 1427 float bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline).toFloat(); 1428 childMin += bpm; 1429 childMax += bpm; 1430 1431 inlineMin += childMin; 1432 inlineMax += childMax; 1433 1434 child->clearPreferredLogicalWidthsDirty(); 1435 } else { 1436 // Inline replaced elts add in their margins to their min/max values. 1437 LayoutUnit margins = 0; 1438 Length startMargin = childStyle->marginStart(); 1439 Length endMargin = childStyle->marginEnd(); 1440 if (startMargin.isFixed()) 1441 margins += adjustFloatForSubPixelLayout(startMargin.value()); 1442 if (endMargin.isFixed()) 1443 margins += adjustFloatForSubPixelLayout(endMargin.value()); 1444 childMin += margins.ceilToFloat(); 1445 childMax += margins.ceilToFloat(); 1446 } 1447 } 1448 1449 if (!child->isRenderInline() && !child->isText()) { 1450 // Case (2). Inline replaced elements and floats. 1451 // Go ahead and terminate the current line as far as 1452 // minwidth is concerned. 1453 LayoutUnit childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth; 1454 if (child->isBox() && child->isHorizontalWritingMode() != isHorizontalWritingMode()) { 1455 RenderBox* childBox = toRenderBox(child); 1456 LogicalExtentComputedValues computedValues; 1457 childBox->computeLogicalHeight(childBox->borderAndPaddingLogicalHeight(), 0, computedValues); 1458 childMinPreferredLogicalWidth = childMaxPreferredLogicalWidth = computedValues.m_extent; 1459 } else { 1460 childMinPreferredLogicalWidth = child->minPreferredLogicalWidth(); 1461 childMaxPreferredLogicalWidth = child->maxPreferredLogicalWidth(); 1462 } 1463 childMin += childMinPreferredLogicalWidth.ceilToFloat(); 1464 childMax += childMaxPreferredLogicalWidth.ceilToFloat(); 1465 1466 bool clearPreviousFloat; 1467 if (child->isFloating()) { 1468 clearPreviousFloat = (prevFloat 1469 && ((prevFloat->style()->floating() == LeftFloat && (childStyle->clear() & CLEFT)) 1470 || (prevFloat->style()->floating() == RightFloat && (childStyle->clear() & CRIGHT)))); 1471 prevFloat = child; 1472 } else { 1473 clearPreviousFloat = false; 1474 } 1475 1476 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak; 1477 if ((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat) { 1478 updatePreferredWidth(minLogicalWidth, inlineMin); 1479 inlineMin = 0; 1480 } 1481 1482 // If we're supposed to clear the previous float, then terminate maxwidth as well. 1483 if (clearPreviousFloat) { 1484 updatePreferredWidth(maxLogicalWidth, inlineMax); 1485 inlineMax = 0; 1486 } 1487 1488 // Add in text-indent. This is added in only once. 1489 if (!addedTextIndent && !child->isFloating()) { 1490 float ceiledTextIndent = textIndent.ceilToFloat(); 1491 childMin += ceiledTextIndent; 1492 childMax += ceiledTextIndent; 1493 1494 if (childMin < 0) 1495 textIndent = adjustFloatForSubPixelLayout(childMin); 1496 else 1497 addedTextIndent = true; 1498 } 1499 1500 // Add our width to the max. 1501 inlineMax += max<float>(0, childMax); 1502 1503 if (!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText)) { 1504 if (child->isFloating()) 1505 updatePreferredWidth(minLogicalWidth, childMin); 1506 else 1507 inlineMin += childMin; 1508 } else { 1509 // Now check our line. 1510 updatePreferredWidth(minLogicalWidth, childMin); 1511 1512 // Now start a new line. 1513 inlineMin = 0; 1514 } 1515 1516 if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) { 1517 updatePreferredWidth(minLogicalWidth, inlineMin); 1518 inlineMin = 0; 1519 } 1520 1521 // We are no longer stripping whitespace at the start of 1522 // a line. 1523 if (!child->isFloating()) { 1524 stripFrontSpaces = false; 1525 trailingSpaceChild = 0; 1526 } 1527 } else if (child->isText()) { 1528 // Case (3). Text. 1529 RenderText* t = toRenderText(child); 1530 1531 if (t->isWordBreak()) { 1532 updatePreferredWidth(minLogicalWidth, inlineMin); 1533 inlineMin = 0; 1534 continue; 1535 } 1536 1537 if (t->style()->hasTextCombine() && t->isCombineText()) 1538 toRenderCombineText(t)->combineText(); 1539 1540 // Determine if we have a breakable character. Pass in 1541 // whether or not we should ignore any spaces at the front 1542 // of the string. If those are going to be stripped out, 1543 // then they shouldn't be considered in the breakable char 1544 // check. 1545 bool hasBreakableChar, hasBreak; 1546 float firstLineMinWidth, lastLineMinWidth; 1547 bool hasBreakableStart, hasBreakableEnd; 1548 float firstLineMaxWidth, lastLineMaxWidth; 1549 t->trimmedPrefWidths(inlineMax, 1550 firstLineMinWidth, hasBreakableStart, lastLineMinWidth, hasBreakableEnd, 1551 hasBreakableChar, hasBreak, firstLineMaxWidth, lastLineMaxWidth, 1552 childMin, childMax, stripFrontSpaces, styleToUse->direction()); 1553 1554 // This text object will not be rendered, but it may still provide a breaking opportunity. 1555 if (!hasBreak && !childMax) { 1556 if (autoWrap && (hasBreakableStart || hasBreakableEnd)) { 1557 updatePreferredWidth(minLogicalWidth, inlineMin); 1558 inlineMin = 0; 1559 } 1560 continue; 1561 } 1562 1563 if (stripFrontSpaces) 1564 trailingSpaceChild = child; 1565 else 1566 trailingSpaceChild = 0; 1567 1568 // Add in text-indent. This is added in only once. 1569 float ti = 0; 1570 if (!addedTextIndent || hasRemainingNegativeTextIndent) { 1571 ti = textIndent.ceilToFloat(); 1572 childMin += ti; 1573 firstLineMinWidth += ti; 1574 1575 // It the text indent negative and larger than the child minimum, we re-use the remainder 1576 // in future minimum calculations, but using the negative value again on the maximum 1577 // will lead to under-counting the max pref width. 1578 if (!addedTextIndent) { 1579 childMax += ti; 1580 firstLineMaxWidth += ti; 1581 addedTextIndent = true; 1582 } 1583 1584 if (childMin < 0) { 1585 textIndent = childMin; 1586 hasRemainingNegativeTextIndent = true; 1587 } 1588 } 1589 1590 // If we have no breakable characters at all, 1591 // then this is the easy case. We add ourselves to the current 1592 // min and max and continue. 1593 if (!hasBreakableChar) { 1594 inlineMin += childMin; 1595 } else { 1596 if (hasBreakableStart) { 1597 updatePreferredWidth(minLogicalWidth, inlineMin); 1598 } else { 1599 inlineMin += firstLineMinWidth; 1600 updatePreferredWidth(minLogicalWidth, inlineMin); 1601 childMin -= ti; 1602 } 1603 1604 inlineMin = childMin; 1605 1606 if (hasBreakableEnd) { 1607 updatePreferredWidth(minLogicalWidth, inlineMin); 1608 inlineMin = 0; 1609 shouldBreakLineAfterText = false; 1610 } else { 1611 updatePreferredWidth(minLogicalWidth, inlineMin); 1612 inlineMin = lastLineMinWidth; 1613 shouldBreakLineAfterText = true; 1614 } 1615 } 1616 1617 if (hasBreak) { 1618 inlineMax += firstLineMaxWidth; 1619 updatePreferredWidth(maxLogicalWidth, inlineMax); 1620 updatePreferredWidth(maxLogicalWidth, childMax); 1621 inlineMax = lastLineMaxWidth; 1622 addedTextIndent = true; 1623 } else { 1624 inlineMax += max<float>(0, childMax); 1625 } 1626 } 1627 1628 // Ignore spaces after a list marker. 1629 if (child->isListMarker()) 1630 stripFrontSpaces = true; 1631 } else { 1632 updatePreferredWidth(minLogicalWidth, inlineMin); 1633 updatePreferredWidth(maxLogicalWidth, inlineMax); 1634 inlineMin = inlineMax = 0; 1635 stripFrontSpaces = true; 1636 trailingSpaceChild = 0; 1637 addedTextIndent = true; 1638 } 1639 1640 if (!child->isText() && child->isRenderInline()) 1641 isPrevChildInlineFlow = true; 1642 else 1643 isPrevChildInlineFlow = false; 1644 1645 oldAutoWrap = autoWrap; 1646 } 1647 1648 if (styleToUse->collapseWhiteSpace()) 1649 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild); 1650 1651 updatePreferredWidth(minLogicalWidth, inlineMin); 1652 updatePreferredWidth(maxLogicalWidth, inlineMax); 1653 } 1654 1655 void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom, LayoutUnit afterEdge) 1656 { 1657 RenderFlowThread* flowThread = flowThreadContainingBlock(); 1658 bool clearLinesForPagination = firstLineBox() && flowThread && !flowThread->hasRegions(); 1659 1660 // Figure out if we should clear out our line boxes. 1661 // FIXME: Handle resize eventually! 1662 bool isFullLayout = !firstLineBox() || selfNeedsLayout() || relayoutChildren || clearLinesForPagination; 1663 LineLayoutState layoutState(isFullLayout, repaintLogicalTop, repaintLogicalBottom, flowThread); 1664 1665 if (isFullLayout) 1666 lineBoxes()->deleteLineBoxes(); 1667 1668 // Text truncation kicks in in two cases: 1669 // 1) If your overflow isn't visible and your text-overflow-mode isn't clip. 1670 // 2) If you're an anonymous block with a block parent that satisfies #1 that was created 1671 // to accomodate a block that has inline and block children. This excludes parents where 1672 // canCollapseAnonymousBlockChild is false, notabley flex items and grid items. 1673 // FIXME: CSS3 says that descendants that are clipped must also know how to truncate. This is insanely 1674 // difficult to figure out in general (especially in the middle of doing layout), so we only handle the 1675 // simple case of an anonymous block truncating when it's parent is clipped. 1676 bool hasTextOverflow = (style()->textOverflow() && hasOverflowClip()) 1677 || (isAnonymousBlock() && parent() && parent()->isRenderBlock() && toRenderBlock(parent())->canCollapseAnonymousBlockChild() 1678 && parent()->style()->textOverflow() && parent()->hasOverflowClip()); 1679 1680 // Walk all the lines and delete our ellipsis line boxes if they exist. 1681 if (hasTextOverflow) 1682 deleteEllipsisLineBoxes(); 1683 1684 if (firstChild()) { 1685 // In full layout mode, clear the line boxes of children upfront. Otherwise, 1686 // siblings can run into stale root lineboxes during layout. Then layout 1687 // the replaced elements later. In partial layout mode, line boxes are not 1688 // deleted and only dirtied. In that case, we can layout the replaced 1689 // elements at the same time. 1690 Vector<RenderBox*> replacedChildren; 1691 for (InlineWalker walker(this); !walker.atEnd(); walker.advance()) { 1692 RenderObject* o = walker.current(); 1693 1694 if (!layoutState.hasInlineChild() && o->isInline()) 1695 layoutState.setHasInlineChild(true); 1696 1697 if (o->isReplaced() || o->isFloating() || o->isOutOfFlowPositioned()) { 1698 RenderBox* box = toRenderBox(o); 1699 1700 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, box); 1701 1702 if (o->isOutOfFlowPositioned()) 1703 o->containingBlock()->insertPositionedObject(box); 1704 else if (o->isFloating()) 1705 layoutState.floats().append(FloatWithRect(box)); 1706 else if (isFullLayout || o->needsLayout()) { 1707 // Replaced element. 1708 box->dirtyLineBoxes(isFullLayout); 1709 if (isFullLayout) 1710 replacedChildren.append(box); 1711 else 1712 o->layoutIfNeeded(); 1713 } 1714 } else if (o->isText() || (o->isRenderInline() && !walker.atEndOfInline())) { 1715 if (!o->isText()) 1716 toRenderInline(o)->updateAlwaysCreateLineBoxes(layoutState.isFullLayout()); 1717 if (layoutState.isFullLayout() || o->selfNeedsLayout()) 1718 dirtyLineBoxesForRenderer(o, layoutState.isFullLayout()); 1719 o->clearNeedsLayout(); 1720 } 1721 } 1722 1723 for (size_t i = 0; i < replacedChildren.size(); i++) 1724 replacedChildren[i]->layoutIfNeeded(); 1725 1726 layoutRunsAndFloats(layoutState); 1727 } 1728 1729 // Expand the last line to accommodate Ruby and emphasis marks. 1730 int lastLineAnnotationsAdjustment = 0; 1731 if (lastRootBox()) { 1732 LayoutUnit lowestAllowedPosition = max(lastRootBox()->lineBottom(), logicalHeight() + paddingAfter()); 1733 if (!style()->isFlippedLinesWritingMode()) 1734 lastLineAnnotationsAdjustment = lastRootBox()->computeUnderAnnotationAdjustment(lowestAllowedPosition); 1735 else 1736 lastLineAnnotationsAdjustment = lastRootBox()->computeOverAnnotationAdjustment(lowestAllowedPosition); 1737 } 1738 1739 // Now add in the bottom border/padding. 1740 setLogicalHeight(logicalHeight() + lastLineAnnotationsAdjustment + afterEdge); 1741 1742 if (!firstLineBox() && hasLineIfEmpty()) 1743 setLogicalHeight(logicalHeight() + lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes)); 1744 1745 // See if we have any lines that spill out of our block. If we do, then we will possibly need to 1746 // truncate text. 1747 if (hasTextOverflow) 1748 checkLinesForTextOverflow(); 1749 } 1750 1751 void RenderBlockFlow::checkFloatsInCleanLine(RootInlineBox* line, Vector<FloatWithRect>& floats, size_t& floatIndex, bool& encounteredNewFloat, bool& dirtiedByFloat) 1752 { 1753 Vector<RenderBox*>* cleanLineFloats = line->floatsPtr(); 1754 if (!cleanLineFloats) 1755 return; 1756 1757 Vector<RenderBox*>::iterator end = cleanLineFloats->end(); 1758 for (Vector<RenderBox*>::iterator it = cleanLineFloats->begin(); it != end; ++it) { 1759 RenderBox* floatingBox = *it; 1760 floatingBox->layoutIfNeeded(); 1761 LayoutSize newSize(floatingBox->width() + floatingBox->marginWidth(), floatingBox->height() + floatingBox->marginHeight()); 1762 if (floats[floatIndex].object != floatingBox) { 1763 encounteredNewFloat = true; 1764 return; 1765 } 1766 1767 if (floats[floatIndex].rect.size() != newSize) { 1768 LayoutUnit floatTop = isHorizontalWritingMode() ? floats[floatIndex].rect.y() : floats[floatIndex].rect.x(); 1769 LayoutUnit floatHeight = isHorizontalWritingMode() ? max(floats[floatIndex].rect.height(), newSize.height()) 1770 : max(floats[floatIndex].rect.width(), newSize.width()); 1771 floatHeight = min(floatHeight, LayoutUnit::max() - floatTop); 1772 line->markDirty(); 1773 markLinesDirtyInBlockRange(line->lineBottomWithLeading(), floatTop + floatHeight, line); 1774 floats[floatIndex].rect.setSize(newSize); 1775 dirtiedByFloat = true; 1776 } 1777 floatIndex++; 1778 } 1779 } 1780 1781 RootInlineBox* RenderBlockFlow::determineStartPosition(LineLayoutState& layoutState, InlineBidiResolver& resolver) 1782 { 1783 RootInlineBox* curr = 0; 1784 RootInlineBox* last = 0; 1785 1786 // FIXME: This entire float-checking block needs to be broken into a new function. 1787 bool dirtiedByFloat = false; 1788 if (!layoutState.isFullLayout()) { 1789 // Paginate all of the clean lines. 1790 bool paginated = view()->layoutState() && view()->layoutState()->isPaginated(); 1791 LayoutUnit paginationDelta = 0; 1792 size_t floatIndex = 0; 1793 for (curr = firstRootBox(); curr && !curr->isDirty(); curr = curr->nextRootBox()) { 1794 if (paginated) { 1795 paginationDelta -= curr->paginationStrut(); 1796 adjustLinePositionForPagination(curr, paginationDelta, layoutState.flowThread()); 1797 if (paginationDelta) { 1798 if (containsFloats() || !layoutState.floats().isEmpty()) { 1799 // FIXME: Do better eventually. For now if we ever shift because of pagination and floats are present just go to a full layout. 1800 layoutState.markForFullLayout(); 1801 break; 1802 } 1803 1804 layoutState.updateRepaintRangeFromBox(curr, paginationDelta); 1805 curr->adjustBlockDirectionPosition(paginationDelta.toFloat()); 1806 } 1807 } 1808 1809 // If a new float has been inserted before this line or before its last known float, just do a full layout. 1810 bool encounteredNewFloat = false; 1811 checkFloatsInCleanLine(curr, layoutState.floats(), floatIndex, encounteredNewFloat, dirtiedByFloat); 1812 if (encounteredNewFloat) 1813 layoutState.markForFullLayout(); 1814 1815 if (dirtiedByFloat || layoutState.isFullLayout()) 1816 break; 1817 } 1818 // Check if a new float has been inserted after the last known float. 1819 if (!curr && floatIndex < layoutState.floats().size()) 1820 layoutState.markForFullLayout(); 1821 } 1822 1823 if (layoutState.isFullLayout()) { 1824 // If we encountered a new float and have inline children, mark ourself to force us to issue paint invalidations. 1825 if (layoutState.hasInlineChild() && !selfNeedsLayout()) { 1826 setNeedsLayoutAndFullPaintInvalidation(MarkOnlyThis); 1827 if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) 1828 setShouldDoFullPaintInvalidationAfterLayout(true); 1829 } 1830 1831 // FIXME: This should just call deleteLineBoxTree, but that causes 1832 // crashes for fast/repaint tests. 1833 curr = firstRootBox(); 1834 while (curr) { 1835 // Note: This uses nextRootBox() insted of nextLineBox() like deleteLineBoxTree does. 1836 RootInlineBox* next = curr->nextRootBox(); 1837 curr->deleteLine(); 1838 curr = next; 1839 } 1840 ASSERT(!firstLineBox() && !lastLineBox()); 1841 } else { 1842 if (curr) { 1843 // We have a dirty line. 1844 if (RootInlineBox* prevRootBox = curr->prevRootBox()) { 1845 // We have a previous line. 1846 if (!dirtiedByFloat && (!prevRootBox->endsWithBreak() || !prevRootBox->lineBreakObj() || (prevRootBox->lineBreakObj()->isText() && prevRootBox->lineBreakPos() >= toRenderText(prevRootBox->lineBreakObj())->textLength()))) 1847 // The previous line didn't break cleanly or broke at a newline 1848 // that has been deleted, so treat it as dirty too. 1849 curr = prevRootBox; 1850 } 1851 } else { 1852 // No dirty lines were found. 1853 // If the last line didn't break cleanly, treat it as dirty. 1854 if (lastRootBox() && !lastRootBox()->endsWithBreak()) 1855 curr = lastRootBox(); 1856 } 1857 1858 // If we have no dirty lines, then last is just the last root box. 1859 last = curr ? curr->prevRootBox() : lastRootBox(); 1860 } 1861 1862 unsigned numCleanFloats = 0; 1863 if (!layoutState.floats().isEmpty()) { 1864 LayoutUnit savedLogicalHeight = logicalHeight(); 1865 // Restore floats from clean lines. 1866 RootInlineBox* line = firstRootBox(); 1867 while (line != curr) { 1868 if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) { 1869 Vector<RenderBox*>::iterator end = cleanLineFloats->end(); 1870 for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) { 1871 FloatingObject* floatingObject = insertFloatingObject(*f); 1872 ASSERT(!floatingObject->originatingLine()); 1873 floatingObject->setOriginatingLine(line); 1874 setLogicalHeight(logicalTopForChild(*f) - marginBeforeForChild(*f)); 1875 positionNewFloats(); 1876 ASSERT(layoutState.floats()[numCleanFloats].object == *f); 1877 numCleanFloats++; 1878 } 1879 } 1880 line = line->nextRootBox(); 1881 } 1882 setLogicalHeight(savedLogicalHeight); 1883 } 1884 layoutState.setFloatIndex(numCleanFloats); 1885 1886 layoutState.lineInfo().setFirstLine(!last); 1887 layoutState.lineInfo().setPreviousLineBrokeCleanly(!last || last->endsWithBreak()); 1888 1889 if (last) { 1890 setLogicalHeight(last->lineBottomWithLeading()); 1891 InlineIterator iter = InlineIterator(this, last->lineBreakObj(), last->lineBreakPos()); 1892 resolver.setPosition(iter, numberOfIsolateAncestors(iter)); 1893 resolver.setStatus(last->lineBreakBidiStatus()); 1894 } else { 1895 TextDirection direction = style()->direction(); 1896 if (style()->unicodeBidi() == Plaintext) 1897 direction = determinePlaintextDirectionality(this); 1898 resolver.setStatus(BidiStatus(direction, isOverride(style()->unicodeBidi()))); 1899 InlineIterator iter = InlineIterator(this, bidiFirstSkippingEmptyInlines(this, &resolver), 0); 1900 resolver.setPosition(iter, numberOfIsolateAncestors(iter)); 1901 } 1902 return curr; 1903 } 1904 1905 void RenderBlockFlow::determineEndPosition(LineLayoutState& layoutState, RootInlineBox* startLine, InlineIterator& cleanLineStart, BidiStatus& cleanLineBidiStatus) 1906 { 1907 ASSERT(!layoutState.endLine()); 1908 size_t floatIndex = layoutState.floatIndex(); 1909 RootInlineBox* last = 0; 1910 for (RootInlineBox* curr = startLine->nextRootBox(); curr; curr = curr->nextRootBox()) { 1911 if (!curr->isDirty()) { 1912 bool encounteredNewFloat = false; 1913 bool dirtiedByFloat = false; 1914 checkFloatsInCleanLine(curr, layoutState.floats(), floatIndex, encounteredNewFloat, dirtiedByFloat); 1915 if (encounteredNewFloat) 1916 return; 1917 } 1918 if (curr->isDirty()) 1919 last = 0; 1920 else if (!last) 1921 last = curr; 1922 } 1923 1924 if (!last) 1925 return; 1926 1927 // At this point, |last| is the first line in a run of clean lines that ends with the last line 1928 // in the block. 1929 1930 RootInlineBox* prev = last->prevRootBox(); 1931 cleanLineStart = InlineIterator(this, prev->lineBreakObj(), prev->lineBreakPos()); 1932 cleanLineBidiStatus = prev->lineBreakBidiStatus(); 1933 layoutState.setEndLineLogicalTop(prev->lineBottomWithLeading()); 1934 1935 for (RootInlineBox* line = last; line; line = line->nextRootBox()) 1936 line->extractLine(); // Disconnect all line boxes from their render objects while preserving 1937 // their connections to one another. 1938 1939 layoutState.setEndLine(last); 1940 } 1941 1942 bool RenderBlockFlow::checkPaginationAndFloatsAtEndLine(LineLayoutState& layoutState) 1943 { 1944 LayoutUnit lineDelta = logicalHeight() - layoutState.endLineLogicalTop(); 1945 1946 bool paginated = view()->layoutState() && view()->layoutState()->isPaginated(); 1947 if (paginated && layoutState.flowThread()) { 1948 // Check all lines from here to the end, and see if the hypothetical new position for the lines will result 1949 // in a different available line width. 1950 for (RootInlineBox* lineBox = layoutState.endLine(); lineBox; lineBox = lineBox->nextRootBox()) { 1951 if (paginated) { 1952 // This isn't the real move we're going to do, so don't update the line box's pagination 1953 // strut yet. 1954 LayoutUnit oldPaginationStrut = lineBox->paginationStrut(); 1955 lineDelta -= oldPaginationStrut; 1956 adjustLinePositionForPagination(lineBox, lineDelta, layoutState.flowThread()); 1957 lineBox->setPaginationStrut(oldPaginationStrut); 1958 } 1959 } 1960 } 1961 1962 if (!lineDelta || !m_floatingObjects) 1963 return true; 1964 1965 // See if any floats end in the range along which we want to shift the lines vertically. 1966 LayoutUnit logicalTop = min(logicalHeight(), layoutState.endLineLogicalTop()); 1967 1968 RootInlineBox* lastLine = layoutState.endLine(); 1969 while (RootInlineBox* nextLine = lastLine->nextRootBox()) 1970 lastLine = nextLine; 1971 1972 LayoutUnit logicalBottom = lastLine->lineBottomWithLeading() + absoluteValue(lineDelta); 1973 1974 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 1975 FloatingObjectSetIterator end = floatingObjectSet.end(); 1976 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 1977 FloatingObject* floatingObject = it->get(); 1978 if (logicalBottomForFloat(floatingObject) >= logicalTop && logicalBottomForFloat(floatingObject) < logicalBottom) 1979 return false; 1980 } 1981 1982 return true; 1983 } 1984 1985 bool RenderBlockFlow::matchedEndLine(LineLayoutState& layoutState, const InlineBidiResolver& resolver, const InlineIterator& endLineStart, const BidiStatus& endLineStatus) 1986 { 1987 if (resolver.position() == endLineStart) { 1988 if (resolver.status() != endLineStatus) 1989 return false; 1990 return checkPaginationAndFloatsAtEndLine(layoutState); 1991 } 1992 1993 // The first clean line doesn't match, but we can check a handful of following lines to try 1994 // to match back up. 1995 static int numLines = 8; // The # of lines we're willing to match against. 1996 RootInlineBox* originalEndLine = layoutState.endLine(); 1997 RootInlineBox* line = originalEndLine; 1998 for (int i = 0; i < numLines && line; i++, line = line->nextRootBox()) { 1999 if (line->lineBreakObj() == resolver.position().object() && line->lineBreakPos() == resolver.position().offset()) { 2000 // We have a match. 2001 if (line->lineBreakBidiStatus() != resolver.status()) 2002 return false; // ...but the bidi state doesn't match. 2003 2004 bool matched = false; 2005 RootInlineBox* result = line->nextRootBox(); 2006 layoutState.setEndLine(result); 2007 if (result) { 2008 layoutState.setEndLineLogicalTop(line->lineBottomWithLeading()); 2009 matched = checkPaginationAndFloatsAtEndLine(layoutState); 2010 } 2011 2012 // Now delete the lines that we failed to sync. 2013 deleteLineRange(layoutState, originalEndLine, result); 2014 return matched; 2015 } 2016 } 2017 2018 return false; 2019 } 2020 2021 bool RenderBlockFlow::generatesLineBoxesForInlineChild(RenderObject* inlineObj) 2022 2023 { 2024 ASSERT(inlineObj->parent() == this); 2025 2026 InlineIterator it(this, inlineObj, 0); 2027 // FIXME: We should pass correct value for WhitespacePosition. 2028 while (!it.atEnd() && !requiresLineBox(it)) 2029 it.increment(); 2030 2031 return !it.atEnd(); 2032 } 2033 2034 2035 void RenderBlockFlow::addOverflowFromInlineChildren() 2036 { 2037 LayoutUnit endPadding = hasOverflowClip() ? paddingEnd() : LayoutUnit(); 2038 // FIXME: Need to find another way to do this, since scrollbars could show when we don't want them to. 2039 if (hasOverflowClip() && !endPadding && node() && node()->isRootEditableElement() && style()->isLeftToRightDirection()) 2040 endPadding = 1; 2041 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { 2042 addLayoutOverflow(curr->paddedLayoutOverflowRect(endPadding)); 2043 LayoutRect visualOverflow = curr->visualOverflowRect(curr->lineTop(), curr->lineBottom()); 2044 addContentsVisualOverflow(visualOverflow); 2045 } 2046 } 2047 2048 void RenderBlockFlow::deleteEllipsisLineBoxes() 2049 { 2050 ETextAlign textAlign = style()->textAlign(); 2051 bool ltr = style()->isLeftToRightDirection(); 2052 bool firstLine = true; 2053 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { 2054 if (curr->hasEllipsisBox()) { 2055 curr->clearTruncation(); 2056 2057 // Shift the line back where it belongs if we cannot accomodate an ellipsis. 2058 float logicalLeft = logicalLeftOffsetForLine(curr->lineTop(), firstLine).toFloat(); 2059 float availableLogicalWidth = logicalRightOffsetForLine(curr->lineTop(), false) - logicalLeft; 2060 float totalLogicalWidth = curr->logicalWidth(); 2061 updateLogicalWidthForAlignment(textAlign, curr, 0, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0); 2062 2063 if (ltr) 2064 curr->adjustLogicalPosition((logicalLeft - curr->logicalLeft()), 0); 2065 else 2066 curr->adjustLogicalPosition(-(curr->logicalLeft() - logicalLeft), 0); 2067 } 2068 firstLine = false; 2069 } 2070 } 2071 2072 void RenderBlockFlow::checkLinesForTextOverflow() 2073 { 2074 // Determine the width of the ellipsis using the current font. 2075 // FIXME: CSS3 says this is configurable, also need to use 0x002E (FULL STOP) if horizontal ellipsis is "not renderable" 2076 const Font& font = style()->font(); 2077 DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1)); 2078 const Font& firstLineFont = firstLineStyle()->font(); 2079 // FIXME: We should probably not hard-code the direction here. https://crbug.com/333004 2080 TextDirection ellipsisDirection = LTR; 2081 float firstLineEllipsisWidth = firstLineFont.width(constructTextRun(this, firstLineFont, &horizontalEllipsis, 1, firstLineStyle(), ellipsisDirection)); 2082 float ellipsisWidth = (font == firstLineFont) ? firstLineEllipsisWidth : font.width(constructTextRun(this, font, &horizontalEllipsis, 1, style(), ellipsisDirection)); 2083 2084 // For LTR text truncation, we want to get the right edge of our padding box, and then we want to see 2085 // if the right edge of a line box exceeds that. For RTL, we use the left edge of the padding box and 2086 // check the left edge of the line box to see if it is less 2087 // Include the scrollbar for overflow blocks, which means we want to use "contentWidth()" 2088 bool ltr = style()->isLeftToRightDirection(); 2089 ETextAlign textAlign = style()->textAlign(); 2090 bool firstLine = true; 2091 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { 2092 float currLogicalLeft = curr->logicalLeft(); 2093 LayoutUnit blockRightEdge = logicalRightOffsetForLine(curr->lineTop(), firstLine); 2094 LayoutUnit blockLeftEdge = logicalLeftOffsetForLine(curr->lineTop(), firstLine); 2095 LayoutUnit lineBoxEdge = ltr ? currLogicalLeft + curr->logicalWidth() : currLogicalLeft; 2096 if ((ltr && lineBoxEdge > blockRightEdge) || (!ltr && lineBoxEdge < blockLeftEdge)) { 2097 // This line spills out of our box in the appropriate direction. Now we need to see if the line 2098 // can be truncated. In order for truncation to be possible, the line must have sufficient space to 2099 // accommodate our truncation string, and no replaced elements (images, tables) can overlap the ellipsis 2100 // space. 2101 2102 LayoutUnit width = firstLine ? firstLineEllipsisWidth : ellipsisWidth; 2103 LayoutUnit blockEdge = ltr ? blockRightEdge : blockLeftEdge; 2104 if (curr->lineCanAccommodateEllipsis(ltr, blockEdge, lineBoxEdge, width)) { 2105 float totalLogicalWidth = curr->placeEllipsis(ellipsisStr, ltr, blockLeftEdge.toFloat(), blockRightEdge.toFloat(), width.toFloat()); 2106 2107 float logicalLeft = 0; // We are only intersted in the delta from the base position. 2108 float availableLogicalWidth = (blockRightEdge - blockLeftEdge).toFloat(); 2109 updateLogicalWidthForAlignment(textAlign, curr, 0, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0); 2110 if (ltr) 2111 curr->adjustLogicalPosition(logicalLeft, 0); 2112 else 2113 curr->adjustLogicalPosition(logicalLeft - (availableLogicalWidth - totalLogicalWidth), 0); 2114 } 2115 } 2116 firstLine = false; 2117 } 2118 } 2119 2120 bool RenderBlockFlow::positionNewFloatOnLine(FloatingObject* newFloat, FloatingObject* lastFloatFromPreviousLine, LineInfo& lineInfo, LineWidth& width) 2121 { 2122 if (!positionNewFloats()) 2123 return false; 2124 2125 width.shrinkAvailableWidthForNewFloatIfNeeded(newFloat); 2126 2127 // We only connect floats to lines for pagination purposes if the floats occur at the start of 2128 // the line and the previous line had a hard break (so this line is either the first in the block 2129 // or follows a <br>). 2130 if (!newFloat->paginationStrut() || !lineInfo.previousLineBrokeCleanly() || !lineInfo.isEmpty()) 2131 return true; 2132 2133 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 2134 ASSERT(floatingObjectSet.last() == newFloat); 2135 2136 LayoutUnit floatLogicalTop = logicalTopForFloat(newFloat); 2137 int paginationStrut = newFloat->paginationStrut(); 2138 2139 if (floatLogicalTop - paginationStrut != logicalHeight() + lineInfo.floatPaginationStrut()) 2140 return true; 2141 2142 FloatingObjectSetIterator it = floatingObjectSet.end(); 2143 --it; // Last float is newFloat, skip that one. 2144 FloatingObjectSetIterator begin = floatingObjectSet.begin(); 2145 while (it != begin) { 2146 --it; 2147 FloatingObject* floatingObject = it->get(); 2148 if (floatingObject == lastFloatFromPreviousLine) 2149 break; 2150 if (logicalTopForFloat(floatingObject) == logicalHeight() + lineInfo.floatPaginationStrut()) { 2151 floatingObject->setPaginationStrut(paginationStrut + floatingObject->paginationStrut()); 2152 RenderBox* floatBox = floatingObject->renderer(); 2153 setLogicalTopForChild(floatBox, logicalTopForChild(floatBox) + marginBeforeForChild(floatBox) + paginationStrut); 2154 if (floatBox->isRenderBlock()) 2155 floatBox->forceChildLayout(); 2156 else 2157 floatBox->layoutIfNeeded(); 2158 // Save the old logical top before calling removePlacedObject which will set 2159 // isPlaced to false. Otherwise it will trigger an assert in logicalTopForFloat. 2160 LayoutUnit oldLogicalTop = logicalTopForFloat(floatingObject); 2161 m_floatingObjects->removePlacedObject(floatingObject); 2162 setLogicalTopForFloat(floatingObject, oldLogicalTop + paginationStrut); 2163 m_floatingObjects->addPlacedObject(floatingObject); 2164 } 2165 } 2166 2167 // Just update the line info's pagination strut without altering our logical height yet. If the line ends up containing 2168 // no content, then we don't want to improperly grow the height of the block. 2169 lineInfo.setFloatPaginationStrut(lineInfo.floatPaginationStrut() + paginationStrut); 2170 return true; 2171 } 2172 2173 LayoutUnit RenderBlockFlow::startAlignedOffsetForLine(LayoutUnit position, bool firstLine) 2174 { 2175 ETextAlign textAlign = style()->textAlign(); 2176 2177 if (textAlign == TASTART) // FIXME: Handle TAEND here 2178 return startOffsetForLine(position, firstLine); 2179 2180 // updateLogicalWidthForAlignment() handles the direction of the block so no need to consider it here 2181 float totalLogicalWidth = 0; 2182 float logicalLeft = logicalLeftOffsetForLine(logicalHeight(), false).toFloat(); 2183 float availableLogicalWidth = logicalRightOffsetForLine(logicalHeight(), false) - logicalLeft; 2184 updateLogicalWidthForAlignment(textAlign, 0, 0, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0); 2185 2186 if (!style()->isLeftToRightDirection()) 2187 return logicalWidth() - logicalLeft; 2188 return logicalLeft; 2189 } 2190 2191 } 2192