Remove an unnecessary extra computeLogicalWidth() from line layout
[WebKit-https.git] / Source / WebCore / rendering / RenderBlockLineLayout.cpp
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 "BidiResolver.h"
26 #include "Hyphenation.h"
27 #include "InlineIterator.h"
28 #include "InlineTextBox.h"
29 #include "Logging.h"
30 #include "RenderArena.h"
31 #include "RenderCombineText.h"
32 #include "RenderInline.h"
33 #include "RenderLayer.h"
34 #include "RenderListMarker.h"
35 #include "RenderView.h"
36 #include "Settings.h"
37 #include "TextBreakIterator.h"
38 #include "TextRun.h"
39 #include "TrailingFloatsRootInlineBox.h"
40 #include "VerticalPositionCache.h"
41 #include "break_lines.h"
42 #include <wtf/AlwaysInline.h>
43 #include <wtf/RefCountedLeakCounter.h>
44 #include <wtf/StdLibExtras.h>
45 #include <wtf/Vector.h>
46 #include <wtf/unicode/CharacterNames.h>
47
48 #if ENABLE(SVG)
49 #include "RenderSVGInlineText.h"
50 #include "SVGRootInlineBox.h"
51 #endif
52
53 using namespace std;
54 using namespace WTF;
55 using namespace Unicode;
56
57 namespace WebCore {
58
59 // We don't let our line box tree for a single line get any deeper than this.
60 const unsigned cMaxLineDepth = 200;
61
62 static int getBorderPaddingMargin(RenderBoxModelObject* child, bool endOfInline)
63 {
64     if (endOfInline)
65         return child->marginEnd() + child->paddingEnd() + child->borderEnd();
66     return child->marginStart() + child->paddingStart() + child->borderStart();
67 }
68
69 static int inlineLogicalWidth(RenderObject* child, bool start = true, bool end = true)
70 {
71     unsigned lineDepth = 1;
72     int extraWidth = 0;
73     RenderObject* parent = child->parent();
74     while (parent->isInline() && !parent->isInlineBlockOrInlineTable() && lineDepth++ < cMaxLineDepth) {
75         if (start && !child->previousSibling())
76             extraWidth += getBorderPaddingMargin(toRenderBoxModelObject(parent), false);
77         if (end && !child->nextSibling())
78             extraWidth += getBorderPaddingMargin(toRenderBoxModelObject(parent), true);
79         child = parent;
80         parent = child->parent();
81     }
82     return extraWidth;
83 }
84
85 static void checkMidpoints(LineMidpointState& lineMidpointState, InlineIterator& lBreak)
86 {
87     // Check to see if our last midpoint is a start point beyond the line break.  If so,
88     // shave it off the list, and shave off a trailing space if the previous end point doesn't
89     // preserve whitespace.
90     if (lBreak.m_obj && lineMidpointState.numMidpoints && !(lineMidpointState.numMidpoints % 2)) {
91         InlineIterator* midpoints = lineMidpointState.midpoints.data();
92         InlineIterator& endpoint = midpoints[lineMidpointState.numMidpoints - 2];
93         const InlineIterator& startpoint = midpoints[lineMidpointState.numMidpoints - 1];
94         InlineIterator currpoint = endpoint;
95         while (!currpoint.atEnd() && currpoint != startpoint && currpoint != lBreak)
96             currpoint.increment();
97         if (currpoint == lBreak) {
98             // We hit the line break before the start point.  Shave off the start point.
99             lineMidpointState.numMidpoints--;
100             if (endpoint.m_obj->style()->collapseWhiteSpace())
101                 endpoint.m_pos--;
102         }
103     }    
104 }
105
106 static void addMidpoint(LineMidpointState& lineMidpointState, const InlineIterator& midpoint)
107 {
108     if (lineMidpointState.midpoints.size() <= lineMidpointState.numMidpoints)
109         lineMidpointState.midpoints.grow(lineMidpointState.numMidpoints + 10);
110
111     InlineIterator* midpoints = lineMidpointState.midpoints.data();
112     midpoints[lineMidpointState.numMidpoints++] = midpoint;
113 }
114
115 void RenderBlock::appendRunsForObject(int start, int end, RenderObject* obj, InlineBidiResolver& resolver)
116 {
117     if (start > end || obj->isFloating() ||
118         (obj->isPositioned() && !obj->style()->hasAutoLeftAndRight() && !obj->style()->hasAutoTopAndBottom() && !obj->container()->isRenderInline()))
119         return;
120
121     LineMidpointState& lineMidpointState = resolver.midpointState();
122     bool haveNextMidpoint = (lineMidpointState.currentMidpoint < lineMidpointState.numMidpoints);
123     InlineIterator nextMidpoint;
124     if (haveNextMidpoint)
125         nextMidpoint = lineMidpointState.midpoints[lineMidpointState.currentMidpoint];
126     if (lineMidpointState.betweenMidpoints) {
127         if (!(haveNextMidpoint && nextMidpoint.m_obj == obj))
128             return;
129         // This is a new start point. Stop ignoring objects and 
130         // adjust our start.
131         lineMidpointState.betweenMidpoints = false;
132         start = nextMidpoint.m_pos;
133         lineMidpointState.currentMidpoint++;
134         if (start < end)
135             return appendRunsForObject(start, end, obj, resolver);
136     } else {
137         if (!haveNextMidpoint || (obj != nextMidpoint.m_obj)) {
138             resolver.addRun(new (obj->renderArena()) BidiRun(start, end, obj, resolver.context(), resolver.dir()));
139             return;
140         }
141
142         // An end midpoint has been encountered within our object.  We
143         // need to go ahead and append a run with our endpoint.
144         if (static_cast<int>(nextMidpoint.m_pos + 1) <= end) {
145             lineMidpointState.betweenMidpoints = true;
146             lineMidpointState.currentMidpoint++;
147             if (nextMidpoint.m_pos != UINT_MAX) { // UINT_MAX means stop at the object and don't include any of it.
148                 if (static_cast<int>(nextMidpoint.m_pos + 1) > start)
149                     resolver.addRun(new (obj->renderArena())
150                         BidiRun(start, nextMidpoint.m_pos + 1, obj, resolver.context(), resolver.dir()));
151                 return appendRunsForObject(nextMidpoint.m_pos + 1, end, obj, resolver);
152             }
153         } else
154            resolver.addRun(new (obj->renderArena()) BidiRun(start, end, obj, resolver.context(), resolver.dir()));
155     }
156 }
157
158 static inline InlineBox* createInlineBoxForRenderer(RenderObject* obj, bool isRootLineBox, bool isOnlyRun = false)
159 {
160     if (isRootLineBox)
161         return toRenderBlock(obj)->createAndAppendRootInlineBox();
162     
163     if (obj->isText()) {
164         InlineTextBox* textBox = toRenderText(obj)->createInlineTextBox();
165         // We only treat a box as text for a <br> if we are on a line by ourself or in strict mode
166         // (Note the use of strict mode.  In "almost strict" mode, we don't treat the box for <br> as text.)
167         if (obj->isBR())
168             textBox->setIsText(isOnlyRun || obj->document()->inNoQuirksMode());
169         return textBox;
170     }
171     
172     if (obj->isBox())
173         return toRenderBox(obj)->createInlineBox();
174     
175     return toRenderInline(obj)->createAndAppendInlineFlowBox();
176 }
177
178 static inline void dirtyLineBoxesForRenderer(RenderObject* o, bool fullLayout)
179 {
180     if (o->isText()) {
181         if (o->preferredLogicalWidthsDirty() && (o->isCounter() || o->isQuote()))
182             toRenderText(o)->computePreferredLogicalWidths(0); // FIXME: Counters depend on this hack. No clue why. Should be investigated and removed.
183         toRenderText(o)->dirtyLineBoxes(fullLayout);
184     } else
185         toRenderInline(o)->dirtyLineBoxes(fullLayout);
186 }
187
188 static bool parentIsConstructedOrHaveNext(InlineFlowBox* parentBox)
189 {
190     do {
191         if (parentBox->isConstructed() || parentBox->nextOnLine())
192             return true;
193         parentBox = parentBox->parent();
194     } while (parentBox);
195     return false;
196 }
197
198 InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, bool firstLine, InlineBox* childBox)
199 {
200     // See if we have an unconstructed line box for this object that is also
201     // the last item on the line.
202     unsigned lineDepth = 1;
203     InlineFlowBox* parentBox = 0;
204     InlineFlowBox* result = 0;
205     bool hasDefaultLineBoxContain = style()->lineBoxContain() == RenderStyle::initialLineBoxContain();
206     do {
207         ASSERT(obj->isRenderInline() || obj == this);
208         
209         // Get the last box we made for this render object.
210         parentBox = obj->isRenderInline() ? toRenderInline(obj)->lastLineBox() : toRenderBlock(obj)->lastLineBox();
211
212         // If this box or its ancestor is constructed then it is from a previous line, and we need
213         // to make a new box for our line.  If this box or its ancestor is unconstructed but it has
214         // something following it on the line, then we know we have to make a new box
215         // as well.  In this situation our inline has actually been split in two on
216         // the same line (this can happen with very fancy language mixtures).
217         bool constructedNewBox = false;
218         if (!parentBox || parentIsConstructedOrHaveNext(parentBox)) {
219             // We need to make a new box for this render object.  Once
220             // made, we need to place it at the end of the current line.
221             InlineBox* newBox = createInlineBoxForRenderer(obj, obj == this);
222             ASSERT(newBox->isInlineFlowBox());
223             parentBox = static_cast<InlineFlowBox*>(newBox);
224             parentBox->setFirstLineStyleBit(firstLine);
225             parentBox->setIsHorizontal(isHorizontalWritingMode());
226             if (!hasDefaultLineBoxContain)
227                 parentBox->clearDescendantsHaveSameLineHeightAndBaseline();
228             constructedNewBox = true;
229         }
230
231         if (!result)
232             result = parentBox;
233
234         // If we have hit the block itself, then |box| represents the root
235         // inline box for the line, and it doesn't have to be appended to any parent
236         // inline.
237         if (childBox)
238             parentBox->addToLine(childBox);
239
240         if (!constructedNewBox || obj == this)
241             break;
242
243         childBox = parentBox;        
244
245         // If we've exceeded our line depth, then jump straight to the root and skip all the remaining
246         // intermediate inline flows.
247         obj = (++lineDepth >= cMaxLineDepth) ? this : obj->parent();
248
249     } while (true);
250
251     return result;
252 }
253
254 RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun, BidiRun* lastRun, bool firstLine, bool lastLine, RenderObject* endObject, RenderObject* logicallyLastRunRenderer)
255 {
256     ASSERT(firstRun);
257
258     bool rootHasSelectedChildren = false;
259     InlineFlowBox* parentBox = 0;
260     for (BidiRun* r = firstRun; r; r = r->next()) {
261         // Create a box for our object.
262         bool isOnlyRun = (runCount == 1);
263         if (runCount == 2 && !r->m_object->isListMarker())
264             isOnlyRun = (!style()->isLeftToRightDirection() ? lastRun : firstRun)->m_object->isListMarker();
265
266         InlineBox* box = createInlineBoxForRenderer(r->m_object, false, isOnlyRun);
267         r->m_box = box;
268
269         ASSERT(box);
270         if (!box)
271             continue;
272
273         if (!rootHasSelectedChildren && box->renderer()->selectionState() != RenderObject::SelectionNone)
274             rootHasSelectedChildren = true;
275
276         // If we have no parent box yet, or if the run is not simply a sibling,
277         // then we need to construct inline boxes as necessary to properly enclose the
278         // run's inline box.
279         if (!parentBox || parentBox->renderer() != r->m_object->parent())
280             // Create new inline boxes all the way back to the appropriate insertion point.
281             parentBox = createLineBoxes(r->m_object->parent(), firstLine, box);
282         else {
283             // Append the inline box to this line.
284             parentBox->addToLine(box);
285         }
286
287         bool visuallyOrdered = r->m_object->style()->visuallyOrdered();
288         box->setBidiLevel(r->level());
289
290         if (box->isInlineTextBox()) {
291             InlineTextBox* text = static_cast<InlineTextBox*>(box);
292             text->setStart(r->m_start);
293             text->setLen(r->m_stop - r->m_start);
294             text->m_dirOverride = r->dirOverride(visuallyOrdered);
295             if (r->m_hasHyphen)
296                 text->setHasHyphen(true);
297         }
298     }
299
300     // We should have a root inline box.  It should be unconstructed and
301     // be the last continuation of our line list.
302     ASSERT(lastLineBox() && !lastLineBox()->isConstructed());
303
304     // Set the m_selectedChildren flag on the root inline box if one of the leaf inline box
305     // from the bidi runs walk above has a selection state.
306     if (rootHasSelectedChildren)
307         lastLineBox()->root()->setHasSelectedChildren(true);
308
309     // Set bits on our inline flow boxes that indicate which sides should
310     // paint borders/margins/padding.  This knowledge will ultimately be used when
311     // we determine the horizontal positions and widths of all the inline boxes on
312     // the line.
313     lastLineBox()->determineSpacingForFlowBoxes(lastLine, endObject, logicallyLastRunRenderer);
314
315     // Now mark the line boxes as being constructed.
316     lastLineBox()->setConstructed();
317
318     // Return the last line.
319     return lastRootBox();
320 }
321
322 ETextAlign RenderBlock::textAlignmentForLine(bool endsWithSoftBreak) const
323 {
324     ETextAlign alignment = style()->textAlign();
325     if (!endsWithSoftBreak && alignment == JUSTIFY)
326         alignment = TAAUTO;
327
328     return alignment;
329 }
330
331 static void updateLogicalWidthForLeftAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
332 {
333     // The direction of the block should determine what happens with wide lines.
334     // In particular with RTL blocks, wide lines should still spill out to the left.
335     if (isLeftToRightDirection) {
336         if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun)
337             trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
338         return;
339     }
340
341     if (trailingSpaceRun)
342         trailingSpaceRun->m_box->setLogicalWidth(0);
343     else if (totalLogicalWidth > availableLogicalWidth)
344         logicalLeft -= (totalLogicalWidth - availableLogicalWidth);
345 }
346
347 static void updateLogicalWidthForRightAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
348 {
349     // Wide lines spill out of the block based off direction.
350     // So even if text-align is right, if direction is LTR, wide lines should overflow out of the right
351     // side of the block.
352     if (isLeftToRightDirection) {
353         if (trailingSpaceRun) {
354             totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
355             trailingSpaceRun->m_box->setLogicalWidth(0);
356         }
357         if (totalLogicalWidth < availableLogicalWidth)
358             logicalLeft += availableLogicalWidth - totalLogicalWidth;
359         return;
360     }
361
362     if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun) {
363         trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
364         totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
365     } else
366         logicalLeft += availableLogicalWidth - totalLogicalWidth;
367 }
368
369 static void updateLogicalWidthForCenterAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
370 {
371     float trailingSpaceWidth = 0;
372     if (trailingSpaceRun) {
373         totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
374         trailingSpaceWidth = min(trailingSpaceRun->m_box->logicalWidth(), (availableLogicalWidth - totalLogicalWidth + 1) / 2);
375         trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceWidth));
376     }
377     if (isLeftToRightDirection)
378         logicalLeft += max<float>((availableLogicalWidth - totalLogicalWidth) / 2, 0);
379     else
380         logicalLeft += totalLogicalWidth > availableLogicalWidth ? (availableLogicalWidth - totalLogicalWidth) : (availableLogicalWidth - totalLogicalWidth) / 2 - trailingSpaceWidth;
381 }
382
383 void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, bool firstLine, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd,
384                                                          GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache)
385 {
386     ETextAlign textAlign = textAlignmentForLine(!reachedEnd && !lineBox->endsWithBreak());
387     float logicalLeft = logicalLeftOffsetForLine(logicalHeight(), firstLine);
388     float availableLogicalWidth = logicalRightOffsetForLine(logicalHeight(), firstLine) - logicalLeft;
389
390     bool needsWordSpacing = false;
391     float totalLogicalWidth = lineBox->getFlowSpacingLogicalWidth();
392     unsigned expansionOpportunityCount = 0;
393     bool isAfterExpansion = true;
394     Vector<unsigned, 16> expansionOpportunities;
395
396     for (BidiRun* r = firstRun; r; r = r->next()) {
397         if (!r->m_box || r->m_object->isPositioned() || r->m_box->isLineBreak())
398             continue; // Positioned objects are only participating to figure out their
399                       // correct static x position.  They have no effect on the width.
400                       // Similarly, line break boxes have no effect on the width.
401         if (r->m_object->isText()) {
402             RenderText* rt = toRenderText(r->m_object);
403
404             if (textAlign == JUSTIFY && r != trailingSpaceRun) {
405                 if (!isAfterExpansion)
406                     static_cast<InlineTextBox*>(r->m_box)->setCanHaveLeadingExpansion(true);
407                 unsigned opportunitiesInRun = Font::expansionOpportunityCount(rt->characters() + r->m_start, r->m_stop - r->m_start, r->m_box->direction(), isAfterExpansion);
408                 expansionOpportunities.append(opportunitiesInRun);
409                 expansionOpportunityCount += opportunitiesInRun;
410             }
411
412             if (int length = rt->textLength()) {
413                 if (!r->m_start && needsWordSpacing && isSpaceOrNewline(rt->characters()[r->m_start]))
414                     totalLogicalWidth += rt->style(firstLine)->font().wordSpacing();
415                 needsWordSpacing = !isSpaceOrNewline(rt->characters()[r->m_stop - 1]) && r->m_stop == length;          
416             }
417             HashSet<const SimpleFontData*> fallbackFonts;
418             GlyphOverflow glyphOverflow;
419             
420             // Always compute glyph overflow if the block's line-box-contain value is "glyphs".
421             if (lineBox->fitsToGlyphs()) {
422                 // If we don't stick out of the root line's font box, then don't bother computing our glyph overflow. This optimization
423                 // will keep us from computing glyph bounds in nearly all cases.
424                 bool includeRootLine = lineBox->includesRootLineBoxFontOrLeading();
425                 int baselineShift = lineBox->verticalPositionForBox(r->m_box, verticalPositionCache);
426                 int rootDescent = includeRootLine ? lineBox->renderer()->style(firstLine)->font().fontMetrics().descent() : 0;
427                 int rootAscent = includeRootLine ? lineBox->renderer()->style(firstLine)->font().fontMetrics().ascent() : 0;
428                 int boxAscent = rt->style(firstLine)->font().fontMetrics().ascent() - baselineShift;
429                 int boxDescent = rt->style(firstLine)->font().fontMetrics().descent() + baselineShift;
430                 if (boxAscent > rootDescent ||  boxDescent > rootAscent)
431                     glyphOverflow.computeBounds = true; 
432             }
433
434             int hyphenWidth = 0;
435             if (static_cast<InlineTextBox*>(r->m_box)->hasHyphen()) {
436                 const AtomicString& hyphenString = rt->style()->hyphenString();
437                 hyphenWidth = rt->style(firstLine)->font().width(TextRun(hyphenString.characters(), hyphenString.length()));
438             }
439             r->m_box->setLogicalWidth(rt->width(r->m_start, r->m_stop - r->m_start, totalLogicalWidth, firstLine, &fallbackFonts, &glyphOverflow) + hyphenWidth);
440             if (!fallbackFonts.isEmpty()) {
441                 ASSERT(r->m_box->isText());
442                 GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(static_cast<InlineTextBox*>(r->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).first;
443                 ASSERT(it->second.first.isEmpty());
444                 copyToVector(fallbackFonts, it->second.first);
445                 r->m_box->parent()->clearDescendantsHaveSameLineHeightAndBaseline();
446             }
447             if ((glyphOverflow.top || glyphOverflow.bottom || glyphOverflow.left || glyphOverflow.right)) {
448                 ASSERT(r->m_box->isText());
449                 GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(static_cast<InlineTextBox*>(r->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).first;
450                 it->second.second = glyphOverflow;
451                 r->m_box->clearKnownToHaveNoOverflow();
452             }
453         } else {
454             isAfterExpansion = false;
455             if (!r->m_object->isRenderInline()) {
456                 RenderBox* renderBox = toRenderBox(r->m_object);
457                 r->m_box->setLogicalWidth(logicalWidthForChild(renderBox));
458                 totalLogicalWidth += marginStartForChild(renderBox) + marginEndForChild(renderBox);
459             }
460         }
461
462         totalLogicalWidth += r->m_box->logicalWidth();
463     }
464
465     if (isAfterExpansion && !expansionOpportunities.isEmpty()) {
466         expansionOpportunities.last()--;
467         expansionOpportunityCount--;
468     }
469
470     // Armed with the total width of the line (without justification),
471     // we now examine our text-align property in order to determine where to position the
472     // objects horizontally.  The total width of the line can be increased if we end up
473     // justifying text.
474     switch (textAlign) {
475         case LEFT:
476         case WEBKIT_LEFT:
477             updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
478             break;
479         case JUSTIFY:
480             adjustInlineDirectionLineBounds(expansionOpportunityCount, logicalLeft, availableLogicalWidth);
481             if (expansionOpportunityCount) {
482                 if (trailingSpaceRun) {
483                     totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
484                     trailingSpaceRun->m_box->setLogicalWidth(0);
485                 }
486                 break;
487             }
488             // fall through
489         case TAAUTO:
490             // for right to left fall through to right aligned
491             if (style()->isLeftToRightDirection()) {
492                 if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun)
493                     trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
494                 break;
495             }
496         case RIGHT:
497         case WEBKIT_RIGHT:
498             updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
499             break;
500         case CENTER:
501         case WEBKIT_CENTER:
502             updateLogicalWidthForCenterAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
503             break;
504         case TASTART:
505             if (style()->isLeftToRightDirection())
506                 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
507             else
508                 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
509             break;
510         case TAEND:
511             if (style()->isLeftToRightDirection())
512                 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
513             else
514                 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
515             break;
516     }
517
518     if (expansionOpportunityCount && availableLogicalWidth > totalLogicalWidth) {
519         size_t i = 0;
520         for (BidiRun* r = firstRun; r; r = r->next()) {
521             if (!r->m_box || r == trailingSpaceRun)
522                 continue;
523
524             if (r->m_object->isText()) {
525                 unsigned opportunitiesInRun = expansionOpportunities[i++];
526
527                 ASSERT(opportunitiesInRun <= expansionOpportunityCount);
528
529                 // Only justify text if whitespace is collapsed.
530                 if (r->m_object->style()->collapseWhiteSpace()) {
531                     InlineTextBox* textBox = static_cast<InlineTextBox*>(r->m_box);
532                     float expansion = (availableLogicalWidth - totalLogicalWidth) * opportunitiesInRun / expansionOpportunityCount;
533                     textBox->setExpansion(expansion);
534                     totalLogicalWidth += expansion;
535                 }
536                 expansionOpportunityCount -= opportunitiesInRun;
537                 if (!expansionOpportunityCount)
538                     break;
539             }
540         }
541     }
542
543     // The widths of all runs are now known.  We can now place every inline box (and
544     // compute accurate widths for the inline flow boxes).
545     needsWordSpacing = false;
546     lineBox->placeBoxesInInlineDirection(logicalLeft, needsWordSpacing, textBoxDataMap);
547 }
548
549 void RenderBlock::computeBlockDirectionPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap,
550                                                         VerticalPositionCache& verticalPositionCache)
551 {
552     setLogicalHeight(lineBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache));
553     lineBox->setBlockLogicalHeight(logicalHeight());
554
555     // Now make sure we place replaced render objects correctly.
556     for (BidiRun* r = firstRun; r; r = r->next()) {
557         ASSERT(r->m_box);
558         if (!r->m_box)
559             continue; // Skip runs with no line boxes.
560
561         // Align positioned boxes with the top of the line box.  This is
562         // a reasonable approximation of an appropriate y position.
563         if (r->m_object->isPositioned())
564             r->m_box->setLogicalTop(logicalHeight());
565
566         // Position is used to properly position both replaced elements and
567         // to update the static normal flow x/y of positioned elements.
568         if (r->m_object->isText())
569             toRenderText(r->m_object)->positionLineBox(r->m_box);
570         else if (r->m_object->isBox())
571             toRenderBox(r->m_object)->positionLineBox(r->m_box);
572     }
573     // Positioned objects and zero-length text nodes destroy their boxes in
574     // position(), which unnecessarily dirties the line.
575     lineBox->markDirty(false);
576 }
577
578 static inline bool isCollapsibleSpace(UChar character, RenderText* renderer)
579 {
580     if (character == ' ' || character == '\t' || character == softHyphen)
581         return true;
582     if (character == '\n')
583         return !renderer->style()->preserveNewline();
584     if (character == noBreakSpace)
585         return renderer->style()->nbspMode() == SPACE;
586     return false;
587 }
588
589
590 static void setStaticPositions(RenderBlock* block, RenderBox* child)
591 {
592     // FIXME: The math here is actually not really right. It's a best-guess approximation that
593     // will work for the common cases
594     RenderObject* containerBlock = child->container();
595     int blockHeight = block->logicalHeight();
596     if (containerBlock->isRenderInline()) {
597         // A relative positioned inline encloses us. In this case, we also have to determine our
598         // position as though we were an inline. Set |staticInlinePosition| and |staticBlockPosition| on the relative positioned
599         // inline so that we can obtain the value later.
600         toRenderInline(containerBlock)->layer()->setStaticInlinePosition(block->startOffsetForLine(blockHeight, false));
601         toRenderInline(containerBlock)->layer()->setStaticBlockPosition(blockHeight);
602     }
603
604     if (child->style()->isOriginalDisplayInlineType())
605         child->layer()->setStaticInlinePosition(block->startOffsetForLine(blockHeight, false));
606     else
607         child->layer()->setStaticInlinePosition(block->borderAndPaddingStart());
608     child->layer()->setStaticBlockPosition(blockHeight);
609 }
610
611 static bool reachedEndOfTextRenderer(InlineBidiResolver& resolver)
612 {
613     BidiRun* run = resolver.logicallyLastRun();
614     if (!run)
615         return true;
616     unsigned int pos = run->stop();
617     RenderObject* r = run->m_object;
618     if (!r->isText() || r->isBR())
619         return false;
620     RenderText* renderText = toRenderText(r);
621     if (pos >= renderText->textLength())
622         return true;
623
624     while (isASCIISpace(renderText->characters()[pos])) {
625         pos++;
626         if (pos >= renderText->textLength())
627             return true;
628     }
629     return false;
630 }
631     
632 void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogicalTop, int& repaintLogicalBottom)
633 {
634     bool useRepaintBounds = false;
635     
636     m_overflow.clear();
637         
638     setLogicalHeight(borderBefore() + paddingBefore());
639
640     // Figure out if we should clear out our line boxes.
641     // FIXME: Handle resize eventually!
642     bool fullLayout = !firstLineBox() || selfNeedsLayout() || relayoutChildren;
643     if (fullLayout)
644         lineBoxes()->deleteLineBoxes(renderArena());
645
646     // Text truncation only kicks in if your overflow isn't visible and your text-overflow-mode isn't
647     // clip.
648     // FIXME: CSS3 says that descendants that are clipped must also know how to truncate.  This is insanely
649     // difficult to figure out (especially in the middle of doing layout), and is really an esoteric pile of nonsense
650     // anyway, so we won't worry about following the draft here.
651     bool hasTextOverflow = style()->textOverflow() && hasOverflowClip();
652
653     // Walk all the lines and delete our ellipsis line boxes if they exist.
654     if (hasTextOverflow)
655          deleteEllipsisLineBoxes();
656
657     if (firstChild()) {
658         // layout replaced elements
659         bool endOfInline = false;
660         RenderObject* o = bidiFirst(this, 0, false);
661         Vector<FloatWithRect> floats;
662         bool hasInlineChild = false;
663         while (o) {
664             if (!hasInlineChild && o->isInline())
665                 hasInlineChild = true;
666
667             if (o->isReplaced() || o->isFloating() || o->isPositioned()) {
668                 RenderBox* box = toRenderBox(o);
669                 
670                 if (relayoutChildren || o->style()->width().isPercent() || o->style()->height().isPercent())
671                     o->setChildNeedsLayout(true, false);
672                     
673                 // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths.
674                 if (relayoutChildren && (o->style()->paddingStart().isPercent() || o->style()->paddingEnd().isPercent()))
675                     o->setPreferredLogicalWidthsDirty(true, false);
676             
677                 if (o->isPositioned())
678                     o->containingBlock()->insertPositionedObject(box);
679                 else if (o->isFloating())
680                     floats.append(FloatWithRect(box));
681                 else if (fullLayout || o->needsLayout()) {
682                     // Replaced elements
683                     toRenderBox(o)->dirtyLineBoxes(fullLayout);
684                     o->layoutIfNeeded();
685                 }
686             } else if (o->isText() || (o->isRenderInline() && !endOfInline)) {
687                 if (fullLayout || o->selfNeedsLayout())
688                     dirtyLineBoxesForRenderer(o, fullLayout);
689                 o->setNeedsLayout(false);
690             }
691             o = bidiNext(this, o, 0, false, &endOfInline);
692         }
693
694         // We want to skip ahead to the first dirty line
695         InlineBidiResolver resolver;
696         unsigned floatIndex;
697         bool firstLine = true;
698         bool previousLineBrokeCleanly = true;
699         RootInlineBox* startLine = determineStartPosition(firstLine, fullLayout, previousLineBrokeCleanly, resolver, floats, floatIndex,
700                                                           useRepaintBounds, repaintLogicalTop, repaintLogicalBottom);
701
702         if (fullLayout && hasInlineChild && !selfNeedsLayout()) {
703             setNeedsLayout(true, false);  // Mark ourselves as needing a full layout. This way we'll repaint like
704                                           // we're supposed to.
705             RenderView* v = view();
706             if (v && !v->doingFullRepaint() && hasLayer()) {
707                 // Because we waited until we were already inside layout to discover
708                 // that the block really needed a full layout, we missed our chance to repaint the layer
709                 // before layout started.  Luckily the layer has cached the repaint rect for its original
710                 // position and size, and so we can use that to make a repaint happen now.
711                 repaintUsingContainer(containerForRepaint(), layer()->repaintRect());
712             }
713         }
714
715         FloatingObject* lastFloat = (m_floatingObjects && !m_floatingObjects->set().isEmpty()) ? m_floatingObjects->set().last() : 0;
716
717         LineMidpointState& lineMidpointState = resolver.midpointState();
718
719         // We also find the first clean line and extract these lines.  We will add them back
720         // if we determine that we're able to synchronize after handling all our dirty lines.
721         InlineIterator cleanLineStart;
722         BidiStatus cleanLineBidiStatus;
723         int endLineLogicalTop = 0;
724         RootInlineBox* endLine = (fullLayout || !startLine) ? 
725                                  0 : determineEndPosition(startLine, floats, floatIndex, cleanLineStart, cleanLineBidiStatus, endLineLogicalTop);
726
727         if (startLine) {
728             if (!useRepaintBounds) {
729                 useRepaintBounds = true;
730                 repaintLogicalTop = logicalHeight();
731                 repaintLogicalBottom = logicalHeight();
732             }
733             RenderArena* arena = renderArena();
734             RootInlineBox* box = startLine;
735             while (box) {
736                 repaintLogicalTop = min(repaintLogicalTop, box->logicalTopVisualOverflow());
737                 repaintLogicalBottom = max(repaintLogicalBottom, box->logicalBottomVisualOverflow());
738                 RootInlineBox* next = box->nextRootBox();
739                 box->deleteLine(arena);
740                 box = next;
741             }
742         }
743
744         InlineIterator end = resolver.position();
745
746         if (!fullLayout && lastRootBox() && lastRootBox()->endsWithBreak()) {
747             // If the last line before the start line ends with a line break that clear floats,
748             // adjust the height accordingly.
749             // A line break can be either the first or the last object on a line, depending on its direction.
750             if (InlineBox* lastLeafChild = lastRootBox()->lastLeafChild()) {
751                 RenderObject* lastObject = lastLeafChild->renderer();
752                 if (!lastObject->isBR())
753                     lastObject = lastRootBox()->firstLeafChild()->renderer();
754                 if (lastObject->isBR()) {
755                     EClear clear = lastObject->style()->clear();
756                     if (clear != CNONE)
757                         newLine(clear);
758                 }
759             }
760         }
761
762         bool endLineMatched = false;
763         bool checkForEndLineMatch = endLine;
764         bool checkForFloatsFromLastLine = false;
765
766         bool isLineEmpty = true;
767         bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
768
769         LineBreakIteratorInfo lineBreakIteratorInfo;
770         VerticalPositionCache verticalPositionCache;
771
772         while (!end.atEnd()) {
773             // FIXME: Is this check necessary before the first iteration or can it be moved to the end?
774             if (checkForEndLineMatch && (endLineMatched = matchedEndLine(resolver, cleanLineStart, cleanLineBidiStatus, endLine, endLineLogicalTop, repaintLogicalBottom, repaintLogicalTop)))
775                 break;
776
777             lineMidpointState.reset();
778             
779             isLineEmpty = true;
780             
781             EClear clear = CNONE;
782             bool hyphenated;
783             Vector<RenderBox*> positionedObjects;
784             
785             InlineIterator oldEnd = end;
786             FloatingObject* lastFloatFromPreviousLine = (m_floatingObjects && !m_floatingObjects->set().isEmpty()) ? m_floatingObjects->set().last() : 0;
787             end = findNextLineBreak(resolver, firstLine, isLineEmpty, lineBreakIteratorInfo, previousLineBrokeCleanly, hyphenated, &clear, lastFloatFromPreviousLine, positionedObjects);
788             if (resolver.position().atEnd()) {
789                 resolver.deleteRuns();
790                 checkForFloatsFromLastLine = true;
791                 break;
792             }
793             ASSERT(end != resolver.position());
794
795             if (isLineEmpty) {
796                 if (lastRootBox())
797                     lastRootBox()->setLineBreakInfo(end.m_obj, end.m_pos, resolver.status());
798             } else {
799                 VisualDirectionOverride override = (style()->visuallyOrdered() ? (style()->direction() == LTR ? VisualLeftToRightOverride : VisualRightToLeftOverride) : NoVisualOverride);
800                 resolver.createBidiRunsForLine(end, override, previousLineBrokeCleanly);
801                 ASSERT(resolver.position() == end);
802
803                 BidiRun* trailingSpaceRun = 0;
804                 if (!previousLineBrokeCleanly && resolver.runCount() && resolver.logicallyLastRun()->m_object->style()->breakOnlyAfterWhiteSpace()
805                         && resolver.logicallyLastRun()->m_object->style()->autoWrap()) {
806                     trailingSpaceRun = resolver.logicallyLastRun();
807                     RenderObject* lastObject = trailingSpaceRun->m_object;
808                     if (lastObject->isText()) {
809                         RenderText* lastText = toRenderText(lastObject);
810                         const UChar* characters = lastText->characters();
811                         int firstSpace = trailingSpaceRun->stop();
812                         while (firstSpace > trailingSpaceRun->start()) {
813                             UChar current = characters[firstSpace - 1];
814                             if (!isCollapsibleSpace(current, lastText))
815                                 break;
816                             firstSpace--;
817                         }
818                         if (firstSpace == trailingSpaceRun->stop())
819                             trailingSpaceRun = 0;
820                         else {
821                             TextDirection direction = style()->direction();
822                             bool shouldReorder = trailingSpaceRun != (direction == LTR ? resolver.lastRun() : resolver.firstRun());
823                             if (firstSpace != trailingSpaceRun->start()) {
824                                 BidiContext* baseContext = resolver.context();
825                                 while (BidiContext* parent = baseContext->parent())
826                                     baseContext = parent;
827
828                                 BidiRun* newTrailingRun = new (renderArena()) BidiRun(firstSpace, trailingSpaceRun->m_stop, trailingSpaceRun->m_object, baseContext, OtherNeutral);
829                                 trailingSpaceRun->m_stop = firstSpace;
830                                 if (direction == LTR)
831                                     resolver.addRun(newTrailingRun);
832                                 else
833                                     resolver.prependRun(newTrailingRun);
834                                 trailingSpaceRun = newTrailingRun;
835                                 shouldReorder = false;
836                             }
837                             if (shouldReorder) {
838                                 if (direction == LTR) {
839                                     resolver.moveRunToEnd(trailingSpaceRun);
840                                     trailingSpaceRun->m_level = 0;
841                                 } else {
842                                     resolver.moveRunToBeginning(trailingSpaceRun);
843                                     trailingSpaceRun->m_level = 1;
844                                 }
845                             }
846                         }
847                     } else
848                         trailingSpaceRun = 0;
849                 }
850
851                 // Now that the runs have been ordered, we create the line boxes.
852                 // At the same time we figure out where border/padding/margin should be applied for
853                 // inline flow boxes.
854
855                 RootInlineBox* lineBox = 0;
856                 int oldLogicalHeight = logicalHeight();
857                 if (resolver.runCount()) {
858                     if (hyphenated)
859                         resolver.logicallyLastRun()->m_hasHyphen = true;
860                     bool lastLine = end.m_obj && end.m_obj->isText() ? reachedEndOfTextRenderer(resolver) : !end.m_obj;
861                     lineBox = constructLine(resolver.runCount(), resolver.firstRun(), resolver.lastRun(), firstLine, lastLine, end.m_obj && !end.m_pos ? end.m_obj : 0, resolver.logicallyLastRun()->m_object);
862                     if (lineBox) {
863                         lineBox->setEndsWithBreak(previousLineBrokeCleanly);
864
865 #if ENABLE(SVG)
866                         bool isSVGRootInlineBox = lineBox->isSVGRootInlineBox();
867 #else
868                         bool isSVGRootInlineBox = false;
869 #endif
870
871                         GlyphOverflowAndFallbackFontsMap textBoxDataMap;
872                     
873                         // Now we position all of our text runs horizontally.
874                         if (!isSVGRootInlineBox)
875                             computeInlineDirectionPositionsForLine(lineBox, firstLine, resolver.firstRun(), trailingSpaceRun, end.atEnd(), textBoxDataMap, verticalPositionCache);
876
877                         // Now position our text runs vertically.
878                         computeBlockDirectionPositionsForLine(lineBox, resolver.firstRun(), textBoxDataMap, verticalPositionCache);
879
880 #if ENABLE(SVG)
881                         // SVG text layout code computes vertical & horizontal positions on its own.
882                         // Note that we still need to execute computeVerticalPositionsForLine() as
883                         // it calls InlineTextBox::positionLineBox(), which tracks whether the box
884                         // contains reversed text or not. If we wouldn't do that editing and thus
885                         // text selection in RTL boxes would not work as expected.
886                         if (isSVGRootInlineBox) {
887                             ASSERT(isSVGText());
888                             static_cast<SVGRootInlineBox*>(lineBox)->computePerCharacterLayoutInformation();
889                         }
890 #endif
891
892                         // Compute our overflow now.
893                         lineBox->computeOverflow(lineBox->lineTop(), lineBox->lineBottom(), textBoxDataMap);
894     
895 #if PLATFORM(MAC)
896                         // Highlight acts as an overflow inflation.
897                         if (style()->highlight() != nullAtom)
898                             lineBox->addHighlightOverflow();
899 #endif
900                     }
901                 }
902
903                 resolver.deleteRuns();
904
905                 if (lineBox) {
906                     lineBox->setLineBreakInfo(end.m_obj, end.m_pos, resolver.status());
907                     if (useRepaintBounds) {
908                         repaintLogicalTop = min(repaintLogicalTop, lineBox->logicalTopVisualOverflow());
909                         repaintLogicalBottom = max(repaintLogicalBottom, lineBox->logicalBottomVisualOverflow());
910                     }
911                     
912                     if (paginated) {
913                         int adjustment = 0;
914                         adjustLinePositionForPagination(lineBox, adjustment);
915                         if (adjustment) {
916                             int oldLineWidth = availableLogicalWidthForLine(oldLogicalHeight, firstLine);
917                             lineBox->adjustBlockDirectionPosition(adjustment);
918                             if (useRepaintBounds) // This can only be a positive adjustment, so no need to update repaintTop.
919                                 repaintLogicalBottom = max(repaintLogicalBottom, lineBox->logicalBottomVisualOverflow());
920                                 
921                             if (availableLogicalWidthForLine(oldLogicalHeight + adjustment, firstLine) != oldLineWidth) {
922                                 // We have to delete this line, remove all floats that got added, and let line layout re-run.
923                                 lineBox->deleteLine(renderArena());
924                                 removeFloatingObjectsBelow(lastFloatFromPreviousLine, oldLogicalHeight);
925                                 setLogicalHeight(oldLogicalHeight + adjustment);
926                                 resolver.setPosition(oldEnd);
927                                 end = oldEnd;
928                                 continue;
929                             }
930
931                             setLogicalHeight(lineBox->blockLogicalHeight());
932                         }
933                     }
934                 }
935
936                 for (size_t i = 0; i < positionedObjects.size(); ++i)
937                     setStaticPositions(this, positionedObjects[i]);
938
939                 firstLine = false;
940                 newLine(clear);
941             }
942
943             if (m_floatingObjects && lastRootBox()) {
944                 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
945                 FloatingObjectSetIterator it = floatingObjectSet.begin();
946                 FloatingObjectSetIterator end = floatingObjectSet.end();
947                 if (lastFloat) {
948                     FloatingObjectSetIterator lastFloatIterator = floatingObjectSet.find(lastFloat);
949                     ASSERT(lastFloatIterator != end);
950                     ++lastFloatIterator;
951                     it = lastFloatIterator;
952                 }
953                 for (; it != end; ++it) {
954                     FloatingObject* f = *it;
955                     lastRootBox()->floats().append(f->m_renderer);
956                     ASSERT(f->m_renderer == floats[floatIndex].object);
957                     // If a float's geometry has changed, give up on syncing with clean lines.
958                     if (floats[floatIndex].rect != f->frameRect())
959                         checkForEndLineMatch = false;
960                     floatIndex++;
961                 }
962                 lastFloat = !floatingObjectSet.isEmpty() ? floatingObjectSet.last() : 0;
963             }
964
965             lineMidpointState.reset();
966             resolver.setPosition(end);
967         }
968
969         if (endLine) {
970             if (endLineMatched) {
971                 // Attach all the remaining lines, and then adjust their y-positions as needed.
972                 int delta = logicalHeight() - endLineLogicalTop;
973                 for (RootInlineBox* line = endLine; line; line = line->nextRootBox()) {
974                     line->attachLine();
975                     if (paginated) {
976                         delta -= line->paginationStrut();
977                         adjustLinePositionForPagination(line, delta);
978                     }
979                     if (delta) {
980                         repaintLogicalTop = min(repaintLogicalTop, line->logicalTopVisualOverflow() + min(delta, 0));
981                         repaintLogicalBottom = max(repaintLogicalBottom, line->logicalBottomVisualOverflow() + max(delta, 0));
982                         line->adjustBlockDirectionPosition(delta);
983                     }
984                     if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) {
985                         Vector<RenderBox*>::iterator end = cleanLineFloats->end();
986                         for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) {
987                             insertFloatingObject(*f);
988                             setLogicalHeight(logicalTopForChild(*f) - marginBeforeForChild(*f) + delta);
989                             positionNewFloats();
990                         }
991                     }
992                 }
993                 setLogicalHeight(lastRootBox()->blockLogicalHeight());
994             } else {
995                 // Delete all the remaining lines.
996                 RootInlineBox* line = endLine;
997                 RenderArena* arena = renderArena();
998                 while (line) {
999                     repaintLogicalTop = min(repaintLogicalTop, line->logicalTopVisualOverflow());
1000                     repaintLogicalBottom = max(repaintLogicalBottom, line->logicalBottomVisualOverflow());
1001                     RootInlineBox* next = line->nextRootBox();
1002                     line->deleteLine(arena);
1003                     line = next;
1004                 }
1005             }
1006         }
1007         if (m_floatingObjects && (checkForFloatsFromLastLine || positionNewFloats()) && lastRootBox()) {
1008             // In case we have a float on the last line, it might not be positioned up to now.
1009             // This has to be done before adding in the bottom border/padding, or the float will
1010             // include the padding incorrectly. -dwh
1011             if (checkForFloatsFromLastLine) {
1012                 int bottomVisualOverflow = lastRootBox()->logicalTopLayoutOverflow();
1013                 int bottomLayoutOverflow = lastRootBox()->logicalBottomLayoutOverflow();
1014                 TrailingFloatsRootInlineBox* trailingFloatsLineBox = new (renderArena()) TrailingFloatsRootInlineBox(this);
1015                 m_lineBoxes.appendLineBox(trailingFloatsLineBox);
1016                 trailingFloatsLineBox->setConstructed();
1017                 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1018                 VerticalPositionCache verticalPositionCache;
1019                 trailingFloatsLineBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache);
1020                 IntRect logicalLayoutOverflow(0, logicalHeight(), 1, bottomLayoutOverflow);
1021                 IntRect logicalVisualOverflow(0, logicalHeight(), 1, bottomVisualOverflow);
1022                 trailingFloatsLineBox->setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow, trailingFloatsLineBox->lineTop(), trailingFloatsLineBox->lineBottom());
1023                 trailingFloatsLineBox->setBlockLogicalHeight(logicalHeight());
1024             }
1025
1026             FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1027             FloatingObjectSetIterator it = floatingObjectSet.begin();
1028             FloatingObjectSetIterator end = floatingObjectSet.end();
1029             if (lastFloat) {
1030                 FloatingObjectSetIterator lastFloatIterator = floatingObjectSet.find(lastFloat);
1031                 ASSERT(lastFloatIterator != end);
1032                 ++lastFloatIterator;
1033                 it = lastFloatIterator;
1034             }
1035             for (; it != end; ++it)
1036                 lastRootBox()->floats().append((*it)->m_renderer);
1037             lastFloat = !floatingObjectSet.isEmpty() ? floatingObjectSet.last() : 0;
1038         }
1039         size_t floatCount = floats.size();
1040         // Floats that did not have layout did not repaint when we laid them out. They would have
1041         // painted by now if they had moved, but if they stayed at (0, 0), they still need to be
1042         // painted.
1043         for (size_t i = 0; i < floatCount; ++i) {
1044             if (!floats[i].everHadLayout) {
1045                 RenderBox* f = floats[i].object;
1046                 if (!f->x() && !f->y() && f->checkForRepaintDuringLayout())
1047                     f->repaint();
1048             }
1049         }
1050     }
1051
1052     // Expand the last line to accommodate Ruby and emphasis marks.
1053     int lastLineAnnotationsAdjustment = 0;
1054     if (lastRootBox()) {
1055         int lowestAllowedPosition = max(lastRootBox()->lineBottom(), logicalHeight() + paddingAfter());
1056         if (!style()->isFlippedLinesWritingMode())
1057             lastLineAnnotationsAdjustment = lastRootBox()->computeUnderAnnotationAdjustment(lowestAllowedPosition);
1058         else
1059             lastLineAnnotationsAdjustment = lastRootBox()->computeOverAnnotationAdjustment(lowestAllowedPosition);
1060     }
1061
1062     // Now add in the bottom border/padding.
1063     setLogicalHeight(logicalHeight() + lastLineAnnotationsAdjustment + borderAfter() + paddingAfter() + scrollbarLogicalHeight());
1064
1065     if (!firstLineBox() && hasLineIfEmpty())
1066         setLogicalHeight(logicalHeight() + lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
1067
1068     // See if we have any lines that spill out of our block.  If we do, then we will possibly need to
1069     // truncate text.
1070     if (hasTextOverflow)
1071         checkLinesForTextOverflow();
1072 }
1073
1074 void RenderBlock::checkFloatsInCleanLine(RootInlineBox* line, Vector<FloatWithRect>& floats, size_t& floatIndex, bool& encounteredNewFloat, bool& dirtiedByFloat)
1075 {
1076     Vector<RenderBox*>* cleanLineFloats = line->floatsPtr();
1077     if (!cleanLineFloats)
1078         return;
1079
1080     Vector<RenderBox*>::iterator end = cleanLineFloats->end();
1081     for (Vector<RenderBox*>::iterator it = cleanLineFloats->begin(); it != end; ++it) {
1082         RenderBox* floatingBox = *it;
1083         floatingBox->layoutIfNeeded();
1084         IntSize newSize(floatingBox->width() + floatingBox->marginLeft() + floatingBox->marginRight(), floatingBox->height() + floatingBox->marginTop() + floatingBox->marginBottom());
1085         ASSERT(floatIndex < floats.size());
1086         if (floats[floatIndex].object != floatingBox) {
1087             encounteredNewFloat = true;
1088             return;
1089         }
1090         if (floats[floatIndex].rect.size() != newSize) {
1091             int floatTop = isHorizontalWritingMode() ? floats[floatIndex].rect.y() : floats[floatIndex].rect.x();
1092             int floatHeight = isHorizontalWritingMode() ? max(floats[floatIndex].rect.height(), newSize.height()) 
1093                                                                  : max(floats[floatIndex].rect.width(), newSize.width());
1094             line->markDirty();
1095             markLinesDirtyInBlockRange(line->blockLogicalHeight(), floatTop + floatHeight, line);
1096             floats[floatIndex].rect.setSize(newSize);
1097             dirtiedByFloat = true;
1098         }
1099         floatIndex++;
1100     }
1101 }
1102
1103 RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLayout, bool& previousLineBrokeCleanly, 
1104                                                    InlineBidiResolver& resolver, Vector<FloatWithRect>& floats, unsigned& numCleanFloats,
1105                                                    bool& useRepaintBounds, int& repaintLogicalTop, int& repaintLogicalBottom)
1106 {
1107     RootInlineBox* curr = 0;
1108     RootInlineBox* last = 0;
1109
1110     bool dirtiedByFloat = false;
1111     if (!fullLayout) {
1112         // Paginate all of the clean lines.
1113         bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
1114         int paginationDelta = 0;
1115         size_t floatIndex = 0;
1116         for (curr = firstRootBox(); curr && !curr->isDirty(); curr = curr->nextRootBox()) {
1117             if (paginated) {
1118                 paginationDelta -= curr->paginationStrut();
1119                 adjustLinePositionForPagination(curr, paginationDelta);
1120                 if (paginationDelta) {
1121                     if (containsFloats() || !floats.isEmpty()) {
1122                         // FIXME: Do better eventually.  For now if we ever shift because of pagination and floats are present just go to a full layout.
1123                         fullLayout = true; 
1124                         break;
1125                     }
1126                     
1127                     if (!useRepaintBounds)
1128                         useRepaintBounds = true;
1129                         
1130                     repaintLogicalTop = min(repaintLogicalTop, curr->logicalTopVisualOverflow() + min(paginationDelta, 0));
1131                     repaintLogicalBottom = max(repaintLogicalBottom, curr->logicalBottomVisualOverflow() + max(paginationDelta, 0));
1132                     curr->adjustBlockDirectionPosition(paginationDelta);
1133                 }                
1134             }
1135
1136             // If a new float has been inserted before this line or before its last known float,just do a full layout.
1137             checkFloatsInCleanLine(curr, floats, floatIndex, fullLayout, dirtiedByFloat);
1138             if (dirtiedByFloat || fullLayout)
1139                 break;
1140         }
1141         // Check if a new float has been inserted after the last known float.
1142         if (!curr && floatIndex < floats.size())
1143             fullLayout = true;
1144     }
1145
1146     if (fullLayout) {
1147         // Nuke all our lines.
1148         if (firstRootBox()) {
1149             RenderArena* arena = renderArena();
1150             curr = firstRootBox(); 
1151             while (curr) {
1152                 RootInlineBox* next = curr->nextRootBox();
1153                 curr->deleteLine(arena);
1154                 curr = next;
1155             }
1156             ASSERT(!firstLineBox() && !lastLineBox());
1157         }
1158     } else {
1159         if (curr) {
1160             // We have a dirty line.
1161             if (RootInlineBox* prevRootBox = curr->prevRootBox()) {
1162                 // We have a previous line.
1163                 if (!dirtiedByFloat && (!prevRootBox->endsWithBreak() || (prevRootBox->lineBreakObj()->isText() && prevRootBox->lineBreakPos() >= toRenderText(prevRootBox->lineBreakObj())->textLength())))
1164                     // The previous line didn't break cleanly or broke at a newline
1165                     // that has been deleted, so treat it as dirty too.
1166                     curr = prevRootBox;
1167             }
1168         } else {
1169             // No dirty lines were found.
1170             // If the last line didn't break cleanly, treat it as dirty.
1171             if (lastRootBox() && !lastRootBox()->endsWithBreak())
1172                 curr = lastRootBox();
1173         }
1174
1175         // If we have no dirty lines, then last is just the last root box.
1176         last = curr ? curr->prevRootBox() : lastRootBox();
1177     }
1178
1179     numCleanFloats = 0;
1180     if (!floats.isEmpty()) {
1181         int savedLogicalHeight = logicalHeight();
1182         // Restore floats from clean lines.
1183         RootInlineBox* line = firstRootBox();
1184         while (line != curr) {
1185             if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) {
1186                 Vector<RenderBox*>::iterator end = cleanLineFloats->end();
1187                 for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) {
1188                     insertFloatingObject(*f);
1189                     setLogicalHeight(logicalTopForChild(*f) - marginBeforeForChild(*f));
1190                     positionNewFloats();
1191                     ASSERT(floats[numCleanFloats].object == *f);
1192                     numCleanFloats++;
1193                 }
1194             }
1195             line = line->nextRootBox();
1196         }
1197         setLogicalHeight(savedLogicalHeight);
1198     }
1199
1200     firstLine = !last;
1201     previousLineBrokeCleanly = !last || last->endsWithBreak();
1202
1203     RenderObject* startObj;
1204     int pos = 0;
1205     if (last) {
1206         setLogicalHeight(last->blockLogicalHeight());
1207         startObj = last->lineBreakObj();
1208         pos = last->lineBreakPos();
1209         resolver.setStatus(last->lineBreakBidiStatus());
1210     } else {
1211         bool ltr = style()->isLeftToRightDirection();
1212         Direction direction = ltr ? LeftToRight : RightToLeft;
1213         resolver.setLastStrongDir(direction);
1214         resolver.setLastDir(direction);
1215         resolver.setEorDir(direction);
1216         resolver.setContext(BidiContext::create(ltr ? 0 : 1, direction, style()->unicodeBidi() == Override, FromStyleOrDOM));
1217
1218         startObj = bidiFirst(this, &resolver);
1219     }
1220
1221     resolver.setPosition(InlineIterator(this, startObj, pos));
1222
1223     return curr;
1224 }
1225
1226 RootInlineBox* RenderBlock::determineEndPosition(RootInlineBox* startLine, Vector<FloatWithRect>& floats, size_t floatIndex, InlineIterator& cleanLineStart, BidiStatus& cleanLineBidiStatus, int& logicalTop)
1227 {
1228     RootInlineBox* last = 0;
1229     for (RootInlineBox* curr = startLine->nextRootBox(); curr; curr = curr->nextRootBox()) {
1230         if (!curr->isDirty()) {
1231             bool encounteredNewFloat = false;
1232             bool dirtiedByFloat = false;
1233             checkFloatsInCleanLine(curr, floats, floatIndex, encounteredNewFloat, dirtiedByFloat);
1234             if (encounteredNewFloat)
1235                 return 0;
1236         }
1237         if (curr->isDirty())
1238             last = 0;
1239         else if (!last)
1240             last = curr;
1241     }
1242
1243     if (!last)
1244         return 0;
1245
1246     // At this point, |last| is the first line in a run of clean lines that ends with the last line
1247     // in the block.
1248
1249     RootInlineBox* prev = last->prevRootBox();
1250     cleanLineStart = InlineIterator(this, prev->lineBreakObj(), prev->lineBreakPos());
1251     cleanLineBidiStatus = prev->lineBreakBidiStatus();
1252     logicalTop = prev->blockLogicalHeight();
1253
1254     for (RootInlineBox* line = last; line; line = line->nextRootBox())
1255         line->extractLine(); // Disconnect all line boxes from their render objects while preserving
1256                              // their connections to one another.
1257
1258     return last;
1259 }
1260
1261 bool RenderBlock::matchedEndLine(const InlineBidiResolver& resolver, const InlineIterator& endLineStart, const BidiStatus& endLineStatus, RootInlineBox*& endLine,
1262                                  int& endLogicalTop, int& repaintLogicalBottom, int& repaintLogicalTop)
1263 {
1264     if (resolver.position() == endLineStart) {
1265         if (resolver.status() != endLineStatus)
1266             return false;
1267
1268         int delta = logicalHeight() - endLogicalTop;
1269         if (!delta || !m_floatingObjects)
1270             return true;
1271
1272         // See if any floats end in the range along which we want to shift the lines vertically.
1273         int logicalTop = min(logicalHeight(), endLogicalTop);
1274
1275         RootInlineBox* lastLine = endLine;
1276         while (RootInlineBox* nextLine = lastLine->nextRootBox())
1277             lastLine = nextLine;
1278
1279         int logicalBottom = lastLine->blockLogicalHeight() + abs(delta);
1280
1281         FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1282         FloatingObjectSetIterator end = floatingObjectSet.end();
1283         for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
1284             FloatingObject* f = *it;
1285             if (logicalBottomForFloat(f) >= logicalTop && logicalBottomForFloat(f) < logicalBottom)
1286                 return false;
1287         }
1288
1289         return true;
1290     }
1291
1292     // The first clean line doesn't match, but we can check a handful of following lines to try
1293     // to match back up.
1294     static int numLines = 8; // The # of lines we're willing to match against.
1295     RootInlineBox* line = endLine;
1296     for (int i = 0; i < numLines && line; i++, line = line->nextRootBox()) {
1297         if (line->lineBreakObj() == resolver.position().m_obj && line->lineBreakPos() == resolver.position().m_pos) {
1298             // We have a match.
1299             if (line->lineBreakBidiStatus() != resolver.status())
1300                 return false; // ...but the bidi state doesn't match.
1301             RootInlineBox* result = line->nextRootBox();
1302
1303             // Set our logical top to be the block height of endLine.
1304             if (result)
1305                 endLogicalTop = line->blockLogicalHeight();
1306
1307             int delta = logicalHeight() - endLogicalTop;
1308             if (delta && m_floatingObjects) {
1309                 // See if any floats end in the range along which we want to shift the lines vertically.
1310                 int logicalTop = min(logicalHeight(), endLogicalTop);
1311
1312                 RootInlineBox* lastLine = endLine;
1313                 while (RootInlineBox* nextLine = lastLine->nextRootBox())
1314                     lastLine = nextLine;
1315
1316                 int logicalBottom = lastLine->blockLogicalHeight() + abs(delta);
1317
1318                 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1319                 FloatingObjectSetIterator end = floatingObjectSet.end();
1320                 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
1321                     FloatingObject* f = *it;
1322                     if (logicalBottomForFloat(f) >= logicalTop && logicalBottomForFloat(f) < logicalBottom)
1323                         return false;
1324                 }
1325             }
1326
1327             // Now delete the lines that we failed to sync.
1328             RootInlineBox* boxToDelete = endLine;
1329             RenderArena* arena = renderArena();
1330             while (boxToDelete && boxToDelete != result) {
1331                 repaintLogicalTop = min(repaintLogicalTop, boxToDelete->logicalTopVisualOverflow());
1332                 repaintLogicalBottom = max(repaintLogicalBottom, boxToDelete->logicalBottomVisualOverflow());
1333                 RootInlineBox* next = boxToDelete->nextRootBox();
1334                 boxToDelete->deleteLine(arena);
1335                 boxToDelete = next;
1336             }
1337
1338             endLine = result;
1339             return result;
1340         }
1341     }
1342
1343     return false;
1344 }
1345
1346 static inline bool skipNonBreakingSpace(const InlineIterator& it, bool isLineEmpty, bool previousLineBrokeCleanly)
1347 {
1348     if (it.m_obj->style()->nbspMode() != SPACE || it.current() != noBreakSpace)
1349         return false;
1350
1351     // FIXME: This is bad.  It makes nbsp inconsistent with space and won't work correctly
1352     // with m_minWidth/m_maxWidth.
1353     // Do not skip a non-breaking space if it is the first character
1354     // on a line after a clean line break (or on the first line, since previousLineBrokeCleanly starts off
1355     // |true|).
1356     if (isLineEmpty && previousLineBrokeCleanly)
1357         return false;
1358
1359     return true;
1360 }
1361
1362 static inline bool shouldCollapseWhiteSpace(const RenderStyle* style, bool isLineEmpty, bool previousLineBrokeCleanly)
1363 {
1364     return style->collapseWhiteSpace() || (style->whiteSpace() == PRE_WRAP && (!isLineEmpty || !previousLineBrokeCleanly));
1365 }
1366
1367 static inline bool shouldPreserveNewline(RenderObject* object)
1368 {
1369 #if ENABLE(SVG)
1370     if (object->isSVGInlineText())
1371         return false;
1372 #endif
1373
1374     return object->style()->preserveNewline();
1375 }
1376
1377 static bool inlineFlowRequiresLineBox(RenderInline* flow)
1378 {
1379     // FIXME: Right now, we only allow line boxes for inlines that are truly empty.
1380     // We need to fix this, though, because at the very least, inlines containing only
1381     // ignorable whitespace should should also have line boxes. 
1382     return !flow->firstChild() && flow->hasInlineDirectionBordersPaddingOrMargin();
1383 }
1384
1385 bool RenderBlock::requiresLineBox(const InlineIterator& it, bool isLineEmpty, bool previousLineBrokeCleanly)
1386 {
1387     if (it.m_obj->isFloatingOrPositioned())
1388         return false;
1389
1390     if (it.m_obj->isRenderInline() && !inlineFlowRequiresLineBox(toRenderInline(it.m_obj)))
1391         return false;
1392
1393     if (!shouldCollapseWhiteSpace(it.m_obj->style(), isLineEmpty, previousLineBrokeCleanly) || it.m_obj->isBR())
1394         return true;
1395
1396     UChar current = it.current();
1397     return current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || shouldPreserveNewline(it.m_obj)) 
1398             && !skipNonBreakingSpace(it, isLineEmpty, previousLineBrokeCleanly);
1399 }
1400
1401 bool RenderBlock::generatesLineBoxesForInlineChild(RenderObject* inlineObj, bool isLineEmpty, bool previousLineBrokeCleanly)
1402 {
1403     ASSERT(inlineObj->parent() == this);
1404
1405     InlineIterator it(this, inlineObj, 0);
1406     while (!it.atEnd() && !requiresLineBox(it, isLineEmpty, previousLineBrokeCleanly))
1407         it.increment();
1408
1409     return !it.atEnd();
1410 }
1411
1412 // FIXME: The entire concept of the skipTrailingWhitespace function is flawed, since we really need to be building
1413 // line boxes even for containers that may ultimately collapse away.  Otherwise we'll never get positioned
1414 // elements quite right.  In other words, we need to build this function's work into the normal line
1415 // object iteration process.
1416 // NB. this function will insert any floating elements that would otherwise
1417 // be skipped but it will not position them.
1418 void RenderBlock::skipTrailingWhitespace(InlineIterator& iterator, bool isLineEmpty, bool previousLineBrokeCleanly)
1419 {
1420     while (!iterator.atEnd() && !requiresLineBox(iterator, isLineEmpty, previousLineBrokeCleanly)) {
1421         RenderObject* object = iterator.m_obj;
1422         if (object->isFloating()) {
1423             insertFloatingObject(toRenderBox(object));
1424         } else if (object->isPositioned())
1425             setStaticPositions(this, toRenderBox(object));
1426         iterator.increment();
1427     }
1428 }
1429
1430 void RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver, bool firstLine, bool isLineEmpty, bool previousLineBrokeCleanly,
1431                                        FloatingObject* lastFloatFromPreviousLine, int& lineLeftOffset, int& lineRightOffset)
1432 {
1433     while (!resolver.position().atEnd() && !requiresLineBox(resolver.position(), isLineEmpty, previousLineBrokeCleanly)) {
1434         RenderObject* object = resolver.position().m_obj;
1435         if (object->isFloating())
1436             positionNewFloatOnLine(insertFloatingObject(toRenderBox(object)), lastFloatFromPreviousLine, firstLine, lineLeftOffset, lineRightOffset);
1437         else if (object->isPositioned())
1438             setStaticPositions(this, toRenderBox(object));
1439         resolver.increment();
1440     }
1441     resolver.commitExplicitEmbedding();
1442 }
1443
1444 // This is currently just used for list markers and inline flows that have line boxes. Neither should 
1445 // have an effect on whitespace at the start of the line. 
1446 static bool shouldSkipWhitespaceAfterStartObject(RenderBlock* block, RenderObject* o, LineMidpointState& lineMidpointState)
1447 {
1448     RenderObject* next = bidiNext(block, o);
1449     if (next && !next->isBR() && next->isText() && toRenderText(next)->textLength() > 0) {
1450         RenderText* nextText = toRenderText(next);
1451         UChar nextChar = nextText->characters()[0];
1452         if (nextText->style()->isCollapsibleWhiteSpace(nextChar)) {
1453             addMidpoint(lineMidpointState, InlineIterator(0, o, 0));
1454             return true;
1455         }
1456     }
1457
1458     return false;
1459 }
1460
1461 void RenderBlock::fitBelowFloats(float widthToFit, bool firstLine, float& availableWidth)
1462 {
1463     ASSERT(widthToFit > availableWidth);
1464
1465     int floatLogicalBottom;
1466     int lastFloatLogicalBottom = logicalHeight();
1467     float newLineWidth = availableWidth;
1468     while (true) {
1469         floatLogicalBottom = nextFloatLogicalBottomBelow(lastFloatLogicalBottom);
1470         if (!floatLogicalBottom)
1471             break;
1472
1473         newLineWidth = availableLogicalWidthForLine(floatLogicalBottom, firstLine);
1474         lastFloatLogicalBottom = floatLogicalBottom;
1475         if (newLineWidth >= widthToFit)
1476             break;
1477     }
1478
1479     if (newLineWidth > availableWidth) {
1480         setLogicalHeight(lastFloatLogicalBottom);
1481         availableWidth = newLineWidth;
1482     }
1483 }
1484
1485 static inline float textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, float xPos, bool isFixedPitch, bool collapseWhiteSpace)
1486 {
1487     if (isFixedPitch || (!from && len == text->textLength()) || text->style()->hasTextCombine())
1488         return text->width(from, len, font, xPos);
1489     return font.width(TextRun(text->characters() + from, len, !collapseWhiteSpace, xPos));
1490 }
1491
1492 static void tryHyphenating(RenderText* text, const Font& font, const AtomicString& localeIdentifier, int minimumPrefixLength, int minimumSuffixLength, int lastSpace, int pos, float xPos, int availableWidth, bool isFixedPitch, bool collapseWhiteSpace, int lastSpaceWordSpacing, InlineIterator& lineBreak, int nextBreakable, bool& hyphenated)
1493 {
1494     // Map 'hyphenate-limit-{before,after}: auto;' to 2.
1495     if (minimumPrefixLength < 0)
1496         minimumPrefixLength = 2;
1497
1498     if (minimumSuffixLength < 0)
1499         minimumSuffixLength = 2;
1500
1501     if (pos - lastSpace <= minimumSuffixLength)
1502         return;
1503
1504     const AtomicString& hyphenString = text->style()->hyphenString();
1505     int hyphenWidth = font.width(TextRun(hyphenString.characters(), hyphenString.length()));
1506
1507     float maxPrefixWidth = availableWidth - xPos - hyphenWidth - lastSpaceWordSpacing;
1508     // If the maximum width available for the prefix before the hyphen is small, then it is very unlikely
1509     // that an hyphenation opportunity exists, so do not bother to look for it.
1510     if (maxPrefixWidth <= font.pixelSize() * 5 / 4)
1511         return;
1512
1513     unsigned prefixLength = font.offsetForPosition(TextRun(text->characters() + lastSpace, pos - lastSpace, !collapseWhiteSpace, xPos + lastSpaceWordSpacing), maxPrefixWidth, false);
1514     if (prefixLength < static_cast<unsigned>(minimumPrefixLength))
1515         return;
1516
1517     prefixLength = lastHyphenLocation(text->characters() + lastSpace, pos - lastSpace, min(prefixLength, static_cast<unsigned>(pos - lastSpace - minimumSuffixLength)) + 1, localeIdentifier);
1518     // FIXME: The following assumes that the character at lastSpace is a space (and therefore should not factor
1519     // into hyphenate-limit-before) unless lastSpace is 0. This is wrong in the rare case of hyphenating
1520     // the first word in a text node which has leading whitespace.
1521     if (!prefixLength || prefixLength - (lastSpace ? 1 : 0) < static_cast<unsigned>(minimumPrefixLength))
1522         return;
1523
1524     ASSERT(pos - lastSpace - prefixLength >= static_cast<unsigned>(minimumSuffixLength));
1525
1526 #if !ASSERT_DISABLED
1527     float prefixWidth = hyphenWidth + textWidth(text, lastSpace, prefixLength, font, xPos, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing;
1528     ASSERT(xPos + prefixWidth <= availableWidth);
1529 #else
1530     UNUSED_PARAM(isFixedPitch);
1531 #endif
1532
1533     lineBreak.moveTo(text, lastSpace + prefixLength, nextBreakable);
1534     hyphenated = true;
1535 }
1536
1537 InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool firstLine, bool& isLineEmpty, LineBreakIteratorInfo& lineBreakIteratorInfo, bool& previousLineBrokeCleanly, 
1538                                               bool& hyphenated, EClear* clear, FloatingObject* lastFloatFromPreviousLine, Vector<RenderBox*>& positionedBoxes)
1539 {
1540     ASSERT(resolver.position().m_block == this);
1541
1542     bool appliedStartWidth = resolver.position().m_pos > 0;
1543     LineMidpointState& lineMidpointState = resolver.midpointState();
1544     
1545     int blockOffset = logicalHeight();
1546     int lineLeftOffset = logicalLeftOffsetForLine(blockOffset, firstLine);
1547     int lineRightOffset = logicalRightOffsetForLine(blockOffset, firstLine);
1548     
1549     skipLeadingWhitespace(resolver, firstLine, isLineEmpty, previousLineBrokeCleanly, lastFloatFromPreviousLine, lineLeftOffset, lineRightOffset);
1550
1551     float width = max(0, lineRightOffset - lineLeftOffset);
1552     float w = 0;
1553     float tmpW = 0;
1554
1555     if (resolver.position().atEnd())
1556         return resolver.position();
1557
1558     // This variable is used only if whitespace isn't set to PRE, and it tells us whether
1559     // or not we are currently ignoring whitespace.
1560     bool ignoringSpaces = false;
1561     InlineIterator ignoreStart;
1562     
1563     // This variable tracks whether the very last character we saw was a space.  We use
1564     // this to detect when we encounter a second space so we know we have to terminate
1565     // a run.
1566     bool currentCharacterIsSpace = false;
1567     bool currentCharacterIsWS = false;
1568     RenderObject* trailingSpaceObject = 0;
1569     Vector<RenderBox*, 4> trailingPositionedBoxes;
1570
1571     InlineIterator lBreak = resolver.position();
1572
1573     // FIXME: It is error-prone to split the position object out like this.
1574     // Teach this code to work with objects instead of this split tuple.
1575     RenderObject* o = resolver.position().m_obj;
1576     RenderObject* last = o;
1577     unsigned pos = resolver.position().m_pos;
1578     int nextBreakable = resolver.position().m_nextBreakablePosition;
1579     bool atStart = true;
1580
1581     bool prevLineBrokeCleanly = previousLineBrokeCleanly;
1582     previousLineBrokeCleanly = false;
1583
1584     hyphenated = false;
1585
1586     bool autoWrapWasEverTrueOnLine = false;
1587     bool floatsFitOnLine = true;
1588     
1589     // Firefox and Opera will allow a table cell to grow to fit an image inside it under
1590     // very specific circumstances (in order to match common WinIE renderings). 
1591     // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.) 
1592     bool allowImagesToBreak = !document()->inQuirksMode() || !isTableCell() || !style()->logicalWidth().isIntrinsicOrAuto();
1593
1594     EWhiteSpace currWS = style()->whiteSpace();
1595     EWhiteSpace lastWS = currWS;
1596     while (o) {
1597         currWS = o->isReplaced() ? o->parent()->style()->whiteSpace() : o->style()->whiteSpace();
1598         lastWS = last->isReplaced() ? last->parent()->style()->whiteSpace() : last->style()->whiteSpace();
1599         
1600         bool autoWrap = RenderStyle::autoWrap(currWS);
1601         autoWrapWasEverTrueOnLine = autoWrapWasEverTrueOnLine || autoWrap;
1602
1603 #if ENABLE(SVG)
1604         bool preserveNewline = o->isSVGInlineText() ? false : RenderStyle::preserveNewline(currWS);
1605 #else
1606         bool preserveNewline = RenderStyle::preserveNewline(currWS);
1607 #endif
1608
1609         bool collapseWhiteSpace = RenderStyle::collapseWhiteSpace(currWS);
1610             
1611         if (o->isBR()) {
1612             if (w + tmpW <= width) {
1613                 lBreak.moveToStartOf(o);
1614                 lBreak.increment();
1615
1616                 // A <br> always breaks a line, so don't let the line be collapsed
1617                 // away. Also, the space at the end of a line with a <br> does not
1618                 // get collapsed away.  It only does this if the previous line broke
1619                 // cleanly.  Otherwise the <br> has no effect on whether the line is
1620                 // empty or not.
1621                 if (prevLineBrokeCleanly)
1622                     isLineEmpty = false;
1623                 trailingSpaceObject = 0;
1624                 previousLineBrokeCleanly = true;
1625
1626                 if (!isLineEmpty && clear)
1627                     *clear = o->style()->clear();
1628             }
1629             goto end;
1630         }
1631
1632         if (o->isFloatingOrPositioned()) {
1633             // add to special objects...
1634             if (o->isFloating()) {
1635                 RenderBox* floatBox = toRenderBox(o);
1636                 FloatingObject* f = insertFloatingObject(floatBox);
1637                 // check if it fits in the current line.
1638                 // If it does, position it now, otherwise, position
1639                 // it after moving to next line (in newLine() func)
1640                 if (floatsFitOnLine && logicalWidthForFloat(f) + w + tmpW <= width) {
1641                     positionNewFloatOnLine(f, lastFloatFromPreviousLine, firstLine, lineLeftOffset, lineRightOffset);
1642                     width = max(0, lineRightOffset - lineLeftOffset);
1643                     if (lBreak.m_obj == o) {
1644                         ASSERT(!lBreak.m_pos);
1645                         lBreak.increment();
1646                     }
1647                 } else
1648                     floatsFitOnLine = false;
1649             } else if (o->isPositioned()) {
1650                 // If our original display wasn't an inline type, then we can
1651                 // go ahead and determine our static inline position now.
1652                 RenderBox* box = toRenderBox(o);
1653                 bool isInlineType = box->style()->isOriginalDisplayInlineType();
1654                 if (!isInlineType)
1655                     box->layer()->setStaticInlinePosition(borderAndPaddingStart());
1656                 else  {
1657                     // If our original display was an INLINE type, then we can go ahead
1658                     // and determine our static y position now.
1659                     box->layer()->setStaticBlockPosition(logicalHeight());
1660                 }
1661                 
1662                 // If we're ignoring spaces, we have to stop and include this object and
1663                 // then start ignoring spaces again.
1664                 if (isInlineType || o->container()->isRenderInline()) {
1665                     if (ignoringSpaces) {
1666                         ignoreStart.m_obj = o;
1667                         ignoreStart.m_pos = 0;
1668                         addMidpoint(lineMidpointState, ignoreStart); // Stop ignoring spaces.
1669                         addMidpoint(lineMidpointState, ignoreStart); // Start ignoring again.
1670                     }
1671                     if (trailingSpaceObject)
1672                         trailingPositionedBoxes.append(box);
1673                 } else
1674                     positionedBoxes.append(box);
1675             }
1676         } else if (o->isRenderInline()) {
1677             // Right now, we should only encounter empty inlines here.
1678             ASSERT(!o->firstChild());
1679     
1680             RenderInline* flowBox = toRenderInline(o);
1681             
1682             // Now that some inline flows have line boxes, if we are already ignoring spaces, we need 
1683             // to make sure that we stop to include this object and then start ignoring spaces again. 
1684             // If this object is at the start of the line, we need to behave like list markers and 
1685             // start ignoring spaces.
1686             if (inlineFlowRequiresLineBox(flowBox)) {
1687                 isLineEmpty = false;
1688                 if (ignoringSpaces) {
1689                     trailingSpaceObject = 0;
1690                     trailingPositionedBoxes.clear();
1691                     addMidpoint(lineMidpointState, InlineIterator(0, o, 0)); // Stop ignoring spaces.
1692                     addMidpoint(lineMidpointState, InlineIterator(0, o, 0)); // Start ignoring again.
1693                 } else if (style()->collapseWhiteSpace() && resolver.position().m_obj == o
1694                     && shouldSkipWhitespaceAfterStartObject(this, o, lineMidpointState)) {
1695                     // Like with list markers, we start ignoring spaces to make sure that any 
1696                     // additional spaces we see will be discarded.
1697                     currentCharacterIsSpace = true;
1698                     currentCharacterIsWS = true;
1699                     ignoringSpaces = true;
1700                 }
1701             }
1702
1703             tmpW += flowBox->marginStart() + flowBox->borderStart() + flowBox->paddingStart() +
1704                     flowBox->marginEnd() + flowBox->borderEnd() + flowBox->paddingEnd();
1705         } else if (o->isReplaced()) {
1706             RenderBox* replacedBox = toRenderBox(o);
1707
1708             // Break on replaced elements if either has normal white-space.
1709             if ((autoWrap || RenderStyle::autoWrap(lastWS)) && (!o->isImage() || allowImagesToBreak)) {
1710                 w += tmpW;
1711                 tmpW = 0;
1712                 lBreak.moveToStartOf(o);
1713             }
1714
1715             if (ignoringSpaces)
1716                 addMidpoint(lineMidpointState, InlineIterator(0, o, 0));
1717
1718             isLineEmpty = false;
1719             ignoringSpaces = false;
1720             currentCharacterIsSpace = false;
1721             currentCharacterIsWS = false;
1722             trailingSpaceObject = 0;
1723             trailingPositionedBoxes.clear();
1724
1725             // Optimize for a common case. If we can't find whitespace after the list
1726             // item, then this is all moot.
1727             int replacedLogicalWidth = logicalWidthForChild(replacedBox) + marginStartForChild(replacedBox) + marginEndForChild(replacedBox) + inlineLogicalWidth(o);
1728             if (o->isListMarker()) {
1729                 if (style()->collapseWhiteSpace() && shouldSkipWhitespaceAfterStartObject(this, o, lineMidpointState)) {
1730                     // Like with inline flows, we start ignoring spaces to make sure that any 
1731                     // additional spaces we see will be discarded.
1732                     currentCharacterIsSpace = true;
1733                     currentCharacterIsWS = true;
1734                     ignoringSpaces = true;
1735                 }
1736                 if (toRenderListMarker(o)->isInside())
1737                     tmpW += replacedLogicalWidth;
1738             } else
1739                 tmpW += replacedLogicalWidth;
1740         } else if (o->isText()) {
1741             if (!pos)
1742                 appliedStartWidth = false;
1743
1744             RenderText* t = toRenderText(o);
1745
1746 #if ENABLE(SVG)
1747             bool isSVGText = t->isSVGInlineText();
1748 #endif
1749
1750             RenderStyle* style = t->style(firstLine);
1751             if (style->hasTextCombine() && o->isCombineText())
1752                 toRenderCombineText(o)->combineText();
1753
1754             int strlen = t->textLength();
1755             int len = strlen - pos;
1756             const UChar* str = t->characters();
1757
1758             const Font& f = style->font();
1759             bool isFixedPitch = f.isFixedPitch();
1760             bool canHyphenate = style->hyphens() == HyphensAuto && WebCore::canHyphenate(style->locale());
1761
1762             int lastSpace = pos;
1763             float wordSpacing = o->style()->wordSpacing();
1764             float lastSpaceWordSpacing = 0;
1765
1766             // Non-zero only when kerning is enabled, in which case we measure words with their trailing
1767             // space, then subtract its width.
1768             float wordTrailingSpaceWidth = f.typesettingFeatures() & Kerning ? f.width(TextRun(&space, 1)) + wordSpacing : 0;
1769
1770             float wrapW = tmpW + inlineLogicalWidth(o, !appliedStartWidth, true);
1771             float charWidth = 0;
1772             bool breakNBSP = autoWrap && o->style()->nbspMode() == SPACE;
1773             // Auto-wrapping text should wrap in the middle of a word only if it could not wrap before the word,
1774             // which is only possible if the word is the first thing on the line, that is, if |w| is zero.
1775             bool breakWords = o->style()->breakWords() && ((autoWrap && !w) || currWS == PRE);
1776             bool midWordBreak = false;
1777             bool breakAll = o->style()->wordBreak() == BreakAllWordBreak && autoWrap;
1778             float hyphenWidth = 0;
1779
1780             if (t->isWordBreak()) {
1781                 w += tmpW;
1782                 tmpW = 0;
1783                 lBreak.moveToStartOf(o);
1784                 ASSERT(!len);
1785             }
1786
1787             while (len) {
1788                 bool previousCharacterIsSpace = currentCharacterIsSpace;
1789                 bool previousCharacterIsWS = currentCharacterIsWS;
1790                 UChar c = str[pos];
1791                 currentCharacterIsSpace = c == ' ' || c == '\t' || (!preserveNewline && (c == '\n'));
1792
1793                 if (!collapseWhiteSpace || !currentCharacterIsSpace)
1794                     isLineEmpty = false;
1795
1796                 if (c == softHyphen && autoWrap && !hyphenWidth && style->hyphens() != HyphensNone) {
1797                     const AtomicString& hyphenString = style->hyphenString();
1798                     hyphenWidth = f.width(TextRun(hyphenString.characters(), hyphenString.length()));
1799                     tmpW += hyphenWidth;
1800                 }
1801
1802 #if ENABLE(SVG)
1803                 if (isSVGText) {
1804                     RenderSVGInlineText* svgInlineText = static_cast<RenderSVGInlineText*>(t);
1805                     if (pos > 0) {
1806                         if (svgInlineText->characterStartsNewTextChunk(pos)) {
1807                             addMidpoint(lineMidpointState, InlineIterator(0, o, pos - 1));
1808                             addMidpoint(lineMidpointState, InlineIterator(0, o, pos));
1809                         }
1810                     }
1811                 }
1812 #endif
1813
1814                 bool applyWordSpacing = false;
1815                 
1816                 currentCharacterIsWS = currentCharacterIsSpace || (breakNBSP && c == noBreakSpace);
1817
1818                 if ((breakAll || breakWords) && !midWordBreak) {
1819                     wrapW += charWidth;
1820                     charWidth = textWidth(t, pos, 1, f, w + wrapW, isFixedPitch, collapseWhiteSpace);
1821                     midWordBreak = w + wrapW + charWidth > width;
1822                 }
1823
1824                 if (lineBreakIteratorInfo.first != t) {
1825                     lineBreakIteratorInfo.first = t;
1826                     lineBreakIteratorInfo.second.reset(str, strlen);
1827                 }
1828
1829                 bool betweenWords = c == '\n' || (currWS != PRE && !atStart && isBreakable(lineBreakIteratorInfo.second, pos, nextBreakable, breakNBSP) && (style->hyphens() != HyphensNone || (pos && str[pos - 1] != softHyphen)));
1830
1831                 if (betweenWords || midWordBreak) {
1832                     bool stoppedIgnoringSpaces = false;
1833                     if (ignoringSpaces) {
1834                         if (!currentCharacterIsSpace) {
1835                             // Stop ignoring spaces and begin at this
1836                             // new point.
1837                             ignoringSpaces = false;
1838                             lastSpaceWordSpacing = 0;
1839                             lastSpace = pos; // e.g., "Foo    goo", don't add in any of the ignored spaces.
1840                             addMidpoint(lineMidpointState, InlineIterator(0, o, pos));
1841                             stoppedIgnoringSpaces = true;
1842                         } else {
1843                             // Just keep ignoring these spaces.
1844                             pos++;
1845                             len--;
1846                             continue;
1847                         }
1848                     }
1849
1850                     float additionalTmpW;
1851                     if (wordTrailingSpaceWidth && currentCharacterIsSpace)
1852                         additionalTmpW = textWidth(t, lastSpace, pos + 1 - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) - wordTrailingSpaceWidth + lastSpaceWordSpacing;
1853                     else
1854                         additionalTmpW = textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing;
1855                     tmpW += additionalTmpW;
1856                     if (!appliedStartWidth) {
1857                         tmpW += inlineLogicalWidth(o, true, false);
1858                         appliedStartWidth = true;
1859                     }
1860                     
1861                     applyWordSpacing =  wordSpacing && currentCharacterIsSpace && !previousCharacterIsSpace;
1862
1863                     if (!w && autoWrap && tmpW > width)
1864                         fitBelowFloats(tmpW, firstLine, width);
1865
1866                     if (autoWrap || breakWords) {
1867                         // If we break only after white-space, consider the current character
1868                         // as candidate width for this line.
1869                         bool lineWasTooWide = false;
1870                         if (w + tmpW <= width && currentCharacterIsWS && o->style()->breakOnlyAfterWhiteSpace() && !midWordBreak) {
1871                             int charWidth = textWidth(t, pos, 1, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + (applyWordSpacing ? wordSpacing : 0);
1872                             // Check if line is too big even without the extra space
1873                             // at the end of the line. If it is not, do nothing. 
1874                             // If the line needs the extra whitespace to be too long, 
1875                             // then move the line break to the space and skip all 
1876                             // additional whitespace.
1877                             if (w + tmpW + charWidth > width) {
1878                                 lineWasTooWide = true;
1879                                 lBreak.moveTo(o, pos, nextBreakable);
1880                                 skipTrailingWhitespace(lBreak, isLineEmpty, previousLineBrokeCleanly);
1881                             }
1882                         }
1883                         if (lineWasTooWide || w + tmpW > width) {
1884                             if (canHyphenate && w + tmpW > width) {
1885                                 tryHyphenating(t, f, style->locale(), style->hyphenationLimitBefore(), style->hyphenationLimitAfter(), lastSpace, pos, w + tmpW - additionalTmpW, width, isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, nextBreakable, hyphenated);
1886                                 if (hyphenated)
1887                                     goto end;
1888                             }
1889                             if (lBreak.m_obj && shouldPreserveNewline(lBreak.m_obj) && lBreak.m_obj->isText() && toRenderText(lBreak.m_obj)->textLength() && !toRenderText(lBreak.m_obj)->isWordBreak() && toRenderText(lBreak.m_obj)->characters()[lBreak.m_pos] == '\n') {
1890                                 if (!stoppedIgnoringSpaces && pos > 0) {
1891                                     // We need to stop right before the newline and then start up again.
1892                                     addMidpoint(lineMidpointState, InlineIterator(0, o, pos - 1)); // Stop
1893                                     addMidpoint(lineMidpointState, InlineIterator(0, o, pos)); // Start
1894                                 }
1895                                 lBreak.increment();
1896                                 previousLineBrokeCleanly = true;
1897                             }
1898                             if (lBreak.m_obj && lBreak.m_pos && lBreak.m_obj->isText() && toRenderText(lBreak.m_obj)->textLength() && toRenderText(lBreak.m_obj)->characters()[lBreak.m_pos - 1] == softHyphen && style->hyphens() != HyphensNone)
1899                                 hyphenated = true;
1900                             goto end; // Didn't fit. Jump to the end.
1901                         } else {
1902                             if (!betweenWords || (midWordBreak && !autoWrap))
1903                                 tmpW -= additionalTmpW;
1904                             if (hyphenWidth) {
1905                                 // Subtract the width of the soft hyphen out since we fit on a line.
1906                                 tmpW -= hyphenWidth;
1907                                 hyphenWidth = 0;
1908                             }
1909                         }
1910                     }
1911
1912                     if (c == '\n' && preserveNewline) {
1913                         if (!stoppedIgnoringSpaces && pos > 0) {
1914                             // We need to stop right before the newline and then start up again.
1915                             addMidpoint(lineMidpointState, InlineIterator(0, o, pos - 1)); // Stop
1916                             addMidpoint(lineMidpointState, InlineIterator(0, o, pos)); // Start
1917                         }
1918                         lBreak.moveTo(o, pos, nextBreakable);
1919                         lBreak.increment();
1920                         previousLineBrokeCleanly = true;
1921                         return lBreak;
1922                     }
1923
1924                     if (autoWrap && betweenWords) {
1925                         w += tmpW;
1926                         wrapW = 0;
1927                         tmpW = 0;
1928                         lBreak.moveTo(o, pos, nextBreakable);
1929                         // Auto-wrapping text should not wrap in the middle of a word once it has had an
1930                         // opportunity to break after a word.
1931                         breakWords = false;
1932                     }
1933                     
1934                     if (midWordBreak) {
1935                         // Remember this as a breakable position in case
1936                         // adding the end width forces a break.
1937                         lBreak.moveTo(o, pos, nextBreakable);
1938                         midWordBreak &= (breakWords || breakAll);
1939                     }
1940
1941                     if (betweenWords) {
1942                         lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
1943                         lastSpace = pos;
1944                     }
1945                     
1946                     if (!ignoringSpaces && o->style()->collapseWhiteSpace()) {
1947                         // If we encounter a newline, or if we encounter a
1948                         // second space, we need to go ahead and break up this
1949                         // run and enter a mode where we start collapsing spaces.
1950                         if (currentCharacterIsSpace && previousCharacterIsSpace) {
1951                             ignoringSpaces = true;
1952                             
1953                             // We just entered a mode where we are ignoring
1954                             // spaces. Create a midpoint to terminate the run
1955                             // before the second space. 
1956                             addMidpoint(lineMidpointState, ignoreStart);
1957                         }
1958                     }
1959                 } else if (ignoringSpaces) {
1960                     // Stop ignoring spaces and begin at this
1961                     // new point.
1962                     ignoringSpaces = false;
1963                     lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
1964                     lastSpace = pos; // e.g., "Foo    goo", don't add in any of the ignored spaces.
1965                     addMidpoint(lineMidpointState, InlineIterator(0, o, pos));
1966                 }
1967
1968                 if (currentCharacterIsSpace && !previousCharacterIsSpace) {
1969                     ignoreStart.m_obj = o;
1970                     ignoreStart.m_pos = pos;
1971                 }
1972
1973                 if (!currentCharacterIsWS && previousCharacterIsWS) {
1974                     if (autoWrap && o->style()->breakOnlyAfterWhiteSpace())
1975                         lBreak.moveTo(o, pos, nextBreakable);
1976                 }
1977                 
1978                 if (collapseWhiteSpace && currentCharacterIsSpace && !ignoringSpaces)
1979                     trailingSpaceObject = o;
1980                 else if (!o->style()->collapseWhiteSpace() || !currentCharacterIsSpace) {
1981                     trailingSpaceObject = 0;
1982                     trailingPositionedBoxes.clear();
1983                 }
1984                     
1985                 pos++;
1986                 len--;
1987                 atStart = false;
1988             }
1989
1990             // IMPORTANT: pos is > length here!
1991             float additionalTmpW = ignoringSpaces ? 0 : textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing;
1992             tmpW += additionalTmpW;
1993             tmpW += inlineLogicalWidth(o, !appliedStartWidth, true);
1994
1995             if (w + tmpW > width) {
1996                 if (canHyphenate)
1997                     tryHyphenating(t, f, style->locale(), style->hyphenationLimitBefore(), style->hyphenationLimitAfter(), lastSpace, pos, w + tmpW - additionalTmpW, width, isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, nextBreakable, hyphenated);
1998                 
1999                 if (!hyphenated && lBreak.m_obj && lBreak.m_pos && lBreak.m_obj->isText() && toRenderText(lBreak.m_obj)->textLength() && toRenderText(lBreak.m_obj)->characters()[lBreak.m_pos - 1] == softHyphen && style->hyphens() != HyphensNone)
2000                     hyphenated = true;
2001                 
2002                 if (hyphenated)
2003                     goto end;
2004             }
2005         } else
2006             ASSERT_NOT_REACHED();
2007
2008         RenderObject* next = bidiNext(this, o);
2009         bool checkForBreak = autoWrap;
2010         if (w && w + tmpW > width && lBreak.m_obj && currWS == NOWRAP)
2011             checkForBreak = true;
2012         else if (next && o->isText() && next->isText() && !next->isBR()) {
2013             if (autoWrap || (next->style()->autoWrap())) {
2014                 if (currentCharacterIsSpace)
2015                     checkForBreak = true;
2016                 else {
2017                     checkForBreak = false;
2018                     RenderText* nextText = toRenderText(next);
2019                     if (nextText->textLength()) {
2020                         UChar c = nextText->characters()[0];
2021                         if (c == ' ' || c == '\t' || (c == '\n' && !shouldPreserveNewline(next)))
2022                             // If the next item on the line is text, and if we did not end with
2023                             // a space, then the next text run continues our word (and so it needs to
2024                             // keep adding to |tmpW|.  Just update and continue.
2025                             checkForBreak = true;
2026                     } else if (nextText->isWordBreak())
2027                         checkForBreak = true;
2028                     bool willFitOnLine = w + tmpW <= width;
2029                     if (!willFitOnLine && !w) {
2030                         fitBelowFloats(tmpW, firstLine, width);
2031                         willFitOnLine = tmpW <= width;
2032                     }
2033                     bool canPlaceOnLine = willFitOnLine || !autoWrapWasEverTrueOnLine;
2034                     if (canPlaceOnLine && checkForBreak) {
2035                         w += tmpW;
2036                         tmpW = 0;
2037                         lBreak.moveToStartOf(next);
2038                     }
2039                 }
2040             }
2041         }
2042
2043         if (checkForBreak && (w + tmpW > width)) {
2044             // if we have floats, try to get below them.
2045             if (currentCharacterIsSpace && !ignoringSpaces && o->style()->collapseWhiteSpace()) {
2046                 trailingSpaceObject = 0;
2047                 trailingPositionedBoxes.clear();
2048             }
2049
2050             if (w)
2051                 goto end;
2052
2053             fitBelowFloats(tmpW, firstLine, width);
2054
2055             // |width| may have been adjusted because we got shoved down past a float (thus
2056             // giving us more room), so we need to retest, and only jump to
2057             // the end label if we still don't fit on the line. -dwh
2058             if (w + tmpW > width)
2059                 goto end;
2060         }
2061
2062         if (!o->isFloatingOrPositioned()) {
2063             last = o;
2064             if (last->isReplaced() && autoWrap && (!last->isImage() || allowImagesToBreak) && (!last->isListMarker() || toRenderListMarker(last)->isInside())) {
2065                 w += tmpW;
2066                 tmpW = 0;
2067                 lBreak.moveToStartOf(next);
2068             }
2069         }
2070
2071         o = next;
2072         nextBreakable = -1;
2073
2074         // Clear out our character space bool, since inline <pre>s don't collapse whitespace
2075         // with adjacent inline normal/nowrap spans.
2076         if (!collapseWhiteSpace)
2077             currentCharacterIsSpace = false;
2078         
2079         pos = 0;
2080         atStart = false;
2081     }
2082
2083     
2084     if (w + tmpW <= width || lastWS == NOWRAP)
2085         lBreak.clear();
2086
2087  end:
2088     if (lBreak == resolver.position() && (!lBreak.m_obj || !lBreak.m_obj->isBR())) {
2089         // we just add as much as possible
2090         if (style()->whiteSpace() == PRE) {
2091             // FIXME: Don't really understand this case.
2092             if (pos != 0) {
2093                 // FIXME: This should call moveTo which would clear m_nextBreakablePosition
2094                 // this code as-is is likely wrong.
2095                 lBreak.m_obj = o;
2096                 lBreak.m_pos = pos - 1;
2097             } else
2098                 lBreak.moveTo(last, last->isText() ? last->length() : 0);
2099         } else if (lBreak.m_obj) {
2100             // Don't ever break in the middle of a word if we can help it.
2101             // There's no room at all. We just have to be on this line,
2102             // even though we'll spill out.
2103             lBreak.moveTo(o, pos);
2104         }
2105     }
2106
2107     // make sure we consume at least one char/object.
2108     if (lBreak == resolver.position())
2109         lBreak.increment();
2110
2111     // Sanity check our midpoints.
2112     checkMidpoints(lineMidpointState, lBreak);
2113         
2114     if (trailingSpaceObject) {
2115         // This object is either going to be part of the last midpoint, or it is going
2116         // to be the actual endpoint.  In both cases we just decrease our pos by 1 level to
2117         // exclude the space, allowing it to - in effect - collapse into the newline.
2118         if (lineMidpointState.numMidpoints % 2) {
2119             // Find the trailing space object's midpoint.
2120             int trailingSpaceMidpoint = lineMidpointState.numMidpoints - 1;
2121             for ( ; trailingSpaceMidpoint >= 0 && lineMidpointState.midpoints[trailingSpaceMidpoint].m_obj != trailingSpaceObject; --trailingSpaceMidpoint) { }
2122             ASSERT(trailingSpaceMidpoint >= 0);
2123             lineMidpointState.midpoints[trailingSpaceMidpoint].m_pos--;
2124
2125             // Now make sure every single trailingPositionedBox following the trailingSpaceMidpoint properly stops and starts 
2126             // ignoring spaces.
2127             size_t currentMidpoint = trailingSpaceMidpoint + 1;
2128             for (size_t i = 0; i < trailingPositionedBoxes.size(); ++i) {
2129                 if (currentMidpoint >= lineMidpointState.numMidpoints) {
2130                     // We don't have a midpoint for this box yet.
2131                     InlineIterator ignoreStart(this, trailingPositionedBoxes[i], 0);
2132                     addMidpoint(lineMidpointState, ignoreStart); // Stop ignoring.
2133                     addMidpoint(lineMidpointState, ignoreStart); // Start ignoring again.
2134                 } else {
2135                     ASSERT(lineMidpointState.midpoints[currentMidpoint].m_obj == trailingPositionedBoxes[i]);
2136                     ASSERT(lineMidpointState.midpoints[currentMidpoint + 1].m_obj == trailingPositionedBoxes[i]);
2137                 }
2138                 currentMidpoint += 2;
2139             }
2140         } else if (!lBreak.m_obj && trailingSpaceObject->isText()) {
2141             // Add a new end midpoint that stops right at the very end.
2142             RenderText* text = toRenderText(trailingSpaceObject);
2143             unsigned length = text->textLength();
2144             unsigned pos = length >= 2 ? length - 2 : UINT_MAX;
2145             InlineIterator endMid(0, trailingSpaceObject, pos);
2146             addMidpoint(lineMidpointState, endMid);
2147             for (size_t i = 0; i < trailingPositionedBoxes.size(); ++i) {
2148                 ignoreStart.m_obj = trailingPositionedBoxes[i];
2149                 ignoreStart.m_pos = 0;
2150                 addMidpoint(lineMidpointState, ignoreStart); // Stop ignoring spaces.
2151                 addMidpoint(lineMidpointState, ignoreStart); // Start ignoring again.
2152             }
2153         }
2154     }
2155
2156     // We might have made lBreak an iterator that points past the end
2157     // of the object. Do this adjustment to make it point to the start
2158     // of the next object instead to avoid confusing the rest of the
2159     // code.
2160     if (lBreak.m_pos > 0) {
2161         lBreak.m_pos--;
2162         lBreak.increment();
2163     }
2164
2165     return lBreak;
2166 }
2167
2168 void RenderBlock::addOverflowFromInlineChildren()
2169 {
2170     int endPadding = hasOverflowClip() ? paddingEnd() : 0;
2171     // FIXME: Need to find another way to do this, since scrollbars could show when we don't want them to.
2172     if (hasOverflowClip() && !endPadding && node() && node()->rendererIsEditable() && node() == node()->rootEditableElement() && style()->isLeftToRightDirection())
2173         endPadding = 1;
2174     for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
2175         addLayoutOverflow(curr->paddedLayoutOverflowRect(endPadding));
2176         if (!hasOverflowClip())
2177             addVisualOverflow(curr->visualOverflowRect(curr->lineTop(), curr->lineBottom()));
2178     }
2179 }
2180
2181 void RenderBlock::deleteEllipsisLineBoxes()
2182 {
2183     for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox())
2184         curr->clearTruncation();
2185 }
2186
2187 void RenderBlock::checkLinesForTextOverflow()
2188 {
2189     // Determine the width of the ellipsis using the current font.
2190     // FIXME: CSS3 says this is configurable, also need to use 0x002E (FULL STOP) if horizontal ellipsis is "not renderable"
2191     TextRun ellipsisRun(&horizontalEllipsis, 1);
2192     DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1));
2193     const Font& firstLineFont = firstLineStyle()->font();
2194     const Font& font = style()->font();
2195     int firstLineEllipsisWidth = firstLineFont.width(ellipsisRun);
2196     int ellipsisWidth = (font == firstLineFont) ? firstLineEllipsisWidth : font.width(ellipsisRun);
2197
2198     // For LTR text truncation, we want to get the right edge of our padding box, and then we want to see
2199     // if the right edge of a line box exceeds that.  For RTL, we use the left edge of the padding box and
2200     // check the left edge of the line box to see if it is less
2201     // Include the scrollbar for overflow blocks, which means we want to use "contentWidth()"
2202     bool ltr = style()->isLeftToRightDirection();
2203     for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
2204         int blockRightEdge = logicalRightOffsetForLine(curr->y(), curr == firstRootBox());
2205         int blockLeftEdge = logicalLeftOffsetForLine(curr->y(), curr == firstRootBox());
2206         int lineBoxEdge = ltr ? curr->x() + curr->logicalWidth() : curr->x();
2207         if ((ltr && lineBoxEdge > blockRightEdge) || (!ltr && lineBoxEdge < blockLeftEdge)) {
2208             // This line spills out of our box in the appropriate direction.  Now we need to see if the line
2209             // can be truncated.  In order for truncation to be possible, the line must have sufficient space to
2210             // accommodate our truncation string, and no replaced elements (images, tables) can overlap the ellipsis
2211             // space.
2212             int width = curr == firstRootBox() ? firstLineEllipsisWidth : ellipsisWidth;
2213             int blockEdge = ltr ? blockRightEdge : blockLeftEdge;
2214             if (curr->lineCanAccommodateEllipsis(ltr, blockEdge, lineBoxEdge, width))
2215                 curr->placeEllipsis(ellipsisStr, ltr, blockLeftEdge, blockRightEdge, width);
2216         }
2217     }
2218 }
2219
2220 }