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