• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     FontFakery getFakery(int i) const { return mGlyphs[i].font.fakery; }
typeface(int i)136     const 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     // Purge all caches, useful in low memory conditions
145     static void purgeCaches();
146 
147     // Dump minikin internal statistics, cache usage, cache hit ratio, etc.
148     static void dumpMinikinStats(int fd);
149 
150     // Append another layout (for example, cached value) into this one
151     void appendLayout(const LayoutPiece& src, size_t start, float extraAdvance);
152 
153     // For gtest output
toString()154     std::string toString() const {
155         std::stringstream ss;
156         ss << "{glyphs: ";
157         for (uint32_t i = 0; i < mGlyphs.size(); ++i) {
158             if (i != 0) {
159                 ss << ", ";
160             }
161             ss << mGlyphs[i];
162         }
163         ss << ", totalAdvance: " << mAdvance;
164         ss << ", advances: {";
165         for (uint32_t i = 0; i < mAdvances.size(); ++i) {
166             if (i != 0) {
167                 ss << ", ";
168             }
169             ss << mAdvances[i];
170         }
171         ss << "}";
172         return ss.str();
173     }
174 
175 private:
176     FRIEND_TEST(LayoutTest, doLayoutWithPrecomputedPiecesTest);
177 
178     void doLayout(const U16StringPiece& str, const Range& range, Bidi bidiFlags,
179                   const MinikinPaint& paint, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen,
180                   RunFlag runFlag);
181 
182     // Lay out a single bidi run
183     // When layout is not null, layout info will be stored in the object.
184     // When advances is not null, measurement results will be stored in the array.
185     static float doLayoutRunCached(const U16StringPiece& textBuf, const Range& range, bool isRtl,
186                                    const MinikinPaint& paint, size_t dstStart,
187                                    StartHyphenEdit startHyphen, EndHyphenEdit endHyphen,
188                                    Layout* layout, float* advances, MinikinRect* bounds,
189                                    uint32_t* clusterCount);
190 
191     // Lay out a single word
192     static float doLayoutWord(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
193                               bool isRtl, const MinikinPaint& paint, size_t bufStart,
194                               StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, Layout* layout,
195                               float* advances, MinikinRect* bounds, uint32_t* clusterCount);
196 
197     // Lay out a single bidi run
198     void doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t bufSize, bool isRtl,
199                      const MinikinPaint& paint, StartHyphenEdit startHyphen,
200                      EndHyphenEdit endHyphen, MinikinRect* bounds, uint32_t* clusterCount);
201 
202     std::vector<LayoutGlyph> mGlyphs;
203 
204     // This vector defined per code unit, so their length is identical to the input text.
205     std::vector<float> mAdvances;
206 
207     float mAdvance;
208 };
209 
210 // For gtest output
211 inline std::ostream& operator<<(std::ostream& os, const Layout& l) {
212     return os << l.toString();
213 }
214 }  // namespace minikin
215 
216 #endif  // MINIKIN_LAYOUT_H
217