/* * Copyright 2014 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "tools/fonts/FontToolUtils.h" #include "include/core/SkBitmap.h" #include "include/core/SkCanvas.h" #include "include/core/SkFont.h" #include "include/core/SkFontMgr.h" #include "include/core/SkFontStyle.h" #include "include/core/SkFontTypes.h" #include "include/core/SkImage.h" #include "include/core/SkPaint.h" #include "include/core/SkPixelRef.h" // IWYU pragma: keep #include "include/core/SkStream.h" #include "include/core/SkTypeface.h" #include "include/private/base/SkMutex.h" #include "include/utils/SkCustomTypeface.h" #include "src/base/SkUTF.h" #include "src/core/SkOSFile.h" #include "tools/Resources.h" #include "tools/flags/CommandLineFlags.h" #include "tools/fonts/TestFontMgr.h" #if defined(SK_BUILD_FOR_WIN) && (defined(SK_FONTMGR_GDI_AVAILABLE) || \ defined(SK_FONTMGR_DIRECTWRITE_AVAILABLE)) #include "include/ports/SkTypeface_win.h" #endif #if defined(SK_BUILD_FOR_ANDROID) && defined(SK_FONTMGR_ANDROID_AVAILABLE) #include "include/ports/SkFontMgr_android.h" #include "include/ports/SkFontScanner_FreeType.h" #endif #if defined(SK_BUILD_FOR_ANDROID) && defined(SK_FONTMGR_ANDROID_NDK_AVAILABLE) #include "include/ports/SkFontMgr_android_ndk.h" #include "include/ports/SkFontScanner_FreeType.h" #endif #if defined(SK_FONTMGR_CORETEXT_AVAILABLE) && (defined(SK_BUILD_FOR_IOS) || \ defined(SK_BUILD_FOR_MAC)) #include "include/ports/SkFontMgr_mac_ct.h" #endif #if defined(SK_FONTMGR_FONTATIONS_AVAILABLE) #include "include/ports/SkFontMgr_Fontations.h" #endif #if defined(SK_BUILD_FOR_UNIX) && defined(SK_FONTMGR_FONTCONFIG_AVAILABLE) #include "include/ports/SkFontMgr_fontconfig.h" #include "include/ports/SkFontScanner_FreeType.h" #endif #if defined(SK_FONTMGR_FREETYPE_DIRECTORY_AVAILABLE) #include "include/ports/SkFontMgr_directory.h" #endif #if defined(SK_FONTMGR_FREETYPE_EMPTY_AVAILABLE) #include "include/ports/SkFontMgr_empty.h" #endif namespace ToolUtils { static DEFINE_bool(nativeFonts, true, "If true, use native font manager and rendering. " "If false, fonts will draw as portably as possible."); #if defined(SK_BUILD_FOR_WIN) static DEFINE_bool(gdi, false, "Use GDI instead of DirectWrite for font rendering."); #endif #if defined(SK_FONTMGR_FONTATIONS_AVAILABLE) static DEFINE_bool(fontations, false, "Use Fontations for native font rendering."); #endif #if defined(SK_FONTMGR_ANDROID_NDK_AVAILABLE) static DEFINE_bool(androidndkfonts, false, "Use AndroidNDK for native font rendering."); #endif sk_sp PlanetTypeface() { static const sk_sp planetTypeface = []() { const char* filename; #if defined(SK_BUILD_FOR_WIN) filename = "fonts/planetcolr.ttf"; #elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) filename = "fonts/planetsbix.ttf"; #else filename = "fonts/planetcbdt.ttf"; #endif sk_sp typeface = CreateTypefaceFromResource(filename); if (typeface) { return typeface; } return CreateTestTypeface("Planet", SkFontStyle()); }(); return planetTypeface; } EmojiTestSample EmojiSample() { static const EmojiTestSample emojiSample = []() { EmojiTestSample sample = {nullptr, ""}; #if defined(SK_BUILD_FOR_WIN) sample = EmojiSample(EmojiFontFormat::ColrV0); #elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) sample = EmojiSample(EmojiFontFormat::Sbix); #else sample = EmojiSample(EmojiFontFormat::Cbdt); #endif if (sample.typeface) { return sample; } return EmojiSample(EmojiFontFormat::Test); }(); return emojiSample; } EmojiTestSample EmojiSample(EmojiFontFormat format) { EmojiTestSample sample; sample.sampleText = "\U0001F600 \u2662"; // 😀 ♢ switch (format) { case EmojiFontFormat::Cbdt: sample.typeface = CreateTypefaceFromResource("fonts/cbdt.ttf"); break; case EmojiFontFormat::Sbix: sample.typeface = CreateTypefaceFromResource("fonts/sbix.ttf"); break; case EmojiFontFormat::ColrV0: sample.typeface = CreateTypefaceFromResource("fonts/colr.ttf"); break; case EmojiFontFormat::Svg: sample.typeface = CreateTypefaceFromResource("fonts/SampleSVG.ttf"); sample.sampleText = "abcdefghij"; break; case EmojiFontFormat::Test: sample.typeface = CreatePortableTypeface("Emoji", SkFontStyle()); } return sample; } SkString NameForFontFormat(EmojiFontFormat format) { switch (format) { case EmojiFontFormat::Cbdt: return SkString("cbdt"); case EmojiFontFormat::Sbix: return SkString("sbix"); case EmojiFontFormat::ColrV0: return SkString("colrv0"); case EmojiFontFormat::Test: return SkString("test"); case EmojiFontFormat::Svg: return SkString("svg"); } return SkString(); } sk_sp SampleUserTypeface() { SkCustomTypefaceBuilder builder; SkFont font; const float upem = 200; { SkFontMetrics metrics; metrics.fFlags = 0; metrics.fTop = -200; metrics.fAscent = -150; metrics.fDescent = 50; metrics.fBottom = -75; metrics.fLeading = 10; metrics.fAvgCharWidth = 150; metrics.fMaxCharWidth = 300; metrics.fXMin = -20; metrics.fXMax = 290; metrics.fXHeight = -100; metrics.fCapHeight = 0; metrics.fUnderlineThickness = 5; metrics.fUnderlinePosition = 2; metrics.fStrikeoutThickness = 5; metrics.fStrikeoutPosition = -50; builder.setMetrics(metrics, 1.0f/upem); } builder.setFontStyle(SkFontStyle(367, 3, SkFontStyle::kOblique_Slant)); const SkMatrix scale = SkMatrix::Scale(1.0f/upem, 1.0f/upem); for (SkGlyphID index = 0; index <= 67; ++index) { SkScalar width; width = 100; builder.setGlyph(index, width/upem, SkPath::Circle(50, -50, 75).makeTransform(scale)); } return builder.detach(); } sk_sp CreatePortableTypeface(const char* name, SkFontStyle style) { static sk_sp portableFontMgr = MakePortableFontMgr(); SkASSERT_RELEASE(portableFontMgr); sk_sp face = portableFontMgr->legacyMakeTypeface(name, style); SkASSERT_RELEASE(face); return face; } sk_sp DefaultPortableTypeface() { // At last check, the default typeface is a serif font. sk_sp face = CreatePortableTypeface(nullptr, SkFontStyle()); SkASSERT_RELEASE(face); return face; } SkFont DefaultPortableFont() { return SkFont(DefaultPortableTypeface(), 12); } SkBitmap CreateStringBitmap(int w, int h, SkColor c, int x, int y, int textSize, const char* str) { SkBitmap bitmap; bitmap.allocN32Pixels(w, h); SkCanvas canvas(bitmap); SkPaint paint; paint.setColor(c); SkFont font(DefaultPortableTypeface(), textSize); canvas.clear(0x00000000); canvas.drawSimpleText(str, strlen(str), SkTextEncoding::kUTF8, SkIntToScalar(x), SkIntToScalar(y), font, paint); // Tag data as sRGB (without doing any color space conversion). Color-space aware configs // will process this correctly but legacy configs will render as if this returned N32. SkBitmap result; result.setInfo(SkImageInfo::MakeS32(w, h, kPremul_SkAlphaType)); result.setPixelRef(sk_ref_sp(bitmap.pixelRef()), 0, 0); return result; } sk_sp CreateStringImage(int w, int h, SkColor c, int x, int y, int textSize, const char* str) { return CreateStringBitmap(w, h, c, x, y, textSize, str).asImage(); } #ifndef SK_FONT_FILE_PREFIX # if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) # define SK_FONT_FILE_PREFIX "/System/Library/Fonts/" # else # define SK_FONT_FILE_PREFIX "/usr/share/fonts/" # endif #endif sk_sp TestFontMgr() { static sk_sp mgr; static SkOnce once; once([] { if (!FLAGS_nativeFonts) { mgr = MakePortableFontMgr(); } #if defined(SK_BUILD_FOR_WIN) && defined(SK_FONTMGR_GDI_AVAILABLE) else if (FLAGS_gdi) { mgr = SkFontMgr_New_GDI(); } #endif #if defined(SK_FONTMGR_FONTATIONS_AVAILABLE) else if (FLAGS_fontations) { mgr = SkFontMgr_New_Fontations_Empty(); } #endif #if defined(SK_BUILD_FOR_ANDROID) && defined(SK_FONTMGR_ANDROID_NDK_AVAILABLE) && defined(SK_TYPEFACE_FACTORY_FREETYPE) else if (FLAGS_androidndkfonts) { mgr = SkFontMgr_New_AndroidNDK(false, SkFontScanner_Make_FreeType()); } #endif else { #if defined(SK_BUILD_FOR_ANDROID) && defined(SK_FONTMGR_ANDROID_AVAILABLE) && defined(SK_TYPEFACE_FACTORY_FREETYPE) mgr = SkFontMgr_New_Android(nullptr, SkFontScanner_Make_FreeType()); #elif defined(SK_BUILD_FOR_WIN) && defined(SK_FONTMGR_DIRECTWRITE_AVAILABLE) mgr = SkFontMgr_New_DirectWrite(); #elif defined(SK_FONTMGR_CORETEXT_AVAILABLE) && (defined(SK_BUILD_FOR_IOS) || \ defined(SK_BUILD_FOR_MAC)) mgr = SkFontMgr_New_CoreText(nullptr); #elif defined(SK_FONTMGR_FONTCONFIG_AVAILABLE) && defined(SK_TYPEFACE_FACTORY_FREETYPE) mgr = SkFontMgr_New_FontConfig(nullptr, SkFontScanner_Make_FreeType()); #elif defined(SK_FONTMGR_FREETYPE_DIRECTORY_AVAILABLE) // In particular, this is used on ChromeOS, which is Linux-like but doesn't have // FontConfig. mgr = SkFontMgr_New_Custom_Directory(SK_FONT_FILE_PREFIX); #elif defined(SK_FONTMGR_FREETYPE_EMPTY_AVAILABLE) mgr = SkFontMgr_New_Custom_Empty(); #else mgr = SkFontMgr::RefEmpty(); #endif } SkASSERT_RELEASE(mgr); }); return mgr; } bool FontMgrIsGDI() { if (!FLAGS_nativeFonts) { return false; } #if defined(SK_BUILD_FOR_WIN) if (FLAGS_gdi) { return true; } #endif return false; } void UsePortableFontMgr() { FLAGS_nativeFonts = false; } sk_sp DefaultTypeface() { return CreateTestTypeface(nullptr, SkFontStyle()); } sk_sp CreateTestTypeface(const char* name, SkFontStyle style) { sk_sp fm = TestFontMgr(); SkASSERT_RELEASE(fm); sk_sp face = fm->legacyMakeTypeface(name, style); if (face) { return face; } return CreatePortableTypeface(name, style); } sk_sp CreateTypefaceFromResource(const char* resource, int ttcIndex) { sk_sp fm = TestFontMgr(); SkASSERT_RELEASE(fm); return fm->makeFromStream(GetResourceAsStream(resource), ttcIndex); } SkFont DefaultFont() { return SkFont(DefaultTypeface(), 12); } } // namespace ToolUtils