1 /*
2 * Copyright (C) 2018 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 #include "minikin/LayoutCore.h"
18
19 #include <gtest/gtest.h>
20
21 #include "minikin/FontCollection.h"
22 #include "minikin/LayoutPieces.h"
23
24 #include "FontTestUtils.h"
25 #include "UnicodeUtils.h"
26
27 namespace minikin {
28 namespace {
29
buildLayout(const std::string & text,const MinikinPaint & paint)30 static LayoutPiece buildLayout(const std::string& text, const MinikinPaint& paint) {
31 auto utf16 = utf8ToUtf16(text);
32 return LayoutPiece(utf16, Range(0, utf16.size()), false /* rtl */, paint,
33 StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
34 }
35
buildLayout(const std::string & text,const std::vector<std::string> & fonts)36 static LayoutPiece buildLayout(const std::string& text, const std::vector<std::string>& fonts) {
37 std::vector<std::shared_ptr<FontFamily>> families;
38 for (const auto& fontPath : fonts) {
39 families.push_back(buildFontFamily(fontPath));
40 }
41 auto fc = std::make_shared<FontCollection>(families);
42 MinikinPaint paint(fc);
43 paint.size = 10.0f; // make 1em = 10px
44 return buildLayout(text, paint);
45 }
46
buildLayout(const std::string & text,const std::vector<std::string> & fonts,const std::string fontFeaturesSettings)47 static LayoutPiece buildLayout(const std::string& text, const std::vector<std::string>& fonts,
48 const std::string fontFeaturesSettings) {
49 std::vector<std::shared_ptr<FontFamily>> families;
50 for (const auto& fontPath : fonts) {
51 families.push_back(buildFontFamily(fontPath));
52 }
53 auto fc = std::make_shared<FontCollection>(families);
54 MinikinPaint paint(fc);
55 paint.size = 10.0f; // make 1em = 10px
56 paint.fontFeatureSettings = fontFeaturesSettings;
57 return buildLayout(text, paint);
58 }
59
TEST(LayoutPieceTest,doLayoutTest)60 TEST(LayoutPieceTest, doLayoutTest) {
61 // The LayoutTestFont.ttf has following coverage, extent, width and bbox.
62 // Ascender: 10em, Descender: -2em
63 // U+0020: 10em, (0, 0) - (10, 10)
64 // U+002E (.): 10em, (0, 0) - (10, 10)
65 // U+0043 (C): 100em, (0, 0) - (100, 100)
66 // U+0049 (I): 1em, (0, 0) - (1, 1)
67 // U+004C (L): 50em, (0, 0) - (50, 50)
68 // U+0056 (V): 5em, (0, 0) - (5, 5)
69 // U+0058 (X): 10em, (0, 0) - (10, 10)
70 // U+005F (_): 0em, (0, 0) - (0, 0)
71 // U+FFFD (invalid surrogate will be replaced to this): 7em, (0, 0) - (7, 7)
72 // U+10331 (\uD800\uDF31): 10em, (0, 0) - (10, 10)
73 {
74 auto layout = buildLayout("I", {"LayoutTestFont.ttf"});
75 EXPECT_EQ(1u, layout.glyphCount());
76 EXPECT_EQ(Point(0, 0), layout.pointAt(0));
77 EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), layout.bounds());
78 EXPECT_EQ(MinikinExtent(-100.0f, 20.0f), layout.extent());
79 EXPECT_EQ(1u, layout.fonts().size());
80 EXPECT_TRUE(layout.fontAt(0).font);
81 EXPECT_EQ(1u, layout.advances().size());
82 EXPECT_EQ(10.0f, layout.advances()[0]);
83 EXPECT_EQ(10.0f, layout.advance());
84 }
85 {
86 auto layout = buildLayout("II", {"LayoutTestFont.ttf"});
87 EXPECT_EQ(2u, layout.glyphCount());
88 EXPECT_EQ(Point(0, 0), layout.pointAt(0));
89 EXPECT_EQ(Point(10.0f, 0), layout.pointAt(1));
90 EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), layout.bounds());
91 EXPECT_EQ(MinikinExtent(-100.0f, 20.0f), layout.extent());
92 EXPECT_EQ(1u, layout.fonts().size());
93 EXPECT_TRUE(layout.fontAt(0).font);
94 EXPECT_TRUE(layout.fontAt(1).font);
95 EXPECT_EQ(layout.fontAt(0), layout.fontAt(1));
96 EXPECT_EQ(2u, layout.advances().size());
97 EXPECT_EQ(10.0f, layout.advances()[0]);
98 EXPECT_EQ(10.0f, layout.advances()[1]);
99 EXPECT_EQ(20.0f, layout.advance());
100 }
101 {
102 auto layout = buildLayout("IV", {"LayoutTestFont.ttf"});
103 EXPECT_EQ(2u, layout.glyphCount());
104 EXPECT_EQ(Point(0, 0), layout.pointAt(0));
105 EXPECT_EQ(Point(10.0f, 0), layout.pointAt(1));
106 EXPECT_EQ(MinikinRect(0.0f, 10.0f, 60.0f, 0.0f), layout.bounds());
107 EXPECT_EQ(MinikinExtent(-100.0f, 20.0f), layout.extent());
108 EXPECT_EQ(1u, layout.fonts().size());
109 EXPECT_TRUE(layout.fontAt(0).font);
110 EXPECT_TRUE(layout.fontAt(1).font);
111 EXPECT_EQ(layout.fontAt(0), layout.fontAt(1));
112 EXPECT_EQ(2u, layout.advances().size());
113 EXPECT_EQ(10.0f, layout.advances()[0]);
114 EXPECT_EQ(50.0f, layout.advances()[1]);
115 EXPECT_EQ(60.0f, layout.advance());
116 }
117 }
118
TEST(LayoutPieceTest,doLayoutTest_MultiFont)119 TEST(LayoutPieceTest, doLayoutTest_MultiFont) {
120 // See doLayoutTest for the details of LayoutTestFont.ttf
121 // The Hiragana.ttf has following coverage, extent, width and bbox.
122 // Ascender: 16em, Descender: -4em
123 // U+3042: 2em, (0, 0) - (2, 2)
124 // U+3044: 2em, (0, 0) - (2, 2)
125 // U+3046: 2em, (0, 0) - (2, 2)
126 // U+3048: 2em, (0, 0) - (2, 2)
127 // U+304A: 2em, (0, 0) - (2, 2)
128 {
129 auto layout = buildLayout("I\u3042", {"LayoutTestFont.ttf", "Hiragana.ttf"});
130 EXPECT_EQ(2u, layout.glyphCount());
131 EXPECT_EQ(Point(0, 0), layout.pointAt(0));
132 EXPECT_EQ(Point(10.0f, 0), layout.pointAt(1));
133 EXPECT_EQ(MinikinRect(0.0f, 10.0f, 30.0f, 0.0f), layout.bounds());
134 EXPECT_EQ(MinikinExtent(-160.0f, 40.0f), layout.extent());
135 EXPECT_EQ(2u, layout.fonts().size());
136 EXPECT_TRUE(layout.fontAt(0).font);
137 EXPECT_TRUE(layout.fontAt(1).font);
138 EXPECT_NE(layout.fontAt(0), layout.fontAt(1));
139 EXPECT_EQ(2u, layout.advances().size());
140 EXPECT_EQ(10.0f, layout.advances()[0]);
141 EXPECT_EQ(20.0f, layout.advances()[1]);
142 EXPECT_EQ(30.0f, layout.advance());
143 }
144 {
145 auto layout = buildLayout("\u3042I", {"LayoutTestFont.ttf", "Hiragana.ttf"});
146 EXPECT_EQ(2u, layout.glyphCount());
147 EXPECT_EQ(Point(0, 0), layout.pointAt(0));
148 EXPECT_EQ(Point(20.0f, 0), layout.pointAt(1));
149 EXPECT_EQ(MinikinRect(0.0f, 10.0f, 30.0f, 0.0f), layout.bounds());
150 EXPECT_EQ(MinikinExtent(-160.0f, 40.0f), layout.extent());
151 EXPECT_EQ(2u, layout.fonts().size());
152 EXPECT_TRUE(layout.fontAt(0).font);
153 EXPECT_TRUE(layout.fontAt(1).font);
154 EXPECT_NE(layout.fontAt(0), layout.fontAt(1));
155 EXPECT_EQ(2u, layout.advances().size());
156 EXPECT_EQ(20.0f, layout.advances()[0]);
157 EXPECT_EQ(10.0f, layout.advances()[1]);
158 EXPECT_EQ(30.0f, layout.advance());
159 }
160 }
161
TEST(LayoutPieceTest,doLayoutTest_Ligature)162 TEST(LayoutPieceTest, doLayoutTest_Ligature) {
163 // Ligature.ttf support all ASCII characters.
164 // Ascender: 8em, Descender: -2em
165 // U+0020..U+007E: 1em, (0, 0) - (1, 1)
166 // Also this has ligature entry for fi as "ccmp" feature, ff as "liga" feature.
167 {
168 auto layout = buildLayout("fi", {"Ligature.ttf"});
169 EXPECT_EQ(1u, layout.glyphCount());
170 EXPECT_EQ(Point(0, 0), layout.pointAt(0));
171 EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), layout.bounds());
172 EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent());
173 EXPECT_EQ(1u, layout.fonts().size());
174 EXPECT_TRUE(layout.fontAt(0).font);
175 EXPECT_EQ(2u, layout.advances().size());
176 EXPECT_EQ(10.0f, layout.advances()[0]);
177 EXPECT_EQ(0.0f, layout.advances()[1]); // Ligature assigns all width to the first char.
178 EXPECT_EQ(10.0f, layout.advance());
179 }
180 {
181 auto layout = buildLayout("ff", {"Ligature.ttf"});
182 EXPECT_EQ(1u, layout.glyphCount());
183 EXPECT_EQ(Point(0, 0), layout.pointAt(0));
184 EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), layout.bounds());
185 EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent());
186 EXPECT_EQ(1u, layout.fonts().size());
187 EXPECT_TRUE(layout.fontAt(0).font);
188 EXPECT_EQ(2u, layout.advances().size());
189 EXPECT_EQ(10.0f, layout.advances()[0]);
190 EXPECT_EQ(0.0f, layout.advances()[1]); // Ligature assigns all width to the first char.
191 EXPECT_EQ(10.0f, layout.advance());
192 }
193 {
194 auto layout = buildLayout("fi", {"Ligature.ttf"}, "'liga' off");
195 EXPECT_EQ(1u, layout.glyphCount());
196 EXPECT_EQ(Point(0, 0), layout.pointAt(0));
197 EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), layout.bounds());
198 EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent());
199 EXPECT_EQ(1u, layout.fonts().size());
200 EXPECT_TRUE(layout.fontAt(0).font);
201 EXPECT_EQ(2u, layout.advances().size());
202 EXPECT_EQ(10.0f, layout.advances()[0]);
203 EXPECT_EQ(0.0f, layout.advances()[1]); // Ligature assigns all width to the first char.
204 EXPECT_EQ(10.0f, layout.advance());
205 }
206 {
207 auto layout = buildLayout("ff", {"Ligature.ttf"}, "'liga' off");
208 EXPECT_EQ(2u, layout.glyphCount());
209 EXPECT_EQ(Point(0, 0), layout.pointAt(0));
210 EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), layout.bounds());
211 EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent());
212 EXPECT_EQ(1u, layout.fonts().size());
213 EXPECT_TRUE(layout.fontAt(0).font);
214 EXPECT_TRUE(layout.fontAt(1).font);
215 EXPECT_EQ(2u, layout.advances().size());
216 EXPECT_EQ(layout.fontAt(0), layout.fontAt(1));
217 EXPECT_EQ(10.0f, layout.advances()[0]);
218 EXPECT_EQ(10.0f, layout.advances()[1]);
219 EXPECT_EQ(20.0f, layout.advance());
220 }
221 {
222 auto layout = buildLayout("fii", {"Ligature.ttf"});
223 EXPECT_EQ(2u, layout.glyphCount());
224 EXPECT_EQ(Point(0, 0), layout.pointAt(0));
225 EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), layout.bounds());
226 EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent());
227 EXPECT_EQ(1u, layout.fonts().size());
228 EXPECT_TRUE(layout.fontAt(0).font);
229 EXPECT_TRUE(layout.fontAt(1).font);
230 EXPECT_EQ(layout.fontAt(0), layout.fontAt(1));
231 EXPECT_EQ(3u, layout.advances().size());
232 EXPECT_EQ(10.0f, layout.advances()[0]);
233 EXPECT_EQ(0.0f, layout.advances()[1]); // Ligature assigns all width to the first char.
234 EXPECT_EQ(10.0f, layout.advances()[2]);
235 EXPECT_EQ(20.0f, layout.advance());
236 }
237 {
238 auto layout = buildLayout("if", {"Ligature.ttf"});
239 EXPECT_EQ(2u, layout.glyphCount());
240 EXPECT_EQ(Point(0, 0), layout.pointAt(0));
241 EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), layout.bounds());
242 EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent());
243 EXPECT_EQ(1u, layout.fonts().size());
244 EXPECT_TRUE(layout.fontAt(0).font);
245 EXPECT_TRUE(layout.fontAt(1).font);
246 EXPECT_EQ(layout.fontAt(0), layout.fontAt(1));
247 EXPECT_EQ(2u, layout.advances().size());
248 EXPECT_EQ(10.0f, layout.advances()[0]);
249 EXPECT_EQ(10.0f, layout.advances()[1]);
250 EXPECT_EQ(20.0f, layout.advance());
251 }
252 }
253
254 } // namespace
255 } // namespace minikin
256