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