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