1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2014 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "tests/Test.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h" 11cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 12cb93a386Sopenharmony_ci#include "include/core/SkFont.h" 13cb93a386Sopenharmony_ci#include "include/core/SkTypeface.h" 14cb93a386Sopenharmony_ci#include "include/ports/SkFontMgr_android.h" 15cb93a386Sopenharmony_ci#include "include/private/SkFixed.h" 16cb93a386Sopenharmony_ci#include "src/core/SkOSFile.h" 17cb93a386Sopenharmony_ci#include "src/ports/SkFontMgr_android_parser.h" 18cb93a386Sopenharmony_ci#include "tools/Resources.h" 19cb93a386Sopenharmony_ci#include "tools/flags/CommandLineFlags.h" 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_ci#include <cmath> 22cb93a386Sopenharmony_ci#include <cstdio> 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_ciDECLARE_bool(verboseFontMgr); 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ciint CountFallbacks(SkTDArray<FontFamily*> fontFamilies) { 27cb93a386Sopenharmony_ci int countOfFallbackFonts = 0; 28cb93a386Sopenharmony_ci for (int i = 0; i < fontFamilies.count(); i++) { 29cb93a386Sopenharmony_ci if (fontFamilies[i]->fIsFallbackFont) { 30cb93a386Sopenharmony_ci countOfFallbackFonts++; 31cb93a386Sopenharmony_ci } 32cb93a386Sopenharmony_ci } 33cb93a386Sopenharmony_ci return countOfFallbackFonts; 34cb93a386Sopenharmony_ci} 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_ci//https://tools.ietf.org/html/rfc5234#appendix-B.1 37cb93a386Sopenharmony_cistatic bool isALPHA(int c) { 38cb93a386Sopenharmony_ci return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); 39cb93a386Sopenharmony_ci} 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci//https://tools.ietf.org/html/rfc5234#appendix-B.1 42cb93a386Sopenharmony_cistatic bool isDIGIT(int c) { 43cb93a386Sopenharmony_ci return ('0' <= c && c <= '9'); 44cb93a386Sopenharmony_ci} 45cb93a386Sopenharmony_ci 46cb93a386Sopenharmony_cistatic void ValidateLoadedFonts(SkTDArray<FontFamily*> fontFamilies, const char* firstExpectedFile, 47cb93a386Sopenharmony_ci skiatest::Reporter* reporter) { 48cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, fontFamilies[0]->fNames.count() == 5); 49cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !strcmp(fontFamilies[0]->fNames[0].c_str(), "sans-serif")); 50cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 51cb93a386Sopenharmony_ci !strcmp(fontFamilies[0]->fFonts[0].fFileName.c_str(), firstExpectedFile)); 52cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !fontFamilies[0]->fIsFallbackFont); 53cb93a386Sopenharmony_ci 54cb93a386Sopenharmony_ci // Check that the languages are all sane. 55cb93a386Sopenharmony_ci for (const auto& fontFamily : fontFamilies) { 56cb93a386Sopenharmony_ci for (const auto& lang : fontFamily->fLanguages) { 57cb93a386Sopenharmony_ci const SkString& langString = lang.getTag(); 58cb93a386Sopenharmony_ci for (size_t i = 0; i < langString.size(); ++i) { 59cb93a386Sopenharmony_ci int c = langString[i]; 60cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, isALPHA(c) || isDIGIT(c) || '-' == c); 61cb93a386Sopenharmony_ci } 62cb93a386Sopenharmony_ci } 63cb93a386Sopenharmony_ci } 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci // All file names in the test configuration files start with a capital letter. 66cb93a386Sopenharmony_ci // This is not a general requirement, but it is true of all the test configuration data. 67cb93a386Sopenharmony_ci // Verifying ensures the filenames have been read sanely and have not been 'sliced'. 68cb93a386Sopenharmony_ci for (int i = 0; i < fontFamilies.count(); ++i) { 69cb93a386Sopenharmony_ci FontFamily& family = *fontFamilies[i]; 70cb93a386Sopenharmony_ci for (int j = 0; j < family.fFonts.count(); ++j) { 71cb93a386Sopenharmony_ci FontFileInfo& file = family.fFonts[j]; 72cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !file.fFileName.isEmpty() && 73cb93a386Sopenharmony_ci file.fFileName[0] >= 'A' && 74cb93a386Sopenharmony_ci file.fFileName[0] <= 'Z'); 75cb93a386Sopenharmony_ci } 76cb93a386Sopenharmony_ci } 77cb93a386Sopenharmony_ci} 78cb93a386Sopenharmony_ci 79cb93a386Sopenharmony_cistatic void DumpFiles(const FontFamily& fontFamily) { 80cb93a386Sopenharmony_ci for (int j = 0; j < fontFamily.fFonts.count(); ++j) { 81cb93a386Sopenharmony_ci const FontFileInfo& ffi = fontFamily.fFonts[j]; 82cb93a386Sopenharmony_ci SkDebugf(" file (%d) %s#%d", ffi.fWeight, ffi.fFileName.c_str(), ffi.fIndex); 83cb93a386Sopenharmony_ci for (const auto& coordinate : ffi.fVariationDesignPosition) { 84cb93a386Sopenharmony_ci SkDebugf(" @'%c%c%c%c'=%f", 85cb93a386Sopenharmony_ci (coordinate.axis >> 24) & 0xFF, 86cb93a386Sopenharmony_ci (coordinate.axis >> 16) & 0xFF, 87cb93a386Sopenharmony_ci (coordinate.axis >> 8) & 0xFF, 88cb93a386Sopenharmony_ci (coordinate.axis ) & 0xFF, 89cb93a386Sopenharmony_ci coordinate.value); 90cb93a386Sopenharmony_ci } 91cb93a386Sopenharmony_ci SkDebugf("\n"); 92cb93a386Sopenharmony_ci } 93cb93a386Sopenharmony_ci} 94cb93a386Sopenharmony_ci 95cb93a386Sopenharmony_cistatic void DumpLoadedFonts(SkTDArray<FontFamily*> fontFamilies, const char* label) { 96cb93a386Sopenharmony_ci if (!FLAGS_verboseFontMgr) { 97cb93a386Sopenharmony_ci return; 98cb93a386Sopenharmony_ci } 99cb93a386Sopenharmony_ci 100cb93a386Sopenharmony_ci SkDebugf("\n--- Dumping %s\n", label); 101cb93a386Sopenharmony_ci for (int i = 0; i < fontFamilies.count(); ++i) { 102cb93a386Sopenharmony_ci SkDebugf("Family %d:\n", i); 103cb93a386Sopenharmony_ci switch(fontFamilies[i]->fVariant) { 104cb93a386Sopenharmony_ci case kElegant_FontVariant: SkDebugf(" elegant\n"); break; 105cb93a386Sopenharmony_ci case kCompact_FontVariant: SkDebugf(" compact\n"); break; 106cb93a386Sopenharmony_ci default: break; 107cb93a386Sopenharmony_ci } 108cb93a386Sopenharmony_ci SkDebugf(" basePath %s\n", fontFamilies[i]->fBasePath.c_str()); 109cb93a386Sopenharmony_ci if (!fontFamilies[i]->fLanguages.empty()) { 110cb93a386Sopenharmony_ci SkDebugf(" language"); 111cb93a386Sopenharmony_ci for (const auto& lang : fontFamilies[i]->fLanguages) { 112cb93a386Sopenharmony_ci SkDebugf(" %s", lang.getTag().c_str()); 113cb93a386Sopenharmony_ci } 114cb93a386Sopenharmony_ci SkDebugf("\n"); 115cb93a386Sopenharmony_ci } 116cb93a386Sopenharmony_ci for (int j = 0; j < fontFamilies[i]->fNames.count(); ++j) { 117cb93a386Sopenharmony_ci SkDebugf(" name %s\n", fontFamilies[i]->fNames[j].c_str()); 118cb93a386Sopenharmony_ci } 119cb93a386Sopenharmony_ci DumpFiles(*fontFamilies[i]); 120cb93a386Sopenharmony_ci for (const auto& [unused, fallbackFamily] : fontFamilies[i]->fallbackFamilies) { 121cb93a386Sopenharmony_ci SkDebugf(" Fallback for: %s\n", fallbackFamily->fFallbackFor.c_str()); 122cb93a386Sopenharmony_ci DumpFiles(*fallbackFamily); 123cb93a386Sopenharmony_ci } 124cb93a386Sopenharmony_ci } 125cb93a386Sopenharmony_ci SkDebugf("\n\n"); 126cb93a386Sopenharmony_ci} 127cb93a386Sopenharmony_ci 128cb93a386Sopenharmony_citemplate <int N, typename T> static double test_parse_fixed_r(skiatest::Reporter* reporter, 129cb93a386Sopenharmony_ci double low, double high, double inc) 130cb93a386Sopenharmony_ci{ 131cb93a386Sopenharmony_ci double SK_FixedMax_double = nextafter(1 << (sizeof(T) * CHAR_BIT - N - 1), 0.0); 132cb93a386Sopenharmony_ci double SK_FixedEpsilon_double = (1.0 / (1 << N)); 133cb93a386Sopenharmony_ci double maxError = 0; 134cb93a386Sopenharmony_ci char buffer[64]; 135cb93a386Sopenharmony_ci for (double f = low; f < high; f += inc) { 136cb93a386Sopenharmony_ci SkString s; 137cb93a386Sopenharmony_ci // 'sprintf' formatting as expected depends on the current locale being "C". 138cb93a386Sopenharmony_ci // We currently expect tests and tools to run in the "C" locale. 139cb93a386Sopenharmony_ci sprintf(buffer, "%.20f", f); 140cb93a386Sopenharmony_ci T fix; 141cb93a386Sopenharmony_ci bool b = parse_fixed<N>(buffer, &fix); 142cb93a386Sopenharmony_ci if (b) { 143cb93a386Sopenharmony_ci double f2 = fix * SK_FixedEpsilon_double; 144cb93a386Sopenharmony_ci double error = fabs(f - f2); 145cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, error <= SK_FixedEpsilon_double); 146cb93a386Sopenharmony_ci maxError = std::max(maxError, error); 147cb93a386Sopenharmony_ci } else { 148cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, f < -SK_FixedMax_double || SK_FixedMax_double < f); 149cb93a386Sopenharmony_ci } 150cb93a386Sopenharmony_ci } 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_ci //SkDebugf("maxError: %.20f\n", maxError); 153cb93a386Sopenharmony_ci return maxError; 154cb93a386Sopenharmony_ci} 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_cistatic void test_parse_fixed(skiatest::Reporter* reporter) { 157cb93a386Sopenharmony_ci test_parse_fixed_r<27, int32_t>(reporter, -8.1, -7.9, 0.000001); 158cb93a386Sopenharmony_ci test_parse_fixed_r<27, int32_t>(reporter, -0.1, 0.1, 0.000001); 159cb93a386Sopenharmony_ci test_parse_fixed_r<27, int32_t>(reporter, 7.9, 8.1, 0.000001); 160cb93a386Sopenharmony_ci test_parse_fixed_r<16, int32_t>(reporter, -0.125, 0.125, 1.0 / (1 << 19)); 161cb93a386Sopenharmony_ci test_parse_fixed_r<16, int32_t>(reporter, -32768.125, -32766.875, 1.0 / (1 << 17)); 162cb93a386Sopenharmony_ci test_parse_fixed_r<16, int32_t>(reporter, 32766.875, 32768.125, 1.0 / (1 << 17)); 163cb93a386Sopenharmony_ci test_parse_fixed_r<16, int32_t>(reporter, -1.1, 1.1, 0.0001); 164cb93a386Sopenharmony_ci 165cb93a386Sopenharmony_ci SkFixed fix; 166cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !parse_fixed<27>("-17.1", &fix)); 167cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !parse_fixed<16>("32768", &fix)); 168cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !parse_fixed<16>("", &fix)); 169cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !parse_fixed<16>(".", &fix)); 170cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !parse_fixed<16>("123.", &fix)); 171cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !parse_fixed<16>("a", &fix)); 172cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !parse_fixed<16>(".123a", &fix)); 173cb93a386Sopenharmony_ci} 174cb93a386Sopenharmony_ci 175cb93a386Sopenharmony_ciDEF_TEST(FontMgrAndroidParser, reporter) { 176cb93a386Sopenharmony_ci test_parse_fixed(reporter); 177cb93a386Sopenharmony_ci 178cb93a386Sopenharmony_ci bool resourcesMissing = false; 179cb93a386Sopenharmony_ci 180cb93a386Sopenharmony_ci SkTDArray<FontFamily*> preV17FontFamilies; 181cb93a386Sopenharmony_ci SkFontMgr_Android_Parser::GetCustomFontFamilies(preV17FontFamilies, 182cb93a386Sopenharmony_ci SkString("/custom/font/path/"), 183cb93a386Sopenharmony_ci GetResourcePath("android_fonts/pre_v17/system_fonts.xml").c_str(), 184cb93a386Sopenharmony_ci GetResourcePath("android_fonts/pre_v17/fallback_fonts.xml").c_str()); 185cb93a386Sopenharmony_ci 186cb93a386Sopenharmony_ci if (preV17FontFamilies.count() > 0) { 187cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, preV17FontFamilies.count() == 14); 188cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, CountFallbacks(preV17FontFamilies) == 10); 189cb93a386Sopenharmony_ci 190cb93a386Sopenharmony_ci DumpLoadedFonts(preV17FontFamilies, "pre version 17"); 191cb93a386Sopenharmony_ci ValidateLoadedFonts(preV17FontFamilies, "Roboto-Regular.ttf", reporter); 192cb93a386Sopenharmony_ci } else { 193cb93a386Sopenharmony_ci resourcesMissing = true; 194cb93a386Sopenharmony_ci } 195cb93a386Sopenharmony_ci preV17FontFamilies.deleteAll(); 196cb93a386Sopenharmony_ci 197cb93a386Sopenharmony_ci 198cb93a386Sopenharmony_ci SkTDArray<FontFamily*> v17FontFamilies; 199cb93a386Sopenharmony_ci SkFontMgr_Android_Parser::GetCustomFontFamilies(v17FontFamilies, 200cb93a386Sopenharmony_ci SkString("/custom/font/path/"), 201cb93a386Sopenharmony_ci GetResourcePath("android_fonts/v17/system_fonts.xml").c_str(), 202cb93a386Sopenharmony_ci GetResourcePath("android_fonts/v17/fallback_fonts.xml").c_str(), 203cb93a386Sopenharmony_ci GetResourcePath("android_fonts/v17").c_str()); 204cb93a386Sopenharmony_ci 205cb93a386Sopenharmony_ci if (v17FontFamilies.count() > 0) { 206cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, v17FontFamilies.count() == 56); 207cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, CountFallbacks(v17FontFamilies) == 46); 208cb93a386Sopenharmony_ci 209cb93a386Sopenharmony_ci DumpLoadedFonts(v17FontFamilies, "version 17"); 210cb93a386Sopenharmony_ci ValidateLoadedFonts(v17FontFamilies, "Roboto-Regular.ttf", reporter); 211cb93a386Sopenharmony_ci } else { 212cb93a386Sopenharmony_ci resourcesMissing = true; 213cb93a386Sopenharmony_ci } 214cb93a386Sopenharmony_ci v17FontFamilies.deleteAll(); 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_ci 217cb93a386Sopenharmony_ci SkTDArray<FontFamily*> v22FontFamilies; 218cb93a386Sopenharmony_ci SkFontMgr_Android_Parser::GetCustomFontFamilies(v22FontFamilies, 219cb93a386Sopenharmony_ci SkString("/custom/font/path/"), 220cb93a386Sopenharmony_ci GetResourcePath("android_fonts/v22/fonts.xml").c_str(), 221cb93a386Sopenharmony_ci nullptr); 222cb93a386Sopenharmony_ci 223cb93a386Sopenharmony_ci if (v22FontFamilies.count() > 0) { 224cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, v22FontFamilies.count() == 54); 225cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, CountFallbacks(v22FontFamilies) == 42); 226cb93a386Sopenharmony_ci 227cb93a386Sopenharmony_ci DumpLoadedFonts(v22FontFamilies, "version 22"); 228cb93a386Sopenharmony_ci ValidateLoadedFonts(v22FontFamilies, "Roboto-Thin.ttf", reporter); 229cb93a386Sopenharmony_ci } else { 230cb93a386Sopenharmony_ci resourcesMissing = true; 231cb93a386Sopenharmony_ci } 232cb93a386Sopenharmony_ci v22FontFamilies.deleteAll(); 233cb93a386Sopenharmony_ci 234cb93a386Sopenharmony_ci if (resourcesMissing) { 235cb93a386Sopenharmony_ci SkDebugf("---- Resource files missing for FontConfigParser test\n"); 236cb93a386Sopenharmony_ci } 237cb93a386Sopenharmony_ci} 238cb93a386Sopenharmony_ci 239cb93a386Sopenharmony_ciDEF_TEST(FontMgrAndroidLegacyMakeTypeface, reporter) { 240cb93a386Sopenharmony_ci constexpr char fontsXmlFilename[] = "fonts/fonts.xml"; 241cb93a386Sopenharmony_ci SkString basePath = GetResourcePath("fonts/"); 242cb93a386Sopenharmony_ci SkString fontsXml = GetResourcePath(fontsXmlFilename); 243cb93a386Sopenharmony_ci 244cb93a386Sopenharmony_ci if (!sk_exists(fontsXml.c_str())) { 245cb93a386Sopenharmony_ci ERRORF(reporter, "file missing: %s\n", fontsXmlFilename); 246cb93a386Sopenharmony_ci return; 247cb93a386Sopenharmony_ci } 248cb93a386Sopenharmony_ci 249cb93a386Sopenharmony_ci SkFontMgr_Android_CustomFonts custom; 250cb93a386Sopenharmony_ci custom.fSystemFontUse = SkFontMgr_Android_CustomFonts::kOnlyCustom; 251cb93a386Sopenharmony_ci custom.fBasePath = basePath.c_str(); 252cb93a386Sopenharmony_ci custom.fFontsXml = fontsXml.c_str(); 253cb93a386Sopenharmony_ci custom.fFallbackFontsXml = nullptr; 254cb93a386Sopenharmony_ci custom.fIsolated = false; 255cb93a386Sopenharmony_ci 256cb93a386Sopenharmony_ci sk_sp<SkFontMgr> fm(SkFontMgr_New_Android(&custom)); 257cb93a386Sopenharmony_ci sk_sp<SkTypeface> t(fm->legacyMakeTypeface("non-existent-font", SkFontStyle())); 258cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, nullptr == t); 259cb93a386Sopenharmony_ci} 260cb93a386Sopenharmony_ci 261cb93a386Sopenharmony_cistatic bool bitmap_compare(const SkBitmap& ref, const SkBitmap& test) { 262cb93a386Sopenharmony_ci for (int y = 0; y < test.height(); ++y) { 263cb93a386Sopenharmony_ci for (int x = 0; x < test.width(); ++x) { 264cb93a386Sopenharmony_ci SkColor testColor = test.getColor(x, y); 265cb93a386Sopenharmony_ci SkColor refColor = ref.getColor(x, y); 266cb93a386Sopenharmony_ci if (refColor != testColor) { 267cb93a386Sopenharmony_ci return false; 268cb93a386Sopenharmony_ci } 269cb93a386Sopenharmony_ci } 270cb93a386Sopenharmony_ci } 271cb93a386Sopenharmony_ci return true; 272cb93a386Sopenharmony_ci} 273cb93a386Sopenharmony_ci 274cb93a386Sopenharmony_ciDEF_TEST(FontMgrAndroidSystemVariableTypeface, reporter) { 275cb93a386Sopenharmony_ci constexpr char fontsXmlFilename[] = "fonts/fonts.xml"; 276cb93a386Sopenharmony_ci SkString basePath = GetResourcePath("fonts/"); 277cb93a386Sopenharmony_ci SkString fontsXml = GetResourcePath(fontsXmlFilename); 278cb93a386Sopenharmony_ci 279cb93a386Sopenharmony_ci if (!sk_exists(fontsXml.c_str())) { 280cb93a386Sopenharmony_ci ERRORF(reporter, "file missing: %s\n", fontsXmlFilename); 281cb93a386Sopenharmony_ci return; 282cb93a386Sopenharmony_ci } 283cb93a386Sopenharmony_ci 284cb93a386Sopenharmony_ci SkFontMgr_Android_CustomFonts custom; 285cb93a386Sopenharmony_ci custom.fSystemFontUse = SkFontMgr_Android_CustomFonts::kOnlyCustom; 286cb93a386Sopenharmony_ci custom.fBasePath = basePath.c_str(); 287cb93a386Sopenharmony_ci custom.fFontsXml = fontsXml.c_str(); 288cb93a386Sopenharmony_ci custom.fFallbackFontsXml = nullptr; 289cb93a386Sopenharmony_ci custom.fIsolated = false; 290cb93a386Sopenharmony_ci 291cb93a386Sopenharmony_ci sk_sp<SkFontMgr> fontMgr(SkFontMgr_New_Android(&custom)); 292cb93a386Sopenharmony_ci // "sans-serif" in "fonts/fonts.xml" is "fonts/Distortable.ttf" 293cb93a386Sopenharmony_ci sk_sp<SkTypeface> typeface(fontMgr->legacyMakeTypeface("sans-serif", SkFontStyle())); 294cb93a386Sopenharmony_ci 295cb93a386Sopenharmony_ci SkBitmap bitmapStream; 296cb93a386Sopenharmony_ci bitmapStream.allocN32Pixels(64, 64); 297cb93a386Sopenharmony_ci SkCanvas canvasStream(bitmapStream); 298cb93a386Sopenharmony_ci canvasStream.drawColor(SK_ColorWHITE); 299cb93a386Sopenharmony_ci 300cb93a386Sopenharmony_ci SkBitmap bitmapClone; 301cb93a386Sopenharmony_ci bitmapClone.allocN32Pixels(64, 64); 302cb93a386Sopenharmony_ci SkCanvas canvasClone(bitmapClone); 303cb93a386Sopenharmony_ci canvasStream.drawColor(SK_ColorWHITE); 304cb93a386Sopenharmony_ci 305cb93a386Sopenharmony_ci SkPaint paint; 306cb93a386Sopenharmony_ci paint.setColor(SK_ColorGRAY); 307cb93a386Sopenharmony_ci paint.setAntiAlias(true); 308cb93a386Sopenharmony_ci constexpr float kTextSize = 20; 309cb93a386Sopenharmony_ci 310cb93a386Sopenharmony_ci std::unique_ptr<SkStreamAsset> distortableStream( 311cb93a386Sopenharmony_ci GetResourceAsStream("fonts/Distortable.ttf")); 312cb93a386Sopenharmony_ci if (!distortableStream) { 313cb93a386Sopenharmony_ci return; 314cb93a386Sopenharmony_ci } 315cb93a386Sopenharmony_ci 316cb93a386Sopenharmony_ci SkPoint point = SkPoint::Make(20.0f, 20.0f); 317cb93a386Sopenharmony_ci SkFourByteTag tag = SkSetFourByteTag('w', 'g', 'h', 't'); 318cb93a386Sopenharmony_ci 319cb93a386Sopenharmony_ci for (int i = 0; i < 10; ++i) { 320cb93a386Sopenharmony_ci SkScalar styleValue = 321cb93a386Sopenharmony_ci SkDoubleToScalar(0.5 + i * ((2.0 - 0.5) / 10)); 322cb93a386Sopenharmony_ci SkFontArguments::VariationPosition::Coordinate 323cb93a386Sopenharmony_ci coordinates[] = {{tag, styleValue}}; 324cb93a386Sopenharmony_ci SkFontArguments::VariationPosition 325cb93a386Sopenharmony_ci position = {coordinates, SK_ARRAY_COUNT(coordinates)}; 326cb93a386Sopenharmony_ci 327cb93a386Sopenharmony_ci SkFont fontStream( 328cb93a386Sopenharmony_ci fontMgr->makeFromStream(distortableStream->duplicate(), 329cb93a386Sopenharmony_ci SkFontArguments().setVariationDesignPosition(position)), 330cb93a386Sopenharmony_ci kTextSize); 331cb93a386Sopenharmony_ci fontStream.setEdging(SkFont::Edging::kSubpixelAntiAlias); 332cb93a386Sopenharmony_ci 333cb93a386Sopenharmony_ci 334cb93a386Sopenharmony_ci SkFont fontClone( 335cb93a386Sopenharmony_ci typeface->makeClone(SkFontArguments().setVariationDesignPosition(position)), kTextSize); 336cb93a386Sopenharmony_ci fontClone.setEdging(SkFont::Edging::kSubpixelAntiAlias); 337cb93a386Sopenharmony_ci 338cb93a386Sopenharmony_ci constexpr char text[] = "abc"; 339cb93a386Sopenharmony_ci 340cb93a386Sopenharmony_ci canvasStream.drawColor(SK_ColorWHITE); 341cb93a386Sopenharmony_ci canvasStream.drawString(text, point.fX, point.fY, fontStream, paint); 342cb93a386Sopenharmony_ci 343cb93a386Sopenharmony_ci canvasClone.drawColor(SK_ColorWHITE); 344cb93a386Sopenharmony_ci canvasClone.drawString(text, point.fX, point.fY, fontClone, paint); 345cb93a386Sopenharmony_ci 346cb93a386Sopenharmony_ci bool success = bitmap_compare(bitmapStream, bitmapClone); 347cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, success); 348cb93a386Sopenharmony_ci } 349cb93a386Sopenharmony_ci} 350cb93a386Sopenharmony_ci 351cb93a386Sopenharmony_ciDEF_TEST(FontMgrAndroidSystemFallbackFor, reporter) { 352cb93a386Sopenharmony_ci constexpr char fontsXmlFilename[] = "fonts/fonts.xml"; 353cb93a386Sopenharmony_ci SkString basePath = GetResourcePath("fonts/"); 354cb93a386Sopenharmony_ci SkString fontsXml = GetResourcePath(fontsXmlFilename); 355cb93a386Sopenharmony_ci 356cb93a386Sopenharmony_ci if (!sk_exists(fontsXml.c_str())) { 357cb93a386Sopenharmony_ci ERRORF(reporter, "file missing: %s\n", fontsXmlFilename); 358cb93a386Sopenharmony_ci return; 359cb93a386Sopenharmony_ci } 360cb93a386Sopenharmony_ci 361cb93a386Sopenharmony_ci SkFontMgr_Android_CustomFonts custom; 362cb93a386Sopenharmony_ci custom.fSystemFontUse = SkFontMgr_Android_CustomFonts::kOnlyCustom; 363cb93a386Sopenharmony_ci custom.fBasePath = basePath.c_str(); 364cb93a386Sopenharmony_ci custom.fFontsXml = fontsXml.c_str(); 365cb93a386Sopenharmony_ci custom.fFallbackFontsXml = nullptr; 366cb93a386Sopenharmony_ci custom.fIsolated = false; 367cb93a386Sopenharmony_ci 368cb93a386Sopenharmony_ci sk_sp<SkFontMgr> fontMgr(SkFontMgr_New_Android(&custom)); 369cb93a386Sopenharmony_ci // "sans-serif" in "fonts/fonts.xml" is "fonts/Distortable.ttf", which doesn't have a '!' 370cb93a386Sopenharmony_ci // but "TestTTC" has a bold font which does have '!' and is marked as fallback for "sans-serif" 371cb93a386Sopenharmony_ci // and should take precedence over the same font marked as normal weight next to it. 372cb93a386Sopenharmony_ci sk_sp<SkTypeface> typeface(fontMgr->matchFamilyStyleCharacter( 373cb93a386Sopenharmony_ci "sans-serif", SkFontStyle(), nullptr, 0, '!')); 374cb93a386Sopenharmony_ci 375cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, typeface->fontStyle() == SkFontStyle::Bold()); 376cb93a386Sopenharmony_ci} 377