Make SkFontMgr_fontconfig respect the sysroot.
An FcConfig has the concept of a sysroot against which file names should be resolved. Add support for this so that it is possible to use relocatable FcConfigs. Also adds a test that this works. Change-Id: I523d5fb1233830434a88dc52b27728aaf83bb5a5 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/206278 Commit-Queue: Ben Wagner <bungeman@google.com> Reviewed-by: Herb Derby <herb@google.com>
This commit is contained in:
parent
0a72a06d10
commit
25e371f7ee
@ -32,7 +32,7 @@ class SkData;
|
|||||||
|
|
||||||
// FC_POSTSCRIPT_NAME was added with b561ff20 which ended up in 2.10.92
|
// FC_POSTSCRIPT_NAME was added with b561ff20 which ended up in 2.10.92
|
||||||
// Ubuntu 14.04 is on 2.11.0
|
// Ubuntu 14.04 is on 2.11.0
|
||||||
// Debian 8 is on 2.11
|
// Debian 8 and 9 are on 2.11
|
||||||
// OpenSUSE Leap 42.1 is on 2.11.0 (42.3 is on 2.11.1)
|
// OpenSUSE Leap 42.1 is on 2.11.0 (42.3 is on 2.11.1)
|
||||||
// Fedora 24 is on 2.11.94
|
// Fedora 24 is on 2.11.94
|
||||||
#ifndef FC_POSTSCRIPT_NAME
|
#ifndef FC_POSTSCRIPT_NAME
|
||||||
@ -463,10 +463,12 @@ private:
|
|||||||
|
|
||||||
class SkTypeface_fontconfig : public SkTypeface_FreeType {
|
class SkTypeface_fontconfig : public SkTypeface_FreeType {
|
||||||
public:
|
public:
|
||||||
static sk_sp<SkTypeface_fontconfig> Make(SkAutoFcPattern pattern) {
|
static sk_sp<SkTypeface_fontconfig> Make(SkAutoFcPattern pattern, SkString sysroot) {
|
||||||
return sk_sp<SkTypeface_fontconfig>(new SkTypeface_fontconfig(std::move(pattern)));
|
return sk_sp<SkTypeface_fontconfig>(new SkTypeface_fontconfig(std::move(pattern),
|
||||||
|
std::move(sysroot)));
|
||||||
}
|
}
|
||||||
mutable SkAutoFcPattern fPattern;
|
mutable SkAutoFcPattern fPattern; // Mutable for passing to FontConfig API.
|
||||||
|
const SkString fSysroot;
|
||||||
|
|
||||||
void onGetFamilyName(SkString* familyName) const override {
|
void onGetFamilyName(SkString* familyName) const override {
|
||||||
*familyName = get_string(fPattern, FC_FAMILY);
|
*familyName = get_string(fPattern, FC_FAMILY);
|
||||||
@ -484,7 +486,17 @@ public:
|
|||||||
std::unique_ptr<SkStreamAsset> onOpenStream(int* ttcIndex) const override {
|
std::unique_ptr<SkStreamAsset> onOpenStream(int* ttcIndex) const override {
|
||||||
FCLocker lock;
|
FCLocker lock;
|
||||||
*ttcIndex = get_int(fPattern, FC_INDEX, 0);
|
*ttcIndex = get_int(fPattern, FC_INDEX, 0);
|
||||||
return SkStream::MakeFromFile(get_string(fPattern, FC_FILE));
|
const char* filename = get_string(fPattern, FC_FILE);
|
||||||
|
// See FontAccessible for note on searching sysroot then non-sysroot path.
|
||||||
|
SkString resolvedFilename;
|
||||||
|
if (!fSysroot.isEmpty()) {
|
||||||
|
resolvedFilename = fSysroot;
|
||||||
|
resolvedFilename += filename;
|
||||||
|
if (sk_exists(resolvedFilename.c_str(), kRead_SkFILE_Flag)) {
|
||||||
|
filename = resolvedFilename.c_str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SkStream::MakeFromFile(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onFilterRec(SkScalerContextRec* rec) const override {
|
void onFilterRec(SkScalerContextRec* rec) const override {
|
||||||
@ -550,19 +562,21 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SkTypeface_fontconfig(SkAutoFcPattern pattern)
|
SkTypeface_fontconfig(SkAutoFcPattern pattern, SkString sysroot)
|
||||||
: INHERITED(skfontstyle_from_fcpattern(pattern),
|
: INHERITED(skfontstyle_from_fcpattern(pattern),
|
||||||
FC_PROPORTIONAL != get_int(pattern, FC_SPACING, FC_PROPORTIONAL))
|
FC_PROPORTIONAL != get_int(pattern, FC_SPACING, FC_PROPORTIONAL))
|
||||||
, fPattern(std::move(pattern))
|
, fPattern(std::move(pattern))
|
||||||
|
, fSysroot(std::move(sysroot))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
typedef SkTypeface_FreeType INHERITED;
|
typedef SkTypeface_FreeType INHERITED;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SkFontMgr_fontconfig : public SkFontMgr {
|
class SkFontMgr_fontconfig : public SkFontMgr {
|
||||||
mutable SkAutoFcConfig fFC;
|
mutable SkAutoFcConfig fFC; // Only mutable to avoid const cast when passed to FontConfig API.
|
||||||
sk_sp<SkDataTable> fFamilyNames;
|
const SkString fSysroot;
|
||||||
SkTypeface_FreeType::Scanner fScanner;
|
const sk_sp<SkDataTable> fFamilyNames;
|
||||||
|
const SkTypeface_FreeType::Scanner fScanner;
|
||||||
|
|
||||||
class StyleSet : public SkFontStyleSet {
|
class StyleSet : public SkFontStyleSet {
|
||||||
public:
|
public:
|
||||||
@ -689,7 +703,7 @@ class SkFontMgr_fontconfig : public SkFontMgr {
|
|||||||
sk_sp<SkTypeface> face = fTFCache.findByProcAndRef(FindByFcPattern, pattern);
|
sk_sp<SkTypeface> face = fTFCache.findByProcAndRef(FindByFcPattern, pattern);
|
||||||
if (!face) {
|
if (!face) {
|
||||||
FcPatternReference(pattern);
|
FcPatternReference(pattern);
|
||||||
face = SkTypeface_fontconfig::Make(SkAutoFcPattern(pattern));
|
face = SkTypeface_fontconfig::Make(SkAutoFcPattern(pattern), fSysroot);
|
||||||
if (face) {
|
if (face) {
|
||||||
// Cannot hold the lock when calling add; an evicted typeface may need to lock.
|
// Cannot hold the lock when calling add; an evicted typeface may need to lock.
|
||||||
FCLocker::Suspend suspend;
|
FCLocker::Suspend suspend;
|
||||||
@ -703,6 +717,7 @@ public:
|
|||||||
/** Takes control of the reference to 'config'. */
|
/** Takes control of the reference to 'config'. */
|
||||||
explicit SkFontMgr_fontconfig(FcConfig* config)
|
explicit SkFontMgr_fontconfig(FcConfig* config)
|
||||||
: fFC(config ? config : FcInitLoadConfigAndFonts())
|
: fFC(config ? config : FcInitLoadConfigAndFonts())
|
||||||
|
, fSysroot(reinterpret_cast<const char*>(FcConfigGetSysRoot(fFC)))
|
||||||
, fFamilyNames(GetFamilyNames(fFC)) { }
|
, fFamilyNames(GetFamilyNames(fFC)) { }
|
||||||
|
|
||||||
~SkFontMgr_fontconfig() override {
|
~SkFontMgr_fontconfig() override {
|
||||||
@ -758,12 +773,30 @@ protected:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool FontAccessible(FcPattern* font) {
|
bool FontAccessible(FcPattern* font) const {
|
||||||
// FontConfig can return fonts which are unreadable.
|
// FontConfig can return fonts which are unreadable.
|
||||||
const char* filename = get_string(font, FC_FILE, nullptr);
|
const char* filename = get_string(font, FC_FILE, nullptr);
|
||||||
if (nullptr == filename) {
|
if (nullptr == filename) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When sysroot was implemented in e96d7760886a3781a46b3271c76af99e15cb0146 (before 2.11.0)
|
||||||
|
// it was broken; mostly fixed in d17f556153fbaf8fe57fdb4fc1f0efa4313f0ecf (after 2.11.1).
|
||||||
|
// This leaves Debian 8 and 9 with broken support for this feature.
|
||||||
|
// As a result, this feature should not be used until at least 2.11.91.
|
||||||
|
// The broken support is mostly around not making all paths relative to the sysroot.
|
||||||
|
// However, even at 2.13.1 it is possible to get a mix of sysroot and non-sysroot paths,
|
||||||
|
// as any added file path not lexically starting with the sysroot will be unchanged.
|
||||||
|
// To allow users to add local app files outside the sysroot,
|
||||||
|
// prefer the sysroot but also look without the sysroot.
|
||||||
|
if (!fSysroot.isEmpty()) {
|
||||||
|
SkString resolvedFilename;
|
||||||
|
resolvedFilename = fSysroot;
|
||||||
|
resolvedFilename += filename;
|
||||||
|
if (sk_exists(resolvedFilename.c_str(), kRead_SkFILE_Flag)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
return sk_exists(filename, kRead_SkFILE_Flag);
|
return sk_exists(filename, kRead_SkFILE_Flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,13 +30,22 @@ static bool bitmap_compare(const SkBitmap& ref, const SkBitmap& test) {
|
|||||||
|
|
||||||
DEF_TEST(FontMgrFontConfig, reporter) {
|
DEF_TEST(FontMgrFontConfig, reporter) {
|
||||||
FcConfig* config = FcConfigCreate();
|
FcConfig* config = FcConfigCreate();
|
||||||
SkString distortablePath = GetResourcePath("fonts/Distortable.ttf");
|
|
||||||
FcConfigAppFontAddFile(
|
// FontConfig may modify the passed path (make absolute or other).
|
||||||
config, reinterpret_cast<const FcChar8*>(distortablePath.c_str()));
|
FcConfigSetSysRoot(config, reinterpret_cast<const FcChar8*>(GetResourcePath("").c_str()));
|
||||||
|
// FontConfig will lexically compare paths against its version of the sysroot.
|
||||||
|
SkString distortablePath(reinterpret_cast<const char*>(FcConfigGetSysRoot(config)));
|
||||||
|
distortablePath += "/fonts/Distortable.ttf";
|
||||||
|
FcConfigAppFontAddFile(config, reinterpret_cast<const FcChar8*>(distortablePath.c_str()));
|
||||||
|
|
||||||
FcConfigBuildFonts(config);
|
FcConfigBuildFonts(config);
|
||||||
|
|
||||||
sk_sp<SkFontMgr> fontMgr(SkFontMgr_New_FontConfig(config));
|
sk_sp<SkFontMgr> fontMgr(SkFontMgr_New_FontConfig(config));
|
||||||
sk_sp<SkTypeface> typeface(fontMgr->legacyMakeTypeface("Distortable", SkFontStyle()));
|
sk_sp<SkTypeface> typeface(fontMgr->legacyMakeTypeface("Distortable", SkFontStyle()));
|
||||||
|
if (!typeface) {
|
||||||
|
ERRORF(reporter, "Could not find typeface. FcVersion: %d", FcGetVersion());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SkBitmap bitmapStream;
|
SkBitmap bitmapStream;
|
||||||
bitmapStream.allocN32Pixels(64, 64);
|
bitmapStream.allocN32Pixels(64, 64);
|
||||||
|
Loading…
Reference in New Issue
Block a user