[LCF][IFC] Add support for hyphenation.
[WebKit-https.git] / Source / WebCore / layout / inlineformatting / textlayout / simple / SimpleLineBreaker.h
1 /*
2  * Copyright (C) 2018 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 #pragma once
27
28 #if ENABLE(LAYOUT_FORMATTING_CONTEXT)
29
30 #include "RenderStyleConstants.h"
31 #include "Runs.h"
32 #include <wtf/IsoMalloc.h>
33
34 namespace WebCore {
35
36 class FontCascade;
37 class RenderStyle;
38
39 namespace Layout {
40
41 class TextContentProvider;
42 struct TextRunSplitPair;
43
44 class SimpleLineBreaker {
45     WTF_MAKE_ISO_ALLOCATED(SimpleLineBreaker);
46 public:
47     struct LineConstraint {
48         // verticalPosition sets the bottom edge for this constraint. Last entry in the list
49         // should always be std::nullopt indicating that left/right pair is set for the rest of the lines
50         // (Normally there's only one entry with the left/right block edges).
51         std::optional<float> verticalPosition;
52         float left { 0 };
53         float right { 0 };
54     };
55     using LineConstraintList = Vector<LineConstraint>;
56     SimpleLineBreaker(const Vector<TextRun>&, const TextContentProvider&, LineConstraintList&&, const RenderStyle&);
57
58     void setLineHeight(float lineHeight) { m_lineHeight = lineHeight; }
59
60     Vector<LayoutRun> runs();
61
62 private:
63     struct Style {
64         explicit Style(const RenderStyle&);
65
66         const FontCascade& font;
67         bool wrapLines { false };
68         bool breakAnyWordOnOverflow { false };
69         bool breakFirstWordOnOverflow { false };
70         bool collapseWhitespace { false };
71         bool preWrap { false };
72         bool preserveNewline { false };
73         TextAlignMode textAlign { TextAlignMode::Left };
74         bool shouldHyphenate;
75         float hyphenStringWidth;
76         ItemPosition hyphenLimitBefore;
77         ItemPosition hyphenLimitAfter;
78         AtomicString locale;
79         std::optional<unsigned> hyphenLimitLines;
80     };
81
82     class TextRunList {
83     public:
84         TextRunList(const Vector<TextRun>& textRuns);
85
86         std::optional<TextRun> current() const;
87         TextRunList& operator++();
88
89         void overrideCurrent(TextRun textRun) { m_overrideTextRun = textRun; }
90         bool isCurrentOverridden() const { return m_overrideTextRun.has_value(); }
91
92     private:
93         const Vector<TextRun>& m_textRuns;
94         unsigned m_currentIndex { 0 };
95         std::optional<TextRun> m_overrideTextRun;
96     };
97
98     class Line {
99     public:
100         Line(Vector<LayoutRun>& layoutRuns);
101
102         void append(const TextRun&);
103         float availableWidth() const { return m_availableWidth - m_runsWidth; }
104         bool hasContent() const { return m_runsWidth; }
105
106         void reset();
107         bool hasTrailingWhitespace() const { return m_trailingWhitespaceWidth; }
108         bool isWhitespaceOnly() const { return m_runsWidth == m_trailingWhitespaceWidth; }
109         void collapseTrailingWhitespace();
110
111         void setAvailableWidth(float availableWidth) { m_availableWidth = availableWidth; }
112         void setLeft(float left) { m_left = left; }
113         void setTextAlign(TextAlignMode);
114         void setCollapseWhitespace(bool collapseWhitespace) { m_style.collapseWhitespace = collapseWhitespace; }
115
116         void closeLastRun();
117         void adjustRunsForTextAlign(bool lastLine);
118
119     private:
120         struct Style {
121             bool collapseWhitespace { false };
122             TextAlignMode textAlign { TextAlignMode::Left };
123         };
124
125         float adjustedLeftForTextAlign(TextAlignMode) const;
126         void justifyRuns();
127         void collectExpansionOpportunities(const TextRun&, bool textRunCreatesNewLayoutRun);
128
129         Vector<LayoutRun>& m_layoutRuns;
130         Style m_style;
131
132         float m_runsWidth { 0 };
133         float m_availableWidth { 0 };
134         float m_left { 0 };
135         float m_trailingWhitespaceWidth { 0 };
136         unsigned m_firstRunIndex { 0 };
137         std::optional<TextRun> m_lastTextRun;
138         std::optional<TextRun> m_lastNonWhitespaceTextRun;
139         bool m_collectExpansionOpportunities { false };
140         struct ExpansionOpportunity {
141             unsigned count { 0 };
142             ExpansionBehavior behavior { DefaultExpansion };
143         };
144         Vector<ExpansionOpportunity> m_expansionOpportunityList;
145         std::optional<ExpansionOpportunity> m_lastNonWhitespaceExpansionOppportunity;
146     };
147
148     void handleLineStart();
149     void handleLineEnd();
150     bool wrapContentOnOverflow() const { return m_style.wrapLines || m_style.breakFirstWordOnOverflow || m_style.breakAnyWordOnOverflow; }
151     void collectRuns();
152     void createRunsForLine();
153     void handleOverflownRun();
154     void collapseLeadingWhitespace();
155     void collapseTrailingWhitespace();
156     bool splitTextRun(const TextRun&);
157     TextRunSplitPair split(const TextRun&, float leftSideMaximumWidth) const;
158     std::optional<ContentPosition> hyphenPositionBefore(const TextRun&, ContentPosition before) const;
159     std::optional<ContentPosition> adjustSplitPositionWithHyphenation(const TextRun&, ContentPosition splitPosition, float leftSideWidth) const;
160     LineConstraint lineConstraint(float verticalPosition);
161     float verticalPosition() const { return m_numberOfLines * m_lineHeight; }
162
163     const TextContentProvider& m_contentProvider;
164     const Style m_style;
165
166     TextRunList m_textRunList;
167
168     Vector<LayoutRun> m_layoutRuns;
169     Line m_currentLine;
170
171     LineConstraintList m_lineConstraintList;
172     ConstVectorIterator<LineConstraint> m_lineConstraintIterator;
173
174     unsigned m_numberOfLines { 0 };
175     bool m_previousLineHasNonForcedContent { false };
176     float m_lineHeight { 0 };
177     bool m_hyphenationIsDisabled { false };
178     unsigned m_numberOfPrecedingLinesWithHyphen { 0 };
179 };
180
181 inline std::optional<TextRun> SimpleLineBreaker::TextRunList::current() const
182 {
183     if (m_overrideTextRun)
184         return m_overrideTextRun;
185
186     if (m_currentIndex < m_textRuns.size())
187         return m_textRuns[m_currentIndex];
188
189     return { };
190 }
191
192 inline SimpleLineBreaker::TextRunList& SimpleLineBreaker::TextRunList::operator++()
193 {
194     m_overrideTextRun = { };
195     ++m_currentIndex;
196     return *this;
197 }
198
199 }
200 }
201 #endif