2 * Copyright (C) 2000 Lars Knoll (knoll@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.
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.
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.
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.
25 #include "core/accessibility/AXObjectCache.h"
26 #include "core/rendering/BidiRunForLine.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/RenderObjectInlines.h"
32 #include "core/rendering/RenderRegion.h"
33 #include "core/rendering/RenderRubyRun.h"
34 #include "core/rendering/RenderView.h"
35 #include "core/rendering/TextRunConstructor.h"
36 #include "core/rendering/TrailingFloatsRootInlineBox.h"
37 #include "core/rendering/VerticalPositionCache.h"
38 #include "core/rendering/line/BreakingContextInlineHeaders.h"
39 #include "core/rendering/line/LineLayoutState.h"
40 #include "core/rendering/line/LineWidth.h"
41 #include "core/rendering/line/RenderTextInfo.h"
42 #include "core/rendering/line/WordMeasurement.h"
43 #include "core/rendering/svg/SVGRootInlineBox.h"
44 #include "platform/fonts/Character.h"
45 #include "platform/text/BidiResolver.h"
46 #include "wtf/RefCountedLeakCounter.h"
47 #include "wtf/StdLibExtras.h"
48 #include "wtf/Vector.h"
49 #include "wtf/unicode/CharacterNames.h"
53 using namespace WTF::Unicode;
55 static inline InlineBox* createInlineBoxForRenderer(RenderObject* obj, bool isRootLineBox, bool isOnlyRun = false)
58 return toRenderBlockFlow(obj)->createAndAppendRootInlineBox();
61 InlineTextBox* textBox = toRenderText(obj)->createInlineTextBox();
62 // We only treat a box as text for a <br> if we are on a line by ourself or in strict mode
63 // (Note the use of strict mode. In "almost strict" mode, we don't treat the box for <br> as text.)
65 textBox->setIsText(isOnlyRun || obj->document().inNoQuirksMode());
70 return toRenderBox(obj)->createInlineBox();
72 return toRenderInline(obj)->createAndAppendInlineFlowBox();
75 static inline void dirtyLineBoxesForRenderer(RenderObject* o, bool fullLayout)
78 RenderText* renderText = toRenderText(o);
79 renderText->dirtyLineBoxes(fullLayout);
81 toRenderInline(o)->dirtyLineBoxes(fullLayout);
84 static bool parentIsConstructedOrHaveNext(InlineFlowBox* parentBox)
87 if (parentBox->isConstructed() || parentBox->nextOnLine())
89 parentBox = parentBox->parent();
94 InlineFlowBox* RenderBlockFlow::createLineBoxes(RenderObject* obj, const LineInfo& lineInfo, InlineBox* childBox)
96 // See if we have an unconstructed line box for this object that is also
97 // the last item on the line.
98 unsigned lineDepth = 1;
99 InlineFlowBox* parentBox = 0;
100 InlineFlowBox* result = 0;
101 bool hasDefaultLineBoxContain = style()->lineBoxContain() == RenderStyle::initialLineBoxContain();
103 ASSERT_WITH_SECURITY_IMPLICATION(obj->isRenderInline() || obj == this);
105 RenderInline* inlineFlow = (obj != this) ? toRenderInline(obj) : 0;
107 // Get the last box we made for this render object.
108 parentBox = inlineFlow ? inlineFlow->lastLineBox() : toRenderBlock(obj)->lastLineBox();
110 // If this box or its ancestor is constructed then it is from a previous line, and we need
111 // to make a new box for our line. If this box or its ancestor is unconstructed but it has
112 // something following it on the line, then we know we have to make a new box
113 // as well. In this situation our inline has actually been split in two on
114 // the same line (this can happen with very fancy language mixtures).
115 bool constructedNewBox = false;
116 bool allowedToConstructNewBox = !hasDefaultLineBoxContain || !inlineFlow || inlineFlow->alwaysCreateLineBoxes();
117 bool canUseExistingParentBox = parentBox && !parentIsConstructedOrHaveNext(parentBox);
118 if (allowedToConstructNewBox && !canUseExistingParentBox) {
119 // We need to make a new box for this render object. Once
120 // made, we need to place it at the end of the current line.
121 InlineBox* newBox = createInlineBoxForRenderer(obj, obj == this);
122 ASSERT_WITH_SECURITY_IMPLICATION(newBox->isInlineFlowBox());
123 parentBox = toInlineFlowBox(newBox);
124 parentBox->setFirstLineStyleBit(lineInfo.isFirstLine());
125 parentBox->setIsHorizontal(isHorizontalWritingMode());
126 if (!hasDefaultLineBoxContain)
127 parentBox->clearDescendantsHaveSameLineHeightAndBaseline();
128 constructedNewBox = true;
131 if (constructedNewBox || canUseExistingParentBox) {
135 // If we have hit the block itself, then |box| represents the root
136 // inline box for the line, and it doesn't have to be appended to any parent
139 parentBox->addToLine(childBox);
141 if (!constructedNewBox || obj == this)
144 childBox = parentBox;
147 // If we've exceeded our line depth, then jump straight to the root and skip all the remaining
148 // intermediate inline flows.
149 obj = (++lineDepth >= cMaxLineDepth) ? this : obj->parent();
156 template <typename CharacterType>
157 static inline bool endsWithASCIISpaces(const CharacterType* characters, unsigned pos, unsigned end)
159 while (isASCIISpace(characters[pos])) {
167 static bool reachedEndOfTextRenderer(const BidiRunList<BidiRun>& bidiRuns)
169 BidiRun* run = bidiRuns.logicallyLastRun();
172 unsigned pos = run->stop();
173 RenderObject* r = run->m_object;
174 if (!r->isText() || r->isBR())
176 RenderText* renderText = toRenderText(r);
177 unsigned length = renderText->textLength();
181 if (renderText->is8Bit())
182 return endsWithASCIISpaces(renderText->characters8(), pos, length);
183 return endsWithASCIISpaces(renderText->characters16(), pos, length);
186 RootInlineBox* RenderBlockFlow::constructLine(BidiRunList<BidiRun>& bidiRuns, const LineInfo& lineInfo)
188 ASSERT(bidiRuns.firstRun());
190 bool rootHasSelectedChildren = false;
191 InlineFlowBox* parentBox = 0;
192 int runCount = bidiRuns.runCount() - lineInfo.runsFromLeadingWhitespace();
193 for (BidiRun* r = bidiRuns.firstRun(); r; r = r->next()) {
194 // Create a box for our object.
195 bool isOnlyRun = (runCount == 1);
196 if (runCount == 2 && !r->m_object->isListMarker())
197 isOnlyRun = (!style()->isLeftToRightDirection() ? bidiRuns.lastRun() : bidiRuns.firstRun())->m_object->isListMarker();
199 if (lineInfo.isEmpty())
202 InlineBox* box = createInlineBoxForRenderer(r->m_object, false, isOnlyRun);
209 if (!rootHasSelectedChildren && box->renderer().selectionState() != RenderObject::SelectionNone)
210 rootHasSelectedChildren = true;
212 // If we have no parent box yet, or if the run is not simply a sibling,
213 // then we need to construct inline boxes as necessary to properly enclose the
214 // run's inline box. Segments can only be siblings at the root level, as
215 // they are positioned separately.
216 if (!parentBox || parentBox->renderer() != r->m_object->parent()) {
217 // Create new inline boxes all the way back to the appropriate insertion point.
218 parentBox = createLineBoxes(r->m_object->parent(), lineInfo, box);
220 // Append the inline box to this line.
221 parentBox->addToLine(box);
224 bool visuallyOrdered = r->m_object->style()->rtlOrdering() == VisualOrder;
225 box->setBidiLevel(r->level());
227 if (box->isInlineTextBox()) {
228 InlineTextBox* text = toInlineTextBox(box);
229 text->setStart(r->m_start);
230 text->setLen(r->m_stop - r->m_start);
231 text->setDirOverride(r->dirOverride(visuallyOrdered));
233 text->setHasHyphen(true);
235 if (AXObjectCache* cache = document().existingAXObjectCache())
236 cache->inlineTextBoxesUpdated(r->m_object);
240 // We should have a root inline box. It should be unconstructed and
241 // be the last continuation of our line list.
242 ASSERT(lastLineBox() && !lastLineBox()->isConstructed());
244 // Set the m_selectedChildren flag on the root inline box if one of the leaf inline box
245 // from the bidi runs walk above has a selection state.
246 if (rootHasSelectedChildren)
247 lastLineBox()->root().setHasSelectedChildren(true);
249 // Set bits on our inline flow boxes that indicate which sides should
250 // paint borders/margins/padding. This knowledge will ultimately be used when
251 // we determine the horizontal positions and widths of all the inline boxes on
253 bool isLogicallyLastRunWrapped = bidiRuns.logicallyLastRun()->m_object && bidiRuns.logicallyLastRun()->m_object->isText() ? !reachedEndOfTextRenderer(bidiRuns) : true;
254 lastLineBox()->determineSpacingForFlowBoxes(lineInfo.isLastLine(), isLogicallyLastRunWrapped, bidiRuns.logicallyLastRun()->m_object);
256 // Now mark the line boxes as being constructed.
257 lastLineBox()->setConstructed();
259 // Return the last line.
260 return lastRootBox();
263 ETextAlign RenderBlockFlow::textAlignmentForLine(bool endsWithSoftBreak) const
265 ETextAlign alignment = style()->textAlign();
266 if (endsWithSoftBreak)
269 if (!RuntimeEnabledFeatures::css3TextEnabled())
270 return (alignment == JUSTIFY) ? TASTART : alignment;
272 if (alignment != JUSTIFY)
275 TextAlignLast alignmentLast = style()->textAlignLast();
276 switch (alignmentLast) {
277 case TextAlignLastStart:
279 case TextAlignLastEnd:
281 case TextAlignLastLeft:
283 case TextAlignLastRight:
285 case TextAlignLastCenter:
287 case TextAlignLastJustify:
289 case TextAlignLastAuto:
290 if (style()->textJustify() == TextJustifyDistribute)
298 static void updateLogicalWidthForLeftAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
300 // The direction of the block should determine what happens with wide lines.
301 // In particular with RTL blocks, wide lines should still spill out to the left.
302 if (isLeftToRightDirection) {
303 if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun)
304 trailingSpaceRun->m_box->setLogicalWidth(std::max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
308 if (trailingSpaceRun)
309 trailingSpaceRun->m_box->setLogicalWidth(0);
310 else if (totalLogicalWidth > availableLogicalWidth)
311 logicalLeft -= (totalLogicalWidth - availableLogicalWidth);
314 static void updateLogicalWidthForRightAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
316 // Wide lines spill out of the block based off direction.
317 // So even if text-align is right, if direction is LTR, wide lines should overflow out of the right
318 // side of the block.
319 if (isLeftToRightDirection) {
320 if (trailingSpaceRun) {
321 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
322 trailingSpaceRun->m_box->setLogicalWidth(0);
324 if (totalLogicalWidth < availableLogicalWidth)
325 logicalLeft += availableLogicalWidth - totalLogicalWidth;
329 if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun) {
330 trailingSpaceRun->m_box->setLogicalWidth(std::max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
331 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
333 logicalLeft += availableLogicalWidth - totalLogicalWidth;
336 static void updateLogicalWidthForCenterAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
338 float trailingSpaceWidth = 0;
339 if (trailingSpaceRun) {
340 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
341 trailingSpaceWidth = std::min(trailingSpaceRun->m_box->logicalWidth(), (availableLogicalWidth - totalLogicalWidth + 1) / 2);
342 trailingSpaceRun->m_box->setLogicalWidth(std::max<float>(0, trailingSpaceWidth));
344 if (isLeftToRightDirection)
345 logicalLeft += std::max<float>((availableLogicalWidth - totalLogicalWidth) / 2, 0);
347 logicalLeft += totalLogicalWidth > availableLogicalWidth ? (availableLogicalWidth - totalLogicalWidth) : (availableLogicalWidth - totalLogicalWidth) / 2 - trailingSpaceWidth;
350 void RenderBlockFlow::setMarginsForRubyRun(BidiRun* run, RenderRubyRun* renderer, RenderObject* previousObject, const LineInfo& lineInfo)
354 RenderObject* nextObject = 0;
355 for (BidiRun* runWithNextObject = run->next(); runWithNextObject; runWithNextObject = runWithNextObject->next()) {
356 if (!runWithNextObject->m_object->isOutOfFlowPositioned() && !runWithNextObject->m_box->isLineBreak()) {
357 nextObject = runWithNextObject->m_object;
361 renderer->getOverhang(lineInfo.isFirstLine(), renderer->style()->isLeftToRightDirection() ? previousObject : nextObject, renderer->style()->isLeftToRightDirection() ? nextObject : previousObject, startOverhang, endOverhang);
362 setMarginStartForChild(renderer, -startOverhang);
363 setMarginEndForChild(renderer, -endOverhang);
366 static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* run, RenderText* renderer, float xPos, const LineInfo& lineInfo,
367 GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, WordMeasurements& wordMeasurements)
369 HashSet<const SimpleFontData*> fallbackFonts;
370 GlyphOverflow glyphOverflow;
372 const Font& font = renderer->style(lineInfo.isFirstLine())->font();
373 // Always compute glyph overflow if the block's line-box-contain value is "glyphs".
374 if (lineBox->fitsToGlyphs()) {
375 // If we don't stick out of the root line's font box, then don't bother computing our glyph overflow. This optimization
376 // will keep us from computing glyph bounds in nearly all cases.
377 bool includeRootLine = lineBox->includesRootLineBoxFontOrLeading();
378 int baselineShift = lineBox->verticalPositionForBox(run->m_box, verticalPositionCache);
379 int rootDescent = includeRootLine ? font.fontMetrics().descent() : 0;
380 int rootAscent = includeRootLine ? font.fontMetrics().ascent() : 0;
381 int boxAscent = font.fontMetrics().ascent() - baselineShift;
382 int boxDescent = font.fontMetrics().descent() + baselineShift;
383 if (boxAscent > rootDescent || boxDescent > rootAscent)
384 glyphOverflow.computeBounds = true;
387 LayoutUnit hyphenWidth = 0;
388 if (toInlineTextBox(run->m_box)->hasHyphen()) {
389 const Font& font = renderer->style(lineInfo.isFirstLine())->font();
390 hyphenWidth = measureHyphenWidth(renderer, font, run->direction());
392 float measuredWidth = 0;
394 bool kerningIsEnabled = font.fontDescription().typesettingFeatures() & Kerning;
397 // FIXME: Having any font feature settings enabled can lead to selection gaps on
398 // Chromium-mac. https://bugs.webkit.org/show_bug.cgi?id=113418
399 bool canUseSimpleFontCodePath = renderer->canUseSimpleFontCodePath() && !font.fontDescription().featureSettings();
401 bool canUseSimpleFontCodePath = renderer->canUseSimpleFontCodePath();
404 // Since we don't cache glyph overflows, we need to re-measure the run if
405 // the style is linebox-contain: glyph.
407 if (!lineBox->fitsToGlyphs() && canUseSimpleFontCodePath) {
408 int lastEndOffset = run->m_start;
409 for (size_t i = 0, size = wordMeasurements.size(); i < size && lastEndOffset < run->m_stop; ++i) {
410 const WordMeasurement& wordMeasurement = wordMeasurements[i];
411 if (wordMeasurement.width <=0 || wordMeasurement.startOffset == wordMeasurement.endOffset)
413 if (wordMeasurement.renderer != renderer || wordMeasurement.startOffset != lastEndOffset || wordMeasurement.endOffset > run->m_stop)
416 lastEndOffset = wordMeasurement.endOffset;
417 if (kerningIsEnabled && lastEndOffset == run->m_stop) {
418 int wordLength = lastEndOffset - wordMeasurement.startOffset;
419 measuredWidth += renderer->width(wordMeasurement.startOffset, wordLength, xPos, run->direction(), lineInfo.isFirstLine());
420 if (i > 0 && wordLength == 1 && renderer->characterAt(wordMeasurement.startOffset) == ' ')
421 measuredWidth += renderer->style()->wordSpacing();
423 measuredWidth += wordMeasurement.width;
424 if (!wordMeasurement.fallbackFonts.isEmpty()) {
425 HashSet<const SimpleFontData*>::const_iterator end = wordMeasurement.fallbackFonts.end();
426 for (HashSet<const SimpleFontData*>::const_iterator it = wordMeasurement.fallbackFonts.begin(); it != end; ++it)
427 fallbackFonts.add(*it);
430 if (measuredWidth && lastEndOffset != run->m_stop) {
431 // If we don't have enough cached data, we'll measure the run again.
433 fallbackFonts.clear();
438 measuredWidth = renderer->width(run->m_start, run->m_stop - run->m_start, xPos, run->direction(), lineInfo.isFirstLine(), &fallbackFonts, &glyphOverflow);
440 run->m_box->setLogicalWidth(measuredWidth + hyphenWidth);
441 if (!fallbackFonts.isEmpty()) {
442 ASSERT(run->m_box->isText());
443 GlyphOverflowAndFallbackFontsMap::ValueType* it = textBoxDataMap.add(toInlineTextBox(run->m_box), std::make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).storedValue;
444 ASSERT(it->value.first.isEmpty());
445 copyToVector(fallbackFonts, it->value.first);
446 run->m_box->parent()->clearDescendantsHaveSameLineHeightAndBaseline();
448 if (!glyphOverflow.isZero()) {
449 ASSERT(run->m_box->isText());
450 GlyphOverflowAndFallbackFontsMap::ValueType* it = textBoxDataMap.add(toInlineTextBox(run->m_box), std::make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).storedValue;
451 it->value.second = glyphOverflow;
452 run->m_box->clearKnownToHaveNoOverflow();
456 static inline void computeExpansionForJustifiedText(BidiRun* firstRun, BidiRun* trailingSpaceRun, Vector<unsigned, 16>& expansionOpportunities, unsigned expansionOpportunityCount, float& totalLogicalWidth, float availableLogicalWidth)
458 if (!expansionOpportunityCount || availableLogicalWidth <= totalLogicalWidth)
462 for (BidiRun* r = firstRun; r; r = r->next()) {
463 if (!r->m_box || r == trailingSpaceRun)
466 if (r->m_object->isText()) {
467 unsigned opportunitiesInRun = expansionOpportunities[i++];
469 ASSERT(opportunitiesInRun <= expansionOpportunityCount);
471 // Don't justify for white-space: pre.
472 if (r->m_object->style()->whiteSpace() != PRE) {
473 InlineTextBox* textBox = toInlineTextBox(r->m_box);
474 int expansion = (availableLogicalWidth - totalLogicalWidth) * opportunitiesInRun / expansionOpportunityCount;
475 textBox->setExpansion(expansion);
476 totalLogicalWidth += expansion;
478 expansionOpportunityCount -= opportunitiesInRun;
479 if (!expansionOpportunityCount)
485 void RenderBlockFlow::updateLogicalWidthForAlignment(const ETextAlign& textAlign, const RootInlineBox* rootInlineBox, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float& availableLogicalWidth, unsigned expansionOpportunityCount)
487 TextDirection direction;
488 if (rootInlineBox && rootInlineBox->renderer().style()->unicodeBidi() == Plaintext)
489 direction = rootInlineBox->direction();
491 direction = style()->direction();
493 // Armed with the total width of the line (without justification),
494 // we now examine our text-align property in order to determine where to position the
495 // objects horizontally. The total width of the line can be increased if we end up
500 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
504 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
508 updateLogicalWidthForCenterAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
511 adjustInlineDirectionLineBounds(expansionOpportunityCount, logicalLeft, availableLogicalWidth);
512 if (expansionOpportunityCount) {
513 if (trailingSpaceRun) {
514 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
515 trailingSpaceRun->m_box->setLogicalWidth(0);
521 if (direction == LTR)
522 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
524 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
527 if (direction == LTR)
528 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
530 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
533 if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
534 logicalLeft += verticalScrollbarWidth();
537 static void updateLogicalInlinePositions(RenderBlockFlow* block, float& lineLogicalLeft, float& lineLogicalRight, float& availableLogicalWidth, bool firstLine, IndentTextOrNot shouldIndentText, LayoutUnit boxLogicalHeight)
539 LayoutUnit lineLogicalHeight = block->minLineHeightForReplacedRenderer(firstLine, boxLogicalHeight);
540 lineLogicalLeft = block->logicalLeftOffsetForLine(block->logicalHeight(), shouldIndentText == IndentText, lineLogicalHeight).toFloat();
541 lineLogicalRight = block->logicalRightOffsetForLine(block->logicalHeight(), shouldIndentText == IndentText, lineLogicalHeight).toFloat();
542 availableLogicalWidth = lineLogicalRight - lineLogicalLeft;
545 void RenderBlockFlow::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, const LineInfo& lineInfo, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd,
546 GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, WordMeasurements& wordMeasurements)
548 ETextAlign textAlign = textAlignmentForLine(!reachedEnd && !lineBox->endsWithBreak());
550 // 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
551 // box is only affected if it is the first child of its parent element."
552 // CSS3 "text-indent", "each-line" affects the first line of the block container as well as each line after a forced line break,
553 // but does not affect lines after a soft wrap break.
554 bool isFirstLine = lineInfo.isFirstLine() && !(isAnonymousBlock() && parent()->slowFirstChild() != this);
555 bool isAfterHardLineBreak = lineBox->prevRootBox() && lineBox->prevRootBox()->endsWithBreak();
556 IndentTextOrNot shouldIndentText = requiresIndent(isFirstLine, isAfterHardLineBreak, style());
557 float lineLogicalLeft;
558 float lineLogicalRight;
559 float availableLogicalWidth;
560 updateLogicalInlinePositions(this, lineLogicalLeft, lineLogicalRight, availableLogicalWidth, isFirstLine, shouldIndentText, 0);
561 bool needsWordSpacing;
563 if (firstRun && firstRun->m_object->isReplaced()) {
564 RenderBox* renderBox = toRenderBox(firstRun->m_object);
565 updateLogicalInlinePositions(this, lineLogicalLeft, lineLogicalRight, availableLogicalWidth, isFirstLine, shouldIndentText, renderBox->logicalHeight());
568 computeInlineDirectionPositionsForSegment(lineBox, lineInfo, textAlign, lineLogicalLeft, availableLogicalWidth, firstRun, trailingSpaceRun, textBoxDataMap, verticalPositionCache, wordMeasurements);
569 // The widths of all runs are now known. We can now place every inline box (and
570 // compute accurate widths for the inline flow boxes).
571 needsWordSpacing = lineBox->isLeftToRightDirection() ? false: true;
572 lineBox->placeBoxesInInlineDirection(lineLogicalLeft, needsWordSpacing);
575 BidiRun* RenderBlockFlow::computeInlineDirectionPositionsForSegment(RootInlineBox* lineBox, const LineInfo& lineInfo, ETextAlign textAlign, float& logicalLeft,
576 float& availableLogicalWidth, BidiRun* firstRun, BidiRun* trailingSpaceRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache,
577 WordMeasurements& wordMeasurements)
579 bool needsWordSpacing = true;
580 float totalLogicalWidth = lineBox->getFlowSpacingLogicalWidth().toFloat();
581 unsigned expansionOpportunityCount = 0;
582 bool isAfterExpansion = true;
583 Vector<unsigned, 16> expansionOpportunities;
584 RenderObject* previousObject = 0;
585 TextJustify textJustify = style()->textJustify();
587 BidiRun* r = firstRun;
588 for (; r; r = r->next()) {
589 if (!r->m_box || r->m_object->isOutOfFlowPositioned() || r->m_box->isLineBreak())
590 continue; // Positioned objects are only participating to figure out their
591 // correct static x position. They have no effect on the width.
592 // Similarly, line break boxes have no effect on the width.
593 if (r->m_object->isText()) {
594 RenderText* rt = toRenderText(r->m_object);
595 if (textAlign == JUSTIFY && r != trailingSpaceRun && textJustify != TextJustifyNone) {
596 if (!isAfterExpansion)
597 toInlineTextBox(r->m_box)->setCanHaveLeadingExpansion(true);
598 unsigned opportunitiesInRun;
600 opportunitiesInRun = Character::expansionOpportunityCount(rt->characters8() + r->m_start, r->m_stop - r->m_start, r->m_box->direction(), isAfterExpansion);
602 opportunitiesInRun = Character::expansionOpportunityCount(rt->characters16() + r->m_start, r->m_stop - r->m_start, r->m_box->direction(), isAfterExpansion);
603 expansionOpportunities.append(opportunitiesInRun);
604 expansionOpportunityCount += opportunitiesInRun;
607 if (rt->textLength()) {
608 if (!r->m_start && needsWordSpacing && isSpaceOrNewline(rt->characterAt(r->m_start)))
609 totalLogicalWidth += rt->style(lineInfo.isFirstLine())->font().fontDescription().wordSpacing();
610 needsWordSpacing = !isSpaceOrNewline(rt->characterAt(r->m_stop - 1));
613 setLogicalWidthForTextRun(lineBox, r, rt, totalLogicalWidth, lineInfo, textBoxDataMap, verticalPositionCache, wordMeasurements);
615 isAfterExpansion = false;
616 if (!r->m_object->isRenderInline()) {
617 RenderBox* renderBox = toRenderBox(r->m_object);
618 if (renderBox->isRubyRun())
619 setMarginsForRubyRun(r, toRenderRubyRun(renderBox), previousObject, lineInfo);
620 r->m_box->setLogicalWidth(logicalWidthForChild(renderBox).toFloat());
621 totalLogicalWidth += marginStartForChild(renderBox) + marginEndForChild(renderBox);
625 totalLogicalWidth += r->m_box->logicalWidth();
626 previousObject = r->m_object;
629 if (isAfterExpansion && !expansionOpportunities.isEmpty()) {
630 expansionOpportunities.last()--;
631 expansionOpportunityCount--;
634 updateLogicalWidthForAlignment(textAlign, lineBox, trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth, expansionOpportunityCount);
636 computeExpansionForJustifiedText(firstRun, trailingSpaceRun, expansionOpportunities, expansionOpportunityCount, totalLogicalWidth, availableLogicalWidth);
641 void RenderBlockFlow::computeBlockDirectionPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap,
642 VerticalPositionCache& verticalPositionCache)
644 setLogicalHeight(lineBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache));
646 // Now make sure we place replaced render objects correctly.
647 for (BidiRun* r = firstRun; r; r = r->next()) {
650 continue; // Skip runs with no line boxes.
652 // Align positioned boxes with the top of the line box. This is
653 // a reasonable approximation of an appropriate y position.
654 if (r->m_object->isOutOfFlowPositioned())
655 r->m_box->setLogicalTop(logicalHeight().toFloat());
657 // Position is used to properly position both replaced elements and
658 // to update the static normal flow x/y of positioned elements.
659 if (r->m_object->isText())
660 toRenderText(r->m_object)->positionLineBox(r->m_box);
661 else if (r->m_object->isBox())
662 toRenderBox(r->m_object)->positionLineBox(r->m_box);
666 void RenderBlockFlow::appendFloatingObjectToLastLine(FloatingObject* floatingObject)
668 ASSERT(!floatingObject->originatingLine());
669 floatingObject->setOriginatingLine(lastRootBox());
670 lastRootBox()->appendFloat(floatingObject->renderer());
673 // This function constructs line boxes for all of the text runs in the resolver and computes their position.
674 RootInlineBox* RenderBlockFlow::createLineBoxesFromBidiRuns(unsigned bidiLevel, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& end, LineInfo& lineInfo, VerticalPositionCache& verticalPositionCache, BidiRun* trailingSpaceRun, WordMeasurements& wordMeasurements)
676 if (!bidiRuns.runCount())
679 // FIXME: Why is this only done when we had runs?
680 lineInfo.setLastLine(!end.object());
682 RootInlineBox* lineBox = constructLine(bidiRuns, lineInfo);
686 lineBox->setBidiLevel(bidiLevel);
687 lineBox->setEndsWithBreak(lineInfo.previousLineBrokeCleanly());
689 bool isSVGRootInlineBox = lineBox->isSVGRootInlineBox();
691 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
693 // Now we position all of our text runs horizontally.
694 if (!isSVGRootInlineBox)
695 computeInlineDirectionPositionsForLine(lineBox, lineInfo, bidiRuns.firstRun(), trailingSpaceRun, end.atEnd(), textBoxDataMap, verticalPositionCache, wordMeasurements);
697 // Now position our text runs vertically.
698 computeBlockDirectionPositionsForLine(lineBox, bidiRuns.firstRun(), textBoxDataMap, verticalPositionCache);
700 // SVG text layout code computes vertical & horizontal positions on its own.
701 // Note that we still need to execute computeVerticalPositionsForLine() as
702 // it calls InlineTextBox::positionLineBox(), which tracks whether the box
703 // contains reversed text or not. If we wouldn't do that editing and thus
704 // text selection in RTL boxes would not work as expected.
705 if (isSVGRootInlineBox) {
707 toSVGRootInlineBox(lineBox)->computePerCharacterLayoutInformation();
710 // Compute our overflow now.
711 lineBox->computeOverflow(lineBox->lineTop(), lineBox->lineBottom(), textBoxDataMap);
716 static void deleteLineRange(LineLayoutState& layoutState, RootInlineBox* startLine, RootInlineBox* stopLine = 0)
718 RootInlineBox* boxToDelete = startLine;
719 while (boxToDelete && boxToDelete != stopLine) {
720 layoutState.updatePaintInvalidationRangeFromBox(boxToDelete);
721 // Note: deleteLineRange(firstRootBox()) is not identical to deleteLineBoxTree().
722 // deleteLineBoxTree uses nextLineBox() instead of nextRootBox() when traversing.
723 RootInlineBox* next = boxToDelete->nextRootBox();
724 boxToDelete->deleteLine();
729 void RenderBlockFlow::layoutRunsAndFloats(LineLayoutState& layoutState)
731 // We want to skip ahead to the first dirty line
732 InlineBidiResolver resolver;
733 RootInlineBox* startLine = determineStartPosition(layoutState, resolver);
735 if (containsFloats())
736 layoutState.setLastFloat(m_floatingObjects->set().last().get());
738 // We also find the first clean line and extract these lines. We will add them back
739 // if we determine that we're able to synchronize after handling all our dirty lines.
740 InlineIterator cleanLineStart;
741 BidiStatus cleanLineBidiStatus;
742 if (!layoutState.isFullLayout() && startLine)
743 determineEndPosition(layoutState, startLine, cleanLineStart, cleanLineBidiStatus);
746 if (!layoutState.usesPaintInvalidationBounds())
747 layoutState.setPaintInvalidationRange(logicalHeight());
748 deleteLineRange(layoutState, startLine);
751 if (!layoutState.isFullLayout() && lastRootBox() && lastRootBox()->endsWithBreak()) {
752 // If the last line before the start line ends with a line break that clear floats,
753 // adjust the height accordingly.
754 // A line break can be either the first or the last object on a line, depending on its direction.
755 if (InlineBox* lastLeafChild = lastRootBox()->lastLeafChild()) {
756 RenderObject* lastObject = &lastLeafChild->renderer();
757 if (!lastObject->isBR())
758 lastObject = &lastRootBox()->firstLeafChild()->renderer();
759 if (lastObject->isBR()) {
760 EClear clear = lastObject->style()->clear();
767 layoutRunsAndFloatsInRange(layoutState, resolver, cleanLineStart, cleanLineBidiStatus);
768 linkToEndLineIfNeeded(layoutState);
769 markDirtyFloatsForPaintInvalidation(layoutState.floats());
772 // Before restarting the layout loop with a new logicalHeight, remove all floats that were added and reset the resolver.
773 inline const InlineIterator& RenderBlockFlow::restartLayoutRunsAndFloatsInRange(LayoutUnit oldLogicalHeight, LayoutUnit newLogicalHeight, FloatingObject* lastFloatFromPreviousLine, InlineBidiResolver& resolver, const InlineIterator& oldEnd)
775 removeFloatingObjectsBelow(lastFloatFromPreviousLine, oldLogicalHeight);
776 setLogicalHeight(newLogicalHeight);
777 resolver.setPositionIgnoringNestedIsolates(oldEnd);
781 void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState,
782 InlineBidiResolver& resolver, const InlineIterator& cleanLineStart,
783 const BidiStatus& cleanLineBidiStatus)
785 RenderStyle* styleToUse = style();
786 bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
787 LineMidpointState& lineMidpointState = resolver.midpointState();
788 InlineIterator endOfLine = resolver.position();
789 bool checkForEndLineMatch = layoutState.endLine();
790 RenderTextInfo renderTextInfo;
791 VerticalPositionCache verticalPositionCache;
793 LineBreaker lineBreaker(this);
795 while (!endOfLine.atEnd()) {
796 // FIXME: Is this check necessary before the first iteration or can it be moved to the end?
797 if (checkForEndLineMatch) {
798 layoutState.setEndLineMatched(matchedEndLine(layoutState, resolver, cleanLineStart, cleanLineBidiStatus));
799 if (layoutState.endLineMatched()) {
800 resolver.setPosition(InlineIterator(resolver.position().root(), 0, 0), 0);
805 lineMidpointState.reset();
807 layoutState.lineInfo().setEmpty(true);
808 layoutState.lineInfo().resetRunsFromLeadingWhitespace();
810 const InlineIterator previousEndofLine = endOfLine;
811 bool isNewUBAParagraph = layoutState.lineInfo().previousLineBrokeCleanly();
812 FloatingObject* lastFloatFromPreviousLine = (containsFloats()) ? m_floatingObjects->set().last().get() : 0;
814 WordMeasurements wordMeasurements;
815 endOfLine = lineBreaker.nextLineBreak(resolver, layoutState.lineInfo(), renderTextInfo,
816 lastFloatFromPreviousLine, wordMeasurements);
817 renderTextInfo.m_lineBreakIterator.resetPriorContext();
818 if (resolver.position().atEnd()) {
819 // FIXME: We shouldn't be creating any runs in nextLineBreak to begin with!
820 // Once BidiRunList is separated from BidiResolver this will not be needed.
821 resolver.runs().deleteRuns();
822 resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed).
823 layoutState.setCheckForFloatsFromLastLine(true);
824 resolver.setPosition(InlineIterator(resolver.position().root(), 0, 0), 0);
828 ASSERT(endOfLine != resolver.position());
830 // This is a short-cut for empty lines.
831 if (layoutState.lineInfo().isEmpty()) {
833 lastRootBox()->setLineBreakInfo(endOfLine.object(), endOfLine.offset(), resolver.status());
835 VisualDirectionOverride override = (styleToUse->rtlOrdering() == VisualOrder ? (styleToUse->direction() == LTR ? VisualLeftToRightOverride : VisualRightToLeftOverride) : NoVisualOverride);
836 if (isNewUBAParagraph && styleToUse->unicodeBidi() == Plaintext && !resolver.context()->parent()) {
837 TextDirection direction = determinePlaintextDirectionality(resolver.position().root(), resolver.position().object(), resolver.position().offset());
838 resolver.setStatus(BidiStatus(direction, isOverride(styleToUse->unicodeBidi())));
840 // FIXME: This ownership is reversed. We should own the BidiRunList and pass it to createBidiRunsForLine.
841 BidiRunList<BidiRun>& bidiRuns = resolver.runs();
842 constructBidiRunsForLine(resolver, bidiRuns, endOfLine, override, layoutState.lineInfo().previousLineBrokeCleanly(), isNewUBAParagraph);
843 ASSERT(resolver.position() == endOfLine);
845 BidiRun* trailingSpaceRun = resolver.trailingSpaceRun();
847 if (bidiRuns.runCount() && lineBreaker.lineWasHyphenated())
848 bidiRuns.logicallyLastRun()->m_hasHyphen = true;
850 // Now that the runs have been ordered, we create the line boxes.
851 // At the same time we figure out where border/padding/margin should be applied for
852 // inline flow boxes.
854 LayoutUnit oldLogicalHeight = logicalHeight();
855 RootInlineBox* lineBox = createLineBoxesFromBidiRuns(resolver.status().context->level(), bidiRuns, endOfLine, layoutState.lineInfo(), verticalPositionCache, trailingSpaceRun, wordMeasurements);
857 bidiRuns.deleteRuns();
858 resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed).
861 lineBox->setLineBreakInfo(endOfLine.object(), endOfLine.offset(), resolver.status());
862 if (layoutState.usesPaintInvalidationBounds())
863 layoutState.updatePaintInvalidationRangeFromBox(lineBox);
866 LayoutUnit adjustment = 0;
867 adjustLinePositionForPagination(lineBox, adjustment, layoutState.flowThread());
869 LayoutUnit oldLineWidth = availableLogicalWidthForLine(oldLogicalHeight, layoutState.lineInfo().isFirstLine());
870 lineBox->adjustBlockDirectionPosition(adjustment.toFloat());
871 if (layoutState.usesPaintInvalidationBounds())
872 layoutState.updatePaintInvalidationRangeFromBox(lineBox);
874 if (availableLogicalWidthForLine(oldLogicalHeight + adjustment, layoutState.lineInfo().isFirstLine()) != oldLineWidth) {
875 // We have to delete this line, remove all floats that got added, and let line layout re-run.
876 lineBox->deleteLine();
877 endOfLine = restartLayoutRunsAndFloatsInRange(oldLogicalHeight, oldLogicalHeight + adjustment, lastFloatFromPreviousLine, resolver, previousEndofLine);
881 setLogicalHeight(lineBox->lineBottomWithLeading());
887 for (size_t i = 0; i < lineBreaker.positionedObjects().size(); ++i)
888 setStaticPositions(this, lineBreaker.positionedObjects()[i]);
890 if (!layoutState.lineInfo().isEmpty()) {
891 layoutState.lineInfo().setFirstLine(false);
892 clearFloats(lineBreaker.clear());
895 if (m_floatingObjects && lastRootBox()) {
896 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
897 FloatingObjectSetIterator it = floatingObjectSet.begin();
898 FloatingObjectSetIterator end = floatingObjectSet.end();
899 if (layoutState.lastFloat()) {
900 FloatingObjectSetIterator lastFloatIterator = floatingObjectSet.find(layoutState.lastFloat());
901 ASSERT(lastFloatIterator != end);
903 it = lastFloatIterator;
905 for (; it != end; ++it) {
906 FloatingObject* f = it->get();
907 appendFloatingObjectToLastLine(f);
908 ASSERT(f->renderer() == layoutState.floats()[layoutState.floatIndex()].object);
909 // If a float's geometry has changed, give up on syncing with clean lines.
910 if (layoutState.floats()[layoutState.floatIndex()].rect != f->frameRect())
911 checkForEndLineMatch = false;
912 layoutState.setFloatIndex(layoutState.floatIndex() + 1);
914 layoutState.setLastFloat(!floatingObjectSet.isEmpty() ? floatingObjectSet.last().get() : 0);
917 lineMidpointState.reset();
918 resolver.setPosition(endOfLine, numberOfIsolateAncestors(endOfLine));
921 // In case we already adjusted the line positions during this layout to avoid widows
922 // then we need to ignore the possibility of having a new widows situation.
923 // Otherwise, we risk leaving empty containers which is against the block fragmentation principles.
924 if (paginated && !style()->hasAutoWidows() && !didBreakAtLineToAvoidWidow()) {
925 // Check the line boxes to make sure we didn't create unacceptable widows.
926 // However, we'll prioritize orphans - so nothing we do here should create
929 RootInlineBox* lineBox = lastRootBox();
931 // Count from the end of the block backwards, to see how many hanging
933 RootInlineBox* firstLineInBlock = firstRootBox();
934 int numLinesHanging = 1;
935 while (lineBox && lineBox != firstLineInBlock && !lineBox->isFirstAfterPageBreak()) {
937 lineBox = lineBox->prevRootBox();
940 // If there were no breaks in the block, we didn't create any widows.
941 if (!lineBox || !lineBox->isFirstAfterPageBreak() || lineBox == firstLineInBlock)
944 if (numLinesHanging < style()->widows()) {
945 // We have detected a widow. Now we need to work out how many
946 // lines there are on the previous page, and how many we need
948 int numLinesNeeded = style()->widows() - numLinesHanging;
949 RootInlineBox* currentFirstLineOfNewPage = lineBox;
951 // Count the number of lines in the previous page.
952 lineBox = lineBox->prevRootBox();
953 int numLinesInPreviousPage = 1;
954 while (lineBox && lineBox != firstLineInBlock && !lineBox->isFirstAfterPageBreak()) {
955 ++numLinesInPreviousPage;
956 lineBox = lineBox->prevRootBox();
959 // If there was an explicit value for orphans, respect that. If not, we still
960 // shouldn't create a situation where we make an orphan bigger than the initial value.
961 // This means that setting widows implies we also care about orphans, but given
962 // the specification says the initial orphan value is non-zero, this is ok. The
963 // author is always free to set orphans explicitly as well.
964 int orphans = style()->hasAutoOrphans() ? style()->initialOrphans() : style()->orphans();
965 int numLinesAvailable = numLinesInPreviousPage - orphans;
966 if (numLinesAvailable <= 0)
969 int numLinesToTake = std::min(numLinesAvailable, numLinesNeeded);
970 // Wind back from our first widowed line.
971 lineBox = currentFirstLineOfNewPage;
972 for (int i = 0; i < numLinesToTake; ++i)
973 lineBox = lineBox->prevRootBox();
975 // We now want to break at this line. Remember for next layout and trigger relayout.
976 setBreakAtLineToAvoidWidow(lineCount(lineBox));
977 markLinesDirtyInBlockRange(lastRootBox()->lineBottomWithLeading(), lineBox->lineBottomWithLeading(), lineBox);
981 clearDidBreakAtLineToAvoidWidow();
984 void RenderBlockFlow::linkToEndLineIfNeeded(LineLayoutState& layoutState)
986 if (layoutState.endLine()) {
987 if (layoutState.endLineMatched()) {
988 bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
989 // Attach all the remaining lines, and then adjust their y-positions as needed.
990 LayoutUnit delta = logicalHeight() - layoutState.endLineLogicalTop();
991 for (RootInlineBox* line = layoutState.endLine(); line; line = line->nextRootBox()) {
994 delta -= line->paginationStrut();
995 adjustLinePositionForPagination(line, delta, layoutState.flowThread());
998 layoutState.updatePaintInvalidationRangeFromBox(line, delta);
999 line->adjustBlockDirectionPosition(delta.toFloat());
1001 if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) {
1002 Vector<RenderBox*>::iterator end = cleanLineFloats->end();
1003 for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) {
1004 FloatingObject* floatingObject = insertFloatingObject(*f);
1005 ASSERT(!floatingObject->originatingLine());
1006 floatingObject->setOriginatingLine(line);
1007 setLogicalHeight(logicalTopForChild(*f) - marginBeforeForChild(*f) + delta);
1008 positionNewFloats();
1012 setLogicalHeight(lastRootBox()->lineBottomWithLeading());
1014 // Delete all the remaining lines.
1015 deleteLineRange(layoutState, layoutState.endLine());
1019 if (m_floatingObjects && (layoutState.checkForFloatsFromLastLine() || positionNewFloats()) && lastRootBox()) {
1020 // In case we have a float on the last line, it might not be positioned up to now.
1021 // This has to be done before adding in the bottom border/padding, or the float will
1022 // include the padding incorrectly. -dwh
1023 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1024 FloatingObjectSetIterator it = floatingObjectSet.begin();
1025 FloatingObjectSetIterator end = floatingObjectSet.end();
1026 if (layoutState.lastFloat()) {
1027 FloatingObjectSetIterator lastFloatIterator = floatingObjectSet.find(layoutState.lastFloat());
1028 ASSERT(lastFloatIterator != end);
1029 ++lastFloatIterator;
1030 it = lastFloatIterator;
1032 layoutState.setLastFloat(!floatingObjectSet.isEmpty() ? floatingObjectSet.last().get() : 0);
1037 if (layoutState.checkForFloatsFromLastLine()) {
1038 LayoutUnit bottomVisualOverflow = lastRootBox()->logicalBottomVisualOverflow();
1039 LayoutUnit bottomLayoutOverflow = lastRootBox()->logicalBottomLayoutOverflow();
1040 TrailingFloatsRootInlineBox* trailingFloatsLineBox = new TrailingFloatsRootInlineBox(*this);
1041 m_lineBoxes.appendLineBox(trailingFloatsLineBox);
1042 trailingFloatsLineBox->setConstructed();
1043 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1044 VerticalPositionCache verticalPositionCache;
1045 LayoutUnit blockLogicalHeight = logicalHeight();
1046 trailingFloatsLineBox->alignBoxesInBlockDirection(blockLogicalHeight, textBoxDataMap, verticalPositionCache);
1047 trailingFloatsLineBox->setLineTopBottomPositions(blockLogicalHeight, blockLogicalHeight, blockLogicalHeight, blockLogicalHeight);
1048 trailingFloatsLineBox->setPaginatedLineWidth(availableLogicalWidthForContent());
1049 LayoutRect logicalLayoutOverflow(0, blockLogicalHeight, 1, bottomLayoutOverflow - blockLogicalHeight);
1050 LayoutRect logicalVisualOverflow(0, blockLogicalHeight, 1, bottomVisualOverflow - blockLogicalHeight);
1051 trailingFloatsLineBox->setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow, trailingFloatsLineBox->lineTop(), trailingFloatsLineBox->lineBottom());
1054 for (; it != end; ++it)
1055 appendFloatingObjectToLastLine(it->get());
1059 void RenderBlockFlow::markDirtyFloatsForPaintInvalidation(Vector<FloatWithRect>& floats)
1061 size_t floatCount = floats.size();
1062 // Floats that did not have layout did not paint invalidations when we laid them out. They would have
1063 // painted by now if they had moved, but if they stayed at (0, 0), they still need to be
1065 for (size_t i = 0; i < floatCount; ++i) {
1066 if (!floats[i].everHadLayout) {
1067 RenderBox* f = floats[i].object;
1068 if (!f->x() && !f->y() && f->checkForPaintInvalidation()) {
1069 f->setShouldDoFullPaintInvalidation(true);
1075 struct InlineMinMaxIterator {
1076 /* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
1077 inline min/max width calculations. Note the following about the way it walks:
1078 (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
1079 (2) We do not drill into the children of floats or replaced elements, since you can't break
1080 in the middle of such an element.
1081 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
1082 distinct borders/margin/padding that contribute to the min/max width.
1084 RenderObject* parent;
1085 RenderObject* current;
1088 InlineMinMaxIterator(RenderObject* p, bool end = false)
1089 : parent(p), current(p), endOfInline(end)
1094 RenderObject* next();
1097 RenderObject* InlineMinMaxIterator::next()
1099 RenderObject* result = 0;
1100 bool oldEndOfInline = endOfInline;
1101 endOfInline = false;
1102 while (current || current == parent) {
1103 if (!oldEndOfInline && (current == parent || (!current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned())))
1104 result = current->slowFirstChild();
1107 // We hit the end of our inline. (It was empty, e.g., <span></span>.)
1108 if (!oldEndOfInline && current->isRenderInline()) {
1114 while (current && current != parent) {
1115 result = current->nextSibling();
1118 current = current->parent();
1119 if (current && current != parent && current->isRenderInline()) {
1130 if (!result->isOutOfFlowPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
1137 // Update our position.
1142 static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit)
1144 if (cssUnit.type() != Auto)
1145 return (cssUnit.isFixed() ? static_cast<LayoutUnit>(cssUnit.value()) : childValue);
1149 static LayoutUnit getBorderPaddingMargin(RenderBoxModelObject* child, bool endOfInline)
1151 RenderStyle* childStyle = child->style();
1153 return getBPMWidth(child->marginEnd(), childStyle->marginEnd()) +
1154 getBPMWidth(child->paddingEnd(), childStyle->paddingEnd()) +
1157 return getBPMWidth(child->marginStart(), childStyle->marginStart()) +
1158 getBPMWidth(child->paddingStart(), childStyle->paddingStart()) +
1159 child->borderStart();
1162 static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, RenderObject* trailingSpaceChild)
1164 if (trailingSpaceChild && trailingSpaceChild->isText()) {
1165 // Collapse away the trailing space at the end of a block.
1166 RenderText* t = toRenderText(trailingSpaceChild);
1167 const UChar space = ' ';
1168 const Font& font = t->style()->font(); // FIXME: This ignores first-line.
1169 float spaceWidth = font.width(constructTextRun(t, font, &space, 1, t->style(), LTR));
1170 inlineMax -= spaceWidth + font.fontDescription().wordSpacing();
1171 if (inlineMin > inlineMax)
1172 inlineMin = inlineMax;
1176 static inline void updatePreferredWidth(LayoutUnit& preferredWidth, float& result)
1178 LayoutUnit snappedResult = LayoutUnit::fromFloatCeil(result);
1179 preferredWidth = std::max(snappedResult, preferredWidth);
1182 // When converting between floating point and LayoutUnits we risk losing precision
1183 // with each conversion. When this occurs while accumulating our preferred widths,
1184 // we can wind up with a line width that's larger than our maxPreferredWidth due to
1185 // pure float accumulation.
1186 static inline LayoutUnit adjustFloatForSubPixelLayout(float value)
1188 return LayoutUnit::fromFloatCeil(value);
1191 // FIXME: This function should be broken into something less monolithic.
1192 // FIXME: The main loop here is very similar to LineBreaker::nextSegmentBreak. They can probably reuse code.
1193 void RenderBlockFlow::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth)
1195 float inlineMax = 0;
1196 float inlineMin = 0;
1198 RenderStyle* styleToUse = style();
1199 RenderBlock* containingBlock = this->containingBlock();
1200 LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit();
1202 // If we are at the start of a line, we want to ignore all white-space.
1203 // Also strip spaces if we previously had text that ended in a trailing space.
1204 bool stripFrontSpaces = true;
1205 RenderObject* trailingSpaceChild = 0;
1207 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
1208 // very specific cirucumstances (in order to match common WinIE renderings).
1209 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
1210 bool allowImagesToBreak = !document().inQuirksMode() || !isTableCell() || !styleToUse->logicalWidth().isIntrinsicOrAuto();
1212 bool autoWrap, oldAutoWrap;
1213 autoWrap = oldAutoWrap = styleToUse->autoWrap();
1215 InlineMinMaxIterator childIterator(this);
1217 // Only gets added to the max preffered width once.
1218 bool addedTextIndent = false;
1219 // Signals the text indent was more negative than the min preferred width
1220 bool hasRemainingNegativeTextIndent = false;
1222 LayoutUnit textIndent = minimumValueForLength(styleToUse->textIndent(), cw);
1223 RenderObject* prevFloat = 0;
1224 bool isPrevChildInlineFlow = false;
1225 bool shouldBreakLineAfterText = false;
1226 while (RenderObject* child = childIterator.next()) {
1227 autoWrap = child->isReplaced() ? child->parent()->style()->autoWrap() :
1228 child->style()->autoWrap();
1230 if (!child->isBR()) {
1231 // Step One: determine whether or not we need to go ahead and
1232 // terminate our current line. Each discrete chunk can become
1233 // the new min-width, if it is the widest chunk seen so far, and
1234 // it can also become the max-width.
1236 // Children fall into three categories:
1237 // (1) An inline flow object. These objects always have a min/max of 0,
1238 // and are included in the iteration solely so that their margins can
1241 // (2) An inline non-text non-flow object, e.g., an inline replaced element.
1242 // These objects can always be on a line by themselves, so in this situation
1243 // we need to go ahead and break the current line, and then add in our own
1244 // margins and min/max width on its own line, and then terminate the line.
1246 // (3) A text object. Text runs can have breakable characters at the start,
1247 // the middle or the end. They may also lose whitespace off the front if
1248 // we're already ignoring whitespace. In order to compute accurate min-width
1249 // information, we need three pieces of information.
1250 // (a) the min-width of the first non-breakable run. Should be 0 if the text string
1251 // starts with whitespace.
1252 // (b) the min-width of the last non-breakable run. Should be 0 if the text string
1253 // ends with whitespace.
1254 // (c) the min/max width of the string (trimmed for whitespace).
1256 // If the text string starts with whitespace, then we need to go ahead and
1257 // terminate our current line (unless we're already in a whitespace stripping
1260 // If the text string has a breakable character in the middle, but didn't start
1261 // with whitespace, then we add the width of the first non-breakable run and
1262 // then end the current line. We then need to use the intermediate min/max width
1263 // values (if any of them are larger than our current min/max). We then look at
1264 // the width of the last non-breakable run and use that to start a new line
1265 // (unless we end in whitespace).
1266 RenderStyle* childStyle = child->style();
1270 if (!child->isText()) {
1271 // Case (1) and (2). Inline replaced and inline flow elements.
1272 if (child->isRenderInline()) {
1273 // Add in padding/border/margin from the appropriate side of
1275 float bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline).toFloat();
1279 inlineMin += childMin;
1280 inlineMax += childMax;
1282 child->clearPreferredLogicalWidthsDirty();
1284 // Inline replaced elts add in their margins to their min/max values.
1285 LayoutUnit margins = 0;
1286 Length startMargin = childStyle->marginStart();
1287 Length endMargin = childStyle->marginEnd();
1288 if (startMargin.isFixed())
1289 margins += adjustFloatForSubPixelLayout(startMargin.value());
1290 if (endMargin.isFixed())
1291 margins += adjustFloatForSubPixelLayout(endMargin.value());
1292 childMin += margins.ceilToFloat();
1293 childMax += margins.ceilToFloat();
1297 if (!child->isRenderInline() && !child->isText()) {
1298 // Case (2). Inline replaced elements and floats.
1299 // Go ahead and terminate the current line as far as
1300 // minwidth is concerned.
1301 LayoutUnit childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth;
1302 if (child->isBox() && child->isHorizontalWritingMode() != isHorizontalWritingMode()) {
1303 RenderBox* childBox = toRenderBox(child);
1304 LogicalExtentComputedValues computedValues;
1305 childBox->computeLogicalHeight(childBox->borderAndPaddingLogicalHeight(), 0, computedValues);
1306 childMinPreferredLogicalWidth = childMaxPreferredLogicalWidth = computedValues.m_extent;
1308 childMinPreferredLogicalWidth = child->minPreferredLogicalWidth();
1309 childMaxPreferredLogicalWidth = child->maxPreferredLogicalWidth();
1311 childMin += childMinPreferredLogicalWidth.ceilToFloat();
1312 childMax += childMaxPreferredLogicalWidth.ceilToFloat();
1314 bool clearPreviousFloat;
1315 if (child->isFloating()) {
1316 clearPreviousFloat = (prevFloat
1317 && ((prevFloat->style()->floating() == LeftFloat && (childStyle->clear() & CLEFT))
1318 || (prevFloat->style()->floating() == RightFloat && (childStyle->clear() & CRIGHT))));
1321 clearPreviousFloat = false;
1324 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
1325 if ((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat) {
1326 updatePreferredWidth(minLogicalWidth, inlineMin);
1330 // If we're supposed to clear the previous float, then terminate maxwidth as well.
1331 if (clearPreviousFloat) {
1332 updatePreferredWidth(maxLogicalWidth, inlineMax);
1336 // Add in text-indent. This is added in only once.
1337 if (!addedTextIndent && !child->isFloating()) {
1338 float ceiledTextIndent = textIndent.ceilToFloat();
1339 childMin += ceiledTextIndent;
1340 childMax += ceiledTextIndent;
1343 textIndent = adjustFloatForSubPixelLayout(childMin);
1345 addedTextIndent = true;
1348 // Add our width to the max.
1349 inlineMax += std::max<float>(0, childMax);
1351 if (!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText)) {
1352 if (child->isFloating())
1353 updatePreferredWidth(minLogicalWidth, childMin);
1355 inlineMin += childMin;
1357 // Now check our line.
1358 updatePreferredWidth(minLogicalWidth, childMin);
1360 // Now start a new line.
1364 if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
1365 updatePreferredWidth(minLogicalWidth, inlineMin);
1369 // We are no longer stripping whitespace at the start of
1371 if (!child->isFloating()) {
1372 stripFrontSpaces = false;
1373 trailingSpaceChild = 0;
1375 } else if (child->isText()) {
1377 RenderText* t = toRenderText(child);
1379 if (t->isWordBreak()) {
1380 updatePreferredWidth(minLogicalWidth, inlineMin);
1385 if (t->style()->hasTextCombine() && t->isCombineText())
1386 toRenderCombineText(t)->combineText();
1388 // Determine if we have a breakable character. Pass in
1389 // whether or not we should ignore any spaces at the front
1390 // of the string. If those are going to be stripped out,
1391 // then they shouldn't be considered in the breakable char
1393 bool hasBreakableChar, hasBreak;
1394 float firstLineMinWidth, lastLineMinWidth;
1395 bool hasBreakableStart, hasBreakableEnd;
1396 float firstLineMaxWidth, lastLineMaxWidth;
1397 t->trimmedPrefWidths(inlineMax,
1398 firstLineMinWidth, hasBreakableStart, lastLineMinWidth, hasBreakableEnd,
1399 hasBreakableChar, hasBreak, firstLineMaxWidth, lastLineMaxWidth,
1400 childMin, childMax, stripFrontSpaces, styleToUse->direction());
1402 // This text object will not be rendered, but it may still provide a breaking opportunity.
1403 if (!hasBreak && !childMax) {
1404 if (autoWrap && (hasBreakableStart || hasBreakableEnd)) {
1405 updatePreferredWidth(minLogicalWidth, inlineMin);
1411 if (stripFrontSpaces)
1412 trailingSpaceChild = child;
1414 trailingSpaceChild = 0;
1416 // Add in text-indent. This is added in only once.
1418 if (!addedTextIndent || hasRemainingNegativeTextIndent) {
1419 ti = textIndent.ceilToFloat();
1421 firstLineMinWidth += ti;
1423 // It the text indent negative and larger than the child minimum, we re-use the remainder
1424 // in future minimum calculations, but using the negative value again on the maximum
1425 // will lead to under-counting the max pref width.
1426 if (!addedTextIndent) {
1428 firstLineMaxWidth += ti;
1429 addedTextIndent = true;
1433 textIndent = childMin;
1434 hasRemainingNegativeTextIndent = true;
1438 // If we have no breakable characters at all,
1439 // then this is the easy case. We add ourselves to the current
1440 // min and max and continue.
1441 if (!hasBreakableChar) {
1442 inlineMin += childMin;
1444 if (hasBreakableStart) {
1445 updatePreferredWidth(minLogicalWidth, inlineMin);
1447 inlineMin += firstLineMinWidth;
1448 updatePreferredWidth(minLogicalWidth, inlineMin);
1452 inlineMin = childMin;
1454 if (hasBreakableEnd) {
1455 updatePreferredWidth(minLogicalWidth, inlineMin);
1457 shouldBreakLineAfterText = false;
1459 updatePreferredWidth(minLogicalWidth, inlineMin);
1460 inlineMin = lastLineMinWidth;
1461 shouldBreakLineAfterText = true;
1466 inlineMax += firstLineMaxWidth;
1467 updatePreferredWidth(maxLogicalWidth, inlineMax);
1468 updatePreferredWidth(maxLogicalWidth, childMax);
1469 inlineMax = lastLineMaxWidth;
1470 addedTextIndent = true;
1472 inlineMax += std::max<float>(0, childMax);
1476 // Ignore spaces after a list marker.
1477 if (child->isListMarker())
1478 stripFrontSpaces = true;
1480 updatePreferredWidth(minLogicalWidth, inlineMin);
1481 updatePreferredWidth(maxLogicalWidth, inlineMax);
1482 inlineMin = inlineMax = 0;
1483 stripFrontSpaces = true;
1484 trailingSpaceChild = 0;
1485 addedTextIndent = true;
1488 if (!child->isText() && child->isRenderInline())
1489 isPrevChildInlineFlow = true;
1491 isPrevChildInlineFlow = false;
1493 oldAutoWrap = autoWrap;
1496 if (styleToUse->collapseWhiteSpace())
1497 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
1499 updatePreferredWidth(minLogicalWidth, inlineMin);
1500 updatePreferredWidth(maxLogicalWidth, inlineMax);
1503 void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& paintInvalidationLogicalTop, LayoutUnit& paintInvalidationLogicalBottom, LayoutUnit afterEdge)
1505 RenderFlowThread* flowThread = flowThreadContainingBlock();
1506 bool clearLinesForPagination = firstLineBox() && flowThread && !flowThread->hasRegions();
1508 // Figure out if we should clear out our line boxes.
1509 // FIXME: Handle resize eventually!
1510 bool isFullLayout = !firstLineBox() || selfNeedsLayout() || relayoutChildren || clearLinesForPagination;
1511 LineLayoutState layoutState(isFullLayout, paintInvalidationLogicalTop, paintInvalidationLogicalBottom, flowThread);
1514 // Ensure the old line boxes will be erased.
1516 setShouldDoFullPaintInvalidation(true);
1517 lineBoxes()->deleteLineBoxes();
1520 // Text truncation kicks in in two cases:
1521 // 1) If your overflow isn't visible and your text-overflow-mode isn't clip.
1522 // 2) If you're an anonymous block with a block parent that satisfies #1 that was created
1523 // to accomodate a block that has inline and block children. This excludes parents where
1524 // canCollapseAnonymousBlockChild is false, notabley flex items and grid items.
1525 // FIXME: CSS3 says that descendants that are clipped must also know how to truncate. This is insanely
1526 // difficult to figure out in general (especially in the middle of doing layout), so we only handle the
1527 // simple case of an anonymous block truncating when it's parent is clipped.
1528 bool hasTextOverflow = (style()->textOverflow() && hasOverflowClip())
1529 || (isAnonymousBlock() && parent() && parent()->isRenderBlock() && toRenderBlock(parent())->canCollapseAnonymousBlockChild()
1530 && parent()->style()->textOverflow() && parent()->hasOverflowClip());
1532 // Walk all the lines and delete our ellipsis line boxes if they exist.
1533 if (hasTextOverflow)
1534 deleteEllipsisLineBoxes();
1537 // In full layout mode, clear the line boxes of children upfront. Otherwise,
1538 // siblings can run into stale root lineboxes during layout. Then layout
1539 // the replaced elements later. In partial layout mode, line boxes are not
1540 // deleted and only dirtied. In that case, we can layout the replaced
1541 // elements at the same time.
1542 Vector<RenderBox*> replacedChildren;
1543 for (InlineWalker walker(this); !walker.atEnd(); walker.advance()) {
1544 RenderObject* o = walker.current();
1546 if (!layoutState.hasInlineChild() && o->isInline())
1547 layoutState.setHasInlineChild(true);
1549 if (o->isReplaced() || o->isFloating() || o->isOutOfFlowPositioned()) {
1550 RenderBox* box = toRenderBox(o);
1552 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, box);
1554 if (o->isOutOfFlowPositioned())
1555 o->containingBlock()->insertPositionedObject(box);
1556 else if (o->isFloating())
1557 layoutState.floats().append(FloatWithRect(box));
1558 else if (isFullLayout || o->needsLayout()) {
1559 // Replaced element.
1560 box->dirtyLineBoxes(isFullLayout);
1562 replacedChildren.append(box);
1564 o->layoutIfNeeded();
1566 } else if (o->isText() || (o->isRenderInline() && !walker.atEndOfInline())) {
1568 toRenderInline(o)->updateAlwaysCreateLineBoxes(layoutState.isFullLayout());
1569 if (layoutState.isFullLayout() || o->selfNeedsLayout())
1570 dirtyLineBoxesForRenderer(o, layoutState.isFullLayout());
1571 o->clearNeedsLayout();
1575 for (size_t i = 0; i < replacedChildren.size(); i++)
1576 replacedChildren[i]->layoutIfNeeded();
1578 layoutRunsAndFloats(layoutState);
1581 // Expand the last line to accommodate Ruby and emphasis marks.
1582 int lastLineAnnotationsAdjustment = 0;
1583 if (lastRootBox()) {
1584 LayoutUnit lowestAllowedPosition = std::max(lastRootBox()->lineBottom(), logicalHeight() + paddingAfter());
1585 if (!style()->isFlippedLinesWritingMode())
1586 lastLineAnnotationsAdjustment = lastRootBox()->computeUnderAnnotationAdjustment(lowestAllowedPosition);
1588 lastLineAnnotationsAdjustment = lastRootBox()->computeOverAnnotationAdjustment(lowestAllowedPosition);
1591 // Now add in the bottom border/padding.
1592 setLogicalHeight(logicalHeight() + lastLineAnnotationsAdjustment + afterEdge);
1594 if (!firstLineBox() && hasLineIfEmpty())
1595 setLogicalHeight(logicalHeight() + lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
1597 // See if we have any lines that spill out of our block. If we do, then we will possibly need to
1599 if (hasTextOverflow)
1600 checkLinesForTextOverflow();
1602 // Ensure the new line boxes will be painted.
1603 if (isFullLayout && firstLineBox())
1604 setShouldDoFullPaintInvalidation(true);
1607 void RenderBlockFlow::checkFloatsInCleanLine(RootInlineBox* line, Vector<FloatWithRect>& floats, size_t& floatIndex, bool& encounteredNewFloat, bool& dirtiedByFloat)
1609 Vector<RenderBox*>* cleanLineFloats = line->floatsPtr();
1610 if (!cleanLineFloats)
1613 Vector<RenderBox*>::iterator end = cleanLineFloats->end();
1614 for (Vector<RenderBox*>::iterator it = cleanLineFloats->begin(); it != end; ++it) {
1615 RenderBox* floatingBox = *it;
1616 floatingBox->layoutIfNeeded();
1617 LayoutSize newSize(floatingBox->width() + floatingBox->marginWidth(), floatingBox->height() + floatingBox->marginHeight());
1618 if (floats[floatIndex].object != floatingBox) {
1619 encounteredNewFloat = true;
1623 if (floats[floatIndex].rect.size() != newSize) {
1624 LayoutUnit floatTop = isHorizontalWritingMode() ? floats[floatIndex].rect.y() : floats[floatIndex].rect.x();
1625 LayoutUnit floatHeight = isHorizontalWritingMode() ? std::max(floats[floatIndex].rect.height(), newSize.height())
1626 : std::max(floats[floatIndex].rect.width(), newSize.width());
1627 floatHeight = std::min(floatHeight, LayoutUnit::max() - floatTop);
1629 markLinesDirtyInBlockRange(line->lineBottomWithLeading(), floatTop + floatHeight, line);
1630 floats[floatIndex].rect.setSize(newSize);
1631 dirtiedByFloat = true;
1637 RootInlineBox* RenderBlockFlow::determineStartPosition(LineLayoutState& layoutState, InlineBidiResolver& resolver)
1639 RootInlineBox* curr = 0;
1640 RootInlineBox* last = 0;
1642 // FIXME: This entire float-checking block needs to be broken into a new function.
1643 bool dirtiedByFloat = false;
1644 if (!layoutState.isFullLayout()) {
1645 // Paginate all of the clean lines.
1646 bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
1647 LayoutUnit paginationDelta = 0;
1648 size_t floatIndex = 0;
1649 for (curr = firstRootBox(); curr && !curr->isDirty(); curr = curr->nextRootBox()) {
1651 paginationDelta -= curr->paginationStrut();
1652 adjustLinePositionForPagination(curr, paginationDelta, layoutState.flowThread());
1653 if (paginationDelta) {
1654 if (containsFloats() || !layoutState.floats().isEmpty()) {
1655 // FIXME: Do better eventually. For now if we ever shift because of pagination and floats are present just go to a full layout.
1656 layoutState.markForFullLayout();
1660 layoutState.updatePaintInvalidationRangeFromBox(curr, paginationDelta);
1661 curr->adjustBlockDirectionPosition(paginationDelta.toFloat());
1665 // If a new float has been inserted before this line or before its last known float, just do a full layout.
1666 bool encounteredNewFloat = false;
1667 checkFloatsInCleanLine(curr, layoutState.floats(), floatIndex, encounteredNewFloat, dirtiedByFloat);
1668 if (encounteredNewFloat)
1669 layoutState.markForFullLayout();
1671 if (dirtiedByFloat || layoutState.isFullLayout())
1674 // Check if a new float has been inserted after the last known float.
1675 if (!curr && floatIndex < layoutState.floats().size())
1676 layoutState.markForFullLayout();
1679 if (layoutState.isFullLayout()) {
1680 // If we encountered a new float and have inline children, mark ourself to force us to issue paint invalidations.
1681 if (layoutState.hasInlineChild() && !selfNeedsLayout()) {
1682 setNeedsLayoutAndFullPaintInvalidation(MarkOnlyThis);
1683 setShouldDoFullPaintInvalidation(true);
1686 // FIXME: This should just call deleteLineBoxTree, but that causes
1687 // crashes for fast/repaint tests.
1688 curr = firstRootBox();
1690 // Note: This uses nextRootBox() insted of nextLineBox() like deleteLineBoxTree does.
1691 RootInlineBox* next = curr->nextRootBox();
1695 ASSERT(!firstLineBox() && !lastLineBox());
1698 // We have a dirty line.
1699 if (RootInlineBox* prevRootBox = curr->prevRootBox()) {
1700 // We have a previous line.
1701 if (!dirtiedByFloat && (!prevRootBox->endsWithBreak() || !prevRootBox->lineBreakObj() || (prevRootBox->lineBreakObj()->isText() && prevRootBox->lineBreakPos() >= toRenderText(prevRootBox->lineBreakObj())->textLength())))
1702 // The previous line didn't break cleanly or broke at a newline
1703 // that has been deleted, so treat it as dirty too.
1707 // No dirty lines were found.
1708 // If the last line didn't break cleanly, treat it as dirty.
1709 if (lastRootBox() && !lastRootBox()->endsWithBreak())
1710 curr = lastRootBox();
1713 // If we have no dirty lines, then last is just the last root box.
1714 last = curr ? curr->prevRootBox() : lastRootBox();
1717 unsigned numCleanFloats = 0;
1718 if (!layoutState.floats().isEmpty()) {
1719 LayoutUnit savedLogicalHeight = logicalHeight();
1720 // Restore floats from clean lines.
1721 RootInlineBox* line = firstRootBox();
1722 while (line != curr) {
1723 if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) {
1724 Vector<RenderBox*>::iterator end = cleanLineFloats->end();
1725 for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) {
1726 FloatingObject* floatingObject = insertFloatingObject(*f);
1727 ASSERT(!floatingObject->originatingLine());
1728 floatingObject->setOriginatingLine(line);
1729 setLogicalHeight(logicalTopForChild(*f) - marginBeforeForChild(*f));
1730 positionNewFloats();
1731 ASSERT(layoutState.floats()[numCleanFloats].object == *f);
1735 line = line->nextRootBox();
1737 setLogicalHeight(savedLogicalHeight);
1739 layoutState.setFloatIndex(numCleanFloats);
1741 layoutState.lineInfo().setFirstLine(!last);
1742 layoutState.lineInfo().setPreviousLineBrokeCleanly(!last || last->endsWithBreak());
1745 setLogicalHeight(last->lineBottomWithLeading());
1746 InlineIterator iter = InlineIterator(this, last->lineBreakObj(), last->lineBreakPos());
1747 resolver.setPosition(iter, numberOfIsolateAncestors(iter));
1748 resolver.setStatus(last->lineBreakBidiStatus());
1750 TextDirection direction = style()->direction();
1751 if (style()->unicodeBidi() == Plaintext)
1752 direction = determinePlaintextDirectionality(this);
1753 resolver.setStatus(BidiStatus(direction, isOverride(style()->unicodeBidi())));
1754 InlineIterator iter = InlineIterator(this, bidiFirstSkippingEmptyInlines(this, resolver.runs(), &resolver), 0);
1755 resolver.setPosition(iter, numberOfIsolateAncestors(iter));
1760 void RenderBlockFlow::determineEndPosition(LineLayoutState& layoutState, RootInlineBox* startLine, InlineIterator& cleanLineStart, BidiStatus& cleanLineBidiStatus)
1762 ASSERT(!layoutState.endLine());
1763 size_t floatIndex = layoutState.floatIndex();
1764 RootInlineBox* last = 0;
1765 for (RootInlineBox* curr = startLine->nextRootBox(); curr; curr = curr->nextRootBox()) {
1766 if (!curr->isDirty()) {
1767 bool encounteredNewFloat = false;
1768 bool dirtiedByFloat = false;
1769 checkFloatsInCleanLine(curr, layoutState.floats(), floatIndex, encounteredNewFloat, dirtiedByFloat);
1770 if (encounteredNewFloat)
1773 if (curr->isDirty())
1782 // At this point, |last| is the first line in a run of clean lines that ends with the last line
1785 RootInlineBox* prev = last->prevRootBox();
1786 cleanLineStart = InlineIterator(this, prev->lineBreakObj(), prev->lineBreakPos());
1787 cleanLineBidiStatus = prev->lineBreakBidiStatus();
1788 layoutState.setEndLineLogicalTop(prev->lineBottomWithLeading());
1790 for (RootInlineBox* line = last; line; line = line->nextRootBox())
1791 line->extractLine(); // Disconnect all line boxes from their render objects while preserving
1792 // their connections to one another.
1794 layoutState.setEndLine(last);
1797 bool RenderBlockFlow::checkPaginationAndFloatsAtEndLine(LineLayoutState& layoutState)
1799 LayoutUnit lineDelta = logicalHeight() - layoutState.endLineLogicalTop();
1801 bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
1802 if (paginated && layoutState.flowThread()) {
1803 // Check all lines from here to the end, and see if the hypothetical new position for the lines will result
1804 // in a different available line width.
1805 for (RootInlineBox* lineBox = layoutState.endLine(); lineBox; lineBox = lineBox->nextRootBox()) {
1807 // This isn't the real move we're going to do, so don't update the line box's pagination
1809 LayoutUnit oldPaginationStrut = lineBox->paginationStrut();
1810 lineDelta -= oldPaginationStrut;
1811 adjustLinePositionForPagination(lineBox, lineDelta, layoutState.flowThread());
1812 lineBox->setPaginationStrut(oldPaginationStrut);
1817 if (!lineDelta || !m_floatingObjects)
1820 // See if any floats end in the range along which we want to shift the lines vertically.
1821 LayoutUnit logicalTop = std::min(logicalHeight(), layoutState.endLineLogicalTop());
1823 RootInlineBox* lastLine = layoutState.endLine();
1824 while (RootInlineBox* nextLine = lastLine->nextRootBox())
1825 lastLine = nextLine;
1827 LayoutUnit logicalBottom = lastLine->lineBottomWithLeading() + absoluteValue(lineDelta);
1829 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1830 FloatingObjectSetIterator end = floatingObjectSet.end();
1831 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
1832 FloatingObject* floatingObject = it->get();
1833 if (logicalBottomForFloat(floatingObject) >= logicalTop && logicalBottomForFloat(floatingObject) < logicalBottom)
1840 bool RenderBlockFlow::matchedEndLine(LineLayoutState& layoutState, const InlineBidiResolver& resolver, const InlineIterator& endLineStart, const BidiStatus& endLineStatus)
1842 if (resolver.position() == endLineStart) {
1843 if (resolver.status() != endLineStatus)
1845 return checkPaginationAndFloatsAtEndLine(layoutState);
1848 // The first clean line doesn't match, but we can check a handful of following lines to try
1849 // to match back up.
1850 static int numLines = 8; // The # of lines we're willing to match against.
1851 RootInlineBox* originalEndLine = layoutState.endLine();
1852 RootInlineBox* line = originalEndLine;
1853 for (int i = 0; i < numLines && line; i++, line = line->nextRootBox()) {
1854 if (line->lineBreakObj() == resolver.position().object() && line->lineBreakPos() == resolver.position().offset()) {
1856 if (line->lineBreakBidiStatus() != resolver.status())
1857 return false; // ...but the bidi state doesn't match.
1859 bool matched = false;
1860 RootInlineBox* result = line->nextRootBox();
1861 layoutState.setEndLine(result);
1863 layoutState.setEndLineLogicalTop(line->lineBottomWithLeading());
1864 matched = checkPaginationAndFloatsAtEndLine(layoutState);
1867 // Now delete the lines that we failed to sync.
1868 deleteLineRange(layoutState, originalEndLine, result);
1876 bool RenderBlockFlow::generatesLineBoxesForInlineChild(RenderObject* inlineObj)
1879 ASSERT(inlineObj->parent() == this);
1881 InlineIterator it(this, inlineObj, 0);
1882 // FIXME: We should pass correct value for WhitespacePosition.
1883 while (!it.atEnd() && !requiresLineBox(it))
1890 void RenderBlockFlow::addOverflowFromInlineChildren()
1892 LayoutUnit endPadding = hasOverflowClip() ? paddingEnd() : LayoutUnit();
1893 // FIXME: Need to find another way to do this, since scrollbars could show when we don't want them to.
1894 if (hasOverflowClip() && !endPadding && node() && node()->isRootEditableElement() && style()->isLeftToRightDirection())
1896 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
1897 addLayoutOverflow(curr->paddedLayoutOverflowRect(endPadding));
1898 LayoutRect visualOverflow = curr->visualOverflowRect(curr->lineTop(), curr->lineBottom());
1899 addContentsVisualOverflow(visualOverflow);
1903 void RenderBlockFlow::deleteEllipsisLineBoxes()
1905 ETextAlign textAlign = style()->textAlign();
1906 bool ltr = style()->isLeftToRightDirection();
1907 bool firstLine = true;
1908 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
1909 if (curr->hasEllipsisBox()) {
1910 curr->clearTruncation();
1912 // Shift the line back where it belongs if we cannot accomodate an ellipsis.
1913 float logicalLeft = logicalLeftOffsetForLine(curr->lineTop(), firstLine).toFloat();
1914 float availableLogicalWidth = logicalRightOffsetForLine(curr->lineTop(), false) - logicalLeft;
1915 float totalLogicalWidth = curr->logicalWidth();
1916 updateLogicalWidthForAlignment(textAlign, curr, 0, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0);
1919 curr->adjustLogicalPosition((logicalLeft - curr->logicalLeft()), 0);
1921 curr->adjustLogicalPosition(-(curr->logicalLeft() - logicalLeft), 0);
1927 void RenderBlockFlow::checkLinesForTextOverflow()
1929 // Determine the width of the ellipsis using the current font.
1930 // FIXME: CSS3 says this is configurable, also need to use 0x002E (FULL STOP) if horizontal ellipsis is "not renderable"
1931 const Font& font = style()->font();
1932 DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1));
1933 const Font& firstLineFont = firstLineStyle()->font();
1934 // FIXME: We should probably not hard-code the direction here. https://crbug.com/333004
1935 TextDirection ellipsisDirection = LTR;
1936 float firstLineEllipsisWidth = firstLineFont.width(constructTextRun(this, firstLineFont, &horizontalEllipsis, 1, firstLineStyle(), ellipsisDirection));
1937 float ellipsisWidth = (font == firstLineFont) ? firstLineEllipsisWidth : font.width(constructTextRun(this, font, &horizontalEllipsis, 1, style(), ellipsisDirection));
1939 // For LTR text truncation, we want to get the right edge of our padding box, and then we want to see
1940 // if the right edge of a line box exceeds that. For RTL, we use the left edge of the padding box and
1941 // check the left edge of the line box to see if it is less
1942 // Include the scrollbar for overflow blocks, which means we want to use "contentWidth()"
1943 bool ltr = style()->isLeftToRightDirection();
1944 ETextAlign textAlign = style()->textAlign();
1945 bool firstLine = true;
1946 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
1947 float currLogicalLeft = curr->logicalLeft();
1948 LayoutUnit blockRightEdge = logicalRightOffsetForLine(curr->lineTop(), firstLine);
1949 LayoutUnit blockLeftEdge = logicalLeftOffsetForLine(curr->lineTop(), firstLine);
1950 LayoutUnit lineBoxEdge = ltr ? currLogicalLeft + curr->logicalWidth() : currLogicalLeft;
1951 if ((ltr && lineBoxEdge > blockRightEdge) || (!ltr && lineBoxEdge < blockLeftEdge)) {
1952 // This line spills out of our box in the appropriate direction. Now we need to see if the line
1953 // can be truncated. In order for truncation to be possible, the line must have sufficient space to
1954 // accommodate our truncation string, and no replaced elements (images, tables) can overlap the ellipsis
1957 LayoutUnit width = firstLine ? firstLineEllipsisWidth : ellipsisWidth;
1958 LayoutUnit blockEdge = ltr ? blockRightEdge : blockLeftEdge;
1959 if (curr->lineCanAccommodateEllipsis(ltr, blockEdge, lineBoxEdge, width)) {
1960 float totalLogicalWidth = curr->placeEllipsis(ellipsisStr, ltr, blockLeftEdge.toFloat(), blockRightEdge.toFloat(), width.toFloat());
1962 float logicalLeft = 0; // We are only intersted in the delta from the base position.
1963 float availableLogicalWidth = (blockRightEdge - blockLeftEdge).toFloat();
1964 updateLogicalWidthForAlignment(textAlign, curr, 0, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0);
1966 curr->adjustLogicalPosition(logicalLeft, 0);
1968 curr->adjustLogicalPosition(logicalLeft - (availableLogicalWidth - totalLogicalWidth), 0);
1975 bool RenderBlockFlow::positionNewFloatOnLine(FloatingObject* newFloat, FloatingObject* lastFloatFromPreviousLine, LineInfo& lineInfo, LineWidth& width)
1977 if (!positionNewFloats())
1980 width.shrinkAvailableWidthForNewFloatIfNeeded(newFloat);
1982 // We only connect floats to lines for pagination purposes if the floats occur at the start of
1983 // the line and the previous line had a hard break (so this line is either the first in the block
1984 // or follows a <br>).
1985 if (!newFloat->paginationStrut() || !lineInfo.previousLineBrokeCleanly() || !lineInfo.isEmpty())
1988 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1989 ASSERT(floatingObjectSet.last() == newFloat);
1991 LayoutUnit floatLogicalTop = logicalTopForFloat(newFloat);
1992 int paginationStrut = newFloat->paginationStrut();
1994 if (floatLogicalTop - paginationStrut != logicalHeight() + lineInfo.floatPaginationStrut())
1997 FloatingObjectSetIterator it = floatingObjectSet.end();
1998 --it; // Last float is newFloat, skip that one.
1999 FloatingObjectSetIterator begin = floatingObjectSet.begin();
2000 while (it != begin) {
2002 FloatingObject* floatingObject = it->get();
2003 if (floatingObject == lastFloatFromPreviousLine)
2005 if (logicalTopForFloat(floatingObject) == logicalHeight() + lineInfo.floatPaginationStrut()) {
2006 floatingObject->setPaginationStrut(paginationStrut + floatingObject->paginationStrut());
2007 RenderBox* floatBox = floatingObject->renderer();
2008 setLogicalTopForChild(floatBox, logicalTopForChild(floatBox) + marginBeforeForChild(floatBox) + paginationStrut);
2009 if (floatBox->isRenderBlock())
2010 floatBox->forceChildLayout();
2012 floatBox->layoutIfNeeded();
2013 // Save the old logical top before calling removePlacedObject which will set
2014 // isPlaced to false. Otherwise it will trigger an assert in logicalTopForFloat.
2015 LayoutUnit oldLogicalTop = logicalTopForFloat(floatingObject);
2016 m_floatingObjects->removePlacedObject(floatingObject);
2017 setLogicalTopForFloat(floatingObject, oldLogicalTop + paginationStrut);
2018 m_floatingObjects->addPlacedObject(floatingObject);
2022 // Just update the line info's pagination strut without altering our logical height yet. If the line ends up containing
2023 // no content, then we don't want to improperly grow the height of the block.
2024 lineInfo.setFloatPaginationStrut(lineInfo.floatPaginationStrut() + paginationStrut);
2028 LayoutUnit RenderBlockFlow::startAlignedOffsetForLine(LayoutUnit position, bool firstLine)
2030 ETextAlign textAlign = style()->textAlign();
2032 if (textAlign == TASTART) // FIXME: Handle TAEND here
2033 return startOffsetForLine(position, firstLine);
2035 // updateLogicalWidthForAlignment() handles the direction of the block so no need to consider it here
2036 float totalLogicalWidth = 0;
2037 float logicalLeft = logicalLeftOffsetForLine(logicalHeight(), false).toFloat();
2038 float availableLogicalWidth = logicalRightOffsetForLine(logicalHeight(), false) - logicalLeft;
2039 updateLogicalWidthForAlignment(textAlign, 0, 0, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0);
2041 if (!style()->isLeftToRightDirection())
2042 return logicalWidth() - logicalLeft;