Use is<>() / downcast<>() for all remaining RenderObject subclasses
[WebKit-https.git] / Source / WebCore / rendering / line / LineBreaker.cpp
1 /*
2  * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
3  * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All right reserved.
4  * Copyright (C) 2010 Google Inc. All rights reserved.
5  * Copyright (C) 2013 ChangSeok Oh <shivamidow@gmail.com>
6  * Copyright (C) 2013 Adobe Systems Inc. All right reserved.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  */
24
25 #include "config.h"
26 #include "LineBreaker.h"
27
28 #include "BreakingContextInlineHeaders.h"
29 #include "RenderCombineText.h"
30
31 namespace WebCore {
32
33 void LineBreaker::reset()
34 {
35     m_positionedObjects.clear();
36     m_hyphenated = false;
37     m_clear = CNONE;
38 }
39
40 // FIXME: The entire concept of the skipTrailingWhitespace function is flawed, since we really need to be building
41 // line boxes even for containers that may ultimately collapse away. Otherwise we'll never get positioned
42 // elements quite right. In other words, we need to build this function's work into the normal line
43 // object iteration process.
44 // NB. this function will insert any floating elements that would otherwise
45 // be skipped but it will not position them.
46 void LineBreaker::skipTrailingWhitespace(InlineIterator& iterator, const LineInfo& lineInfo)
47 {
48     while (!iterator.atEnd() && !requiresLineBox(iterator, lineInfo, TrailingWhitespace)) {
49         RenderObject& object = *iterator.renderer();
50         if (object.isOutOfFlowPositioned())
51             setStaticPositions(m_block, downcast<RenderBox>(object));
52         else if (object.isFloating())
53             m_block.insertFloatingObject(downcast<RenderBox>(object));
54         iterator.increment();
55     }
56 }
57
58 void LineBreaker::skipLeadingWhitespace(InlineBidiResolver& resolver, LineInfo& lineInfo, FloatingObject* lastFloatFromPreviousLine, LineWidth& width)
59 {
60     while (!resolver.position().atEnd() && !requiresLineBox(resolver.position(), lineInfo, LeadingWhitespace)) {
61         RenderObject& object = *resolver.position().renderer();
62         if (object.isOutOfFlowPositioned()) {
63             setStaticPositions(m_block, downcast<RenderBox>(object));
64             if (object.style().isOriginalDisplayInlineType()) {
65                 resolver.runs().addRun(new BidiRun(0, 1, object, resolver.context(), resolver.dir()));
66                 lineInfo.incrementRunsFromLeadingWhitespace();
67             }
68         } else if (object.isFloating())
69             m_block.positionNewFloatOnLine(m_block.insertFloatingObject(downcast<RenderBox>(object)), lastFloatFromPreviousLine, lineInfo, width);
70         else if (is<RenderCombineText>(object) && object.style().hasTextCombine() && !downcast<RenderCombineText>(object).isCombined()) {
71             downcast<RenderCombineText>(object).combineText();
72             if (downcast<RenderCombineText>(object).isCombined())
73                 continue;
74         }
75         resolver.increment();
76     }
77     resolver.commitExplicitEmbedding();
78 }
79
80 InlineIterator LineBreaker::nextLineBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurements)
81 {
82     return nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
83 }
84
85 InlineIterator LineBreaker::nextSegmentBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurements)
86 {
87     reset();
88
89     ASSERT(resolver.position().root() == &m_block);
90
91     bool appliedStartWidth = resolver.position().offset();
92
93     LineWidth width(m_block, lineInfo.isFirstLine(), requiresIndent(lineInfo.isFirstLine(), lineInfo.previousLineBrokeCleanly(), m_block.style()));
94
95     skipLeadingWhitespace(resolver, lineInfo, lastFloatFromPreviousLine, width);
96
97     if (resolver.position().atEnd())
98         return resolver.position();
99
100     BreakingContext context(*this, resolver, lineInfo, width, renderTextInfo, lastFloatFromPreviousLine, appliedStartWidth, m_block);
101
102     while (context.currentObject()) {
103         context.initializeForCurrentObject();
104         if (context.currentObject()->isBR()) {
105             context.handleBR(m_clear);
106         } else if (context.currentObject()->isOutOfFlowPositioned()) {
107             context.handleOutOfFlowPositioned(m_positionedObjects);
108         } else if (context.currentObject()->isFloating()) {
109             context.handleFloat();
110         } else if (context.currentObject()->isRenderInline()) {
111             context.handleEmptyInline();
112         } else if (context.currentObject()->isReplaced()) {
113             context.handleReplaced();
114         } else if (context.currentObject()->isText()) {
115             if (context.handleText(wordMeasurements, m_hyphenated, consecutiveHyphenatedLines)) {
116                 // We've hit a hard text line break. Our line break iterator is updated, so go ahead and early return.
117                 return context.lineBreak();
118             }
119         } else if (context.currentObject()->isLineBreakOpportunity())
120             context.commitLineBreakAtCurrentWidth(*context.currentObject());
121         else
122             ASSERT_NOT_REACHED();
123
124         if (context.atEnd())
125             return context.handleEndOfLine();
126
127         context.commitAndUpdateLineBreakIfNeeded();
128
129         if (context.atEnd())
130             return context.handleEndOfLine();
131
132         context.increment();
133     }
134
135     context.clearLineBreakIfFitsOnLine(true);
136
137     return context.handleEndOfLine();
138 }
139
140 }