Rename rendering/RenderFileUploadControl to layout/LayoutFileUploadControl.
[chromium-blink-merge.git] / third_party / WebKit / Source / core / rendering / RenderBlockLineLayout.cpp
blob7a11f4fc1b7b154a86ed2fe67541147a0685e28d
1 /*
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.
23 #include "config.h"
25 #include "core/dom/AXObjectCache.h"
26 #include "core/layout/BidiRunForLine.h"
27 #include "core/layout/Layer.h"
28 #include "core/layout/LayoutCounter.h"
29 #include "core/layout/LayoutFlowThread.h"
30 #include "core/layout/LayoutListMarker.h"
31 #include "core/layout/LayoutObject.h"
32 #include "core/layout/LayoutRegion.h"
33 #include "core/layout/LayoutRubyRun.h"
34 #include "core/layout/TextRunConstructor.h"
35 #include "core/layout/VerticalPositionCache.h"
36 #include "core/layout/line/BreakingContextInlineHeaders.h"
37 #include "core/layout/line/LayoutTextInfo.h"
38 #include "core/layout/line/LineLayoutState.h"
39 #include "core/layout/line/LineWidth.h"
40 #include "core/layout/line/TrailingFloatsRootInlineBox.h"
41 #include "core/layout/line/WordMeasurement.h"
42 #include "core/layout/svg/line/SVGRootInlineBox.h"
43 #include "core/rendering/RenderView.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"
51 namespace blink {
53 using namespace WTF::Unicode;
55 static inline InlineBox* createInlineBoxForRenderer(LayoutObject* obj, bool isRootLineBox, bool isOnlyRun = false)
57 // Callers should handle text themselves.
58 ASSERT(!obj->isText());
60 if (isRootLineBox)
61 return toRenderBlockFlow(obj)->createAndAppendRootInlineBox();
63 if (obj->isBox())
64 return toLayoutBox(obj)->createInlineBox();
66 return toRenderInline(obj)->createAndAppendInlineFlowBox();
69 static inline InlineTextBox* createInlineBoxForText(BidiRun& run, bool isOnlyRun)
71 ASSERT(run.m_object->isText());
72 RenderText* text = toRenderText(run.m_object);
73 InlineTextBox* textBox = text->createInlineTextBox(run.m_start, run.m_stop - run.m_start);
74 // We only treat a box as text for a <br> if we are on a line by ourself or in strict mode
75 // (Note the use of strict mode. In "almost strict" mode, we don't treat the box for <br> as text.)
76 if (text->isBR())
77 textBox->setIsText(isOnlyRun || text->document().inNoQuirksMode());
78 textBox->setDirOverride(run.dirOverride(text->style()->rtlOrdering() == VisualOrder));
79 if (run.m_hasHyphen)
80 textBox->setHasHyphen(true);
81 return textBox;
84 static inline void dirtyLineBoxesForRenderer(LayoutObject* o, bool fullLayout)
86 if (o->isText()) {
87 RenderText* renderText = toRenderText(o);
88 renderText->dirtyOrDeleteLineBoxesIfNeeded(fullLayout);
89 } else
90 toRenderInline(o)->dirtyLineBoxes(fullLayout);
93 static bool parentIsConstructedOrHaveNext(InlineFlowBox* parentBox)
95 do {
96 if (parentBox->isConstructed() || parentBox->nextOnLine())
97 return true;
98 parentBox = parentBox->parent();
99 } while (parentBox);
100 return false;
103 InlineFlowBox* RenderBlockFlow::createLineBoxes(LayoutObject* obj, const LineInfo& lineInfo, InlineBox* childBox)
105 // See if we have an unconstructed line box for this object that is also
106 // the last item on the line.
107 unsigned lineDepth = 1;
108 InlineFlowBox* parentBox = 0;
109 InlineFlowBox* result = 0;
110 bool hasDefaultLineBoxContain = style()->lineBoxContain() == LayoutStyle::initialLineBoxContain();
111 do {
112 ASSERT_WITH_SECURITY_IMPLICATION(obj->isRenderInline() || obj == this);
114 RenderInline* inlineFlow = (obj != this) ? toRenderInline(obj) : 0;
116 // Get the last box we made for this render object.
117 parentBox = inlineFlow ? inlineFlow->lastLineBox() : toRenderBlock(obj)->lastLineBox();
119 // If this box or its ancestor is constructed then it is from a previous line, and we need
120 // to make a new box for our line. If this box or its ancestor is unconstructed but it has
121 // something following it on the line, then we know we have to make a new box
122 // as well. In this situation our inline has actually been split in two on
123 // the same line (this can happen with very fancy language mixtures).
124 bool constructedNewBox = false;
125 bool allowedToConstructNewBox = !hasDefaultLineBoxContain || !inlineFlow || inlineFlow->alwaysCreateLineBoxes();
126 bool canUseExistingParentBox = parentBox && !parentIsConstructedOrHaveNext(parentBox);
127 if (allowedToConstructNewBox && !canUseExistingParentBox) {
128 // We need to make a new box for this render object. Once
129 // made, we need to place it at the end of the current line.
130 InlineBox* newBox = createInlineBoxForRenderer(obj, obj == this);
131 ASSERT_WITH_SECURITY_IMPLICATION(newBox->isInlineFlowBox());
132 parentBox = toInlineFlowBox(newBox);
133 parentBox->setFirstLineStyleBit(lineInfo.isFirstLine());
134 parentBox->setIsHorizontal(isHorizontalWritingMode());
135 if (!hasDefaultLineBoxContain)
136 parentBox->clearDescendantsHaveSameLineHeightAndBaseline();
137 constructedNewBox = true;
140 if (constructedNewBox || canUseExistingParentBox) {
141 if (!result)
142 result = parentBox;
144 // If we have hit the block itself, then |box| represents the root
145 // inline box for the line, and it doesn't have to be appended to any parent
146 // inline.
147 if (childBox)
148 parentBox->addToLine(childBox);
150 if (!constructedNewBox || obj == this)
151 break;
153 childBox = parentBox;
156 // If we've exceeded our line depth, then jump straight to the root and skip all the remaining
157 // intermediate inline flows.
158 obj = (++lineDepth >= cMaxLineDepth) ? this : obj->parent();
160 } while (true);
162 return result;
165 template <typename CharacterType>
166 static inline bool endsWithASCIISpaces(const CharacterType* characters, unsigned pos, unsigned end)
168 while (isASCIISpace(characters[pos])) {
169 pos++;
170 if (pos >= end)
171 return true;
173 return false;
176 static bool reachedEndOfTextRenderer(const BidiRunList<BidiRun>& bidiRuns)
178 BidiRun* run = bidiRuns.logicallyLastRun();
179 if (!run)
180 return true;
181 unsigned pos = run->stop();
182 LayoutObject* r = run->m_object;
183 if (!r->isText() || r->isBR())
184 return false;
185 RenderText* renderText = toRenderText(r);
186 unsigned length = renderText->textLength();
187 if (pos >= length)
188 return true;
190 if (renderText->is8Bit())
191 return endsWithASCIISpaces(renderText->characters8(), pos, length);
192 return endsWithASCIISpaces(renderText->characters16(), pos, length);
195 RootInlineBox* RenderBlockFlow::constructLine(BidiRunList<BidiRun>& bidiRuns, const LineInfo& lineInfo)
197 ASSERT(bidiRuns.firstRun());
199 bool rootHasSelectedChildren = false;
200 InlineFlowBox* parentBox = 0;
201 int runCount = bidiRuns.runCount() - lineInfo.runsFromLeadingWhitespace();
202 for (BidiRun* r = bidiRuns.firstRun(); r; r = r->next()) {
203 // Create a box for our object.
204 bool isOnlyRun = (runCount == 1);
205 if (runCount == 2 && !r->m_object->isListMarker())
206 isOnlyRun = (!style()->isLeftToRightDirection() ? bidiRuns.lastRun() : bidiRuns.firstRun())->m_object->isListMarker();
208 if (lineInfo.isEmpty())
209 continue;
211 InlineBox* box;
212 if (r->m_object->isText())
213 box = createInlineBoxForText(*r, isOnlyRun);
214 else
215 box = createInlineBoxForRenderer(r->m_object, false, isOnlyRun);
216 r->m_box = box;
218 ASSERT(box);
219 if (!box)
220 continue;
222 if (!rootHasSelectedChildren && box->renderer().selectionState() != LayoutObject::SelectionNone)
223 rootHasSelectedChildren = true;
225 // If we have no parent box yet, or if the run is not simply a sibling,
226 // then we need to construct inline boxes as necessary to properly enclose the
227 // run's inline box. Segments can only be siblings at the root level, as
228 // they are positioned separately.
229 if (!parentBox || parentBox->renderer() != r->m_object->parent()) {
230 // Create new inline boxes all the way back to the appropriate insertion point.
231 parentBox = createLineBoxes(r->m_object->parent(), lineInfo, box);
232 } else {
233 // Append the inline box to this line.
234 parentBox->addToLine(box);
237 box->setBidiLevel(r->level());
239 if (box->isInlineTextBox()) {
240 if (AXObjectCache* cache = document().existingAXObjectCache())
241 cache->inlineTextBoxesUpdated(r->m_object);
245 // We should have a root inline box. It should be unconstructed and
246 // be the last continuation of our line list.
247 ASSERT(lastLineBox() && !lastLineBox()->isConstructed());
249 // Set the m_selectedChildren flag on the root inline box if one of the leaf inline box
250 // from the bidi runs walk above has a selection state.
251 if (rootHasSelectedChildren)
252 lastLineBox()->root().setHasSelectedChildren(true);
254 // Set bits on our inline flow boxes that indicate which sides should
255 // paint borders/margins/padding. This knowledge will ultimately be used when
256 // we determine the horizontal positions and widths of all the inline boxes on
257 // the line.
258 bool isLogicallyLastRunWrapped = bidiRuns.logicallyLastRun()->m_object && bidiRuns.logicallyLastRun()->m_object->isText() ? !reachedEndOfTextRenderer(bidiRuns) : true;
259 lastLineBox()->determineSpacingForFlowBoxes(lineInfo.isLastLine(), isLogicallyLastRunWrapped, bidiRuns.logicallyLastRun()->m_object);
261 // Now mark the line boxes as being constructed.
262 lastLineBox()->setConstructed();
264 // Return the last line.
265 return lastRootBox();
268 ETextAlign RenderBlockFlow::textAlignmentForLine(bool endsWithSoftBreak) const
270 ETextAlign alignment = style()->textAlign();
271 if (endsWithSoftBreak)
272 return alignment;
274 if (!RuntimeEnabledFeatures::css3TextEnabled())
275 return (alignment == JUSTIFY) ? TASTART : alignment;
277 TextAlignLast alignmentLast = style()->textAlignLast();
278 switch (alignmentLast) {
279 case TextAlignLastStart:
280 return TASTART;
281 case TextAlignLastEnd:
282 return TAEND;
283 case TextAlignLastLeft:
284 return LEFT;
285 case TextAlignLastRight:
286 return RIGHT;
287 case TextAlignLastCenter:
288 return CENTER;
289 case TextAlignLastJustify:
290 return JUSTIFY;
291 case TextAlignLastAuto:
292 if (alignment == JUSTIFY)
293 return TASTART;
294 return alignment;
297 return alignment;
300 static void updateLogicalWidthForLeftAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
302 // The direction of the block should determine what happens with wide lines.
303 // In particular with RTL blocks, wide lines should still spill out to the left.
304 if (isLeftToRightDirection) {
305 if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun)
306 trailingSpaceRun->m_box->setLogicalWidth(std::max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
307 return;
310 if (trailingSpaceRun)
311 trailingSpaceRun->m_box->setLogicalWidth(0);
312 else if (totalLogicalWidth > availableLogicalWidth)
313 logicalLeft -= (totalLogicalWidth - availableLogicalWidth);
316 static void updateLogicalWidthForRightAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
318 // Wide lines spill out of the block based off direction.
319 // So even if text-align is right, if direction is LTR, wide lines should overflow out of the right
320 // side of the block.
321 if (isLeftToRightDirection) {
322 if (trailingSpaceRun) {
323 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
324 trailingSpaceRun->m_box->setLogicalWidth(0);
326 if (totalLogicalWidth < availableLogicalWidth)
327 logicalLeft += availableLogicalWidth - totalLogicalWidth;
328 return;
331 if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun) {
332 trailingSpaceRun->m_box->setLogicalWidth(std::max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
333 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
334 } else
335 logicalLeft += availableLogicalWidth - totalLogicalWidth;
338 static void updateLogicalWidthForCenterAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
340 float trailingSpaceWidth = 0;
341 if (trailingSpaceRun) {
342 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
343 trailingSpaceWidth = std::min(trailingSpaceRun->m_box->logicalWidth().toFloat(), (availableLogicalWidth - totalLogicalWidth + 1) / 2);
344 trailingSpaceRun->m_box->setLogicalWidth(std::max<float>(0, trailingSpaceWidth));
346 if (isLeftToRightDirection)
347 logicalLeft += std::max<float>((availableLogicalWidth - totalLogicalWidth) / 2, 0);
348 else
349 logicalLeft += totalLogicalWidth > availableLogicalWidth ? (availableLogicalWidth - totalLogicalWidth) : (availableLogicalWidth - totalLogicalWidth) / 2 - trailingSpaceWidth;
352 void RenderBlockFlow::setMarginsForRubyRun(BidiRun* run, LayoutRubyRun* renderer, LayoutObject* previousObject, const LineInfo& lineInfo)
354 int startOverhang;
355 int endOverhang;
356 LayoutObject* nextObject = 0;
357 for (BidiRun* runWithNextObject = run->next(); runWithNextObject; runWithNextObject = runWithNextObject->next()) {
358 if (!runWithNextObject->m_object->isOutOfFlowPositioned() && !runWithNextObject->m_box->isLineBreak()) {
359 nextObject = runWithNextObject->m_object;
360 break;
363 renderer->getOverhang(lineInfo.isFirstLine(), renderer->style()->isLeftToRightDirection() ? previousObject : nextObject, renderer->style()->isLeftToRightDirection() ? nextObject : previousObject, startOverhang, endOverhang);
364 setMarginStartForChild(*renderer, -startOverhang);
365 setMarginEndForChild(*renderer, -endOverhang);
368 static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* run, RenderText* renderer, float xPos, const LineInfo& lineInfo,
369 GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, WordMeasurements& wordMeasurements)
371 HashSet<const SimpleFontData*> fallbackFonts;
372 GlyphOverflow glyphOverflow;
374 const Font& font = renderer->style(lineInfo.isFirstLine())->font();
375 // Always compute glyph overflow if the block's line-box-contain value is "glyphs".
376 if (lineBox->fitsToGlyphs()) {
377 // If we don't stick out of the root line's font box, then don't bother computing our glyph overflow. This optimization
378 // will keep us from computing glyph bounds in nearly all cases.
379 bool includeRootLine = lineBox->includesRootLineBoxFontOrLeading();
380 int baselineShift = lineBox->verticalPositionForBox(run->m_box, verticalPositionCache);
381 int rootDescent = includeRootLine ? font.fontMetrics().descent() : 0;
382 int rootAscent = includeRootLine ? font.fontMetrics().ascent() : 0;
383 int boxAscent = font.fontMetrics().ascent() - baselineShift;
384 int boxDescent = font.fontMetrics().descent() + baselineShift;
385 if (boxAscent > rootDescent || boxDescent > rootAscent)
386 glyphOverflow.computeBounds = true;
389 LayoutUnit hyphenWidth = 0;
390 if (toInlineTextBox(run->m_box)->hasHyphen()) {
391 const Font& font = renderer->style(lineInfo.isFirstLine())->font();
392 hyphenWidth = measureHyphenWidth(renderer, font, run->direction());
394 float measuredWidth = 0;
396 bool kerningIsEnabled = font.fontDescription().typesettingFeatures() & Kerning;
398 #if OS(MACOSX)
399 // FIXME: Having any font feature settings enabled can lead to selection gaps on
400 // Chromium-mac. https://bugs.webkit.org/show_bug.cgi?id=113418
401 bool canUseSimpleFontCodePath = renderer->canUseSimpleFontCodePath() && !font.fontDescription().featureSettings();
402 #else
403 bool canUseSimpleFontCodePath = renderer->canUseSimpleFontCodePath();
404 #endif
406 // Since we don't cache glyph overflows, we need to re-measure the run if
407 // the style is linebox-contain: glyph.
409 if (!lineBox->fitsToGlyphs() && canUseSimpleFontCodePath) {
410 int lastEndOffset = run->m_start;
411 for (size_t i = 0, size = wordMeasurements.size(); i < size && lastEndOffset < run->m_stop; ++i) {
412 const WordMeasurement& wordMeasurement = wordMeasurements[i];
413 if (wordMeasurement.width <=0 || wordMeasurement.startOffset == wordMeasurement.endOffset)
414 continue;
415 if (wordMeasurement.renderer != renderer || wordMeasurement.startOffset != lastEndOffset || wordMeasurement.endOffset > run->m_stop)
416 continue;
418 lastEndOffset = wordMeasurement.endOffset;
419 if (kerningIsEnabled && lastEndOffset == run->m_stop) {
420 int wordLength = lastEndOffset - wordMeasurement.startOffset;
421 measuredWidth += renderer->width(wordMeasurement.startOffset, wordLength, xPos, run->direction(), lineInfo.isFirstLine());
422 if (i > 0 && wordLength == 1 && renderer->characterAt(wordMeasurement.startOffset) == ' ')
423 measuredWidth += renderer->style()->wordSpacing();
424 } else
425 measuredWidth += wordMeasurement.width;
426 if (!wordMeasurement.fallbackFonts.isEmpty()) {
427 HashSet<const SimpleFontData*>::const_iterator end = wordMeasurement.fallbackFonts.end();
428 for (HashSet<const SimpleFontData*>::const_iterator it = wordMeasurement.fallbackFonts.begin(); it != end; ++it)
429 fallbackFonts.add(*it);
432 if (measuredWidth && lastEndOffset != run->m_stop) {
433 // If we don't have enough cached data, we'll measure the run again.
434 measuredWidth = 0;
435 fallbackFonts.clear();
439 if (!measuredWidth)
440 measuredWidth = renderer->width(run->m_start, run->m_stop - run->m_start, xPos, run->direction(), lineInfo.isFirstLine(), &fallbackFonts, &glyphOverflow);
442 run->m_box->setLogicalWidth(measuredWidth + hyphenWidth);
443 if (!fallbackFonts.isEmpty()) {
444 ASSERT(run->m_box->isText());
445 GlyphOverflowAndFallbackFontsMap::ValueType* it = textBoxDataMap.add(toInlineTextBox(run->m_box), std::make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).storedValue;
446 ASSERT(it->value.first.isEmpty());
447 copyToVector(fallbackFonts, it->value.first);
448 run->m_box->parent()->clearDescendantsHaveSameLineHeightAndBaseline();
450 if (!glyphOverflow.isZero()) {
451 ASSERT(run->m_box->isText());
452 GlyphOverflowAndFallbackFontsMap::ValueType* it = textBoxDataMap.add(toInlineTextBox(run->m_box), std::make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).storedValue;
453 it->value.second = glyphOverflow;
454 run->m_box->clearKnownToHaveNoOverflow();
458 static inline void computeExpansionForJustifiedText(BidiRun* firstRun, BidiRun* trailingSpaceRun, Vector<unsigned, 16>& expansionOpportunities, unsigned expansionOpportunityCount, float& totalLogicalWidth, float availableLogicalWidth)
460 if (!expansionOpportunityCount || availableLogicalWidth <= totalLogicalWidth)
461 return;
463 size_t i = 0;
464 for (BidiRun* r = firstRun; r; r = r->next()) {
465 if (!r->m_box || r == trailingSpaceRun)
466 continue;
468 if (r->m_object->isText()) {
469 unsigned opportunitiesInRun = expansionOpportunities[i++];
471 ASSERT(opportunitiesInRun <= expansionOpportunityCount);
473 // Don't justify for white-space: pre.
474 if (r->m_object->style()->whiteSpace() != PRE) {
475 InlineTextBox* textBox = toInlineTextBox(r->m_box);
476 int expansion = (availableLogicalWidth - totalLogicalWidth) * opportunitiesInRun / expansionOpportunityCount;
477 textBox->setExpansion(expansion);
478 totalLogicalWidth += expansion;
480 expansionOpportunityCount -= opportunitiesInRun;
481 if (!expansionOpportunityCount)
482 break;
487 void RenderBlockFlow::updateLogicalWidthForAlignment(const ETextAlign& textAlign, const RootInlineBox* rootInlineBox, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float& availableLogicalWidth, unsigned expansionOpportunityCount)
489 TextDirection direction;
490 if (rootInlineBox && rootInlineBox->renderer().style()->unicodeBidi() == Plaintext)
491 direction = rootInlineBox->direction();
492 else
493 direction = style()->direction();
495 // Armed with the total width of the line (without justification),
496 // we now examine our text-align property in order to determine where to position the
497 // objects horizontally. The total width of the line can be increased if we end up
498 // justifying text.
499 switch (textAlign) {
500 case LEFT:
501 case WEBKIT_LEFT:
502 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
503 break;
504 case RIGHT:
505 case WEBKIT_RIGHT:
506 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
507 break;
508 case CENTER:
509 case WEBKIT_CENTER:
510 updateLogicalWidthForCenterAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
511 break;
512 case JUSTIFY:
513 adjustInlineDirectionLineBounds(expansionOpportunityCount, logicalLeft, availableLogicalWidth);
514 if (expansionOpportunityCount) {
515 if (trailingSpaceRun) {
516 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
517 trailingSpaceRun->m_box->setLogicalWidth(0);
519 break;
521 // Fall through
522 case TASTART:
523 if (direction == LTR)
524 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
525 else
526 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
527 break;
528 case TAEND:
529 if (direction == LTR)
530 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
531 else
532 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
533 break;
535 if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
536 logicalLeft += verticalScrollbarWidth();
539 static void updateLogicalInlinePositions(RenderBlockFlow* block, float& lineLogicalLeft, float& lineLogicalRight, float& availableLogicalWidth, bool firstLine, IndentTextOrNot shouldIndentText, LayoutUnit boxLogicalHeight)
541 LayoutUnit lineLogicalHeight = block->minLineHeightForReplacedRenderer(firstLine, boxLogicalHeight);
542 lineLogicalLeft = block->logicalLeftOffsetForLine(block->logicalHeight(), shouldIndentText == IndentText, lineLogicalHeight).toFloat();
543 lineLogicalRight = block->logicalRightOffsetForLine(block->logicalHeight(), shouldIndentText == IndentText, lineLogicalHeight).toFloat();
544 availableLogicalWidth = lineLogicalRight - lineLogicalLeft;
547 void RenderBlockFlow::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, const LineInfo& lineInfo, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd,
548 GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, WordMeasurements& wordMeasurements)
550 ETextAlign textAlign = textAlignmentForLine(!reachedEnd && !lineBox->endsWithBreak());
552 // 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
553 // box is only affected if it is the first child of its parent element."
554 // CSS3 "text-indent", "each-line" affects the first line of the block container as well as each line after a forced line break,
555 // but does not affect lines after a soft wrap break.
556 bool isFirstLine = lineInfo.isFirstLine() && !(isAnonymousBlock() && parent()->slowFirstChild() != this);
557 bool isAfterHardLineBreak = lineBox->prevRootBox() && lineBox->prevRootBox()->endsWithBreak();
558 IndentTextOrNot shouldIndentText = requiresIndent(isFirstLine, isAfterHardLineBreak, styleRef());
559 float lineLogicalLeft;
560 float lineLogicalRight;
561 float availableLogicalWidth;
562 updateLogicalInlinePositions(this, lineLogicalLeft, lineLogicalRight, availableLogicalWidth, isFirstLine, shouldIndentText, 0);
563 bool needsWordSpacing;
565 if (firstRun && firstRun->m_object->isReplaced()) {
566 LayoutBox* layoutBox = toLayoutBox(firstRun->m_object);
567 updateLogicalInlinePositions(this, lineLogicalLeft, lineLogicalRight, availableLogicalWidth, isFirstLine, shouldIndentText, layoutBox->logicalHeight());
570 computeInlineDirectionPositionsForSegment(lineBox, lineInfo, textAlign, lineLogicalLeft, availableLogicalWidth, firstRun, trailingSpaceRun, textBoxDataMap, verticalPositionCache, wordMeasurements);
571 // The widths of all runs are now known. We can now place every inline box (and
572 // compute accurate widths for the inline flow boxes).
573 needsWordSpacing = lineBox->isLeftToRightDirection() ? false: true;
574 lineBox->placeBoxesInInlineDirection(lineLogicalLeft, needsWordSpacing);
577 BidiRun* RenderBlockFlow::computeInlineDirectionPositionsForSegment(RootInlineBox* lineBox, const LineInfo& lineInfo, ETextAlign textAlign, float& logicalLeft,
578 float& availableLogicalWidth, BidiRun* firstRun, BidiRun* trailingSpaceRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache,
579 WordMeasurements& wordMeasurements)
581 bool needsWordSpacing = true;
582 float totalLogicalWidth = lineBox->getFlowSpacingLogicalWidth().toFloat();
583 unsigned expansionOpportunityCount = 0;
584 bool isAfterExpansion = true;
585 Vector<unsigned, 16> expansionOpportunities;
586 LayoutObject* previousObject = 0;
587 TextJustify textJustify = style()->textJustify();
589 BidiRun* r = firstRun;
590 for (; r; r = r->next()) {
591 if (!r->m_box || r->m_object->isOutOfFlowPositioned() || r->m_box->isLineBreak())
592 continue; // Positioned objects are only participating to figure out their
593 // correct static x position. They have no effect on the width.
594 // Similarly, line break boxes have no effect on the width.
595 if (r->m_object->isText()) {
596 RenderText* rt = toRenderText(r->m_object);
597 if (textAlign == JUSTIFY && r != trailingSpaceRun && textJustify != TextJustifyNone) {
598 if (!isAfterExpansion)
599 toInlineTextBox(r->m_box)->setCanHaveLeadingExpansion(true);
600 unsigned opportunitiesInRun;
601 if (rt->is8Bit())
602 opportunitiesInRun = Character::expansionOpportunityCount(rt->characters8() + r->m_start, r->m_stop - r->m_start, r->m_box->direction(), isAfterExpansion, textJustify);
603 else
604 opportunitiesInRun = Character::expansionOpportunityCount(rt->characters16() + r->m_start, r->m_stop - r->m_start, r->m_box->direction(), isAfterExpansion, textJustify);
605 expansionOpportunities.append(opportunitiesInRun);
606 expansionOpportunityCount += opportunitiesInRun;
609 if (rt->textLength()) {
610 if (!r->m_start && needsWordSpacing && isSpaceOrNewline(rt->characterAt(r->m_start)))
611 totalLogicalWidth += rt->style(lineInfo.isFirstLine())->font().fontDescription().wordSpacing();
612 needsWordSpacing = !isSpaceOrNewline(rt->characterAt(r->m_stop - 1));
615 setLogicalWidthForTextRun(lineBox, r, rt, totalLogicalWidth, lineInfo, textBoxDataMap, verticalPositionCache, wordMeasurements);
616 } else {
617 isAfterExpansion = false;
618 if (!r->m_object->isRenderInline()) {
619 LayoutBox* layoutBox = toLayoutBox(r->m_object);
620 if (layoutBox->isRubyRun())
621 setMarginsForRubyRun(r, toLayoutRubyRun(layoutBox), previousObject, lineInfo);
622 r->m_box->setLogicalWidth(logicalWidthForChild(*layoutBox).toFloat());
623 totalLogicalWidth += marginStartForChild(*layoutBox) + marginEndForChild(*layoutBox);
624 needsWordSpacing = true;
628 totalLogicalWidth += r->m_box->logicalWidth();
629 previousObject = r->m_object;
632 if (isAfterExpansion && !expansionOpportunities.isEmpty()) {
633 expansionOpportunities.last()--;
634 expansionOpportunityCount--;
637 updateLogicalWidthForAlignment(textAlign, lineBox, trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth, expansionOpportunityCount);
639 computeExpansionForJustifiedText(firstRun, trailingSpaceRun, expansionOpportunities, expansionOpportunityCount, totalLogicalWidth, availableLogicalWidth);
641 return r;
644 void RenderBlockFlow::computeBlockDirectionPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap,
645 VerticalPositionCache& verticalPositionCache)
647 setLogicalHeight(lineBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache));
649 // Now make sure we place replaced render objects correctly.
650 for (BidiRun* r = firstRun; r; r = r->next()) {
651 ASSERT(r->m_box);
652 if (!r->m_box)
653 continue; // Skip runs with no line boxes.
655 // Align positioned boxes with the top of the line box. This is
656 // a reasonable approximation of an appropriate y position.
657 if (r->m_object->isOutOfFlowPositioned())
658 r->m_box->setLogicalTop(logicalHeight().toFloat());
660 // Position is used to properly position both replaced elements and
661 // to update the static normal flow x/y of positioned elements.
662 if (r->m_object->isText())
663 toRenderText(r->m_object)->positionLineBox(r->m_box);
664 else if (r->m_object->isBox())
665 toLayoutBox(r->m_object)->positionLineBox(r->m_box);
669 void RenderBlockFlow::appendFloatingObjectToLastLine(FloatingObject* floatingObject)
671 ASSERT(!floatingObject->originatingLine());
672 floatingObject->setOriginatingLine(lastRootBox());
673 lastRootBox()->appendFloat(floatingObject->renderer());
676 // This function constructs line boxes for all of the text runs in the resolver and computes their position.
677 RootInlineBox* RenderBlockFlow::createLineBoxesFromBidiRuns(unsigned bidiLevel, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& end, LineInfo& lineInfo, VerticalPositionCache& verticalPositionCache, BidiRun* trailingSpaceRun, WordMeasurements& wordMeasurements)
679 if (!bidiRuns.runCount())
680 return 0;
682 // FIXME: Why is this only done when we had runs?
683 lineInfo.setLastLine(!end.object());
685 RootInlineBox* lineBox = constructLine(bidiRuns, lineInfo);
686 if (!lineBox)
687 return 0;
689 lineBox->setBidiLevel(bidiLevel);
690 lineBox->setEndsWithBreak(lineInfo.previousLineBrokeCleanly());
692 bool isSVGRootInlineBox = lineBox->isSVGRootInlineBox();
694 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
696 // Now we position all of our text runs horizontally.
697 if (!isSVGRootInlineBox)
698 computeInlineDirectionPositionsForLine(lineBox, lineInfo, bidiRuns.firstRun(), trailingSpaceRun, end.atEnd(), textBoxDataMap, verticalPositionCache, wordMeasurements);
700 // Now position our text runs vertically.
701 computeBlockDirectionPositionsForLine(lineBox, bidiRuns.firstRun(), textBoxDataMap, verticalPositionCache);
703 // SVG text layout code computes vertical & horizontal positions on its own.
704 // Note that we still need to execute computeVerticalPositionsForLine() as
705 // it calls InlineTextBox::positionLineBox(), which tracks whether the box
706 // contains reversed text or not. If we wouldn't do that editing and thus
707 // text selection in RTL boxes would not work as expected.
708 if (isSVGRootInlineBox) {
709 ASSERT(isSVGText());
710 toSVGRootInlineBox(lineBox)->computePerCharacterLayoutInformation();
713 // Compute our overflow now.
714 lineBox->computeOverflow(lineBox->lineTop(), lineBox->lineBottom(), textBoxDataMap);
716 return lineBox;
719 static void deleteLineRange(LineLayoutState& layoutState, RootInlineBox* startLine, RootInlineBox* stopLine = 0)
721 RootInlineBox* boxToDelete = startLine;
722 while (boxToDelete && boxToDelete != stopLine) {
723 layoutState.updatePaintInvalidationRangeFromBox(boxToDelete);
724 // Note: deleteLineRange(firstRootBox()) is not identical to deleteLineBoxTree().
725 // deleteLineBoxTree uses nextLineBox() instead of nextRootBox() when traversing.
726 RootInlineBox* next = boxToDelete->nextRootBox();
727 boxToDelete->deleteLine();
728 boxToDelete = next;
732 void RenderBlockFlow::layoutRunsAndFloats(LineLayoutState& layoutState)
734 // We want to skip ahead to the first dirty line
735 InlineBidiResolver resolver;
736 RootInlineBox* startLine = determineStartPosition(layoutState, resolver);
738 if (containsFloats())
739 layoutState.setLastFloat(m_floatingObjects->set().last().get());
741 // We also find the first clean line and extract these lines. We will add them back
742 // if we determine that we're able to synchronize after handling all our dirty lines.
743 InlineIterator cleanLineStart;
744 BidiStatus cleanLineBidiStatus;
745 if (!layoutState.isFullLayout() && startLine)
746 determineEndPosition(layoutState, startLine, cleanLineStart, cleanLineBidiStatus);
748 if (startLine) {
749 if (!layoutState.usesPaintInvalidationBounds())
750 layoutState.setPaintInvalidationRange(logicalHeight());
751 deleteLineRange(layoutState, startLine);
754 if (!layoutState.isFullLayout() && lastRootBox() && lastRootBox()->endsWithBreak()) {
755 // If the last line before the start line ends with a line break that clear floats,
756 // adjust the height accordingly.
757 // A line break can be either the first or the last object on a line, depending on its direction.
758 if (InlineBox* lastLeafChild = lastRootBox()->lastLeafChild()) {
759 LayoutObject* lastObject = &lastLeafChild->renderer();
760 if (!lastObject->isBR())
761 lastObject = &lastRootBox()->firstLeafChild()->renderer();
762 if (lastObject->isBR()) {
763 EClear clear = lastObject->style()->clear();
764 if (clear != CNONE)
765 clearFloats(clear);
770 layoutRunsAndFloatsInRange(layoutState, resolver, cleanLineStart, cleanLineBidiStatus);
771 linkToEndLineIfNeeded(layoutState);
772 markDirtyFloatsForPaintInvalidation(layoutState.floats());
775 // Before restarting the layout loop with a new logicalHeight, remove all floats that were added and reset the resolver.
776 inline const InlineIterator& RenderBlockFlow::restartLayoutRunsAndFloatsInRange(LayoutUnit oldLogicalHeight, LayoutUnit newLogicalHeight, FloatingObject* lastFloatFromPreviousLine, InlineBidiResolver& resolver, const InlineIterator& oldEnd)
778 removeFloatingObjectsBelow(lastFloatFromPreviousLine, oldLogicalHeight);
779 setLogicalHeight(newLogicalHeight);
780 resolver.setPositionIgnoringNestedIsolates(oldEnd);
781 return oldEnd;
784 void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState,
785 InlineBidiResolver& resolver, const InlineIterator& cleanLineStart,
786 const BidiStatus& cleanLineBidiStatus)
788 const LayoutStyle& styleToUse = styleRef();
789 bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
790 LineMidpointState& lineMidpointState = resolver.midpointState();
791 InlineIterator endOfLine = resolver.position();
792 bool checkForEndLineMatch = layoutState.endLine();
793 LayoutTextInfo renderTextInfo;
794 VerticalPositionCache verticalPositionCache;
796 LineBreaker lineBreaker(this);
798 while (!endOfLine.atEnd()) {
799 bool logicalWidthIsAvailable = false;
801 // FIXME: Is this check necessary before the first iteration or can it be moved to the end?
802 if (checkForEndLineMatch) {
803 layoutState.setEndLineMatched(matchedEndLine(layoutState, resolver, cleanLineStart, cleanLineBidiStatus));
804 if (layoutState.endLineMatched()) {
805 resolver.setPosition(InlineIterator(resolver.position().root(), 0, 0), 0);
806 break;
810 lineMidpointState.reset();
812 layoutState.lineInfo().setEmpty(true);
813 layoutState.lineInfo().resetRunsFromLeadingWhitespace();
815 const InlineIterator previousEndofLine = endOfLine;
816 bool isNewUBAParagraph = layoutState.lineInfo().previousLineBrokeCleanly();
817 FloatingObject* lastFloatFromPreviousLine = (containsFloats()) ? m_floatingObjects->set().last().get() : 0;
819 WordMeasurements wordMeasurements;
820 endOfLine = lineBreaker.nextLineBreak(resolver, layoutState.lineInfo(), renderTextInfo,
821 lastFloatFromPreviousLine, wordMeasurements);
822 renderTextInfo.m_lineBreakIterator.resetPriorContext();
823 if (resolver.position().atEnd()) {
824 // FIXME: We shouldn't be creating any runs in nextLineBreak to begin with!
825 // Once BidiRunList is separated from BidiResolver this will not be needed.
826 resolver.runs().deleteRuns();
827 resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed).
828 layoutState.setCheckForFloatsFromLastLine(true);
829 resolver.setPosition(InlineIterator(resolver.position().root(), 0, 0), 0);
830 break;
833 ASSERT(endOfLine != resolver.position());
835 // This is a short-cut for empty lines.
836 if (layoutState.lineInfo().isEmpty()) {
837 if (lastRootBox())
838 lastRootBox()->setLineBreakInfo(endOfLine.object(), endOfLine.offset(), resolver.status());
839 } else {
840 VisualDirectionOverride override = (styleToUse.rtlOrdering() == VisualOrder ? (styleToUse.direction() == LTR ? VisualLeftToRightOverride : VisualRightToLeftOverride) : NoVisualOverride);
841 if (isNewUBAParagraph && styleToUse.unicodeBidi() == Plaintext && !resolver.context()->parent()) {
842 TextDirection direction = determinePlaintextDirectionality(resolver.position().root(), resolver.position().object(), resolver.position().offset());
843 resolver.setStatus(BidiStatus(direction, isOverride(styleToUse.unicodeBidi())));
845 // FIXME: This ownership is reversed. We should own the BidiRunList and pass it to createBidiRunsForLine.
846 BidiRunList<BidiRun>& bidiRuns = resolver.runs();
847 constructBidiRunsForLine(resolver, bidiRuns, endOfLine, override, layoutState.lineInfo().previousLineBrokeCleanly(), isNewUBAParagraph);
848 ASSERT(resolver.position() == endOfLine);
850 BidiRun* trailingSpaceRun = resolver.trailingSpaceRun();
852 if (bidiRuns.runCount() && lineBreaker.lineWasHyphenated())
853 bidiRuns.logicallyLastRun()->m_hasHyphen = true;
855 // Now that the runs have been ordered, we create the line boxes.
856 // At the same time we figure out where border/padding/margin should be applied for
857 // inline flow boxes.
859 LayoutUnit oldLogicalHeight = logicalHeight();
860 RootInlineBox* lineBox = createLineBoxesFromBidiRuns(resolver.status().context->level(), bidiRuns, endOfLine, layoutState.lineInfo(), verticalPositionCache, trailingSpaceRun, wordMeasurements);
862 bidiRuns.deleteRuns();
863 resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed).
865 if (lineBox) {
866 lineBox->setLineBreakInfo(endOfLine.object(), endOfLine.offset(), resolver.status());
867 if (layoutState.usesPaintInvalidationBounds())
868 layoutState.updatePaintInvalidationRangeFromBox(lineBox);
870 if (paginated) {
871 LayoutUnit adjustment = 0;
872 adjustLinePositionForPagination(*lineBox, adjustment, layoutState.flowThread());
873 if (adjustment) {
874 LayoutUnit oldLineWidth = availableLogicalWidthForLine(oldLogicalHeight, layoutState.lineInfo().isFirstLine());
875 lineBox->adjustBlockDirectionPosition(adjustment.toFloat());
876 if (layoutState.usesPaintInvalidationBounds())
877 layoutState.updatePaintInvalidationRangeFromBox(lineBox);
879 if (availableLogicalWidthForLine(oldLogicalHeight + adjustment, layoutState.lineInfo().isFirstLine()) != oldLineWidth) {
880 // We have to delete this line, remove all floats that got added, and let line layout re-run.
881 lineBox->deleteLine();
882 endOfLine = restartLayoutRunsAndFloatsInRange(oldLogicalHeight, oldLogicalHeight + adjustment, lastFloatFromPreviousLine, resolver, previousEndofLine);
883 logicalWidthIsAvailable = true;
884 } else {
885 setLogicalHeight(lineBox->lineBottomWithLeading());
892 if (!logicalWidthIsAvailable) {
893 for (size_t i = 0; i < lineBreaker.positionedObjects().size(); ++i)
894 setStaticPositions(this, lineBreaker.positionedObjects()[i]);
896 if (!layoutState.lineInfo().isEmpty()) {
897 layoutState.lineInfo().setFirstLine(false);
898 clearFloats(lineBreaker.clear());
901 if (m_floatingObjects && lastRootBox()) {
902 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
903 FloatingObjectSetIterator it = floatingObjectSet.begin();
904 FloatingObjectSetIterator end = floatingObjectSet.end();
905 if (layoutState.lastFloat()) {
906 FloatingObjectSetIterator lastFloatIterator = floatingObjectSet.find(layoutState.lastFloat());
907 ASSERT(lastFloatIterator != end);
908 ++lastFloatIterator;
909 it = lastFloatIterator;
911 for (; it != end; ++it) {
912 FloatingObject* f = it->get();
913 appendFloatingObjectToLastLine(f);
914 ASSERT(f->renderer() == layoutState.floats()[layoutState.floatIndex()].object);
915 // If a float's geometry has changed, give up on syncing with clean lines.
916 if (layoutState.floats()[layoutState.floatIndex()].rect != f->frameRect())
917 checkForEndLineMatch = false;
918 layoutState.setFloatIndex(layoutState.floatIndex() + 1);
920 layoutState.setLastFloat(!floatingObjectSet.isEmpty() ? floatingObjectSet.last().get() : 0);
924 lineMidpointState.reset();
925 resolver.setPosition(endOfLine, numberOfIsolateAncestors(endOfLine));
928 // In case we already adjusted the line positions during this layout to avoid widows
929 // then we need to ignore the possibility of having a new widows situation.
930 // Otherwise, we risk leaving empty containers which is against the block fragmentation principles.
931 if (paginated && !style()->hasAutoWidows() && !didBreakAtLineToAvoidWidow()) {
932 // Check the line boxes to make sure we didn't create unacceptable widows.
933 // However, we'll prioritize orphans - so nothing we do here should create
934 // a new orphan.
936 RootInlineBox* lineBox = lastRootBox();
938 // Count from the end of the block backwards, to see how many hanging
939 // lines we have.
940 RootInlineBox* firstLineInBlock = firstRootBox();
941 int numLinesHanging = 1;
942 while (lineBox && lineBox != firstLineInBlock && !lineBox->isFirstAfterPageBreak()) {
943 ++numLinesHanging;
944 lineBox = lineBox->prevRootBox();
947 // If there were no breaks in the block, we didn't create any widows.
948 if (!lineBox || !lineBox->isFirstAfterPageBreak() || lineBox == firstLineInBlock)
949 return;
951 if (numLinesHanging < style()->widows()) {
952 // We have detected a widow. Now we need to work out how many
953 // lines there are on the previous page, and how many we need
954 // to steal.
955 int numLinesNeeded = style()->widows() - numLinesHanging;
956 RootInlineBox* currentFirstLineOfNewPage = lineBox;
958 // Count the number of lines in the previous page.
959 lineBox = lineBox->prevRootBox();
960 int numLinesInPreviousPage = 1;
961 while (lineBox && lineBox != firstLineInBlock && !lineBox->isFirstAfterPageBreak()) {
962 ++numLinesInPreviousPage;
963 lineBox = lineBox->prevRootBox();
966 // If there was an explicit value for orphans, respect that. If not, we still
967 // shouldn't create a situation where we make an orphan bigger than the initial value.
968 // This means that setting widows implies we also care about orphans, but given
969 // the specification says the initial orphan value is non-zero, this is ok. The
970 // author is always free to set orphans explicitly as well.
971 int orphans = style()->hasAutoOrphans() ? style()->initialOrphans() : style()->orphans();
972 int numLinesAvailable = numLinesInPreviousPage - orphans;
973 if (numLinesAvailable <= 0)
974 return;
976 int numLinesToTake = std::min(numLinesAvailable, numLinesNeeded);
977 // Wind back from our first widowed line.
978 lineBox = currentFirstLineOfNewPage;
979 for (int i = 0; i < numLinesToTake; ++i)
980 lineBox = lineBox->prevRootBox();
982 // We now want to break at this line. Remember for next layout and trigger relayout.
983 setBreakAtLineToAvoidWidow(lineCount(lineBox));
984 markLinesDirtyInBlockRange(lastRootBox()->lineBottomWithLeading(), lineBox->lineBottomWithLeading(), lineBox);
988 clearDidBreakAtLineToAvoidWidow();
991 void RenderBlockFlow::linkToEndLineIfNeeded(LineLayoutState& layoutState)
993 if (layoutState.endLine()) {
994 if (layoutState.endLineMatched()) {
995 bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
996 // Attach all the remaining lines, and then adjust their y-positions as needed.
997 LayoutUnit delta = logicalHeight() - layoutState.endLineLogicalTop();
998 for (RootInlineBox* line = layoutState.endLine(); line; line = line->nextRootBox()) {
999 line->attachLine();
1000 if (paginated) {
1001 delta -= line->paginationStrut();
1002 adjustLinePositionForPagination(*line, delta, layoutState.flowThread());
1004 if (delta) {
1005 layoutState.updatePaintInvalidationRangeFromBox(line, delta);
1006 line->adjustBlockDirectionPosition(delta.toFloat());
1008 if (Vector<LayoutBox*>* cleanLineFloats = line->floatsPtr()) {
1009 Vector<LayoutBox*>::iterator end = cleanLineFloats->end();
1010 for (Vector<LayoutBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) {
1011 FloatingObject* floatingObject = insertFloatingObject(**f);
1012 ASSERT(!floatingObject->originatingLine());
1013 floatingObject->setOriginatingLine(line);
1014 setLogicalHeight(logicalTopForChild(**f) - marginBeforeForChild(**f) + delta);
1015 positionNewFloats();
1019 setLogicalHeight(lastRootBox()->lineBottomWithLeading());
1020 } else {
1021 // Delete all the remaining lines.
1022 deleteLineRange(layoutState, layoutState.endLine());
1026 if (m_floatingObjects && (layoutState.checkForFloatsFromLastLine() || positionNewFloats()) && lastRootBox()) {
1027 // In case we have a float on the last line, it might not be positioned up to now.
1028 // This has to be done before adding in the bottom border/padding, or the float will
1029 // include the padding incorrectly. -dwh
1030 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1031 FloatingObjectSetIterator it = floatingObjectSet.begin();
1032 FloatingObjectSetIterator end = floatingObjectSet.end();
1033 if (layoutState.lastFloat()) {
1034 FloatingObjectSetIterator lastFloatIterator = floatingObjectSet.find(layoutState.lastFloat());
1035 ASSERT(lastFloatIterator != end);
1036 ++lastFloatIterator;
1037 it = lastFloatIterator;
1039 layoutState.setLastFloat(!floatingObjectSet.isEmpty() ? floatingObjectSet.last().get() : 0);
1041 if (it == end)
1042 return;
1044 if (layoutState.checkForFloatsFromLastLine()) {
1045 LayoutUnit bottomVisualOverflow = lastRootBox()->logicalBottomVisualOverflow();
1046 LayoutUnit bottomLayoutOverflow = lastRootBox()->logicalBottomLayoutOverflow();
1047 TrailingFloatsRootInlineBox* trailingFloatsLineBox = new TrailingFloatsRootInlineBox(*this);
1048 m_lineBoxes.appendLineBox(trailingFloatsLineBox);
1049 trailingFloatsLineBox->setConstructed();
1050 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1051 VerticalPositionCache verticalPositionCache;
1052 LayoutUnit blockLogicalHeight = logicalHeight();
1053 trailingFloatsLineBox->alignBoxesInBlockDirection(blockLogicalHeight, textBoxDataMap, verticalPositionCache);
1054 trailingFloatsLineBox->setLineTopBottomPositions(blockLogicalHeight, blockLogicalHeight, blockLogicalHeight, blockLogicalHeight);
1055 LayoutRect logicalLayoutOverflow(0, blockLogicalHeight, 1, bottomLayoutOverflow - blockLogicalHeight);
1056 LayoutRect logicalVisualOverflow(0, blockLogicalHeight, 1, bottomVisualOverflow - blockLogicalHeight);
1057 trailingFloatsLineBox->setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow, trailingFloatsLineBox->lineTop(), trailingFloatsLineBox->lineBottom());
1060 for (; it != end; ++it)
1061 appendFloatingObjectToLastLine(it->get());
1065 void RenderBlockFlow::markDirtyFloatsForPaintInvalidation(Vector<FloatWithRect>& floats)
1067 size_t floatCount = floats.size();
1068 // Floats that did not have layout did not paint invalidations when we laid them out. They would have
1069 // painted by now if they had moved, but if they stayed at (0, 0), they still need to be
1070 // painted.
1071 for (size_t i = 0; i < floatCount; ++i) {
1072 if (!floats[i].everHadLayout) {
1073 LayoutBox* f = floats[i].object;
1074 if (!f->location().x() && !f->location().y())
1075 f->setShouldDoFullPaintInvalidation();
1080 struct InlineMinMaxIterator {
1081 /* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
1082 inline min/max width calculations. Note the following about the way it walks:
1083 (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
1084 (2) We do not drill into the children of floats or replaced elements, since you can't break
1085 in the middle of such an element.
1086 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
1087 distinct borders/margin/padding that contribute to the min/max width.
1089 LayoutObject* parent;
1090 LayoutObject* current;
1091 bool endOfInline;
1093 InlineMinMaxIterator(LayoutObject* p, bool end = false)
1094 : parent(p), current(p), endOfInline(end)
1099 LayoutObject* next();
1102 LayoutObject* InlineMinMaxIterator::next()
1104 LayoutObject* result = 0;
1105 bool oldEndOfInline = endOfInline;
1106 endOfInline = false;
1107 while (current || current == parent) {
1108 if (!oldEndOfInline && (current == parent || (!current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned())))
1109 result = current->slowFirstChild();
1111 if (!result) {
1112 // We hit the end of our inline. (It was empty, e.g., <span></span>.)
1113 if (!oldEndOfInline && current->isRenderInline()) {
1114 result = current;
1115 endOfInline = true;
1116 break;
1119 while (current && current != parent) {
1120 result = current->nextSibling();
1121 if (result)
1122 break;
1123 current = current->parent();
1124 if (current && current != parent && current->isRenderInline()) {
1125 result = current;
1126 endOfInline = true;
1127 break;
1132 if (!result)
1133 break;
1135 if (!result->isOutOfFlowPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
1136 break;
1138 current = result;
1139 result = 0;
1142 // Update our position.
1143 current = result;
1144 return current;
1147 static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit)
1149 if (cssUnit.type() != Auto)
1150 return (cssUnit.isFixed() ? static_cast<LayoutUnit>(cssUnit.value()) : childValue);
1151 return LayoutUnit();
1154 static LayoutUnit getBorderPaddingMargin(const LayoutBoxModelObject& child, bool endOfInline)
1156 const LayoutStyle& childStyle = child.styleRef();
1157 if (endOfInline) {
1158 return getBPMWidth(child.marginEnd(), childStyle.marginEnd()) +
1159 getBPMWidth(child.paddingEnd(), childStyle.paddingEnd()) +
1160 child.borderEnd();
1162 return getBPMWidth(child.marginStart(), childStyle.marginStart()) +
1163 getBPMWidth(child.paddingStart(), childStyle.paddingStart()) +
1164 child.borderStart();
1167 static inline void stripTrailingSpace(FloatWillBeLayoutUnit& inlineMax, FloatWillBeLayoutUnit& inlineMin,
1168 LayoutObject* trailingSpaceChild)
1170 if (trailingSpaceChild && trailingSpaceChild->isText()) {
1171 // Collapse away the trailing space at the end of a block by finding
1172 // the first white-space character and subtracting its width. Subsequent
1173 // white-space characters have been collapsed into the first one (which
1174 // can be either a space or a tab character).
1175 RenderText* text = toRenderText(trailingSpaceChild);
1176 UChar trailingWhitespaceChar = ' ';
1177 for (unsigned i = text->textLength(); i > 0; i--) {
1178 UChar c = text->characterAt(i - 1);
1179 if (!Character::treatAsSpace(c))
1180 break;
1181 trailingWhitespaceChar = c;
1184 // FIXME: This ignores first-line.
1185 const Font& font = text->style()->font();
1186 TextRun run = constructTextRun(text, font, &trailingWhitespaceChar, 1,
1187 text->styleRef(), text->style()->direction());
1188 run.setCodePath(text->canUseSimpleFontCodePath()
1189 ? TextRun::ForceSimple
1190 : TextRun::ForceComplex);
1191 float spaceWidth = font.width(run);
1192 inlineMax -= spaceWidth + font.fontDescription().wordSpacing();
1193 if (inlineMin > inlineMax)
1194 inlineMin = inlineMax;
1198 // When converting between floating point and LayoutUnits we risk losing precision
1199 // with each conversion. When this occurs while accumulating our preferred widths,
1200 // we can wind up with a line width that's larger than our maxPreferredWidth due to
1201 // pure float accumulation.
1202 static inline LayoutUnit adjustFloatForSubPixelLayout(float value)
1204 return LayoutUnit::fromFloatCeil(value);
1207 // FIXME: This function should be broken into something less monolithic.
1208 // FIXME: The main loop here is very similar to LineBreaker::nextSegmentBreak. They can probably reuse code.
1209 void RenderBlockFlow::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth)
1211 FloatWillBeLayoutUnit inlineMax;
1212 FloatWillBeLayoutUnit inlineMin;
1214 const LayoutStyle& styleToUse = styleRef();
1215 RenderBlock* containingBlock = this->containingBlock();
1216 LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit();
1218 // If we are at the start of a line, we want to ignore all white-space.
1219 // Also strip spaces if we previously had text that ended in a trailing space.
1220 bool stripFrontSpaces = true;
1221 LayoutObject* trailingSpaceChild = 0;
1223 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
1224 // very specific cirucumstances (in order to match common WinIE renderings).
1225 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
1226 bool allowImagesToBreak = !document().inQuirksMode() || !isTableCell() || !styleToUse.logicalWidth().isIntrinsicOrAuto();
1228 bool autoWrap, oldAutoWrap;
1229 autoWrap = oldAutoWrap = styleToUse.autoWrap();
1231 InlineMinMaxIterator childIterator(this);
1233 // Only gets added to the max preffered width once.
1234 bool addedTextIndent = false;
1235 // Signals the text indent was more negative than the min preferred width
1236 bool hasRemainingNegativeTextIndent = false;
1238 LayoutUnit textIndent = minimumValueForLength(styleToUse.textIndent(), cw);
1239 LayoutObject* prevFloat = 0;
1240 bool isPrevChildInlineFlow = false;
1241 bool shouldBreakLineAfterText = false;
1242 while (LayoutObject* child = childIterator.next()) {
1243 autoWrap = child->isReplaced() ? child->parent()->style()->autoWrap() :
1244 child->style()->autoWrap();
1246 if (!child->isBR()) {
1247 // Step One: determine whether or not we need to go ahead and
1248 // terminate our current line. Each discrete chunk can become
1249 // the new min-width, if it is the widest chunk seen so far, and
1250 // it can also become the max-width.
1252 // Children fall into three categories:
1253 // (1) An inline flow object. These objects always have a min/max of 0,
1254 // and are included in the iteration solely so that their margins can
1255 // be added in.
1257 // (2) An inline non-text non-flow object, e.g., an inline replaced element.
1258 // These objects can always be on a line by themselves, so in this situation
1259 // we need to go ahead and break the current line, and then add in our own
1260 // margins and min/max width on its own line, and then terminate the line.
1262 // (3) A text object. Text runs can have breakable characters at the start,
1263 // the middle or the end. They may also lose whitespace off the front if
1264 // we're already ignoring whitespace. In order to compute accurate min-width
1265 // information, we need three pieces of information.
1266 // (a) the min-width of the first non-breakable run. Should be 0 if the text string
1267 // starts with whitespace.
1268 // (b) the min-width of the last non-breakable run. Should be 0 if the text string
1269 // ends with whitespace.
1270 // (c) the min/max width of the string (trimmed for whitespace).
1272 // If the text string starts with whitespace, then we need to go ahead and
1273 // terminate our current line (unless we're already in a whitespace stripping
1274 // mode.
1276 // If the text string has a breakable character in the middle, but didn't start
1277 // with whitespace, then we add the width of the first non-breakable run and
1278 // then end the current line. We then need to use the intermediate min/max width
1279 // values (if any of them are larger than our current min/max). We then look at
1280 // the width of the last non-breakable run and use that to start a new line
1281 // (unless we end in whitespace).
1282 const LayoutStyle& childStyle = child->styleRef();
1283 FloatWillBeLayoutUnit childMin;
1284 FloatWillBeLayoutUnit childMax;
1286 if (!child->isText()) {
1287 // Case (1) and (2). Inline replaced and inline flow elements.
1288 if (child->isRenderInline()) {
1289 // Add in padding/border/margin from the appropriate side of
1290 // the element.
1291 FloatWillBeLayoutUnit bpm = getBorderPaddingMargin(toRenderInline(*child), childIterator.endOfInline);
1292 childMin += bpm;
1293 childMax += bpm;
1295 inlineMin += childMin;
1296 inlineMax += childMax;
1298 child->clearPreferredLogicalWidthsDirty();
1299 } else {
1300 // Inline replaced elts add in their margins to their min/max values.
1301 LayoutUnit margins;
1302 Length startMargin = childStyle.marginStart();
1303 Length endMargin = childStyle.marginEnd();
1304 if (startMargin.isFixed())
1305 margins += adjustFloatForSubPixelLayout(startMargin.value());
1306 if (endMargin.isFixed())
1307 margins += adjustFloatForSubPixelLayout(endMargin.value());
1308 childMin += margins;
1309 childMax += margins;
1313 if (!child->isRenderInline() && !child->isText()) {
1314 // Case (2). Inline replaced elements and floats.
1315 // Go ahead and terminate the current line as far as
1316 // minwidth is concerned.
1317 LayoutUnit childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth;
1318 if (child->isBox() && child->isHorizontalWritingMode() != isHorizontalWritingMode()) {
1319 LayoutBox* childBox = toLayoutBox(child);
1320 LogicalExtentComputedValues computedValues;
1321 childBox->computeLogicalHeight(childBox->borderAndPaddingLogicalHeight(), 0, computedValues);
1322 childMinPreferredLogicalWidth = childMaxPreferredLogicalWidth = computedValues.m_extent;
1323 } else {
1324 childMinPreferredLogicalWidth = child->minPreferredLogicalWidth();
1325 childMaxPreferredLogicalWidth = child->maxPreferredLogicalWidth();
1327 childMin += childMinPreferredLogicalWidth;
1328 childMax += childMaxPreferredLogicalWidth;
1330 bool clearPreviousFloat;
1331 if (child->isFloating()) {
1332 clearPreviousFloat = (prevFloat
1333 && ((prevFloat->styleRef().floating() == LeftFloat && (childStyle.clear() & CLEFT))
1334 || (prevFloat->styleRef().floating() == RightFloat && (childStyle.clear() & CRIGHT))));
1335 prevFloat = child;
1336 } else {
1337 clearPreviousFloat = false;
1340 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
1341 if ((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat) {
1342 minLogicalWidth = std::max(minLogicalWidth, inlineMin.toLayoutUnit());
1343 inlineMin = FloatWillBeLayoutUnit();
1346 // If we're supposed to clear the previous float, then terminate maxwidth as well.
1347 if (clearPreviousFloat) {
1348 maxLogicalWidth = std::max(maxLogicalWidth, inlineMax.toLayoutUnit());
1349 inlineMax = FloatWillBeLayoutUnit();
1352 // Add in text-indent. This is added in only once.
1353 if (!addedTextIndent && !child->isFloating()) {
1354 childMin += textIndent;
1355 childMax += textIndent;
1357 if (childMin < FloatWillBeLayoutUnit())
1358 textIndent = childMin;
1359 else
1360 addedTextIndent = true;
1363 // Add our width to the max.
1364 inlineMax += std::max(FloatWillBeLayoutUnit(), childMax);
1366 if (!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText)) {
1367 if (child->isFloating())
1368 minLogicalWidth = std::max(minLogicalWidth, childMin.toLayoutUnit());
1369 else
1370 inlineMin += childMin;
1371 } else {
1372 // Now check our line.
1373 minLogicalWidth = std::max(minLogicalWidth, childMin.toLayoutUnit());
1375 // Now start a new line.
1376 inlineMin = FloatWillBeLayoutUnit();
1379 if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
1380 minLogicalWidth = std::max(minLogicalWidth, inlineMin.toLayoutUnit());
1381 inlineMin = FloatWillBeLayoutUnit();
1384 // We are no longer stripping whitespace at the start of
1385 // a line.
1386 if (!child->isFloating()) {
1387 stripFrontSpaces = false;
1388 trailingSpaceChild = 0;
1390 } else if (child->isText()) {
1391 // Case (3). Text.
1392 RenderText* t = toRenderText(child);
1394 if (t->isWordBreak()) {
1395 minLogicalWidth = std::max(minLogicalWidth, inlineMin.toLayoutUnit());
1396 inlineMin = FloatWillBeLayoutUnit();
1397 continue;
1400 // Determine if we have a breakable character. Pass in
1401 // whether or not we should ignore any spaces at the front
1402 // of the string. If those are going to be stripped out,
1403 // then they shouldn't be considered in the breakable char
1404 // check.
1405 bool hasBreakableChar, hasBreak;
1406 FloatWillBeLayoutUnit firstLineMinWidth, lastLineMinWidth;
1407 bool hasBreakableStart, hasBreakableEnd;
1408 FloatWillBeLayoutUnit firstLineMaxWidth, lastLineMaxWidth;
1409 t->trimmedPrefWidths(inlineMax,
1410 firstLineMinWidth, hasBreakableStart, lastLineMinWidth, hasBreakableEnd,
1411 hasBreakableChar, hasBreak, firstLineMaxWidth, lastLineMaxWidth,
1412 childMin, childMax, stripFrontSpaces, styleToUse.direction());
1414 // This text object will not be rendered, but it may still provide a breaking opportunity.
1415 if (!hasBreak && !childMax) {
1416 if (autoWrap && (hasBreakableStart || hasBreakableEnd)) {
1417 minLogicalWidth = std::max(minLogicalWidth, inlineMin.toLayoutUnit());
1418 inlineMin = FloatWillBeLayoutUnit();
1420 continue;
1423 if (stripFrontSpaces)
1424 trailingSpaceChild = child;
1425 else
1426 trailingSpaceChild = 0;
1428 // Add in text-indent. This is added in only once.
1429 FloatWillBeLayoutUnit ti;
1430 if (!addedTextIndent || hasRemainingNegativeTextIndent) {
1431 ti = textIndent;
1432 childMin += ti;
1433 firstLineMinWidth += ti;
1435 // It the text indent negative and larger than the child minimum, we re-use the remainder
1436 // in future minimum calculations, but using the negative value again on the maximum
1437 // will lead to under-counting the max pref width.
1438 if (!addedTextIndent) {
1439 childMax += ti;
1440 firstLineMaxWidth += ti;
1441 addedTextIndent = true;
1444 if (childMin < FloatWillBeLayoutUnit()) {
1445 textIndent = childMin;
1446 hasRemainingNegativeTextIndent = true;
1450 // If we have no breakable characters at all,
1451 // then this is the easy case. We add ourselves to the current
1452 // min and max and continue.
1453 if (!hasBreakableChar) {
1454 inlineMin += childMin;
1455 } else {
1456 if (hasBreakableStart) {
1457 minLogicalWidth = std::max(minLogicalWidth, inlineMin.toLayoutUnit());
1458 } else {
1459 inlineMin += firstLineMinWidth;
1460 minLogicalWidth = std::max(minLogicalWidth, inlineMin.toLayoutUnit());
1461 childMin -= ti;
1464 inlineMin = childMin;
1466 if (hasBreakableEnd) {
1467 minLogicalWidth = std::max(minLogicalWidth, inlineMin.toLayoutUnit());
1468 inlineMin = FloatWillBeLayoutUnit();
1469 shouldBreakLineAfterText = false;
1470 } else {
1471 minLogicalWidth = std::max(minLogicalWidth, inlineMin.toLayoutUnit());
1472 inlineMin = lastLineMinWidth;
1473 shouldBreakLineAfterText = true;
1477 if (hasBreak) {
1478 inlineMax += firstLineMaxWidth;
1479 maxLogicalWidth = std::max(maxLogicalWidth, inlineMax.toLayoutUnit());
1480 maxLogicalWidth = std::max(maxLogicalWidth, childMax.toLayoutUnit());
1481 inlineMax = lastLineMaxWidth;
1482 addedTextIndent = true;
1483 } else {
1484 inlineMax += std::max<float>(0, childMax);
1488 // Ignore spaces after a list marker.
1489 if (child->isListMarker())
1490 stripFrontSpaces = true;
1491 } else {
1492 minLogicalWidth = std::max(minLogicalWidth, inlineMin.toLayoutUnit());
1493 maxLogicalWidth = std::max(maxLogicalWidth, inlineMax.toLayoutUnit());
1494 inlineMin = inlineMax = FloatWillBeLayoutUnit();
1495 stripFrontSpaces = true;
1496 trailingSpaceChild = 0;
1497 addedTextIndent = true;
1500 if (!child->isText() && child->isRenderInline())
1501 isPrevChildInlineFlow = true;
1502 else
1503 isPrevChildInlineFlow = false;
1505 oldAutoWrap = autoWrap;
1508 if (styleToUse.collapseWhiteSpace())
1509 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
1511 minLogicalWidth = std::max(minLogicalWidth, LayoutUnit::fromFloatCeil(inlineMin.toFloat()));
1512 maxLogicalWidth = std::max(maxLogicalWidth, LayoutUnit::fromFloatCeil(inlineMax.toFloat()));
1515 void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& paintInvalidationLogicalTop, LayoutUnit& paintInvalidationLogicalBottom, LayoutUnit afterEdge)
1517 LayoutFlowThread* flowThread = flowThreadContainingBlock();
1518 bool clearLinesForPagination = firstLineBox() && flowThread && !flowThread->hasRegions();
1520 // Figure out if we should clear out our line boxes.
1521 // FIXME: Handle resize eventually!
1522 bool isFullLayout = !firstLineBox() || selfNeedsLayout() || relayoutChildren || clearLinesForPagination;
1523 LineLayoutState layoutState(isFullLayout, paintInvalidationLogicalTop, paintInvalidationLogicalBottom, flowThread);
1525 if (isFullLayout) {
1526 // Ensure the old line boxes will be erased.
1527 if (firstLineBox())
1528 setShouldDoFullPaintInvalidation();
1529 lineBoxes()->deleteLineBoxes();
1532 // Text truncation kicks in in two cases:
1533 // 1) If your overflow isn't visible and your text-overflow-mode isn't clip.
1534 // 2) If you're an anonymous block with a block parent that satisfies #1 that was created
1535 // to accomodate a block that has inline and block children. This excludes parents where
1536 // canCollapseAnonymousBlockChild is false, notabley flex items and grid items.
1537 // FIXME: CSS3 says that descendants that are clipped must also know how to truncate. This is insanely
1538 // difficult to figure out in general (especially in the middle of doing layout), so we only handle the
1539 // simple case of an anonymous block truncating when it's parent is clipped.
1540 bool hasTextOverflow = (style()->textOverflow() && hasOverflowClip())
1541 || (isAnonymousBlock() && parent() && parent()->isRenderBlock() && toRenderBlock(parent())->canCollapseAnonymousBlockChild()
1542 && parent()->style()->textOverflow() && parent()->hasOverflowClip());
1544 // Walk all the lines and delete our ellipsis line boxes if they exist.
1545 if (hasTextOverflow)
1546 deleteEllipsisLineBoxes();
1548 if (firstChild()) {
1549 // In full layout mode, clear the line boxes of children upfront. Otherwise,
1550 // siblings can run into stale root lineboxes during layout. Then layout
1551 // the replaced elements later. In partial layout mode, line boxes are not
1552 // deleted and only dirtied. In that case, we can layout the replaced
1553 // elements at the same time.
1554 Vector<LayoutBox*> replacedChildren;
1555 for (InlineWalker walker(this); !walker.atEnd(); walker.advance()) {
1556 LayoutObject* o = walker.current();
1558 if (!layoutState.hasInlineChild() && o->isInline())
1559 layoutState.setHasInlineChild(true);
1561 if (o->isReplaced() || o->isFloating() || o->isOutOfFlowPositioned()) {
1562 LayoutBox* box = toLayoutBox(o);
1564 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, *box);
1566 if (o->isOutOfFlowPositioned())
1567 o->containingBlock()->insertPositionedObject(box);
1568 else if (o->isFloating())
1569 layoutState.floats().append(FloatWithRect(box));
1570 else if (isFullLayout || o->needsLayout()) {
1571 // Replaced element.
1572 box->dirtyLineBoxes(isFullLayout);
1573 if (isFullLayout)
1574 replacedChildren.append(box);
1575 else
1576 o->layoutIfNeeded();
1578 } else if (o->isText() || (o->isRenderInline() && !walker.atEndOfInline())) {
1579 if (!o->isText())
1580 toRenderInline(o)->updateAlwaysCreateLineBoxes(layoutState.isFullLayout());
1581 if (layoutState.isFullLayout() || o->selfNeedsLayout())
1582 dirtyLineBoxesForRenderer(o, layoutState.isFullLayout());
1583 o->clearNeedsLayout();
1587 for (size_t i = 0; i < replacedChildren.size(); i++)
1588 replacedChildren[i]->layoutIfNeeded();
1590 layoutRunsAndFloats(layoutState);
1593 // Expand the last line to accommodate Ruby and emphasis marks.
1594 int lastLineAnnotationsAdjustment = 0;
1595 if (lastRootBox()) {
1596 LayoutUnit lowestAllowedPosition = std::max(lastRootBox()->lineBottom(), logicalHeight() + paddingAfter());
1597 if (!style()->isFlippedLinesWritingMode())
1598 lastLineAnnotationsAdjustment = lastRootBox()->computeUnderAnnotationAdjustment(lowestAllowedPosition);
1599 else
1600 lastLineAnnotationsAdjustment = lastRootBox()->computeOverAnnotationAdjustment(lowestAllowedPosition);
1603 // Now add in the bottom border/padding.
1604 setLogicalHeight(logicalHeight() + lastLineAnnotationsAdjustment + afterEdge);
1606 if (!firstLineBox() && hasLineIfEmpty())
1607 setLogicalHeight(logicalHeight() + lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
1609 // See if we have any lines that spill out of our block. If we do, then we will possibly need to
1610 // truncate text.
1611 if (hasTextOverflow)
1612 checkLinesForTextOverflow();
1614 // Ensure the new line boxes will be painted.
1615 if (isFullLayout && firstLineBox())
1616 setShouldDoFullPaintInvalidation();
1619 void RenderBlockFlow::checkFloatsInCleanLine(RootInlineBox* line, Vector<FloatWithRect>& floats, size_t& floatIndex, bool& encounteredNewFloat, bool& dirtiedByFloat)
1621 Vector<LayoutBox*>* cleanLineFloats = line->floatsPtr();
1622 if (!cleanLineFloats)
1623 return;
1625 Vector<LayoutBox*>::iterator end = cleanLineFloats->end();
1626 for (Vector<LayoutBox*>::iterator it = cleanLineFloats->begin(); it != end; ++it) {
1627 LayoutBox* floatingBox = *it;
1628 floatingBox->layoutIfNeeded();
1629 LayoutSize newSize = floatingBox->size() +
1630 LayoutSize(floatingBox->marginWidth(), floatingBox->marginHeight());
1631 if (floats[floatIndex].object != floatingBox) {
1632 encounteredNewFloat = true;
1633 return;
1636 if (floats[floatIndex].rect.size() != newSize) {
1637 LayoutUnit floatTop = isHorizontalWritingMode() ? floats[floatIndex].rect.y() : floats[floatIndex].rect.x();
1638 LayoutUnit floatHeight = isHorizontalWritingMode() ? std::max(floats[floatIndex].rect.height(), newSize.height())
1639 : std::max(floats[floatIndex].rect.width(), newSize.width());
1640 floatHeight = std::min(floatHeight, LayoutUnit::max() - floatTop);
1641 line->markDirty();
1642 markLinesDirtyInBlockRange(line->lineBottomWithLeading(), floatTop + floatHeight, line);
1643 floats[floatIndex].rect.setSize(newSize);
1644 dirtiedByFloat = true;
1646 floatIndex++;
1650 RootInlineBox* RenderBlockFlow::determineStartPosition(LineLayoutState& layoutState, InlineBidiResolver& resolver)
1652 RootInlineBox* curr = 0;
1653 RootInlineBox* last = 0;
1655 // FIXME: This entire float-checking block needs to be broken into a new function.
1656 bool dirtiedByFloat = false;
1657 if (!layoutState.isFullLayout()) {
1658 // Paginate all of the clean lines.
1659 bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
1660 LayoutUnit paginationDelta = 0;
1661 size_t floatIndex = 0;
1662 for (curr = firstRootBox(); curr && !curr->isDirty(); curr = curr->nextRootBox()) {
1663 if (paginated) {
1664 paginationDelta -= curr->paginationStrut();
1665 adjustLinePositionForPagination(*curr, paginationDelta, layoutState.flowThread());
1666 if (paginationDelta) {
1667 if (containsFloats() || !layoutState.floats().isEmpty()) {
1668 // FIXME: Do better eventually. For now if we ever shift because of pagination and floats are present just go to a full layout.
1669 layoutState.markForFullLayout();
1670 break;
1673 layoutState.updatePaintInvalidationRangeFromBox(curr, paginationDelta);
1674 curr->adjustBlockDirectionPosition(paginationDelta.toFloat());
1678 // If a new float has been inserted before this line or before its last known float, just do a full layout.
1679 bool encounteredNewFloat = false;
1680 checkFloatsInCleanLine(curr, layoutState.floats(), floatIndex, encounteredNewFloat, dirtiedByFloat);
1681 if (encounteredNewFloat)
1682 layoutState.markForFullLayout();
1684 if (dirtiedByFloat || layoutState.isFullLayout())
1685 break;
1687 // Check if a new float has been inserted after the last known float.
1688 if (!curr && floatIndex < layoutState.floats().size())
1689 layoutState.markForFullLayout();
1692 if (layoutState.isFullLayout()) {
1693 // If we encountered a new float and have inline children, mark ourself to force us to issue paint invalidations.
1694 if (layoutState.hasInlineChild() && !selfNeedsLayout()) {
1695 setNeedsLayoutAndFullPaintInvalidation(MarkOnlyThis);
1696 setShouldDoFullPaintInvalidation();
1699 // FIXME: This should just call deleteLineBoxTree, but that causes
1700 // crashes for fast/repaint tests.
1701 curr = firstRootBox();
1702 while (curr) {
1703 // Note: This uses nextRootBox() insted of nextLineBox() like deleteLineBoxTree does.
1704 RootInlineBox* next = curr->nextRootBox();
1705 curr->deleteLine();
1706 curr = next;
1708 ASSERT(!firstLineBox() && !lastLineBox());
1709 } else {
1710 if (curr) {
1711 // We have a dirty line.
1712 if (RootInlineBox* prevRootBox = curr->prevRootBox()) {
1713 // We have a previous line.
1714 if (!dirtiedByFloat && (!prevRootBox->endsWithBreak() || !prevRootBox->lineBreakObj() || (prevRootBox->lineBreakObj()->isText() && prevRootBox->lineBreakPos() >= toRenderText(prevRootBox->lineBreakObj())->textLength())))
1715 // The previous line didn't break cleanly or broke at a newline
1716 // that has been deleted, so treat it as dirty too.
1717 curr = prevRootBox;
1719 } else {
1720 // No dirty lines were found.
1721 // If the last line didn't break cleanly, treat it as dirty.
1722 if (lastRootBox() && !lastRootBox()->endsWithBreak())
1723 curr = lastRootBox();
1726 // If we have no dirty lines, then last is just the last root box.
1727 last = curr ? curr->prevRootBox() : lastRootBox();
1730 unsigned numCleanFloats = 0;
1731 if (!layoutState.floats().isEmpty()) {
1732 LayoutUnit savedLogicalHeight = logicalHeight();
1733 // Restore floats from clean lines.
1734 RootInlineBox* line = firstRootBox();
1735 while (line != curr) {
1736 if (Vector<LayoutBox*>* cleanLineFloats = line->floatsPtr()) {
1737 Vector<LayoutBox*>::iterator end = cleanLineFloats->end();
1738 for (Vector<LayoutBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) {
1739 FloatingObject* floatingObject = insertFloatingObject(**f);
1740 ASSERT(!floatingObject->originatingLine());
1741 floatingObject->setOriginatingLine(line);
1742 setLogicalHeight(logicalTopForChild(**f) - marginBeforeForChild(**f));
1743 positionNewFloats();
1744 ASSERT(layoutState.floats()[numCleanFloats].object == *f);
1745 numCleanFloats++;
1748 line = line->nextRootBox();
1750 setLogicalHeight(savedLogicalHeight);
1752 layoutState.setFloatIndex(numCleanFloats);
1754 layoutState.lineInfo().setFirstLine(!last);
1755 layoutState.lineInfo().setPreviousLineBrokeCleanly(!last || last->endsWithBreak());
1757 if (last) {
1758 setLogicalHeight(last->lineBottomWithLeading());
1759 InlineIterator iter = InlineIterator(this, last->lineBreakObj(), last->lineBreakPos());
1760 resolver.setPosition(iter, numberOfIsolateAncestors(iter));
1761 resolver.setStatus(last->lineBreakBidiStatus());
1762 } else {
1763 TextDirection direction = style()->direction();
1764 if (style()->unicodeBidi() == Plaintext)
1765 direction = determinePlaintextDirectionality(this);
1766 resolver.setStatus(BidiStatus(direction, isOverride(style()->unicodeBidi())));
1767 InlineIterator iter = InlineIterator(this, bidiFirstSkippingEmptyInlines(this, resolver.runs(), &resolver), 0);
1768 resolver.setPosition(iter, numberOfIsolateAncestors(iter));
1770 return curr;
1773 void RenderBlockFlow::determineEndPosition(LineLayoutState& layoutState, RootInlineBox* startLine, InlineIterator& cleanLineStart, BidiStatus& cleanLineBidiStatus)
1775 ASSERT(!layoutState.endLine());
1776 size_t floatIndex = layoutState.floatIndex();
1777 RootInlineBox* last = 0;
1778 for (RootInlineBox* curr = startLine->nextRootBox(); curr; curr = curr->nextRootBox()) {
1779 if (!curr->isDirty()) {
1780 bool encounteredNewFloat = false;
1781 bool dirtiedByFloat = false;
1782 checkFloatsInCleanLine(curr, layoutState.floats(), floatIndex, encounteredNewFloat, dirtiedByFloat);
1783 if (encounteredNewFloat)
1784 return;
1786 if (curr->isDirty())
1787 last = 0;
1788 else if (!last)
1789 last = curr;
1792 if (!last)
1793 return;
1795 // At this point, |last| is the first line in a run of clean lines that ends with the last line
1796 // in the block.
1798 RootInlineBox* prev = last->prevRootBox();
1799 cleanLineStart = InlineIterator(this, prev->lineBreakObj(), prev->lineBreakPos());
1800 cleanLineBidiStatus = prev->lineBreakBidiStatus();
1801 layoutState.setEndLineLogicalTop(prev->lineBottomWithLeading());
1803 for (RootInlineBox* line = last; line; line = line->nextRootBox())
1804 line->extractLine(); // Disconnect all line boxes from their render objects while preserving
1805 // their connections to one another.
1807 layoutState.setEndLine(last);
1810 bool RenderBlockFlow::checkPaginationAndFloatsAtEndLine(LineLayoutState& layoutState)
1812 LayoutUnit lineDelta = logicalHeight() - layoutState.endLineLogicalTop();
1814 bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
1815 if (paginated && layoutState.flowThread()) {
1816 // Check all lines from here to the end, and see if the hypothetical new position for the lines will result
1817 // in a different available line width.
1818 for (RootInlineBox* lineBox = layoutState.endLine(); lineBox; lineBox = lineBox->nextRootBox()) {
1819 if (paginated) {
1820 // This isn't the real move we're going to do, so don't update the line box's pagination
1821 // strut yet.
1822 LayoutUnit oldPaginationStrut = lineBox->paginationStrut();
1823 lineDelta -= oldPaginationStrut;
1824 adjustLinePositionForPagination(*lineBox, lineDelta, layoutState.flowThread());
1825 lineBox->setPaginationStrut(oldPaginationStrut);
1830 if (!lineDelta || !m_floatingObjects)
1831 return true;
1833 // See if any floats end in the range along which we want to shift the lines vertically.
1834 LayoutUnit logicalTop = std::min(logicalHeight(), layoutState.endLineLogicalTop());
1836 RootInlineBox* lastLine = layoutState.endLine();
1837 while (RootInlineBox* nextLine = lastLine->nextRootBox())
1838 lastLine = nextLine;
1840 LayoutUnit logicalBottom = lastLine->lineBottomWithLeading() + absoluteValue(lineDelta);
1842 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1843 FloatingObjectSetIterator end = floatingObjectSet.end();
1844 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
1845 FloatingObject* floatingObject = it->get();
1846 if (logicalBottomForFloat(floatingObject) >= logicalTop && logicalBottomForFloat(floatingObject) < logicalBottom)
1847 return false;
1850 return true;
1853 bool RenderBlockFlow::matchedEndLine(LineLayoutState& layoutState, const InlineBidiResolver& resolver, const InlineIterator& endLineStart, const BidiStatus& endLineStatus)
1855 if (resolver.position() == endLineStart) {
1856 if (resolver.status() != endLineStatus)
1857 return false;
1858 return checkPaginationAndFloatsAtEndLine(layoutState);
1861 // The first clean line doesn't match, but we can check a handful of following lines to try
1862 // to match back up.
1863 static int numLines = 8; // The # of lines we're willing to match against.
1864 RootInlineBox* originalEndLine = layoutState.endLine();
1865 RootInlineBox* line = originalEndLine;
1866 for (int i = 0; i < numLines && line; i++, line = line->nextRootBox()) {
1867 if (line->lineBreakObj() == resolver.position().object() && line->lineBreakPos() == resolver.position().offset()) {
1868 // We have a match.
1869 if (line->lineBreakBidiStatus() != resolver.status())
1870 return false; // ...but the bidi state doesn't match.
1872 bool matched = false;
1873 RootInlineBox* result = line->nextRootBox();
1874 layoutState.setEndLine(result);
1875 if (result) {
1876 layoutState.setEndLineLogicalTop(line->lineBottomWithLeading());
1877 matched = checkPaginationAndFloatsAtEndLine(layoutState);
1880 // Now delete the lines that we failed to sync.
1881 deleteLineRange(layoutState, originalEndLine, result);
1882 return matched;
1886 return false;
1889 bool RenderBlockFlow::generatesLineBoxesForInlineChild(LayoutObject* inlineObj)
1892 ASSERT(inlineObj->parent() == this);
1894 InlineIterator it(this, inlineObj, 0);
1895 // FIXME: We should pass correct value for WhitespacePosition.
1896 while (!it.atEnd() && !requiresLineBox(it))
1897 it.increment();
1899 return !it.atEnd();
1903 void RenderBlockFlow::addOverflowFromInlineChildren()
1905 LayoutUnit endPadding = hasOverflowClip() ? paddingEnd() : LayoutUnit();
1906 // FIXME: Need to find another way to do this, since scrollbars could show when we don't want them to.
1907 if (hasOverflowClip() && !endPadding && node() && node()->isRootEditableElement() && style()->isLeftToRightDirection())
1908 endPadding = 1;
1909 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
1910 addLayoutOverflow(curr->paddedLayoutOverflowRect(endPadding));
1911 LayoutRect visualOverflow = curr->visualOverflowRect(curr->lineTop(), curr->lineBottom());
1912 addContentsVisualOverflow(visualOverflow);
1916 void RenderBlockFlow::deleteEllipsisLineBoxes()
1918 ETextAlign textAlign = style()->textAlign();
1919 bool ltr = style()->isLeftToRightDirection();
1920 bool firstLine = true;
1921 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
1922 if (curr->hasEllipsisBox()) {
1923 curr->clearTruncation();
1925 // Shift the line back where it belongs if we cannot accomodate an ellipsis.
1926 float logicalLeft = logicalLeftOffsetForLine(curr->lineTop(), firstLine).toFloat();
1927 float availableLogicalWidth = logicalRightOffsetForLine(curr->lineTop(), false) - logicalLeft;
1928 float totalLogicalWidth = curr->logicalWidth();
1929 updateLogicalWidthForAlignment(textAlign, curr, 0, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0);
1931 if (ltr)
1932 curr->adjustLogicalPosition((logicalLeft - curr->logicalLeft()), 0);
1933 else
1934 curr->adjustLogicalPosition(-(curr->logicalLeft() - logicalLeft), 0);
1936 firstLine = false;
1940 void RenderBlockFlow::checkLinesForTextOverflow()
1942 // Determine the width of the ellipsis using the current font.
1943 // FIXME: CSS3 says this is configurable, also need to use 0x002E (FULL STOP) if horizontal ellipsis is "not renderable"
1944 const Font& font = style()->font();
1945 DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1));
1946 const Font& firstLineFont = firstLineStyle()->font();
1947 // FIXME: We should probably not hard-code the direction here. https://crbug.com/333004
1948 TextDirection ellipsisDirection = LTR;
1949 float firstLineEllipsisWidth = firstLineFont.width(constructTextRun(this, firstLineFont, &horizontalEllipsis, 1, *firstLineStyle(), ellipsisDirection));
1950 float ellipsisWidth = (font == firstLineFont) ? firstLineEllipsisWidth : font.width(constructTextRun(this, font, &horizontalEllipsis, 1, styleRef(), ellipsisDirection));
1952 // For LTR text truncation, we want to get the right edge of our padding box, and then we want to see
1953 // if the right edge of a line box exceeds that. For RTL, we use the left edge of the padding box and
1954 // check the left edge of the line box to see if it is less
1955 // Include the scrollbar for overflow blocks, which means we want to use "contentWidth()"
1956 bool ltr = style()->isLeftToRightDirection();
1957 ETextAlign textAlign = style()->textAlign();
1958 bool firstLine = true;
1959 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
1960 float currLogicalLeft = curr->logicalLeft();
1961 LayoutUnit blockRightEdge = logicalRightOffsetForLine(curr->lineTop(), firstLine);
1962 LayoutUnit blockLeftEdge = logicalLeftOffsetForLine(curr->lineTop(), firstLine);
1963 LayoutUnit lineBoxEdge = ltr ? currLogicalLeft + curr->logicalWidth() : currLogicalLeft;
1964 if ((ltr && lineBoxEdge > blockRightEdge) || (!ltr && lineBoxEdge < blockLeftEdge)) {
1965 // This line spills out of our box in the appropriate direction. Now we need to see if the line
1966 // can be truncated. In order for truncation to be possible, the line must have sufficient space to
1967 // accommodate our truncation string, and no replaced elements (images, tables) can overlap the ellipsis
1968 // space.
1970 LayoutUnit width = firstLine ? firstLineEllipsisWidth : ellipsisWidth;
1971 LayoutUnit blockEdge = ltr ? blockRightEdge : blockLeftEdge;
1972 if (curr->lineCanAccommodateEllipsis(ltr, blockEdge, lineBoxEdge, width)) {
1973 float totalLogicalWidth = curr->placeEllipsis(ellipsisStr, ltr, blockLeftEdge.toFloat(), blockRightEdge.toFloat(), width.toFloat());
1975 float logicalLeft = 0; // We are only intersted in the delta from the base position.
1976 float availableLogicalWidth = (blockRightEdge - blockLeftEdge).toFloat();
1977 updateLogicalWidthForAlignment(textAlign, curr, 0, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0);
1978 if (ltr)
1979 curr->adjustLogicalPosition(logicalLeft, 0);
1980 else
1981 curr->adjustLogicalPosition(logicalLeft - (availableLogicalWidth - totalLogicalWidth), 0);
1984 firstLine = false;
1988 bool RenderBlockFlow::positionNewFloatOnLine(FloatingObject* newFloat, FloatingObject* lastFloatFromPreviousLine, LineInfo& lineInfo, LineWidth& width)
1990 if (!positionNewFloats(&width))
1991 return false;
1993 // We only connect floats to lines for pagination purposes if the floats occur at the start of
1994 // the line and the previous line had a hard break (so this line is either the first in the block
1995 // or follows a <br>).
1996 if (!newFloat->paginationStrut() || !lineInfo.previousLineBrokeCleanly() || !lineInfo.isEmpty())
1997 return true;
1999 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2000 ASSERT(floatingObjectSet.last() == newFloat);
2002 LayoutUnit floatLogicalTop = logicalTopForFloat(newFloat);
2003 int paginationStrut = newFloat->paginationStrut();
2005 if (floatLogicalTop - paginationStrut != logicalHeight() + lineInfo.floatPaginationStrut())
2006 return true;
2008 FloatingObjectSetIterator it = floatingObjectSet.end();
2009 --it; // Last float is newFloat, skip that one.
2010 FloatingObjectSetIterator begin = floatingObjectSet.begin();
2011 while (it != begin) {
2012 --it;
2013 FloatingObject* floatingObject = it->get();
2014 if (floatingObject == lastFloatFromPreviousLine)
2015 break;
2016 if (logicalTopForFloat(floatingObject) == logicalHeight() + lineInfo.floatPaginationStrut()) {
2017 floatingObject->setPaginationStrut(paginationStrut + floatingObject->paginationStrut());
2018 LayoutBox* floatBox = floatingObject->renderer();
2019 setLogicalTopForChild(*floatBox, logicalTopForChild(*floatBox) + marginBeforeForChild(*floatBox) + paginationStrut);
2020 if (floatBox->isRenderBlock())
2021 floatBox->forceChildLayout();
2022 else
2023 floatBox->layoutIfNeeded();
2024 // Save the old logical top before calling removePlacedObject which will set
2025 // isPlaced to false. Otherwise it will trigger an assert in logicalTopForFloat.
2026 LayoutUnit oldLogicalTop = logicalTopForFloat(floatingObject);
2027 m_floatingObjects->removePlacedObject(floatingObject);
2028 setLogicalTopForFloat(floatingObject, oldLogicalTop + paginationStrut);
2029 m_floatingObjects->addPlacedObject(floatingObject);
2033 // Just update the line info's pagination strut without altering our logical height yet. If the line ends up containing
2034 // no content, then we don't want to improperly grow the height of the block.
2035 lineInfo.setFloatPaginationStrut(lineInfo.floatPaginationStrut() + paginationStrut);
2036 return true;
2039 LayoutUnit RenderBlockFlow::startAlignedOffsetForLine(LayoutUnit position, bool firstLine)
2041 ETextAlign textAlign = style()->textAlign();
2043 if (textAlign == TASTART) // FIXME: Handle TAEND here
2044 return startOffsetForLine(position, firstLine);
2046 // updateLogicalWidthForAlignment() handles the direction of the block so no need to consider it here
2047 float totalLogicalWidth = 0;
2048 float logicalLeft = logicalLeftOffsetForLine(logicalHeight(), false).toFloat();
2049 float availableLogicalWidth = logicalRightOffsetForLine(logicalHeight(), false) - logicalLeft;
2050 updateLogicalWidthForAlignment(textAlign, 0, 0, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0);
2052 if (!style()->isLeftToRightDirection())
2053 return logicalWidth() - logicalLeft;
2054 return logicalLeft;