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