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