Flutter Engine
LineBreaker.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /**
18  * A module for breaking paragraphs into lines, supporting high quality
19  * hyphenation and justification.
20  */
21 
22 #ifndef MINIKIN_LINE_BREAKER_H
23 #define MINIKIN_LINE_BREAKER_H
24 
25 #ifndef U_USING_ICU_NAMESPACE
26 #define U_USING_ICU_NAMESPACE 0
27 #endif // U_USING_ICU_NAMESPACE
28 
29 #include <cmath>
30 #include <vector>
31 #include "minikin/FontCollection.h"
32 #include "minikin/Hyphenator.h"
33 #include "minikin/MinikinFont.h"
34 #include "minikin/WordBreaker.h"
35 #include "unicode/brkiter.h"
36 #include "unicode/locid.h"
37 
38 namespace minikin {
39 
44 };
45 
50 };
51 
52 bool isLineEndSpace(uint16_t c);
53 
54 // TODO: want to generalize to be able to handle array of line widths
55 class LineWidths {
56  public:
57  void setWidths(float firstWidth, int firstWidthLineCount, float restWidth) {
58  mFirstWidth = firstWidth;
59  mFirstWidthLineCount = firstWidthLineCount;
60  mRestWidth = restWidth;
61  }
62  void setIndents(const std::vector<float>& indents) { mIndents = indents; }
63  bool isConstant() const {
64  // technically mFirstWidthLineCount == 0 would count too, but doesn't
65  // actually happen
66  return mRestWidth == mFirstWidth && mIndents.empty();
67  }
68  float getLineWidth(int line) const {
69  float width = (line < mFirstWidthLineCount) ? mFirstWidth : mRestWidth;
70  if (!mIndents.empty()) {
71  if ((size_t)line < mIndents.size()) {
72  width -= mIndents[line];
73  } else {
74  width -= mIndents.back();
75  }
76  }
77  return width;
78  }
79  void clear() { mIndents.clear(); }
80 
81  private:
82  float mFirstWidth;
83  int mFirstWidthLineCount;
84  float mRestWidth;
85  std::vector<float> mIndents;
86 };
87 
88 class LineBreaker {
89  public:
90  const static int kTab_Shift =
91  29; // keep synchronized with TAB_MASK in StaticLayout.java
92 
93  // Note: Locale persists across multiple invocations (it is not cleaned up by
94  // finish()), explicitly to avoid the cost of creating ICU BreakIterator
95  // objects. It should always be set on the first invocation, but callers are
96  // encouraged not to call again unless locale has actually changed. That logic
97  // could be here but it's better for performance that it's upstream because of
98  // the cost of constructing and comparing the ICU Locale object.
99  // Note: caller is responsible for managing lifetime of hyphenator
100  void setLocale(const icu::Locale& locale, Hyphenator* hyphenator);
101 
102  void resize(size_t size) {
103  mTextBuf.resize(size);
104  mCharWidths.resize(size);
105  }
106 
107  size_t size() const { return mTextBuf.size(); }
108 
109  uint16_t* buffer() { return mTextBuf.data(); }
110 
111  float* charWidths() { return mCharWidths.data(); }
112 
113  // set text to current contents of buffer
114  void setText();
115 
116  void setLineWidths(float firstWidth,
117  int firstWidthLineCount,
118  float restWidth);
119 
120  void setIndents(const std::vector<float>& indents);
121 
122  BreakStrategy getStrategy() const { return mStrategy; }
123 
124  void setStrategy(BreakStrategy strategy) { mStrategy = strategy; }
125 
126  void setJustified(bool justified) { mJustified = justified; }
127 
129  return mHyphenationFrequency;
130  }
131 
133  mHyphenationFrequency = frequency;
134  }
135 
136  // TODO: this class is actually fairly close to being general and not tied to
137  // using Minikin to do the shaping of the strings. The main thing that would
138  // need to be changed is having some kind of callback (or virtual class, or
139  // maybe even template), which could easily be instantiated with Minikin's
140  // Layout. Future work for when needed.
141  float addStyleRun(MinikinPaint* paint,
142  const std::shared_ptr<FontCollection>& typeface,
143  FontStyle style,
144  size_t start,
145  size_t end,
146  bool isRtl);
147 
148  void addReplacement(size_t start, size_t end, float width);
149 
150  size_t computeBreaks();
151 
152  // libtxt: Add ability to set custom char widths. This allows manual
153  // definition of the widths of arbitrary glyphs. To linebreak properly, call
154  // addStyleRun with nullptr as the paint property, which will lead it to
155  // assume the width has already been calculated. Used for properly breaking
156  // inline placeholders.
157  void setCustomCharWidth(size_t offset, float width);
158 
159  const int* getBreaks() const { return mBreaks.data(); }
160 
161  const float* getWidths() const { return mWidths.data(); }
162 
163  const int* getFlags() const { return mFlags.data(); }
164 
165  void finish();
166 
167  private:
168  // ParaWidth is used to hold cumulative width from beginning of paragraph.
169  // Note that for very large paragraphs, accuracy could degrade using only
170  // 32-bit float. Note however that float is used extensively on the Java side
171  // for this. This is a typedef so that we can easily change it based on
172  // performance/accuracy tradeoff.
173  typedef double ParaWidth;
174 
175  // A single candidate break
176  struct Candidate {
177  size_t offset; // offset to text buffer, in code units
178  size_t prev; // index to previous break
179  ParaWidth preBreak; // width of text until this point, if we decide to not
180  // break here
181  ParaWidth postBreak; // width of text until this point, if we decide to
182  // break here
183  float penalty; // penalty of this break (for example, hyphen penalty)
184  float score; // best score found for this break
185  size_t lineNumber; // only updated for non-constant line widths
186  size_t preSpaceCount; // preceding space count before breaking
187  size_t postSpaceCount; // preceding space count after breaking
188  HyphenationType hyphenType;
189  };
190 
191  float currentLineWidth() const;
192 
193  void addWordBreak(size_t offset,
194  ParaWidth preBreak,
195  ParaWidth postBreak,
196  size_t preSpaceCount,
197  size_t postSpaceCount,
198  float penalty,
199  HyphenationType hyph);
200 
201  void addCandidate(Candidate cand);
202  void pushGreedyBreak();
203 
204  // push an actual break to the output. Takes care of setting flags for tab
205  void pushBreak(int offset, float width, uint8_t hyphenEdit);
206 
207  float getSpaceWidth() const;
208 
209  void computeBreaksGreedy();
210 
211  void computeBreaksOptimal(bool isRectangular);
212 
213  void finishBreaksOptimal();
214 
215  WordBreaker mWordBreaker;
216  icu::Locale mLocale;
217  std::vector<uint16_t> mTextBuf;
218  std::vector<float> mCharWidths;
219 
220  Hyphenator* mHyphenator;
221  std::vector<HyphenationType> mHyphBuf;
222 
223  // layout parameters
225  HyphenationFrequency mHyphenationFrequency = kHyphenationFrequency_Normal;
226  bool mJustified;
227  LineWidths mLineWidths;
228 
229  // result of line breaking
230  std::vector<int> mBreaks;
231  std::vector<float> mWidths;
232  std::vector<int> mFlags;
233 
234  ParaWidth mWidth = 0;
235  std::vector<Candidate> mCandidates;
236  float mLinePenalty = 0.0f;
237 
238  // the following are state for greedy breaker (updated while adding style
239  // runs)
240  size_t mLastBreak;
241  size_t mBestBreak;
242  float mBestScore;
243  ParaWidth mPreBreak; // prebreak of last break
244  uint32_t mLastHyphenation; // hyphen edit of last break kept for next line
245  int mFirstTabIndex;
246  size_t mSpaceCount;
247 };
248 
249 } // namespace minikin
250 
251 #endif // MINIKIN_LINE_BREAKER_H
const int * getBreaks() const
Definition: LineBreaker.h:159
HyphenationFrequency getHyphenationFrequency() const
Definition: LineBreaker.h:128
void setHyphenationFrequency(HyphenationFrequency frequency)
Definition: LineBreaker.h:132
void setIndents(const std::vector< float > &indents)
Definition: LineBreaker.h:62
void resize(size_t size)
Definition: LineBreaker.h:102
constexpr std::size_t size(T(&array)[N])
Definition: size.h:13
uint16_t * buffer()
Definition: LineBreaker.h:109
void setStrategy(BreakStrategy strategy)
Definition: LineBreaker.h:124
HyphenationFrequency
Definition: LineBreaker.h:46
void setJustified(bool justified)
Definition: LineBreaker.h:126
int32_t width
float getLineWidth(int line) const
Definition: LineBreaker.h:68
BreakStrategy getStrategy() const
Definition: LineBreaker.h:122
const float * getWidths() const
Definition: LineBreaker.h:161
bool isConstant() const
Definition: LineBreaker.h:63
HyphenationType
Definition: Hyphenator.h:35
const int * getFlags() const
Definition: LineBreaker.h:163
size_t size() const
Definition: LineBreaker.h:107
void setWidths(float firstWidth, int firstWidthLineCount, float restWidth)
Definition: LineBreaker.h:57
bool isLineEndSpace(uint16_t c)