1/*
2 * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All right reserved.
4 * Copyright (C) 2010 Google Inc. All rights reserved.
5 * 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
37namespace WebCore {
38
39using namespace std;
40using namespace WTF;
41using namespace Unicode;
42
43// We don't let our line box tree for a single line get any deeper than this.
44const unsigned cMaxLineDepth = 200;
45
46struct 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
66class WordMeasurement {
67public:
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.
84inline 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
93inline void startIgnoringSpaces(LineMidpointState& lineMidpointState, const InlineIterator& midpoint)
94{
95    ASSERT(!(lineMidpointState.numMidpoints % 2));
96    deprecatedAddMidpoint(lineMidpointState, midpoint);
97}
98
99inline 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.
107inline 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.
115inline 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
122class TrailingObjects {
123public:
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
133private:
134    RenderText* m_whitespace;
135    Vector<RenderBox*, 4> m_boxes;
136};
137
138TrailingObjects::TrailingObjects()
139    : m_whitespace(0)
140{
141}
142
143inline void TrailingObjects::setTrailingWhitespace(RenderText* whitespace)
144{
145    ASSERT(whitespace);
146    m_whitespace = whitespace;
147}
148
149inline 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
158inline void TrailingObjects::appendBoxIfNeeded(RenderBox* box)
159{
160    if (m_whitespace)
161        m_boxes.append(box);
162}
163
164void 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
206class BreakingContext {
207public:
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
265private:
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
312enum WhitespacePosition { LeadingWhitespace, TrailingWhitespace };
313
314inline 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
324inline 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
335inline 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
343inline 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
359inline 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.
382inline 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
394inline 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
412inline 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
423inline 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
452inline LayoutUnit borderPaddingMarginStart(RenderInline* child)
453{
454    return child->marginStart() + child->paddingStart() + child->borderStart();
455}
456
457inline LayoutUnit borderPaddingMarginEnd(RenderInline* child)
458{
459    return child->marginEnd() + child->paddingEnd() + child->borderEnd();
460}
461
462inline 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
470inline 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
491inline 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
519inline 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.
542inline 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
560inline 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
592inline 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
634inline bool iteratorIsBeyondEndOfRenderCombineText(const InlineIterator& iter, RenderCombineText* renderer)
635{
636    return iter.object() == renderer && iter.m_pos >= renderer->textLength();
637}
638
639inline void nextCharacter(UChar& currentCharacter, UChar& lastCharacter, UChar& secondToLastCharacter)
640{
641    secondToLastCharacter = lastCharacter;
642    lastCharacter = currentCharacter;
643}
644
645inline 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
654inline 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
695inline 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
701ALWAYS_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
720inline 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
1013inline 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
1078inline 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
1099InlineIterator 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