# HG changeset patch # User Jonathan Kew # Date 1517232251 0 # Node ID 33fb37dc9d54aed1361ef20fcd50154fbbe61bd9 # Parent 39ca1468093d393554f442cf58d96d14ed48e13d Bug 1432552 - patch 2 - Linux font back-end implementation of getVariationInstances. r=dholbert diff --git a/gfx/thebes/gfxFcPlatformFontList.cpp b/gfx/thebes/gfxFcPlatformFontList.cpp --- a/gfx/thebes/gfxFcPlatformFontList.cpp +++ b/gfx/thebes/gfxFcPlatformFontList.cpp @@ -355,18 +355,47 @@ gfxFontconfigFontEntry::gfxFontconfigFon // because our cmap-reading code will fail and we depend on FT+Fc to // determine the coverage. // We set the flag here, but may flip it the first time TestCharacterMap // is called, at which point we'll look to see whether a 'cmap' is // actually present in the font. mIgnoreFcCharmap = true; } +typedef FT_Error (*GetVarFunc)(FT_Face, FT_MM_Var**); +typedef FT_Error (*DoneVarFunc)(FT_Library, FT_MM_Var*); +static GetVarFunc sGetVar; +static DoneVarFunc sDoneVar; +static bool sInitializedVarFuncs = false; + +static void +InitializeVarFuncs() +{ + if (sInitializedVarFuncs) { + return; + } + sInitializedVarFuncs = true; + sGetVar = (GetVarFunc)dlsym(RTLD_DEFAULT, "FT_Get_MM_Var"); + sDoneVar = (DoneVarFunc)dlsym(RTLD_DEFAULT, "FT_Done_MM_Var"); +} + gfxFontconfigFontEntry::~gfxFontconfigFontEntry() { + if (mMMVar) { + // Prior to freetype 2.9, there was no specific function to free the + // FT_MM_Var record, and the docs just said to use free(). + // InitializeVarFuncs must have been called in order for mMMVar to be + // non-null here, so we don't need to do it again. + if (sDoneVar) { + MOZ_ASSERT(mFTFace, "How did mMMVar get set without a face?"); + (*sDoneVar)(mFTFace->glyph->library, mMMVar); + } else { + free(mMMVar); + } + } } nsresult gfxFontconfigFontEntry::ReadCMAP(FontInfoData *aFontInfoData) { // attempt this once, if errors occur leave a blank cmap if (mCharacterMap) { return NS_OK; @@ -464,16 +493,24 @@ gfxFontconfigFontEntry::MaybeReleaseFTFa { // don't release if either HB or Gr face still exists if (mHBFace || mGrFace) { return; } // only close out FT_Face for system fonts, not for data fonts if (!mIsDataUserFont) { if (mFTFace) { + if (mMMVar) { + if (sDoneVar) { + (*sDoneVar)(mFTFace->glyph->library, mMMVar); + } else { + free(mMMVar); + } + mMMVar = nullptr; + } Factory::ReleaseFTFace(mFTFace); mFTFace = nullptr; } mFTFaceInitialized = false; } } void @@ -1012,58 +1049,90 @@ gfxFontconfigFontEntry::HasVariations() { FT_Face face = GetFTFace(); if (face) { return face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS; } return false; } +FT_MM_Var* +gfxFontconfigFontEntry::GetMMVar() +{ + if (mMMVarInitialized) { + return mMMVar; + } + mMMVarInitialized = true; + InitializeVarFuncs(); + if (!sGetVar) { + return nullptr; + } + FT_Face face = GetFTFace(); + if (!face) { + return nullptr; + } + if (FT_Err_Ok != (*sGetVar)(face, &mMMVar)) { + mMMVar = nullptr; + } + return mMMVar; +} + void gfxFontconfigFontEntry::GetVariationAxes(nsTArray& aAxes) { MOZ_ASSERT(aAxes.IsEmpty()); - FT_Face face = GetFTFace(); - if (!face) { + FT_MM_Var* mmVar = GetMMVar(); + if (!mmVar) { return; } - typedef FT_Error (*GetVarFunc)(FT_Face, FT_MM_Var**); - static GetVarFunc getVar; - typedef FT_Error (*DoneVarFunc)(FT_Library, FT_MM_Var*); - static DoneVarFunc doneVar; - static bool firstTime = true; - if (firstTime) { - firstTime = false; - getVar = (GetVarFunc)dlsym(RTLD_DEFAULT, "FT_Get_MM_Var"); - doneVar = (DoneVarFunc)dlsym(RTLD_DEFAULT, "FT_Done_MM_Var"); - } - if (!getVar) { - return; - } - FT_MM_Var* mmVar; - if (FT_Err_Ok != (*getVar)(face, &mmVar)) { - return; - } + aAxes.SetCapacity(mmVar->num_axis); for (unsigned i = 0; i < mmVar->num_axis; i++) { const auto& a = mmVar->axis[i]; gfxFontVariationAxis axis; axis.mMinValue = a.minimum / 65536.0; axis.mMaxValue = a.maximum / 65536.0; axis.mDefaultValue = a.def / 65536.0; axis.mTag = a.tag; axis.mName.Assign(NS_ConvertUTF8toUTF16(a.name)); aAxes.AppendElement(axis); } - // Prior to freetype 2.9, there was no specific function to free the FT_MM_Var, - // and the docs just said to use free(). - if (doneVar) { - (*doneVar)(face->glyph->library, mmVar); - } else { - free(mmVar); +} + +void +gfxFontconfigFontEntry::GetVariationInstances( + nsTArray& aInstances) +{ + MOZ_ASSERT(aInstances.IsEmpty()); + FT_MM_Var* mmVar = GetMMVar(); + if (!mmVar) { + return; + } + hb_blob_t* nameTable = GetFontTable(TRUETYPE_TAG('n','a','m','e')); + if (!nameTable) { + return; } + aInstances.SetCapacity(mmVar->num_namedstyles); + for (unsigned i = 0; i < mmVar->num_namedstyles; i++) { + const auto& ns = mmVar->namedstyle[i]; + gfxFontVariationInstance inst; + nsresult rv = + gfxFontUtils::ReadCanonicalName(nameTable, ns.strid, inst.mName); + if (NS_FAILED(rv)) { + continue; + } + inst.mValues.SetCapacity(mmVar->num_axis); + for (unsigned j = 0; j < mmVar->num_axis; j++) { + gfxFontVariationValue value; + value.mAxis = mmVar->axis[j].tag; + value.mValue = ns.coords[j] / 65536.0; + inst.mValues.AppendElement(value); + } + aInstances.AppendElement(inst); + } + hb_blob_destroy(nameTable); } nsresult gfxFontconfigFontEntry::CopyFontTable(uint32_t aTableTag, nsTArray& aBuffer) { NS_ASSERTION(!mIsDataUserFont, "data fonts should be reading tables directly from memory"); diff --git a/gfx/thebes/gfxFcPlatformFontList.h b/gfx/thebes/gfxFcPlatformFontList.h --- a/gfx/thebes/gfxFcPlatformFontList.h +++ b/gfx/thebes/gfxFcPlatformFontList.h @@ -13,16 +13,17 @@ #include "mozilla/mozalloc.h" #include "nsAutoRef.h" #include "nsClassHashtable.h" #include #include "ft2build.h" #include FT_FREETYPE_H #include FT_TRUETYPE_TABLES_H +#include FT_MULTIPLE_MASTERS_H #include #include #ifdef MOZ_CONTENT_SANDBOX #include "mozilla/SandboxBroker.h" #endif namespace mozilla { @@ -110,18 +111,21 @@ public: FcPattern* GetPattern() { return mFontPattern; } nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr) override; bool TestCharacterMap(uint32_t aCh) override; FT_Face GetFTFace(); + FT_MM_Var* GetMMVar(); + bool HasVariations() override; void GetVariationAxes(nsTArray& aAxes) override; + void GetVariationInstances(nsTArray& aInstances) override; hb_blob_t* GetFontTable(uint32_t aTableTag) override; void ForgetHBFace() override; void ReleaseGrFace(gr_face* aFace) override; double GetAspect(); @@ -183,16 +187,21 @@ protected: private: void MoveToFront(size_t aIndex); static const size_t kNumEntries = 3; mozilla::ThreadSafeWeakPtr mUnscaledFonts[kNumEntries]; }; UnscaledFontCache mUnscaledFontCache; + + // Because of FreeType bug 52955, we keep the FT_MM_Var struct when it is + // first loaded, rather than releasing it and re-fetching it as needed. + FT_MM_Var* mMMVar = nullptr; + bool mMMVarInitialized = false; }; class gfxFontconfigFontFamily : public gfxFontFamily { public: explicit gfxFontconfigFontFamily(const nsAString& aName) : gfxFontFamily(aName), mContainsAppFonts(false), mHasNonScalableFaces(false),