From f13d0ae5a68c3ae93d2839a1cc8ff3fe96622a6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= Date: Wed, 20 Mar 2019 15:41:20 +0000 Subject: [PATCH] rhbz#1690732 basic font variation support on the fontconfig/harfbuzz/cairo drawing path for preset variations Related: rhbz#1690732 FC_INDEX doesn't mean exactly what it used to mean its been repurposed to hold font face variation information too (cherry picked from commit 3681e8d8e6270912090b22445e67899bc2207e39) Change-Id: I95ef68aecfd59687ae9aae58e01e394c83c6ea9e --- vcl/inc/unx/fc_fontoptions.hxx | 2 +- vcl/inc/unx/fontmanager.hxx | 6 +- vcl/inc/unx/freetype_glyphcache.hxx | 9 +-- vcl/inc/unx/glyphcache.hxx | 8 ++- vcl/unx/generic/fontmanager/fontconfig.cxx | 54 ++++++++++++------ vcl/unx/generic/fontmanager/fontmanager.cxx | 20 ++++++- vcl/unx/generic/gdi/cairotextrender.cxx | 3 +- .../generic/glyphs/freetype_glyphcache.cxx | 55 +++++++++++++++++-- vcl/unx/generic/glyphs/glyphcache.cxx | 5 +- vcl/unx/generic/print/genpspgraphics.cxx | 3 +- 10 files changed, 129 insertions(+), 36 deletions(-) diff --git a/vcl/inc/unx/fc_fontoptions.hxx b/vcl/inc/unx/fc_fontoptions.hxx index 4e21a4d28c3e..c5ea38ce4f54 100644 --- a/vcl/inc/unx/fc_fontoptions.hxx +++ b/vcl/inc/unx/fc_fontoptions.hxx @@ -34,7 +34,7 @@ public: mpPattern(pPattern) {} ~FontConfigFontOptions(); - void SyncPattern(const OString& rFileName, int nFontFace, bool bEmbolden); + void SyncPattern(const OString& rFileName, sal_uInt32 nFontFace, sal_uInt32 nFontVariation, bool bEmbolden); FcPattern* GetPattern() const; static void cairo_font_options_substitute(FcPattern* pPattern); private: diff --git a/vcl/inc/unx/fontmanager.hxx b/vcl/inc/unx/fontmanager.hxx index e19b5f3fc9ae..d796aba7e944 100644 --- a/vcl/inc/unx/fontmanager.hxx +++ b/vcl/inc/unx/fontmanager.hxx @@ -131,6 +131,7 @@ class VCL_PLUGIN_PUBLIC PrintFontManager int m_nDirectory; // atom containing system dependent path OString m_aFontFile; // relative to directory int m_nCollectionEntry; // 0 for regular fonts, 0 to ... for fonts stemming from collections + int m_nVariationEntry; // 0 for regular fonts, 0 to ... for fonts stemming from font variations explicit PrintFont(); }; @@ -154,7 +155,7 @@ class VCL_PLUGIN_PUBLIC PrintFontManager bool analyzeSfntFile(PrintFont* pFont) const; // finds the font id for the nFaceIndex face in this font file // There may be multiple font ids for font collections - fontID findFontFileID( int nDirID, const OString& rFile, int nFaceIndex ) const; + fontID findFontFileID(int nDirID, const OString& rFile, int nFaceIndex, int nVariationIndex) const; // There may be multiple font ids for font collections std::vector findFontFileIDs( int nDirID, const OString& rFile ) const; @@ -242,6 +243,9 @@ public: // get the ttc face number int getFontFaceNumber( fontID nFontID ) const; + // get the ttc face variation + int getFontFaceVariation( fontID nFontID ) const; + // get a specific fonts ascend int getFontAscend( fontID nFontID ) const; diff --git a/vcl/inc/unx/freetype_glyphcache.hxx b/vcl/inc/unx/freetype_glyphcache.hxx index 774eec877957..3c09fe9b4157 100644 --- a/vcl/inc/unx/freetype_glyphcache.hxx +++ b/vcl/inc/unx/freetype_glyphcache.hxx @@ -55,10 +55,9 @@ private: class FreetypeFontInfo { public: - FreetypeFontInfo( const FontAttributes&, - const OString& rNativeFileName, - int nFaceNum, sal_IntPtr nFontId); - ~FreetypeFontInfo(); + FreetypeFontInfo(const FontAttributes&, const OString& rNativeFileName, + int nFaceNum, int nFaceVariation, sal_IntPtr nFontId); + ~FreetypeFontInfo(); const unsigned char* GetTable( const char*, sal_uLong* pLength) const; @@ -67,6 +66,7 @@ public: const OString& GetFontFileName() const { return mpFontFile->GetFileName(); } int GetFontFaceIndex() const { return mnFaceNum; } + int GetFontFaceVariation() const { return mnFaceVariation; } sal_IntPtr GetFontId() const { return mnFontId; } bool IsSymbolFont() const { return maDevFontAttributes.IsSymbolFont(); } const FontAttributes& GetFontAttributes() const { return maDevFontAttributes; } @@ -80,6 +80,7 @@ private: FT_FaceRec_* maFaceFT; FreetypeFontFile* const mpFontFile; const int mnFaceNum; + const int mnFaceVariation; int mnRefCount; sal_IntPtr const mnFontId; FontAttributes maDevFontAttributes; diff --git a/vcl/inc/unx/glyphcache.hxx b/vcl/inc/unx/glyphcache.hxx index 59811d6a144a..77a764e6e058 100644 --- a/vcl/inc/unx/glyphcache.hxx +++ b/vcl/inc/unx/glyphcache.hxx @@ -57,9 +57,9 @@ public: static GlyphCache& GetInstance(); - void AddFontFile( - const OString& rNormalizedName, - int nFaceNum, sal_IntPtr nFontId, + void AddFontFile(const OString& rNormalizedName, + int nFaceNum, int nVariantNum, + sal_IntPtr nFontId, const FontAttributes&); void AnnounceFonts( PhysicalFontCollection* ) const; @@ -98,6 +98,7 @@ public: const OString& GetFontFileName() const; int GetFontFaceIndex() const; + int GetFontFaceVariation() const; bool TestFont() const { return mbFaceOk;} FT_Face GetFtFace() const; int GetLoadFlags() const { return (mnLoadFlags & ~FT_LOAD_IGNORE_TRANSFORM); } @@ -117,6 +118,7 @@ public: FreetypeFontInstance* GetFontInstance() const { return mpFontInstance.get(); } + void SetFontVariationsOnHBFont(hb_font_t* pHbFace) const; private: friend class GlyphCache; friend class FreetypeFontInstance; diff --git a/vcl/unx/generic/fontmanager/fontconfig.cxx b/vcl/unx/generic/fontmanager/fontconfig.cxx index 76598746bec6..7205ef386668 100644 --- a/vcl/unx/generic/fontmanager/fontconfig.cxx +++ b/vcl/unx/generic/fontmanager/fontconfig.cxx @@ -467,6 +467,22 @@ static void lcl_FcFontSetRemove(FcFontSet* pFSet, int i) memmove(pFSet->fonts + i, pFSet->fonts + i + 1, nTail*sizeof(FcPattern*)); } +namespace +{ + // for variable fonts, FC_INDEX has been changed such that the lower half is now the + // index of the font within the collection, and the upper half has been repurposed + // as the index within the variations + unsigned int GetCollectionIndex(unsigned int nEntryId) + { + return nEntryId & 0xFFFF; + } + + unsigned int GetVariationIndex(unsigned int nEntryId) + { + return nEntryId >> 16; + } +} + void PrintFontManager::countFontconfigFonts( std::unordered_map& o_rVisitedPaths ) { int nFonts = 0; @@ -487,7 +503,7 @@ void PrintFontManager::countFontconfigFonts( std::unordered_map& o int weight = 0; int width = 0; int spacing = 0; - int nCollectionEntry = -1; + int nEntryId = -1; FcBool outline = false; FcResult eFileRes = FcPatternGetString(pFSet->fonts[i], FC_FILE, 0, &file); @@ -500,7 +516,7 @@ void PrintFontManager::countFontconfigFonts( std::unordered_map& o FcResult eWidthRes = FcPatternGetInteger(pFSet->fonts[i], FC_WIDTH, 0, &width); FcResult eSpacRes = FcPatternGetInteger(pFSet->fonts[i], FC_SPACING, 0, &spacing); FcResult eOutRes = FcPatternGetBool(pFSet->fonts[i], FC_OUTLINE, 0, &outline); - FcResult eIndexRes = FcPatternGetInteger(pFSet->fonts[i], FC_INDEX, 0, &nCollectionEntry); + FcResult eIndexRes = FcPatternGetInteger(pFSet->fonts[i], FC_INDEX, 0, &nEntryId); FcResult eFormatRes = FcPatternGetString(pFSet->fonts[i], FC_FONTFORMAT, 0, &format); if( eFileRes != FcResultMatch || eFamilyRes != FcResultMatch || eOutRes != FcResultMatch ) @@ -565,8 +581,9 @@ void PrintFontManager::countFontconfigFonts( std::unordered_map& o else // more than one font { // a collection entry, get the correct index - if( eIndexRes == FcResultMatch && nCollectionEntry != -1 ) + if( eIndexRes == FcResultMatch && nEntryId != -1 ) { + int nCollectionEntry = GetCollectionIndex(nEntryId); for (auto & font : aFonts) { if( font->m_nCollectionEntry == nCollectionEntry ) @@ -583,14 +600,14 @@ void PrintFontManager::countFontconfigFonts( std::unordered_map& o // additional entries will be created in the cache // if this is a new index (that is if the loop above // ran to the end of the list) - xUpdate->m_nCollectionEntry = nCollectionEntry; + xUpdate->m_nCollectionEntry = GetCollectionIndex(nEntryId); } else { SAL_INFO( "vcl.fonts", "multiple fonts for file, but no index in fontconfig pattern ! (index res =" - << eIndexRes << " collection entry = " << nCollectionEntry + << eIndexRes << " collection entry = " << nEntryId << "; file will not be used"); // we have found more than one font in this file // but fontconfig will not tell us which index is meant @@ -610,9 +627,9 @@ void PrintFontManager::countFontconfigFonts( std::unordered_map& o if( eSlantRes == FcResultMatch ) xUpdate->m_eItalic = convertSlant(slant); if( eStyleRes == FcResultMatch ) - { xUpdate->m_aStyleName = OStringToOUString( OString( reinterpret_cast(style) ), RTL_TEXTENCODING_UTF8 ); - } + if( eIndexRes == FcResultMatch ) + xUpdate->m_nVariationEntry = GetVariationIndex(nEntryId); // sort into known fonts fontID aFont = m_nNextFontID++; @@ -933,16 +950,16 @@ void PrintFontManager::Substitute(FontSelectPattern &rPattern, OUString& rMissin //extract the closest match FcChar8* file = nullptr; FcResult eFileRes = FcPatternGetString(pSet->fonts[0], FC_FILE, 0, &file); - int nCollectionEntry = 0; - FcResult eIndexRes = FcPatternGetInteger(pSet->fonts[0], FC_INDEX, 0, &nCollectionEntry); + int nEntryId = 0; + FcResult eIndexRes = FcPatternGetInteger(pSet->fonts[0], FC_INDEX, 0, &nEntryId); if (eIndexRes != FcResultMatch) - nCollectionEntry = 0; + nEntryId = 0; if( eFileRes == FcResultMatch ) { OString aDir, aBase, aOrgPath( reinterpret_cast(file) ); splitPath( aOrgPath, aDir, aBase ); int nDirID = getDirectoryAtom( aDir ); - fontID aFont = findFontFileID( nDirID, aBase, nCollectionEntry ); + fontID aFont = findFontFileID(nDirID, aBase, GetCollectionIndex(nEntryId), GetVariationIndex(nEntryId)); if( aFont > 0 ) { FastPrintFontInfo aInfo; @@ -1060,12 +1077,13 @@ FcPattern *FontConfigFontOptions::GetPattern() const return mpPattern; } -void FontConfigFontOptions::SyncPattern(const OString& rFileName, int nIndex, bool bEmbolden) +void FontConfigFontOptions::SyncPattern(const OString& rFileName, sal_uInt32 nIndex, sal_uInt32 nVariation, bool bEmbolden) { FcPatternDel(mpPattern, FC_FILE); FcPatternAddString(mpPattern, FC_FILE, reinterpret_cast(rFileName.getStr())); FcPatternDel(mpPattern, FC_INDEX); - FcPatternAddInteger(mpPattern, FC_INDEX, nIndex); + sal_uInt32 nFcIndex = (nVariation << 16) | nIndex; + FcPatternAddInteger(mpPattern, FC_INDEX, nFcIndex); FcPatternDel(mpPattern, FC_EMBOLDEN); FcPatternAddBool(mpPattern, FC_EMBOLDEN, bEmbolden ? FcTrue : FcFalse); } @@ -1145,16 +1163,18 @@ void PrintFontManager::matchFont( FastPrintFontInfo& rInfo, const css::lang::Loc //extract the closest match FcChar8* file = nullptr; FcResult eFileRes = FcPatternGetString(pSet->fonts[0], FC_FILE, 0, &file); - int nCollectionEntry = 0; - FcResult eIndexRes = FcPatternGetInteger(pSet->fonts[0], FC_INDEX, 0, &nCollectionEntry); + int nEntryId = 0; + FcResult eIndexRes = FcPatternGetInteger(pSet->fonts[0], FC_INDEX, 0, &nEntryId); if (eIndexRes != FcResultMatch) - nCollectionEntry = 0; + nEntryId = 0; if( eFileRes == FcResultMatch ) { OString aDir, aBase, aOrgPath( reinterpret_cast(file) ); splitPath( aOrgPath, aDir, aBase ); int nDirID = getDirectoryAtom( aDir ); - fontID aFont = findFontFileID( nDirID, aBase, nCollectionEntry ); + fontID aFont = findFontFileID(nDirID, aBase, + GetCollectionIndex(nEntryId), + GetVariationIndex(nEntryId)); if( aFont > 0 ) getFontFastInfo( aFont, rInfo ); } diff --git a/vcl/unx/generic/fontmanager/fontmanager.cxx b/vcl/unx/generic/fontmanager/fontmanager.cxx index 394c5484a5bd..16e8b786dc88 100644 --- a/vcl/unx/generic/fontmanager/fontmanager.cxx +++ b/vcl/unx/generic/fontmanager/fontmanager.cxx @@ -108,6 +108,7 @@ PrintFontManager::PrintFont::PrintFont() , m_nYMax(0) , m_nDirectory(0) , m_nCollectionEntry(0) +, m_nVariationEntry(0) { } @@ -278,7 +279,7 @@ std::vector> PrintFontManager::anal return aNewFonts; } -fontID PrintFontManager::findFontFileID( int nDirID, const OString& rFontFile, int nFaceIndex ) const +fontID PrintFontManager::findFontFileID(int nDirID, const OString& rFontFile, int nFaceIndex, int nVariationIndex) const { fontID nID = 0; @@ -293,7 +294,9 @@ fontID PrintFontManager::findFontFileID( int nDirID, const OString& rFontFile, i continue; PrintFont* const pFont = (*it).second.get(); if (pFont->m_nDirectory == nDirID && - pFont->m_aFontFile == rFontFile && pFont->m_nCollectionEntry == nFaceIndex) + pFont->m_aFontFile == rFontFile && + pFont->m_nCollectionEntry == nFaceIndex && + pFont->m_nVariationEntry == nVariationIndex) { nID = it->first; if (nID) @@ -838,6 +841,19 @@ int PrintFontManager::getFontFaceNumber( fontID nFontID ) const return nRet; } +int PrintFontManager::getFontFaceVariation( fontID nFontID ) const +{ + int nRet = 0; + PrintFont* pFont = getFont( nFontID ); + if (pFont) + { + nRet = pFont->m_nVariationEntry; + if (nRet < 0) + nRet = 0; + } + return nRet; +} + FontFamily PrintFontManager::matchFamilyName( const OUString& rFamily ) { typedef struct { diff --git a/vcl/unx/generic/gdi/cairotextrender.cxx b/vcl/unx/generic/gdi/cairotextrender.cxx index c8956d02226b..f9e6a0a522a1 100644 --- a/vcl/unx/generic/gdi/cairotextrender.cxx +++ b/vcl/unx/generic/gdi/cairotextrender.cxx @@ -408,12 +408,13 @@ void CairoTextRender::GetDevFontList( PhysicalFontCollection* pFontCollection ) // normalize face number to the GlyphCache int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID ); + int nVariantNum = rMgr.getFontFaceVariation( aInfo.m_nID ); // inform GlyphCache about this font provided by the PsPrint subsystem FontAttributes aDFA = GenPspGraphics::Info2FontAttributes( aInfo ); aDFA.IncreaseQualityBy( 4096 ); const OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID ); - rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA ); + rGC.AddFontFile( rFileName, nFaceNum, nVariantNum, aInfo.m_nID, aDFA ); } // announce glyphcache fonts diff --git a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx index 42bf6d0a98b9..1fcb0938ef77 100644 --- a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx +++ b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx @@ -47,6 +47,7 @@ #include #include FT_FREETYPE_H #include FT_GLYPH_H +#include FT_MULTIPLE_MASTERS_H #include FT_OUTLINE_H #include FT_SIZES_H #include FT_SYNTHESIS_H @@ -166,11 +167,12 @@ void FreetypeFontFile::Unmap() } FreetypeFontInfo::FreetypeFontInfo( const FontAttributes& rDevFontAttributes, - const OString& rNativeFileName, int nFaceNum, sal_IntPtr nFontId) + const OString& rNativeFileName, int nFaceNum, int nFaceVariation, sal_IntPtr nFontId) : maFaceFT( nullptr ), mpFontFile( FreetypeFontFile::FindFontFile( rNativeFileName ) ), mnFaceNum( nFaceNum ), + mnFaceVariation( nFaceVariation ), mnRefCount( 0 ), mnFontId( nFontId ), maDevFontAttributes( rDevFontAttributes ) @@ -194,12 +196,50 @@ FT_FaceRec_* FreetypeFontInfo::GetFaceFT() mpFontFile->GetFileSize(), mnFaceNum, &maFaceFT ); if( (rc != FT_Err_Ok) || (maFaceFT->num_glyphs <= 0) ) maFaceFT = nullptr; + + if (maFaceFT && mnFaceVariation) + { + FT_MM_Var *pFtMMVar; + if (FT_Get_MM_Var(maFaceFT, &pFtMMVar) == 0) + { + if (static_cast(mnFaceVariation) <= pFtMMVar->num_namedstyles) + { + FT_Var_Named_Style *instance = &pFtMMVar->namedstyle[mnFaceVariation - 1]; + FT_Set_Var_Design_Coordinates(maFaceFT, pFtMMVar->num_axis, instance->coords); + } + FT_Done_MM_Var(aLibFT, pFtMMVar); + } + } } ++mnRefCount; return maFaceFT; } +void FreetypeFont::SetFontVariationsOnHBFont(hb_font_t* pHbFace) const +{ + sal_uInt32 nFaceVariation = mpFontInfo->GetFontFaceVariation(); + if (maFaceFT && nFaceVariation) + { + FT_MM_Var *pFtMMVar; + if (FT_Get_MM_Var(maFaceFT, &pFtMMVar) == 0) + { + if (nFaceVariation <= pFtMMVar->num_namedstyles) + { + FT_Var_Named_Style *instance = &pFtMMVar->namedstyle[nFaceVariation - 1]; + std::vector aVariations(pFtMMVar->num_axis); + for (FT_UInt i = 0; i < pFtMMVar->num_axis; ++i) + { + aVariations[i].tag = pFtMMVar->axis[i].tag; + aVariations[i].value = instance->coords[i] / 65536.0; + } + hb_font_set_variations(pHbFace, aVariations.data(), aVariations.size()); + } + FT_Done_MM_Var(aLibFT, pFtMMVar); + } + } +} + void FreetypeFontInfo::ReleaseFaceFT() { if (--mnRefCount <= 0) @@ -289,8 +329,8 @@ FT_Face FreetypeFont::GetFtFace() const return maFaceFT; } -void GlyphCache::AddFontFile( const OString& rNormalizedName, - int nFaceNum, sal_IntPtr nFontId, const FontAttributes& rDevFontAttr) +void GlyphCache::AddFontFile(const OString& rNormalizedName, + int nFaceNum, int nVariantNum, sal_IntPtr nFontId, const FontAttributes& rDevFontAttr) { if( rNormalizedName.isEmpty() ) return; @@ -299,7 +339,7 @@ void GlyphCache::AddFontFile( const OString& rNormalizedName, return; FreetypeFontInfo* pFontInfo = new FreetypeFontInfo( rDevFontAttr, - rNormalizedName, nFaceNum, nFontId); + rNormalizedName, nFaceNum, nVariantNum, nFontId); m_aFontInfoList[ nFontId ].reset(pFontInfo); if( m_nMaxFontId < nFontId ) m_nMaxFontId = nFontId; @@ -441,7 +481,7 @@ const FontConfigFontOptions* FreetypeFont::GetFontOptions() const if (!mxFontOptions) { mxFontOptions.reset(GetFCFontOptions(mpFontInfo->GetFontAttributes(), mpFontInstance->GetFontSelectPattern().mnHeight)); - mxFontOptions->SyncPattern(GetFontFileName(), GetFontFaceIndex(), NeedsArtificialBold()); + mxFontOptions->SyncPattern(GetFontFileName(), GetFontFaceIndex(), GetFontFaceVariation(), NeedsArtificialBold()); } return mxFontOptions.get(); } @@ -461,6 +501,11 @@ int FreetypeFont::GetFontFaceIndex() const return mpFontInfo->GetFontFaceIndex(); } +int FreetypeFont::GetFontFaceVariation() const +{ + return mpFontInfo->GetFontFaceVariation(); +} + FreetypeFont::~FreetypeFont() { if( maSizeFT ) diff --git a/vcl/unx/generic/glyphs/glyphcache.cxx b/vcl/unx/generic/glyphs/glyphcache.cxx index b541fe1861fe..d4a32f30a521 100644 --- a/vcl/unx/generic/glyphs/glyphcache.cxx +++ b/vcl/unx/generic/glyphs/glyphcache.cxx @@ -298,7 +298,10 @@ static hb_blob_t* getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pU hb_font_t* FreetypeFontInstance::ImplInitHbFont() { - return InitHbFont(hb_face_create_for_tables(getFontTable, this, nullptr)); + hb_font_t* pRet = InitHbFont(hb_face_create_for_tables(getFontTable, this, nullptr)); + assert(mpFreetypeFont); + mpFreetypeFont->SetFontVariationsOnHBFont(pRet); + return pRet; } bool FreetypeFontInstance::ImplGetGlyphBoundRect(sal_GlyphId nId, tools::Rectangle& rRect, bool bVertical) const diff --git a/vcl/unx/generic/print/genpspgraphics.cxx b/vcl/unx/generic/print/genpspgraphics.cxx index e40b9fd5cc82..c5675bfa3bcd 100644 --- a/vcl/unx/generic/print/genpspgraphics.cxx +++ b/vcl/unx/generic/print/genpspgraphics.cxx @@ -694,9 +694,10 @@ bool GenPspGraphics::AddTempDevFontHelper( PhysicalFontCollection* pFontCollecti aDFA.IncreaseQualityBy( 5800 ); int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID ); + int nVariantNum = rMgr.getFontFaceVariation( aInfo.m_nID ); const OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID ); - rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA ); + rGC.AddFontFile( rFileName, nFaceNum, nVariantNum, aInfo.m_nID, aDFA ); } // announce new font to device's font list -- 2.21.0