From 88ac266967f7d3f59a7c551f8af31c2b23d1e124 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Thu, 7 Dec 2017 13:22:49 +0000 Subject: [PATCH] Bug 1427641 - patch 3 - Add variation data to the cairo_ft_*_font objects, so they can properly track instances of the same font resource used with different variation parameters. r=lsalzman --- gfx/2d/ScaledFontFontconfig.cpp | 2 +- gfx/cairo/cairo/src/cairo-ft-font.c | 87 +++++++++++++++++++++++----- gfx/cairo/cairo/src/cairo-ft.h | 8 ++- gfx/thebes/gfxFT2FontBase.cpp | 73 +++++++++++++++-------- gfx/thebes/gfxFT2FontBase.h | 4 ++ gfx/thebes/gfxFT2FontList.cpp | 4 +- gfx/thebes/gfxFcPlatformFontList.cpp | 54 ++++++++++------- gfx/thebes/gfxFcPlatformFontList.h | 2 + 8 files changed, 171 insertions(+), 63 deletions(-) diff --git a/gfx/2d/ScaledFontFontconfig.cpp b/gfx/2d/ScaledFontFontconfig.cpp index df22211cfd89..dd92b880bb30 100644 --- a/gfx/2d/ScaledFontFontconfig.cpp +++ b/gfx/2d/ScaledFontFontconfig.cpp @@ -397,7 +397,7 @@ ScaledFontFontconfig::CreateFromInstanceData(const InstanceData& aInstanceData, FcPatternAddDouble(pattern, FC_PIXEL_SIZE, aSize); aInstanceData.SetupPattern(pattern); - cairo_font_face_t* font = cairo_ft_font_face_create_for_pattern(pattern); + cairo_font_face_t* font = cairo_ft_font_face_create_for_pattern(pattern, nullptr, 0); if (cairo_font_face_status(font) != CAIRO_STATUS_SUCCESS) { gfxWarning() << "Failed creating Cairo font face for Fontconfig pattern"; FcPatternDestroy(pattern); diff --git a/gfx/cairo/cairo/src/cairo-ft-font.c b/gfx/cairo/cairo/src/cairo-ft-font.c index 94a33557286b..3031ed89fd54 100644 --- a/gfx/cairo/cairo/src/cairo-ft-font.c +++ b/gfx/cairo/cairo/src/cairo-ft-font.c @@ -54,6 +54,7 @@ #include FT_IMAGE_H #include FT_BITMAP_H #include FT_TRUETYPE_TABLES_H +#include FT_MULTIPLE_MASTERS_H #if HAVE_FT_GLYPHSLOT_EMBOLDEN #include FT_SYNTHESIS_H #endif @@ -164,6 +165,10 @@ struct _cairo_ft_unscaled_font { char *filename; int id; + /* For variation fonts, the variation coordinates to apply to each axis. */ + const FT_Fixed *var_coords; + int num_var_coords; + /* We temporarily scale the unscaled font as needed */ cairo_bool_t have_scale; cairo_matrix_t current_scale; @@ -360,6 +365,8 @@ _cairo_ft_unscaled_font_init_key (cairo_ft_unscaled_font_t *key, cairo_bool_t from_face, char *filename, int id, + const FT_Fixed *var_coords, + int num_var_coords, FT_Face face) { unsigned long hash; @@ -368,12 +375,16 @@ _cairo_ft_unscaled_font_init_key (cairo_ft_unscaled_font_t *key, key->filename = filename; key->id = id; key->face = face; + key->var_coords = var_coords; + key->num_var_coords = num_var_coords; hash = _cairo_hash_string (filename); /* the constants are just arbitrary primes */ hash += ((unsigned long) id) * 1607; hash += ((unsigned long) face) * 2137; + hash = _cairo_hash_bytes (hash, var_coords, num_var_coords * sizeof(FT_Fixed)); + key->base.hash_entry.hash = hash; } @@ -403,6 +414,8 @@ _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled, cairo_bool_t from_face, const char *filename, int id, + const FT_Fixed *var_coords, + int num_var_coords, FT_Face face) { _cairo_unscaled_font_init (&unscaled->base, @@ -410,7 +423,7 @@ _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled, if (from_face) { unscaled->from_face = TRUE; - _cairo_ft_unscaled_font_init_key (unscaled, TRUE, NULL, 0, face); + _cairo_ft_unscaled_font_init_key (unscaled, TRUE, NULL, 0, var_coords, num_var_coords, face); } else { char *filename_copy; @@ -421,7 +434,7 @@ _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled, if (unlikely (filename_copy == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - _cairo_ft_unscaled_font_init_key (unscaled, FALSE, filename_copy, id, NULL); + _cairo_ft_unscaled_font_init_key (unscaled, FALSE, filename_copy, id, var_coords, num_var_coords, NULL); } unscaled->have_scale = FALSE; @@ -454,6 +467,11 @@ _cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled) unscaled->filename = NULL; } + if (unscaled->var_coords) { + free (unscaled->var_coords); + unscaled->var_coords = NULL; + } + CAIRO_MUTEX_FINI (unscaled->mutex); } @@ -465,12 +483,17 @@ _cairo_ft_unscaled_font_keys_equal (const void *key_a, const cairo_ft_unscaled_font_t *unscaled_b = key_b; if (unscaled_a->id == unscaled_b->id && - unscaled_a->from_face == unscaled_b->from_face) + unscaled_a->from_face == unscaled_b->from_face && + unscaled_a->num_var_coords == unscaled_b->num_var_coords) { if (unscaled_a->from_face) return unscaled_a->face == unscaled_b->face; - if (unscaled_a->filename == NULL && unscaled_b->filename == NULL) + if (unscaled_a->num_var_coords > 0 && + (memcmp (unscaled_a->var_coords, unscaled_b->var_coords, + unscaled_a->num_var_coords * sizeof(FT_Fixed)) != 0)) + return FALSE; + else if (unscaled_a->filename == NULL && unscaled_b->filename == NULL) return TRUE; else if (unscaled_a->filename == NULL || unscaled_b->filename == NULL) return FALSE; @@ -489,17 +512,20 @@ _cairo_ft_unscaled_font_create_internal (cairo_bool_t from_face, char *filename, int id, FT_Face font_face, + const FT_Fixed *var_coords, + int num_var_coords, cairo_ft_unscaled_font_t **out) { cairo_ft_unscaled_font_t key, *unscaled; cairo_ft_unscaled_font_map_t *font_map; + FT_Fixed* new_var_coords = NULL; cairo_status_t status; font_map = _cairo_ft_unscaled_font_map_lock (); if (unlikely (font_map == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - _cairo_ft_unscaled_font_init_key (&key, from_face, filename, id, font_face); + _cairo_ft_unscaled_font_init_key (&key, from_face, filename, id, var_coords, num_var_coords, font_face); /* Return existing unscaled font if it exists in the hash table. */ unscaled = _cairo_hash_table_lookup (font_map->hash_table, @@ -516,7 +542,17 @@ _cairo_ft_unscaled_font_create_internal (cairo_bool_t from_face, goto UNWIND_FONT_MAP_LOCK; } - status = _cairo_ft_unscaled_font_init (unscaled, from_face, filename, id, font_face); + /* If we have variation coordinate data, make a copy to save in the unscaled_font */ + if (var_coords && num_var_coords) { + new_var_coords = malloc (num_var_coords * sizeof(FT_Fixed)); + if (unlikely (!new_var_coords)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto UNWIND_VAR_COORDS; + } + memcpy (new_var_coords, var_coords, num_var_coords * sizeof(FT_Fixed)); + } + + status = _cairo_ft_unscaled_font_init (unscaled, from_face, filename, id, new_var_coords, num_var_coords, font_face); if (unlikely (status)) goto UNWIND_UNSCALED_MALLOC; @@ -535,6 +571,8 @@ UNWIND_UNSCALED_FONT_INIT: _cairo_ft_unscaled_font_fini (unscaled); UNWIND_UNSCALED_MALLOC: free (unscaled); +UNWIND_VAR_COORDS: + free (new_var_coords); UNWIND_FONT_MAP_LOCK: _cairo_ft_unscaled_font_map_unlock (); return status; @@ -544,6 +582,7 @@ UNWIND_FONT_MAP_LOCK: #if CAIRO_HAS_FC_FONT static cairo_status_t _cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern, + const FT_Fixed *var_coords, int num_var_coords, cairo_ft_unscaled_font_t **out) { FT_Face font_face = NULL; @@ -576,15 +615,17 @@ _cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern, DONE: return _cairo_ft_unscaled_font_create_internal (font_face != NULL, filename, id, font_face, + var_coords, num_var_coords, out); } #endif static cairo_status_t -_cairo_ft_unscaled_font_create_from_face (FT_Face face, +_cairo_ft_unscaled_font_create_from_face (FT_Face face, const FT_Fixed *var_coords, int num_var_coords, cairo_ft_unscaled_font_t **out) { - return _cairo_ft_unscaled_font_create_internal (TRUE, NULL, 0, face, out); + return _cairo_ft_unscaled_font_create_internal (TRUE, NULL, 0, face, + var_coords, num_var_coords, out); } static void @@ -684,6 +725,19 @@ _cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled) return NULL; } + if (unscaled->var_coords) { + typedef FT_UInt (*SetCoordsFunc)(FT_Face, FT_UInt, FT_Fixed*); + static SetCoordsFunc setCoords; + static cairo_bool_t firstTime = TRUE; + if (firstTime) { + firstTime = FALSE; + (SetCoordsFunc)dlsym(RTLD_DEFAULT, "FT_Set_Var_Design_Coordinates"); + } + if (setCoords) { + (*setCoords)(face, unscaled->num_var_coords, unscaled->var_coords); + } + } + unscaled->face = face; font_map->num_open_faces++; @@ -3066,7 +3120,7 @@ _cairo_ft_resolve_pattern (FcPattern *pattern, goto FREE_PATTERN; } - status = _cairo_ft_unscaled_font_create_for_pattern (resolved, &unscaled); + status = _cairo_ft_unscaled_font_create_for_pattern (resolved, NULL, 0, &unscaled); if (unlikely (status || unscaled == NULL)) { font_face = (cairo_font_face_t *)&_cairo_font_face_nil; goto FREE_RESOLVED; @@ -3123,14 +3177,17 @@ FREE_PATTERN: * cairo_font_face_destroy() when you are done using it. **/ cairo_font_face_t * -cairo_ft_font_face_create_for_pattern (FcPattern *pattern) +cairo_ft_font_face_create_for_pattern (FcPattern *pattern, + const FT_Fixed *var_coords, int num_var_coords) { cairo_ft_unscaled_font_t *unscaled; cairo_font_face_t *font_face; cairo_ft_options_t ft_options; cairo_status_t status; - status = _cairo_ft_unscaled_font_create_for_pattern (pattern, &unscaled); + status = _cairo_ft_unscaled_font_create_for_pattern (pattern, + var_coords, num_var_coords, + &unscaled); if (unlikely (status)) return (cairo_font_face_t *) &_cairo_font_face_nil; if (unlikely (unscaled == NULL)) { @@ -3200,14 +3257,18 @@ cairo_ft_font_face_create_for_pattern (FcPattern *pattern) **/ cairo_font_face_t * cairo_ft_font_face_create_for_ft_face (FT_Face face, - int load_flags) + int load_flags, + const FT_Fixed *var_coords, + int num_var_coords) { cairo_ft_unscaled_font_t *unscaled; cairo_font_face_t *font_face; cairo_ft_options_t ft_options; cairo_status_t status; - status = _cairo_ft_unscaled_font_create_from_face (face, &unscaled); + status = _cairo_ft_unscaled_font_create_from_face (face, + var_coords, num_var_coords, + &unscaled); if (unlikely (status)) return (cairo_font_face_t *)&_cairo_font_face_nil; diff --git a/gfx/cairo/cairo/src/cairo-ft.h b/gfx/cairo/cairo/src/cairo-ft.h index 56d48c3280a5..79c9cfff57d6 100644 --- a/gfx/cairo/cairo/src/cairo-ft.h +++ b/gfx/cairo/cairo/src/cairo-ft.h @@ -54,7 +54,9 @@ CAIRO_BEGIN_DECLS cairo_public cairo_font_face_t * cairo_ft_font_face_create_for_ft_face (FT_Face face, - int load_flags); + int load_flags, + const FT_Fixed *var_coords, + int num_var_coords); cairo_public FT_Face cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *scaled_font); @@ -65,7 +67,9 @@ cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *scaled_font); #if CAIRO_HAS_FC_FONT cairo_public cairo_font_face_t * -cairo_ft_font_face_create_for_pattern (FcPattern *pattern); +cairo_ft_font_face_create_for_pattern (FcPattern *pattern, + const FT_Fixed *var_coords, + int num_var_coords); cairo_public void cairo_ft_font_options_substitute (const cairo_font_options_t *options, diff --git a/gfx/thebes/gfxFT2FontBase.cpp b/gfx/thebes/gfxFT2FontBase.cpp index 679e5fd90939..a82e5f42b86d 100644 --- a/gfx/thebes/gfxFT2FontBase.cpp +++ b/gfx/thebes/gfxFT2FontBase.cpp @@ -207,32 +207,18 @@ gfxFT2FontBase::InitMetrics() return; } - // For variation fonts, figure out the variation coordinates to be applied - // for each axis, in freetype's order (which may not match the order of - // axes in mStyle.variationSettings, so we need to search by axis tag). - if (face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) { - typedef FT_UInt (*GetVarFunc)(FT_Face, FT_MM_Var**); - typedef FT_UInt (*SetCoordsFunc)(FT_Face, FT_UInt, FT_Fixed*); - static GetVarFunc getVar = - (GetVarFunc)dlsym(RTLD_DEFAULT, "FT_Get_MM_Var"); - static SetCoordsFunc setCoords = - (SetCoordsFunc)dlsym(RTLD_DEFAULT, "FT_Set_Var_Design_Coordinates"); - FT_MM_Var* ftVar; - if (getVar && setCoords && FT_Err_Ok == (*getVar)(face, &ftVar)) { - for (unsigned i = 0; i < ftVar->num_axis; ++i) { - mCoords.AppendElement(ftVar->axis[i].def); - for (const auto& v : mStyle.variationSettings) { - if (ftVar->axis[i].tag == v.mTag) { - FT_Fixed val = v.mValue * 0x10000; - val = std::min(val, ftVar->axis[i].maximum); - val = std::max(val, ftVar->axis[i].minimum); - mCoords[i] = val; - break; - } - } + if (!mStyle.variationSettings.IsEmpty()) { + SetupVarCoords(face, mStyle.variationSettings, &mCoords); + if (!mCoords.IsEmpty()) { + typedef FT_UInt (*SetCoordsFunc)(FT_Face, FT_UInt, FT_Fixed*); + static SetCoordsFunc setCoords; + static bool firstTime = true; + if (firstTime) { + firstTime = false; + setCoords = (SetCoordsFunc) + dlsym(RTLD_DEFAULT, "FT_Set_Var_Design_Coordinates"); } - free(ftVar); - if (!mCoords.IsEmpty()) { + if (setCoords) { (*setCoords)(face, mCoords.Length(), mCoords.Elements()); } } @@ -581,3 +567,40 @@ gfxFT2FontBase::SetupCairoFont(DrawTarget* aDrawTarget) cairo_set_scaled_font(gfxFont::RefCairo(aDrawTarget), cairoFont); return true; } + +// For variation fonts, figure out the variation coordinates to be applied +// for each axis, in freetype's order (which may not match the order of +// axes in mStyle.variationSettings, so we need to search by axis tag). +/*static*/ +void +gfxFT2FontBase::SetupVarCoords(FT_Face aFace, + const nsTArray& aVariations, + nsTArray* aCoords) +{ + aCoords->TruncateLength(0); + if (aFace->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) { + typedef FT_UInt (*GetVarFunc)(FT_Face, FT_MM_Var**); + static GetVarFunc getVar; + static bool firstTime = true; + if (firstTime) { + firstTime = false; + getVar = (GetVarFunc)dlsym(RTLD_DEFAULT, "FT_Get_MM_Var"); + } + FT_MM_Var* ftVar; + if (getVar && FT_Err_Ok == (*getVar)(aFace, &ftVar)) { + for (unsigned i = 0; i < ftVar->num_axis; ++i) { + aCoords->AppendElement(ftVar->axis[i].def); + for (const auto& v : aVariations) { + if (ftVar->axis[i].tag == v.mTag) { + FT_Fixed val = v.mValue * 0x10000; + val = std::min(val, ftVar->axis[i].maximum); + val = std::max(val, ftVar->axis[i].minimum); + (*aCoords)[i] = val; + break; + } + } + } + free(ftVar); + } + } +} diff --git a/gfx/thebes/gfxFT2FontBase.h b/gfx/thebes/gfxFT2FontBase.h index a284b992f9ef..12b489f4c54d 100644 --- a/gfx/thebes/gfxFT2FontBase.h +++ b/gfx/thebes/gfxFT2FontBase.h @@ -38,6 +38,10 @@ public: virtual FontType GetType() const override { return FONT_TYPE_FT2; } + static void SetupVarCoords(FT_Face aFace, + const nsTArray& aVariations, + nsTArray* aCoords); + private: uint32_t GetCharExtents(char aChar, cairo_text_extents_t* aExtents); void InitMetrics(); diff --git a/gfx/thebes/gfxFT2FontList.cpp b/gfx/thebes/gfxFT2FontList.cpp index 14dc91c75bbc..04bae88995f1 100644 --- a/gfx/thebes/gfxFT2FontList.cpp +++ b/gfx/thebes/gfxFT2FontList.cpp @@ -390,7 +390,7 @@ FT2FontEntry::CreateFontEntry(FT_Face aFace, int flags = gfxPlatform::GetPlatform()->FontHintingEnabled() ? FT_LOAD_DEFAULT : (FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING); - fe->mFontFace = cairo_ft_font_face_create_for_ft_face(aFace, flags); + fe->mFontFace = cairo_ft_font_face_create_for_ft_face(aFace, flags, nullptr, 0); FTUserFontData *userFontData = new FTUserFontData(aFace, aFontData); cairo_font_face_set_user_data(fe->mFontFace, &sFTUserFontDataKey, userFontData, FTFontDestroyFunc); @@ -434,7 +434,7 @@ FT2FontEntry::CairoFontFace() int flags = gfxPlatform::GetPlatform()->FontHintingEnabled() ? FT_LOAD_DEFAULT : (FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING); - mFontFace = cairo_ft_font_face_create_for_ft_face(face, flags); + mFontFace = cairo_ft_font_face_create_for_ft_face(face, flags, nullptr, 0); FTUserFontData *userFontData = new FTUserFontData(face, face.FontData()); cairo_font_face_set_user_data(mFontFace, &sFTUserFontDataKey, userFontData, FTFontDestroyFunc); diff --git a/gfx/thebes/gfxFcPlatformFontList.cpp b/gfx/thebes/gfxFcPlatformFontList.cpp index 28113938485d..58408a74038a 100644 --- a/gfx/thebes/gfxFcPlatformFontList.cpp +++ b/gfx/thebes/gfxFcPlatformFontList.cpp @@ -694,8 +694,19 @@ gfxFontconfigFontEntry::CreateScaledFont(FcPattern* aRenderPattern, FcPatternAddBool(aRenderPattern, FC_EMBEDDED_BITMAP, FcFalse); } + AutoTArray coords; + if (!aStyle->variationSettings.IsEmpty()) { + FT_Face ftFace = GetFTFace(); + if (ftFace) { + gfxFT2FontBase::SetupVarCoords(ftFace, aStyle->variationSettings, + &coords); + } + } + cairo_font_face_t *face = - cairo_ft_font_face_create_for_pattern(aRenderPattern); + cairo_ft_font_face_create_for_pattern(aRenderPattern, + coords.Elements(), + coords.Length()); if (mFontData) { // for data fonts, add the face/data pointer to the cairo font face @@ -928,6 +939,24 @@ gfxFontconfigFontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, return newFont; } +FT_Face +gfxFontconfigFontEntry::GetFTFace() +{ + if (!mFTFaceInitialized) { + mFTFaceInitialized = true; + FcChar8 *filename; + if (FcPatternGetString(mFontPattern, FC_FILE, 0, &filename) != FcResultMatch) { + return nullptr; + } + int index; + if (FcPatternGetInteger(mFontPattern, FC_INDEX, 0, &index) != FcResultMatch) { + index = 0; // default to 0 if not found in pattern + } + mFTFace = Factory::NewFTFace(nullptr, ToCharPtr(filename), index); + } + return mFTFace; +} + nsresult gfxFontconfigFontEntry::CopyFontTable(uint32_t aTableTag, nsTArray& aBuffer) @@ -935,34 +964,19 @@ gfxFontconfigFontEntry::CopyFontTable(uint32_t aTableTag, NS_ASSERTION(!mIsDataUserFont, "data fonts should be reading tables directly from memory"); - if (!mFTFaceInitialized) { - mFTFaceInitialized = true; - FcChar8 *filename; - if (FcPatternGetString(mFontPattern, FC_FILE, 0, &filename) != FcResultMatch) { - return NS_ERROR_FAILURE; - } - int index; - if (FcPatternGetInteger(mFontPattern, FC_INDEX, 0, &index) != FcResultMatch) { - index = 0; // default to 0 if not found in pattern - } - mFTFace = Factory::NewFTFace(nullptr, ToCharPtr(filename), index); - if (!mFTFace) { - return NS_ERROR_FAILURE; - } - } - - if (!mFTFace) { + FT_Face face = GetFTFace(); + if (!face) { return NS_ERROR_NOT_AVAILABLE; } FT_ULong length = 0; - if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, nullptr, &length) != 0) { + if (FT_Load_Sfnt_Table(face, aTableTag, 0, nullptr, &length) != 0) { return NS_ERROR_NOT_AVAILABLE; } if (!aBuffer.SetLength(length, fallible)) { return NS_ERROR_OUT_OF_MEMORY; } - if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, aBuffer.Elements(), &length) != 0) { + if (FT_Load_Sfnt_Table(face, aTableTag, 0, aBuffer.Elements(), &length) != 0) { aBuffer.Clear(); return NS_ERROR_FAILURE; } diff --git a/gfx/thebes/gfxFcPlatformFontList.h b/gfx/thebes/gfxFcPlatformFontList.h index 94e074fc56fd..7b6aa547335f 100644 --- a/gfx/thebes/gfxFcPlatformFontList.h +++ b/gfx/thebes/gfxFcPlatformFontList.h @@ -112,6 +112,8 @@ public: nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr) override; bool TestCharacterMap(uint32_t aCh) override; + FT_Face GetFTFace(); + hb_blob_t* GetFontTable(uint32_t aTableTag) override; void ForgetHBFace() override;