Home | History | Annotate | Download | only in line
      1 /*
      2  * Copyright (C) 2000 Lars Knoll (knoll (at) 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  * Copyright (C) 2013 Adobe Systems Incorporated.
      6  *
      7  * This library is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU Library General Public
      9  * License as published by the Free Software Foundation; either
     10  * version 2 of the License, or (at your option) any later version.
     11  *
     12  * This library is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  * Library General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU Library General Public License
     18  * along with this library; see the file COPYING.LIB.  If not, write to
     19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     20  * Boston, MA 02110-1301, USA.
     21  *
     22  */
     23 
     24 #ifndef BreakingContextInlineHeaders_h
     25 #define BreakingContextInlineHeaders_h
     26 
     27 #include "core/rendering/InlineIterator.h"
     28 #include "core/rendering/InlineTextBox.h"
     29 #include "core/rendering/LineWidth.h"
     30 #include "core/rendering/RenderCombineText.h"
     31 #include "core/rendering/RenderInline.h"
     32 #include "core/rendering/break_lines.h"
     33 #include "core/rendering/line/LineInfo.h"
     34 #include "core/rendering/shapes/ShapeInsideInfo.h"
     35 #include "core/rendering/svg/RenderSVGInlineText.h"
     36 
     37 namespace WebCore {
     38 
     39 using namespace std;
     40 using namespace WTF;
     41 using namespace Unicode;
     42 
     43 // We don't let our line box tree for a single line get any deeper than this.
     44 const unsigned cMaxLineDepth = 200;
     45 
     46 struct RenderTextInfo {
     47     // Destruction of m_layout requires TextLayout to be a complete type, so the constructor and destructor are made non-inline to avoid compilation errors.
     48     RenderTextInfo();
     49     ~RenderTextInfo();
     50 
     51     RenderText* m_text;
     52     OwnPtr<TextLayout> m_layout;
     53     LazyLineBreakIterator m_lineBreakIterator;
     54     const Font* m_font;
     55 
     56     void createLayout(RenderText* renderText, float xPos, bool collapseWhiteSpace)
     57     {
     58 #if OS(MACOSX)
     59         m_layout = m_font->createLayoutForMacComplexText(RenderBlockFlow::constructTextRun(renderText, *m_font, renderText, renderText->style()), renderText->textLength(), xPos, collapseWhiteSpace);
     60 #else
     61         m_layout = nullptr;
     62 #endif
     63     }
     64 };
     65 
     66 class WordMeasurement {
     67 public:
     68     WordMeasurement()
     69         : renderer(0)
     70         , width(0)
     71         , startOffset(0)
     72         , endOffset(0)
     73     {
     74     }
     75 
     76     RenderText* renderer;
     77     float width;
     78     int startOffset;
     79     int endOffset;
     80     HashSet<const SimpleFontData*> fallbackFonts;
     81 };
     82 
     83 // Don't call this directly. Use one of the descriptive helper functions below.
     84 inline void deprecatedAddMidpoint(LineMidpointState& lineMidpointState, const InlineIterator& midpoint)
     85 {
     86     if (lineMidpointState.midpoints.size() <= lineMidpointState.numMidpoints)
     87         lineMidpointState.midpoints.grow(lineMidpointState.numMidpoints + 10);
     88 
     89     InlineIterator* midpoints = lineMidpointState.midpoints.data();
     90     midpoints[lineMidpointState.numMidpoints++] = midpoint;
     91 }
     92 
     93 inline void startIgnoringSpaces(LineMidpointState& lineMidpointState, const InlineIterator& midpoint)
     94 {
     95     ASSERT(!(lineMidpointState.numMidpoints % 2));
     96     deprecatedAddMidpoint(lineMidpointState, midpoint);
     97 }
     98 
     99 inline void stopIgnoringSpaces(LineMidpointState& lineMidpointState, const InlineIterator& midpoint)
    100 {
    101     ASSERT(lineMidpointState.numMidpoints % 2);
    102     deprecatedAddMidpoint(lineMidpointState, midpoint);
    103 }
    104 
    105 // When ignoring spaces, this needs to be called for objects that need line boxes such as RenderInlines or
    106 // hard line breaks to ensure that they're not ignored.
    107 inline void ensureLineBoxInsideIgnoredSpaces(LineMidpointState& lineMidpointState, RenderObject* renderer)
    108 {
    109     InlineIterator midpoint(0, renderer, 0);
    110     stopIgnoringSpaces(lineMidpointState, midpoint);
    111     startIgnoringSpaces(lineMidpointState, midpoint);
    112 }
    113 
    114 // Adding a pair of midpoints before a character will split it out into a new line box.
    115 inline void ensureCharacterGetsLineBox(LineMidpointState& lineMidpointState, InlineIterator& textParagraphSeparator)
    116 {
    117     InlineIterator midpoint(0, textParagraphSeparator.object(), textParagraphSeparator.m_pos);
    118     startIgnoringSpaces(lineMidpointState, InlineIterator(0, textParagraphSeparator.object(), textParagraphSeparator.m_pos - 1));
    119     stopIgnoringSpaces(lineMidpointState, InlineIterator(0, textParagraphSeparator.object(), textParagraphSeparator.m_pos));
    120 }
    121 
    122 class TrailingObjects {
    123 public:
    124     TrailingObjects();
    125     void setTrailingWhitespace(RenderText*);
    126     void clear();
    127     void appendBoxIfNeeded(RenderBox*);
    128 
    129     enum CollapseFirstSpaceOrNot { DoNotCollapseFirstSpace, CollapseFirstSpace };
    130 
    131     void updateMidpointsForTrailingBoxes(LineMidpointState&, const InlineIterator& lBreak, CollapseFirstSpaceOrNot);
    132 
    133 private:
    134     RenderText* m_whitespace;
    135     Vector<RenderBox*, 4> m_boxes;
    136 };
    137 
    138 TrailingObjects::TrailingObjects()
    139     : m_whitespace(0)
    140 {
    141 }
    142 
    143 inline void TrailingObjects::setTrailingWhitespace(RenderText* whitespace)
    144 {
    145     ASSERT(whitespace);
    146     m_whitespace = whitespace;
    147 }
    148 
    149 inline void TrailingObjects::clear()
    150 {
    151     m_whitespace = 0;
    152     // Using resize(0) rather than clear() here saves 2% on
    153     // PerformanceTests/Layout/line-layout.html because we avoid freeing and
    154     // re-allocating the underlying buffer repeatedly.
    155     m_boxes.resize(0);
    156 }
    157 
    158 inline void TrailingObjects::appendBoxIfNeeded(RenderBox* box)
    159 {
    160     if (m_whitespace)
    161         m_boxes.append(box);
    162 }
    163 
    164 void TrailingObjects::updateMidpointsForTrailingBoxes(LineMidpointState& lineMidpointState, const InlineIterator& lBreak, CollapseFirstSpaceOrNot collapseFirstSpace)
    165 {
    166     if (!m_whitespace)
    167         return;
    168 
    169     // This object is either going to be part of the last midpoint, or it is going to be the actual endpoint.
    170     // In both cases we just decrease our pos by 1 level to exclude the space, allowing it to - in effect - collapse into the newline.
    171     if (lineMidpointState.numMidpoints % 2) {
    172         // Find the trailing space object's midpoint.
    173         int trailingSpaceMidpoint = lineMidpointState.numMidpoints - 1;
    174         for ( ; trailingSpaceMidpoint > 0 && lineMidpointState.midpoints[trailingSpaceMidpoint].object() != m_whitespace; --trailingSpaceMidpoint) { }
    175         ASSERT(trailingSpaceMidpoint >= 0);
    176         if (collapseFirstSpace == CollapseFirstSpace)
    177             lineMidpointState.midpoints[trailingSpaceMidpoint].m_pos--;
    178 
    179         // Now make sure every single trailingPositionedBox following the trailingSpaceMidpoint properly stops and starts
    180         // ignoring spaces.
    181         size_t currentMidpoint = trailingSpaceMidpoint + 1;
    182         for (size_t i = 0; i < m_boxes.size(); ++i) {
    183             if (currentMidpoint >= lineMidpointState.numMidpoints) {
    184                 // We don't have a midpoint for this box yet.
    185                 ensureLineBoxInsideIgnoredSpaces(lineMidpointState, m_boxes[i]);
    186             } else {
    187                 ASSERT(lineMidpointState.midpoints[currentMidpoint].object() == m_boxes[i]);
    188                 ASSERT(lineMidpointState.midpoints[currentMidpoint + 1].object() == m_boxes[i]);
    189             }
    190             currentMidpoint += 2;
    191         }
    192     } else if (!lBreak.object()) {
    193         ASSERT(m_whitespace->isText());
    194         ASSERT(collapseFirstSpace == CollapseFirstSpace);
    195         // Add a new end midpoint that stops right at the very end.
    196         unsigned length = m_whitespace->textLength();
    197         unsigned pos = length >= 2 ? length - 2 : UINT_MAX;
    198         InlineIterator endMid(0, m_whitespace, pos);
    199         startIgnoringSpaces(lineMidpointState, endMid);
    200         for (size_t i = 0; i < m_boxes.size(); ++i) {
    201             ensureLineBoxInsideIgnoredSpaces(lineMidpointState, m_boxes[i]);
    202         }
    203     }
    204 }
    205 
    206 class BreakingContext {
    207 public:
    208     BreakingContext(InlineBidiResolver& resolver, LineInfo& inLineInfo, LineWidth& lineWidth, RenderTextInfo& inRenderTextInfo, FloatingObject* inLastFloatFromPreviousLine, bool appliedStartWidth, RenderBlockFlow* block)
    209         : m_resolver(resolver)
    210         , m_current(resolver.position())
    211         , m_lineBreak(resolver.position())
    212         , m_block(block)
    213         , m_lastObject(m_current.object())
    214         , m_nextObject(0)
    215         , m_currentStyle(0)
    216         , m_blockStyle(block->style())
    217         , m_lineInfo(inLineInfo)
    218         , m_renderTextInfo(inRenderTextInfo)
    219         , m_lastFloatFromPreviousLine(inLastFloatFromPreviousLine)
    220         , m_width(lineWidth)
    221         , m_currWS(NORMAL)
    222         , m_lastWS(NORMAL)
    223         , m_preservesNewline(false)
    224         , m_atStart(true)
    225         , m_ignoringSpaces(false)
    226         , m_currentCharacterIsSpace(false)
    227         , m_currentCharacterShouldCollapseIfPreWap(false)
    228         , m_appliedStartWidth(appliedStartWidth)
    229         , m_includeEndWidth(true)
    230         , m_autoWrap(false)
    231         , m_autoWrapWasEverTrueOnLine(false)
    232         , m_floatsFitOnLine(true)
    233         , m_collapseWhiteSpace(false)
    234         , m_startingNewParagraph(m_lineInfo.previousLineBrokeCleanly())
    235         , m_allowImagesToBreak(!block->document().inQuirksMode() || !block->isTableCell() || !m_blockStyle->logicalWidth().isIntrinsicOrAuto())
    236         , m_atEnd(false)
    237         , m_lineMidpointState(resolver.midpointState())
    238     {
    239         m_lineInfo.setPreviousLineBrokeCleanly(false);
    240     }
    241 
    242     RenderObject* currentObject() { return m_current.object(); }
    243     InlineIterator lineBreak() { return m_lineBreak; }
    244     bool atEnd() { return m_atEnd; }
    245 
    246     void initializeForCurrentObject();
    247 
    248     void increment();
    249 
    250     void handleBR(EClear&);
    251     void handleOutOfFlowPositioned(Vector<RenderBox*>& positionedObjects);
    252     void handleFloat();
    253     void handleEmptyInline();
    254     void handleReplaced();
    255     bool handleText(WordMeasurements&, bool& hyphenated);
    256     void commitAndUpdateLineBreakIfNeeded();
    257     InlineIterator handleEndOfLine();
    258 
    259     void clearLineBreakIfFitsOnLine()
    260     {
    261         if (m_width.fitsOnLine() || m_lastWS == NOWRAP)
    262             m_lineBreak.clear();
    263     }
    264 
    265 private:
    266     void skipTrailingWhitespace(InlineIterator&, const LineInfo&);
    267 
    268     InlineBidiResolver& m_resolver;
    269 
    270     InlineIterator m_current;
    271     InlineIterator m_lineBreak;
    272     InlineIterator m_startOfIgnoredSpaces;
    273 
    274     RenderBlockFlow* m_block;
    275     RenderObject* m_lastObject;
    276     RenderObject* m_nextObject;
    277 
    278     RenderStyle* m_currentStyle;
    279     RenderStyle* m_blockStyle;
    280 
    281     LineInfo& m_lineInfo;
    282 
    283     RenderTextInfo& m_renderTextInfo;
    284 
    285     FloatingObject* m_lastFloatFromPreviousLine;
    286 
    287     LineWidth m_width;
    288 
    289     EWhiteSpace m_currWS;
    290     EWhiteSpace m_lastWS;
    291 
    292     bool m_preservesNewline;
    293     bool m_atStart;
    294     bool m_ignoringSpaces;
    295     bool m_currentCharacterIsSpace;
    296     bool m_currentCharacterShouldCollapseIfPreWap;
    297     bool m_appliedStartWidth;
    298     bool m_includeEndWidth;
    299     bool m_autoWrap;
    300     bool m_autoWrapWasEverTrueOnLine;
    301     bool m_floatsFitOnLine;
    302     bool m_collapseWhiteSpace;
    303     bool m_startingNewParagraph;
    304     bool m_allowImagesToBreak;
    305     bool m_atEnd;
    306 
    307     LineMidpointState& m_lineMidpointState;
    308 
    309     TrailingObjects m_trailingObjects;
    310 };
    311 
    312 enum WhitespacePosition { LeadingWhitespace, TrailingWhitespace };
    313 
    314 inline bool shouldCollapseWhiteSpace(const RenderStyle* style, const LineInfo& lineInfo, WhitespacePosition whitespacePosition)
    315 {
    316     // CSS2 16.6.1
    317     // If a space (U+0020) at the beginning of a line has 'white-space' set to 'normal', 'nowrap', or 'pre-line', it is removed.
    318     // If a space (U+0020) at the end of a line has 'white-space' set to 'normal', 'nowrap', or 'pre-line', it is also removed.
    319     // If spaces (U+0020) or tabs (U+0009) at the end of a line have 'white-space' set to 'pre-wrap', UAs may visually collapse them.
    320     return style->collapseWhiteSpace()
    321         || (whitespacePosition == TrailingWhitespace && style->whiteSpace() == PRE_WRAP && (!lineInfo.isEmpty() || !lineInfo.previousLineBrokeCleanly()));
    322 }
    323 
    324 inline bool requiresLineBoxForContent(RenderInline* flow, const LineInfo& lineInfo)
    325 {
    326     RenderObject* parent = flow->parent();
    327     if (flow->document().inNoQuirksMode()
    328         && (flow->style(lineInfo.isFirstLine())->lineHeight() != parent->style(lineInfo.isFirstLine())->lineHeight()
    329         || flow->style()->verticalAlign() != parent->style()->verticalAlign()
    330         || !parent->style()->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(flow->style()->font().fontMetrics())))
    331         return true;
    332     return false;
    333 }
    334 
    335 inline bool alwaysRequiresLineBox(RenderObject* flow)
    336 {
    337     // FIXME: Right now, we only allow line boxes for inlines that are truly empty.
    338     // We need to fix this, though, because at the very least, inlines containing only
    339     // ignorable whitespace should should also have line boxes.
    340     return isEmptyInline(flow) && toRenderInline(flow)->hasInlineDirectionBordersPaddingOrMargin();
    341 }
    342 
    343 inline bool requiresLineBox(const InlineIterator& it, const LineInfo& lineInfo = LineInfo(), WhitespacePosition whitespacePosition = LeadingWhitespace)
    344 {
    345     if (it.object()->isFloatingOrOutOfFlowPositioned())
    346         return false;
    347 
    348     if (it.object()->isRenderInline() && !alwaysRequiresLineBox(it.object()) && !requiresLineBoxForContent(toRenderInline(it.object()), lineInfo))
    349         return false;
    350 
    351     if (!shouldCollapseWhiteSpace(it.object()->style(), lineInfo, whitespacePosition) || it.object()->isBR())
    352         return true;
    353 
    354     UChar current = it.current();
    355     bool notJustWhitespace = current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || it.object()->preservesNewline());
    356     return notJustWhitespace || isEmptyInline(it.object());
    357 }
    358 
    359 inline void setStaticPositions(RenderBlockFlow* block, RenderBox* child)
    360 {
    361     // FIXME: The math here is actually not really right. It's a best-guess approximation that
    362     // will work for the common cases
    363     RenderObject* containerBlock = child->container();
    364     LayoutUnit blockHeight = block->logicalHeight();
    365     if (containerBlock->isRenderInline()) {
    366         // A relative positioned inline encloses us. In this case, we also have to determine our
    367         // position as though we were an inline. Set |staticInlinePosition| and |staticBlockPosition| on the relative positioned
    368         // inline so that we can obtain the value later.
    369         toRenderInline(containerBlock)->layer()->setStaticInlinePosition(block->startAlignedOffsetForLine(blockHeight, false));
    370         toRenderInline(containerBlock)->layer()->setStaticBlockPosition(blockHeight);
    371     }
    372     block->updateStaticInlinePositionForChild(child, blockHeight);
    373     child->layer()->setStaticBlockPosition(blockHeight);
    374 }
    375 
    376 // FIXME: The entire concept of the skipTrailingWhitespace function is flawed, since we really need to be building
    377 // line boxes even for containers that may ultimately collapse away. Otherwise we'll never get positioned
    378 // elements quite right. In other words, we need to build this function's work into the normal line
    379 // object iteration process.
    380 // NB. this function will insert any floating elements that would otherwise
    381 // be skipped but it will not position them.
    382 inline void BreakingContext::skipTrailingWhitespace(InlineIterator& iterator, const LineInfo& lineInfo)
    383 {
    384     while (!iterator.atEnd() && !requiresLineBox(iterator, lineInfo, TrailingWhitespace)) {
    385         RenderObject* object = iterator.object();
    386         if (object->isOutOfFlowPositioned())
    387             setStaticPositions(m_block, toRenderBox(object));
    388         else if (object->isFloating())
    389             m_block->insertFloatingObject(toRenderBox(object));
    390         iterator.increment();
    391     }
    392 }
    393 
    394 inline void BreakingContext::initializeForCurrentObject()
    395 {
    396     m_currentStyle = m_current.object()->style();
    397     m_nextObject = bidiNextSkippingEmptyInlines(m_block, m_current.object());
    398     if (m_nextObject && m_nextObject->parent() && !m_nextObject->parent()->isDescendantOf(m_current.object()->parent()))
    399         m_includeEndWidth = true;
    400 
    401     m_currWS = m_current.object()->isReplaced() ? m_current.object()->parent()->style()->whiteSpace() : m_currentStyle->whiteSpace();
    402     m_lastWS = m_lastObject->isReplaced() ? m_lastObject->parent()->style()->whiteSpace() : m_lastObject->style()->whiteSpace();
    403 
    404     m_autoWrap = RenderStyle::autoWrap(m_currWS);
    405     m_autoWrapWasEverTrueOnLine = m_autoWrapWasEverTrueOnLine || m_autoWrap;
    406 
    407     m_preservesNewline = m_current.object()->isSVGInlineText() ? false : RenderStyle::preserveNewline(m_currWS);
    408 
    409     m_collapseWhiteSpace = RenderStyle::collapseWhiteSpace(m_currWS);
    410 }
    411 
    412 inline void BreakingContext::increment()
    413 {
    414     // Clear out our character space bool, since inline <pre>s don't collapse whitespace
    415     // with adjacent inline normal/nowrap spans.
    416     if (!m_collapseWhiteSpace)
    417         m_currentCharacterIsSpace = false;
    418 
    419     m_current.moveToStartOf(m_nextObject);
    420     m_atStart = false;
    421 }
    422 
    423 inline void BreakingContext::handleBR(EClear& clear)
    424 {
    425     if (m_width.fitsOnLine()) {
    426         RenderObject* br = m_current.object();
    427         m_lineBreak.moveToStartOf(br);
    428         m_lineBreak.increment();
    429 
    430         // A <br> always breaks a line, so don't let the line be collapsed
    431         // away. Also, the space at the end of a line with a <br> does not
    432         // get collapsed away. It only does this if the previous line broke
    433         // cleanly. Otherwise the <br> has no effect on whether the line is
    434         // empty or not.
    435         if (m_startingNewParagraph)
    436             m_lineInfo.setEmpty(false, m_block, &m_width);
    437         m_trailingObjects.clear();
    438         m_lineInfo.setPreviousLineBrokeCleanly(true);
    439 
    440         // A <br> with clearance always needs a linebox in case the lines below it get dirtied later and
    441         // need to check for floats to clear - so if we're ignoring spaces, stop ignoring them and add a
    442         // run for this object.
    443         if (m_ignoringSpaces && m_currentStyle->clear() != CNONE)
    444             ensureLineBoxInsideIgnoredSpaces(m_lineMidpointState, br);
    445 
    446         if (!m_lineInfo.isEmpty())
    447             clear = m_currentStyle->clear();
    448     }
    449     m_atEnd = true;
    450 }
    451 
    452 inline LayoutUnit borderPaddingMarginStart(RenderInline* child)
    453 {
    454     return child->marginStart() + child->paddingStart() + child->borderStart();
    455 }
    456 
    457 inline LayoutUnit borderPaddingMarginEnd(RenderInline* child)
    458 {
    459     return child->marginEnd() + child->paddingEnd() + child->borderEnd();
    460 }
    461 
    462 inline bool shouldAddBorderPaddingMargin(RenderObject* child, bool &checkSide)
    463 {
    464     if (!child || (child->isText() && !toRenderText(child)->textLength()))
    465         return true;
    466     checkSide = false;
    467     return checkSide;
    468 }
    469 
    470 inline LayoutUnit inlineLogicalWidth(RenderObject* child, bool start = true, bool end = true)
    471 {
    472     unsigned lineDepth = 1;
    473     LayoutUnit extraWidth = 0;
    474     RenderObject* parent = child->parent();
    475     while (parent->isRenderInline() && lineDepth++ < cMaxLineDepth) {
    476         RenderInline* parentAsRenderInline = toRenderInline(parent);
    477         if (!isEmptyInline(parentAsRenderInline)) {
    478             if (start && shouldAddBorderPaddingMargin(child->previousSibling(), start))
    479                 extraWidth += borderPaddingMarginStart(parentAsRenderInline);
    480             if (end && shouldAddBorderPaddingMargin(child->nextSibling(), end))
    481                 extraWidth += borderPaddingMarginEnd(parentAsRenderInline);
    482             if (!start && !end)
    483                 return extraWidth;
    484         }
    485         child = parent;
    486         parent = child->parent();
    487     }
    488     return extraWidth;
    489 }
    490 
    491 inline void BreakingContext::handleOutOfFlowPositioned(Vector<RenderBox*>& positionedObjects)
    492 {
    493     // If our original display wasn't an inline type, then we can
    494     // go ahead and determine our static inline position now.
    495     RenderBox* box = toRenderBox(m_current.object());
    496     bool isInlineType = box->style()->isOriginalDisplayInlineType();
    497     if (!isInlineType) {
    498         m_block->setStaticInlinePositionForChild(box, m_block->logicalHeight(), m_block->startOffsetForContent(m_block->logicalHeight()));
    499     } else {
    500         // If our original display was an INLINE type, then we can go ahead
    501         // and determine our static y position now.
    502         box->layer()->setStaticBlockPosition(m_block->logicalHeight());
    503     }
    504 
    505     // If we're ignoring spaces, we have to stop and include this object and
    506     // then start ignoring spaces again.
    507     if (isInlineType || box->container()->isRenderInline()) {
    508         if (m_ignoringSpaces)
    509             ensureLineBoxInsideIgnoredSpaces(m_lineMidpointState, box);
    510         m_trailingObjects.appendBoxIfNeeded(box);
    511     } else {
    512         positionedObjects.append(box);
    513     }
    514     m_width.addUncommittedWidth(inlineLogicalWidth(box));
    515     // Reset prior line break context characters.
    516     m_renderTextInfo.m_lineBreakIterator.resetPriorContext();
    517 }
    518 
    519 inline void BreakingContext::handleFloat()
    520 {
    521     RenderBox* floatBox = toRenderBox(m_current.object());
    522     FloatingObject* floatingObject = m_block->insertFloatingObject(floatBox);
    523     // check if it fits in the current line.
    524     // If it does, position it now, otherwise, position
    525     // it after moving to next line (in newLine() func)
    526     // FIXME: Bug 110372: Properly position multiple stacked floats with non-rectangular shape outside.
    527     if (m_floatsFitOnLine && m_width.fitsOnLine(m_block->logicalWidthForFloat(floatingObject))) {
    528         m_block->positionNewFloatOnLine(floatingObject, m_lastFloatFromPreviousLine, m_lineInfo, m_width);
    529         if (m_lineBreak.object() == m_current.object()) {
    530             ASSERT(!m_lineBreak.m_pos);
    531             m_lineBreak.increment();
    532         }
    533     } else {
    534         m_floatsFitOnLine = false;
    535     }
    536     // Update prior line break context characters, using U+FFFD (OBJECT REPLACEMENT CHARACTER) for floating element.
    537     m_renderTextInfo.m_lineBreakIterator.updatePriorContext(replacementCharacter);
    538 }
    539 
    540 // This is currently just used for list markers and inline flows that have line boxes. Neither should
    541 // have an effect on whitespace at the start of the line.
    542 inline bool shouldSkipWhitespaceAfterStartObject(RenderBlockFlow* block, RenderObject* o, LineMidpointState& lineMidpointState)
    543 {
    544     RenderObject* next = bidiNextSkippingEmptyInlines(block, o);
    545     while (next && next->isFloatingOrOutOfFlowPositioned())
    546         next = bidiNextSkippingEmptyInlines(block, next);
    547 
    548     if (next && !next->isBR() && next->isText() && toRenderText(next)->textLength() > 0) {
    549         RenderText* nextText = toRenderText(next);
    550         UChar nextChar = nextText->characterAt(0);
    551         if (nextText->style()->isCollapsibleWhiteSpace(nextChar)) {
    552             startIgnoringSpaces(lineMidpointState, InlineIterator(0, o, 0));
    553             return true;
    554         }
    555     }
    556 
    557     return false;
    558 }
    559 
    560 inline void BreakingContext::handleEmptyInline()
    561 {
    562     // This should only end up being called on empty inlines
    563     ASSERT(isEmptyInline(m_current.object()));
    564 
    565     RenderInline* flowBox = toRenderInline(m_current.object());
    566 
    567     // Now that some inline flows have line boxes, if we are already ignoring spaces, we need
    568     // to make sure that we stop to include this object and then start ignoring spaces again.
    569     // If this object is at the start of the line, we need to behave like list markers and
    570     // start ignoring spaces.
    571     bool requiresLineBox = alwaysRequiresLineBox(m_current.object());
    572     if (requiresLineBox || requiresLineBoxForContent(flowBox, m_lineInfo)) {
    573         // An empty inline that only has line-height, vertical-align or font-metrics will only get a
    574         // line box to affect the height of the line if the rest of the line is not empty.
    575         if (requiresLineBox)
    576             m_lineInfo.setEmpty(false, m_block, &m_width);
    577         if (m_ignoringSpaces) {
    578             m_trailingObjects.clear();
    579             ensureLineBoxInsideIgnoredSpaces(m_lineMidpointState, m_current.object());
    580         } else if (m_blockStyle->collapseWhiteSpace() && m_resolver.position().object() == m_current.object()
    581             && shouldSkipWhitespaceAfterStartObject(m_block, m_current.object(), m_lineMidpointState)) {
    582             // Like with list markers, we start ignoring spaces to make sure that any
    583             // additional spaces we see will be discarded.
    584             m_currentCharacterShouldCollapseIfPreWap = m_currentCharacterIsSpace = true;
    585             m_ignoringSpaces = true;
    586         }
    587     }
    588 
    589     m_width.addUncommittedWidth(inlineLogicalWidth(m_current.object()) + borderPaddingMarginStart(flowBox) + borderPaddingMarginEnd(flowBox));
    590 }
    591 
    592 inline void BreakingContext::handleReplaced()
    593 {
    594     RenderBox* replacedBox = toRenderBox(m_current.object());
    595 
    596     if (m_atStart)
    597         m_width.updateAvailableWidth(replacedBox->logicalHeight());
    598 
    599     // Break on replaced elements if either has normal white-space.
    600     if ((m_autoWrap || RenderStyle::autoWrap(m_lastWS)) && (!m_current.object()->isImage() || m_allowImagesToBreak)) {
    601         m_width.commit();
    602         m_lineBreak.moveToStartOf(m_current.object());
    603     }
    604 
    605     if (m_ignoringSpaces)
    606         stopIgnoringSpaces(m_lineMidpointState, InlineIterator(0, m_current.object(), 0));
    607 
    608     m_lineInfo.setEmpty(false, m_block, &m_width);
    609     m_ignoringSpaces = false;
    610     m_currentCharacterShouldCollapseIfPreWap = m_currentCharacterIsSpace = false;
    611     m_trailingObjects.clear();
    612 
    613     // Optimize for a common case. If we can't find whitespace after the list
    614     // item, then this is all moot.
    615     LayoutUnit replacedLogicalWidth = m_block->logicalWidthForChild(replacedBox) + m_block->marginStartForChild(replacedBox) + m_block->marginEndForChild(replacedBox) + inlineLogicalWidth(m_current.object());
    616     if (m_current.object()->isListMarker()) {
    617         if (m_blockStyle->collapseWhiteSpace() && shouldSkipWhitespaceAfterStartObject(m_block, m_current.object(), m_lineMidpointState)) {
    618             // Like with inline flows, we start ignoring spaces to make sure that any
    619             // additional spaces we see will be discarded.
    620             m_currentCharacterShouldCollapseIfPreWap = m_currentCharacterIsSpace = true;
    621             m_ignoringSpaces = true;
    622         }
    623         if (toRenderListMarker(m_current.object())->isInside())
    624             m_width.addUncommittedWidth(replacedLogicalWidth);
    625     } else {
    626         m_width.addUncommittedWidth(replacedLogicalWidth);
    627     }
    628     if (m_current.object()->isRubyRun())
    629         m_width.applyOverhang(toRenderRubyRun(m_current.object()), m_lastObject, m_nextObject);
    630     // Update prior line break context characters, using U+FFFD (OBJECT REPLACEMENT CHARACTER) for replaced element.
    631     m_renderTextInfo.m_lineBreakIterator.updatePriorContext(replacementCharacter);
    632 }
    633 
    634 inline bool iteratorIsBeyondEndOfRenderCombineText(const InlineIterator& iter, RenderCombineText* renderer)
    635 {
    636     return iter.object() == renderer && iter.m_pos >= renderer->textLength();
    637 }
    638 
    639 inline void nextCharacter(UChar& currentCharacter, UChar& lastCharacter, UChar& secondToLastCharacter)
    640 {
    641     secondToLastCharacter = lastCharacter;
    642     lastCharacter = currentCharacter;
    643 }
    644 
    645 inline float firstPositiveWidth(const WordMeasurements& wordMeasurements)
    646 {
    647     for (size_t i = 0; i < wordMeasurements.size(); ++i) {
    648         if (wordMeasurements[i].width > 0)
    649             return wordMeasurements[i].width;
    650     }
    651     return 0;
    652 }
    653 
    654 inline void updateSegmentsForShapes(RenderBlockFlow* block, const FloatingObject* lastFloatFromPreviousLine, const WordMeasurements& wordMeasurements, LineWidth& width, bool isFirstLine)
    655 {
    656     ASSERT(lastFloatFromPreviousLine);
    657 
    658     ShapeInsideInfo* shapeInsideInfo = block->layoutShapeInsideInfo();
    659     if (!lastFloatFromPreviousLine->isPlaced() || !shapeInsideInfo)
    660         return;
    661 
    662     bool isHorizontalWritingMode = block->isHorizontalWritingMode();
    663     LayoutUnit logicalOffsetFromShapeContainer = block->logicalOffsetFromShapeAncestorContainer(shapeInsideInfo->owner()).height();
    664 
    665     LayoutUnit lineLogicalTop = block->logicalHeight() + logicalOffsetFromShapeContainer;
    666     LayoutUnit lineLogicalHeight = block->lineHeight(isFirstLine, isHorizontalWritingMode ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
    667     LayoutUnit lineLogicalBottom = lineLogicalTop + lineLogicalHeight;
    668 
    669     LayoutUnit floatLogicalTop = block->logicalTopForFloat(lastFloatFromPreviousLine);
    670     LayoutUnit floatLogicalBottom = block->logicalBottomForFloat(lastFloatFromPreviousLine);
    671 
    672     bool lineOverlapsWithFloat = (floatLogicalTop < lineLogicalBottom) && (lineLogicalTop < floatLogicalBottom);
    673     if (!lineOverlapsWithFloat)
    674         return;
    675 
    676     float minSegmentWidth = firstPositiveWidth(wordMeasurements);
    677 
    678     LayoutUnit floatLogicalWidth = block->logicalWidthForFloat(lastFloatFromPreviousLine);
    679     LayoutUnit availableLogicalWidth = block->logicalWidth() - block->logicalRightForFloat(lastFloatFromPreviousLine);
    680     if (availableLogicalWidth < minSegmentWidth)
    681         block->setLogicalHeight(floatLogicalBottom);
    682 
    683     if (block->logicalHeight() < floatLogicalTop) {
    684         shapeInsideInfo->adjustLogicalLineTop(minSegmentWidth + floatLogicalWidth);
    685         block->setLogicalHeight(shapeInsideInfo->logicalLineTop() - logicalOffsetFromShapeContainer);
    686     }
    687 
    688     lineLogicalTop = block->logicalHeight() + logicalOffsetFromShapeContainer;
    689 
    690     shapeInsideInfo->updateSegmentsForLine(lineLogicalTop, lineLogicalHeight);
    691     width.updateCurrentShapeSegment();
    692     width.updateAvailableWidth();
    693 }
    694 
    695 inline float measureHyphenWidth(RenderText* renderer, const Font& font)
    696 {
    697     RenderStyle* style = renderer->style();
    698     return font.width(RenderBlockFlow::constructTextRun(renderer, font, style->hyphenString().string(), style));
    699 }
    700 
    701 ALWAYS_INLINE float textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, float xPos, bool isFixedPitch, bool collapseWhiteSpace, HashSet<const SimpleFontData*>* fallbackFonts = 0, TextLayout* layout = 0)
    702 {
    703     GlyphOverflow glyphOverflow;
    704     if (isFixedPitch || (!from && len == text->textLength()) || text->style()->hasTextCombine())
    705         return text->width(from, len, font, xPos, fallbackFonts, &glyphOverflow);
    706 
    707     if (layout)
    708         return Font::width(*layout, from, len, fallbackFonts);
    709 
    710     TextRun run = RenderBlockFlow::constructTextRun(text, font, text, from, len, text->style());
    711     run.setCharactersLength(text->textLength() - from);
    712     ASSERT(run.charactersLength() >= run.length());
    713 
    714     run.setCharacterScanForCodePath(!text->canUseSimpleFontCodePath());
    715     run.setTabSize(!collapseWhiteSpace, text->style()->tabSize());
    716     run.setXPos(xPos);
    717     return font.width(run, fallbackFonts, &glyphOverflow);
    718 }
    719 
    720 inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool& hyphenated)
    721 {
    722     if (!m_current.m_pos)
    723         m_appliedStartWidth = false;
    724 
    725     RenderText* renderText = toRenderText(m_current.object());
    726 
    727     bool isSVGText = renderText->isSVGInlineText();
    728 
    729     if (renderText->style()->hasTextCombine() && m_current.object()->isCombineText() && !toRenderCombineText(m_current.object())->isCombined()) {
    730         RenderCombineText* combineRenderer = toRenderCombineText(m_current.object());
    731         combineRenderer->combineText();
    732         // The length of the renderer's text may have changed. Increment stale iterator positions
    733         if (iteratorIsBeyondEndOfRenderCombineText(m_lineBreak, combineRenderer)) {
    734             ASSERT(iteratorIsBeyondEndOfRenderCombineText(m_resolver.position(), combineRenderer));
    735             m_lineBreak.increment();
    736             m_resolver.position().increment(&m_resolver);
    737         }
    738     }
    739 
    740     RenderStyle* style = renderText->style(m_lineInfo.isFirstLine());
    741     const Font& font = style->font();
    742     bool isFixedPitch = font.isFixedPitch();
    743 
    744     unsigned lastSpace = m_current.m_pos;
    745     float wordSpacing = m_currentStyle->wordSpacing();
    746     float lastSpaceWordSpacing = 0;
    747     float wordSpacingForWordMeasurement = 0;
    748 
    749     float wrapW = m_width.uncommittedWidth() + inlineLogicalWidth(m_current.object(), !m_appliedStartWidth, true);
    750     float charWidth = 0;
    751     // Auto-wrapping text should wrap in the middle of a word only if it could not wrap before the word,
    752     // which is only possible if the word is the first thing on the line, that is, if |w| is zero.
    753     bool breakWords = m_currentStyle->breakWords() && ((m_autoWrap && !m_width.committedWidth()) || m_currWS == PRE);
    754     bool midWordBreak = false;
    755     bool breakAll = m_currentStyle->wordBreak() == BreakAllWordBreak && m_autoWrap;
    756     float hyphenWidth = 0;
    757 
    758     if (isSVGText) {
    759         breakWords = false;
    760         breakAll = false;
    761     }
    762 
    763     if (renderText->isWordBreak()) {
    764         m_width.commit();
    765         m_lineBreak.moveToStartOf(m_current.object());
    766         ASSERT(m_current.m_pos == renderText->textLength());
    767     }
    768 
    769     if (m_renderTextInfo.m_text != renderText) {
    770         m_renderTextInfo.m_text = renderText;
    771         m_renderTextInfo.m_font = &font;
    772         m_renderTextInfo.createLayout(renderText, m_width.currentWidth(), m_collapseWhiteSpace);
    773         m_renderTextInfo.m_lineBreakIterator.resetStringAndReleaseIterator(renderText->text(), style->locale());
    774     } else if (m_renderTextInfo.m_layout && m_renderTextInfo.m_font != &font) {
    775         m_renderTextInfo.m_font = &font;
    776         m_renderTextInfo.createLayout(renderText, m_width.currentWidth(), m_collapseWhiteSpace);
    777     }
    778 
    779     TextLayout* textLayout = m_renderTextInfo.m_layout.get();
    780 
    781     // Non-zero only when kerning is enabled and TextLayout isn't used, in which case we measure
    782     // words with their trailing space, then subtract its width.
    783     float wordTrailingSpaceWidth = (font.typesettingFeatures() & Kerning) && !textLayout ? font.width(RenderBlockFlow::constructTextRun(renderText, font, &space, 1, style)) + wordSpacing : 0;
    784 
    785     UChar lastCharacter = m_renderTextInfo.m_lineBreakIterator.lastCharacter();
    786     UChar secondToLastCharacter = m_renderTextInfo.m_lineBreakIterator.secondToLastCharacter();
    787     for (; m_current.m_pos < renderText->textLength(); m_current.fastIncrementInTextNode()) {
    788         bool previousCharacterIsSpace = m_currentCharacterIsSpace;
    789         bool previousCharacterShouldCollapseIfPreWap = m_currentCharacterShouldCollapseIfPreWap;
    790         UChar c = m_current.current();
    791         m_currentCharacterShouldCollapseIfPreWap = m_currentCharacterIsSpace = c == ' ' || c == '\t' || (!m_preservesNewline && (c == '\n'));
    792 
    793         if (!m_collapseWhiteSpace || !m_currentCharacterIsSpace)
    794             m_lineInfo.setEmpty(false, m_block, &m_width);
    795 
    796         if (c == softHyphen && m_autoWrap && !hyphenWidth) {
    797             hyphenWidth = measureHyphenWidth(renderText, font);
    798             m_width.addUncommittedWidth(hyphenWidth);
    799         }
    800 
    801         bool applyWordSpacing = false;
    802 
    803         if ((breakAll || breakWords) && !midWordBreak) {
    804             wrapW += charWidth;
    805             bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && m_current.m_pos + 1 < renderText->textLength() && U16_IS_TRAIL((*renderText)[m_current.m_pos + 1]);
    806             charWidth = textWidth(renderText, m_current.m_pos, midWordBreakIsBeforeSurrogatePair ? 2 : 1, font, m_width.committedWidth() + wrapW, isFixedPitch, m_collapseWhiteSpace, 0, textLayout);
    807             midWordBreak = m_width.committedWidth() + wrapW + charWidth > m_width.availableWidth();
    808         }
    809 
    810         bool betweenWords = c == '\n' || (m_currWS != PRE && !m_atStart && isBreakable(m_renderTextInfo.m_lineBreakIterator, m_current.m_pos, m_current.m_nextBreakablePosition));
    811 
    812         if (betweenWords || midWordBreak) {
    813             bool stoppedIgnoringSpaces = false;
    814             if (m_ignoringSpaces) {
    815                 lastSpaceWordSpacing = 0;
    816                 if (!m_currentCharacterIsSpace) {
    817                     // Stop ignoring spaces and begin at this
    818                     // new point.
    819                     m_ignoringSpaces = false;
    820                     wordSpacingForWordMeasurement = 0;
    821                     lastSpace = m_current.m_pos; // e.g., "Foo    goo", don't add in any of the ignored spaces.
    822                     stopIgnoringSpaces(m_lineMidpointState, InlineIterator(0, m_current.object(), m_current.m_pos));
    823                     stoppedIgnoringSpaces = true;
    824                 } else {
    825                     // Just keep ignoring these spaces.
    826                     nextCharacter(c, lastCharacter, secondToLastCharacter);
    827                     continue;
    828                 }
    829             }
    830 
    831             wordMeasurements.grow(wordMeasurements.size() + 1);
    832             WordMeasurement& wordMeasurement = wordMeasurements.last();
    833 
    834             wordMeasurement.renderer = renderText;
    835             wordMeasurement.endOffset = m_current.m_pos;
    836             wordMeasurement.startOffset = lastSpace;
    837 
    838             float additionalTmpW;
    839             if (wordTrailingSpaceWidth && c == ' ')
    840                 additionalTmpW = textWidth(renderText, lastSpace, m_current.m_pos + 1 - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout) - wordTrailingSpaceWidth;
    841             else
    842                 additionalTmpW = textWidth(renderText, lastSpace, m_current.m_pos - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout);
    843 
    844             wordMeasurement.width = additionalTmpW + wordSpacingForWordMeasurement;
    845             additionalTmpW += lastSpaceWordSpacing;
    846             m_width.addUncommittedWidth(additionalTmpW);
    847             if (!m_appliedStartWidth) {
    848                 m_width.addUncommittedWidth(inlineLogicalWidth(m_current.object(), true, false));
    849                 m_appliedStartWidth = true;
    850             }
    851 
    852             if (m_lastFloatFromPreviousLine)
    853                 updateSegmentsForShapes(m_block, m_lastFloatFromPreviousLine, wordMeasurements, m_width, m_lineInfo.isFirstLine());
    854 
    855             applyWordSpacing = wordSpacing && m_currentCharacterIsSpace;
    856 
    857             if (!m_width.committedWidth() && m_autoWrap && !m_width.fitsOnLine())
    858                 m_width.fitBelowFloats();
    859 
    860             if (m_autoWrap || breakWords) {
    861                 // If we break only after white-space, consider the current character
    862                 // as candidate width for this line.
    863                 bool lineWasTooWide = false;
    864                 if (m_width.fitsOnLine() && m_currentCharacterIsSpace && m_currentStyle->breakOnlyAfterWhiteSpace() && !midWordBreak) {
    865                     float charWidth = textWidth(renderText, m_current.m_pos, 1, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout) + (applyWordSpacing ? wordSpacing : 0);
    866                     // Check if line is too big even without the extra space
    867                     // at the end of the line. If it is not, do nothing.
    868                     // If the line needs the extra whitespace to be too long,
    869                     // then move the line break to the space and skip all
    870                     // additional whitespace.
    871                     if (!m_width.fitsOnLine(charWidth)) {
    872                         lineWasTooWide = true;
    873                         m_lineBreak.moveTo(m_current.object(), m_current.m_pos, m_current.m_nextBreakablePosition);
    874                         skipTrailingWhitespace(m_lineBreak, m_lineInfo);
    875                     }
    876                 }
    877                 if (lineWasTooWide || !m_width.fitsOnLine()) {
    878                     if (m_lineBreak.atTextParagraphSeparator()) {
    879                         if (!stoppedIgnoringSpaces && m_current.m_pos > 0)
    880                             ensureCharacterGetsLineBox(m_lineMidpointState, m_current);
    881                         m_lineBreak.increment();
    882                         m_lineInfo.setPreviousLineBrokeCleanly(true);
    883                         wordMeasurement.endOffset = m_lineBreak.m_pos;
    884                     }
    885                     if (m_lineBreak.object() && m_lineBreak.m_pos && m_lineBreak.object()->isText() && toRenderText(m_lineBreak.object())->textLength() && toRenderText(m_lineBreak.object())->characterAt(m_lineBreak.m_pos - 1) == softHyphen)
    886                         hyphenated = true;
    887                     if (m_lineBreak.m_pos && m_lineBreak.m_pos != (unsigned)wordMeasurement.endOffset && !wordMeasurement.width) {
    888                         if (charWidth) {
    889                             wordMeasurement.endOffset = m_lineBreak.m_pos;
    890                             wordMeasurement.width = charWidth;
    891                         }
    892                     }
    893                     // Didn't fit. Jump to the end unless there's still an opportunity to collapse whitespace.
    894                     if (m_ignoringSpaces || !m_collapseWhiteSpace || !m_currentCharacterIsSpace || !previousCharacterIsSpace) {
    895                         m_atEnd = true;
    896                         return false;
    897                     }
    898                 } else {
    899                     if (!betweenWords || (midWordBreak && !m_autoWrap))
    900                         m_width.addUncommittedWidth(-additionalTmpW);
    901                     if (hyphenWidth) {
    902                         // Subtract the width of the soft hyphen out since we fit on a line.
    903                         m_width.addUncommittedWidth(-hyphenWidth);
    904                         hyphenWidth = 0;
    905                     }
    906                 }
    907             }
    908 
    909             if (c == '\n' && m_preservesNewline) {
    910                 if (!stoppedIgnoringSpaces && m_current.m_pos > 0)
    911                     ensureCharacterGetsLineBox(m_lineMidpointState, m_current);
    912                 m_lineBreak.moveTo(m_current.object(), m_current.m_pos, m_current.m_nextBreakablePosition);
    913                 m_lineBreak.increment();
    914                 m_lineInfo.setPreviousLineBrokeCleanly(true);
    915                 return true;
    916             }
    917 
    918             if (m_autoWrap && betweenWords) {
    919                 m_width.commit();
    920                 wrapW = 0;
    921                 m_lineBreak.moveTo(m_current.object(), m_current.m_pos, m_current.m_nextBreakablePosition);
    922                 // Auto-wrapping text should not wrap in the middle of a word once it has had an
    923                 // opportunity to break after a word.
    924                 breakWords = false;
    925             }
    926 
    927             if (midWordBreak && !U16_IS_TRAIL(c) && !(category(c) & (Mark_NonSpacing | Mark_Enclosing | Mark_SpacingCombining))) {
    928                 // Remember this as a breakable position in case
    929                 // adding the end width forces a break.
    930                 m_lineBreak.moveTo(m_current.object(), m_current.m_pos, m_current.m_nextBreakablePosition);
    931                 midWordBreak &= (breakWords || breakAll);
    932             }
    933 
    934             if (betweenWords) {
    935                 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
    936                 wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurement.width) ? wordSpacing : 0;
    937                 lastSpace = m_current.m_pos;
    938             }
    939 
    940             if (!m_ignoringSpaces && m_currentStyle->collapseWhiteSpace()) {
    941                 // If we encounter a newline, or if we encounter a
    942                 // second space, we need to go ahead and break up this
    943                 // run and enter a mode where we start collapsing spaces.
    944                 if (m_currentCharacterIsSpace && previousCharacterIsSpace) {
    945                     m_ignoringSpaces = true;
    946 
    947                     // We just entered a mode where we are ignoring
    948                     // spaces. Create a midpoint to terminate the run
    949                     // before the second space.
    950                     startIgnoringSpaces(m_lineMidpointState, m_startOfIgnoredSpaces);
    951                     m_trailingObjects.updateMidpointsForTrailingBoxes(m_lineMidpointState, InlineIterator(), TrailingObjects::DoNotCollapseFirstSpace);
    952                 }
    953             }
    954         } else if (m_ignoringSpaces) {
    955             // Stop ignoring spaces and begin at this
    956             // new point.
    957             m_ignoringSpaces = false;
    958             lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
    959             wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurements.last().width) ? wordSpacing : 0;
    960             lastSpace = m_current.m_pos; // e.g., "Foo    goo", don't add in any of the ignored spaces.
    961             stopIgnoringSpaces(m_lineMidpointState, InlineIterator(0, m_current.object(), m_current.m_pos));
    962         }
    963 
    964         if (isSVGText && m_current.m_pos > 0) {
    965             // Force creation of new InlineBoxes for each absolute positioned character (those that start new text chunks).
    966             if (toRenderSVGInlineText(renderText)->characterStartsNewTextChunk(m_current.m_pos))
    967                 ensureCharacterGetsLineBox(m_lineMidpointState, m_current);
    968         }
    969 
    970         if (m_currentCharacterIsSpace && !previousCharacterIsSpace) {
    971             m_startOfIgnoredSpaces.setObject(m_current.object());
    972             m_startOfIgnoredSpaces.m_pos = m_current.m_pos;
    973         }
    974 
    975         if (!m_currentCharacterIsSpace && previousCharacterShouldCollapseIfPreWap) {
    976             if (m_autoWrap && m_currentStyle->breakOnlyAfterWhiteSpace())
    977                 m_lineBreak.moveTo(m_current.object(), m_current.m_pos, m_current.m_nextBreakablePosition);
    978         }
    979 
    980         if (m_collapseWhiteSpace && m_currentCharacterIsSpace && !m_ignoringSpaces)
    981             m_trailingObjects.setTrailingWhitespace(toRenderText(m_current.object()));
    982         else if (!m_currentStyle->collapseWhiteSpace() || !m_currentCharacterIsSpace)
    983             m_trailingObjects.clear();
    984 
    985         m_atStart = false;
    986         nextCharacter(c, lastCharacter, secondToLastCharacter);
    987     }
    988 
    989     m_renderTextInfo.m_lineBreakIterator.setPriorContext(lastCharacter, secondToLastCharacter);
    990 
    991     wordMeasurements.grow(wordMeasurements.size() + 1);
    992     WordMeasurement& wordMeasurement = wordMeasurements.last();
    993     wordMeasurement.renderer = renderText;
    994 
    995     // IMPORTANT: current.m_pos is > length here!
    996     float additionalTmpW = m_ignoringSpaces ? 0 : textWidth(renderText, lastSpace, m_current.m_pos - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout);
    997     wordMeasurement.startOffset = lastSpace;
    998     wordMeasurement.endOffset = m_current.m_pos;
    999     wordMeasurement.width = m_ignoringSpaces ? 0 : additionalTmpW + wordSpacingForWordMeasurement;
   1000     additionalTmpW += lastSpaceWordSpacing;
   1001     m_width.addUncommittedWidth(additionalTmpW + inlineLogicalWidth(m_current.object(), !m_appliedStartWidth, m_includeEndWidth));
   1002     m_includeEndWidth = false;
   1003 
   1004     if (!m_width.fitsOnLine()) {
   1005         if (!hyphenated && m_lineBreak.previousInSameNode() == softHyphen) {
   1006             hyphenated = true;
   1007             m_atEnd = true;
   1008         }
   1009     }
   1010     return false;
   1011 }
   1012 
   1013 inline void BreakingContext::commitAndUpdateLineBreakIfNeeded()
   1014 {
   1015     bool checkForBreak = m_autoWrap;
   1016     if (m_width.committedWidth() && !m_width.fitsOnLine() && m_lineBreak.object() && m_currWS == NOWRAP) {
   1017         checkForBreak = true;
   1018     } else if (m_nextObject && m_current.object()->isText() && m_nextObject->isText() && !m_nextObject->isBR() && (m_autoWrap || m_nextObject->style()->autoWrap())) {
   1019         if (m_autoWrap && m_currentCharacterIsSpace) {
   1020             checkForBreak = true;
   1021         } else {
   1022             RenderText* nextText = toRenderText(m_nextObject);
   1023             if (nextText->textLength()) {
   1024                 UChar c = nextText->characterAt(0);
   1025                 // If the next item on the line is text, and if we did not end with
   1026                 // a space, then the next text run continues our word (and so it needs to
   1027                 // keep adding to the uncommitted width. Just update and continue.
   1028                 checkForBreak = !m_currentCharacterIsSpace && (c == ' ' || c == '\t' || (c == '\n' && !m_nextObject->preservesNewline()));
   1029             } else if (nextText->isWordBreak()) {
   1030                 checkForBreak = true;
   1031             }
   1032 
   1033             if (!m_width.fitsOnLine() && !m_width.committedWidth())
   1034                 m_width.fitBelowFloats();
   1035 
   1036             bool canPlaceOnLine = m_width.fitsOnLine() || !m_autoWrapWasEverTrueOnLine;
   1037             if (canPlaceOnLine && checkForBreak) {
   1038                 m_width.commit();
   1039                 m_lineBreak.moveToStartOf(m_nextObject);
   1040             }
   1041         }
   1042     }
   1043 
   1044     if (checkForBreak && !m_width.fitsOnLine()) {
   1045         // if we have floats, try to get below them.
   1046         if (m_currentCharacterIsSpace && !m_ignoringSpaces && m_currentStyle->collapseWhiteSpace())
   1047             m_trailingObjects.clear();
   1048 
   1049         if (m_width.committedWidth()) {
   1050             m_atEnd = true;
   1051             return;
   1052         }
   1053 
   1054         m_width.fitBelowFloats();
   1055 
   1056         // |width| may have been adjusted because we got shoved down past a float (thus
   1057         // giving us more room), so we need to retest, and only jump to
   1058         // the end label if we still don't fit on the line. -dwh
   1059         if (!m_width.fitsOnLine()) {
   1060             m_atEnd = true;
   1061             return;
   1062         }
   1063     } else if (m_blockStyle->autoWrap() && !m_width.fitsOnLine() && !m_width.committedWidth()) {
   1064         // If the container autowraps but the current child does not then we still need to ensure that it
   1065         // wraps and moves below any floats.
   1066         m_width.fitBelowFloats();
   1067     }
   1068 
   1069     if (!m_current.object()->isFloatingOrOutOfFlowPositioned()) {
   1070         m_lastObject = m_current.object();
   1071         if (m_lastObject->isReplaced() && m_autoWrap && (!m_lastObject->isImage() || m_allowImagesToBreak) && (!m_lastObject->isListMarker() || toRenderListMarker(m_lastObject)->isInside())) {
   1072             m_width.commit();
   1073             m_lineBreak.moveToStartOf(m_nextObject);
   1074         }
   1075     }
   1076 }
   1077 
   1078 inline void checkMidpoints(LineMidpointState& lineMidpointState, InlineIterator& lBreak)
   1079 {
   1080     // Check to see if our last midpoint is a start point beyond the line break. If so,
   1081     // shave it off the list, and shave off a trailing space if the previous end point doesn't
   1082     // preserve whitespace.
   1083     if (lBreak.object() && lineMidpointState.numMidpoints && !(lineMidpointState.numMidpoints % 2)) {
   1084         InlineIterator* midpoints = lineMidpointState.midpoints.data();
   1085         InlineIterator& endpoint = midpoints[lineMidpointState.numMidpoints - 2];
   1086         const InlineIterator& startpoint = midpoints[lineMidpointState.numMidpoints - 1];
   1087         InlineIterator currpoint = endpoint;
   1088         while (!currpoint.atEnd() && currpoint != startpoint && currpoint != lBreak)
   1089             currpoint.increment();
   1090         if (currpoint == lBreak) {
   1091             // We hit the line break before the start point. Shave off the start point.
   1092             lineMidpointState.numMidpoints--;
   1093             if (endpoint.object()->style()->collapseWhiteSpace() && endpoint.object()->isText())
   1094                 endpoint.m_pos--;
   1095         }
   1096     }
   1097 }
   1098 
   1099 InlineIterator BreakingContext::handleEndOfLine()
   1100 {
   1101     ShapeInsideInfo* shapeInfo = m_block->layoutShapeInsideInfo();
   1102     bool segmentAllowsOverflow = !shapeInfo || !shapeInfo->hasSegments();
   1103 
   1104     if (m_lineBreak == m_resolver.position() && (!m_lineBreak.object() || !m_lineBreak.object()->isBR()) && segmentAllowsOverflow) {
   1105         // we just add as much as possible
   1106         if (m_blockStyle->whiteSpace() == PRE && !m_current.m_pos) {
   1107             m_lineBreak.moveTo(m_lastObject, m_lastObject->isText() ? m_lastObject->length() : 0);
   1108         } else if (m_lineBreak.object()) {
   1109             // Don't ever break in the middle of a word if we can help it.
   1110             // There's no room at all. We just have to be on this line,
   1111             // even though we'll spill out.
   1112             m_lineBreak.moveTo(m_current.object(), m_current.m_pos);
   1113         }
   1114     }
   1115 
   1116     // FIXME Bug 100049: We do not need to consume input in a multi-segment line
   1117     // unless no segment will.
   1118     // make sure we consume at least one char/object.
   1119     if (m_lineBreak == m_resolver.position() && segmentAllowsOverflow)
   1120         m_lineBreak.increment();
   1121 
   1122     // Sanity check our midpoints.
   1123     checkMidpoints(m_lineMidpointState, m_lineBreak);
   1124 
   1125     m_trailingObjects.updateMidpointsForTrailingBoxes(m_lineMidpointState, m_lineBreak, TrailingObjects::CollapseFirstSpace);
   1126 
   1127     // We might have made lineBreak an iterator that points past the end
   1128     // of the object. Do this adjustment to make it point to the start
   1129     // of the next object instead to avoid confusing the rest of the
   1130     // code.
   1131     if (m_lineBreak.m_pos > 0) {
   1132         // This loop enforces the invariant that line breaks should never point
   1133         // at an empty inline. See http://crbug.com/305904.
   1134         do {
   1135             m_lineBreak.m_pos--;
   1136             m_lineBreak.increment();
   1137         } while (!m_lineBreak.atEnd() && isEmptyInline(m_lineBreak.object()));
   1138     }
   1139 
   1140     return m_lineBreak;
   1141 }
   1142 
   1143 }
   1144 
   1145 #endif // BreakingContextInlineHeaders_h
   1146