• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "config.h"
24 
25 #include "core/accessibility/AXObjectCache.h"
26 #include "core/rendering/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"
50 
51 namespace blink {
52 
53 using namespace WTF::Unicode;
54 
createInlineBoxForRenderer(RenderObject * obj,bool isRootLineBox,bool isOnlyRun=false)55 static inline InlineBox* createInlineBoxForRenderer(RenderObject* obj, bool isRootLineBox, bool isOnlyRun = false)
56 {
57     if (isRootLineBox)
58         return toRenderBlockFlow(obj)->createAndAppendRootInlineBox();
59 
60     if (obj->isText()) {
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.)
64         if (obj->isBR())
65             textBox->setIsText(isOnlyRun || obj->document().inNoQuirksMode());
66         return textBox;
67     }
68 
69     if (obj->isBox())
70         return toRenderBox(obj)->createInlineBox();
71 
72     return toRenderInline(obj)->createAndAppendInlineFlowBox();
73 }
74 
dirtyLineBoxesForRenderer(RenderObject * o,bool fullLayout)75 static inline void dirtyLineBoxesForRenderer(RenderObject* o, bool fullLayout)
76 {
77     if (o->isText()) {
78         RenderText* renderText = toRenderText(o);
79         renderText->dirtyLineBoxes(fullLayout);
80     } else
81         toRenderInline(o)->dirtyLineBoxes(fullLayout);
82 }
83 
parentIsConstructedOrHaveNext(InlineFlowBox * parentBox)84 static bool parentIsConstructedOrHaveNext(InlineFlowBox* parentBox)
85 {
86     do {
87         if (parentBox->isConstructed() || parentBox->nextOnLine())
88             return true;
89         parentBox = parentBox->parent();
90     } while (parentBox);
91     return false;
92 }
93 
createLineBoxes(RenderObject * obj,const LineInfo & lineInfo,InlineBox * childBox)94 InlineFlowBox* RenderBlockFlow::createLineBoxes(RenderObject* obj, const LineInfo& lineInfo, InlineBox* childBox)
95 {
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();
102     do {
103         ASSERT_WITH_SECURITY_IMPLICATION(obj->isRenderInline() || obj == this);
104 
105         RenderInline* inlineFlow = (obj != this) ? toRenderInline(obj) : 0;
106 
107         // Get the last box we made for this render object.
108         parentBox = inlineFlow ? inlineFlow->lastLineBox() : toRenderBlock(obj)->lastLineBox();
109 
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;
129         }
130 
131         if (constructedNewBox || canUseExistingParentBox) {
132             if (!result)
133                 result = parentBox;
134 
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
137             // inline.
138             if (childBox)
139                 parentBox->addToLine(childBox);
140 
141             if (!constructedNewBox || obj == this)
142                 break;
143 
144             childBox = parentBox;
145         }
146 
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();
150 
151     } while (true);
152 
153     return result;
154 }
155 
156 template <typename CharacterType>
endsWithASCIISpaces(const CharacterType * characters,unsigned pos,unsigned end)157 static inline bool endsWithASCIISpaces(const CharacterType* characters, unsigned pos, unsigned end)
158 {
159     while (isASCIISpace(characters[pos])) {
160         pos++;
161         if (pos >= end)
162             return true;
163     }
164     return false;
165 }
166 
reachedEndOfTextRenderer(const BidiRunList<BidiRun> & bidiRuns)167 static bool reachedEndOfTextRenderer(const BidiRunList<BidiRun>& bidiRuns)
168 {
169     BidiRun* run = bidiRuns.logicallyLastRun();
170     if (!run)
171         return true;
172     unsigned pos = run->stop();
173     RenderObject* r = run->m_object;
174     if (!r->isText() || r->isBR())
175         return false;
176     RenderText* renderText = toRenderText(r);
177     unsigned length = renderText->textLength();
178     if (pos >= length)
179         return true;
180 
181     if (renderText->is8Bit())
182         return endsWithASCIISpaces(renderText->characters8(), pos, length);
183     return endsWithASCIISpaces(renderText->characters16(), pos, length);
184 }
185 
constructLine(BidiRunList<BidiRun> & bidiRuns,const LineInfo & lineInfo)186 RootInlineBox* RenderBlockFlow::constructLine(BidiRunList<BidiRun>& bidiRuns, const LineInfo& lineInfo)
187 {
188     ASSERT(bidiRuns.firstRun());
189 
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();
198 
199         if (lineInfo.isEmpty())
200             continue;
201 
202         InlineBox* box = createInlineBoxForRenderer(r->m_object, false, isOnlyRun);
203         r->m_box = box;
204 
205         ASSERT(box);
206         if (!box)
207             continue;
208 
209         if (!rootHasSelectedChildren && box->renderer().selectionState() != RenderObject::SelectionNone)
210             rootHasSelectedChildren = true;
211 
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);
219         } else {
220             // Append the inline box to this line.
221             parentBox->addToLine(box);
222         }
223 
224         bool visuallyOrdered = r->m_object->style()->rtlOrdering() == VisualOrder;
225         box->setBidiLevel(r->level());
226 
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));
232             if (r->m_hasHyphen)
233                 text->setHasHyphen(true);
234 
235             if (AXObjectCache* cache = document().existingAXObjectCache())
236                 cache->inlineTextBoxesUpdated(r->m_object);
237         }
238     }
239 
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());
243 
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);
248 
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
252     // the line.
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);
255 
256     // Now mark the line boxes as being constructed.
257     lastLineBox()->setConstructed();
258 
259     // Return the last line.
260     return lastRootBox();
261 }
262 
textAlignmentForLine(bool endsWithSoftBreak) const263 ETextAlign RenderBlockFlow::textAlignmentForLine(bool endsWithSoftBreak) const
264 {
265     ETextAlign alignment = style()->textAlign();
266     if (endsWithSoftBreak)
267         return alignment;
268 
269     if (!RuntimeEnabledFeatures::css3TextEnabled())
270         return (alignment == JUSTIFY) ? TASTART : alignment;
271 
272     if (alignment != JUSTIFY)
273         return alignment;
274 
275     TextAlignLast alignmentLast = style()->textAlignLast();
276     switch (alignmentLast) {
277     case TextAlignLastStart:
278         return TASTART;
279     case TextAlignLastEnd:
280         return TAEND;
281     case TextAlignLastLeft:
282         return LEFT;
283     case TextAlignLastRight:
284         return RIGHT;
285     case TextAlignLastCenter:
286         return CENTER;
287     case TextAlignLastJustify:
288         return JUSTIFY;
289     case TextAlignLastAuto:
290         if (style()->textJustify() == TextJustifyDistribute)
291             return JUSTIFY;
292         return TASTART;
293     }
294 
295     return alignment;
296 }
297 
updateLogicalWidthForLeftAlignedBlock(bool isLeftToRightDirection,BidiRun * trailingSpaceRun,float & logicalLeft,float & totalLogicalWidth,float availableLogicalWidth)298 static void updateLogicalWidthForLeftAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
299 {
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));
305         return;
306     }
307 
308     if (trailingSpaceRun)
309         trailingSpaceRun->m_box->setLogicalWidth(0);
310     else if (totalLogicalWidth > availableLogicalWidth)
311         logicalLeft -= (totalLogicalWidth - availableLogicalWidth);
312 }
313 
updateLogicalWidthForRightAlignedBlock(bool isLeftToRightDirection,BidiRun * trailingSpaceRun,float & logicalLeft,float & totalLogicalWidth,float availableLogicalWidth)314 static void updateLogicalWidthForRightAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
315 {
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);
323         }
324         if (totalLogicalWidth < availableLogicalWidth)
325             logicalLeft += availableLogicalWidth - totalLogicalWidth;
326         return;
327     }
328 
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();
332     } else
333         logicalLeft += availableLogicalWidth - totalLogicalWidth;
334 }
335 
updateLogicalWidthForCenterAlignedBlock(bool isLeftToRightDirection,BidiRun * trailingSpaceRun,float & logicalLeft,float & totalLogicalWidth,float availableLogicalWidth)336 static void updateLogicalWidthForCenterAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
337 {
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));
343     }
344     if (isLeftToRightDirection)
345         logicalLeft += std::max<float>((availableLogicalWidth - totalLogicalWidth) / 2, 0);
346     else
347         logicalLeft += totalLogicalWidth > availableLogicalWidth ? (availableLogicalWidth - totalLogicalWidth) : (availableLogicalWidth - totalLogicalWidth) / 2 - trailingSpaceWidth;
348 }
349 
setMarginsForRubyRun(BidiRun * run,RenderRubyRun * renderer,RenderObject * previousObject,const LineInfo & lineInfo)350 void RenderBlockFlow::setMarginsForRubyRun(BidiRun* run, RenderRubyRun* renderer, RenderObject* previousObject, const LineInfo& lineInfo)
351 {
352     int startOverhang;
353     int endOverhang;
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;
358             break;
359         }
360     }
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);
364 }
365 
setLogicalWidthForTextRun(RootInlineBox * lineBox,BidiRun * run,RenderText * renderer,float xPos,const LineInfo & lineInfo,GlyphOverflowAndFallbackFontsMap & textBoxDataMap,VerticalPositionCache & verticalPositionCache,WordMeasurements & wordMeasurements)366 static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* run, RenderText* renderer, float xPos, const LineInfo& lineInfo,
367                                              GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, WordMeasurements& wordMeasurements)
368 {
369     HashSet<const SimpleFontData*> fallbackFonts;
370     GlyphOverflow glyphOverflow;
371 
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;
385     }
386 
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());
391     }
392     float measuredWidth = 0;
393 
394     bool kerningIsEnabled = font.fontDescription().typesettingFeatures() & Kerning;
395 
396 #if OS(MACOSX)
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();
400 #else
401     bool canUseSimpleFontCodePath = renderer->canUseSimpleFontCodePath();
402 #endif
403 
404     // Since we don't cache glyph overflows, we need to re-measure the run if
405     // the style is linebox-contain: glyph.
406 
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)
412                 continue;
413             if (wordMeasurement.renderer != renderer || wordMeasurement.startOffset != lastEndOffset || wordMeasurement.endOffset > run->m_stop)
414                 continue;
415 
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();
422             } else
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);
428             }
429         }
430         if (measuredWidth && lastEndOffset != run->m_stop) {
431             // If we don't have enough cached data, we'll measure the run again.
432             measuredWidth = 0;
433             fallbackFonts.clear();
434         }
435     }
436 
437     if (!measuredWidth)
438         measuredWidth = renderer->width(run->m_start, run->m_stop - run->m_start, xPos, run->direction(), lineInfo.isFirstLine(), &fallbackFonts, &glyphOverflow);
439 
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();
447     }
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();
453     }
454 }
455 
computeExpansionForJustifiedText(BidiRun * firstRun,BidiRun * trailingSpaceRun,Vector<unsigned,16> & expansionOpportunities,unsigned expansionOpportunityCount,float & totalLogicalWidth,float availableLogicalWidth)456 static inline void computeExpansionForJustifiedText(BidiRun* firstRun, BidiRun* trailingSpaceRun, Vector<unsigned, 16>& expansionOpportunities, unsigned expansionOpportunityCount, float& totalLogicalWidth, float availableLogicalWidth)
457 {
458     if (!expansionOpportunityCount || availableLogicalWidth <= totalLogicalWidth)
459         return;
460 
461     size_t i = 0;
462     for (BidiRun* r = firstRun; r; r = r->next()) {
463         if (!r->m_box || r == trailingSpaceRun)
464             continue;
465 
466         if (r->m_object->isText()) {
467             unsigned opportunitiesInRun = expansionOpportunities[i++];
468 
469             ASSERT(opportunitiesInRun <= expansionOpportunityCount);
470 
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;
477             }
478             expansionOpportunityCount -= opportunitiesInRun;
479             if (!expansionOpportunityCount)
480                 break;
481         }
482     }
483 }
484 
updateLogicalWidthForAlignment(const ETextAlign & textAlign,const RootInlineBox * rootInlineBox,BidiRun * trailingSpaceRun,float & logicalLeft,float & totalLogicalWidth,float & availableLogicalWidth,unsigned expansionOpportunityCount)485 void RenderBlockFlow::updateLogicalWidthForAlignment(const ETextAlign& textAlign, const RootInlineBox* rootInlineBox, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float& availableLogicalWidth, unsigned expansionOpportunityCount)
486 {
487     TextDirection direction;
488     if (rootInlineBox && rootInlineBox->renderer().style()->unicodeBidi() == Plaintext)
489         direction = rootInlineBox->direction();
490     else
491         direction = style()->direction();
492 
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
496     // justifying text.
497     switch (textAlign) {
498     case LEFT:
499     case WEBKIT_LEFT:
500         updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
501         break;
502     case RIGHT:
503     case WEBKIT_RIGHT:
504         updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
505         break;
506     case CENTER:
507     case WEBKIT_CENTER:
508         updateLogicalWidthForCenterAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
509         break;
510     case JUSTIFY:
511         adjustInlineDirectionLineBounds(expansionOpportunityCount, logicalLeft, availableLogicalWidth);
512         if (expansionOpportunityCount) {
513             if (trailingSpaceRun) {
514                 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
515                 trailingSpaceRun->m_box->setLogicalWidth(0);
516             }
517             break;
518         }
519         // Fall through
520     case TASTART:
521         if (direction == LTR)
522             updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
523         else
524             updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
525         break;
526     case TAEND:
527         if (direction == LTR)
528             updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
529         else
530             updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
531         break;
532     }
533     if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
534         logicalLeft += verticalScrollbarWidth();
535 }
536 
updateLogicalInlinePositions(RenderBlockFlow * block,float & lineLogicalLeft,float & lineLogicalRight,float & availableLogicalWidth,bool firstLine,IndentTextOrNot shouldIndentText,LayoutUnit boxLogicalHeight)537 static void updateLogicalInlinePositions(RenderBlockFlow* block, float& lineLogicalLeft, float& lineLogicalRight, float& availableLogicalWidth, bool firstLine, IndentTextOrNot shouldIndentText, LayoutUnit boxLogicalHeight)
538 {
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;
543 }
544 
computeInlineDirectionPositionsForLine(RootInlineBox * lineBox,const LineInfo & lineInfo,BidiRun * firstRun,BidiRun * trailingSpaceRun,bool reachedEnd,GlyphOverflowAndFallbackFontsMap & textBoxDataMap,VerticalPositionCache & verticalPositionCache,WordMeasurements & wordMeasurements)545 void RenderBlockFlow::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, const LineInfo& lineInfo, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd,
546                                                          GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, WordMeasurements& wordMeasurements)
547 {
548     ETextAlign textAlign = textAlignmentForLine(!reachedEnd && !lineBox->endsWithBreak());
549 
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;
562 
563     if (firstRun && firstRun->m_object->isReplaced()) {
564         RenderBox* renderBox = toRenderBox(firstRun->m_object);
565         updateLogicalInlinePositions(this, lineLogicalLeft, lineLogicalRight, availableLogicalWidth, isFirstLine, shouldIndentText, renderBox->logicalHeight());
566     }
567 
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);
573 }
574 
computeInlineDirectionPositionsForSegment(RootInlineBox * lineBox,const LineInfo & lineInfo,ETextAlign textAlign,float & logicalLeft,float & availableLogicalWidth,BidiRun * firstRun,BidiRun * trailingSpaceRun,GlyphOverflowAndFallbackFontsMap & textBoxDataMap,VerticalPositionCache & verticalPositionCache,WordMeasurements & wordMeasurements)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)
578 {
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();
586 
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;
599                 if (rt->is8Bit())
600                     opportunitiesInRun = Character::expansionOpportunityCount(rt->characters8() + r->m_start, r->m_stop - r->m_start, r->m_box->direction(), isAfterExpansion);
601                 else
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;
605             }
606 
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));
611             }
612 
613             setLogicalWidthForTextRun(lineBox, r, rt, totalLogicalWidth, lineInfo, textBoxDataMap, verticalPositionCache, wordMeasurements);
614         } else {
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);
622             }
623         }
624 
625         totalLogicalWidth += r->m_box->logicalWidth();
626         previousObject = r->m_object;
627     }
628 
629     if (isAfterExpansion && !expansionOpportunities.isEmpty()) {
630         expansionOpportunities.last()--;
631         expansionOpportunityCount--;
632     }
633 
634     updateLogicalWidthForAlignment(textAlign, lineBox, trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth, expansionOpportunityCount);
635 
636     computeExpansionForJustifiedText(firstRun, trailingSpaceRun, expansionOpportunities, expansionOpportunityCount, totalLogicalWidth, availableLogicalWidth);
637 
638     return r;
639 }
640 
computeBlockDirectionPositionsForLine(RootInlineBox * lineBox,BidiRun * firstRun,GlyphOverflowAndFallbackFontsMap & textBoxDataMap,VerticalPositionCache & verticalPositionCache)641 void RenderBlockFlow::computeBlockDirectionPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap,
642                                                         VerticalPositionCache& verticalPositionCache)
643 {
644     setLogicalHeight(lineBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache));
645 
646     // Now make sure we place replaced render objects correctly.
647     for (BidiRun* r = firstRun; r; r = r->next()) {
648         ASSERT(r->m_box);
649         if (!r->m_box)
650             continue; // Skip runs with no line boxes.
651 
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());
656 
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);
663     }
664 }
665 
appendFloatingObjectToLastLine(FloatingObject * floatingObject)666 void RenderBlockFlow::appendFloatingObjectToLastLine(FloatingObject* floatingObject)
667 {
668     ASSERT(!floatingObject->originatingLine());
669     floatingObject->setOriginatingLine(lastRootBox());
670     lastRootBox()->appendFloat(floatingObject->renderer());
671 }
672 
673 // This function constructs line boxes for all of the text runs in the resolver and computes their position.
createLineBoxesFromBidiRuns(unsigned bidiLevel,BidiRunList<BidiRun> & bidiRuns,const InlineIterator & end,LineInfo & lineInfo,VerticalPositionCache & verticalPositionCache,BidiRun * trailingSpaceRun,WordMeasurements & wordMeasurements)674 RootInlineBox* RenderBlockFlow::createLineBoxesFromBidiRuns(unsigned bidiLevel, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& end, LineInfo& lineInfo, VerticalPositionCache& verticalPositionCache, BidiRun* trailingSpaceRun, WordMeasurements& wordMeasurements)
675 {
676     if (!bidiRuns.runCount())
677         return 0;
678 
679     // FIXME: Why is this only done when we had runs?
680     lineInfo.setLastLine(!end.object());
681 
682     RootInlineBox* lineBox = constructLine(bidiRuns, lineInfo);
683     if (!lineBox)
684         return 0;
685 
686     lineBox->setBidiLevel(bidiLevel);
687     lineBox->setEndsWithBreak(lineInfo.previousLineBrokeCleanly());
688 
689     bool isSVGRootInlineBox = lineBox->isSVGRootInlineBox();
690 
691     GlyphOverflowAndFallbackFontsMap textBoxDataMap;
692 
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);
696 
697     // Now position our text runs vertically.
698     computeBlockDirectionPositionsForLine(lineBox, bidiRuns.firstRun(), textBoxDataMap, verticalPositionCache);
699 
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) {
706         ASSERT(isSVGText());
707         toSVGRootInlineBox(lineBox)->computePerCharacterLayoutInformation();
708     }
709 
710     // Compute our overflow now.
711     lineBox->computeOverflow(lineBox->lineTop(), lineBox->lineBottom(), textBoxDataMap);
712 
713     return lineBox;
714 }
715 
deleteLineRange(LineLayoutState & layoutState,RootInlineBox * startLine,RootInlineBox * stopLine=0)716 static void deleteLineRange(LineLayoutState& layoutState, RootInlineBox* startLine, RootInlineBox* stopLine = 0)
717 {
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();
725         boxToDelete = next;
726     }
727 }
728 
layoutRunsAndFloats(LineLayoutState & layoutState)729 void RenderBlockFlow::layoutRunsAndFloats(LineLayoutState& layoutState)
730 {
731     // We want to skip ahead to the first dirty line
732     InlineBidiResolver resolver;
733     RootInlineBox* startLine = determineStartPosition(layoutState, resolver);
734 
735     if (containsFloats())
736         layoutState.setLastFloat(m_floatingObjects->set().last().get());
737 
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);
744 
745     if (startLine) {
746         if (!layoutState.usesPaintInvalidationBounds())
747             layoutState.setPaintInvalidationRange(logicalHeight());
748         deleteLineRange(layoutState, startLine);
749     }
750 
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();
761                 if (clear != CNONE)
762                     clearFloats(clear);
763             }
764         }
765     }
766 
767     layoutRunsAndFloatsInRange(layoutState, resolver, cleanLineStart, cleanLineBidiStatus);
768     linkToEndLineIfNeeded(layoutState);
769     markDirtyFloatsForPaintInvalidation(layoutState.floats());
770 }
771 
772 // Before restarting the layout loop with a new logicalHeight, remove all floats that were added and reset the resolver.
restartLayoutRunsAndFloatsInRange(LayoutUnit oldLogicalHeight,LayoutUnit newLogicalHeight,FloatingObject * lastFloatFromPreviousLine,InlineBidiResolver & resolver,const InlineIterator & oldEnd)773 inline const InlineIterator& RenderBlockFlow::restartLayoutRunsAndFloatsInRange(LayoutUnit oldLogicalHeight, LayoutUnit newLogicalHeight,  FloatingObject* lastFloatFromPreviousLine, InlineBidiResolver& resolver,  const InlineIterator& oldEnd)
774 {
775     removeFloatingObjectsBelow(lastFloatFromPreviousLine, oldLogicalHeight);
776     setLogicalHeight(newLogicalHeight);
777     resolver.setPositionIgnoringNestedIsolates(oldEnd);
778     return oldEnd;
779 }
780 
layoutRunsAndFloatsInRange(LineLayoutState & layoutState,InlineBidiResolver & resolver,const InlineIterator & cleanLineStart,const BidiStatus & cleanLineBidiStatus)781 void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState,
782     InlineBidiResolver& resolver, const InlineIterator& cleanLineStart,
783     const BidiStatus& cleanLineBidiStatus)
784 {
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;
792 
793     LineBreaker lineBreaker(this);
794 
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);
801                 break;
802             }
803         }
804 
805         lineMidpointState.reset();
806 
807         layoutState.lineInfo().setEmpty(true);
808         layoutState.lineInfo().resetRunsFromLeadingWhitespace();
809 
810         const InlineIterator previousEndofLine = endOfLine;
811         bool isNewUBAParagraph = layoutState.lineInfo().previousLineBrokeCleanly();
812         FloatingObject* lastFloatFromPreviousLine = (containsFloats()) ? m_floatingObjects->set().last().get() : 0;
813 
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);
825             break;
826         }
827 
828         ASSERT(endOfLine != resolver.position());
829 
830         // This is a short-cut for empty lines.
831         if (layoutState.lineInfo().isEmpty()) {
832             if (lastRootBox())
833                 lastRootBox()->setLineBreakInfo(endOfLine.object(), endOfLine.offset(), resolver.status());
834         } else {
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())));
839             }
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);
844 
845             BidiRun* trailingSpaceRun = resolver.trailingSpaceRun();
846 
847             if (bidiRuns.runCount() && lineBreaker.lineWasHyphenated())
848                 bidiRuns.logicallyLastRun()->m_hasHyphen = true;
849 
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.
853 
854             LayoutUnit oldLogicalHeight = logicalHeight();
855             RootInlineBox* lineBox = createLineBoxesFromBidiRuns(resolver.status().context->level(), bidiRuns, endOfLine, layoutState.lineInfo(), verticalPositionCache, trailingSpaceRun, wordMeasurements);
856 
857             bidiRuns.deleteRuns();
858             resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed).
859 
860             if (lineBox) {
861                 lineBox->setLineBreakInfo(endOfLine.object(), endOfLine.offset(), resolver.status());
862                 if (layoutState.usesPaintInvalidationBounds())
863                     layoutState.updatePaintInvalidationRangeFromBox(lineBox);
864 
865                 if (paginated) {
866                     LayoutUnit adjustment = 0;
867                     adjustLinePositionForPagination(lineBox, adjustment, layoutState.flowThread());
868                     if (adjustment) {
869                         LayoutUnit oldLineWidth = availableLogicalWidthForLine(oldLogicalHeight, layoutState.lineInfo().isFirstLine());
870                         lineBox->adjustBlockDirectionPosition(adjustment.toFloat());
871                         if (layoutState.usesPaintInvalidationBounds())
872                             layoutState.updatePaintInvalidationRangeFromBox(lineBox);
873 
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);
878                             continue;
879                         }
880 
881                         setLogicalHeight(lineBox->lineBottomWithLeading());
882                     }
883                 }
884             }
885         }
886 
887         for (size_t i = 0; i < lineBreaker.positionedObjects().size(); ++i)
888             setStaticPositions(this, lineBreaker.positionedObjects()[i]);
889 
890         if (!layoutState.lineInfo().isEmpty()) {
891             layoutState.lineInfo().setFirstLine(false);
892             clearFloats(lineBreaker.clear());
893         }
894 
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);
902                 ++lastFloatIterator;
903                 it = lastFloatIterator;
904             }
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);
913             }
914             layoutState.setLastFloat(!floatingObjectSet.isEmpty() ? floatingObjectSet.last().get() : 0);
915         }
916 
917         lineMidpointState.reset();
918         resolver.setPosition(endOfLine, numberOfIsolateAncestors(endOfLine));
919     }
920 
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
927         // a new orphan.
928 
929         RootInlineBox* lineBox = lastRootBox();
930 
931         // Count from the end of the block backwards, to see how many hanging
932         // lines we have.
933         RootInlineBox* firstLineInBlock = firstRootBox();
934         int numLinesHanging = 1;
935         while (lineBox && lineBox != firstLineInBlock && !lineBox->isFirstAfterPageBreak()) {
936             ++numLinesHanging;
937             lineBox = lineBox->prevRootBox();
938         }
939 
940         // If there were no breaks in the block, we didn't create any widows.
941         if (!lineBox || !lineBox->isFirstAfterPageBreak() || lineBox == firstLineInBlock)
942             return;
943 
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
947             // to steal.
948             int numLinesNeeded = style()->widows() - numLinesHanging;
949             RootInlineBox* currentFirstLineOfNewPage = lineBox;
950 
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();
957             }
958 
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)
967                 return;
968 
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();
974 
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);
978         }
979     }
980 
981     clearDidBreakAtLineToAvoidWidow();
982 }
983 
linkToEndLineIfNeeded(LineLayoutState & layoutState)984 void RenderBlockFlow::linkToEndLineIfNeeded(LineLayoutState& layoutState)
985 {
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()) {
992                 line->attachLine();
993                 if (paginated) {
994                     delta -= line->paginationStrut();
995                     adjustLinePositionForPagination(line, delta, layoutState.flowThread());
996                 }
997                 if (delta) {
998                     layoutState.updatePaintInvalidationRangeFromBox(line, delta);
999                     line->adjustBlockDirectionPosition(delta.toFloat());
1000                 }
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();
1009                     }
1010                 }
1011             }
1012             setLogicalHeight(lastRootBox()->lineBottomWithLeading());
1013         } else {
1014             // Delete all the remaining lines.
1015             deleteLineRange(layoutState, layoutState.endLine());
1016         }
1017     }
1018 
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;
1031         }
1032         layoutState.setLastFloat(!floatingObjectSet.isEmpty() ? floatingObjectSet.last().get() : 0);
1033 
1034         if (it == end)
1035             return;
1036 
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());
1052         }
1053 
1054         for (; it != end; ++it)
1055             appendFloatingObjectToLastLine(it->get());
1056     }
1057 }
1058 
markDirtyFloatsForPaintInvalidation(Vector<FloatWithRect> & floats)1059 void RenderBlockFlow::markDirtyFloatsForPaintInvalidation(Vector<FloatWithRect>& floats)
1060 {
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
1064     // painted.
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);
1070             }
1071         }
1072     }
1073 }
1074 
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.
1083 */
1084     RenderObject* parent;
1085     RenderObject* current;
1086     bool endOfInline;
1087 
InlineMinMaxIteratorblink::InlineMinMaxIterator1088     InlineMinMaxIterator(RenderObject* p, bool end = false)
1089         : parent(p), current(p), endOfInline(end)
1090     {
1091 
1092     }
1093 
1094     RenderObject* next();
1095 };
1096 
next()1097 RenderObject* InlineMinMaxIterator::next()
1098 {
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();
1105 
1106         if (!result) {
1107             // We hit the end of our inline. (It was empty, e.g., <span></span>.)
1108             if (!oldEndOfInline && current->isRenderInline()) {
1109                 result = current;
1110                 endOfInline = true;
1111                 break;
1112             }
1113 
1114             while (current && current != parent) {
1115                 result = current->nextSibling();
1116                 if (result)
1117                     break;
1118                 current = current->parent();
1119                 if (current && current != parent && current->isRenderInline()) {
1120                     result = current;
1121                     endOfInline = true;
1122                     break;
1123                 }
1124             }
1125         }
1126 
1127         if (!result)
1128             break;
1129 
1130         if (!result->isOutOfFlowPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
1131             break;
1132 
1133         current = result;
1134         result = 0;
1135     }
1136 
1137     // Update our position.
1138     current = result;
1139     return current;
1140 }
1141 
getBPMWidth(LayoutUnit childValue,Length cssUnit)1142 static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit)
1143 {
1144     if (cssUnit.type() != Auto)
1145         return (cssUnit.isFixed() ? static_cast<LayoutUnit>(cssUnit.value()) : childValue);
1146     return 0;
1147 }
1148 
getBorderPaddingMargin(RenderBoxModelObject * child,bool endOfInline)1149 static LayoutUnit getBorderPaddingMargin(RenderBoxModelObject* child, bool endOfInline)
1150 {
1151     RenderStyle* childStyle = child->style();
1152     if (endOfInline) {
1153         return getBPMWidth(child->marginEnd(), childStyle->marginEnd()) +
1154             getBPMWidth(child->paddingEnd(), childStyle->paddingEnd()) +
1155             child->borderEnd();
1156     }
1157     return getBPMWidth(child->marginStart(), childStyle->marginStart()) +
1158         getBPMWidth(child->paddingStart(), childStyle->paddingStart()) +
1159         child->borderStart();
1160 }
1161 
stripTrailingSpace(float & inlineMax,float & inlineMin,RenderObject * trailingSpaceChild)1162 static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, RenderObject* trailingSpaceChild)
1163 {
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;
1173     }
1174 }
1175 
updatePreferredWidth(LayoutUnit & preferredWidth,float & result)1176 static inline void updatePreferredWidth(LayoutUnit& preferredWidth, float& result)
1177 {
1178     LayoutUnit snappedResult = LayoutUnit::fromFloatCeil(result);
1179     preferredWidth = std::max(snappedResult, preferredWidth);
1180 }
1181 
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.
adjustFloatForSubPixelLayout(float value)1186 static inline LayoutUnit adjustFloatForSubPixelLayout(float value)
1187 {
1188     return LayoutUnit::fromFloatCeil(value);
1189 }
1190 
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.
computeInlinePreferredLogicalWidths(LayoutUnit & minLogicalWidth,LayoutUnit & maxLogicalWidth)1193 void RenderBlockFlow::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth)
1194 {
1195     float inlineMax = 0;
1196     float inlineMin = 0;
1197 
1198     RenderStyle* styleToUse = style();
1199     RenderBlock* containingBlock = this->containingBlock();
1200     LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit();
1201 
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;
1206 
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();
1211 
1212     bool autoWrap, oldAutoWrap;
1213     autoWrap = oldAutoWrap = styleToUse->autoWrap();
1214 
1215     InlineMinMaxIterator childIterator(this);
1216 
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;
1221 
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();
1229 
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.
1235 
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
1239             // be added in.
1240             //
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.
1245             //
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).
1255             //
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
1258             // mode.
1259             //
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();
1267             float childMin = 0;
1268             float childMax = 0;
1269 
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
1274                     // the element.
1275                     float bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline).toFloat();
1276                     childMin += bpm;
1277                     childMax += bpm;
1278 
1279                     inlineMin += childMin;
1280                     inlineMax += childMax;
1281 
1282                     child->clearPreferredLogicalWidthsDirty();
1283                 } else {
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();
1294                 }
1295             }
1296 
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;
1307                 } else {
1308                     childMinPreferredLogicalWidth = child->minPreferredLogicalWidth();
1309                     childMaxPreferredLogicalWidth = child->maxPreferredLogicalWidth();
1310                 }
1311                 childMin += childMinPreferredLogicalWidth.ceilToFloat();
1312                 childMax += childMaxPreferredLogicalWidth.ceilToFloat();
1313 
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))));
1319                     prevFloat = child;
1320                 } else {
1321                     clearPreviousFloat = false;
1322                 }
1323 
1324                 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
1325                 if ((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat) {
1326                     updatePreferredWidth(minLogicalWidth, inlineMin);
1327                     inlineMin = 0;
1328                 }
1329 
1330                 // If we're supposed to clear the previous float, then terminate maxwidth as well.
1331                 if (clearPreviousFloat) {
1332                     updatePreferredWidth(maxLogicalWidth, inlineMax);
1333                     inlineMax = 0;
1334                 }
1335 
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;
1341 
1342                     if (childMin < 0)
1343                         textIndent = adjustFloatForSubPixelLayout(childMin);
1344                     else
1345                         addedTextIndent = true;
1346                 }
1347 
1348                 // Add our width to the max.
1349                 inlineMax += std::max<float>(0, childMax);
1350 
1351                 if (!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText)) {
1352                     if (child->isFloating())
1353                         updatePreferredWidth(minLogicalWidth, childMin);
1354                     else
1355                         inlineMin += childMin;
1356                 } else {
1357                     // Now check our line.
1358                     updatePreferredWidth(minLogicalWidth, childMin);
1359 
1360                     // Now start a new line.
1361                     inlineMin = 0;
1362                 }
1363 
1364                 if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
1365                     updatePreferredWidth(minLogicalWidth, inlineMin);
1366                     inlineMin = 0;
1367                 }
1368 
1369                 // We are no longer stripping whitespace at the start of
1370                 // a line.
1371                 if (!child->isFloating()) {
1372                     stripFrontSpaces = false;
1373                     trailingSpaceChild = 0;
1374                 }
1375             } else if (child->isText()) {
1376                 // Case (3). Text.
1377                 RenderText* t = toRenderText(child);
1378 
1379                 if (t->isWordBreak()) {
1380                     updatePreferredWidth(minLogicalWidth, inlineMin);
1381                     inlineMin = 0;
1382                     continue;
1383                 }
1384 
1385                 if (t->style()->hasTextCombine() && t->isCombineText())
1386                     toRenderCombineText(t)->combineText();
1387 
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
1392                 // check.
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());
1401 
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);
1406                         inlineMin = 0;
1407                     }
1408                     continue;
1409                 }
1410 
1411                 if (stripFrontSpaces)
1412                     trailingSpaceChild = child;
1413                 else
1414                     trailingSpaceChild = 0;
1415 
1416                 // Add in text-indent. This is added in only once.
1417                 float ti = 0;
1418                 if (!addedTextIndent || hasRemainingNegativeTextIndent) {
1419                     ti = textIndent.ceilToFloat();
1420                     childMin += ti;
1421                     firstLineMinWidth += ti;
1422 
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) {
1427                         childMax += ti;
1428                         firstLineMaxWidth += ti;
1429                         addedTextIndent = true;
1430                     }
1431 
1432                     if (childMin < 0) {
1433                         textIndent = childMin;
1434                         hasRemainingNegativeTextIndent = true;
1435                     }
1436                 }
1437 
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;
1443                 } else {
1444                     if (hasBreakableStart) {
1445                         updatePreferredWidth(minLogicalWidth, inlineMin);
1446                     } else {
1447                         inlineMin += firstLineMinWidth;
1448                         updatePreferredWidth(minLogicalWidth, inlineMin);
1449                         childMin -= ti;
1450                     }
1451 
1452                     inlineMin = childMin;
1453 
1454                     if (hasBreakableEnd) {
1455                         updatePreferredWidth(minLogicalWidth, inlineMin);
1456                         inlineMin = 0;
1457                         shouldBreakLineAfterText = false;
1458                     } else {
1459                         updatePreferredWidth(minLogicalWidth, inlineMin);
1460                         inlineMin = lastLineMinWidth;
1461                         shouldBreakLineAfterText = true;
1462                     }
1463                 }
1464 
1465                 if (hasBreak) {
1466                     inlineMax += firstLineMaxWidth;
1467                     updatePreferredWidth(maxLogicalWidth, inlineMax);
1468                     updatePreferredWidth(maxLogicalWidth, childMax);
1469                     inlineMax = lastLineMaxWidth;
1470                     addedTextIndent = true;
1471                 } else {
1472                     inlineMax += std::max<float>(0, childMax);
1473                 }
1474             }
1475 
1476             // Ignore spaces after a list marker.
1477             if (child->isListMarker())
1478                 stripFrontSpaces = true;
1479         } else {
1480             updatePreferredWidth(minLogicalWidth, inlineMin);
1481             updatePreferredWidth(maxLogicalWidth, inlineMax);
1482             inlineMin = inlineMax = 0;
1483             stripFrontSpaces = true;
1484             trailingSpaceChild = 0;
1485             addedTextIndent = true;
1486         }
1487 
1488         if (!child->isText() && child->isRenderInline())
1489             isPrevChildInlineFlow = true;
1490         else
1491             isPrevChildInlineFlow = false;
1492 
1493         oldAutoWrap = autoWrap;
1494     }
1495 
1496     if (styleToUse->collapseWhiteSpace())
1497         stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
1498 
1499     updatePreferredWidth(minLogicalWidth, inlineMin);
1500     updatePreferredWidth(maxLogicalWidth, inlineMax);
1501 }
1502 
layoutInlineChildren(bool relayoutChildren,LayoutUnit & paintInvalidationLogicalTop,LayoutUnit & paintInvalidationLogicalBottom,LayoutUnit afterEdge)1503 void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& paintInvalidationLogicalTop, LayoutUnit& paintInvalidationLogicalBottom, LayoutUnit afterEdge)
1504 {
1505     RenderFlowThread* flowThread = flowThreadContainingBlock();
1506     bool clearLinesForPagination = firstLineBox() && flowThread && !flowThread->hasRegions();
1507 
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);
1512 
1513     if (isFullLayout) {
1514         // Ensure the old line boxes will be erased.
1515         if (firstLineBox())
1516             setShouldDoFullPaintInvalidation(true);
1517         lineBoxes()->deleteLineBoxes();
1518     }
1519 
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());
1531 
1532     // Walk all the lines and delete our ellipsis line boxes if they exist.
1533     if (hasTextOverflow)
1534          deleteEllipsisLineBoxes();
1535 
1536     if (firstChild()) {
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();
1545 
1546             if (!layoutState.hasInlineChild() && o->isInline())
1547                 layoutState.setHasInlineChild(true);
1548 
1549             if (o->isReplaced() || o->isFloating() || o->isOutOfFlowPositioned()) {
1550                 RenderBox* box = toRenderBox(o);
1551 
1552                 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, box);
1553 
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);
1561                     if (isFullLayout)
1562                         replacedChildren.append(box);
1563                     else
1564                         o->layoutIfNeeded();
1565                 }
1566             } else if (o->isText() || (o->isRenderInline() && !walker.atEndOfInline())) {
1567                 if (!o->isText())
1568                     toRenderInline(o)->updateAlwaysCreateLineBoxes(layoutState.isFullLayout());
1569                 if (layoutState.isFullLayout() || o->selfNeedsLayout())
1570                     dirtyLineBoxesForRenderer(o, layoutState.isFullLayout());
1571                 o->clearNeedsLayout();
1572             }
1573         }
1574 
1575         for (size_t i = 0; i < replacedChildren.size(); i++)
1576             replacedChildren[i]->layoutIfNeeded();
1577 
1578         layoutRunsAndFloats(layoutState);
1579     }
1580 
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);
1587         else
1588             lastLineAnnotationsAdjustment = lastRootBox()->computeOverAnnotationAdjustment(lowestAllowedPosition);
1589     }
1590 
1591     // Now add in the bottom border/padding.
1592     setLogicalHeight(logicalHeight() + lastLineAnnotationsAdjustment + afterEdge);
1593 
1594     if (!firstLineBox() && hasLineIfEmpty())
1595         setLogicalHeight(logicalHeight() + lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
1596 
1597     // See if we have any lines that spill out of our block.  If we do, then we will possibly need to
1598     // truncate text.
1599     if (hasTextOverflow)
1600         checkLinesForTextOverflow();
1601 
1602     // Ensure the new line boxes will be painted.
1603     if (isFullLayout && firstLineBox())
1604         setShouldDoFullPaintInvalidation(true);
1605 }
1606 
checkFloatsInCleanLine(RootInlineBox * line,Vector<FloatWithRect> & floats,size_t & floatIndex,bool & encounteredNewFloat,bool & dirtiedByFloat)1607 void RenderBlockFlow::checkFloatsInCleanLine(RootInlineBox* line, Vector<FloatWithRect>& floats, size_t& floatIndex, bool& encounteredNewFloat, bool& dirtiedByFloat)
1608 {
1609     Vector<RenderBox*>* cleanLineFloats = line->floatsPtr();
1610     if (!cleanLineFloats)
1611         return;
1612 
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;
1620             return;
1621         }
1622 
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);
1628             line->markDirty();
1629             markLinesDirtyInBlockRange(line->lineBottomWithLeading(), floatTop + floatHeight, line);
1630             floats[floatIndex].rect.setSize(newSize);
1631             dirtiedByFloat = true;
1632         }
1633         floatIndex++;
1634     }
1635 }
1636 
determineStartPosition(LineLayoutState & layoutState,InlineBidiResolver & resolver)1637 RootInlineBox* RenderBlockFlow::determineStartPosition(LineLayoutState& layoutState, InlineBidiResolver& resolver)
1638 {
1639     RootInlineBox* curr = 0;
1640     RootInlineBox* last = 0;
1641 
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()) {
1650             if (paginated) {
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();
1657                         break;
1658                     }
1659 
1660                     layoutState.updatePaintInvalidationRangeFromBox(curr, paginationDelta);
1661                     curr->adjustBlockDirectionPosition(paginationDelta.toFloat());
1662                 }
1663             }
1664 
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();
1670 
1671             if (dirtiedByFloat || layoutState.isFullLayout())
1672                 break;
1673         }
1674         // Check if a new float has been inserted after the last known float.
1675         if (!curr && floatIndex < layoutState.floats().size())
1676             layoutState.markForFullLayout();
1677     }
1678 
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);
1684         }
1685 
1686         // FIXME: This should just call deleteLineBoxTree, but that causes
1687         // crashes for fast/repaint tests.
1688         curr = firstRootBox();
1689         while (curr) {
1690             // Note: This uses nextRootBox() insted of nextLineBox() like deleteLineBoxTree does.
1691             RootInlineBox* next = curr->nextRootBox();
1692             curr->deleteLine();
1693             curr = next;
1694         }
1695         ASSERT(!firstLineBox() && !lastLineBox());
1696     } else {
1697         if (curr) {
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.
1704                     curr = prevRootBox;
1705             }
1706         } else {
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();
1711         }
1712 
1713         // If we have no dirty lines, then last is just the last root box.
1714         last = curr ? curr->prevRootBox() : lastRootBox();
1715     }
1716 
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);
1732                     numCleanFloats++;
1733                 }
1734             }
1735             line = line->nextRootBox();
1736         }
1737         setLogicalHeight(savedLogicalHeight);
1738     }
1739     layoutState.setFloatIndex(numCleanFloats);
1740 
1741     layoutState.lineInfo().setFirstLine(!last);
1742     layoutState.lineInfo().setPreviousLineBrokeCleanly(!last || last->endsWithBreak());
1743 
1744     if (last) {
1745         setLogicalHeight(last->lineBottomWithLeading());
1746         InlineIterator iter = InlineIterator(this, last->lineBreakObj(), last->lineBreakPos());
1747         resolver.setPosition(iter, numberOfIsolateAncestors(iter));
1748         resolver.setStatus(last->lineBreakBidiStatus());
1749     } else {
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));
1756     }
1757     return curr;
1758 }
1759 
determineEndPosition(LineLayoutState & layoutState,RootInlineBox * startLine,InlineIterator & cleanLineStart,BidiStatus & cleanLineBidiStatus)1760 void RenderBlockFlow::determineEndPosition(LineLayoutState& layoutState, RootInlineBox* startLine, InlineIterator& cleanLineStart, BidiStatus& cleanLineBidiStatus)
1761 {
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)
1771                 return;
1772         }
1773         if (curr->isDirty())
1774             last = 0;
1775         else if (!last)
1776             last = curr;
1777     }
1778 
1779     if (!last)
1780         return;
1781 
1782     // At this point, |last| is the first line in a run of clean lines that ends with the last line
1783     // in the block.
1784 
1785     RootInlineBox* prev = last->prevRootBox();
1786     cleanLineStart = InlineIterator(this, prev->lineBreakObj(), prev->lineBreakPos());
1787     cleanLineBidiStatus = prev->lineBreakBidiStatus();
1788     layoutState.setEndLineLogicalTop(prev->lineBottomWithLeading());
1789 
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.
1793 
1794     layoutState.setEndLine(last);
1795 }
1796 
checkPaginationAndFloatsAtEndLine(LineLayoutState & layoutState)1797 bool RenderBlockFlow::checkPaginationAndFloatsAtEndLine(LineLayoutState& layoutState)
1798 {
1799     LayoutUnit lineDelta = logicalHeight() - layoutState.endLineLogicalTop();
1800 
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()) {
1806             if (paginated) {
1807                 // This isn't the real move we're going to do, so don't update the line box's pagination
1808                 // strut yet.
1809                 LayoutUnit oldPaginationStrut = lineBox->paginationStrut();
1810                 lineDelta -= oldPaginationStrut;
1811                 adjustLinePositionForPagination(lineBox, lineDelta, layoutState.flowThread());
1812                 lineBox->setPaginationStrut(oldPaginationStrut);
1813             }
1814         }
1815     }
1816 
1817     if (!lineDelta || !m_floatingObjects)
1818         return true;
1819 
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());
1822 
1823     RootInlineBox* lastLine = layoutState.endLine();
1824     while (RootInlineBox* nextLine = lastLine->nextRootBox())
1825         lastLine = nextLine;
1826 
1827     LayoutUnit logicalBottom = lastLine->lineBottomWithLeading() + absoluteValue(lineDelta);
1828 
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)
1834             return false;
1835     }
1836 
1837     return true;
1838 }
1839 
matchedEndLine(LineLayoutState & layoutState,const InlineBidiResolver & resolver,const InlineIterator & endLineStart,const BidiStatus & endLineStatus)1840 bool RenderBlockFlow::matchedEndLine(LineLayoutState& layoutState, const InlineBidiResolver& resolver, const InlineIterator& endLineStart, const BidiStatus& endLineStatus)
1841 {
1842     if (resolver.position() == endLineStart) {
1843         if (resolver.status() != endLineStatus)
1844             return false;
1845         return checkPaginationAndFloatsAtEndLine(layoutState);
1846     }
1847 
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()) {
1855             // We have a match.
1856             if (line->lineBreakBidiStatus() != resolver.status())
1857                 return false; // ...but the bidi state doesn't match.
1858 
1859             bool matched = false;
1860             RootInlineBox* result = line->nextRootBox();
1861             layoutState.setEndLine(result);
1862             if (result) {
1863                 layoutState.setEndLineLogicalTop(line->lineBottomWithLeading());
1864                 matched = checkPaginationAndFloatsAtEndLine(layoutState);
1865             }
1866 
1867             // Now delete the lines that we failed to sync.
1868             deleteLineRange(layoutState, originalEndLine, result);
1869             return matched;
1870         }
1871     }
1872 
1873     return false;
1874 }
1875 
generatesLineBoxesForInlineChild(RenderObject * inlineObj)1876 bool RenderBlockFlow::generatesLineBoxesForInlineChild(RenderObject* inlineObj)
1877 
1878 {
1879     ASSERT(inlineObj->parent() == this);
1880 
1881     InlineIterator it(this, inlineObj, 0);
1882     // FIXME: We should pass correct value for WhitespacePosition.
1883     while (!it.atEnd() && !requiresLineBox(it))
1884         it.increment();
1885 
1886     return !it.atEnd();
1887 }
1888 
1889 
addOverflowFromInlineChildren()1890 void RenderBlockFlow::addOverflowFromInlineChildren()
1891 {
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())
1895         endPadding = 1;
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);
1900     }
1901 }
1902 
deleteEllipsisLineBoxes()1903 void RenderBlockFlow::deleteEllipsisLineBoxes()
1904 {
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();
1911 
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);
1917 
1918             if (ltr)
1919                 curr->adjustLogicalPosition((logicalLeft - curr->logicalLeft()), 0);
1920             else
1921                 curr->adjustLogicalPosition(-(curr->logicalLeft() - logicalLeft), 0);
1922         }
1923         firstLine = false;
1924     }
1925 }
1926 
checkLinesForTextOverflow()1927 void RenderBlockFlow::checkLinesForTextOverflow()
1928 {
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));
1938 
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
1955             // space.
1956 
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());
1961 
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);
1965                 if (ltr)
1966                     curr->adjustLogicalPosition(logicalLeft, 0);
1967                 else
1968                     curr->adjustLogicalPosition(logicalLeft - (availableLogicalWidth - totalLogicalWidth), 0);
1969             }
1970         }
1971         firstLine = false;
1972     }
1973 }
1974 
positionNewFloatOnLine(FloatingObject * newFloat,FloatingObject * lastFloatFromPreviousLine,LineInfo & lineInfo,LineWidth & width)1975 bool RenderBlockFlow::positionNewFloatOnLine(FloatingObject* newFloat, FloatingObject* lastFloatFromPreviousLine, LineInfo& lineInfo, LineWidth& width)
1976 {
1977     if (!positionNewFloats())
1978         return false;
1979 
1980     width.shrinkAvailableWidthForNewFloatIfNeeded(newFloat);
1981 
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())
1986         return true;
1987 
1988     const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1989     ASSERT(floatingObjectSet.last() == newFloat);
1990 
1991     LayoutUnit floatLogicalTop = logicalTopForFloat(newFloat);
1992     int paginationStrut = newFloat->paginationStrut();
1993 
1994     if (floatLogicalTop - paginationStrut != logicalHeight() + lineInfo.floatPaginationStrut())
1995         return true;
1996 
1997     FloatingObjectSetIterator it = floatingObjectSet.end();
1998     --it; // Last float is newFloat, skip that one.
1999     FloatingObjectSetIterator begin = floatingObjectSet.begin();
2000     while (it != begin) {
2001         --it;
2002         FloatingObject* floatingObject = it->get();
2003         if (floatingObject == lastFloatFromPreviousLine)
2004             break;
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();
2011             else
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);
2019         }
2020     }
2021 
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);
2025     return true;
2026 }
2027 
startAlignedOffsetForLine(LayoutUnit position,bool firstLine)2028 LayoutUnit RenderBlockFlow::startAlignedOffsetForLine(LayoutUnit position, bool firstLine)
2029 {
2030     ETextAlign textAlign = style()->textAlign();
2031 
2032     if (textAlign == TASTART) // FIXME: Handle TAEND here
2033         return startOffsetForLine(position, firstLine);
2034 
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);
2040 
2041     if (!style()->isLeftToRightDirection())
2042         return logicalWidth() - logicalLeft;
2043     return logicalLeft;
2044 }
2045 
2046 }
2047