• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 #ifndef MINIKIN_MEASURED_TEXT_H
18 #define MINIKIN_MEASURED_TEXT_H
19 
20 #include <deque>
21 #include <vector>
22 
23 #include "minikin/FontCollection.h"
24 #include "minikin/Layout.h"
25 #include "minikin/LayoutPieces.h"
26 #include "minikin/LineBreakStyle.h"
27 #include "minikin/Macros.h"
28 #include "minikin/MinikinFont.h"
29 #include "minikin/Range.h"
30 #include "minikin/U16StringPiece.h"
31 
32 namespace minikin {
33 
34 class Run {
35 public:
Run(const Range & range)36     Run(const Range& range) : mRange(range) {}
~Run()37     virtual ~Run() {}
38 
39     // Returns true if this run is RTL. Otherwise returns false.
40     virtual bool isRtl() const = 0;
41 
42     // Returns true if this run can be broken into multiple pieces for line breaking.
43     virtual bool canBreak() const = 0;
44 
45     // Return the line break style(lb) for this run.
46     virtual LineBreakStyle lineBreakStyle() const = 0;
47 
48     // Return the line break word style(lw) for this run.
49     virtual LineBreakWordStyle lineBreakWordStyle() const = 0;
50 
51     // Returns the locale list ID for this run.
52     virtual uint32_t getLocaleListId() const = 0;
53 
54     // Fills the each character's advances, extents and overhangs.
55     virtual void getMetrics(const U16StringPiece& text, std::vector<float>* advances,
56                             LayoutPieces* precomputed, LayoutPieces* outPieces) const = 0;
57 
58     virtual std::pair<float, MinikinRect> getBounds(const U16StringPiece& text, const Range& range,
59                                                     const LayoutPieces& pieces) const = 0;
60     virtual MinikinExtent getExtent(const U16StringPiece& text, const Range& range,
61                                     const LayoutPieces& pieces) const = 0;
62 
63     virtual void appendLayout(const U16StringPiece& text, const Range& range,
64                               const Range& contextRange, const LayoutPieces& pieces,
65                               const MinikinPaint& paint, uint32_t outOrigin,
66                               StartHyphenEdit startHyphen, EndHyphenEdit endHyphen,
67                               Layout* outLayout) const = 0;
68 
69     virtual float measureText(const U16StringPiece& text) const = 0;
70 
71     // Following two methods are only called when the implementation returns true for
72     // canBreak method.
73 
74     // Returns the paint pointer used for this run.
75     // Returns null if canBreak has not returned true.
getPaint()76     virtual const MinikinPaint* getPaint() const { return nullptr; }
77 
78     // Measures the hyphenation piece and fills each character's advances and overhangs.
measureHyphenPiece(const U16StringPiece &,const Range &,StartHyphenEdit,EndHyphenEdit,LayoutPieces *)79     virtual float measureHyphenPiece(const U16StringPiece& /* text */,
80                                      const Range& /* hyphenPieceRange */,
81                                      StartHyphenEdit /* startHyphen */,
82                                      EndHyphenEdit /* endHyphen */,
83                                      LayoutPieces* /* pieces */) const {
84         return 0.0;
85     }
86 
getRange()87     inline const Range& getRange() const { return mRange; }
88 
89 protected:
90     const Range mRange;
91 };
92 
93 class StyleRun : public Run {
94 public:
StyleRun(const Range & range,MinikinPaint && paint,int lineBreakStyle,int lineBreakWordStyle,bool isRtl)95     StyleRun(const Range& range, MinikinPaint&& paint, int lineBreakStyle, int lineBreakWordStyle,
96              bool isRtl)
97             : Run(range),
98               mPaint(std::move(paint)),
99               mLineBreakStyle(lineBreakStyle),
100               mLineBreakWordStyle(lineBreakWordStyle),
101               mIsRtl(isRtl) {}
102 
canBreak()103     bool canBreak() const override { return true; }
lineBreakStyle()104     LineBreakStyle lineBreakStyle() const override {
105         return static_cast<LineBreakStyle>(mLineBreakStyle);
106     }
lineBreakWordStyle()107     LineBreakWordStyle lineBreakWordStyle() const override {
108         return static_cast<LineBreakWordStyle>(mLineBreakWordStyle);
109     }
getLocaleListId()110     uint32_t getLocaleListId() const override { return mPaint.localeListId; }
isRtl()111     bool isRtl() const override { return mIsRtl; }
112 
113     void getMetrics(const U16StringPiece& text, std::vector<float>* advances,
114                     LayoutPieces* precomputed, LayoutPieces* outPieces) const override;
115 
116     std::pair<float, MinikinRect> getBounds(const U16StringPiece& text, const Range& range,
117                                             const LayoutPieces& pieces) const override;
118 
119     MinikinExtent getExtent(const U16StringPiece& text, const Range& range,
120                             const LayoutPieces& pieces) const override;
121 
122     void appendLayout(const U16StringPiece& text, const Range& range, const Range& contextRange,
123                       const LayoutPieces& pieces, const MinikinPaint& paint, uint32_t outOrigin,
124                       StartHyphenEdit startHyphen, EndHyphenEdit endHyphen,
125                       Layout* outLayout) const override;
126 
getPaint()127     const MinikinPaint* getPaint() const override { return &mPaint; }
128 
129     float measureHyphenPiece(const U16StringPiece& text, const Range& range,
130                              StartHyphenEdit startHyphen, EndHyphenEdit endHyphen,
131                              LayoutPieces* pieces) const override;
132     float measureText(const U16StringPiece& text) const;
133 
134 private:
135     MinikinPaint mPaint;
136     int mLineBreakStyle;
137     int mLineBreakWordStyle;
138     const bool mIsRtl;
139 };
140 
141 class ReplacementRun : public Run {
142 public:
ReplacementRun(const Range & range,float width,uint32_t localeListId)143     ReplacementRun(const Range& range, float width, uint32_t localeListId)
144             : Run(range), mWidth(width), mLocaleListId(localeListId) {}
145 
isRtl()146     bool isRtl() const { return false; }
canBreak()147     bool canBreak() const { return false; }
lineBreakStyle()148     LineBreakStyle lineBreakStyle() const override { return LineBreakStyle::None; }
lineBreakWordStyle()149     LineBreakWordStyle lineBreakWordStyle() const override { return LineBreakWordStyle::None; }
getLocaleListId()150     uint32_t getLocaleListId() const { return mLocaleListId; }
151 
getMetrics(const U16StringPiece &,std::vector<float> * advances,LayoutPieces *,LayoutPieces *)152     void getMetrics(const U16StringPiece& /* text */, std::vector<float>* advances,
153                     LayoutPieces* /* precomputed */, LayoutPieces* /* outPieces */) const override {
154         (*advances)[mRange.getStart()] = mWidth;
155         // TODO: Get the extents information from the caller.
156     }
157 
getBounds(const U16StringPiece &,const Range &,const LayoutPieces &)158     std::pair<float, MinikinRect> getBounds(const U16StringPiece& /* text */,
159                                             const Range& /* range */,
160                                             const LayoutPieces& /* pieces */) const override {
161         // Bounding Box is not used in replacement run.
162         return std::make_pair(mWidth, MinikinRect());
163     }
164 
getExtent(const U16StringPiece &,const Range &,const LayoutPieces &)165     MinikinExtent getExtent(const U16StringPiece& /* text */, const Range& /* range */,
166                             const LayoutPieces& /* pieces */) const override {
167         return MinikinExtent();
168     }
169 
appendLayout(const U16StringPiece &,const Range &,const Range &,const LayoutPieces &,const MinikinPaint &,uint32_t,StartHyphenEdit,EndHyphenEdit,Layout *)170     void appendLayout(const U16StringPiece& /* text */, const Range& /* range */,
171                       const Range& /* contextRange */, const LayoutPieces& /* pieces */,
172                       const MinikinPaint& /* paint */, uint32_t /* outOrigin */,
173                       StartHyphenEdit /* startHyphen */, EndHyphenEdit /* endHyphen */,
174                       Layout* /* outLayout*/) const override {}
175 
measureText(const U16StringPiece &)176     float measureText(const U16StringPiece&) const { return 0; }
177 
178 private:
179     const float mWidth;
180     const uint32_t mLocaleListId;
181 };
182 
183 // Represents a hyphenation break point.
184 struct HyphenBreak {
185     // The break offset.
186     uint32_t offset;
187 
188     // The hyphenation type.
189     HyphenationType type;
190 
191     // The width of preceding piece after break at hyphenation point.
192     float first;
193 
194     // The width of following piece after break at hyphenation point.
195     float second;
196 
HyphenBreakHyphenBreak197     HyphenBreak(uint32_t offset, HyphenationType type, float first, float second)
198             : offset(offset), type(type), first(first), second(second) {}
199 };
200 
201 class MeasuredText {
202 public:
203     // Character widths.
204     std::vector<float> widths;
205 
206     // Hyphenation points.
207     std::vector<HyphenBreak> hyphenBreaks;
208 
209     // The style information.
210     std::vector<std::unique_ptr<Run>> runs;
211 
212     // The copied layout pieces for construcing final layouts.
213     // TODO: Stop assigning width/extents if layout pieces are available for reducing memory impact.
214     LayoutPieces layoutPieces;
215 
getMemoryUsage()216     uint32_t getMemoryUsage() const {
217         return sizeof(float) * widths.size() + sizeof(HyphenBreak) * hyphenBreaks.size() +
218                layoutPieces.getMemoryUsage();
219     }
220 
221     Layout buildLayout(const U16StringPiece& textBuf, const Range& range, const Range& contextRange,
222                        const MinikinPaint& paint, StartHyphenEdit startHyphen,
223                        EndHyphenEdit endHyphen);
224     MinikinRect getBounds(const U16StringPiece& textBuf, const Range& range) const;
225     MinikinExtent getExtent(const U16StringPiece& textBuf, const Range& range) const;
226 
227     MeasuredText(MeasuredText&&) = default;
228     MeasuredText& operator=(MeasuredText&&) = default;
229 
230     MINIKIN_PREVENT_COPY_AND_ASSIGN(MeasuredText);
231 
232 private:
233     friend class MeasuredTextBuilder;
234 
235     void measure(const U16StringPiece& textBuf, bool computeHyphenation, bool computeLayout,
236                  bool ignoreHyphenKerning, MeasuredText* hint);
237 
238     // Use MeasuredTextBuilder instead.
MeasuredText(const U16StringPiece & textBuf,std::vector<std::unique_ptr<Run>> && runs,bool computeHyphenation,bool computeLayout,bool ignoreHyphenKerning,MeasuredText * hint)239     MeasuredText(const U16StringPiece& textBuf, std::vector<std::unique_ptr<Run>>&& runs,
240                  bool computeHyphenation, bool computeLayout, bool ignoreHyphenKerning,
241                  MeasuredText* hint)
242             : widths(textBuf.size()), runs(std::move(runs)) {
243         measure(textBuf, computeHyphenation, computeLayout, ignoreHyphenKerning, hint);
244     }
245 };
246 
247 class MeasuredTextBuilder {
248 public:
MeasuredTextBuilder()249     MeasuredTextBuilder() {}
250 
addStyleRun(int32_t start,int32_t end,MinikinPaint && paint,int lineBreakStyle,int lineBreakWordStyle,bool isRtl)251     void addStyleRun(int32_t start, int32_t end, MinikinPaint&& paint, int lineBreakStyle,
252                      int lineBreakWordStyle, bool isRtl) {
253         mRuns.emplace_back(std::make_unique<StyleRun>(Range(start, end), std::move(paint),
254                                                       lineBreakStyle, lineBreakWordStyle, isRtl));
255     }
256 
addReplacementRun(int32_t start,int32_t end,float width,uint32_t localeListId)257     void addReplacementRun(int32_t start, int32_t end, float width, uint32_t localeListId) {
258         mRuns.emplace_back(
259                 std::make_unique<ReplacementRun>(Range(start, end), width, localeListId));
260     }
261 
262     template <class T, typename... Args>
addCustomRun(Args &&...args)263     void addCustomRun(Args&&... args) {
264         mRuns.emplace_back(std::make_unique<T>(std::forward<Args>(args)...));
265     }
266 
build(const U16StringPiece & textBuf,bool computeHyphenation,bool computeLayout,bool ignoreHyphenKerning,MeasuredText * hint)267     std::unique_ptr<MeasuredText> build(const U16StringPiece& textBuf, bool computeHyphenation,
268                                         bool computeLayout, bool ignoreHyphenKerning,
269                                         MeasuredText* hint) {
270         // Unable to use make_unique here since make_unique is not a friend of MeasuredText.
271         return std::unique_ptr<MeasuredText>(new MeasuredText(textBuf, std::move(mRuns),
272                                                               computeHyphenation, computeLayout,
273                                                               ignoreHyphenKerning, hint));
274     }
275 
276     MINIKIN_PREVENT_COPY_ASSIGN_AND_MOVE(MeasuredTextBuilder);
277 
278 private:
279     std::vector<std::unique_ptr<Run>> mRuns;
280 };
281 
282 }  // namespace minikin
283 
284 #endif  // MINIKIN_MEASURED_TEXT_H
285