diff options
author | Jan-Marek Glogowski <glogow@fbihome.de> | 2017-12-26 15:14:31 +0000 |
---|---|---|
committer | Khaled Hosny <khaledhosny@eglug.org> | 2018-05-08 00:55:27 +0200 |
commit | bdccb7e9991d83029eb2f2f11327b54534a00db8 (patch) | |
tree | c32e95c49849647dc72c1071f375f3d2b67d8d7a | |
parent | 9615e45d2e2bac79c252a018846e4f20012cfa34 (diff) |
Refactor CommonSalLayout font handling
Moves all platform specific code from CommonSalLayout into the
platform specific plugins. This way the vcl library won't depend
on the Qt5 libraries and the Qt5Font header can be moved into the
qt5 VCL plugin.
While at it, switch the CommonSalLayouts font reference from the
FontSelectPattern to the LogicalFontInstance and also add the
harfbuzz font handling to the instance.
Change-Id: Ida910b8d88837ea949a2f84394ccc0cfae153060
Reviewed-on: https://gerrit.libreoffice.org/47408
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Khaled Hosny <khaledhosny@eglug.org>
34 files changed, 377 insertions, 450 deletions
diff --git a/bin/check-elf-dynamic-objects b/bin/check-elf-dynamic-objects index 5c484598b3b6..ea2d67e31ff4 100755 --- a/bin/check-elf-dynamic-objects +++ b/bin/check-elf-dynamic-objects @@ -133,10 +133,6 @@ local file="$1" ;; */libvcllo.so) whitelist="${whitelist} ${x11whitelist} ${openglwhitelist} ${giowhitelist} libcups.so.2" - if [ "$ENABLE_QT5" = TRUE ]; then - #TODO: is inclusion of vcl/qt5/Qt5Font.cxx in Library_vcl really wanted? - whitelist="${whitelist} ${qt5whitelist}" - fi ;; */libsofficeapp.so) whitelist="${whitelist} ${x11whitelist} ${openglwhitelist} ${giowhitelist} libcups.so.2" diff --git a/vcl/CppunitTest_vcl_fontmetric.mk b/vcl/CppunitTest_vcl_fontmetric.mk index 776064817ea1..70e2386e5f50 100644 --- a/vcl/CppunitTest_vcl_fontmetric.mk +++ b/vcl/CppunitTest_vcl_fontmetric.mk @@ -46,4 +46,8 @@ $(eval $(call gb_CppunitTest_use_components,vcl_fontmetric,\ $(eval $(call gb_CppunitTest_use_configuration,vcl_fontmetric)) +$(eval $(call gb_CppunitTest_use_externals,vcl_fontmetric,\ + harfbuzz \ +)) + # vim: set noet sw=4 ts=4: diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index b69fbfdd96f9..3da03f8acfbb 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -780,22 +780,4 @@ ifeq ($(OS),WNT) $(eval $(call gb_Library_use_package,vcl,postprocess_images)) endif -ifeq ($(ENABLE_QT5),TRUE) -$(eval $(call gb_Library_use_externals,vcl,\ - qt5 \ -)) -$(eval $(call gb_Library_add_defs,vcl,\ - $(QT5_CFLAGS) \ -)) -$(eval $(call gb_Library_add_libs,vcl,\ - $(QT5_LIBS) \ -)) -$(eval $(call gb_Library_add_cxxflags,vcl,\ - $(QT5_CFLAGS) \ -)) -$(eval $(call gb_Library_add_exception_objects,vcl,\ - vcl/qt5/Qt5Font \ -)) -endif - # vim: set noet sw=4 ts=4: diff --git a/vcl/Library_vclplug_kde4.mk b/vcl/Library_vclplug_kde4.mk index acd7bd5981da..88dfd50f41f7 100644 --- a/vcl/Library_vclplug_kde4.mk +++ b/vcl/Library_vclplug_kde4.mk @@ -52,6 +52,7 @@ $(eval $(call gb_Library_use_libraries,vclplug_kde4,\ $(eval $(call gb_Library_use_externals,vclplug_kde4,\ boost_headers \ + harfbuzz \ icuuc \ kde4 \ epoxy \ diff --git a/vcl/Library_vclplug_qt5.mk b/vcl/Library_vclplug_qt5.mk index 2a12414401dc..5245d8a0149b 100644 --- a/vcl/Library_vclplug_qt5.mk +++ b/vcl/Library_vclplug_qt5.mk @@ -80,8 +80,9 @@ endif $(eval $(call gb_Library_add_exception_objects,vclplug_qt5,\ vcl/qt5/Qt5Bitmap \ vcl/qt5/Qt5Data \ - vcl/qt5/Qt5Frame \ + vcl/qt5/Qt5Font \ vcl/qt5/Qt5FontFace \ + vcl/qt5/Qt5Frame \ vcl/qt5/Qt5Graphics \ vcl/qt5/Qt5Graphics_Controls \ vcl/qt5/Qt5Graphics_GDI \ diff --git a/vcl/inc/CommonSalLayout.hxx b/vcl/inc/CommonSalLayout.hxx index 6ad2627b129b..ae5804d5df95 100644 --- a/vcl/inc/CommonSalLayout.hxx +++ b/vcl/inc/CommonSalLayout.hxx @@ -20,85 +20,32 @@ #ifndef INCLUDED_VCL_INC_COMMONSALLAYOUT_HXX #define INCLUDED_VCL_INC_COMMONSALLAYOUT_HXX -#include <config_qt5.h> - #include <com/sun/star/i18n/XBreakIterator.hpp> -#ifdef _WIN32 -#include "win/winlayout.hxx" - -#elif defined(MACOSX) || defined(IOS) -#include "quartz/ctfonts.hxx" -#include <hb-coretext.h> - -#else -#include "unx/freetype_glyphcache.hxx" -#endif - #include "sallayout.hxx" -#include <hb-icu.h> -#include <hb-ot.h> +#include "fontinstance.hxx" -#if ENABLE_QT5 -class Qt5Font; -#endif +#include <hb-icu.h> class VCL_DLLPUBLIC CommonSalLayout : public GenericSalLayout { - hb_font_t* mpHbFont; - const FontSelectPattern& mrFontSelData; + LogicalFontInstance* const mpFont; css::uno::Reference<css::i18n::XBreakIterator> mxBreak; -#ifdef _WIN32 - HDC mhDC; - HFONT mhFont; - WinFontInstance& mrWinFontInstance; - double mnAveWidthFactor; -#elif defined(MACOSX) || defined(IOS) - const CoreTextStyle& mrCoreTextStyle; -#else - FreetypeFont* mpFreetypeFont; -#if ENABLE_QT5 - const bool mbUseQt5; - Qt5Font* mpQFont; - - explicit CommonSalLayout(const FontSelectPattern &rFSP, - FreetypeFont *pFreetypeFont, - Qt5Font *pFont, bool bUseQt5); -#endif - void InitFromFreetypeFont(); -#endif void ParseFeatures(const OUString& name); OString msLanguage; std::vector<hb_feature_t> maFeatures; - void getScale(double* nXScale, double* nYScale); - hb_set_t* mpVertGlyphs; - bool mbFuzzing; + const bool mbFuzzing; bool HasVerticalAlternate(sal_UCS4 aChar, sal_UCS4 aNextChar); void SetNeedFallback(ImplLayoutArgs&, sal_Int32, bool); public: -#if defined(_WIN32) - explicit CommonSalLayout(HDC, WinFontInstance&); - const FontSelectPattern& getFontSelData() const { return mrFontSelData; } - HFONT getHFONT() const { return mhFont; } - WinFontInstance& getWinFontInstance() const { return mrWinFontInstance; } - bool hasHScale() const; -#elif defined(MACOSX) || defined(IOS) - explicit CommonSalLayout(const CoreTextStyle&); - const CoreTextStyle& getFontData() const { return mrCoreTextStyle; } -#else - explicit CommonSalLayout(FreetypeFont&); - const FreetypeFont* getFreetypeFont() const { return mpFreetypeFont; } -#if ENABLE_QT5 - explicit CommonSalLayout(Qt5Font&); - const Qt5Font* getQt5Font() const { return mpQFont; } - bool useQt5() const { return mbUseQt5; } -#endif -#endif + CommonSalLayout(LogicalFontInstance&); + ~CommonSalLayout() override; + LogicalFontInstance& getFont() const { return *mpFont; } virtual void InitFont() const override; void AdjustLayout(ImplLayoutArgs&) final override; @@ -113,4 +60,5 @@ public: }; #endif // INCLUDED_VCL_INC_COMMONSALLAYOUT_HXX + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/fontinstance.hxx b/vcl/inc/fontinstance.hxx index c37ada563fb0..8bd6584c6154 100644 --- a/vcl/inc/fontinstance.hxx +++ b/vcl/inc/fontinstance.hxx @@ -26,6 +26,8 @@ #include <unordered_map> #include <memory> +#include <hb-ot.h> + class ConvertChar; class ImplFontCache; class PhysicalFontFace; @@ -57,13 +59,25 @@ public: // TODO: make data members private void Acquire(); void Release(); + inline hb_font_t* GetHbFont(); + void SetAverageWidthFactor(double nFactor) { m_nAveWidthFactor = nFactor; } + double GetAverageWidthFactor() const { return m_nAveWidthFactor; } const FontSelectPattern& GetFontSelectPattern() const { return m_aFontSelData; } + const PhysicalFontFace* GetFontFace() const { return m_pFontFace; } const ImplFontCache* GetFontCache() const { return mpFontCache; } + void GetScale(double* nXScale, double* nYScale); + static inline void DecodeOpenTypeTag(const uint32_t nTableTag, char* pTagName); + protected: explicit LogicalFontInstance(const PhysicalFontFace&, const FontSelectPattern&); + // Takes ownership of pHbFace. + hb_font_t* InitHbFont(hb_face_t* pHbFace) const; + virtual hb_font_t* ImplInitHbFont() { assert(false); return nullptr; } + inline void ReleaseHbFont(); + private: // cache of Unicode characters and replacement font names // TODO: a fallback map can be shared with many other ImplFontEntries @@ -73,9 +87,35 @@ private: ImplFontCache * mpFontCache; sal_uInt32 mnRefCount; const FontSelectPattern m_aFontSelData; + hb_font_t* m_pHbFont; + double m_nAveWidthFactor; const PhysicalFontFace* m_pFontFace; }; +inline hb_font_t* LogicalFontInstance::GetHbFont() +{ + if (!m_pHbFont) + m_pHbFont = ImplInitHbFont(); + return m_pHbFont; +} + +inline void LogicalFontInstance::ReleaseHbFont() +{ + if (!m_pHbFont) + return; + hb_font_destroy(m_pHbFont); + m_pHbFont = nullptr; +} + +inline void LogicalFontInstance::DecodeOpenTypeTag(const uint32_t nTableTag, char* pTagName) +{ + pTagName[0] = static_cast<char>(nTableTag >> 24); + pTagName[1] = static_cast<char>(nTableTag >> 16); + pTagName[2] = static_cast<char>(nTableTag >> 8); + pTagName[3] = static_cast<char>(nTableTag); + pTagName[4] = 0; +} + #endif // INCLUDED_VCL_INC_FONTINSTANCE_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h index 4d7fa35a0981..dbbbdee612e8 100644 --- a/vcl/inc/quartz/salgdi.h +++ b/vcl/inc/quartz/salgdi.h @@ -47,6 +47,8 @@ #include <unordered_map> #include <hb-ot.h> +#include "fontinstance.hxx" + class AquaSalFrame; class FontAttributes; class CoreTextStyle; @@ -63,6 +65,7 @@ public: PhysicalFontFace* Clone() const override; sal_IntPtr GetFontId() const override; + int GetFontTable( uint32_t nTagCode, unsigned char* ) const; int GetFontTable( const char pTagName[5], unsigned char* ) const; const FontCharMapRef GetFontCharMap() const; @@ -91,8 +94,6 @@ public: void GetFontMetric( ImplFontMetricDataRef const & ) const; bool GetGlyphBoundRect(const GlyphItem&, tools::Rectangle&) const; bool GetGlyphOutline(const GlyphItem&, basegfx::B2DPolyPolygon&) const; - hb_font_t* GetHbFont() const { return mpHbFont; } - void SetHbFont(hb_font_t* pHbFont) const { mpHbFont = pHbFont; } CFMutableDictionaryRef GetStyleDict( void ) const { return mpStyleDict; } @@ -104,9 +105,10 @@ public: private: explicit CoreTextStyle(const PhysicalFontFace&, const FontSelectPattern&); + virtual hb_font_t* ImplInitHbFont() override; + /// CoreText text style object CFMutableDictionaryRef mpStyleDict; - mutable hb_font_t* mpHbFont; }; // TODO: move into cross-platform headers diff --git a/vcl/inc/salwtype.hxx b/vcl/inc/salwtype.hxx index 1800b976aeb9..a7384090a20f 100644 --- a/vcl/inc/salwtype.hxx +++ b/vcl/inc/salwtype.hxx @@ -24,11 +24,11 @@ #include <rtl/ustring.hxx> #include <tools/solar.h> +class LogicalFontInstance; class SalGraphics; class SalFrame; class SalObject; namespace vcl { class Window; } -class FontSelectPattern; enum class InputContextFlags; enum class WindowStateMask; enum class WindowStateState; @@ -239,7 +239,7 @@ struct SalFrameState struct SalInputContext { - const FontSelectPattern* mpFont; + LogicalFontInstance* mpFont; LanguageType meLanguage; InputContextFlags mnOptions; }; diff --git a/vcl/inc/svdata.hxx b/vcl/inc/svdata.hxx index 42300a1e56e2..09cd76695b62 100644 --- a/vcl/inc/svdata.hxx +++ b/vcl/inc/svdata.hxx @@ -31,7 +31,6 @@ #include <com/sun/star/i18n/XCharacterClassification.hpp> #include "vcleventlisteners.hxx" -#include "impfontcache.hxx" #include "salwtype.hxx" #include "displayconnectiondispatch.hxx" diff --git a/vcl/inc/unx/freetype_glyphcache.hxx b/vcl/inc/unx/freetype_glyphcache.hxx index fc1852db4f7c..0a7b88887b24 100644 --- a/vcl/inc/unx/freetype_glyphcache.hxx +++ b/vcl/inc/unx/freetype_glyphcache.hxx @@ -126,6 +126,8 @@ class VCL_DLLPUBLIC FreetypeFontInstance : public LogicalFontInstance FreetypeFont* mpFreetypeFont; + virtual hb_font_t* ImplInitHbFont() override; + protected: explicit FreetypeFontInstance(const PhysicalFontFace& rPFF, const FontSelectPattern& rFSP); diff --git a/vcl/inc/unx/glyphcache.hxx b/vcl/inc/unx/glyphcache.hxx index ba56ecf48b75..7d507f100fe0 100644 --- a/vcl/inc/unx/glyphcache.hxx +++ b/vcl/inc/unx/glyphcache.hxx @@ -118,7 +118,7 @@ class VCL_DLLPUBLIC FreetypeFont final { public: FreetypeFont( const FontSelectPattern&, FreetypeFontInfo* ); - ~FreetypeFont(); + virtual ~FreetypeFont(); const OString& GetFontFileName() const; int GetFontFaceIndex() const; @@ -130,8 +130,6 @@ public: bool NeedsArtificialBold() const { return mbArtBold; } bool NeedsArtificialItalic() const { return mbArtItalic; } - const FontSelectPattern& GetFontSelData() const { return maFontSelData; } - void GetFontMetric(ImplFontMetricDataRef const &) const; const unsigned char* GetTable( const char* pName, sal_uLong* pLength ) const; const FontCharMapRef GetFontCharMap() const; @@ -140,8 +138,8 @@ public: const tools::Rectangle& GetGlyphBoundRect(const GlyphItem& rGlyph); bool GetGlyphOutline(const GlyphItem& rGlyph, basegfx::B2DPolyPolygon&) const; bool GetAntialiasAdvice() const; - hb_font_t* GetHbFont() { return mpHbFont; } - void SetHbFont( hb_font_t* pHbFont ) { mpHbFont = pHbFont; } + + LogicalFontInstance* GetFontInstance() const { return mpFontInstance; } private: friend class GlyphCache; @@ -163,7 +161,7 @@ private: typedef std::unordered_map<int,GlyphData> GlyphList; mutable GlyphList maGlyphList; - const FontSelectPattern maFontSelData; + LogicalFontInstance* const mpFontInstance; // used by GlyphCache for cache LRU algorithm mutable long mnRefCount; @@ -190,8 +188,6 @@ private: bool mbFaceOk; bool mbArtItalic; bool mbArtBold; - - hb_font_t* mpHbFont; }; #endif // INCLUDED_VCL_INC_GENERIC_GLYPHCACHE_HXX diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h index cc30963d21c2..85b88e8e5f10 100644 --- a/vcl/inc/win/salgdi.h +++ b/vcl/inc/win/salgdi.h @@ -90,14 +90,9 @@ private: BYTE mnPitchAndFamily; bool mbAliasSymbolsHigh; bool mbAliasSymbolsLow; -private: + void ReadCmapTable( HDC ) const; void GetFontCapabilities( HDC hDC ) const; - - mutable hb_font_t* mpHbFont; -public: - hb_font_t* GetHbFont() const { return mpHbFont; } - void SetHbFont( hb_font_t* pHbFont ) const { mpHbFont = pHbFont; } }; /** Class that creates (and destroys) a compatible Device Context. diff --git a/vcl/inc/win/winlayout.hxx b/vcl/inc/win/winlayout.hxx index 600817d8e2b8..ca0945949265 100644 --- a/vcl/inc/win/winlayout.hxx +++ b/vcl/inc/win/winlayout.hxx @@ -25,6 +25,7 @@ #include <sallayout.hxx> #include <svsys.h> #include <win/salgdi.h> +#include <CommonSalLayout.hxx> #include <opengl/PackedTextureAtlas.hxx> @@ -150,14 +151,20 @@ class WinFontInstance : public LogicalFontInstance public: virtual ~WinFontInstance() override; -public: bool CacheGlyphToAtlas(HDC hDC, HFONT hFont, int nGlyphIndex, SalGraphics& rGraphics); GlyphCache& GetGlyphCache() { return maGlyphCache; } + bool hasHScale() const; + + void SetHDC(const HDC); + HFONT GetHFONT() const { return m_hFont; } private: explicit WinFontInstance(const PhysicalFontFace&, const FontSelectPattern&); - // TODO: also add HFONT??? Watch out for issues with too many active fonts... + virtual hb_font_t* ImplInitHbFont() override; + + HDC m_hDC; + HFONT m_hFont; GlyphCache maGlyphCache; }; diff --git a/vcl/qt5/Qt5Font.cxx b/vcl/qt5/Qt5Font.cxx index 01a45d359600..0164c3b13cd4 100644 --- a/vcl/qt5/Qt5Font.cxx +++ b/vcl/qt5/Qt5Font.cxx @@ -17,8 +17,37 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#include <qt5/Qt5Font.hxx> +#include "Qt5Font.hxx" + +#include <QtGui/QFont> +#include <QtGui/QRawFont> + +Qt5Font::Qt5Font(const PhysicalFontFace& rPFF, const FontSelectPattern& rFSP) + : LogicalFontInstance(rPFF, rFSP) +{ +} Qt5Font::~Qt5Font() {} +static hb_blob_t* getFontTable(hb_face_t*, hb_tag_t nTableTag, void* pUserData) +{ + char pTagName[5]; + LogicalFontInstance::DecodeOpenTypeTag(nTableTag, pTagName); + + Qt5Font* pFont = static_cast<Qt5Font*>(pUserData); + QRawFont aRawFont(QRawFont::fromFont(*pFont)); + QByteArray aTable = aRawFont.fontTable(pTagName); + const sal_uInt32 nLength = aTable.size(); + + hb_blob_t* pBlob = nullptr; + if (nLength > 0) + pBlob = hb_blob_create(aTable.data(), nLength, HB_MEMORY_MODE_DUPLICATE, nullptr, nullptr); + return pBlob; +} + +hb_font_t* Qt5Font::ImplInitHbFont() +{ + return InitHbFont(hb_face_create_for_tables(getFontTable, this, nullptr)); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Font.hxx b/vcl/qt5/Qt5Font.hxx index 1a1940fa7df0..fd496348c9b6 100644 --- a/vcl/inc/qt5/Qt5Font.hxx +++ b/vcl/qt5/Qt5Font.hxx @@ -19,26 +19,22 @@ #pragma once -#include <vcl/dllapi.h> +#include <fontinstance.hxx> + #include <QtGui/QFont> -#include <fontinstance.hxx> -#include <hb-ot.h> +#include "Qt5FontFace.hxx" -class VCL_DLLPUBLIC Qt5Font : public QFont, public LogicalFontInstance +class Qt5Font final : public QFont, public LogicalFontInstance { - hb_font_t* m_pHbFont; + friend LogicalFontInstance* Qt5FontFace::CreateFontInstance(const FontSelectPattern&) const; + + virtual hb_font_t* ImplInitHbFont() override; + + explicit Qt5Font(const PhysicalFontFace&, const FontSelectPattern&); public: - Qt5Font(const PhysicalFontFace& rPFF, const FontSelectPattern& rFSP) - : LogicalFontInstance(rPFF, rFSP) - , m_pHbFont(nullptr) - { - } virtual ~Qt5Font() override; - - hb_font_t* GetHbFont() const { return m_pHbFont; } - void SetHbFont(hb_font_t* pHbFont) { m_pHbFont = pHbFont; } }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5FontFace.cxx b/vcl/qt5/Qt5FontFace.cxx index dd80292922aa..0cd071385aaa 100644 --- a/vcl/qt5/Qt5FontFace.cxx +++ b/vcl/qt5/Qt5FontFace.cxx @@ -18,7 +18,7 @@ */ #include "Qt5FontFace.hxx" -#include <qt5/Qt5Font.hxx> +#include "Qt5Font.hxx" #include "Qt5Tools.hxx" #include <sft.hxx> diff --git a/vcl/qt5/Qt5Graphics.cxx b/vcl/qt5/Qt5Graphics.cxx index cf39b916ab42..8bf37adddff8 100644 --- a/vcl/qt5/Qt5Graphics.cxx +++ b/vcl/qt5/Qt5Graphics.cxx @@ -19,7 +19,7 @@ #include "Qt5Graphics.hxx" -#include <qt5/Qt5Font.hxx> +#include "Qt5Font.hxx" #include "Qt5Frame.hxx" #include "Qt5Painter.hxx" @@ -34,7 +34,6 @@ Qt5Graphics::Qt5Graphics( Qt5Frame *pFrame, QImage *pQImage ) , m_aFillColor( 0xFF, 0xFF, 0XFF ) , m_eCompositionMode( QPainter::CompositionMode_SourceOver ) , m_pFontCollection( nullptr ) - , m_pFontData{ nullptr, } , m_pTextStyle{ nullptr, } , m_aTextColor( 0x00, 0x00, 0x00 ) { diff --git a/vcl/qt5/Qt5Graphics.hxx b/vcl/qt5/Qt5Graphics.hxx index 9feff684ec93..8b37232f7e5c 100644 --- a/vcl/qt5/Qt5Graphics.hxx +++ b/vcl/qt5/Qt5Graphics.hxx @@ -48,7 +48,6 @@ class Qt5Graphics : public SalGraphics QPainter::CompositionMode m_eCompositionMode; PhysicalFontCollection* m_pFontCollection; - const Qt5FontFace* m_pFontData[MAX_FALLBACK]; Qt5Font* m_pTextStyle[MAX_FALLBACK]; Color m_aTextColor; diff --git a/vcl/qt5/Qt5Graphics_Text.cxx b/vcl/qt5/Qt5Graphics_Text.cxx index 4314e6333fe3..ed3d849aa3f4 100644 --- a/vcl/qt5/Qt5Graphics_Text.cxx +++ b/vcl/qt5/Qt5Graphics_Text.cxx @@ -19,7 +19,7 @@ #include "Qt5Graphics.hxx" #include "Qt5FontFace.hxx" -#include <qt5/Qt5Font.hxx> +#include "Qt5Font.hxx" #include <vcl/fontcharmap.hxx> @@ -78,16 +78,17 @@ void Qt5Graphics::GetFontMetric(ImplFontMetricDataRef& rFMD, int nFallbackLevel) const FontCharMapRef Qt5Graphics::GetFontCharMap() const { - if (!m_pFontData[0]) + if (!m_pTextStyle[0]) return FontCharMapRef(new FontCharMap()); - return m_pFontData[0]->GetFontCharMap(); + return static_cast<const Qt5FontFace*>(m_pTextStyle[0]->GetFontFace())->GetFontCharMap(); } bool Qt5Graphics::GetFontCapabilities(vcl::FontCapabilities& rFontCapabilities) const { - if (!m_pFontData[0]) + if (!m_pTextStyle[0]) return false; - return m_pFontData[0]->GetFontCapabilities(rFontCapabilities); + return static_cast<const Qt5FontFace*>(m_pTextStyle[0]->GetFontFace()) + ->GetFontCapabilities(rFontCapabilities); } void Qt5Graphics::GetDevFontList(PhysicalFontCollection* pPFC) diff --git a/vcl/quartz/ctfonts.cxx b/vcl/quartz/ctfonts.cxx index b35d121a314c..be615a1ee377 100644 --- a/vcl/quartz/ctfonts.cxx +++ b/vcl/quartz/ctfonts.cxx @@ -49,7 +49,6 @@ CoreTextStyle::CoreTextStyle(const PhysicalFontFace& rPFF, const FontSelectPatte , mfFontStretch( 1.0 ) , mfFontRotation( 0.0 ) , mpStyleDict( nullptr ) - , mpHbFont( nullptr ) { double fScaledFontHeight = rFSP.mfExactHeight; @@ -103,8 +102,6 @@ CoreTextStyle::~CoreTextStyle() { if( mpStyleDict ) CFRelease( mpStyleDict ); - if( mpHbFont ) - hb_font_destroy( mpHbFont ); } void CoreTextStyle::GetFontMetric( ImplFontMetricDataRef const & rxFontMetric ) const @@ -261,6 +258,42 @@ bool CoreTextStyle::GetGlyphOutline(const GlyphItem& rGlyph, basegfx::B2DPolyPol return true; } +static hb_blob_t* getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pUserData) +{ + sal_uLong nLength = 0; + unsigned char* pBuffer = nullptr; + CoreTextFontFace* pFont = static_cast<CoreTextFontFace*>(pUserData); + nLength = pFont->GetFontTable(nTableTag, nullptr); + if (nLength > 0) + { + pBuffer = new unsigned char[nLength]; + pFont->GetFontTable(nTableTag, pBuffer); + } + + hb_blob_t* pBlob = nullptr; + if (pBuffer != nullptr) + pBlob = hb_blob_create(reinterpret_cast<const char*>(pBuffer), nLength, HB_MEMORY_MODE_READONLY, + pBuffer, [](void* data){ delete[] static_cast<unsigned char*>(data); }); + return pBlob; +} + +hb_font_t* CoreTextStyle::ImplInitHbFont() +{ + // On macOS we use HarfBuzz for AAT shaping, but HarfBuzz will then + // need a CGFont (as it offloads the actual AAT shaping to Core Text), + // if we have one we use it to create the hb_face_t. + hb_face_t* pHbFace; + CTFontRef pCTFont = static_cast<CTFontRef>(CFDictionaryGetValue(GetStyleDict(), kCTFontAttributeName)); + CGFontRef pCGFont = CTFontCopyGraphicsFont(pCTFont, nullptr); + if (pCGFont) + pHbFace = hb_coretext_face_create(pCGFont); + else + pHbFace = hb_face_create_for_tables(getFontTable, const_cast<PhysicalFontFace*>(GetFontFace()), nullptr); + CGFontRelease(pCGFont); + + return InitHbFont(pHbFace); +} + PhysicalFontFace* CoreTextFontFace::Clone() const { return new CoreTextFontFace( *this); @@ -277,6 +310,11 @@ int CoreTextFontFace::GetFontTable( const char pTagName[5], unsigned char* pResu const CTFontTableTag nTagCode = (pTagName[0]<<24) + (pTagName[1]<<16) + (pTagName[2]<<8) + (pTagName[3]<<0); + return GetFontTable(nTagCode, pResultBuf); +} + +int CoreTextFontFace::GetFontTable(uint32_t nTagCode, unsigned char* pResultBuf ) const +{ // get the raw table length CTFontDescriptorRef pFontDesc = reinterpret_cast<CTFontDescriptorRef>( GetFontId()); CTFontRef rCTFont = CTFontCreateWithFontDescriptor( pFontDesc, 0.0, nullptr); diff --git a/vcl/quartz/salgdi.cxx b/vcl/quartz/salgdi.cxx index 80825e77c84f..9e8d8df100a4 100644 --- a/vcl/quartz/salgdi.cxx +++ b/vcl/quartz/salgdi.cxx @@ -409,7 +409,7 @@ bool AquaSalGraphics::GetGlyphBoundRect(const GlyphItem& rGlyph, tools::Rectangl void AquaSalGraphics::DrawTextLayout(const CommonSalLayout& rLayout) { - const CoreTextStyle& rStyle = rLayout.getFontData(); + const CoreTextStyle& rStyle = *static_cast<const CoreTextStyle*>(&rLayout.getFont()); const FontSelectPattern& rFontSelect = rStyle.GetFontSelectPattern(); if (rFontSelect.mnHeight == 0) return; diff --git a/vcl/source/font/fontcache.cxx b/vcl/source/font/fontcache.cxx index 1aa5f3e4c700..3e4945505144 100644 --- a/vcl/source/font/fontcache.cxx +++ b/vcl/source/font/fontcache.cxx @@ -20,6 +20,7 @@ #include <svdata.hxx> #include <fontinstance.hxx> +#include <impfontcache.hxx> #include <PhysicalFontCollection.hxx> #include <PhysicalFontFace.hxx> #include <PhysicalFontFamily.hxx> diff --git a/vcl/source/font/fontinstance.cxx b/vcl/source/font/fontinstance.cxx index 5f9ac49afcf7..845eb2e9e635 100644 --- a/vcl/source/font/fontinstance.cxx +++ b/vcl/source/font/fontinstance.cxx @@ -20,6 +20,9 @@ #include <svdata.hxx> #include <fontinstance.hxx> +#include <impfontcache.hxx> + +#include <PhysicalFontFace.hxx> // extend std namespace to add custom hash needed for LogicalFontInstance @@ -47,6 +50,8 @@ LogicalFontInstance::LogicalFontInstance(const PhysicalFontFace& rFontFace, cons , mpFontCache( nullptr ) , mnRefCount( 1 ) , m_aFontSelData(rFontSelData) + , m_pHbFont(nullptr) + , m_nAveWidthFactor(1.0f) , m_pFontFace(&rFontFace) { const_cast<FontSelectPattern*>(&m_aFontSelData)->mpFontInstance = this; @@ -57,6 +62,41 @@ LogicalFontInstance::~LogicalFontInstance() mpUnicodeFallbackList.reset(); mpFontCache = nullptr; mxFontMetric = nullptr; + + if (m_pHbFont) + hb_font_destroy(m_pHbFont); +} + +hb_font_t* LogicalFontInstance::InitHbFont(hb_face_t* pHbFace) const +{ + assert(pHbFace); + hb_font_t* pHbFont = hb_font_create(pHbFace); + unsigned int nUPEM = hb_face_get_upem(pHbFace); + hb_font_set_scale(pHbFont, nUPEM, nUPEM); + hb_ot_font_set_funcs(pHbFont); + // hb_font_t keeps a reference to hb_face_t, so destroy this one. + hb_face_destroy(pHbFace); + return pHbFont; +} + +void LogicalFontInstance::GetScale(double* nXScale, double* nYScale) +{ + hb_face_t* pHbFace = hb_font_get_face(GetHbFont()); + unsigned int nUPEM = hb_face_get_upem(pHbFace); + + double nHeight(m_aFontSelData.mnHeight); + + // On Windows, mnWidth is relative to average char width not font height, + // and we need to keep it that way for GDI to correctly scale the glyphs. + // Here we compensate for this so that HarfBuzz gives us the correct glyph + // positions. + double nWidth(m_aFontSelData.mnWidth ? m_aFontSelData.mnWidth * m_nAveWidthFactor : nHeight); + + if (nYScale) + *nYScale = nHeight / nUPEM; + + if (nXScale) + *nXScale = nWidth / nUPEM; } void LogicalFontInstance::Acquire() diff --git a/vcl/source/font/fontselect.cxx b/vcl/source/font/fontselect.cxx index fd67335eb1cd..80b9ba78ce6b 100644 --- a/vcl/source/font/fontselect.cxx +++ b/vcl/source/font/fontselect.cxx @@ -20,6 +20,8 @@ #include <sal/config.h> #include <o3tl/safeint.hxx> +#include <fontselect.hxx> + #include <PhysicalFontFace.hxx> #include <svdata.hxx> diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index 120993557634..0cc0c06c382c 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -29,119 +29,8 @@ #include <salgdi.hxx> #include <unicode/uchar.h> -#if ENABLE_QT5 -#include <qt5/Qt5Font.hxx> -#include <QtGui/QRawFont> -#endif - -static inline void decode_hb_tag( const hb_tag_t nTableTag, char *pTagName ) -{ - pTagName[0] = static_cast<char>(nTableTag >> 24); - pTagName[1] = static_cast<char>(nTableTag >> 16); - pTagName[2] = static_cast<char>(nTableTag >> 8); - pTagName[3] = static_cast<char>(nTableTag); - pTagName[4] = 0; -} - -static hb_blob_t* getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pUserData) -{ - char pTagName[5]; - decode_hb_tag( nTableTag, pTagName ); - - sal_uLong nLength = 0; -#if defined(_WIN32) - unsigned char* pBuffer = nullptr; - HFONT hFont = static_cast<HFONT>(pUserData); - HDC hDC = GetDC(nullptr); - HGDIOBJ hOrigFont = SelectObject(hDC, hFont); - nLength = ::GetFontData(hDC, OSL_NETDWORD(nTableTag), 0, nullptr, 0); - if (nLength > 0 && nLength != GDI_ERROR) - { - pBuffer = new unsigned char[nLength]; - ::GetFontData(hDC, OSL_NETDWORD(nTableTag), 0, pBuffer, nLength); - } - SelectObject(hDC, hOrigFont); - ReleaseDC(nullptr, hDC); -#elif defined(MACOSX) || defined(IOS) - unsigned char* pBuffer = nullptr; - CoreTextFontFace* pFont = static_cast<CoreTextFontFace*>(pUserData); - nLength = pFont->GetFontTable(pTagName, nullptr); - if (nLength > 0) - { - pBuffer = new unsigned char[nLength]; - pFont->GetFontTable(pTagName, pBuffer); - } -#else - FreetypeFont* pFont = static_cast<FreetypeFont*>( pUserData ); - const char* pBuffer = reinterpret_cast<const char*>( - pFont->GetTable(pTagName, &nLength) ); -#endif - - hb_blob_t* pBlob = nullptr; - if (pBuffer != nullptr) -#if defined(_WIN32) || defined(MACOSX) || defined(IOS) - pBlob = hb_blob_create(reinterpret_cast<const char*>(pBuffer), nLength, HB_MEMORY_MODE_READONLY, - pBuffer, [](void* data){ delete[] static_cast<unsigned char*>(data); }); -#else - pBlob = hb_blob_create(pBuffer, nLength, HB_MEMORY_MODE_READONLY, nullptr, nullptr); -#endif - - return pBlob; -} - -#if ENABLE_QT5 -static hb_blob_t* getFontTable_Qt5Font(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pUserData) -{ - char pTagName[5]; - decode_hb_tag( nTableTag, pTagName ); - - Qt5Font *pFont = static_cast<Qt5Font*>( pUserData ); - QRawFont aRawFont( QRawFont::fromFont( *pFont ) ); - QByteArray aTable = aRawFont.fontTable( pTagName ); - const sal_uLong nLength = aTable.size(); - - hb_blob_t* pBlob = nullptr; - if (nLength > 0) - pBlob = hb_blob_create(reinterpret_cast<const char*>( aTable.data() ), - nLength, HB_MEMORY_MODE_READONLY, nullptr, nullptr); - return pBlob; -} -#endif - -static hb_font_t* createHbFont(hb_face_t* pHbFace) -{ - hb_font_t* pHbFont = hb_font_create(pHbFace); - unsigned int nUPEM = hb_face_get_upem(pHbFace); - hb_font_set_scale(pHbFont, nUPEM, nUPEM); - hb_ot_font_set_funcs(pHbFont); - - hb_face_destroy(pHbFace); - - return pHbFont; -} - -void CommonSalLayout::getScale(double* nXScale, double* nYScale) -{ - hb_face_t* pHbFace = hb_font_get_face(mpHbFont); - unsigned int nUPEM = hb_face_get_upem(pHbFace); - - double nHeight(mrFontSelData.mnHeight); -#if defined(_WIN32) - // On Windows, mnWidth is relative to average char width not font height, - // and we need to keep it that way for GDI to correctly scale the glyphs. - // Here we compensate for this so that HarfBuzz gives us the correct glyph - // positions. - double nWidth(mrFontSelData.mnWidth ? mrFontSelData.mnWidth * mnAveWidthFactor : nHeight); -#else - double nWidth(mrFontSelData.mnWidth ? mrFontSelData.mnWidth : nHeight); -#endif - - if (nYScale) - *nYScale = nHeight / nUPEM; - - if (nXScale) - *nXScale = nWidth / nUPEM; -} +#include <fontselect.hxx> +#include <impfontcache.hxx> #if !HB_VERSION_ATLEAST(1, 1, 0) // Disabled Unicode compatibility decomposition, see fdo#66715 @@ -161,6 +50,19 @@ static hb_unicode_funcs_t* getUnicodeFuncs() } #endif +CommonSalLayout::CommonSalLayout(LogicalFontInstance &rFont) + : mpFont(&rFont) + , mpVertGlyphs(nullptr) + , mbFuzzing(utl::ConfigManager::IsFuzzing()) +{ + mpFont->Acquire(); +} + +CommonSalLayout::~CommonSalLayout() +{ + mpFont->Release(); +} + void CommonSalLayout::ParseFeatures(const OUString& aName) { if (aName.indexOf(FontSelectPatternAttributes::FEAT_PREFIX) < 0) @@ -186,159 +88,8 @@ void CommonSalLayout::ParseFeatures(const OUString& aName) while (nIndex >= 0); } -#if defined(_WIN32) -CommonSalLayout::CommonSalLayout(HDC hDC, WinFontInstance& rWinFontInstance) -: mrFontSelData(rWinFontInstance.GetFontSelectPattern()) -, mhDC(hDC) -, mhFont(static_cast<HFONT>(GetCurrentObject(hDC, OBJ_FONT))) -, mrWinFontInstance(rWinFontInstance) -, mnAveWidthFactor(1.0f) -, mpVertGlyphs(nullptr) -, mbFuzzing(utl::ConfigManager::IsFuzzing()) -{ - const WinFontFace& rWinFontFace = *static_cast<const WinFontFace*>(rWinFontInstance.GetFontFace()); - mpHbFont = rWinFontFace.GetHbFont(); - if (!mpHbFont) - { - hb_face_t* pHbFace = hb_face_create_for_tables(getFontTable, mhFont, nullptr); - - mpHbFont = createHbFont(pHbFace); - rWinFontFace.SetHbFont(mpHbFont); - } - - // Calculate the mnAveWidthFactor, see the comment where it is used. - if (mrFontSelData.mnWidth) - { - double nUPEM = hb_face_get_upem(hb_font_get_face(mpHbFont)); - - LOGFONTW aLogFont; - GetObjectW(mhFont, sizeof(LOGFONTW), &aLogFont); - - // Set the height (font size) to EM to minimize rounding errors. - aLogFont.lfHeight = -nUPEM; - // Set width to the default to get the original value in the metrics. - aLogFont.lfWidth = 0; - - // Get the font metrics. - HFONT hNewFont = CreateFontIndirectW(&aLogFont); - HFONT hOldFont = static_cast<HFONT>(SelectObject(hDC, hNewFont)); - TEXTMETRICW aFontMetric; - GetTextMetricsW(hDC, &aFontMetric); - SelectObject(hDC, hOldFont); - DeleteObject(hNewFont); - - mnAveWidthFactor = nUPEM / aFontMetric.tmAveCharWidth; - } -} - -bool CommonSalLayout::hasHScale() const -{ - int nHeight(mrFontSelData.mnHeight); - int nWidth(mrFontSelData.mnWidth ? mrFontSelData.mnWidth * mnAveWidthFactor : nHeight); - return nWidth != nHeight; -} - -#elif defined(MACOSX) || defined(IOS) -CommonSalLayout::CommonSalLayout(const CoreTextStyle& rCoreTextStyle) -: mrFontSelData(rCoreTextStyle.GetFontSelectPattern()) -, mrCoreTextStyle(rCoreTextStyle) -, mpVertGlyphs(nullptr) -, mbFuzzing(utl::ConfigManager::IsFuzzing()) -{ - mpHbFont = rCoreTextStyle.GetHbFont(); - if (!mpHbFont) - { - // On macOS we use HarfBuzz for AAT shaping, but HarfBuzz will then - // need a CGFont (as it offloads the actual AAT shaping to Core Text), - // if we have one we use it to create the hb_face_t. - hb_face_t* pHbFace; - CTFontRef pCTFont = static_cast<CTFontRef>(CFDictionaryGetValue(rCoreTextStyle.GetStyleDict(), kCTFontAttributeName)); - CGFontRef pCGFont = CTFontCopyGraphicsFont(pCTFont, nullptr); - if (pCGFont) - pHbFace = hb_coretext_face_create(pCGFont); - else - pHbFace = hb_face_create_for_tables(getFontTable, const_cast<PhysicalFontFace*>(rCoreTextStyle.GetFontFace()), nullptr); - CGFontRelease(pCGFont); - - mpHbFont = createHbFont(pHbFace); - rCoreTextStyle.SetHbFont(mpHbFont); - } -} - -#else - -void CommonSalLayout::InitFromFreetypeFont() -{ - mpHbFont = mpFreetypeFont->GetHbFont(); - if (!mpHbFont) - { - hb_face_t* pHbFace = hb_face_create_for_tables(getFontTable, mpFreetypeFont, nullptr); - mpHbFont = createHbFont(pHbFace); - mpFreetypeFont->SetHbFont(mpHbFont); - } -} - -#if ENABLE_QT5 -CommonSalLayout::CommonSalLayout(const FontSelectPattern &rFSP, - FreetypeFont *pFreetypeFont, - Qt5Font *pQt5Font, bool bUseQt5) - : mrFontSelData(rFSP) - , mpFreetypeFont(pFreetypeFont) - , mbUseQt5(bUseQt5) - , mpQFont(pQt5Font) - , mpVertGlyphs(nullptr) - , mbFuzzing(utl::ConfigManager::IsFuzzing()) -{ - if (mbUseQt5) - { - assert( pQt5Font && !pFreetypeFont ); - mpHbFont = mpQFont->GetHbFont(); - if (!mpHbFont) - { - hb_face_t* pHbFace = hb_face_create_for_tables( - getFontTable_Qt5Font, pQt5Font, nullptr); - mpHbFont = createHbFont(pHbFace); - mpQFont->SetHbFont(mpHbFont); - } - } - else - { - assert( !pQt5Font && pFreetypeFont ); - InitFromFreetypeFont(); - } -} - -CommonSalLayout::CommonSalLayout(FreetypeFont& rFreetypeFont) - : CommonSalLayout(rFreetypeFont.GetFontSelData(), - &rFreetypeFont, nullptr, false) -{ -} - -CommonSalLayout::CommonSalLayout(Qt5Font& rQFont) - : CommonSalLayout(rQFont.GetFontSelectPattern(), - nullptr, &rQFont, true) -{ -} - -#else // ! ENABLE_QT5 - -CommonSalLayout::CommonSalLayout(FreetypeFont& rFreetypeFont) - : mrFontSelData(rFreetypeFont.GetFontSelData()) - , mpFreetypeFont(&rFreetypeFont) - , mpVertGlyphs(nullptr) - , mbFuzzing(utl::ConfigManager::IsFuzzing()) -{ - InitFromFreetypeFont(); -} - -#endif -#endif - void CommonSalLayout::InitFont() const { -#if defined(_WIN32) - SelectObject(mhDC, mhFont); -#endif } struct SubRun @@ -484,12 +235,13 @@ void CommonSalLayout::DrawText(SalGraphics& rSalGraphics) const bool CommonSalLayout::HasVerticalAlternate(sal_UCS4 aChar, sal_UCS4 aVariationSelector) { hb_codepoint_t nGlyphIndex = 0; - if (!hb_font_get_glyph(mpHbFont, aChar, aVariationSelector, &nGlyphIndex)) + hb_font_t *pHbFont = mpFont->GetHbFont(); + if (!hb_font_get_glyph(pHbFont, aChar, aVariationSelector, &nGlyphIndex)) return false; if (!mpVertGlyphs) { - hb_face_t* pHbFace = hb_font_get_face(mpHbFont); + hb_face_t* pHbFace = hb_font_get_face(pHbFont); mpVertGlyphs = hb_set_create(); // Find all GSUB lookups for “vert” feature. @@ -519,7 +271,8 @@ bool CommonSalLayout::HasVerticalAlternate(sal_UCS4 aChar, sal_UCS4 aVariationSe bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) { - hb_face_t* pHbFace = hb_font_get_face(mpHbFont); + hb_font_t *pHbFont = mpFont->GetHbFont(); + hb_face_t* pHbFace = hb_font_get_face(pHbFont); int nGlyphCapacity = 2 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos); Reserve(nGlyphCapacity); @@ -546,17 +299,18 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) hb_buffer_set_unicode_funcs(pHbBuffer, pHbUnicodeFuncs); #endif + const FontSelectPattern& rFontSelData = mpFont->GetFontSelectPattern(); if (rArgs.mnFlags & SalLayoutFlags::DisableKerning) { - SAL_INFO("vcl.harfbuzz", "Disabling kerning for font: " << mrFontSelData.maTargetName); + SAL_INFO("vcl.harfbuzz", "Disabling kerning for font: " << rFontSelData.maTargetName); maFeatures.push_back({ HB_TAG('k','e','r','n'), 0, 0, static_cast<unsigned int>(-1) }); } - ParseFeatures(mrFontSelData.maTargetName); + ParseFeatures(rFontSelData.maTargetName); double nXScale = 0; double nYScale = 0; - getScale(&nXScale, &nYScale); + mpFont->GetScale(&nXScale, &nYScale); Point aCurrPos(0, 0); while (true) @@ -682,7 +436,7 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) hb_segment_properties_t aHbProps; hb_buffer_get_segment_properties(pHbBuffer, &aHbProps); hb_shape_plan_t* pHbPlan = hb_shape_plan_create_cached(pHbFace, &aHbProps, maFeatures.data(), maFeatures.size(), pHbShapers); - bool ok = hb_shape_plan_execute(pHbPlan, mpHbFont, pHbBuffer, maFeatures.data(), maFeatures.size()); + bool ok = hb_shape_plan_execute(pHbPlan, pHbFont, pHbBuffer, maFeatures.data(), maFeatures.size()); assert(ok); (void) ok; hb_buffer_set_content_type(pHbBuffer, HB_BUFFER_CONTENT_TYPE_GLYPHS); @@ -795,7 +549,7 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs) // We have glyph offsets that is relative to h origin now, // add the origin back so it is relative to v origin. - hb_font_add_glyph_origin_for_direction( mpHbFont, + hb_font_add_glyph_origin_for_direction(pHbFont, nGlyphIndex, HB_DIRECTION_TTB, &pHbPositions[i].x_offset , @@ -887,12 +641,13 @@ void CommonSalLayout::ApplyDXArray(ImplLayoutArgs& rArgs) hb_codepoint_t nKashidaIndex = 0; if (rArgs.mnFlags & SalLayoutFlags::KashidaJustification) { + hb_font_t *pHbFont = mpFont->GetHbFont(); // Find Kashida glyph width and index. - if (hb_font_get_glyph(mpHbFont, 0x0640, 0, &nKashidaIndex)) + if (hb_font_get_glyph(pHbFont, 0x0640, 0, &nKashidaIndex)) { double nXScale = 0; - getScale(&nXScale, nullptr); - nKashidaWidth = hb_font_get_glyph_h_advance(mpHbFont, nKashidaIndex) * nXScale; + mpFont->GetScale(&nXScale, nullptr); + nKashidaWidth = hb_font_get_glyph_h_advance(pHbFont, nKashidaIndex) * nXScale; } bKashidaJustify = nKashidaWidth != 0; } diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx index 879834c0da4c..24a562925ff3 100644 --- a/vcl/source/window/window.cxx +++ b/vcl/source/window/window.cxx @@ -1756,7 +1756,7 @@ void Window::ImplNewInputContext() pFontInstance = pFocusWin->mpFontCache->GetFontInstance( pFocusWin->mpFontCollection, rFont, aSize, static_cast<float>(aSize.Height()) ); if ( pFontInstance ) - aNewContext.mpFont = &pFontInstance->GetFontSelectPattern(); + aNewContext.mpFont = pFontInstance; } aNewContext.meLanguage = rFont.GetLanguage(); aNewContext.mnOptions = rInputContext.GetOptions(); diff --git a/vcl/unx/generic/gdi/cairotextrender.cxx b/vcl/unx/generic/gdi/cairotextrender.cxx index bde9ff6827ac..d856821de72c 100644 --- a/vcl/unx/generic/gdi/cairotextrender.cxx +++ b/vcl/unx/generic/gdi/cairotextrender.cxx @@ -31,6 +31,7 @@ #include <unx/geninst.h> #include <unx/glyphcache.hxx> #include <unx/fc_fontoptions.hxx> +#include <unx/freetype_glyphcache.hxx> #include <PhysicalFontFace.hxx> #include <impfont.hxx> #include <impfontmetricdata.hxx> @@ -169,7 +170,8 @@ namespace void CairoTextRender::DrawTextLayout(const CommonSalLayout& rLayout) { - const FreetypeFont& rFont = *rLayout.getFreetypeFont(); + const FreetypeFontInstance& rInstance = static_cast<FreetypeFontInstance&>(rLayout.getFont()); + const FreetypeFont& rFont = *rInstance.GetFreetypeFont(); std::vector<cairo_glyph_t> cairo_glyphs; std::vector<int> glyph_extrarotation; @@ -195,7 +197,7 @@ void CairoTextRender::DrawTextLayout(const CommonSalLayout& rLayout) if (cairo_glyphs.empty()) return; - const FontSelectPattern& rFSD = rFont.GetFontSelData(); + const FontSelectPattern& rFSD = rInstance.GetFontSelectPattern(); int nHeight = rFSD.mnHeight; int nWidth = rFSD.mnWidth ? rFSD.mnWidth : nHeight; if (nWidth == 0 || nHeight == 0) @@ -460,7 +462,7 @@ bool CairoTextRender::GetGlyphOutline(const GlyphItem& rGlyph, if( nLevel >= MAX_FALLBACK ) return false; - FreetypeFont* pSF = mpFreetypeFont[ nLevel ]; + const FreetypeFont* pSF = mpFreetypeFont[ nLevel ]; if( !pSF ) return false; @@ -470,7 +472,7 @@ bool CairoTextRender::GetGlyphOutline(const GlyphItem& rGlyph, std::unique_ptr<SalLayout> CairoTextRender::GetTextLayout(ImplLayoutArgs& /*rArgs*/, int nFallbackLevel) { if (mpFreetypeFont[nFallbackLevel]) - return std::unique_ptr<SalLayout>(new CommonSalLayout(*mpFreetypeFont[nFallbackLevel])); + return std::unique_ptr<SalLayout>(new CommonSalLayout(*mpFreetypeFont[nFallbackLevel]->GetFontInstance())); return nullptr; } @@ -485,13 +487,13 @@ SystemFontData CairoTextRender::GetSysFontData( int nFallbackLevel ) const if (mpFreetypeFont[nFallbackLevel] != nullptr) { - FreetypeFont* rFont = mpFreetypeFont[nFallbackLevel]; + const FreetypeFont* rFont = mpFreetypeFont[nFallbackLevel]; aSysFontData.nFontId = rFont->GetFtFace(); aSysFontData.nFontFlags = rFont->GetLoadFlags(); aSysFontData.bFakeBold = rFont->NeedsArtificialBold(); aSysFontData.bFakeItalic = rFont->NeedsArtificialItalic(); aSysFontData.bAntialias = rFont->GetAntialiasAdvice(); - aSysFontData.bVerticalCharacterType = rFont->GetFontSelData().mbVertical; + aSysFontData.bVerticalCharacterType = rFont->GetFontInstance()->GetFontSelectPattern().mbVertical; } return aSysFontData; @@ -555,4 +557,5 @@ void CairoTextRender::GetGlyphWidths( const PhysicalFontFace* pFont, psp::fontID aFont = pFont->GetFontId(); GenPspGraphics::DoGetGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc ); } + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx index 795284493f12..b2b1c59f67cf 100644 --- a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx +++ b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx @@ -367,7 +367,7 @@ LogicalFontInstance* FreetypeFontFace::CreateFontInstance(const FontSelectPatter FreetypeFont::FreetypeFont( const FontSelectPattern& rFSD, FreetypeFontInfo* pFI ) : maGlyphList( 0), - maFontSelData(rFSD), + mpFontInstance(rFSD.mpFontInstance), mnRefCount(1), mnBytesUsed( sizeof(FreetypeFont) ), mpPrevGCFont( nullptr ), @@ -382,13 +382,12 @@ FreetypeFont::FreetypeFont( const FontSelectPattern& rFSD, FreetypeFontInfo* pFI maSizeFT( nullptr ), mbFaceOk( false ), mbArtItalic( false ), - mbArtBold( false ), - mpHbFont( nullptr ) + mbArtBold(false) { // TODO: move update of mpFontInstance into FontEntry class when // it becomes responsible for the FreetypeFont instantiation - static_cast<FreetypeFontInstance*>(rFSD.mpFontInstance)->SetFreetypeFont( this ); - maFontSelData.mpFontInstance->Acquire(); + static_cast<FreetypeFontInstance*>(mpFontInstance)->SetFreetypeFont( this ); + mpFontInstance->Acquire(); maFaceFT = pFI->GetFaceFT(); @@ -459,7 +458,7 @@ const FontConfigFontOptions* FreetypeFont::GetFontOptions() const { if (!mxFontOptions) { - mxFontOptions.reset(GetFCFontOptions(mpFontInfo->GetFontAttributes(), maFontSelData.mnHeight)); + mxFontOptions.reset(GetFCFontOptions(mpFontInfo->GetFontAttributes(), mpFontInstance->GetFontSelectPattern().mnHeight)); mxFontOptions->SyncPattern(GetFontFileName(), GetFontFaceIndex(), NeedsArtificialBold()); } return mxFontOptions.get(); @@ -487,10 +486,7 @@ FreetypeFont::~FreetypeFont() mpFontInfo->ReleaseFaceFT(); - if( mpHbFont ) - hb_font_destroy( mpHbFont ); - - maFontSelData.mpFontInstance->Release(); + mpFontInstance->Release(); ReleaseFromGarbageCollect(); } @@ -499,7 +495,7 @@ void FreetypeFont::GetFontMetric(ImplFontMetricDataRef const & rxTo) const { rxTo->FontAttributes::operator =(mpFontInfo->GetFontAttributes()); - rxTo->SetOrientation( maFontSelData.mnOrientation ); + rxTo->SetOrientation( mpFontInstance->GetFontSelectPattern().mnOrientation ); //Always consider [star]symbol as symbol fonts if ( IsStarSymbol( rxTo->GetFamilyName() ) ) @@ -569,7 +565,7 @@ void FreetypeFont::GetFontMetric(ImplFontMetricDataRef const & rxTo) const void FreetypeFont::ApplyGlyphTransform(bool bVertical, FT_Glyph pGlyphFT ) const { // shortcut most common case - if (!maFontSelData.mnOrientation && !bVertical) + if (!mpFontInstance->GetFontSelectPattern().mnOrientation && !bVertical) return; const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics; @@ -650,7 +646,7 @@ void FreetypeFont::InitGlyphData(const GlyphItem& rGlyph, GlyphData& rGD ) const bool FreetypeFont::GetAntialiasAdvice() const { // TODO: also use GASP info - return !maFontSelData.mbNonAntialiased && (mnPrioAntiAlias > 0); + return !mpFontInstance->GetFontSelectPattern().mbNonAntialiased && (mnPrioAntiAlias > 0); } // determine unicode ranges in font diff --git a/vcl/unx/generic/glyphs/glyphcache.cxx b/vcl/unx/generic/glyphs/glyphcache.cxx index ac2f8cf83218..218161c65be2 100644 --- a/vcl/unx/generic/glyphs/glyphcache.cxx +++ b/vcl/unx/generic/glyphs/glyphcache.cxx @@ -259,7 +259,7 @@ void GlyphCache::GarbageCollect() pFreetypeFont->GarbageCollect( mnLruIndex+0x10000000 ); if( pFreetypeFont == mpCurrentGCFont ) mpCurrentGCFont = nullptr; - const FontSelectPattern& rIFSD = pFreetypeFont->GetFontSelData(); + const FontSelectPattern& rIFSD = pFreetypeFont->GetFontInstance()->GetFontSelectPattern(); maFontList.erase( rIFSD ); mnBytesUsed -= pFreetypeFont->GetByteCount(); @@ -370,4 +370,28 @@ FreetypeFontInstance::~FreetypeFontInstance() if (mpFreetypeFont) mpFreetypeFont->Release(); } + +static hb_blob_t* getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pUserData) +{ + char pTagName[5]; + LogicalFontInstance::DecodeOpenTypeTag( nTableTag, pTagName ); + + sal_uLong nLength = 0; + FreetypeFontInstance* pFontInstance = static_cast<FreetypeFontInstance*>( pUserData ); + FreetypeFont* pFont = pFontInstance->GetFreetypeFont(); + const char* pBuffer = reinterpret_cast<const char*>( + pFont->GetTable(pTagName, &nLength) ); + + hb_blob_t* pBlob = nullptr; + if (pBuffer != nullptr) + pBlob = hb_blob_create(pBuffer, nLength, HB_MEMORY_MODE_READONLY, nullptr, nullptr); + + return pBlob; +} + +hb_font_t* FreetypeFontInstance::ImplInitHbFont() +{ + return InitHbFont(hb_face_create_for_tables(getFontTable, this, nullptr)); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/generic/print/genpspgraphics.cxx b/vcl/unx/generic/print/genpspgraphics.cxx index d651da2812c6..c1f1caf014a0 100644 --- a/vcl/unx/generic/print/genpspgraphics.cxx +++ b/vcl/unx/generic/print/genpspgraphics.cxx @@ -547,7 +547,7 @@ private: }; PspCommonSalLayout::PspCommonSalLayout(::psp::PrinterGfx& rGfx, FreetypeFont& rFont) -: CommonSalLayout(rFont) +: CommonSalLayout(*rFont.GetFontInstance()) , mrPrinterGfx(rGfx) { mnFontID = mrPrinterGfx.GetFontID(); diff --git a/vcl/win/gdi/salfont.cxx b/vcl/win/gdi/salfont.cxx index 2c96edc91fbe..62d9f7d85dd7 100644 --- a/vcl/win/gdi/salfont.cxx +++ b/vcl/win/gdi/salfont.cxx @@ -622,8 +622,7 @@ WinFontFace::WinFontFace( const FontAttributes& rDFS, meWinCharSet( eWinCharSet ), mnPitchAndFamily( nPitchAndFamily ), mbAliasSymbolsHigh( false ), - mbAliasSymbolsLow( false ), - mpHbFont( nullptr ) + mbAliasSymbolsLow( false ) { SetBitmapSize( 0, nHeight ); @@ -652,9 +651,6 @@ WinFontFace::WinFontFace( const FontAttributes& rDFS, WinFontFace::~WinFontFace() { mxUnicodeMap.clear(); - - if( mpHbFont ) - hb_font_destroy( mpHbFont ); } sal_IntPtr WinFontFace::GetFontId() const @@ -662,6 +658,16 @@ sal_IntPtr WinFontFace::GetFontId() const return mnId; } +PhysicalFontFace* WinFontFace::Clone() const +{ + return new WinFontFace(*this); +} + +LogicalFontInstance* WinFontFace::CreateFontInstance(const FontSelectPattern& rFSD) const +{ + return new WinFontInstance(*this, rFSD); +} + static inline DWORD CalcTag( const char p[5]) { return (p[0]+(p[1]<<8)+(p[2]<<16)+(p[3]<<24)); } void WinFontFace::UpdateFromHDC( HDC hDC ) const diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx index cc37b866848d..3188f7f3d0bb 100644 --- a/vcl/win/gdi/winlayout.cxx +++ b/vcl/win/gdi/winlayout.cxx @@ -251,7 +251,7 @@ bool ExTextOutRenderer::operator ()(CommonSalLayout const &rLayout, HFONT hAltFont = nullptr; bool bUseAltFont = false; bool bShift = false; - if (rLayout.getFontSelData().mbVertical) + if (rLayout.getFont().GetFontSelectPattern().mbVertical) { LOGFONTW aLogFont; GetObjectW(hFont, sizeof(aLogFont), &aLogFont); @@ -307,7 +307,9 @@ std::unique_ptr<SalLayout> WinSalGraphics::GetTextLayout(ImplLayoutArgs& /*rArgs assert(mpWinFontEntry[nFallbackLevel]->GetFontFace()); - return std::unique_ptr<SalLayout>(new CommonSalLayout(getHDC(), *mpWinFontEntry[nFallbackLevel])); + mpWinFontEntry[nFallbackLevel]->SetHDC(getHDC()); + CommonSalLayout *aLayout = new CommonSalLayout(*mpWinFontEntry[nFallbackLevel]); + return std::unique_ptr<SalLayout>(aLayout); } LogicalFontInstance * WinSalGraphics::GetWinFontEntry(int const nFallbackLevel) @@ -324,18 +326,76 @@ WinFontInstance::~WinFontInstance() { } -PhysicalFontFace* WinFontFace::Clone() const +bool WinFontInstance::hasHScale() const { - if( mpHbFont ) - hb_font_reference( mpHbFont ); + const FontSelectPattern &rPattern = GetFontSelectPattern(); + int nHeight(rPattern.mnHeight); + int nWidth(rPattern.mnWidth ? rPattern.mnWidth * GetAverageWidthFactor() : nHeight); + return nWidth != nHeight; +} - PhysicalFontFace* pClone = new WinFontFace( *this ); - return pClone; +static hb_blob_t* getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pUserData) +{ + sal_uLong nLength = 0; + unsigned char* pBuffer = nullptr; + HFONT hFont = static_cast<HFONT>(pUserData); + HDC hDC = GetDC(nullptr); + HGDIOBJ hOrigFont = SelectObject(hDC, hFont); + nLength = ::GetFontData(hDC, OSL_NETDWORD(nTableTag), 0, nullptr, 0); + if (nLength > 0 && nLength != GDI_ERROR) + { + pBuffer = new unsigned char[nLength]; + ::GetFontData(hDC, OSL_NETDWORD(nTableTag), 0, pBuffer, nLength); + } + SelectObject(hDC, hOrigFont); + ReleaseDC(nullptr, hDC); + + hb_blob_t* pBlob = nullptr; + if (pBuffer != nullptr) + pBlob = hb_blob_create(reinterpret_cast<const char*>(pBuffer), nLength, HB_MEMORY_MODE_READONLY, + pBuffer, [](void* data){ delete[] static_cast<unsigned char*>(data); }); + return pBlob; } -LogicalFontInstance* WinFontFace::CreateFontInstance(const FontSelectPattern& rFSD) const +hb_font_t* WinFontInstance::ImplInitHbFont() { - return new WinFontInstance(*this, rFSD); + assert(m_hDC); + m_hFont = static_cast<HFONT>(GetCurrentObject(m_hDC, OBJ_FONT)); + hb_font_t* pHbFont = InitHbFont(hb_face_create_for_tables(getFontTable, m_hFont, nullptr)); + + // Calculate the AverageWidthFactor, see LogicalFontInstance::GetScale(). + if (GetFontSelectPattern().mnWidth) + { + double nUPEM = hb_face_get_upem(hb_font_get_face(pHbFont)); + + LOGFONTW aLogFont; + GetObjectW(m_hFont, sizeof(LOGFONTW), &aLogFont); + + // Set the height (font size) to EM to minimize rounding errors. + aLogFont.lfHeight = -nUPEM; + // Set width to the default to get the original value in the metrics. + aLogFont.lfWidth = 0; + + // Get the font metrics. + HFONT hNewFont = CreateFontIndirectW(&aLogFont); + HFONT hOldFont = static_cast<HFONT>(SelectObject(m_hDC, hNewFont)); + TEXTMETRICW aFontMetric; + GetTextMetricsW(m_hDC, &aFontMetric); + SelectObject(m_hDC, hOldFont); + DeleteObject(hNewFont); + + SetAverageWidthFactor(nUPEM / aFontMetric.tmAveCharWidth); + } + + return pHbFont; +} + +void WinFontInstance::SetHDC(const HDC hDC) +{ + if (m_hDC == hDC) + return; + ReleaseHbFont(); + m_hDC = hDC; } bool WinSalGraphics::CacheGlyphs(const CommonSalLayout& rLayout) @@ -345,8 +405,8 @@ bool WinSalGraphics::CacheGlyphs(const CommonSalLayout& rLayout) return false; HDC hDC = getHDC(); - HFONT hFONT = rLayout.getHFONT(); - WinFontInstance& rFont = rLayout.getWinFontInstance(); + WinFontInstance& rFont = *static_cast<WinFontInstance*>(&rLayout.getFont()); + HFONT hFONT = rFont.GetHFONT(); int nStart = 0; Point aPos(0, 0); @@ -377,7 +437,7 @@ bool WinSalGraphics::DrawCachedGlyphs(const CommonSalLayout& rLayout) if (!pImpl) return false; - WinFontInstance& rFont = rLayout.getWinFontInstance(); + WinFontInstance& rFont = *static_cast<WinFontInstance*>(&rLayout.getFont()); int nStart = 0; Point aPos(0, 0); @@ -412,9 +472,12 @@ void WinSalGraphics::DrawTextLayout(const CommonSalLayout& rLayout) { HDC hDC = getHDC(); + HFONT hFont = static_cast<const WinFontInstance*>(&rLayout.getFont())->GetHFONT(); + HGDIOBJ hOrigFont = SelectObject(hDC, hFont); + // Our DirectWrite renderer is incomplete, skip it for non-horizontal or // stretched text. - bool bForceGDI = rLayout.GetOrientation() || rLayout.hasHScale(); + bool bForceGDI = rLayout.GetOrientation() || static_cast<const WinFontInstance*>(&rLayout.getFont())->hasHScale(); bool bUseOpenGL = OpenGLHelper::isVCLOpenGLEnabled() && !mbPrinter; if (!bUseOpenGL) @@ -477,7 +540,7 @@ void WinSalGraphics::DrawTextLayout(const CommonSalLayout& rLayout) // setup the hidden DC with black color and white background, we will // use the result of the text drawing later as a mask only - HFONT hOrigFont = ::SelectFont(aDC.getCompatibleHDC(), static_cast<HFONT>(::GetCurrentObject(hDC, OBJ_FONT))); + HFONT hOFont = ::SelectFont(aDC.getCompatibleHDC(), hFont); ::SetTextColor(aDC.getCompatibleHDC(), RGB(0, 0, 0)); ::SetBkColor(aDC.getCompatibleHDC(), RGB(255, 255, 255)); @@ -495,11 +558,13 @@ void WinSalGraphics::DrawTextLayout(const CommonSalLayout& rLayout) if (xTexture) pImpl->DrawMask(*xTexture, salColor, aDC.getTwoRect()); - ::SelectFont(aDC.getCompatibleHDC(), hOrigFont); + ::SelectFont(aDC.getCompatibleHDC(), hOFont); pImpl->PostDraw(); } } + + SelectObject(hDC, hOrigFont); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/win/window/salframe.cxx b/vcl/win/window/salframe.cxx index ed65a8698d70..633e97c6670e 100644 --- a/vcl/win/window/salframe.cxx +++ b/vcl/win/window/salframe.cxx @@ -2184,7 +2184,7 @@ static void ImplSalFrameSetInputContext( HWND hWnd, const SalInputContext* pCont // specified by this font name; but it seems to decide whether // to use that font's horizontal or vertical variant based on a // '@' in front of this font name. - ImplGetLogFontFromFontSelect(hDC, pContext->mpFont, + ImplGetLogFontFromFontSelect(hDC, &pContext->mpFont->GetFontSelectPattern(), nullptr, aLogFont); ReleaseDC( pFrame->mhWnd, hDC ); ImmSetCompositionFontW( hIMC, &aLogFont ); |