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 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 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 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 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 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 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