xref: /aosp_15_r20/frameworks/minikin/include/minikin/Layout.h (revision 834a2baab5fdfc28e9a428ee87c7ea8f6a06a53d)
1 /*
2  * Copyright (C) 2013 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_LAYOUT_H
18 #define MINIKIN_LAYOUT_H
19 
20 #include <gtest/gtest_prod.h>
21 
22 #include <memory>
23 #include <sstream>
24 #include <unordered_map>
25 #include <vector>
26 
27 #include "minikin/FontCollection.h"
28 #include "minikin/FontFileParser.h"
29 #include "minikin/LayoutCore.h"
30 #include "minikin/Range.h"
31 #include "minikin/U16StringPiece.h"
32 
33 namespace minikin {
34 
35 class Layout;
36 struct LayoutPieces;
37 
38 struct LayoutGlyph {
LayoutGlyphLayoutGlyph39     LayoutGlyph(FakedFont font, uint32_t glyph_id, uint32_t cluster, float x, float y)
40             : font(font), glyph_id(glyph_id), cluster(cluster), x(x), y(y) {}
41     FakedFont font;
42 
43     uint32_t glyph_id;
44     uint32_t cluster;
45     float x;
46     float y;
47 };
48 
49 // For gtest output
50 inline std::ostream& operator<<(std::ostream& os, const LayoutGlyph& g) {
51     std::optional<std::string> psName = FontFileParser(g.font.hbFont()).getPostScriptName();
52     return os << "{ font:" << psName.value_or("{UNKNOWN}") << ", gid:" << g.glyph_id
53               << ", cluster:" << g.cluster << ", pos=(" << g.x << "," << g.y << ") }";
54 }
55 
56 // Must be the same value with Paint.java
57 enum class Bidi : uint8_t {
58     LTR = 0b0000,          // Must be same with Paint.BIDI_LTR
59     RTL = 0b0001,          // Must be same with Paint.BIDI_RTL
60     DEFAULT_LTR = 0b0010,  // Must be same with Paint.BIDI_DEFAULT_LTR
61     DEFAULT_RTL = 0b0011,  // Must be same with Paint.BIDI_DEFAULT_RTL
62     FORCE_LTR = 0b0100,    // Must be same with Paint.BIDI_FORCE_LTR
63     FORCE_RTL = 0b0101,    // Must be same with Paint.BIDI_FORCE_RTL
64 };
65 
isRtl(Bidi bidi)66 inline bool isRtl(Bidi bidi) {
67     return static_cast<uint8_t>(bidi) & 0b0001;
68 }
isOverride(Bidi bidi)69 inline bool isOverride(Bidi bidi) {
70     return static_cast<uint8_t>(bidi) & 0b0100;
71 }
72 
73 enum RunFlag : uint8_t {
74     // The run is in the middle of the line. Neither left or right edge.
75     NONE = 0,
76     // The run is located at the most visually left of the line.
77     LEFT_EDGE = 1,
78     // The run is located at the most visually right of the line.
79     RIGHT_EDGE = 2,
80     // The run is both most visually left and most visually right, i.e. the run covers entire line.
81     WHOLE_LINE = LEFT_EDGE | RIGHT_EDGE,
82 };
83 
84 // Lifecycle and threading assumptions for Layout:
85 // The object is assumed to be owned by a single thread; multiple threads
86 // may not mutate it at the same time.
87 class Layout {
88 public:
Layout(const U16StringPiece & str,const Range & range,Bidi bidiFlags,const MinikinPaint & paint,StartHyphenEdit startHyphen,EndHyphenEdit endHyphen,uint32_t runFlag)89     Layout(const U16StringPiece& str, const Range& range, Bidi bidiFlags, const MinikinPaint& paint,
90            StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, uint32_t runFlag)
91             : mAdvance(0) {
92         doLayout(str, range, bidiFlags, paint, startHyphen, endHyphen,
93                  static_cast<RunFlag>(runFlag));
94     }
95 
96     // TODO(nona): Remove once the HWUI start calling new API.
Layout(const U16StringPiece & str,const Range & range,Bidi bidiFlags,const MinikinPaint & paint,StartHyphenEdit startHyphen,EndHyphenEdit endHyphen)97     Layout(const U16StringPiece& str, const Range& range, Bidi bidiFlags, const MinikinPaint& paint,
98            StartHyphenEdit startHyphen, EndHyphenEdit endHyphen)
99             : mAdvance(0) {
100         doLayout(str, range, bidiFlags, paint, startHyphen, endHyphen, RunFlag::NONE);
101     }
102 
Layout(uint32_t count)103     Layout(uint32_t count) : mAdvance(0) {
104         mAdvances.resize(count, 0);
105         mGlyphs.reserve(count);
106     }
107 
measureText(const U16StringPiece & str,const Range & range,Bidi bidiFlags,const MinikinPaint & paint,StartHyphenEdit startHyphen,EndHyphenEdit endHyphen,float * advances)108     static float measureText(const U16StringPiece& str, const Range& range, Bidi bidiFlags,
109                              const MinikinPaint& paint, StartHyphenEdit startHyphen,
110                              EndHyphenEdit endHyphen, float* advances) {
111         return measureText(str, range, bidiFlags, paint, startHyphen, endHyphen, advances, nullptr,
112                            nullptr, RunFlag::NONE);
113     }
114 
115     // TODO(nona): Remove once the HWUI start calling new API.
measureText(const U16StringPiece & str,const Range & range,Bidi bidiFlags,const MinikinPaint & paint,StartHyphenEdit startHyphen,EndHyphenEdit endHyphen,float * advances,MinikinRect * bounds,uint32_t * clusterCount)116     static float measureText(const U16StringPiece& str, const Range& range, Bidi bidiFlags,
117                              const MinikinPaint& paint, StartHyphenEdit startHyphen,
118                              EndHyphenEdit endHyphen, float* advances, MinikinRect* bounds,
119                              uint32_t* clusterCount) {
120         return measureText(str, range, bidiFlags, paint, startHyphen, endHyphen, advances, bounds,
121                            clusterCount, RunFlag::NONE);
122     }
123 
124     static float measureText(const U16StringPiece& str, const Range& range, Bidi bidiFlags,
125                              const MinikinPaint& paint, StartHyphenEdit startHyphen,
126                              EndHyphenEdit endHyphen, float* advances, MinikinRect* bounds,
127                              uint32_t* clusterCount, RunFlag runFlag);
128 
advances()129     const std::vector<float>& advances() const { return mAdvances; }
130 
131     // public accessors
nGlyphs()132     size_t nGlyphs() const { return mGlyphs.size(); }
getFont(int i)133     const Font* getFont(int i) const { return mGlyphs[i].font.font.get(); }
getFontRef(int i)134     const std::shared_ptr<Font>& getFontRef(int i) const { return mGlyphs[i].font.font; }
getFakery(int i)135     const FontFakery& getFakery(int i) const { return mGlyphs[i].font.fakery; }
typeface(int i)136     std::shared_ptr<MinikinFont> typeface(int i) const { return mGlyphs[i].font.typeface(); }
getGlyphId(int i)137     unsigned int getGlyphId(int i) const { return mGlyphs[i].glyph_id; }
getX(int i)138     float getX(int i) const { return mGlyphs[i].x; }
getY(int i)139     float getY(int i) const { return mGlyphs[i].y; }
getAdvance()140     float getAdvance() const { return mAdvance; }
getCharAdvance(size_t i)141     float getCharAdvance(size_t i) const { return mAdvances[i]; }
getAdvances()142     const std::vector<float>& getAdvances() const { return mAdvances; }
143 
144     // Returns number of font runs.
getFontRunCount()145     uint32_t getFontRunCount() const { return mFonts.size(); }
146     // Returns inclusive start offset of the font run.
getFontRunStart(uint32_t i)147     uint32_t getFontRunStart(uint32_t i) const { return i == 0 ? 0 : mEnds[i - 1]; }
148     // Returns exclusive end offset of the font run.
getFontRunEnd(uint32_t i)149     uint32_t getFontRunEnd(uint32_t i) const { return mEnds[i]; }
150     // Returns the font associated to the given run index.
getFontRunFont(uint32_t i)151     const FakedFont& getFontRunFont(uint32_t i) const { return mFonts[i]; }
152 
153     // Purge all caches, useful in low memory conditions
154     static void purgeCaches();
155 
156     // Dump minikin internal statistics, cache usage, cache hit ratio, etc.
157     static void dumpMinikinStats(int fd);
158 
159     // Append another layout (for example, cached value) into this one
160     void appendLayout(const LayoutPiece& src, size_t start, float extraAdvance);
161 
162     // For gtest output
toString()163     std::string toString() const {
164         std::stringstream ss;
165         ss << "{glyphs: ";
166         for (uint32_t i = 0; i < mGlyphs.size(); ++i) {
167             if (i != 0) {
168                 ss << ", ";
169             }
170             ss << mGlyphs[i];
171         }
172         ss << ", totalAdvance: " << mAdvance;
173         ss << ", advances: {";
174         for (uint32_t i = 0; i < mAdvances.size(); ++i) {
175             if (i != 0) {
176                 ss << ", ";
177             }
178             ss << mAdvances[i];
179         }
180         ss << "}";
181         return ss.str();
182     }
183 
184 private:
185     FRIEND_TEST(LayoutTest, doLayoutWithPrecomputedPiecesTest);
186 
187     void doLayout(const U16StringPiece& str, const Range& range, Bidi bidiFlags,
188                   const MinikinPaint& paint, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen,
189                   RunFlag runFlag);
190 
191     // Lay out a single bidi run
192     // When layout is not null, layout info will be stored in the object.
193     // When advances is not null, measurement results will be stored in the array.
194     static float doLayoutRunCached(const U16StringPiece& textBuf, const Range& range, bool isRtl,
195                                    const MinikinPaint& paint, size_t dstStart,
196                                    StartHyphenEdit startHyphen, EndHyphenEdit endHyphen,
197                                    Layout* layout, float* advances, MinikinRect* bounds,
198                                    uint32_t* clusterCount);
199 
200     // Lay out a single word
201     static float doLayoutWord(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
202                               bool isRtl, const MinikinPaint& paint, size_t bufStart,
203                               StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, Layout* layout,
204                               float* advances, MinikinRect* bounds, uint32_t* clusterCount);
205 
206     // Lay out a single bidi run
207     void doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t bufSize, bool isRtl,
208                      const MinikinPaint& paint, StartHyphenEdit startHyphen,
209                      EndHyphenEdit endHyphen, MinikinRect* bounds, uint32_t* clusterCount);
210 
211     std::vector<FakedFont> mFonts;
212     std::vector<uint32_t> mEnds;
213     std::vector<LayoutGlyph> mGlyphs;
214 
215     // This vector defined per code unit, so their length is identical to the input text.
216     std::vector<float> mAdvances;
217 
218     float mAdvance;
219 };
220 
221 // For gtest output
222 inline std::ostream& operator<<(std::ostream& os, const Layout& l) {
223     return os << l.toString();
224 }
225 }  // namespace minikin
226 
227 #endif  // MINIKIN_LAYOUT_H
228