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/RenderCombineText.h"
     30 #include "core/rendering/RenderInline.h"
     31 #include "core/rendering/RenderLayer.h"
     32 #include "core/rendering/RenderListMarker.h"
     33 #include "core/rendering/RenderRubyRun.h"
     34 #include "core/rendering/break_lines.h"
     35 #include "core/rendering/line/LineBreaker.h"
     36 #include "core/rendering/line/LineInfo.h"
     37 #include "core/rendering/line/LineWidth.h"
     38 #include "core/rendering/line/RenderTextInfo.h"
     39 #include "core/rendering/line/TrailingObjects.h"
     40 #include "core/rendering/line/WordMeasurement.h"
     41 #include "core/rendering/svg/RenderSVGInlineText.h"
     42 
     43 namespace WebCore {
     44 
     45 // We don't let our line box tree for a single line get any deeper than this.
     46 const unsigned cMaxLineDepth = 200;
     47 
     48 class BreakingContext {
     49 public:
     50     BreakingContext(InlineBidiResolver& resolver, LineInfo& inLineInfo, LineWidth& lineWidth, RenderTextInfo& inRenderTextInfo, FloatingObject* inLastFloatFromPreviousLine, bool appliedStartWidth, RenderBlockFlow* block)
     51         : m_resolver(resolver)
     52         , m_current(resolver.position())
     53         , m_lineBreak(resolver.position())
     54         , m_block(block)
     55         , m_lastObject(m_current.object())
     56         , m_nextObject(0)
     57         , m_currentStyle(0)
     58         , m_blockStyle(block->style())
     59         , m_lineInfo(inLineInfo)
     60         , m_renderTextInfo(inRenderTextInfo)
     61         , m_lastFloatFromPreviousLine(inLastFloatFromPreviousLine)
     62         , m_width(lineWidth)
     63         , m_currWS(NORMAL)
     64         , m_lastWS(NORMAL)
     65         , m_preservesNewline(false)
     66         , m_atStart(true)
     67         , m_ignoringSpaces(false)
     68         , m_currentCharacterIsSpace(false)
     69         , m_currentCharacterShouldCollapseIfPreWap(false)
     70         , m_appliedStartWidth(appliedStartWidth)
     71         , m_includeEndWidth(true)
     72         , m_autoWrap(false)
     73         , m_autoWrapWasEverTrueOnLine(false)
     74         , m_floatsFitOnLine(true)
     75         , m_collapseWhiteSpace(false)
     76         , m_startingNewParagraph(m_lineInfo.previousLineBrokeCleanly())
     77         , m_allowImagesToBreak(!block->document().inQuirksMode() || !block->isTableCell() || !m_blockStyle->logicalWidth().isIntrinsicOrAuto())
     78         , m_atEnd(false)
     79         , m_lineMidpointState(resolver.midpointState())
     80     {
     81         m_lineInfo.setPreviousLineBrokeCleanly(false);
     82     }
     83 
     84     RenderObject* currentObject() { return m_current.object(); }
     85     InlineIterator lineBreak() { return m_lineBreak; }
     86     bool atEnd() { return m_atEnd; }
     87 
     88     void initializeForCurrentObject();
     89 
     90     void increment();
     91 
     92     void handleBR(EClear&);
     93     void handleOutOfFlowPositioned(Vector<RenderBox*>& positionedObjects);
     94     void handleFloat();
     95     void handleEmptyInline();
     96     void handleReplaced();
     97     bool handleText(WordMeasurements&, bool& hyphenated);
     98     void commitAndUpdateLineBreakIfNeeded();
     99     InlineIterator handleEndOfLine();
    100 
    101     void clearLineBreakIfFitsOnLine()
    102     {
    103         if (m_width.fitsOnLine() || m_lastWS == NOWRAP)
    104             m_lineBreak.clear();
    105     }
    106 
    107 private:
    108     void skipTrailingWhitespace(InlineIterator&, const LineInfo&);
    109 
    110     InlineBidiResolver& m_resolver;
    111 
    112     InlineIterator m_current;
    113     InlineIterator m_lineBreak;
    114     InlineIterator m_startOfIgnoredSpaces;
    115 
    116     RenderBlockFlow* m_block;
    117     RenderObject* m_lastObject;
    118     RenderObject* m_nextObject;
    119 
    120     RenderStyle* m_currentStyle;
    121     RenderStyle* m_blockStyle;
    122 
    123     LineInfo& m_lineInfo;
    124 
    125     RenderTextInfo& m_renderTextInfo;
    126 
    127     FloatingObject* m_lastFloatFromPreviousLine;
    128 
    129     LineWidth m_width;
    130 
    131     EWhiteSpace m_currWS;
    132     EWhiteSpace m_lastWS;
    133 
    134     bool m_preservesNewline;
    135     bool m_atStart;
    136     bool m_ignoringSpaces;
    137     bool m_currentCharacterIsSpace;
    138     bool m_currentCharacterShouldCollapseIfPreWap;
    139     bool m_appliedStartWidth;
    140     bool m_includeEndWidth;
    141     bool m_autoWrap;
    142     bool m_autoWrapWasEverTrueOnLine;
    143     bool m_floatsFitOnLine;
    144     bool m_collapseWhiteSpace;
    145     bool m_startingNewParagraph;
    146     bool m_allowImagesToBreak;
    147     bool m_atEnd;
    148 
    149     LineMidpointState& m_lineMidpointState;
    150 
    151     TrailingObjects m_trailingObjects;
    152 };
    153 
    154 inline bool shouldCollapseWhiteSpace(const RenderStyle* style, const LineInfo& lineInfo, WhitespacePosition whitespacePosition)
    155 {
    156     // CSS2 16.6.1
    157     // If a space (U+0020) at the beginning of a line has 'white-space' set to 'normal', 'nowrap', or 'pre-line', it is removed.
    158     // 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.
    159     // 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.
    160     return style->collapseWhiteSpace()
    161         || (whitespacePosition == TrailingWhitespace && style->whiteSpace() == PRE_WRAP && (!lineInfo.isEmpty() || !lineInfo.previousLineBrokeCleanly()));
    162 }
    163 
    164 inline bool requiresLineBoxForContent(RenderInline* flow, const LineInfo& lineInfo)
    165 {
    166     RenderObject* parent = flow->parent();
    167     if (flow->document().inNoQuirksMode()
    168         && (flow->style(lineInfo.isFirstLine())->lineHeight() != parent->style(lineInfo.isFirstLine())->lineHeight()
    169         || flow->style()->verticalAlign() != parent->style()->verticalAlign()
    170         || !parent->style()->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(flow->style()->font().fontMetrics())))
    171         return true;
    172     return false;
    173 }
    174 
    175 inline bool alwaysRequiresLineBox(RenderObject* flow)
    176 {
    177     // FIXME: Right now, we only allow line boxes for inlines that are truly empty.
    178     // We need to fix this, though, because at the very least, inlines containing only
    179     // ignorable whitespace should should also have line boxes.
    180     return isEmptyInline(flow) && toRenderInline(flow)->hasInlineDirectionBordersPaddingOrMargin();
    181 }
    182 
    183 inline bool requiresLineBox(const InlineIterator& it, const LineInfo& lineInfo = LineInfo(), WhitespacePosition whitespacePosition = LeadingWhitespace)
    184 {
    185     if (it.object()->isFloatingOrOutOfFlowPositioned())
    186         return false;
    187 
    188     if (it.object()->isRenderInline() && !alwaysRequiresLineBox(it.object()) && !requiresLineBoxForContent(toRenderInline(it.object()), lineInfo))
    189         return false;
    190 
    191     if (!shouldCollapseWhiteSpace(it.object()->style(), lineInfo, whitespacePosition) || it.object()->isBR())
    192         return true;
    193 
    194     UChar current = it.current();
    195     bool notJustWhitespace = current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || it.object()->preservesNewline());
    196     return notJustWhitespace || isEmptyInline(it.object());
    197 }
    198 
    199 inline void setStaticPositions(RenderBlockFlow* block, RenderBox* child)
    200 {
    201     // FIXME: The math here is actually not really right. It's a best-guess approximation that
    202     // will work for the common cases
    203     RenderObject* containerBlock = child->container();
    204     LayoutUnit blockHeight = block->logicalHeight();
    205     if (containerBlock->isRenderInline()) {
    206         // A relative positioned inline encloses us. In this case, we also have to determine our
    207         // position as though we were an inline. Set |staticInlinePosition| and |staticBlockPosition| on the relative positioned
    208         // inline so that we can obtain the value later.
    209         toRenderInline(containerBlock)->layer()->setStaticInlinePosition(block->startAlignedOffsetForLine(blockHeight, false));
    210         toRenderInline(containerBlock)->layer()->setStaticBlockPosition(blockHeight);
    211     }
    212     block->updateStaticInlinePositionForChild(child, blockHeight);
    213     child->layer()->setStaticBlockPosition(blockHeight);
    214 }
    215 
    216 // FIXME: The entire concept of the skipTrailingWhitespace function is flawed, since we really need to be building
    217 // line boxes even for containers that may ultimately collapse away. Otherwise we'll never get positioned
    218 // elements quite right. In other words, we need to build this function's work into the normal line
    219 // object iteration process.
    220 // NB. this function will insert any floating elements that would otherwise
    221 // be skipped but it will not position them.
    222 inline void BreakingContext::skipTrailingWhitespace(InlineIterator& iterator, const LineInfo& lineInfo)
    223 {
    224     while (!iterator.atEnd() && !requiresLineBox(iterator, lineInfo, TrailingWhitespace)) {
    225         RenderObject* object = iterator.object();
    226         if (object->isOutOfFlowPositioned())
    227             setStaticPositions(m_block, toRenderBox(object));
    228         else if (object->isFloating())
    229             m_block->insertFloatingObject(toRenderBox(object));
    230         iterator.increment();
    231     }
    232 }
    233 
    234 inline void BreakingContext::initializeForCurrentObject()
    235 {
    236     m_currentStyle = m_current.object()->style();
    237     m_nextObject = bidiNextSkippingEmptyInlines(m_block, m_current.object());
    238     if (m_nextObject && m_nextObject->parent() && !m_nextObject->parent()->isDescendantOf(m_current.object()->parent()))
    239         m_includeEndWidth = true;
    240 
    241     m_currWS = m_current.object()->isReplaced() ? m_current.object()->parent()->style()->whiteSpace() : m_currentStyle->whiteSpace();
    242     m_lastWS = m_lastObject->isReplaced() ? m_lastObject->parent()->style()->whiteSpace() : m_lastObject->style()->whiteSpace();
    243 
    244     m_autoWrap = RenderStyle::autoWrap(m_currWS);
    245     m_autoWrapWasEverTrueOnLine = m_autoWrapWasEverTrueOnLine || m_autoWrap;
    246 
    247     m_preservesNewline = m_current.object()->isSVGInlineText() ? false : RenderStyle::preserveNewline(m_currWS);
    248 
    249     m_collapseWhiteSpace = RenderStyle::collapseWhiteSpace(m_currWS);
    250 }
    251 
    252 inline void BreakingContext::increment()
    253 {
    254     // Clear out our character space bool, since inline <pre>s don't collapse whitespace
    255     // with adjacent inline normal/nowrap spans.
    256     if (!m_collapseWhiteSpace)
    257         m_currentCharacterIsSpace = false;
    258 
    259     m_current.moveToStartOf(m_nextObject);
    260     m_atStart = false;
    261 }
    262 
    263 inline void BreakingContext::handleBR(EClear& clear)
    264 {
    265     if (m_width.fitsOnLine()) {
    266         RenderObject* br = m_current.object();
    267         m_lineBreak.moveToStartOf(br);
    268         m_lineBreak.increment();
    269 
    270         // A <br> always breaks a line, so don't let the line be collapsed
    271         // away. Also, the space at the end of a line with a <br> does not
    272         // get collapsed away. It only does this if the previous line broke
    273         // cleanly. Otherwise the <br> has no effect on whether the line is
    274         // empty or not.
    275         if (m_startingNewParagraph)
    276             m_lineInfo.setEmpty(false, m_block, &m_width);
    277         m_trailingObjects.clear();
    278         m_lineInfo.setPreviousLineBrokeCleanly(true);
    279 
    280         // A <br> with clearance always needs a linebox in case the lines below it get dirtied later and
    281         // need to check for floats to clear - so if we're ignoring spaces, stop ignoring them and add a
    282         // run for this object.
    283         if (m_ignoringSpaces && m_currentStyle->clear() != CNONE)
    284             m_lineMidpointState.ensureLineBoxInsideIgnoredSpaces(br);
    285 
    286         if (!m_lineInfo.isEmpty())
    287             clear = m_currentStyle->clear();
    288     }
    289     m_atEnd = true;
    290 }
    291 
    292 inline LayoutUnit borderPaddingMarginStart(RenderInline* child)
    293 {
    294     return child->marginStart() + child->paddingStart() + child->borderStart();
    295 }
    296 
    297 inline LayoutUnit borderPaddingMarginEnd(RenderInline* child)
    298 {
    299     return child->marginEnd() + child->paddingEnd() + child->borderEnd();
    300 }
    301 
    302 inline bool shouldAddBorderPaddingMargin(RenderObject* child, bool &checkSide)
    303 {
    304     if (!child || (child->isText() && !toRenderText(child)->textLength()))
    305         return true;
    306     checkSide = false;
    307     return checkSide;
    308 }
    309 
    310 inline LayoutUnit inlineLogicalWidth(RenderObject* child, bool start = true, bool end = true)
    311 {
    312     unsigned lineDepth = 1;
    313     LayoutUnit extraWidth = 0;
    314     RenderObject* parent = child->parent();
    315     while (parent->isRenderInline() && lineDepth++ < cMaxLineDepth) {
    316         RenderInline* parentAsRenderInline = toRenderInline(parent);
    317         if (!isEmptyInline(parentAsRenderInline)) {
    318             if (start && shouldAddBorderPaddingMargin(child->previousSibling(), start))
    319                 extraWidth += borderPaddingMarginStart(parentAsRenderInline);
    320             if (end && shouldAddBorderPaddingMargin(child->nextSibling(), end))
    321                 extraWidth += borderPaddingMarginEnd(parentAsRenderInline);
    322             if (!start && !end)
    323                 return extraWidth;
    324         }
    325         child = parent;
    326         parent = child->parent();
    327     }
    328     return extraWidth;
    329 }
    330 
    331 inline void BreakingContext::handleOutOfFlowPositioned(Vector<RenderBox*>& positionedObjects)
    332 {
    333     // If our original display wasn't an inline type, then we can
    334     // go ahead and determine our static inline position now.
    335     RenderBox* box = toRenderBox(m_current.object());
    336     bool isInlineType = box->style()->isOriginalDisplayInlineType();
    337     if (!isInlineType) {
    338         m_block->setStaticInlinePositionForChild(box, m_block->logicalHeight(), m_block->startOffsetForContent());
    339     } else {
    340         // If our original display was an INLINE type, then we can go ahead
    341         // and determine our static y position now.
    342         box->layer()->setStaticBlockPosition(m_block->logicalHeight());
    343     }
    344 
    345     // If we're ignoring spaces, we have to stop and include this object and
    346     // then start ignoring spaces again.
    347     if (isInlineType || box->container()->isRenderInline()) {
    348         if (m_ignoringSpaces)
    349             m_lineMidpointState.ensureLineBoxInsideIgnoredSpaces(box);
    350         m_trailingObjects.appendObjectIfNeeded(box);
    351     } else {
    352         positionedObjects.append(box);
    353     }
    354     m_width.addUncommittedWidth(inlineLogicalWidth(box).toFloat());
    355     // Reset prior line break context characters.
    356     m_renderTextInfo.m_lineBreakIterator.resetPriorContext();
    357 }
    358 
    359 inline void BreakingContext::handleFloat()
    360 {
    361     RenderBox* floatBox = toRenderBox(m_current.object());
    362     FloatingObject* floatingObject = m_block->insertFloatingObject(floatBox);
    363     // check if it fits in the current line.
    364     // If it does, position it now, otherwise, position
    365     // it after moving to next line (in newLine() func)
    366     // FIXME: Bug 110372: Properly position multiple stacked floats with non-rectangular shape outside.
    367     if (m_floatsFitOnLine && m_width.fitsOnLine(m_block->logicalWidthForFloat(floatingObject).toFloat(), ExcludeWhitespace)) {
    368         m_block->positionNewFloatOnLine(floatingObject, m_lastFloatFromPreviousLine, m_lineInfo, m_width);
    369         if (m_lineBreak.object() == m_current.object()) {
    370             ASSERT(!m_lineBreak.offset());
    371             m_lineBreak.increment();
    372         }
    373     } else {
    374         m_floatsFitOnLine = false;
    375     }
    376     // Update prior line break context characters, using U+FFFD (OBJECT REPLACEMENT CHARACTER) for floating element.
    377     m_renderTextInfo.m_lineBreakIterator.updatePriorContext(replacementCharacter);
    378 }
    379 
    380 // This is currently just used for list markers and inline flows that have line boxes. Neither should
    381 // have an effect on whitespace at the start of the line.
    382 inline bool shouldSkipWhitespaceAfterStartObject(RenderBlockFlow* block, RenderObject* o, LineMidpointState& lineMidpointState)
    383 {
    384     RenderObject* next = bidiNextSkippingEmptyInlines(block, o);
    385     while (next && next->isFloatingOrOutOfFlowPositioned())
    386         next = bidiNextSkippingEmptyInlines(block, next);
    387 
    388     if (next && !next->isBR() && next->isText() && toRenderText(next)->textLength() > 0) {
    389         RenderText* nextText = toRenderText(next);
    390         UChar nextChar = nextText->characterAt(0);
    391         if (nextText->style()->isCollapsibleWhiteSpace(nextChar)) {
    392             lineMidpointState.startIgnoringSpaces(InlineIterator(0, o, 0));
    393             return true;
    394         }
    395     }
    396 
    397     return false;
    398 }
    399 
    400 inline void BreakingContext::handleEmptyInline()
    401 {
    402     // This should only end up being called on empty inlines
    403     ASSERT(isEmptyInline(m_current.object()));
    404 
    405     RenderInline* flowBox = toRenderInline(m_current.object());
    406 
    407     bool requiresLineBox = alwaysRequiresLineBox(m_current.object());
    408     if (requiresLineBox || requiresLineBoxForContent(flowBox, m_lineInfo)) {
    409         // An empty inline that only has line-height, vertical-align or font-metrics will
    410         // not force linebox creation (and thus affect the height of the line) if the rest of the line is empty.
    411         if (requiresLineBox)
    412             m_lineInfo.setEmpty(false, m_block, &m_width);
    413         if (m_ignoringSpaces) {
    414             // If we are in a run of ignored spaces then ensure we get a linebox if lineboxes are eventually
    415             // created for the line...
    416             m_trailingObjects.clear();
    417             m_lineMidpointState.ensureLineBoxInsideIgnoredSpaces(m_current.object());
    418         } else if (m_blockStyle->collapseWhiteSpace() && m_resolver.position().object() == m_current.object()
    419             && shouldSkipWhitespaceAfterStartObject(m_block, m_current.object(), m_lineMidpointState)) {
    420             // If this object is at the start of the line, we need to behave like list markers and
    421             // start ignoring spaces.
    422             m_currentCharacterShouldCollapseIfPreWap = m_currentCharacterIsSpace = true;
    423             m_ignoringSpaces = true;
    424         } else {
    425             // If we are after a trailing space but aren't ignoring spaces yet then ensure we get a linebox
    426             // if we encounter collapsible whitepace.
    427             m_trailingObjects.appendObjectIfNeeded(m_current.object());
    428         }
    429     }
    430 
    431     m_width.addUncommittedWidth((inlineLogicalWidth(m_current.object()) + borderPaddingMarginStart(flowBox) + borderPaddingMarginEnd(flowBox)).toFloat());
    432 }
    433 
    434 inline void BreakingContext::handleReplaced()
    435 {
    436     RenderBox* replacedBox = toRenderBox(m_current.object());
    437 
    438     if (m_atStart)
    439         m_width.updateAvailableWidth(replacedBox->logicalHeight());
    440 
    441     // Break on replaced elements if either has normal white-space.
    442     if ((m_autoWrap || RenderStyle::autoWrap(m_lastWS)) && (!m_current.object()->isImage() || m_allowImagesToBreak)) {
    443         m_width.commit();
    444         m_lineBreak.moveToStartOf(m_current.object());
    445     }
    446 
    447     if (m_ignoringSpaces)
    448         m_lineMidpointState.stopIgnoringSpaces(InlineIterator(0, m_current.object(), 0));
    449 
    450     m_lineInfo.setEmpty(false, m_block, &m_width);
    451     m_ignoringSpaces = false;
    452     m_currentCharacterShouldCollapseIfPreWap = m_currentCharacterIsSpace = false;
    453     m_trailingObjects.clear();
    454 
    455     // Optimize for a common case. If we can't find whitespace after the list
    456     // item, then this is all moot.
    457     LayoutUnit replacedLogicalWidth = m_block->logicalWidthForChild(replacedBox) + m_block->marginStartForChild(replacedBox) + m_block->marginEndForChild(replacedBox) + inlineLogicalWidth(m_current.object());
    458     if (m_current.object()->isListMarker()) {
    459         if (m_blockStyle->collapseWhiteSpace() && shouldSkipWhitespaceAfterStartObject(m_block, m_current.object(), m_lineMidpointState)) {
    460             // Like with inline flows, we start ignoring spaces to make sure that any
    461             // additional spaces we see will be discarded.
    462             m_currentCharacterShouldCollapseIfPreWap = m_currentCharacterIsSpace = true;
    463             m_ignoringSpaces = true;
    464         }
    465         if (toRenderListMarker(m_current.object())->isInside())
    466             m_width.addUncommittedWidth(replacedLogicalWidth.toFloat());
    467     } else {
    468         m_width.addUncommittedWidth(replacedLogicalWidth.toFloat());
    469     }
    470     if (m_current.object()->isRubyRun())
    471         m_width.applyOverhang(toRenderRubyRun(m_current.object()), m_lastObject, m_nextObject);
    472     // Update prior line break context characters, using U+FFFD (OBJECT REPLACEMENT CHARACTER) for replaced element.
    473     m_renderTextInfo.m_lineBreakIterator.updatePriorContext(replacementCharacter);
    474 }
    475 
    476 inline bool iteratorIsBeyondEndOfRenderCombineText(const InlineIterator& iter, RenderCombineText* renderer)
    477 {
    478     return iter.object() == renderer && iter.offset() >= renderer->textLength();
    479 }
    480 
    481 inline void nextCharacter(UChar& currentCharacter, UChar& lastCharacter, UChar& secondToLastCharacter)
    482 {
    483     secondToLastCharacter = lastCharacter;
    484     lastCharacter = currentCharacter;
    485 }
    486 
    487 inline float firstPositiveWidth(const WordMeasurements& wordMeasurements)
    488 {
    489     for (size_t i = 0; i < wordMeasurements.size(); ++i) {
    490         if (wordMeasurements[i].width > 0)
    491             return wordMeasurements[i].width;
    492     }
    493     return 0;
    494 }
    495 
    496 inline float measureHyphenWidth(RenderText* renderer, const Font& font, TextDirection textDirection)
    497 {
    498     RenderStyle* style = renderer->style();
    499     return font.width(RenderBlockFlow::constructTextRun(renderer, font,
    500         style->hyphenString().string(), style, style->direction()));
    501 }
    502 
    503 ALWAYS_INLINE TextDirection textDirectionFromUnicode(WTF::Unicode::Direction direction)
    504 {
    505     return direction == WTF::Unicode::RightToLeft
    506         || direction == WTF::Unicode::RightToLeftArabic ? RTL : LTR;
    507 }
    508 
    509 ALWAYS_INLINE float textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, float xPos, bool isFixedPitch, bool collapseWhiteSpace, HashSet<const SimpleFontData*>* fallbackFonts = 0)
    510 {
    511     GlyphOverflow glyphOverflow;
    512     if (isFixedPitch || (!from && len == text->textLength()) || text->style()->hasTextCombine())
    513         return text->width(from, len, font, xPos, text->style()->direction(), fallbackFonts, &glyphOverflow);
    514 
    515     TextRun run = RenderBlockFlow::constructTextRun(text, font, text, from, len, text->style());
    516     run.setCharacterScanForCodePath(!text->canUseSimpleFontCodePath());
    517     run.setTabSize(!collapseWhiteSpace, text->style()->tabSize());
    518     run.setXPos(xPos);
    519     return font.width(run, fallbackFonts, &glyphOverflow);
    520 }
    521 
    522 inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool& hyphenated)
    523 {
    524     if (!m_current.offset())
    525         m_appliedStartWidth = false;
    526 
    527     RenderText* renderText = toRenderText(m_current.object());
    528 
    529     bool isSVGText = renderText->isSVGInlineText();
    530 
    531     // If we have left a no-wrap inline and entered an autowrap inline while ignoring spaces
    532     // then we need to mark the start of the autowrap inline as a potential linebreak now.
    533     if (m_autoWrap && !RenderStyle::autoWrap(m_lastWS) && m_ignoringSpaces) {
    534         m_width.commit();
    535         m_lineBreak.moveToStartOf(m_current.object());
    536     }
    537 
    538     if (renderText->style()->hasTextCombine() && m_current.object()->isCombineText() && !toRenderCombineText(m_current.object())->isCombined()) {
    539         RenderCombineText* combineRenderer = toRenderCombineText(m_current.object());
    540         combineRenderer->combineText();
    541         // The length of the renderer's text may have changed. Increment stale iterator positions
    542         if (iteratorIsBeyondEndOfRenderCombineText(m_lineBreak, combineRenderer)) {
    543             ASSERT(iteratorIsBeyondEndOfRenderCombineText(m_resolver.position(), combineRenderer));
    544             m_lineBreak.increment();
    545             m_resolver.position().increment(&m_resolver);
    546         }
    547     }
    548 
    549     RenderStyle* style = renderText->style(m_lineInfo.isFirstLine());
    550     const Font& font = style->font();
    551     bool isFixedPitch = font.isFixedPitch();
    552 
    553     unsigned lastSpace = m_current.offset();
    554     float wordSpacing = m_currentStyle->wordSpacing();
    555     float lastSpaceWordSpacing = 0;
    556     float wordSpacingForWordMeasurement = 0;
    557 
    558     float wrapW = m_width.uncommittedWidth() + inlineLogicalWidth(m_current.object(), !m_appliedStartWidth, true);
    559     float charWidth = 0;
    560     // Auto-wrapping text should wrap in the middle of a word only if it could not wrap before the word,
    561     // which is only possible if the word is the first thing on the line, that is, if |w| is zero.
    562     bool breakWords = m_currentStyle->breakWords() && ((m_autoWrap && !m_width.committedWidth()) || m_currWS == PRE);
    563     bool midWordBreak = false;
    564     bool breakAll = m_currentStyle->wordBreak() == BreakAllWordBreak && m_autoWrap;
    565     float hyphenWidth = 0;
    566 
    567     if (isSVGText) {
    568         breakWords = false;
    569         breakAll = false;
    570     }
    571 
    572     if (renderText->isWordBreak()) {
    573         m_width.commit();
    574         m_lineBreak.moveToStartOf(m_current.object());
    575         ASSERT(m_current.offset() == renderText->textLength());
    576     }
    577 
    578     if (m_renderTextInfo.m_text != renderText) {
    579         m_renderTextInfo.m_text = renderText;
    580         m_renderTextInfo.m_font = &font;
    581         m_renderTextInfo.m_lineBreakIterator.resetStringAndReleaseIterator(renderText->text(), style->locale());
    582     } else if (m_renderTextInfo.m_font != &font) {
    583         m_renderTextInfo.m_font = &font;
    584     }
    585 
    586     // Non-zero only when kerning is enabled, in which case we measure
    587     // words with their trailing space, then subtract its width.
    588     float wordTrailingSpaceWidth = (font.fontDescription().typesettingFeatures() & Kerning) ?
    589         font.width(RenderBlockFlow::constructTextRun(
    590             renderText, font, &space, 1, style,
    591             style->direction())) + wordSpacing
    592         : 0;
    593 
    594     UChar lastCharacter = m_renderTextInfo.m_lineBreakIterator.lastCharacter();
    595     UChar secondToLastCharacter = m_renderTextInfo.m_lineBreakIterator.secondToLastCharacter();
    596     for (; m_current.offset() < renderText->textLength(); m_current.fastIncrementInTextNode()) {
    597         bool previousCharacterIsSpace = m_currentCharacterIsSpace;
    598         bool previousCharacterShouldCollapseIfPreWap = m_currentCharacterShouldCollapseIfPreWap;
    599         UChar c = m_current.current();
    600         m_currentCharacterShouldCollapseIfPreWap = m_currentCharacterIsSpace = c == ' ' || c == '\t' || (!m_preservesNewline && (c == '\n'));
    601 
    602         if (!m_collapseWhiteSpace || !m_currentCharacterIsSpace)
    603             m_lineInfo.setEmpty(false, m_block, &m_width);
    604 
    605         if (c == softHyphen && m_autoWrap && !hyphenWidth) {
    606             hyphenWidth = measureHyphenWidth(renderText, font, textDirectionFromUnicode(m_resolver.position().direction()));
    607             m_width.addUncommittedWidth(hyphenWidth);
    608         }
    609 
    610         bool applyWordSpacing = false;
    611 
    612         if ((breakAll || breakWords) && !midWordBreak) {
    613             wrapW += charWidth;
    614             bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && m_current.offset() + 1 < renderText->textLength() && U16_IS_TRAIL((*renderText)[m_current.offset() + 1]);
    615             charWidth = textWidth(renderText, m_current.offset(), midWordBreakIsBeforeSurrogatePair ? 2 : 1, font, m_width.committedWidth() + wrapW, isFixedPitch, m_collapseWhiteSpace, 0);
    616             midWordBreak = m_width.committedWidth() + wrapW + charWidth > m_width.availableWidth();
    617         }
    618 
    619         int nextBreakablePosition = m_current.nextBreakablePosition();
    620         bool betweenWords = c == '\n' || (m_currWS != PRE && !m_atStart && isBreakable(m_renderTextInfo.m_lineBreakIterator, m_current.offset(), nextBreakablePosition));
    621         m_current.setNextBreakablePosition(nextBreakablePosition);
    622 
    623         if (betweenWords || midWordBreak) {
    624             bool stoppedIgnoringSpaces = false;
    625             if (m_ignoringSpaces) {
    626                 lastSpaceWordSpacing = 0;
    627                 if (!m_currentCharacterIsSpace) {
    628                     // Stop ignoring spaces and begin at this
    629                     // new point.
    630                     m_ignoringSpaces = false;
    631                     wordSpacingForWordMeasurement = 0;
    632                     lastSpace = m_current.offset(); // e.g., "Foo    goo", don't add in any of the ignored spaces.
    633                     m_lineMidpointState.stopIgnoringSpaces(InlineIterator(0, m_current.object(), m_current.offset()));
    634                     stoppedIgnoringSpaces = true;
    635                 } else {
    636                     // Just keep ignoring these spaces.
    637                     nextCharacter(c, lastCharacter, secondToLastCharacter);
    638                     continue;
    639                 }
    640             }
    641 
    642             wordMeasurements.grow(wordMeasurements.size() + 1);
    643             WordMeasurement& wordMeasurement = wordMeasurements.last();
    644 
    645             wordMeasurement.renderer = renderText;
    646             wordMeasurement.endOffset = m_current.offset();
    647             wordMeasurement.startOffset = lastSpace;
    648 
    649             float additionalTempWidth;
    650             if (wordTrailingSpaceWidth && c == ' ')
    651                 additionalTempWidth = textWidth(renderText, lastSpace, m_current.offset() + 1 - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasurement.fallbackFonts) - wordTrailingSpaceWidth;
    652             else
    653                 additionalTempWidth = textWidth(renderText, lastSpace, m_current.offset() - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasurement.fallbackFonts);
    654 
    655             wordMeasurement.width = additionalTempWidth + wordSpacingForWordMeasurement;
    656             additionalTempWidth += lastSpaceWordSpacing;
    657             m_width.addUncommittedWidth(additionalTempWidth);
    658 
    659             if (m_collapseWhiteSpace && previousCharacterIsSpace && m_currentCharacterIsSpace && additionalTempWidth)
    660                 m_width.setTrailingWhitespaceWidth(additionalTempWidth);
    661 
    662             if (!m_appliedStartWidth) {
    663                 m_width.addUncommittedWidth(inlineLogicalWidth(m_current.object(), true, false).toFloat());
    664                 m_appliedStartWidth = true;
    665             }
    666 
    667             applyWordSpacing = wordSpacing && m_currentCharacterIsSpace;
    668 
    669             if (!m_width.committedWidth() && m_autoWrap && !m_width.fitsOnLine())
    670                 m_width.fitBelowFloats(m_lineInfo.isFirstLine());
    671 
    672             if (m_autoWrap || breakWords) {
    673                 // If we break only after white-space, consider the current character
    674                 // as candidate width for this line.
    675                 bool lineWasTooWide = false;
    676                 if (m_width.fitsOnLine() && m_currentCharacterIsSpace && m_currentStyle->breakOnlyAfterWhiteSpace() && !midWordBreak) {
    677                     float charWidth = textWidth(renderText, m_current.offset(), 1, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasurement.fallbackFonts) + (applyWordSpacing ? wordSpacing : 0);
    678                     // Check if line is too big even without the extra space
    679                     // at the end of the line. If it is not, do nothing.
    680                     // If the line needs the extra whitespace to be too long,
    681                     // then move the line break to the space and skip all
    682                     // additional whitespace.
    683                     if (!m_width.fitsOnLine(charWidth)) {
    684                         lineWasTooWide = true;
    685                         m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition());
    686                         skipTrailingWhitespace(m_lineBreak, m_lineInfo);
    687                     }
    688                 }
    689                 if (lineWasTooWide || !m_width.fitsOnLine()) {
    690                     if (m_lineBreak.atTextParagraphSeparator()) {
    691                         if (!stoppedIgnoringSpaces && m_current.offset() > 0)
    692                             m_lineMidpointState.ensureCharacterGetsLineBox(m_current);
    693                         m_lineBreak.increment();
    694                         m_lineInfo.setPreviousLineBrokeCleanly(true);
    695                         wordMeasurement.endOffset = m_lineBreak.offset();
    696                     }
    697                     if (m_lineBreak.object() && m_lineBreak.offset() && m_lineBreak.object()->isText() && toRenderText(m_lineBreak.object())->textLength() && toRenderText(m_lineBreak.object())->characterAt(m_lineBreak.offset() - 1) == softHyphen)
    698                         hyphenated = true;
    699                     if (m_lineBreak.offset() && m_lineBreak.offset() != (unsigned)wordMeasurement.endOffset && !wordMeasurement.width) {
    700                         if (charWidth) {
    701                             wordMeasurement.endOffset = m_lineBreak.offset();
    702                             wordMeasurement.width = charWidth;
    703                         }
    704                     }
    705                     // Didn't fit. Jump to the end unless there's still an opportunity to collapse whitespace.
    706                     if (m_ignoringSpaces || !m_collapseWhiteSpace || !m_currentCharacterIsSpace || !previousCharacterIsSpace) {
    707                         m_atEnd = true;
    708                         return false;
    709                     }
    710                 } else {
    711                     if (!betweenWords || (midWordBreak && !m_autoWrap))
    712                         m_width.addUncommittedWidth(-additionalTempWidth);
    713                     if (hyphenWidth) {
    714                         // Subtract the width of the soft hyphen out since we fit on a line.
    715                         m_width.addUncommittedWidth(-hyphenWidth);
    716                         hyphenWidth = 0;
    717                     }
    718                 }
    719             }
    720 
    721             if (c == '\n' && m_preservesNewline) {
    722                 if (!stoppedIgnoringSpaces && m_current.offset())
    723                     m_lineMidpointState.ensureCharacterGetsLineBox(m_current);
    724                 m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition());
    725                 m_lineBreak.increment();
    726                 m_lineInfo.setPreviousLineBrokeCleanly(true);
    727                 return true;
    728             }
    729 
    730             if (m_autoWrap && betweenWords) {
    731                 m_width.commit();
    732                 wrapW = 0;
    733                 m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition());
    734                 // Auto-wrapping text should not wrap in the middle of a word once it has had an
    735                 // opportunity to break after a word.
    736                 breakWords = false;
    737             }
    738 
    739             if (midWordBreak && !U16_IS_TRAIL(c) && !(WTF::Unicode::category(c) & (WTF::Unicode::Mark_NonSpacing | WTF::Unicode::Mark_Enclosing | WTF::Unicode::Mark_SpacingCombining))) {
    740                 // Remember this as a breakable position in case
    741                 // adding the end width forces a break.
    742                 m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition());
    743                 midWordBreak &= (breakWords || breakAll);
    744             }
    745 
    746             if (betweenWords) {
    747                 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
    748                 wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurement.width) ? wordSpacing : 0;
    749                 lastSpace = m_current.offset();
    750             }
    751 
    752             if (!m_ignoringSpaces && m_currentStyle->collapseWhiteSpace()) {
    753                 // If we encounter a newline, or if we encounter a
    754                 // second space, we need to go ahead and break up this
    755                 // run and enter a mode where we start collapsing spaces.
    756                 if (m_currentCharacterIsSpace && previousCharacterIsSpace) {
    757                     m_ignoringSpaces = true;
    758 
    759                     // We just entered a mode where we are ignoring
    760                     // spaces. Create a midpoint to terminate the run
    761                     // before the second space.
    762                     m_lineMidpointState.startIgnoringSpaces(m_startOfIgnoredSpaces);
    763                     m_trailingObjects.updateMidpointsForTrailingObjects(m_lineMidpointState, InlineIterator(), TrailingObjects::DoNotCollapseFirstSpace);
    764                 }
    765             }
    766         } else if (m_ignoringSpaces) {
    767             // Stop ignoring spaces and begin at this
    768             // new point.
    769             m_ignoringSpaces = false;
    770             lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
    771             wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurements.last().width) ? wordSpacing : 0;
    772             lastSpace = m_current.offset(); // e.g., "Foo    goo", don't add in any of the ignored spaces.
    773             m_lineMidpointState.stopIgnoringSpaces(InlineIterator(0, m_current.object(), m_current.offset()));
    774         }
    775 
    776         if (isSVGText && m_current.offset()) {
    777             // Force creation of new InlineBoxes for each absolute positioned character (those that start new text chunks).
    778             if (toRenderSVGInlineText(renderText)->characterStartsNewTextChunk(m_current.offset()))
    779                 m_lineMidpointState.ensureCharacterGetsLineBox(m_current);
    780         }
    781 
    782         if (m_currentCharacterIsSpace && !previousCharacterIsSpace) {
    783             m_startOfIgnoredSpaces.setObject(m_current.object());
    784             m_startOfIgnoredSpaces.setOffset(m_current.offset());
    785         }
    786 
    787         if (!m_currentCharacterIsSpace && previousCharacterShouldCollapseIfPreWap) {
    788             if (m_autoWrap && m_currentStyle->breakOnlyAfterWhiteSpace())
    789                 m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition());
    790         }
    791 
    792         if (m_collapseWhiteSpace && m_currentCharacterIsSpace && !m_ignoringSpaces)
    793             m_trailingObjects.setTrailingWhitespace(toRenderText(m_current.object()));
    794         else if (!m_currentStyle->collapseWhiteSpace() || !m_currentCharacterIsSpace)
    795             m_trailingObjects.clear();
    796 
    797         m_atStart = false;
    798         nextCharacter(c, lastCharacter, secondToLastCharacter);
    799     }
    800 
    801     m_renderTextInfo.m_lineBreakIterator.setPriorContext(lastCharacter, secondToLastCharacter);
    802 
    803     wordMeasurements.grow(wordMeasurements.size() + 1);
    804     WordMeasurement& wordMeasurement = wordMeasurements.last();
    805     wordMeasurement.renderer = renderText;
    806 
    807     // IMPORTANT: current.m_pos is > length here!
    808     float additionalTempWidth = m_ignoringSpaces ? 0 : textWidth(renderText, lastSpace, m_current.offset() - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasurement.fallbackFonts);
    809     wordMeasurement.startOffset = lastSpace;
    810     wordMeasurement.endOffset = m_current.offset();
    811     wordMeasurement.width = m_ignoringSpaces ? 0 : additionalTempWidth + wordSpacingForWordMeasurement;
    812     additionalTempWidth += lastSpaceWordSpacing;
    813 
    814     LayoutUnit inlineLogicalTempWidth = inlineLogicalWidth(m_current.object(), !m_appliedStartWidth, m_includeEndWidth);
    815     m_width.addUncommittedWidth(additionalTempWidth + inlineLogicalTempWidth);
    816 
    817     if (m_collapseWhiteSpace && m_currentCharacterIsSpace && additionalTempWidth)
    818         m_width.setTrailingWhitespaceWidth(additionalTempWidth + inlineLogicalTempWidth);
    819 
    820     m_includeEndWidth = false;
    821 
    822     if (!m_width.fitsOnLine()) {
    823         if (!hyphenated && m_lineBreak.previousInSameNode() == softHyphen) {
    824             hyphenated = true;
    825             m_atEnd = true;
    826         }
    827     }
    828     return false;
    829 }
    830 
    831 inline void BreakingContext::commitAndUpdateLineBreakIfNeeded()
    832 {
    833     bool checkForBreak = m_autoWrap;
    834     if (m_width.committedWidth() && !m_width.fitsOnLine() && m_lineBreak.object() && m_currWS == NOWRAP) {
    835         checkForBreak = true;
    836     } else if (m_nextObject && m_current.object()->isText() && m_nextObject->isText() && !m_nextObject->isBR() && (m_autoWrap || m_nextObject->style()->autoWrap())) {
    837         if (m_autoWrap && m_currentCharacterIsSpace) {
    838             checkForBreak = true;
    839         } else {
    840             RenderText* nextText = toRenderText(m_nextObject);
    841             if (nextText->textLength()) {
    842                 UChar c = nextText->characterAt(0);
    843                 // If the next item on the line is text, and if we did not end with
    844                 // a space, then the next text run continues our word (and so it needs to
    845                 // keep adding to the uncommitted width. Just update and continue.
    846                 checkForBreak = !m_currentCharacterIsSpace && (c == ' ' || c == '\t' || (c == '\n' && !m_nextObject->preservesNewline()));
    847             } else if (nextText->isWordBreak()) {
    848                 checkForBreak = true;
    849             }
    850 
    851             if (!m_width.fitsOnLine() && !m_width.committedWidth())
    852                 m_width.fitBelowFloats(m_lineInfo.isFirstLine());
    853 
    854             bool canPlaceOnLine = m_width.fitsOnLine() || !m_autoWrapWasEverTrueOnLine;
    855             if (canPlaceOnLine && checkForBreak) {
    856                 m_width.commit();
    857                 m_lineBreak.moveToStartOf(m_nextObject);
    858             }
    859         }
    860     }
    861 
    862     ASSERT_WITH_SECURITY_IMPLICATION(m_currentStyle->refCount() > 0);
    863     if (checkForBreak && !m_width.fitsOnLine()) {
    864         // if we have floats, try to get below them.
    865         if (m_currentCharacterIsSpace && !m_ignoringSpaces && m_currentStyle->collapseWhiteSpace())
    866             m_trailingObjects.clear();
    867 
    868         if (m_width.committedWidth()) {
    869             m_atEnd = true;
    870             return;
    871         }
    872 
    873         m_width.fitBelowFloats(m_lineInfo.isFirstLine());
    874 
    875         // |width| may have been adjusted because we got shoved down past a float (thus
    876         // giving us more room), so we need to retest, and only jump to
    877         // the end label if we still don't fit on the line. -dwh
    878         if (!m_width.fitsOnLine()) {
    879             m_atEnd = true;
    880             return;
    881         }
    882     } else if (m_blockStyle->autoWrap() && !m_width.fitsOnLine() && !m_width.committedWidth()) {
    883         // If the container autowraps but the current child does not then we still need to ensure that it
    884         // wraps and moves below any floats.
    885         m_width.fitBelowFloats(m_lineInfo.isFirstLine());
    886     }
    887 
    888     if (!m_current.object()->isFloatingOrOutOfFlowPositioned()) {
    889         m_lastObject = m_current.object();
    890         if (m_lastObject->isReplaced() && m_autoWrap && (!m_lastObject->isImage() || m_allowImagesToBreak) && (!m_lastObject->isListMarker() || toRenderListMarker(m_lastObject)->isInside())) {
    891             m_width.commit();
    892             m_lineBreak.moveToStartOf(m_nextObject);
    893         }
    894     }
    895 }
    896 
    897 inline IndentTextOrNot requiresIndent(bool isFirstLine, bool isAfterHardLineBreak, RenderStyle* style)
    898 {
    899     IndentTextOrNot shouldIndentText = DoNotIndentText;
    900     if (isFirstLine || (isAfterHardLineBreak && style->textIndentLine()) == TextIndentEachLine)
    901         shouldIndentText = IndentText;
    902 
    903     if (style->textIndentType() == TextIndentHanging)
    904         shouldIndentText = shouldIndentText == IndentText ? DoNotIndentText : IndentText;
    905 
    906     return shouldIndentText;
    907 }
    908 
    909 }
    910 
    911 #endif // BreakingContextInlineHeaders_h
    912