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