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