Simple line layout: Add <br> support.
[WebKit-https.git] / Source / WebCore / rendering / SimpleLineLayoutTextFragmentIterator.h
1 /*
2  * Copyright (C) 2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #ifndef SimpleLineLayoutTextFragmentIterator_h
27 #define SimpleLineLayoutTextFragmentIterator_h
28
29 #include "RenderLineBreak.h"
30 #include "RenderStyle.h"
31 #include "SimpleLineLayoutFlowContents.h"
32 #include "TextBreakIterator.h"
33 #include "break_lines.h"
34
35 namespace WebCore {
36 class RenderBlockFlow;
37
38 namespace SimpleLineLayout {
39
40 class TextFragmentIterator  {
41 public:
42     TextFragmentIterator(const RenderBlockFlow&);
43     class TextFragment {
44     public:
45         enum Type { ContentEnd, SoftLineBreak, HardLineBreak, Whitespace, NonWhitespace };
46         TextFragment() = default;
47         TextFragment(unsigned start, unsigned end, float width, Type type, bool isLastInRenderer = false, bool overlapsToNextRenderer = false, bool isCollapsed = false, bool isCollapsible = false, bool isBreakable = false)
48             : m_start(start)
49             , m_end(end)
50             , m_width(width)
51             , m_type(type)
52             , m_isLastInRenderer(isLastInRenderer)
53             , m_overlapsToNextRenderer(overlapsToNextRenderer)
54             , m_isCollapsed(isCollapsed)
55             , m_isCollapsible(isCollapsible)
56             , m_isBreakable(isBreakable)
57         {
58         }
59
60         unsigned start() const { return m_start; }
61         unsigned end() const { return m_end; }
62         float width() const { return m_width; }
63         Type type() const { return m_type; }
64         bool overlapsToNextRenderer() const { return m_overlapsToNextRenderer; }
65         bool isLastInRenderer() const { return m_isLastInRenderer; }
66         bool isLineBreak() const { return m_type == SoftLineBreak || m_type == HardLineBreak; }
67         bool isCollapsed() const { return m_isCollapsed; }
68         bool isCollapsible() const { return m_isCollapsible; }
69         bool isBreakable() const { return m_isBreakable; }
70
71         bool isEmpty() const { return start() == end() && !isLineBreak(); }
72         TextFragment split(unsigned splitPosition, const TextFragmentIterator&);
73         bool operator==(const TextFragment& other) const
74         {
75             return m_start == other.m_start
76                 && m_end == other.m_end
77                 && m_width == other.m_width
78                 && m_type == other.m_type
79                 && m_isLastInRenderer == other.m_isLastInRenderer
80                 && m_overlapsToNextRenderer == other.m_overlapsToNextRenderer
81                 && m_isCollapsed == other.m_isCollapsed
82                 && m_isCollapsible == other.m_isCollapsible
83                 && m_isBreakable == other.m_isBreakable;
84         }
85
86     private:
87         unsigned m_start { 0 };
88         unsigned m_end { 0 };
89         float m_width { 0 };
90         Type m_type { NonWhitespace };
91         bool m_isLastInRenderer { false };
92         bool m_overlapsToNextRenderer { false };
93         bool m_isCollapsed { false };
94         bool m_isCollapsible { false };
95         bool m_isBreakable { false };
96     };
97     TextFragment nextTextFragment(float xPosition = 0);
98     void revertToFragment(const TextFragment&);
99     float textWidth(unsigned startPosition, unsigned endPosition, float xPosition) const;
100
101     struct Style {
102         explicit Style(const RenderStyle&);
103
104         const FontCascade& font;
105         ETextAlign textAlign;
106         bool collapseWhitespace;
107         bool preserveNewline;
108         bool wrapLines;
109         bool breakWordOnOverflow;
110         float spaceWidth;
111         unsigned tabWidth;
112         AtomicString locale;
113     };
114     const Style& style() const { return m_style; }
115
116 private:
117     TextFragment findNextTextFragment(float xPosition);
118     enum PositionType { Breakable, NonWhitespace };
119     unsigned skipToNextPosition(PositionType, unsigned startPosition, float& width, float xPosition, bool& overlappingFragment);
120     bool isSoftLineBreak(unsigned position) const;
121     bool isHardLineBreak(const FlowContents::Iterator& segment) const;
122     template <typename CharacterType> unsigned nextBreakablePosition(const FlowContents::Segment&, unsigned startPosition);
123     template <typename CharacterType> unsigned nextNonWhitespacePosition(const FlowContents::Segment&, unsigned startPosition);
124     template <typename CharacterType> float runWidth(const FlowContents::Segment&, unsigned startPosition, unsigned endPosition, float xPosition) const;
125
126     FlowContents m_flowContents;
127     FlowContents::Iterator m_currentSegment;
128     LazyLineBreakIterator m_lineBreakIterator;
129     const Style m_style;
130     unsigned m_position { 0 };
131     bool m_atEndOfSegment { false };
132 };
133
134 inline TextFragmentIterator::TextFragment TextFragmentIterator::TextFragment::split(unsigned splitPosition, const TextFragmentIterator& textFragmentIterator)
135 {
136     auto updateFragmentProperties = [&textFragmentIterator] (TextFragment& fragment)
137     {
138         fragment.m_width = 0;
139         if (fragment.start() != fragment.end())
140             fragment.m_width = textFragmentIterator.textWidth(fragment.start(), fragment.end(), 0);
141         if (fragment.start() + 1 > fragment.end())
142             return;
143         fragment.m_isCollapsed = false;
144         fragment.m_isBreakable = false;
145     };
146
147     TextFragment newFragment(*this);
148     m_end = splitPosition;
149     updateFragmentProperties(*this);
150
151     newFragment.m_start = splitPosition;
152     updateFragmentProperties(newFragment);
153     return newFragment;
154 }
155
156 inline bool TextFragmentIterator::isSoftLineBreak(unsigned position) const
157 {
158     const auto& segment = *m_currentSegment;
159     ASSERT(segment.start <= position && position < segment.end);
160     return m_style.preserveNewline && segment.text[position - segment.start] == '\n';
161 }
162
163 inline bool TextFragmentIterator::isHardLineBreak(const FlowContents::Iterator& segment) const
164 {
165     ASSERT(segment->start != segment->end || (segment->start == segment->end && is<RenderLineBreak>(segment->renderer)));
166     return segment->start == segment->end;
167 }
168
169 }
170 }
171
172 #endif