diff options
27 files changed, 1906 insertions, 1598 deletions
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index 80c6405964dd..e605343cb943 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -183,7 +183,9 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/filter/wmf/winwmf \ vcl/source/filter/wmf/wmf \ vcl/source/filter/wmf/wmfwr \ + vcl/source/font/PhysicalFontCollection \ vcl/source/font/PhysicalFontFace \ + vcl/source/font/PhysicalFontFamily \ vcl/source/fontsubset/cff \ vcl/source/fontsubset/fontsubset \ vcl/source/fontsubset/gsub \ diff --git a/vcl/generic/fontmanager/fontsubst.cxx b/vcl/generic/fontmanager/fontsubst.cxx index f2f57f4a80bb..deeb7916004a 100644 --- a/vcl/generic/fontmanager/fontsubst.cxx +++ b/vcl/generic/fontmanager/fontsubst.cxx @@ -28,6 +28,7 @@ #include "salbmp.hxx" #include "impfont.hxx" #include "outdev.h" +#include "PhysicalFontCollection.hxx" #include "fontsubset.hxx" #include "salprn.hxx" diff --git a/vcl/generic/glyphs/gcach_ftyp.cxx b/vcl/generic/glyphs/gcach_ftyp.cxx index ea6c966e1e57..eee46f4b68d3 100644 --- a/vcl/generic/glyphs/gcach_ftyp.cxx +++ b/vcl/generic/glyphs/gcach_ftyp.cxx @@ -41,6 +41,7 @@ #include "osl/thread.hxx" #include "langboost.hxx" +#include "PhysicalFontCollection.hxx" #include "sft.hxx" #include <ft2build.h> diff --git a/vcl/generic/print/genpspgraphics.cxx b/vcl/generic/print/genpspgraphics.cxx index 515dc0eee675..d111c28e1024 100644 --- a/vcl/generic/print/genpspgraphics.cxx +++ b/vcl/generic/print/genpspgraphics.cxx @@ -45,6 +45,7 @@ #include "impfont.hxx" #include "langboost.hxx" #include "outfont.hxx" +#include "PhysicalFontCollection.hxx" #include "PhysicalFontFace.hxx" #include "salbmp.hxx" #include "salprn.hxx" diff --git a/vcl/headless/svptext.cxx b/vcl/headless/svptext.cxx index 7fd3cd30e587..e53ac29514cd 100644 --- a/vcl/headless/svptext.cxx +++ b/vcl/headless/svptext.cxx @@ -38,6 +38,8 @@ #include "outfont.hxx" #include "PhysicalFontFace.hxx" +class PhysicalFontCollection; + using namespace basegfx; using namespace basebmp; diff --git a/vcl/inc/PhysicalFontCollection.hxx b/vcl/inc/PhysicalFontCollection.hxx new file mode 100644 index 000000000000..9c0c7a19ada2 --- /dev/null +++ b/vcl/inc/PhysicalFontCollection.hxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include <vcl/dllapi.h> + +#include "outfont.hxx" +#include "PhysicalFontFamily.hxx" + +// - PhysicalFontCollection - + +// TODO: merge with ImplFontCache +// TODO: rename to LogicalFontManager + +class VCL_PLUGIN_PUBLIC PhysicalFontCollection +{ +private: + friend class WinGlyphFallbackSubstititution; + mutable bool mbMatchData; // true if matching attributes are initialized + bool mbMapNames; // true if MapNames are available + + typedef boost::unordered_map<const OUString, PhysicalFontFamily*,FontNameHash> PhysicalFontFamilies; + PhysicalFontFamilies maPhysicalFontFamilies; + + ImplPreMatchFontSubstitution* mpPreMatchHook; // device specific prematch substitution + ImplGlyphFallbackFontSubstitution* mpFallbackHook; // device specific glyh fallback substitution + +public: + explicit PhysicalFontCollection(); + virtual ~PhysicalFontCollection(); + + // fill the list with device fonts + void Add( PhysicalFontFace* ); + void Clear(); + int Count() const { return maPhysicalFontFamilies.size(); } + + // find the device font + PhysicalFontFamily* FindFontFamily( const OUString& rFontName ) const; + PhysicalFontFamily* ImplFindByFont( FontSelectPattern& ) const; + PhysicalFontFamily* ImplFindBySearchName( const OUString& ) const; + + // suggest fonts for glyph fallback + PhysicalFontFamily* GetGlyphFallbackFont( FontSelectPattern&, + OUString& rMissingCodes, int nFallbackLevel ) const; + + // prepare platform specific font substitutions + void SetPreMatchHook( ImplPreMatchFontSubstitution* ); + void SetFallbackHook( ImplGlyphFallbackFontSubstitution* ); + + // misc utilities + PhysicalFontCollection* Clone( bool bScalable, bool bEmbeddable ) const; + ImplGetDevFontList* GetDevFontList() const; + ImplGetDevSizeList* GetDevSizeList( const OUString& rFontName ) const; + + PhysicalFontFamily* ImplFindByTokenNames(const OUString& rTokenStr) const; + +protected: + void InitMatchData() const; + bool AreMapNamesAvailable() const { return mbMapNames; } + + PhysicalFontFamily* ImplFindByAliasName(const OUString& rSearchName, + const OUString& rShortName) const; + PhysicalFontFamily* ImplFindBySubstFontAttr( const utl::FontNameAttr& ) const; + PhysicalFontFamily* ImplFindByAttributes(sal_uLong nSearchType, FontWeight, FontWidth, + FontItalic, const OUString& rSearchFamily) const; + PhysicalFontFamily* FindDefaultFont() const; + +private: + void InitGenericGlyphFallback() const; + mutable PhysicalFontFamily** mpFallbackList; + mutable int mnFallbackCount; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/PhysicalFontFamily.hxx b/vcl/inc/PhysicalFontFamily.hxx new file mode 100644 index 000000000000..b1f56dece2db --- /dev/null +++ b/vcl/inc/PhysicalFontFamily.hxx @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include <set> + +#include <unotools/fontcfg.hxx> + +#include "PhysicalFontFace.hxx" +#include "PhysicalFontFamily.hxx" + +class PhysicalFontFace; +class PhysicalFontCollection; + +// flags for mnMatchType member +#define FONT_FAMILY_SCALABLE (1<<0) +#define FONT_FAMILY_SYMBOL (1<<1) +#define FONT_FAMILY_NONESYMBOL (1<<2) +#define FONT_FAMILY_LIGHT (1<<4) +#define FONT_FAMILY_BOLD (1<<5) +#define FONT_FAMILY_NORMAL (1<<6) +#define FONT_FAMILY_NONEITALIC (1<<8) +#define FONT_FAMILY_ITALIC (1<<9) + +class PhysicalFontFamily +{ +public: + PhysicalFontFamily( const OUString& rSearchName ); + ~PhysicalFontFamily(); + + const OUString& GetFamilyName() const { return maName; } + const OUString& GetSearchName() const { return maSearchName; } + const OUString& GetAliasNames() const { return maMapNames; } + const OUString& GetMatchFamilyName() const { return maMatchFamilyName; } + sal_uLong GetMatchType() const { return mnMatchType ; } + FontWeight GetMatchWeight() const { return meMatchWeight ; } + FontWidth GetMatchWidth() const { return meMatchWidth ; } + bool IsScalable() const { return mpFirst->IsScalable(); } + int GetMinQuality() const { return mnMinQuality; } + int GetTypeFaces() const { return mnTypeFaces; } + bool AddFontFace( PhysicalFontFace* ); + void InitMatchData( const utl::FontSubstConfiguration&, + const OUString& rSearchName ); + PhysicalFontFace* FindBestFontFace( const FontSelectPattern& rFSD ) const; + + void GetFontHeights( std::set<int>& rHeights ) const; + void UpdateDevFontList( ImplGetDevFontList& ) const; + void UpdateCloneFontList( PhysicalFontCollection&, + bool bScalable, bool bEmbeddable ) const; + +static void CalcType( sal_uLong& rType, FontWeight& rWeight, FontWidth& rWidth, + FontFamily eFamily, const utl::FontNameAttr* pFontAttr ); + +private: + PhysicalFontFace* mpFirst; // linked list of physical font faces + OUString maName; // Fontname (original font family name) + OUString maSearchName; // normalized font family name + OUString maMapNames; // fontname aliases + int mnTypeFaces; // Typeface Flags + sal_uLong mnMatchType; // MATCH - Type + OUString maMatchFamilyName; // MATCH - FamilyName + FontWeight meMatchWeight; // MATCH - Weight + FontWidth meMatchWidth; // MATCH - Width + FontFamily meFamily; + FontPitch mePitch; + int mnMinQuality; // quality of the worst font face +}; + diff --git a/vcl/inc/generic/genpspgraphics.h b/vcl/inc/generic/genpspgraphics.h index ea7d381545fc..3d1bbc7178fc 100644 --- a/vcl/inc/generic/genpspgraphics.h +++ b/vcl/inc/generic/genpspgraphics.h @@ -29,6 +29,7 @@ #include "vclpluginapi.h" class PhysicalFontFace; +class PhysicalFontCollection; namespace psp { struct JobData; class PrinterGfx; } diff --git a/vcl/inc/generic/glyphcache.hxx b/vcl/inc/generic/glyphcache.hxx index 47188e9370c5..28770f784ab2 100644 --- a/vcl/inc/generic/glyphcache.hxx +++ b/vcl/inc/generic/glyphcache.hxx @@ -30,6 +30,7 @@ class GlyphCachePeer; class ServerFontLayoutEngine; class ServerFontLayout; class ImplFontOptions; +class PhysicalFontCollection; #include <tools/gen.hxx> #include <basebmp/bitmapdevice.hxx> diff --git a/vcl/inc/magic.h b/vcl/inc/magic.h new file mode 100644 index 000000000000..7da1d09b9b50 --- /dev/null +++ b/vcl/inc/magic.h @@ -0,0 +1,23 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#define MAX_FALLBACK 16 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/outdev.h b/vcl/inc/outdev.h index 9baba35dc988..a8f4037a0dd5 100644 --- a/vcl/inc/outdev.h +++ b/vcl/inc/outdev.h @@ -24,6 +24,8 @@ #include <set> #include <vector> +#include <tools/gen.hxx> + #include "outfont.hxx" #include "PhysicalFontFace.hxx" @@ -32,56 +34,7 @@ class Font; class VirtualDevice; class ImplGetDevFontList; class GetDevSizeList; - -// flags for mnMatchType member -#define IMPL_DEVFONT_SCALABLE ((sal_uIntPtr)0x00000001) -#define IMPL_DEVFONT_SYMBOL ((sal_uIntPtr)0x00000002) -#define IMPL_DEVFONT_NONESYMBOL ((sal_uIntPtr)0x00000004) -#define IMPL_DEVFONT_LIGHT ((sal_uIntPtr)0x00000010) -#define IMPL_DEVFONT_BOLD ((sal_uIntPtr)0x00000020) -#define IMPL_DEVFONT_NORMAL ((sal_uIntPtr)0x00000040) -#define IMPL_DEVFONT_NONEITALIC ((sal_uIntPtr)0x00000100) -#define IMPL_DEVFONT_ITALIC ((sal_uIntPtr)0x00000200) - - -class PhysicalFontFamily -{ -public: - PhysicalFontFamily( const OUString& rSearchName ); - ~PhysicalFontFamily(); - - const OUString& GetFamilyName() const { return maName; } - const OUString& GetSearchName() const { return maSearchName; } - const OUString& GetAliasNames() const { return maMapNames; } - bool IsScalable() const { return mpFirst->IsScalable(); } - int GetMinQuality() const { return mnMinQuality; } - - bool AddFontFace( PhysicalFontFace* ); - void InitMatchData( const utl::FontSubstConfiguration&, - const OUString& rSearchName ); - PhysicalFontFace* FindBestFontFace( const FontSelectPattern& rFSD ) const; - - void GetFontHeights( std::set<int>& rHeights ) const; - void UpdateDevFontList( ImplGetDevFontList& ) const; - void UpdateCloneFontList( PhysicalFontCollection&, - bool bScalable, bool bEmbeddable ) const; - -private: -friend class PhysicalFontCollection; // TODO: remove soon - PhysicalFontFace* mpFirst; // linked list of physical font faces - OUString maName; // Fontname (original font family name) - OUString maSearchName; // normalized font family name - OUString maMapNames; // fontname aliases - sal_uIntPtr mnTypeFaces; // Typeface Flags - sal_uIntPtr mnMatchType; // MATCH - Type - OUString maMatchFamilyName; // MATCH - FamilyName - FontWeight meMatchWeight; // MATCH - Weight - FontWidth meMatchWidth; // MATCH - Width - FontFamily meFamily; - FontPitch mePitch; - int mnMinQuality; // quality of the worst font face -}; - +class PhysicalFontCollection; // an ImplGetDevFontList is created by an PhysicalFontCollection // it becomes invalid when original PhysicalFontCollection is modified class ImplGetDevFontList @@ -218,6 +171,9 @@ struct ImplOutDevData basegfx::B2DHomMatrix* mpInverseViewTransform; }; +void ImplFontSubstitute( OUString& rFontName ); + + #endif // INCLUDED_VCL_INC_OUTDEV_H /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/outfont.hxx b/vcl/inc/outfont.hxx index 12adb7cc7837..798f2611dcdc 100644 --- a/vcl/inc/outfont.hxx +++ b/vcl/inc/outfont.hxx @@ -161,71 +161,6 @@ public: // TODO: change to private }; -// - PhysicalFontCollection - - -// TODO: merge with ImplFontCache -// TODO: rename to LogicalFontManager - -class VCL_PLUGIN_PUBLIC PhysicalFontCollection -{ -private: - friend class WinGlyphFallbackSubstititution; - mutable bool mbMatchData; // true if matching attributes are initialized - bool mbMapNames; // true if MapNames are available - - typedef boost::unordered_map<const OUString, PhysicalFontFamily*,FontNameHash> PhysicalFontFamilies; - PhysicalFontFamilies maPhysicalFontFamilies; - - ImplPreMatchFontSubstitution* mpPreMatchHook; // device specific prematch substitution - ImplGlyphFallbackFontSubstitution* mpFallbackHook; // device specific glyh fallback substitution - -public: - explicit PhysicalFontCollection(); - virtual ~PhysicalFontCollection(); - - // fill the list with device fonts - void Add( PhysicalFontFace* ); - void Clear(); - int Count() const { return maPhysicalFontFamilies.size(); } - - // find the device font - PhysicalFontFamily* FindFontFamily( const OUString& rFontName ) const; - PhysicalFontFamily* ImplFindByFont( FontSelectPattern& ) const; - PhysicalFontFamily* ImplFindBySearchName( const OUString& ) const; - - // suggest fonts for glyph fallback - PhysicalFontFamily* GetGlyphFallbackFont( FontSelectPattern&, - OUString& rMissingCodes, int nFallbackLevel ) const; - - // prepare platform specific font substitutions - void SetPreMatchHook( ImplPreMatchFontSubstitution* ); - void SetFallbackHook( ImplGlyphFallbackFontSubstitution* ); - - // misc utilities - PhysicalFontCollection* Clone( bool bScalable, bool bEmbeddable ) const; - ImplGetDevFontList* GetDevFontList() const; - ImplGetDevSizeList* GetDevSizeList( const OUString& rFontName ) const; - - PhysicalFontFamily* ImplFindByTokenNames(const OUString& rTokenStr) const; - -protected: - void InitMatchData() const; - bool AreMapNamesAvailable() const { return mbMapNames; } - - PhysicalFontFamily* ImplFindByAliasName(const OUString& rSearchName, - const OUString& rShortName) const; - PhysicalFontFamily* ImplFindBySubstFontAttr( const utl::FontNameAttr& ) const; - PhysicalFontFamily* ImplFindByAttributes(sal_uLong nSearchType, FontWeight, FontWidth, - FontItalic, const OUString& rSearchFamily) const; - PhysicalFontFamily* FindDefaultFont() const; - -private: - void InitGenericGlyphFallback() const; - mutable PhysicalFontFamily** mpFallbackList; - mutable int mnFallbackCount; -}; - - // - ImplFontMetricData - diff --git a/vcl/inc/sallayout.hxx b/vcl/inc/sallayout.hxx index f3727bab61b3..57e7480369fd 100644 --- a/vcl/inc/sallayout.hxx +++ b/vcl/inc/sallayout.hxx @@ -21,28 +21,25 @@ #define INCLUDED_VCL_INC_SALLAYOUT_HXX #include <iostream> +#include <list> +#include <vector> -#include <tools/gen.hxx> #include <basegfx/polygon/b2dpolypolygon.hxx> #include <i18nlangtag/languagetag.hxx> +#include <tools/gen.hxx> +#include <vcl/dllapi.h> +#include <vcl/vclenum.hxx> // for typedef sal_UCS4 #ifndef _TOOLS_LANG_HXX typedef unsigned short LanguageType; #endif -#include <vector> -#include <list> -#include <vcl/dllapi.h> - -// for typedef sal_UCS4 -#include <vcl/vclenum.hxx> +#include "magic.h" #include "salglyphid.hxx" class SalGraphics; class PhysicalFontFace; -#define MAX_FALLBACK 16 - // Layout options #define SAL_LAYOUT_BIDI_RTL 0x0001 #define SAL_LAYOUT_BIDI_STRONG 0x0002 diff --git a/vcl/inc/unx/salgdi.h b/vcl/inc/unx/salgdi.h index da91204b6b2a..03e7f50662a5 100644 --- a/vcl/inc/unx/salgdi.h +++ b/vcl/inc/unx/salgdi.h @@ -46,6 +46,7 @@ class PspSalInfoPrinter; class ServerFont; class ImplLayoutArgs; class ServerFontLayout; +class PhysicalFontCollection; class PhysicalFontFace; namespace basegfx { diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h index c649cc3cc9ab..dac4d6e6565d 100644 --- a/vcl/inc/win/salgdi.h +++ b/vcl/inc/win/salgdi.h @@ -39,6 +39,7 @@ class FontSelectPattern; class ImplWinFontEntry; class ImplFontAttrCache; +class PhysicalFontCollection; #define RGB_TO_PALRGB(nRGB) ((nRGB)|0x02000000) #define PALRGB_TO_RGB(nPalRGB) ((nPalRGB)&0x00ffffff) diff --git a/vcl/quartz/ctfonts.cxx b/vcl/quartz/ctfonts.cxx index 2506d31c973d..ce44ca8e1e8e 100644 --- a/vcl/quartz/ctfonts.cxx +++ b/vcl/quartz/ctfonts.cxx @@ -21,6 +21,7 @@ #include "impfont.hxx" #include "outfont.hxx" +#include "PhysicalFontCollection.hxx" #include "sallayout.hxx" #ifdef MACOSX diff --git a/vcl/source/app/svmain.cxx b/vcl/source/app/svmain.cxx index 6d572b416dbf..3047488f4748 100644 --- a/vcl/source/app/svmain.cxx +++ b/vcl/source/app/svmain.cxx @@ -58,6 +58,7 @@ #include "idlemgr.hxx" #include "outdev.h" #include "outfont.hxx" +#include "PhysicalFontCollection.hxx" #include "print.h" #include "salsys.hxx" #include "saltimer.hxx" diff --git a/vcl/source/font/PhysicalFontCollection.cxx b/vcl/source/font/PhysicalFontCollection.cxx new file mode 100644 index 000000000000..6dcecc5d2766 --- /dev/null +++ b/vcl/source/font/PhysicalFontCollection.cxx @@ -0,0 +1,1362 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/types.h> + +#include <vector> + +#include <i18nlangtag/mslangid.hxx> + +#include <config_graphite.h> +#if ENABLE_GRAPHITE +#include "graphite_features.hxx" +#endif + +#include "magic.h" +#include "outdev.h" +#include "outfont.hxx" +#include "PhysicalFontFace.hxx" + +#include "PhysicalFontCollection.hxx" + +static OUString lcl_stripCharSetFromName(const OUString& _aName) +{ + // I worry that someone will have a font which *does* have + // e.g. "Greek" legitimately at the end of its name :-( + const char*suffixes[] = { " baltic", + " ce", + " cyr", + " greek", + " tur", + " (arabic)", + " (hebrew)", + " (thai)", + " (vietnamese)" + }; + + OUString aName = _aName; + // These can be crazily piled up, e.g. Times New Roman CYR Greek + bool bFinished = false; + while (!bFinished) + { + bFinished = true; + for (size_t i = 0; i < SAL_N_ELEMENTS(suffixes); ++i) + { + size_t nLen = strlen(suffixes[i]); + if (aName.endsWithIgnoreAsciiCaseAsciiL(suffixes[i], nLen)) + { + bFinished = false; + aName = aName.copy(0, aName.getLength() - nLen); + } + } + } + return aName; +} + +static unsigned lcl_IsCJKFont( const OUString& rFontName ) +{ + // Test, if Fontname includes CJK characters --> In this case we + // mention that it is a CJK font + for(int i = 0; i < rFontName.getLength(); i++) + { + const sal_Unicode ch = rFontName[i]; + // japanese + if ( ((ch >= 0x3040) && (ch <= 0x30FF)) || + ((ch >= 0x3190) && (ch <= 0x319F)) ) + return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_JP; + + // korean + if ( ((ch >= 0xAC00) && (ch <= 0xD7AF)) || + ((ch >= 0x3130) && (ch <= 0x318F)) || + ((ch >= 0x1100) && (ch <= 0x11FF)) ) + return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_KR; + + // chinese + if ( ((ch >= 0x3400) && (ch <= 0x9FFF)) ) + return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_TC|IMPL_FONT_ATTR_CJK_SC; + + // cjk + if ( ((ch >= 0x3000) && (ch <= 0xD7AF)) || + ((ch >= 0xFF00) && (ch <= 0xFFEE)) ) + return IMPL_FONT_ATTR_CJK; + + } + + return 0; +} + + +PhysicalFontCollection::PhysicalFontCollection() + : mbMatchData( false ) + , mbMapNames( false ) + , mpPreMatchHook( NULL ) + , mpFallbackHook( NULL ) + , mpFallbackList( NULL ) + , mnFallbackCount( -1 ) +{} + +PhysicalFontCollection::~PhysicalFontCollection() +{ + Clear(); +} + +void PhysicalFontCollection::SetPreMatchHook( ImplPreMatchFontSubstitution* pHook ) +{ + mpPreMatchHook = pHook; +} + +void PhysicalFontCollection::SetFallbackHook( ImplGlyphFallbackFontSubstitution* pHook ) +{ + mpFallbackHook = pHook; +} + +void PhysicalFontCollection::Clear() +{ + // remove fallback lists + delete[] mpFallbackList; + mpFallbackList = NULL; + mnFallbackCount = -1; + + // clear all entries in the device font list + PhysicalFontFamilies::iterator it = maPhysicalFontFamilies.begin(); + for(; it != maPhysicalFontFamilies.end(); ++it ) + { + PhysicalFontFamily* pEntry = (*it).second; + delete pEntry; + } + + maPhysicalFontFamilies.clear(); + + // match data must be recalculated too + mbMatchData = false; +} + +void PhysicalFontCollection::InitGenericGlyphFallback( void ) const +{ + // normalized family names of fonts suited for glyph fallback + // if a font is available related fonts can be ignored + // TODO: implement dynamic lists + static const char* aGlyphFallbackList[] = { + // empty strings separate the names of unrelated fonts + "eudc", "", + "arialunicodems", "cyberbit", "code2000", "", + "andalesansui", "", + "starsymbol", "opensymbol", "", + "msmincho", "fzmingti", "fzheiti", "ipamincho", "sazanamimincho", "kochimincho", "", + "sunbatang", "sundotum", "baekmukdotum", "gulim", "batang", "dotum", "", + "hgmincholightj", "msunglightsc", "msunglighttc", "hymyeongjolightk", "", + "tahoma", "dejavusans", "timesnewroman", "liberationsans", "", + "shree", "mangal", "", + "raavi", "shruti", "tunga", "", + "latha", "gautami", "kartika", "vrinda", "", + "shayyalmt", "naskmt", "scheherazade", "", + "david", "nachlieli", "lucidagrande", "", + "norasi", "angsanaupc", "", + "khmerossystem", "", + "muktinarrow", "", + "phetsarathot", "", + "padauk", "pinlonmyanmar", "", + "iskoolapota", "lklug", "", + 0 + }; + + bool bHasEudc = false; + int nMaxLevel = 0; + int nBestQuality = 0; + PhysicalFontFamily** pFallbackList = NULL; + + for( const char** ppNames = &aGlyphFallbackList[0];; ++ppNames ) + { + // advance to next sub-list when end-of-sublist marker + if( !**ppNames ) // #i46456# check for empty string, i.e., deref string itself not only ptr to it + { + if( nBestQuality > 0 ) + if( ++nMaxLevel >= MAX_FALLBACK ) + break; + + if( !ppNames[1] ) + break; + + nBestQuality = 0; + continue; + } + + // test if the glyph fallback candidate font is available and scalable + OUString aTokenName( *ppNames, strlen(*ppNames), RTL_TEXTENCODING_UTF8 ); + PhysicalFontFamily* pFallbackFont = FindFontFamily( aTokenName ); + + if( !pFallbackFont ) + continue; + + if( !pFallbackFont->IsScalable() ) + continue; + + // keep the best font of the glyph fallback sub-list + if( nBestQuality < pFallbackFont->GetMinQuality() ) + { + nBestQuality = pFallbackFont->GetMinQuality(); + // store available glyph fallback fonts + if( !pFallbackList ) + pFallbackList = new PhysicalFontFamily*[ MAX_FALLBACK ]; + + pFallbackList[ nMaxLevel ] = pFallbackFont; + if( !bHasEudc && !nMaxLevel ) + bHasEudc = !strncmp( *ppNames, "eudc", 5 ); + } + } + +#ifdef SAL_FONTENUM_STABLE_ON_PLATFORM // #i113472# + // sort the list of fonts for glyph fallback by quality (highest first) + // #i33947# keep the EUDC font at the front of the list + // an insertion sort is good enough for this short list + const int nSortStart = bHasEudc ? 1 : 0; + for( int i = nSortStart+1, j; i < nMaxLevel; ++i ) + { + PhysicalFontFamily* pTestFont = pFallbackList[ i ]; + int nTestQuality = pTestFont->GetMinQuality(); + + for( j = i; --j >= nSortStart; ) + { + if( nTestQuality > pFallbackList[j]->GetMinQuality() ) + pFallbackList[ j+1 ] = pFallbackList[ j ]; + else + break; + } + pFallbackList[ j+1 ] = pTestFont; + } +#endif + + mnFallbackCount = nMaxLevel; + mpFallbackList = pFallbackList; +} + +PhysicalFontFamily* PhysicalFontCollection::GetGlyphFallbackFont( FontSelectPattern& rFontSelData, + OUString& rMissingCodes, + int nFallbackLevel ) const +{ + PhysicalFontFamily* pFallbackData = NULL; + + // find a matching font candidate for platform specific glyph fallback + if( mpFallbackHook ) + { + // check cache for the first matching entry + // to avoid calling the expensive fallback hook (#i83491#) + sal_UCS4 cChar = 0; + bool bCached = true; + sal_Int32 nStrIndex = 0; + while( nStrIndex < rMissingCodes.getLength() ) + { + cChar = rMissingCodes.iterateCodePoints( &nStrIndex ); + bCached = rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName ); + + // ignore entries which don't have a fallback + if( !bCached || !rFontSelData.maSearchName.isEmpty() ) + break; + } + + if( bCached ) + { + // there is a matching fallback in the cache + // so update rMissingCodes with codepoints not yet resolved by this fallback + int nRemainingLength = 0; + sal_UCS4* pRemainingCodes = (sal_UCS4*)alloca( rMissingCodes.getLength() * sizeof(sal_UCS4) ); + OUString aFontName; + + while( nStrIndex < rMissingCodes.getLength() ) + { + cChar = rMissingCodes.iterateCodePoints( &nStrIndex ); + bCached = rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &aFontName ); + if( !bCached || (rFontSelData.maSearchName != aFontName) ) + pRemainingCodes[ nRemainingLength++ ] = cChar; + } + rMissingCodes = OUString( pRemainingCodes, nRemainingLength ); + } + else + { + OUString aOldMissingCodes = rMissingCodes; + + // call the hook to query the best matching glyph fallback font + if( mpFallbackHook->FindFontSubstitute( rFontSelData, rMissingCodes ) ) + // apply outdev3.cxx specific fontname normalization + GetEnglishSearchFontName( rFontSelData.maSearchName ); + else + rFontSelData.maSearchName = ""; + + // See fdo#32665 for an example. FreeSerif that has glyphs in normal + // font, but not in the italic or bold version + bool bSubSetOfFontRequiresPropertyFaking = rFontSelData.mbEmbolden || rFontSelData.maItalicMatrix != ItalicMatrix(); + + // Cache the result even if there was no match, unless its from part of a font for which the properties need + // to be faked. We need to rework this cache to take into account that fontconfig can return different fonts + // for different input sizes, weights, etc. Basically the cache is way to naive + if (!bSubSetOfFontRequiresPropertyFaking) + { + for(;;) + { + if( !rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName ) ) + rFontSelData.mpFontEntry->AddFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName ); + if( nStrIndex >= aOldMissingCodes.getLength() ) + break; + cChar = aOldMissingCodes.iterateCodePoints( &nStrIndex ); + } + if( !rFontSelData.maSearchName.isEmpty() ) + { + // remove cache entries that were still not resolved + for( nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); ) + { + cChar = rMissingCodes.iterateCodePoints( &nStrIndex ); + rFontSelData.mpFontEntry->IgnoreFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName ); + } + } + } + } + + // find the matching device font + if( !rFontSelData.maSearchName.isEmpty() ) + pFallbackData = FindFontFamily( rFontSelData.maSearchName ); + } + + // else find a matching font candidate for generic glyph fallback + if( !pFallbackData ) + { + // initialize font candidates for generic glyph fallback if needed + if( mnFallbackCount < 0 ) + InitGenericGlyphFallback(); + + // TODO: adjust nFallbackLevel by number of levels resolved by the fallback hook + if( nFallbackLevel < mnFallbackCount ) + pFallbackData = mpFallbackList[ nFallbackLevel ]; + } + + return pFallbackData; +} + +void PhysicalFontCollection::Add( PhysicalFontFace* pNewData ) +{ + OUString aSearchName = pNewData->GetFamilyName(); + GetEnglishSearchFontName( aSearchName ); + + PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.find( aSearchName ); + PhysicalFontFamily* pFoundData = NULL; + + if( it != maPhysicalFontFamilies.end() ) + pFoundData = (*it).second; + + if( !pFoundData ) + { + pFoundData = new PhysicalFontFamily( aSearchName ); + maPhysicalFontFamilies[ aSearchName ] = pFoundData; + } + + bool bKeepNewData = pFoundData->AddFontFace( pNewData ); + + if( !bKeepNewData ) + delete pNewData; +} + +// find the font from the normalized font family name +PhysicalFontFamily* PhysicalFontCollection::ImplFindBySearchName( const OUString& rSearchName ) const +{ +#ifdef DEBUG + OUString aTempName = rSearchName; + GetEnglishSearchFontName( aTempName ); + DBG_ASSERT( aTempName == rSearchName, "PhysicalFontCollection::ImplFindBySearchName() called with non-normalized name" ); +#endif + + PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.find( rSearchName ); + if( it == maPhysicalFontFamilies.end() ) + return NULL; + + PhysicalFontFamily* pFoundData = (*it).second; + return pFoundData; +} + +PhysicalFontFamily* PhysicalFontCollection::ImplFindByAliasName(const OUString& rSearchName, + const OUString& rShortName) const +{ + // short circuit for impossible font name alias + if (rSearchName.isEmpty()) + return NULL; + + // short circuit if no alias names are available + if (!mbMapNames) + return NULL; + + // use the font's alias names to find the font + // TODO: get rid of linear search + PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin(); + while( it != maPhysicalFontFamilies.end() ) + { + PhysicalFontFamily* pData = (*it).second; + if( pData->GetAliasNames().isEmpty() ) + continue; + + // if one alias name matches we found a matching font + OUString aTempName; + sal_Int32 nIndex = 0; + + do + { + aTempName = GetNextFontToken( pData->GetAliasNames(), nIndex ); + // Test, if the Font name match with one of the mapping names + if ( (aTempName == rSearchName) || (aTempName == rShortName) ) + return pData; + } + while ( nIndex != -1 ); + } + + return NULL; +} + +PhysicalFontFamily* PhysicalFontCollection::FindFontFamily( const OUString& rFontName ) const +{ + // normalize the font family name and + OUString aName = rFontName; + GetEnglishSearchFontName( aName ); + + PhysicalFontFamily* pFound = ImplFindBySearchName( aName ); + return pFound; +} + +PhysicalFontFamily* PhysicalFontCollection::ImplFindByTokenNames(const OUString& rTokenStr) const +{ + PhysicalFontFamily* pFoundData = NULL; + + // use normalized font name tokens to find the font + for( sal_Int32 nTokenPos = 0; nTokenPos != -1; ) + { + OUString aSearchName = GetNextFontToken( rTokenStr, nTokenPos ); + if( aSearchName.isEmpty() ) + continue; + + GetEnglishSearchFontName( aSearchName ); + pFoundData = ImplFindBySearchName( aSearchName ); + + if( pFoundData ) + break; + } + + return pFoundData; +} + +PhysicalFontFamily* PhysicalFontCollection::ImplFindBySubstFontAttr( const utl::FontNameAttr& rFontAttr ) const +{ + PhysicalFontFamily* pFoundData = NULL; + + // use the font substitutions suggested by the FontNameAttr to find the font + ::std::vector< OUString >::const_iterator it = rFontAttr.Substitutions.begin(); + for(; it != rFontAttr.Substitutions.end(); ++it ) + { + OUString aSearchName( *it ); + GetEnglishSearchFontName( aSearchName ); + + pFoundData = ImplFindBySearchName( aSearchName ); + if( pFoundData ) + return pFoundData; + } + + // use known attributes from the configuration to find a matching substitute + const sal_uLong nSearchType = rFontAttr.Type; + if( nSearchType != 0 ) + { + const FontWeight eSearchWeight = rFontAttr.Weight; + const FontWidth eSearchWidth = rFontAttr.Width; + const FontItalic eSearchSlant = ITALIC_DONTKNOW; + const OUString aSearchName; + + pFoundData = ImplFindByAttributes( nSearchType, + eSearchWeight, eSearchWidth, eSearchSlant, aSearchName ); + + if( pFoundData ) + return pFoundData; + } + + return NULL; +} + +void PhysicalFontCollection::InitMatchData() const +{ + // short circuit if already done + if( mbMatchData ) + return; + mbMatchData = true; + + // calculate MatchData for all entries + const utl::FontSubstConfiguration& rFontSubst = utl::FontSubstConfiguration::get(); + + PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin(); + for(; it != maPhysicalFontFamilies.end(); ++it ) + { + const OUString& rSearchName = (*it).first; + PhysicalFontFamily* pEntry = (*it).second; + + pEntry->InitMatchData( rFontSubst, rSearchName ); + } +} + +PhysicalFontFamily* PhysicalFontCollection::ImplFindByAttributes( sal_uLong nSearchType, + FontWeight eSearchWeight, + FontWidth eSearchWidth, + FontItalic eSearchItalic, + const OUString& rSearchFamilyName ) const +{ + if( (eSearchItalic != ITALIC_NONE) && (eSearchItalic != ITALIC_DONTKNOW) ) + nSearchType |= IMPL_FONT_ATTR_ITALIC; + + // don't bother to match attributes if the attributes aren't worth matching + if( !nSearchType + && ((eSearchWeight == WEIGHT_DONTKNOW) || (eSearchWeight == WEIGHT_NORMAL)) + && ((eSearchWidth == WIDTH_DONTKNOW) || (eSearchWidth == WIDTH_NORMAL)) ) + return NULL; + + InitMatchData(); + PhysicalFontFamily* pFoundData = NULL; + + long nTestMatch; + long nBestMatch = 40000; + sal_uLong nBestType = 0; + + PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin(); + for(; it != maPhysicalFontFamilies.end(); ++it ) + { + PhysicalFontFamily* pData = (*it).second; + + // Get all information about the matching font + sal_uLong nMatchType = pData->GetMatchType(); + FontWeight eMatchWeight= pData->GetMatchWeight(); + FontWidth eMatchWidth = pData->GetMatchWidth(); + + // Calculate Match Value + // 1000000000 + // 100000000 + // 10000000 CJK, CTL, None-Latin, Symbol + // 1000000 FamilyName, Script, Fixed, -Special, -Decorative, + // Titling, Capitals, Outline, Shadow + // 100000 Match FamilyName, Serif, SansSerif, Italic, + // Width, Weight + // 10000 Scalable, Standard, Default, + // full, Normal, Knownfont, + // Otherstyle, +Special, +Decorative, + // 1000 Typewriter, Rounded, Gothic, Schollbook + // 100 + nTestMatch = 0; + + // test CJK script attributes + if ( nSearchType & IMPL_FONT_ATTR_CJK ) + { + // Matching language + if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_CJK_ALLLANG) ) + nTestMatch += 10000000*3; + if( nMatchType & IMPL_FONT_ATTR_CJK ) + nTestMatch += 10000000*2; + if( nMatchType & IMPL_FONT_ATTR_FULL ) + nTestMatch += 10000000; + } + else if ( nMatchType & IMPL_FONT_ATTR_CJK ) + { + nTestMatch -= 10000000; + } + + // test CTL script attributes + if( nSearchType & IMPL_FONT_ATTR_CTL ) + { + if( nMatchType & IMPL_FONT_ATTR_CTL ) + nTestMatch += 10000000*2; + if( nMatchType & IMPL_FONT_ATTR_FULL ) + nTestMatch += 10000000; + } + else if ( nMatchType & IMPL_FONT_ATTR_CTL ) + { + nTestMatch -= 10000000; + } + + // test LATIN script attributes + if( nSearchType & IMPL_FONT_ATTR_NONELATIN ) + { + if( nMatchType & IMPL_FONT_ATTR_NONELATIN ) + nTestMatch += 10000000*2; + if( nMatchType & IMPL_FONT_ATTR_FULL ) + nTestMatch += 10000000; + } + + // test SYMBOL attributes + if ( nSearchType & IMPL_FONT_ATTR_SYMBOL ) + { + const OUString& rSearchName = it->first; + // prefer some special known symbol fonts + if ( rSearchName == "starsymbol" ) + { + nTestMatch += 10000000*6+(10000*3); + } + else if ( rSearchName == "opensymbol" ) + { + nTestMatch += 10000000*6; + } + else if ( rSearchName == "starbats" || + rSearchName == "wingdings" || + rSearchName == "monotypesorts" || + rSearchName == "dingbats" || + rSearchName == "zapfdingbats" ) + { + nTestMatch += 10000000*5; + } + else if ( pData->GetTypeFaces() & FONT_FAMILY_SYMBOL ) + { + nTestMatch += 10000000*4; + } + else + { + if( nMatchType & IMPL_FONT_ATTR_SYMBOL ) + nTestMatch += 10000000*2; + if( nMatchType & IMPL_FONT_ATTR_FULL ) + nTestMatch += 10000000; + } + } + else if ( (pData->GetTypeFaces() & (FONT_FAMILY_SYMBOL | FONT_FAMILY_NONESYMBOL)) == FONT_FAMILY_SYMBOL ) + { + nTestMatch -= 10000000; + } + else if ( nMatchType & IMPL_FONT_ATTR_SYMBOL ) + { + nTestMatch -= 10000; + } + + // match stripped family name + if( !rSearchFamilyName.isEmpty() && (rSearchFamilyName == pData->GetMatchFamilyName()) ) + { + nTestMatch += 1000000*3; + } + + // match ALLSCRIPT? attribute + if( nSearchType & IMPL_FONT_ATTR_ALLSCRIPT ) + { + if( nMatchType & IMPL_FONT_ATTR_ALLSCRIPT ) + { + nTestMatch += 1000000*2; + } + if( nSearchType & IMPL_FONT_ATTR_ALLSUBSCRIPT ) + { + if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_ALLSUBSCRIPT) ) + nTestMatch += 1000000*2; + if( 0 != ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_BRUSHSCRIPT) ) + nTestMatch -= 1000000; + } + } + else if( nMatchType & IMPL_FONT_ATTR_ALLSCRIPT ) + { + nTestMatch -= 1000000; + } + + // test MONOSPACE+TYPEWRITER attributes + if( nSearchType & IMPL_FONT_ATTR_FIXED ) + { + if( nMatchType & IMPL_FONT_ATTR_FIXED ) + nTestMatch += 1000000*2; + // a typewriter attribute is even better + if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_TYPEWRITER) ) + nTestMatch += 10000*2; + } + else if( nMatchType & IMPL_FONT_ATTR_FIXED ) + { + nTestMatch -= 1000000; + } + + // test SPECIAL attribute + if( nSearchType & IMPL_FONT_ATTR_SPECIAL ) + { + if( nMatchType & IMPL_FONT_ATTR_SPECIAL ) + { + nTestMatch += 10000; + } + else if( !(nSearchType & IMPL_FONT_ATTR_ALLSERIFSTYLE) ) + { + if( nMatchType & IMPL_FONT_ATTR_SERIF ) + { + nTestMatch += 1000*2; + } + else if( nMatchType & IMPL_FONT_ATTR_SANSSERIF ) + { + nTestMatch += 1000; + } + } + } + else if( (nMatchType & IMPL_FONT_ATTR_SPECIAL) && !(nSearchType & IMPL_FONT_ATTR_SYMBOL) ) + { + nTestMatch -= 1000000; + } + + // test DECORATIVE attribute + if( nSearchType & IMPL_FONT_ATTR_DECORATIVE ) + { + if( nMatchType & IMPL_FONT_ATTR_DECORATIVE ) + { + nTestMatch += 10000; + } + else if( !(nSearchType & IMPL_FONT_ATTR_ALLSERIFSTYLE) ) + { + if( nMatchType & IMPL_FONT_ATTR_SERIF ) + nTestMatch += 1000*2; + else if ( nMatchType & IMPL_FONT_ATTR_SANSSERIF ) + nTestMatch += 1000; + } + } + else if( nMatchType & IMPL_FONT_ATTR_DECORATIVE ) + { + nTestMatch -= 1000000; + } + + // test TITLE+CAPITALS attributes + if( nSearchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) ) + { + if( nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) ) + { + nTestMatch += 1000000*2; + } + if( 0 == ((nSearchType^nMatchType) & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS))) + { + nTestMatch += 1000000; + } + else if( (nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS)) && + (nMatchType & (IMPL_FONT_ATTR_STANDARD | IMPL_FONT_ATTR_DEFAULT)) ) + { + nTestMatch += 1000000; + } + } + else if( nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) ) + { + nTestMatch -= 1000000; + } + + // test OUTLINE+SHADOW attributes + if( nSearchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) ) + { + if( nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) ) + { + nTestMatch += 1000000*2; + } + if( 0 == ((nSearchType ^ nMatchType) & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW)) ) + { + nTestMatch += 1000000; + } + else if( (nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW)) && + (nMatchType & (IMPL_FONT_ATTR_STANDARD | IMPL_FONT_ATTR_DEFAULT)) ) + { + nTestMatch += 1000000; + } + } + else if ( nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) ) + { + nTestMatch -= 1000000; + } + + // test font name substrings + // TODO: calculate name matching score using e.g. Levenstein distance + if( (rSearchFamilyName.getLength() >= 4) && + (pData->GetMatchFamilyName().getLength() >= 4) && + ((rSearchFamilyName.indexOf( pData->GetMatchFamilyName() ) != -1) || + (pData->GetMatchFamilyName().indexOf( rSearchFamilyName ) != -1)) ) + { + nTestMatch += 5000; + } + // test SERIF attribute + if( nSearchType & IMPL_FONT_ATTR_SERIF ) + { + if( nMatchType & IMPL_FONT_ATTR_SERIF ) + nTestMatch += 1000000*2; + else if( nMatchType & IMPL_FONT_ATTR_SANSSERIF ) + nTestMatch -= 1000000; + } + + // test SANSERIF attribute + if( nSearchType & IMPL_FONT_ATTR_SANSSERIF ) + { + if( nMatchType & IMPL_FONT_ATTR_SANSSERIF ) + nTestMatch += 1000000; + else if ( nMatchType & IMPL_FONT_ATTR_SERIF ) + nTestMatch -= 1000000; + } + + // test ITALIC attribute + if( nSearchType & IMPL_FONT_ATTR_ITALIC ) + { + if( pData->GetTypeFaces() & FONT_FAMILY_ITALIC ) + nTestMatch += 1000000*3; + if( nMatchType & IMPL_FONT_ATTR_ITALIC ) + nTestMatch += 1000000; + } + else if( !(nSearchType & IMPL_FONT_ATTR_ALLSCRIPT) && + ((nMatchType & IMPL_FONT_ATTR_ITALIC) || + !(pData->GetTypeFaces() & FONT_FAMILY_NONEITALIC)) ) + { + nTestMatch -= 1000000*2; + } + + // test WIDTH attribute + if( (eSearchWidth != WIDTH_DONTKNOW) && (eSearchWidth != WIDTH_NORMAL) ) + { + if( eSearchWidth < WIDTH_NORMAL ) + { + if( eSearchWidth == eMatchWidth ) + nTestMatch += 1000000*3; + else if( (eMatchWidth < WIDTH_NORMAL) && (eMatchWidth != WIDTH_DONTKNOW) ) + nTestMatch += 1000000; + } + else + { + if( eSearchWidth == eMatchWidth ) + nTestMatch += 1000000*3; + else if( eMatchWidth > WIDTH_NORMAL ) + nTestMatch += 1000000; + } + } + else if( (eMatchWidth != WIDTH_DONTKNOW) && (eMatchWidth != WIDTH_NORMAL) ) + { + nTestMatch -= 1000000; + } + + // test WEIGHT attribute + if( (eSearchWeight != WEIGHT_DONTKNOW) && + (eSearchWeight != WEIGHT_NORMAL) && + (eSearchWeight != WEIGHT_MEDIUM) ) + { + if( eSearchWeight < WEIGHT_NORMAL ) + { + if( pData->GetTypeFaces() & FONT_FAMILY_LIGHT ) + nTestMatch += 1000000; + if( (eMatchWeight < WEIGHT_NORMAL) && (eMatchWeight != WEIGHT_DONTKNOW) ) + nTestMatch += 1000000; + } + else + { + if( pData->GetTypeFaces() & FONT_FAMILY_BOLD ) + nTestMatch += 1000000; + if( eMatchWeight > WEIGHT_BOLD ) + nTestMatch += 1000000; + } + } + else if( ((eMatchWeight != WEIGHT_DONTKNOW) && + (eMatchWeight != WEIGHT_NORMAL) && + (eMatchWeight != WEIGHT_MEDIUM)) || + !(pData->GetTypeFaces() & FONT_FAMILY_NORMAL) ) + { + nTestMatch -= 1000000; + } + + // prefer scalable fonts + if( pData->GetTypeFaces() & FONT_FAMILY_SCALABLE ) + nTestMatch += 10000*4; + else + nTestMatch -= 10000*4; + + // test STANDARD+DEFAULT+FULL+NORMAL attributes + if( nMatchType & IMPL_FONT_ATTR_STANDARD ) + nTestMatch += 10000*2; + if( nMatchType & IMPL_FONT_ATTR_DEFAULT ) + nTestMatch += 10000; + if( nMatchType & IMPL_FONT_ATTR_FULL ) + nTestMatch += 10000; + if( nMatchType & IMPL_FONT_ATTR_NORMAL ) + nTestMatch += 10000; + + // test OTHERSTYLE attribute + if( ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_OTHERSTYLE) != 0 ) + { + nTestMatch -= 10000; + } + + // test ROUNDED attribute + if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_ROUNDED) ) + nTestMatch += 1000; + + // test TYPEWRITER attribute + if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_TYPEWRITER) ) + nTestMatch += 1000; + + // test GOTHIC attribute + if( nSearchType & IMPL_FONT_ATTR_GOTHIC ) + { + if( nMatchType & IMPL_FONT_ATTR_GOTHIC ) + nTestMatch += 1000*3; + if( nMatchType & IMPL_FONT_ATTR_SANSSERIF ) + nTestMatch += 1000*2; + } + + // test SCHOOLBOOK attribute + if( nSearchType & IMPL_FONT_ATTR_SCHOOLBOOK ) + { + if( nMatchType & IMPL_FONT_ATTR_SCHOOLBOOK ) + nTestMatch += 1000*3; + if( nMatchType & IMPL_FONT_ATTR_SERIF ) + nTestMatch += 1000*2; + } + + // compare with best matching font yet + if ( nTestMatch > nBestMatch ) + { + pFoundData = pData; + nBestMatch = nTestMatch; + nBestType = nMatchType; + } + else if( nTestMatch == nBestMatch ) + { + // some fonts are more suitable defaults + if( nMatchType & IMPL_FONT_ATTR_DEFAULT ) + { + pFoundData = pData; + nBestType = nMatchType; + } + else if( (nMatchType & IMPL_FONT_ATTR_STANDARD) && + !(nBestType & IMPL_FONT_ATTR_DEFAULT) ) + { + pFoundData = pData; + nBestType = nMatchType; + } + } + } + + return pFoundData; +} + +PhysicalFontFamily* PhysicalFontCollection::FindDefaultFont() const +{ + // try to find one of the default fonts of the + // UNICODE, SANSSERIF, SERIF or FIXED default font lists + const utl::DefaultFontConfiguration& rDefaults = utl::DefaultFontConfiguration::get(); + LanguageTag aLanguageTag( OUString( "en")); + OUString aFontname = rDefaults.getDefaultFont( aLanguageTag, DEFAULTFONT_SANS_UNICODE ); + PhysicalFontFamily* pFoundData = ImplFindByTokenNames( aFontname ); + + if( pFoundData ) + return pFoundData; + + aFontname = rDefaults.getDefaultFont( aLanguageTag, DEFAULTFONT_SANS ); + pFoundData = ImplFindByTokenNames( aFontname ); + if( pFoundData ) + return pFoundData; + + aFontname = rDefaults.getDefaultFont( aLanguageTag, DEFAULTFONT_SERIF ); + pFoundData = ImplFindByTokenNames( aFontname ); + if( pFoundData ) + return pFoundData; + + aFontname = rDefaults.getDefaultFont( aLanguageTag, DEFAULTFONT_FIXED ); + pFoundData = ImplFindByTokenNames( aFontname ); + if( pFoundData ) + return pFoundData; + + // now try to find a reasonable non-symbol font + + InitMatchData(); + + PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin(); + for(; it != maPhysicalFontFamilies.end(); ++it ) + { + PhysicalFontFamily* pData = (*it).second; + if( pData->GetMatchType() & IMPL_FONT_ATTR_SYMBOL ) + continue; + + pFoundData = pData; + if( pData->GetMatchType() & (IMPL_FONT_ATTR_DEFAULT|IMPL_FONT_ATTR_STANDARD) ) + break; + } + if( pFoundData ) + return pFoundData; + + // finding any font is better than finding no font at all + it = maPhysicalFontFamilies.begin(); + if( it != maPhysicalFontFamilies.end() ) + pFoundData = (*it).second; + + return pFoundData; +} + +PhysicalFontCollection* PhysicalFontCollection::Clone( bool bScalable, bool bEmbeddable ) const +{ + PhysicalFontCollection* pClonedCollection = new PhysicalFontCollection; + pClonedCollection->mbMapNames = mbMapNames; + pClonedCollection->mpPreMatchHook = mpPreMatchHook; + pClonedCollection->mpFallbackHook = mpFallbackHook; + + // TODO: clone the config-font attributes too? + pClonedCollection->mbMatchData = false; + + PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin(); + for(; it != maPhysicalFontFamilies.end(); ++it ) + { + const PhysicalFontFamily* pFontFace = (*it).second; + pFontFace->UpdateCloneFontList( *pClonedCollection, bScalable, bEmbeddable ); + } + + return pClonedCollection; +} + +ImplGetDevFontList* PhysicalFontCollection::GetDevFontList() const +{ + ImplGetDevFontList* pGetDevFontList = new ImplGetDevFontList; + + PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin(); + for(; it != maPhysicalFontFamilies.end(); ++it ) + { + const PhysicalFontFamily* pFontFamily = (*it).second; + pFontFamily->UpdateDevFontList( *pGetDevFontList ); + } + + return pGetDevFontList; +} + +ImplGetDevSizeList* PhysicalFontCollection::GetDevSizeList( const OUString& rFontName ) const +{ + ImplGetDevSizeList* pGetDevSizeList = new ImplGetDevSizeList( rFontName ); + + PhysicalFontFamily* pFontFamily = FindFontFamily( rFontName ); + if( pFontFamily != NULL ) + { + std::set<int> rHeights; + pFontFamily->GetFontHeights( rHeights ); + + std::set<int>::const_iterator it = rHeights.begin(); + for(; it != rHeights.begin(); ++it ) + pGetDevSizeList->Add( *it ); + } + + return pGetDevSizeList; +} + +PhysicalFontFamily* PhysicalFontCollection::ImplFindByFont( FontSelectPattern& rFSD ) const +{ + // give up if no fonts are available + if( !Count() ) + return NULL; + + bool bMultiToken = false; + sal_Int32 nTokenPos = 0; + OUString& aSearchName = rFSD.maSearchName; // TODO: get rid of reference + for(;;) + { + rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos ); + aSearchName = rFSD.maTargetName; + +#if ENABLE_GRAPHITE + // Until features are properly supported, they are appended to the + // font name, so we need to strip them off so the font is found. + sal_Int32 nFeat = aSearchName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX); + OUString aOrigName = rFSD.maTargetName; + OUString aBaseFontName = aSearchName.copy( 0, (nFeat != -1) ? nFeat : aSearchName.getLength() ); + + if (nFeat != -1 && + -1 != aSearchName.indexOf(grutils::GrFeatureParser::FEAT_ID_VALUE_SEPARATOR, nFeat)) + { + aSearchName = aBaseFontName; + rFSD.maTargetName = aBaseFontName; + } + +#endif + + GetEnglishSearchFontName( aSearchName ); + ImplFontSubstitute( aSearchName ); + // #114999# special emboldening for Ricoh fonts + // TODO: smarter check for special cases by using PreMatch infrastructure? + if( (rFSD.GetWeight() > WEIGHT_MEDIUM) && + aSearchName.startsWithIgnoreAsciiCase( "hg" ) ) + { + OUString aBoldName; + if( aSearchName.startsWithIgnoreAsciiCase( "hggothicb" ) ) + aBoldName = "hggothice"; + else if( aSearchName.startsWithIgnoreAsciiCase( "hgpgothicb" ) ) + aBoldName = "hgpgothice"; + else if( aSearchName.startsWithIgnoreAsciiCase( "hgminchol" ) ) + aBoldName = "hgminchob"; + else if( aSearchName.startsWithIgnoreAsciiCase( "hgpminchol" ) ) + aBoldName = "hgpminchob"; + else if( aSearchName.equalsIgnoreAsciiCase( "hgminchob" ) ) + aBoldName = "hgminchoe"; + else if( aSearchName.equalsIgnoreAsciiCase( "hgpminchob" ) ) + aBoldName = "hgpminchoe"; + + if( !aBoldName.isEmpty() && ImplFindBySearchName( aBoldName ) ) + { + // the other font is available => use it + aSearchName = aBoldName; + // prevent synthetic emboldening of bold version + rFSD.SetWeight(WEIGHT_DONTKNOW); + } + } + +#if ENABLE_GRAPHITE + // restore the features to make the font selection data unique + rFSD.maTargetName = aOrigName; +#endif + // check if the current font name token or its substitute is valid + PhysicalFontFamily* pFoundData = ImplFindBySearchName( aSearchName ); + if( pFoundData ) + return pFoundData; + + // some systems provide special customization + // e.g. they suggest "serif" as UI-font, but this name cannot be used directly + // because the system wants to map it to another font first, e.g. "Helvetica" +#if ENABLE_GRAPHITE + // use the target name to search in the prematch hook + rFSD.maTargetName = aBaseFontName; +#endif + + // Related: fdo#49271 RTF files often contain weird-ass + // Win 3.1/Win95 style fontnames which attempt to put the + // charset encoding into the filename + // http://www.webcenter.ru/~kazarn/eng/fonts_ttf.htm + OUString sStrippedName = lcl_stripCharSetFromName(rFSD.maTargetName); + if (sStrippedName != rFSD.maTargetName) + { + rFSD.maTargetName = sStrippedName; + aSearchName = rFSD.maTargetName; + GetEnglishSearchFontName(aSearchName); + pFoundData = ImplFindBySearchName(aSearchName); + if( pFoundData ) + return pFoundData; + } + + if( mpPreMatchHook ) + { + if( mpPreMatchHook->FindFontSubstitute( rFSD ) ) + GetEnglishSearchFontName( aSearchName ); + } +#if ENABLE_GRAPHITE + // the prematch hook uses the target name to search, but we now need + // to restore the features to make the font selection data unique + rFSD.maTargetName = aOrigName; +#endif + pFoundData = ImplFindBySearchName( aSearchName ); + if( pFoundData ) + return pFoundData; + + // break after last font name token was checked unsuccessfully + if( nTokenPos == -1) + break; + bMultiToken = true; + } + + // if the first font was not available find the next available font in + // the semicolon separated list of font names. A font is also considered + // available when there is a matching entry in the Tools->Options->Fonts + // dialog witho neither ALWAYS nor SCREENONLY flags set and the substitution + // font is available + for( nTokenPos = 0; nTokenPos != -1; ) + { + if( bMultiToken ) + { + rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos ); + aSearchName = rFSD.maTargetName; + GetEnglishSearchFontName( aSearchName ); + } + else + nTokenPos = -1; + if( mpPreMatchHook ) + if( mpPreMatchHook->FindFontSubstitute( rFSD ) ) + GetEnglishSearchFontName( aSearchName ); + ImplFontSubstitute( aSearchName ); + PhysicalFontFamily* pFoundData = ImplFindBySearchName( aSearchName ); + if( pFoundData ) + return pFoundData; + } + + // if no font with a directly matching name is available use the + // first font name token and get its attributes to find a replacement + if ( bMultiToken ) + { + nTokenPos = 0; + rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos ); + aSearchName = rFSD.maTargetName; + GetEnglishSearchFontName( aSearchName ); + } + + OUString aSearchShortName; + OUString aSearchFamilyName; + FontWeight eSearchWeight = rFSD.GetWeight(); + FontWidth eSearchWidth = rFSD.GetWidthType(); + sal_uLong nSearchType = 0; + utl::FontSubstConfiguration::getMapName( aSearchName, aSearchShortName, aSearchFamilyName, + eSearchWeight, eSearchWidth, nSearchType ); + + // note: the search name was already translated to english (if possible) + // use the font's shortened name if needed + if ( aSearchShortName != aSearchName ) + { + PhysicalFontFamily* pFoundData = ImplFindBySearchName( aSearchShortName ); + if( pFoundData ) + { +#ifdef UNX + /* #96738# don't use mincho as an replacement for "MS Mincho" on X11: Mincho is + a korean bitmap font that is not suitable here. Use the font replacement table, + that automatically leads to the desired "HG Mincho Light J". Same story for + MS Gothic, there are thai and korean "Gothic" fonts, so we even prefer Andale */ + static OUString aMS_Mincho( "msmincho" ); + static OUString aMS_Gothic( "msgothic" ); + if ((aSearchName != aMS_Mincho) && (aSearchName != aMS_Gothic)) + // TODO: add heuristic to only throw out the fake ms* fonts +#endif + { + return pFoundData; + } + } + } + + // use font fallback + const utl::FontNameAttr* pFontAttr = NULL; + if( !aSearchName.isEmpty() ) + { + // get fallback info using FontSubstConfiguration and + // the target name, it's shortened name and family name in that order + const utl::FontSubstConfiguration& rFontSubst = utl::FontSubstConfiguration::get(); + pFontAttr = rFontSubst.getSubstInfo( aSearchName ); + if ( !pFontAttr && (aSearchShortName != aSearchName) ) + pFontAttr = rFontSubst.getSubstInfo( aSearchShortName ); + if ( !pFontAttr && (aSearchFamilyName != aSearchShortName) ) + pFontAttr = rFontSubst.getSubstInfo( aSearchFamilyName ); + + // try the font substitutions suggested by the fallback info + if( pFontAttr ) + { + PhysicalFontFamily* pFoundData = ImplFindBySubstFontAttr( *pFontAttr ); + if( pFoundData ) + return pFoundData; + } + } + + // if a target symbol font is not available use a default symbol font + if( rFSD.IsSymbolFont() ) + { + LanguageTag aDefaultLanguageTag( OUString( "en")); + aSearchName = utl::DefaultFontConfiguration::get().getDefaultFont( aDefaultLanguageTag, DEFAULTFONT_SYMBOL ); + PhysicalFontFamily* pFoundData = ImplFindByTokenNames( aSearchName ); + if( pFoundData ) + return pFoundData; + } + + // now try the other font name tokens + while( nTokenPos != -1 ) + { + rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos ); + if( rFSD.maTargetName.isEmpty() ) + continue; + + aSearchName = rFSD.maTargetName; + GetEnglishSearchFontName( aSearchName ); + + OUString aTempShortName; + OUString aTempFamilyName; + sal_uLong nTempType = 0; + FontWeight eTempWeight = rFSD.GetWeight(); + FontWidth eTempWidth = WIDTH_DONTKNOW; + utl::FontSubstConfiguration::getMapName( aSearchName, aTempShortName, aTempFamilyName, + eTempWeight, eTempWidth, nTempType ); + + // use a shortend token name if available + if( aTempShortName != aSearchName ) + { + PhysicalFontFamily* pFoundData = ImplFindBySearchName( aTempShortName ); + if( pFoundData ) + return pFoundData; + } + + // use a font name from font fallback list to determine font attributes + // get fallback info using FontSubstConfiguration and + // the target name, it's shortened name and family name in that order + const utl::FontSubstConfiguration& rFontSubst = utl::FontSubstConfiguration::get(); + const utl::FontNameAttr* pTempFontAttr = rFontSubst.getSubstInfo( aSearchName ); + + if ( !pTempFontAttr && (aTempShortName != aSearchName) ) + pTempFontAttr = rFontSubst.getSubstInfo( aTempShortName ); + + if ( !pTempFontAttr && (aTempFamilyName != aTempShortName) ) + pTempFontAttr = rFontSubst.getSubstInfo( aTempFamilyName ); + + // try the font substitutions suggested by the fallback info + if( pTempFontAttr ) + { + PhysicalFontFamily* pFoundData = ImplFindBySubstFontAttr( *pTempFontAttr ); + if( pFoundData ) + return pFoundData; + if( !pFontAttr ) + pFontAttr = pTempFontAttr; + } + } + + // if still needed use the alias names of the installed fonts + if( mbMapNames ) + { + PhysicalFontFamily* pFoundData = ImplFindByAliasName( rFSD.maTargetName, aSearchShortName ); + if( pFoundData ) + return pFoundData; + } + + // if still needed use the font request's attributes to find a good match + if (MsLangId::isSimplifiedChinese(rFSD.meLanguage)) + nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_SC; + else if (MsLangId::isTraditionalChinese(rFSD.meLanguage)) + nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_TC; + else if (MsLangId::isKorean(rFSD.meLanguage)) + nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_KR; + else if (rFSD.meLanguage == LANGUAGE_JAPANESE) + nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_JP; + else + { + nSearchType |= lcl_IsCJKFont( rFSD.GetFamilyName() ); + if( rFSD.IsSymbolFont() ) + nSearchType |= IMPL_FONT_ATTR_SYMBOL; + } + + PhysicalFontFamily::CalcType( nSearchType, eSearchWeight, eSearchWidth, rFSD.GetFamilyType(), pFontAttr ); + PhysicalFontFamily* pFoundData = ImplFindByAttributes( nSearchType, + eSearchWeight, eSearchWidth, rFSD.GetSlant(), aSearchFamilyName ); + + if( pFoundData ) + { + // overwrite font selection attributes using info from the typeface flags + if( (eSearchWeight >= WEIGHT_BOLD) && + (eSearchWeight > rFSD.GetWeight()) && + (pFoundData->GetTypeFaces() & FONT_FAMILY_BOLD) ) + { + rFSD.SetWeight( eSearchWeight ); + } + else if( (eSearchWeight < WEIGHT_NORMAL) && + (eSearchWeight < rFSD.GetWeight()) && + (eSearchWeight != WEIGHT_DONTKNOW) && + (pFoundData->GetTypeFaces() & FONT_FAMILY_LIGHT) ) + { + rFSD.SetWeight( eSearchWeight ); + } + + if( (nSearchType & IMPL_FONT_ATTR_ITALIC) && + ((rFSD.GetSlant() == ITALIC_DONTKNOW) || + (rFSD.GetSlant() == ITALIC_NONE)) && + (pFoundData->GetTypeFaces() & FONT_FAMILY_ITALIC) ) + { + rFSD.SetItalic( ITALIC_NORMAL ); + } + } + else + { + // if still needed fall back to default fonts + pFoundData = FindDefaultFont(); + } + + return pFoundData; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ + diff --git a/vcl/source/font/PhysicalFontFamily.cxx b/vcl/source/font/PhysicalFontFamily.cxx new file mode 100644 index 000000000000..f0f33071b1b3 --- /dev/null +++ b/vcl/source/font/PhysicalFontFamily.cxx @@ -0,0 +1,298 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/types.h> + +#include <rtl/ustring.hxx> + +#include "outdev.h" +#include "PhysicalFontFace.hxx" +#include "PhysicalFontCollection.hxx" + +#include "PhysicalFontFamily.hxx" + +void PhysicalFontFamily::CalcType( sal_uLong& rType, FontWeight& rWeight, FontWidth& rWidth, + FontFamily eFamily, const utl::FontNameAttr* pFontAttr ) +{ + if ( eFamily != FAMILY_DONTKNOW ) + { + if ( eFamily == FAMILY_SWISS ) + rType |= IMPL_FONT_ATTR_SANSSERIF; + else if ( eFamily == FAMILY_ROMAN ) + rType |= IMPL_FONT_ATTR_SERIF; + else if ( eFamily == FAMILY_SCRIPT ) + rType |= IMPL_FONT_ATTR_SCRIPT; + else if ( eFamily == FAMILY_MODERN ) + rType |= IMPL_FONT_ATTR_FIXED; + else if ( eFamily == FAMILY_DECORATIVE ) + rType |= IMPL_FONT_ATTR_DECORATIVE; + } + + if ( pFontAttr ) + { + rType |= pFontAttr->Type; + + if ( ((rWeight == WEIGHT_DONTKNOW) || (rWeight == WEIGHT_NORMAL)) && + (pFontAttr->Weight != WEIGHT_DONTKNOW) ) + rWeight = pFontAttr->Weight; + if ( ((rWidth == WIDTH_DONTKNOW) || (rWidth == WIDTH_NORMAL)) && + (pFontAttr->Width != WIDTH_DONTKNOW) ) + rWidth = pFontAttr->Width; + } +} + +static unsigned lcl_IsCJKFont( const OUString& rFontName ) +{ + // Test, if Fontname includes CJK characters --> In this case we + // mention that it is a CJK font + for(int i = 0; i < rFontName.getLength(); i++) + { + const sal_Unicode ch = rFontName[i]; + // japanese + if ( ((ch >= 0x3040) && (ch <= 0x30FF)) || + ((ch >= 0x3190) && (ch <= 0x319F)) ) + return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_JP; + + // korean + if ( ((ch >= 0xAC00) && (ch <= 0xD7AF)) || + ((ch >= 0x3130) && (ch <= 0x318F)) || + ((ch >= 0x1100) && (ch <= 0x11FF)) ) + return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_KR; + + // chinese + if ( ((ch >= 0x3400) && (ch <= 0x9FFF)) ) + return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_TC|IMPL_FONT_ATTR_CJK_SC; + + // cjk + if ( ((ch >= 0x3000) && (ch <= 0xD7AF)) || + ((ch >= 0xFF00) && (ch <= 0xFFEE)) ) + return IMPL_FONT_ATTR_CJK; + + } + + return 0; +} + + +PhysicalFontFamily::PhysicalFontFamily( const OUString& rSearchName ) +: mpFirst( NULL ), + maSearchName( rSearchName ), + mnTypeFaces( 0 ), + mnMatchType( 0 ), + meMatchWeight( WEIGHT_DONTKNOW ), + meMatchWidth( WIDTH_DONTKNOW ), + meFamily( FAMILY_DONTKNOW ), + mePitch( PITCH_DONTKNOW ), + mnMinQuality( -1 ) +{} + +PhysicalFontFamily::~PhysicalFontFamily() +{ + // release all physical font faces + while( mpFirst ) + { + PhysicalFontFace* pFace = mpFirst; + mpFirst = pFace->GetNextFace(); + delete pFace; + } +} + +bool PhysicalFontFamily::AddFontFace( PhysicalFontFace* pNewData ) +{ + pNewData->mpNext = NULL; + + if( !mpFirst ) + { + maName = pNewData->GetFamilyName(); + maMapNames = pNewData->maMapNames; + meFamily = pNewData->GetFamilyType(); + mePitch = pNewData->GetPitch(); + mnMinQuality = pNewData->mnQuality; + } + else + { + if( meFamily == FAMILY_DONTKNOW ) + meFamily = pNewData->GetFamilyType(); + if( mePitch == PITCH_DONTKNOW ) + mePitch = pNewData->GetPitch(); + if( mnMinQuality > pNewData->mnQuality ) + mnMinQuality = pNewData->mnQuality; + } + + // set attributes for attribute based font matching + if( pNewData->IsScalable() ) + mnTypeFaces |= FONT_FAMILY_SCALABLE; + + if( pNewData->IsSymbolFont() ) + mnTypeFaces |= FONT_FAMILY_SYMBOL; + else + mnTypeFaces |= FONT_FAMILY_NONESYMBOL; + + if( pNewData->GetWeight() != WEIGHT_DONTKNOW ) + { + if( pNewData->GetWeight() >= WEIGHT_SEMIBOLD ) + mnTypeFaces |= FONT_FAMILY_BOLD; + else if( pNewData->GetWeight() <= WEIGHT_SEMILIGHT ) + mnTypeFaces |= FONT_FAMILY_LIGHT; + else + mnTypeFaces |= FONT_FAMILY_NORMAL; + } + + if( pNewData->GetSlant() == ITALIC_NONE ) + mnTypeFaces |= FONT_FAMILY_NONEITALIC; + else if( (pNewData->GetSlant() == ITALIC_NORMAL) + || (pNewData->GetSlant() == ITALIC_OBLIQUE) ) + mnTypeFaces |= FONT_FAMILY_ITALIC; + + if( (meMatchWeight == WEIGHT_DONTKNOW) + || (meMatchWidth == WIDTH_DONTKNOW) + || (mnMatchType == 0) ) + { + // TODO: is it cheaper to calc matching attributes now or on demand? + // calc matching attributes if other entries are already initialized + + // Do lazy, quite expensive, not needed in start-up! + // const FontSubstConfiguration& rFontSubst = *FontSubstConfiguration::get(); + // InitMatchData( rFontSubst, maSearchName ); + // mbMatchData=true; // Somewhere else??? + } + + // reassign name (sharing saves memory) + if( pNewData->GetFamilyName() == GetFamilyName() ) + pNewData->SetFamilyName( GetFamilyName() ); + + // insert new physical font face into linked list + // TODO: get rid of linear search? + PhysicalFontFace* pData; + PhysicalFontFace** ppHere = &mpFirst; + for(; (pData=*ppHere) != NULL; ppHere=&pData->mpNext ) + { + sal_Int32 eComp = pNewData->CompareWithSize( *pData ); + if( eComp > 0 ) + continue; + if( eComp < 0 ) + break; + + // ignore duplicate if its quality is worse + if( pNewData->mnQuality < pData->mnQuality ) + return false; + + // keep the device font if its quality is good enough + if( (pNewData->mnQuality == pData->mnQuality) + && (pData->mbDevice || !pNewData->mbDevice) ) + return false; + + // replace existing font face with a better one + pNewData->mpNext = pData->mpNext; + *ppHere = pNewData; + delete pData; + return true; + } + + // insert into or append to list of physical font faces + pNewData->mpNext = pData; + *ppHere = pNewData; + return true; +} + +// get font attributes using the normalized font family name +void PhysicalFontFamily::InitMatchData( const utl::FontSubstConfiguration& rFontSubst, + const OUString& rSearchName ) +{ + OUString aShortName; + OUString aMatchFamilyName(maMatchFamilyName); + // get font attributes from the decorated font name + rFontSubst.getMapName( rSearchName, aShortName, aMatchFamilyName, + meMatchWeight, meMatchWidth, mnMatchType ); + maMatchFamilyName = aMatchFamilyName; + const utl::FontNameAttr* pFontAttr = rFontSubst.getSubstInfo( rSearchName ); + // eventually use the stripped name + if( !pFontAttr ) + if( aShortName != rSearchName ) + pFontAttr = rFontSubst.getSubstInfo( aShortName ); + CalcType( mnMatchType, meMatchWeight, meMatchWidth, meFamily, pFontAttr ); + mnMatchType |= lcl_IsCJKFont( maName ); +} + +PhysicalFontFace* PhysicalFontFamily::FindBestFontFace( const FontSelectPattern& rFSD ) const +{ + if( !mpFirst ) + return NULL; + if( !mpFirst->GetNextFace() ) + return mpFirst; + + // FontName+StyleName should map to FamilyName+StyleName + const OUString& rSearchName = rFSD.maTargetName; + OUString aTargetStyleName; + const OUString* pTargetStyleName = NULL; + if( (rSearchName.getLength() > maSearchName.getLength()) + && rSearchName.startsWith( maSearchName ) ) + { + aTargetStyleName = rSearchName.copy(maSearchName.getLength() + 1); + pTargetStyleName = &aTargetStyleName; + } + + // TODO: linear search improve! + PhysicalFontFace* pFontFace = mpFirst; + PhysicalFontFace* pBestFontFace = pFontFace; + FontMatchStatus aFontMatchStatus = {0,0,0, pTargetStyleName}; + for(; pFontFace; pFontFace = pFontFace->GetNextFace() ) + if( pFontFace->IsBetterMatch( rFSD, aFontMatchStatus ) ) + pBestFontFace = pFontFace; + + return pBestFontFace; +} + +// update device font list with unique font faces, with uniqueness +// meaning different font attributes, but not different fonts sizes +void PhysicalFontFamily::UpdateDevFontList( ImplGetDevFontList& rDevFontList ) const +{ + PhysicalFontFace* pPrevFace = NULL; + for( PhysicalFontFace* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() ) + { + if( !pPrevFace || pFace->CompareIgnoreSize( *pPrevFace ) ) + rDevFontList.Add( pFace ); + pPrevFace = pFace; + } +} + +void PhysicalFontFamily::GetFontHeights( std::set<int>& rHeights ) const +{ + // add all available font heights + for( const PhysicalFontFace* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() ) + rHeights.insert( pFace->GetHeight() ); +} + +void PhysicalFontFamily::UpdateCloneFontList( PhysicalFontCollection& rFontCollection, + bool bScalable, bool bEmbeddable ) const +{ + for( PhysicalFontFace* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() ) + { + if( bScalable && !pFace->IsScalable() ) + continue; + if( bEmbeddable && !pFace->IsEmbeddable() && !pFace->IsSubsettable() ) + continue; + + PhysicalFontFace* pClonedFace = pFace->Clone(); + rFontCollection.Add( pClonedFace ); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/gdi/embeddedfontshelper.cxx b/vcl/source/gdi/embeddedfontshelper.cxx index 3e4d94694638..05730b7cc959 100644 --- a/vcl/source/gdi/embeddedfontshelper.cxx +++ b/vcl/source/gdi/embeddedfontshelper.cxx @@ -8,23 +8,23 @@ */ #include <config_folders.h> +#include <config_eot.h> -#include <vcl/embeddedfontshelper.hxx> - +#include <boost/scoped_ptr.hpp> +#include <boost/shared_ptr.hpp> #include <osl/file.hxx> #include <rtl/bootstrap.hxx> -#include <sft.hxx> #include <vcl/outdev.hxx> #include <vcl/svapp.hxx> -#include <boost/scoped_ptr.hpp> -#include <boost/shared_ptr.hpp> -#include <fontsubset.hxx> -#include <outdev.h> -#include <outfont.hxx> -#include <salgdi.hxx> +#include "fontsubset.hxx" +#include "outdev.h" +#include "outfont.hxx" +#include "PhysicalFontCollection.hxx" +#include "salgdi.hxx" +#include "sft.hxx" -#include <config_eot.h> +#include <vcl/embeddedfontshelper.hxx> #if ENABLE_EOT extern "C" diff --git a/vcl/source/gdi/outdev.cxx b/vcl/source/gdi/outdev.cxx index 1939e2ea3111..762f2bdb3729 100644 --- a/vcl/source/gdi/outdev.cxx +++ b/vcl/source/gdi/outdev.cxx @@ -43,6 +43,7 @@ #include <window.h> #include <outdev.h> #include <outdata.hxx> +#include "PhysicalFontCollection.hxx" #include <basegfx/point/b2dpoint.hxx> #include <basegfx/vector/b2dvector.hxx> diff --git a/vcl/source/gdi/outdev3.cxx b/vcl/source/gdi/outdev3.cxx index 8dd4b9206302..7de3d81c0c19 100644 --- a/vcl/source/gdi/outdev3.cxx +++ b/vcl/source/gdi/outdev3.cxx @@ -55,6 +55,10 @@ #include "outdata.hxx" #include "outfont.hxx" #include "outdev.h" +#include "PhysicalFontCollection.hxx" +#include "PhysicalFontFace.hxx" +#include "PhysicalFontFamily.hxx" + #include "textlayout.hxx" #include "svids.hrc" #include "window.h" @@ -424,7 +428,7 @@ bool ImplDirectFontSubstitution::FindFontSubstitute( OUString& rSubstName, return false; } -static void ImplFontSubstitute( OUString& rFontName ) +void ImplFontSubstitute( OUString& rFontName ) { #ifdef DBG_UTIL OUString aTempName = rFontName; @@ -637,67 +641,6 @@ Font OutputDevice::GetDefaultFont( sal_uInt16 nType, LanguageType eLang, return aFont; } -static unsigned ImplIsCJKFont( const OUString& rFontName ) -{ - // Test, if Fontname includes CJK characters --> In this case we - // mention that it is a CJK font - for(int i = 0; i < rFontName.getLength(); i++) - { - const sal_Unicode ch = rFontName[i]; - // japanese - if ( ((ch >= 0x3040) && (ch <= 0x30FF)) || - ((ch >= 0x3190) && (ch <= 0x319F)) ) - return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_JP; - - // korean - if ( ((ch >= 0xAC00) && (ch <= 0xD7AF)) || - ((ch >= 0x3130) && (ch <= 0x318F)) || - ((ch >= 0x1100) && (ch <= 0x11FF)) ) - return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_KR; - - // chinese - if ( ((ch >= 0x3400) && (ch <= 0x9FFF)) ) - return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_TC|IMPL_FONT_ATTR_CJK_SC; - - // cjk - if ( ((ch >= 0x3000) && (ch <= 0xD7AF)) || - ((ch >= 0xFF00) && (ch <= 0xFFEE)) ) - return IMPL_FONT_ATTR_CJK; - - } - - return 0; -} - -static void ImplCalcType( sal_uLong& rType, FontWeight& rWeight, FontWidth& rWidth, - FontFamily eFamily, const FontNameAttr* pFontAttr ) -{ - if ( eFamily != FAMILY_DONTKNOW ) - { - if ( eFamily == FAMILY_SWISS ) - rType |= IMPL_FONT_ATTR_SANSSERIF; - else if ( eFamily == FAMILY_ROMAN ) - rType |= IMPL_FONT_ATTR_SERIF; - else if ( eFamily == FAMILY_SCRIPT ) - rType |= IMPL_FONT_ATTR_SCRIPT; - else if ( eFamily == FAMILY_MODERN ) - rType |= IMPL_FONT_ATTR_FIXED; - else if ( eFamily == FAMILY_DECORATIVE ) - rType |= IMPL_FONT_ATTR_DECORATIVE; - } - - if ( pFontAttr ) - { - rType |= pFontAttr->Type; - - if ( ((rWeight == WEIGHT_DONTKNOW) || (rWeight == WEIGHT_NORMAL)) && - (pFontAttr->Weight != WEIGHT_DONTKNOW) ) - rWeight = pFontAttr->Weight; - if ( ((rWidth == WIDTH_DONTKNOW) || (rWidth == WIDTH_NORMAL)) && - (pFontAttr->Width != WIDTH_DONTKNOW) ) - rWidth = pFontAttr->Width; - } -} ImplFontEntry::ImplFontEntry( const FontSelectPattern& rFontSelData ) : maFontSelData( rFontSelData ) @@ -726,14 +669,14 @@ size_t ImplFontEntry::GFBCacheKey_Hash::operator()( const GFBCacheKey& rData ) c return a(rData.first) ^ b(rData.second); } -inline void ImplFontEntry::AddFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const OUString& rFontName ) +void ImplFontEntry::AddFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const OUString& rFontName ) { if( !mpUnicodeFallbackList ) mpUnicodeFallbackList = new UnicodeFallbackList; (*mpUnicodeFallbackList)[ GFBCacheKey(cChar,eWeight) ] = rFontName; } -inline bool ImplFontEntry::GetFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, OUString* pFontName ) const +bool ImplFontEntry::GetFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, OUString* pFontName ) const { if( !mpUnicodeFallbackList ) return false; @@ -746,7 +689,7 @@ inline bool ImplFontEntry::GetFallbackForUnicode( sal_UCS4 cChar, FontWeight eWe return true; } -inline void ImplFontEntry::IgnoreFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const OUString& rFontName ) +void ImplFontEntry::IgnoreFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const OUString& rFontName ) { // DBG_ASSERT( mpUnicodeFallbackList, "ImplFontEntry::IgnoreFallbackForUnicode no list" ); UnicodeFallbackList::iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) ); @@ -757,1056 +700,6 @@ inline void ImplFontEntry::IgnoreFallbackForUnicode( sal_UCS4 cChar, FontWeight mpUnicodeFallbackList->erase( it ); } -PhysicalFontFamily::PhysicalFontFamily( const OUString& rSearchName ) -: mpFirst( NULL ), - maSearchName( rSearchName ), - mnTypeFaces( 0 ), - mnMatchType( 0 ), - meMatchWeight( WEIGHT_DONTKNOW ), - meMatchWidth( WIDTH_DONTKNOW ), - meFamily( FAMILY_DONTKNOW ), - mePitch( PITCH_DONTKNOW ), - mnMinQuality( -1 ) -{} - -PhysicalFontFamily::~PhysicalFontFamily() -{ - // release all physical font faces - while( mpFirst ) - { - PhysicalFontFace* pFace = mpFirst; - mpFirst = pFace->GetNextFace(); - delete pFace; - } -} - -bool PhysicalFontFamily::AddFontFace( PhysicalFontFace* pNewData ) -{ - pNewData->mpNext = NULL; - - if( !mpFirst ) - { - maName = pNewData->GetFamilyName(); - maMapNames = pNewData->maMapNames; - meFamily = pNewData->GetFamilyType(); - mePitch = pNewData->GetPitch(); - mnMinQuality = pNewData->mnQuality; - } - else - { - if( meFamily == FAMILY_DONTKNOW ) - meFamily = pNewData->GetFamilyType(); - if( mePitch == PITCH_DONTKNOW ) - mePitch = pNewData->GetPitch(); - if( mnMinQuality > pNewData->mnQuality ) - mnMinQuality = pNewData->mnQuality; - } - - // set attributes for attribute based font matching - if( pNewData->IsScalable() ) - mnTypeFaces |= IMPL_DEVFONT_SCALABLE; - - if( pNewData->IsSymbolFont() ) - mnTypeFaces |= IMPL_DEVFONT_SYMBOL; - else - mnTypeFaces |= IMPL_DEVFONT_NONESYMBOL; - - if( pNewData->GetWeight() != WEIGHT_DONTKNOW ) - { - if( pNewData->GetWeight() >= WEIGHT_SEMIBOLD ) - mnTypeFaces |= IMPL_DEVFONT_BOLD; - else if( pNewData->GetWeight() <= WEIGHT_SEMILIGHT ) - mnTypeFaces |= IMPL_DEVFONT_LIGHT; - else - mnTypeFaces |= IMPL_DEVFONT_NORMAL; - } - - if( pNewData->GetSlant() == ITALIC_NONE ) - mnTypeFaces |= IMPL_DEVFONT_NONEITALIC; - else if( (pNewData->GetSlant() == ITALIC_NORMAL) - || (pNewData->GetSlant() == ITALIC_OBLIQUE) ) - mnTypeFaces |= IMPL_DEVFONT_ITALIC; - - if( (meMatchWeight == WEIGHT_DONTKNOW) - || (meMatchWidth == WIDTH_DONTKNOW) - || (mnMatchType == 0) ) - { - // TODO: is it cheaper to calc matching attributes now or on demand? - // calc matching attributes if other entries are already initialized - - // Do lazy, quite expensive, not needed in start-up! - // const FontSubstConfiguration& rFontSubst = *FontSubstConfiguration::get(); - // InitMatchData( rFontSubst, maSearchName ); - // mbMatchData=true; // Somewhere else??? - } - - // reassign name (sharing saves memory) - if( pNewData->GetFamilyName() == GetFamilyName() ) - pNewData->SetFamilyName( GetFamilyName() ); - - // insert new physical font face into linked list - // TODO: get rid of linear search? - PhysicalFontFace* pData; - PhysicalFontFace** ppHere = &mpFirst; - for(; (pData=*ppHere) != NULL; ppHere=&pData->mpNext ) - { - sal_Int32 eComp = pNewData->CompareWithSize( *pData ); - if( eComp > 0 ) - continue; - if( eComp < 0 ) - break; - - // ignore duplicate if its quality is worse - if( pNewData->mnQuality < pData->mnQuality ) - return false; - - // keep the device font if its quality is good enough - if( (pNewData->mnQuality == pData->mnQuality) - && (pData->mbDevice || !pNewData->mbDevice) ) - return false; - - // replace existing font face with a better one - pNewData->mpNext = pData->mpNext; - *ppHere = pNewData; - delete pData; - return true; - } - - // insert into or append to list of physical font faces - pNewData->mpNext = pData; - *ppHere = pNewData; - return true; -} - -// get font attributes using the normalized font family name -void PhysicalFontFamily::InitMatchData( const utl::FontSubstConfiguration& rFontSubst, - const OUString& rSearchName ) -{ - OUString aShortName; - OUString aMatchFamilyName(maMatchFamilyName); - // get font attributes from the decorated font name - rFontSubst.getMapName( rSearchName, aShortName, aMatchFamilyName, - meMatchWeight, meMatchWidth, mnMatchType ); - maMatchFamilyName = aMatchFamilyName; - const FontNameAttr* pFontAttr = rFontSubst.getSubstInfo( rSearchName ); - // eventually use the stripped name - if( !pFontAttr ) - if( aShortName != rSearchName ) - pFontAttr = rFontSubst.getSubstInfo( aShortName ); - ImplCalcType( mnMatchType, meMatchWeight, meMatchWidth, meFamily, pFontAttr ); - mnMatchType |= ImplIsCJKFont( maName ); -} - -PhysicalFontFace* PhysicalFontFamily::FindBestFontFace( const FontSelectPattern& rFSD ) const -{ - if( !mpFirst ) - return NULL; - if( !mpFirst->GetNextFace() ) - return mpFirst; - - // FontName+StyleName should map to FamilyName+StyleName - const OUString& rSearchName = rFSD.maTargetName; - OUString aTargetStyleName; - const OUString* pTargetStyleName = NULL; - if( (rSearchName.getLength() > maSearchName.getLength()) - && rSearchName.startsWith( maSearchName ) ) - { - aTargetStyleName = rSearchName.copy(maSearchName.getLength() + 1); - pTargetStyleName = &aTargetStyleName; - } - - // TODO: linear search improve! - PhysicalFontFace* pFontFace = mpFirst; - PhysicalFontFace* pBestFontFace = pFontFace; - FontMatchStatus aFontMatchStatus = {0,0,0, pTargetStyleName}; - for(; pFontFace; pFontFace = pFontFace->GetNextFace() ) - if( pFontFace->IsBetterMatch( rFSD, aFontMatchStatus ) ) - pBestFontFace = pFontFace; - - return pBestFontFace; -} - -// update device font list with unique font faces, with uniqueness -// meaning different font attributes, but not different fonts sizes -void PhysicalFontFamily::UpdateDevFontList( ImplGetDevFontList& rDevFontList ) const -{ - PhysicalFontFace* pPrevFace = NULL; - for( PhysicalFontFace* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() ) - { - if( !pPrevFace || pFace->CompareIgnoreSize( *pPrevFace ) ) - rDevFontList.Add( pFace ); - pPrevFace = pFace; - } -} - -void PhysicalFontFamily::GetFontHeights( std::set<int>& rHeights ) const -{ - // add all available font heights - for( const PhysicalFontFace* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() ) - rHeights.insert( pFace->GetHeight() ); -} - -void PhysicalFontFamily::UpdateCloneFontList( PhysicalFontCollection& rFontCollection, - bool bScalable, bool bEmbeddable ) const -{ - for( PhysicalFontFace* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() ) - { - if( bScalable && !pFace->IsScalable() ) - continue; - if( bEmbeddable && !pFace->IsEmbeddable() && !pFace->IsSubsettable() ) - continue; - - PhysicalFontFace* pClonedFace = pFace->Clone(); - rFontCollection.Add( pClonedFace ); - } -} - -PhysicalFontCollection::PhysicalFontCollection() -: mbMatchData( false ) -, mbMapNames( false ) -, mpPreMatchHook( NULL ) -, mpFallbackHook( NULL ) -, mpFallbackList( NULL ) -, mnFallbackCount( -1 ) -{} - -PhysicalFontCollection::~PhysicalFontCollection() -{ - Clear(); -} - -void PhysicalFontCollection::SetPreMatchHook( ImplPreMatchFontSubstitution* pHook ) -{ - mpPreMatchHook = pHook; -} - -void PhysicalFontCollection::SetFallbackHook( ImplGlyphFallbackFontSubstitution* pHook ) -{ - mpFallbackHook = pHook; -} - -void PhysicalFontCollection::Clear() -{ - // remove fallback lists - delete[] mpFallbackList; - mpFallbackList = NULL; - mnFallbackCount = -1; - - // clear all entries in the device font list - PhysicalFontFamilies::iterator it = maPhysicalFontFamilies.begin(); - for(; it != maPhysicalFontFamilies.end(); ++it ) - { - PhysicalFontFamily* pEntry = (*it).second; - delete pEntry; - } - - maPhysicalFontFamilies.clear(); - - // match data must be recalculated too - mbMatchData = false; -} - -void PhysicalFontCollection::InitGenericGlyphFallback( void ) const -{ - // normalized family names of fonts suited for glyph fallback - // if a font is available related fonts can be ignored - // TODO: implement dynamic lists - static const char* aGlyphFallbackList[] = { - // empty strings separate the names of unrelated fonts - "eudc", "", - "arialunicodems", "cyberbit", "code2000", "", - "andalesansui", "", - "starsymbol", "opensymbol", "", - "msmincho", "fzmingti", "fzheiti", "ipamincho", "sazanamimincho", "kochimincho", "", - "sunbatang", "sundotum", "baekmukdotum", "gulim", "batang", "dotum", "", - "hgmincholightj", "msunglightsc", "msunglighttc", "hymyeongjolightk", "", - "tahoma", "dejavusans", "timesnewroman", "liberationsans", "", - "shree", "mangal", "", - "raavi", "shruti", "tunga", "", - "latha", "gautami", "kartika", "vrinda", "", - "shayyalmt", "naskmt", "scheherazade", "", - "david", "nachlieli", "lucidagrande", "", - "norasi", "angsanaupc", "", - "khmerossystem", "", - "muktinarrow", "", - "phetsarathot", "", - "padauk", "pinlonmyanmar", "", - "iskoolapota", "lklug", "", - 0 - }; - - bool bHasEudc = false; - int nMaxLevel = 0; - int nBestQuality = 0; - PhysicalFontFamily** pFallbackList = NULL; - for( const char** ppNames = &aGlyphFallbackList[0];; ++ppNames ) - { - // advance to next sub-list when end-of-sublist marker - if( !**ppNames ) // #i46456# check for empty string, i.e., deref string itself not only ptr to it - { - if( nBestQuality > 0 ) - if( ++nMaxLevel >= MAX_FALLBACK ) - break; - if( !ppNames[1] ) - break; - nBestQuality = 0; - continue; - } - - // test if the glyph fallback candidate font is available and scalable - OUString aTokenName( *ppNames, strlen(*ppNames), RTL_TEXTENCODING_UTF8 ); - PhysicalFontFamily* pFallbackFont = FindFontFamily( aTokenName ); - if( !pFallbackFont ) - continue; - if( !pFallbackFont->IsScalable() ) - continue; - - // keep the best font of the glyph fallback sub-list - if( nBestQuality < pFallbackFont->GetMinQuality() ) - { - nBestQuality = pFallbackFont->GetMinQuality(); - // store available glyph fallback fonts - if( !pFallbackList ) - pFallbackList = new PhysicalFontFamily*[ MAX_FALLBACK ]; - pFallbackList[ nMaxLevel ] = pFallbackFont; - if( !bHasEudc && !nMaxLevel ) - bHasEudc = !strncmp( *ppNames, "eudc", 5 ); - } - } - -#ifdef SAL_FONTENUM_STABLE_ON_PLATFORM // #i113472# - // sort the list of fonts for glyph fallback by quality (highest first) - // #i33947# keep the EUDC font at the front of the list - // an insertion sort is good enough for this short list - const int nSortStart = bHasEudc ? 1 : 0; - for( int i = nSortStart+1, j; i < nMaxLevel; ++i ) - { - PhysicalFontFamily* pTestFont = pFallbackList[ i ]; - int nTestQuality = pTestFont->GetMinQuality(); - for( j = i; --j >= nSortStart; ) - if( nTestQuality > pFallbackList[j]->GetMinQuality() ) - pFallbackList[ j+1 ] = pFallbackList[ j ]; - else - break; - pFallbackList[ j+1 ] = pTestFont; - } -#endif - - mnFallbackCount = nMaxLevel; - mpFallbackList = pFallbackList; -} - -PhysicalFontFamily* PhysicalFontCollection::GetGlyphFallbackFont( FontSelectPattern& rFontSelData, - OUString& rMissingCodes, int nFallbackLevel ) const -{ - PhysicalFontFamily* pFallbackData = NULL; - - // find a matching font candidate for platform specific glyph fallback - if( mpFallbackHook ) - { - // check cache for the first matching entry - // to avoid calling the expensive fallback hook (#i83491#) - sal_UCS4 cChar = 0; - bool bCached = true; - sal_Int32 nStrIndex = 0; - while( nStrIndex < rMissingCodes.getLength() ) - { - cChar = rMissingCodes.iterateCodePoints( &nStrIndex ); - bCached = rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName ); - // ignore entries which don't have a fallback - if( !bCached || !rFontSelData.maSearchName.isEmpty() ) - break; - } - - if( bCached ) - { - // there is a matching fallback in the cache - // so update rMissingCodes with codepoints not yet resolved by this fallback - int nRemainingLength = 0; - sal_UCS4* pRemainingCodes = (sal_UCS4*)alloca( rMissingCodes.getLength() * sizeof(sal_UCS4) ); - OUString aFontName; - while( nStrIndex < rMissingCodes.getLength() ) - { - cChar = rMissingCodes.iterateCodePoints( &nStrIndex ); - bCached = rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &aFontName ); - if( !bCached || (rFontSelData.maSearchName != aFontName) ) - pRemainingCodes[ nRemainingLength++ ] = cChar; - } - rMissingCodes = OUString( pRemainingCodes, nRemainingLength ); - } - else - { - OUString aOldMissingCodes = rMissingCodes; - // call the hook to query the best matching glyph fallback font - if( mpFallbackHook->FindFontSubstitute( rFontSelData, rMissingCodes ) ) - // apply outdev3.cxx specific fontname normalization - GetEnglishSearchFontName( rFontSelData.maSearchName ); - else - rFontSelData.maSearchName = ""; - - // See fdo#32665 for an example. FreeSerif that has glyphs in normal - // font, but not in the italic or bold version - bool bSubSetOfFontRequiresPropertyFaking = rFontSelData.mbEmbolden || rFontSelData.maItalicMatrix != ItalicMatrix(); - - // Cache the result even if there was no match, unless its from part of a font for which the properties need - // to be faked. We need to rework this cache to take into account that fontconfig can return different fonts - // for different input sizes, weights, etc. Basically the cache is way to naive - if (!bSubSetOfFontRequiresPropertyFaking) - { - for(;;) - { - if( !rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName ) ) - rFontSelData.mpFontEntry->AddFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName ); - if( nStrIndex >= aOldMissingCodes.getLength() ) - break; - cChar = aOldMissingCodes.iterateCodePoints( &nStrIndex ); - } - if( !rFontSelData.maSearchName.isEmpty() ) - { - // remove cache entries that were still not resolved - for( nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); ) - { - cChar = rMissingCodes.iterateCodePoints( &nStrIndex ); - rFontSelData.mpFontEntry->IgnoreFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName ); - } - } - } - } - - // find the matching device font - if( !rFontSelData.maSearchName.isEmpty() ) - pFallbackData = FindFontFamily( rFontSelData.maSearchName ); - } - - // else find a matching font candidate for generic glyph fallback - if( !pFallbackData ) - { - // initialize font candidates for generic glyph fallback if needed - if( mnFallbackCount < 0 ) - InitGenericGlyphFallback(); - // TODO: adjust nFallbackLevel by number of levels resolved by the fallback hook - if( nFallbackLevel < mnFallbackCount ) - pFallbackData = mpFallbackList[ nFallbackLevel ]; - } - - return pFallbackData; -} - -void PhysicalFontCollection::Add( PhysicalFontFace* pNewData ) -{ - OUString aSearchName = pNewData->GetFamilyName(); - GetEnglishSearchFontName( aSearchName ); - - PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.find( aSearchName ); - PhysicalFontFamily* pFoundData = NULL; - if( it != maPhysicalFontFamilies.end() ) - pFoundData = (*it).second; - - if( !pFoundData ) - { - pFoundData = new PhysicalFontFamily( aSearchName ); - maPhysicalFontFamilies[ aSearchName ] = pFoundData; - } - - bool bKeepNewData = pFoundData->AddFontFace( pNewData ); - - if( !bKeepNewData ) - delete pNewData; -} - -// find the font from the normalized font family name -PhysicalFontFamily* PhysicalFontCollection::ImplFindBySearchName( const OUString& rSearchName ) const -{ -#ifdef DEBUG - OUString aTempName = rSearchName; - GetEnglishSearchFontName( aTempName ); - DBG_ASSERT( aTempName == rSearchName, "PhysicalFontCollection::ImplFindBySearchName() called with non-normalized name" ); -#endif - - PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.find( rSearchName ); - if( it == maPhysicalFontFamilies.end() ) - return NULL; - - PhysicalFontFamily* pFoundData = (*it).second; - return pFoundData; -} - -PhysicalFontFamily* PhysicalFontCollection::ImplFindByAliasName(const OUString& rSearchName, - const OUString& rShortName) const -{ - // short circuit for impossible font name alias - if (rSearchName.isEmpty()) - return NULL; - - // short circuit if no alias names are available - if (!mbMapNames) - return NULL; - - // use the font's alias names to find the font - // TODO: get rid of linear search - PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin(); - while( it != maPhysicalFontFamilies.end() ) - { - PhysicalFontFamily* pData = (*it).second; - if( pData->maMapNames.isEmpty() ) - continue; - - // if one alias name matches we found a matching font - OUString aTempName; - sal_Int32 nIndex = 0; - do - { - aTempName = GetNextFontToken( pData->maMapNames, nIndex ); - // Test, if the Font name match with one of the mapping names - if ( (aTempName == rSearchName) || (aTempName == rShortName) ) - return pData; - } - while ( nIndex != -1 ); - } - - return NULL; -} - -PhysicalFontFamily* PhysicalFontCollection::FindFontFamily( const OUString& rFontName ) const -{ - // normalize the font family name and - OUString aName = rFontName; - GetEnglishSearchFontName( aName ); - PhysicalFontFamily* pFound = ImplFindBySearchName( aName ); - return pFound; -} - -PhysicalFontFamily* PhysicalFontCollection::ImplFindByTokenNames(const OUString& rTokenStr) const -{ - PhysicalFontFamily* pFoundData = NULL; - - // use normalized font name tokens to find the font - for( sal_Int32 nTokenPos = 0; nTokenPos != -1; ) - { - OUString aSearchName = GetNextFontToken( rTokenStr, nTokenPos ); - if( aSearchName.isEmpty() ) - continue; - GetEnglishSearchFontName( aSearchName ); - pFoundData = ImplFindBySearchName( aSearchName ); - if( pFoundData ) - break; - } - - return pFoundData; -} - -PhysicalFontFamily* PhysicalFontCollection::ImplFindBySubstFontAttr( const utl::FontNameAttr& rFontAttr ) const -{ - PhysicalFontFamily* pFoundData = NULL; - - // use the font substitutions suggested by the FontNameAttr to find the font - ::std::vector< OUString >::const_iterator it = rFontAttr.Substitutions.begin(); - for(; it != rFontAttr.Substitutions.end(); ++it ) - { - OUString aSearchName( *it ); - GetEnglishSearchFontName( aSearchName ); - - pFoundData = ImplFindBySearchName( aSearchName ); - if( pFoundData ) - return pFoundData; - } - - // use known attributes from the configuration to find a matching substitute - const sal_uLong nSearchType = rFontAttr.Type; - if( nSearchType != 0 ) - { - const FontWeight eSearchWeight = rFontAttr.Weight; - const FontWidth eSearchWidth = rFontAttr.Width; - const FontItalic eSearchSlant = ITALIC_DONTKNOW; - const OUString aSearchName; - pFoundData = ImplFindByAttributes( nSearchType, - eSearchWeight, eSearchWidth, eSearchSlant, aSearchName ); - if( pFoundData ) - return pFoundData; - } - - return NULL; -} - -void PhysicalFontCollection::InitMatchData() const -{ - // short circuit if already done - if( mbMatchData ) - return; - mbMatchData = true; - - // calculate MatchData for all entries - const FontSubstConfiguration& rFontSubst = FontSubstConfiguration::get(); - - PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin(); - for(; it != maPhysicalFontFamilies.end(); ++it ) - { - const OUString& rSearchName = (*it).first; - PhysicalFontFamily* pEntry = (*it).second; - - pEntry->InitMatchData( rFontSubst, rSearchName ); - } -} - -PhysicalFontFamily* PhysicalFontCollection::ImplFindByAttributes( sal_uLong nSearchType, - FontWeight eSearchWeight, FontWidth eSearchWidth, - FontItalic eSearchItalic, const OUString& rSearchFamilyName ) const -{ - if( (eSearchItalic != ITALIC_NONE) && (eSearchItalic != ITALIC_DONTKNOW) ) - nSearchType |= IMPL_FONT_ATTR_ITALIC; - - // don't bother to match attributes if the attributes aren't worth matching - if( !nSearchType - && ((eSearchWeight == WEIGHT_DONTKNOW) || (eSearchWeight == WEIGHT_NORMAL)) - && ((eSearchWidth == WIDTH_DONTKNOW) || (eSearchWidth == WIDTH_NORMAL)) ) - return NULL; - - InitMatchData(); - PhysicalFontFamily* pFoundData = NULL; - - long nTestMatch; - long nBestMatch = 40000; - sal_uLong nBestType = 0; - - PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin(); - for(; it != maPhysicalFontFamilies.end(); ++it ) - { - PhysicalFontFamily* pData = (*it).second; - - // Get all information about the matching font - sal_uLong nMatchType = pData->mnMatchType; - FontWeight eMatchWeight= pData->meMatchWeight; - FontWidth eMatchWidth = pData->meMatchWidth; - - // Calculate Match Value - // 1000000000 - // 100000000 - // 10000000 CJK, CTL, None-Latin, Symbol - // 1000000 FamilyName, Script, Fixed, -Special, -Decorative, - // Titling, Capitals, Outline, Shadow - // 100000 Match FamilyName, Serif, SansSerif, Italic, - // Width, Weight - // 10000 Scalable, Standard, Default, - // full, Normal, Knownfont, - // Otherstyle, +Special, +Decorative, - // 1000 Typewriter, Rounded, Gothic, Schollbook - // 100 - nTestMatch = 0; - - // test CJK script attributes - if ( nSearchType & IMPL_FONT_ATTR_CJK ) - { - // Matching language - if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_CJK_ALLLANG) ) - nTestMatch += 10000000*3; - if( nMatchType & IMPL_FONT_ATTR_CJK ) - nTestMatch += 10000000*2; - if( nMatchType & IMPL_FONT_ATTR_FULL ) - nTestMatch += 10000000; - } - else if ( nMatchType & IMPL_FONT_ATTR_CJK ) - nTestMatch -= 10000000; - - // test CTL script attributes - if( nSearchType & IMPL_FONT_ATTR_CTL ) - { - if( nMatchType & IMPL_FONT_ATTR_CTL ) - nTestMatch += 10000000*2; - if( nMatchType & IMPL_FONT_ATTR_FULL ) - nTestMatch += 10000000; - } - else if ( nMatchType & IMPL_FONT_ATTR_CTL ) - nTestMatch -= 10000000; - - // test LATIN script attributes - if( nSearchType & IMPL_FONT_ATTR_NONELATIN ) - { - if( nMatchType & IMPL_FONT_ATTR_NONELATIN ) - nTestMatch += 10000000*2; - if( nMatchType & IMPL_FONT_ATTR_FULL ) - nTestMatch += 10000000; - } - - // test SYMBOL attributes - if ( nSearchType & IMPL_FONT_ATTR_SYMBOL ) - { - const OUString& rSearchName = it->first; - // prefer some special known symbol fonts - if ( rSearchName.equalsAscii( "starsymbol" ) ) - nTestMatch += 10000000*6+(10000*3); - else if ( rSearchName.equalsAscii( "opensymbol" ) ) - nTestMatch += 10000000*6; - else if ( rSearchName.equalsAscii( "starbats" ) - || rSearchName.equalsAscii( "wingdings" ) - || rSearchName.equalsAscii( "monotypesorts" ) - || rSearchName.equalsAscii( "dingbats" ) - || rSearchName.equalsAscii( "zapfdingbats" ) ) - nTestMatch += 10000000*5; - else if ( pData->mnTypeFaces & IMPL_DEVFONT_SYMBOL ) - nTestMatch += 10000000*4; - else - { - if( nMatchType & IMPL_FONT_ATTR_SYMBOL ) - nTestMatch += 10000000*2; - if( nMatchType & IMPL_FONT_ATTR_FULL ) - nTestMatch += 10000000; - } - } - else if ( (pData->mnTypeFaces & (IMPL_DEVFONT_SYMBOL | IMPL_DEVFONT_NONESYMBOL)) == IMPL_DEVFONT_SYMBOL ) - nTestMatch -= 10000000; - else if ( nMatchType & IMPL_FONT_ATTR_SYMBOL ) - nTestMatch -= 10000; - - // match stripped family name - if( !rSearchFamilyName.isEmpty() && (rSearchFamilyName.equals(pData->maMatchFamilyName)) ) - nTestMatch += 1000000*3; - - // match ALLSCRIPT? attribute - if( nSearchType & IMPL_FONT_ATTR_ALLSCRIPT ) - { - if( nMatchType & IMPL_FONT_ATTR_ALLSCRIPT ) - nTestMatch += 1000000*2; - if( nSearchType & IMPL_FONT_ATTR_ALLSUBSCRIPT ) - { - if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_ALLSUBSCRIPT) ) - nTestMatch += 1000000*2; - if( 0 != ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_BRUSHSCRIPT) ) - nTestMatch -= 1000000; - } - } - else if( nMatchType & IMPL_FONT_ATTR_ALLSCRIPT ) - nTestMatch -= 1000000; - - // test MONOSPACE+TYPEWRITER attributes - if( nSearchType & IMPL_FONT_ATTR_FIXED ) - { - if( nMatchType & IMPL_FONT_ATTR_FIXED ) - nTestMatch += 1000000*2; - // a typewriter attribute is even better - if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_TYPEWRITER) ) - nTestMatch += 10000*2; - } - else if( nMatchType & IMPL_FONT_ATTR_FIXED ) - nTestMatch -= 1000000; - - // test SPECIAL attribute - if( nSearchType & IMPL_FONT_ATTR_SPECIAL ) - { - if( nMatchType & IMPL_FONT_ATTR_SPECIAL ) - nTestMatch += 10000; - else if( !(nSearchType & IMPL_FONT_ATTR_ALLSERIFSTYLE) ) - { - if( nMatchType & IMPL_FONT_ATTR_SERIF ) - nTestMatch += 1000*2; - else if( nMatchType & IMPL_FONT_ATTR_SANSSERIF ) - nTestMatch += 1000; - } - } - else if( (nMatchType & IMPL_FONT_ATTR_SPECIAL) && !(nSearchType & IMPL_FONT_ATTR_SYMBOL) ) - nTestMatch -= 1000000; - - // test DECORATIVE attribute - if( nSearchType & IMPL_FONT_ATTR_DECORATIVE ) - { - if( nMatchType & IMPL_FONT_ATTR_DECORATIVE ) - nTestMatch += 10000; - else if( !(nSearchType & IMPL_FONT_ATTR_ALLSERIFSTYLE) ) - { - if( nMatchType & IMPL_FONT_ATTR_SERIF ) - nTestMatch += 1000*2; - else if ( nMatchType & IMPL_FONT_ATTR_SANSSERIF ) - nTestMatch += 1000; - } - } - else if( nMatchType & IMPL_FONT_ATTR_DECORATIVE ) - nTestMatch -= 1000000; - - // test TITLE+CAPITALS attributes - if( nSearchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) ) - { - if( nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) ) - nTestMatch += 1000000*2; - if( 0 == ((nSearchType^nMatchType) & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS))) - nTestMatch += 1000000; - else if( (nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS)) - && (nMatchType & (IMPL_FONT_ATTR_STANDARD | IMPL_FONT_ATTR_DEFAULT)) ) - nTestMatch += 1000000; - } - else if( nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) ) - nTestMatch -= 1000000; - - // test OUTLINE+SHADOW attributes - if( nSearchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) ) - { - if( nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) ) - nTestMatch += 1000000*2; - if( 0 == ((nSearchType ^ nMatchType) & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW)) ) - nTestMatch += 1000000; - else if( (nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW)) - && (nMatchType & (IMPL_FONT_ATTR_STANDARD | IMPL_FONT_ATTR_DEFAULT)) ) - nTestMatch += 1000000; - } - else if ( nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) ) - nTestMatch -= 1000000; - - // test font name substrings - // TODO: calculate name matching score using e.g. Levenstein distance - if( (rSearchFamilyName.getLength() >= 4) && (pData->maMatchFamilyName.getLength() >= 4) - && ((rSearchFamilyName.indexOf( pData->maMatchFamilyName ) != -1) - || (pData->maMatchFamilyName.indexOf( rSearchFamilyName ) != -1)) ) - nTestMatch += 5000; - - // test SERIF attribute - if( nSearchType & IMPL_FONT_ATTR_SERIF ) - { - if( nMatchType & IMPL_FONT_ATTR_SERIF ) - nTestMatch += 1000000*2; - else if( nMatchType & IMPL_FONT_ATTR_SANSSERIF ) - nTestMatch -= 1000000; - } - - // test SANSERIF attribute - if( nSearchType & IMPL_FONT_ATTR_SANSSERIF ) - { - if( nMatchType & IMPL_FONT_ATTR_SANSSERIF ) - nTestMatch += 1000000; - else if ( nMatchType & IMPL_FONT_ATTR_SERIF ) - nTestMatch -= 1000000; - } - - // test ITALIC attribute - if( nSearchType & IMPL_FONT_ATTR_ITALIC ) - { - if( pData->mnTypeFaces & IMPL_DEVFONT_ITALIC ) - nTestMatch += 1000000*3; - if( nMatchType & IMPL_FONT_ATTR_ITALIC ) - nTestMatch += 1000000; - } - else if( !(nSearchType & IMPL_FONT_ATTR_ALLSCRIPT) - && ((nMatchType & IMPL_FONT_ATTR_ITALIC) - || !(pData->mnTypeFaces & IMPL_DEVFONT_NONEITALIC)) ) - nTestMatch -= 1000000*2; - - // test WIDTH attribute - if( (eSearchWidth != WIDTH_DONTKNOW) && (eSearchWidth != WIDTH_NORMAL) ) - { - if( eSearchWidth < WIDTH_NORMAL ) - { - if( eSearchWidth == eMatchWidth ) - nTestMatch += 1000000*3; - else if( (eMatchWidth < WIDTH_NORMAL) && (eMatchWidth != WIDTH_DONTKNOW) ) - nTestMatch += 1000000; - } - else - { - if( eSearchWidth == eMatchWidth ) - nTestMatch += 1000000*3; - else if( eMatchWidth > WIDTH_NORMAL ) - nTestMatch += 1000000; - } - } - else if( (eMatchWidth != WIDTH_DONTKNOW) && (eMatchWidth != WIDTH_NORMAL) ) - nTestMatch -= 1000000; - - // test WEIGHT attribute - if( (eSearchWeight != WEIGHT_DONTKNOW) && (eSearchWeight != WEIGHT_NORMAL) && (eSearchWeight != WEIGHT_MEDIUM) ) - { - if( eSearchWeight < WEIGHT_NORMAL ) - { - if( pData->mnTypeFaces & IMPL_DEVFONT_LIGHT ) - nTestMatch += 1000000; - if( (eMatchWeight < WEIGHT_NORMAL) && (eMatchWeight != WEIGHT_DONTKNOW) ) - nTestMatch += 1000000; - } - else - { - if( pData->mnTypeFaces & IMPL_DEVFONT_BOLD ) - nTestMatch += 1000000; - if( eMatchWeight > WEIGHT_BOLD ) - nTestMatch += 1000000; - } - } - else if( ((eMatchWeight != WEIGHT_DONTKNOW) && (eMatchWeight != WEIGHT_NORMAL) && (eMatchWeight != WEIGHT_MEDIUM)) - || !(pData->mnTypeFaces & IMPL_DEVFONT_NORMAL) ) - nTestMatch -= 1000000; - - // prefer scalable fonts - if( pData->mnTypeFaces & IMPL_DEVFONT_SCALABLE ) - nTestMatch += 10000*4; - else - nTestMatch -= 10000*4; - - // test STANDARD+DEFAULT+FULL+NORMAL attributes - if( nMatchType & IMPL_FONT_ATTR_STANDARD ) - nTestMatch += 10000*2; - if( nMatchType & IMPL_FONT_ATTR_DEFAULT ) - nTestMatch += 10000; - if( nMatchType & IMPL_FONT_ATTR_FULL ) - nTestMatch += 10000; - if( nMatchType & IMPL_FONT_ATTR_NORMAL ) - nTestMatch += 10000; - - // test OTHERSTYLE attribute - if( ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_OTHERSTYLE) != 0 ) - { - nTestMatch -= 10000; - } - - // test ROUNDED attribute - if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_ROUNDED) ) - nTestMatch += 1000; - - // test TYPEWRITER attribute - if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_TYPEWRITER) ) - nTestMatch += 1000; - - // test GOTHIC attribute - if( nSearchType & IMPL_FONT_ATTR_GOTHIC ) - { - if( nMatchType & IMPL_FONT_ATTR_GOTHIC ) - nTestMatch += 1000*3; - if( nMatchType & IMPL_FONT_ATTR_SANSSERIF ) - nTestMatch += 1000*2; - } - - // test SCHOOLBOOK attribute - if( nSearchType & IMPL_FONT_ATTR_SCHOOLBOOK ) - { - if( nMatchType & IMPL_FONT_ATTR_SCHOOLBOOK ) - nTestMatch += 1000*3; - if( nMatchType & IMPL_FONT_ATTR_SERIF ) - nTestMatch += 1000*2; - } - - // compare with best matching font yet - if ( nTestMatch > nBestMatch ) - { - pFoundData = pData; - nBestMatch = nTestMatch; - nBestType = nMatchType; - } - else if( nTestMatch == nBestMatch ) - { - // some fonts are more suitable defaults - if( nMatchType & IMPL_FONT_ATTR_DEFAULT ) - { - pFoundData = pData; - nBestType = nMatchType; - } - else if( (nMatchType & IMPL_FONT_ATTR_STANDARD) && - !(nBestType & IMPL_FONT_ATTR_DEFAULT) ) - { - pFoundData = pData; - nBestType = nMatchType; - } - } - } - - return pFoundData; -} - -PhysicalFontFamily* PhysicalFontCollection::FindDefaultFont() const -{ - // try to find one of the default fonts of the - // UNICODE, SANSSERIF, SERIF or FIXED default font lists - const DefaultFontConfiguration& rDefaults = DefaultFontConfiguration::get(); - LanguageTag aLanguageTag( OUString( "en")); - OUString aFontname = rDefaults.getDefaultFont( aLanguageTag, DEFAULTFONT_SANS_UNICODE ); - PhysicalFontFamily* pFoundData = ImplFindByTokenNames( aFontname ); - if( pFoundData ) - return pFoundData; - - aFontname = rDefaults.getDefaultFont( aLanguageTag, DEFAULTFONT_SANS ); - pFoundData = ImplFindByTokenNames( aFontname ); - if( pFoundData ) - return pFoundData; - - aFontname = rDefaults.getDefaultFont( aLanguageTag, DEFAULTFONT_SERIF ); - pFoundData = ImplFindByTokenNames( aFontname ); - if( pFoundData ) - return pFoundData; - - aFontname = rDefaults.getDefaultFont( aLanguageTag, DEFAULTFONT_FIXED ); - pFoundData = ImplFindByTokenNames( aFontname ); - if( pFoundData ) - return pFoundData; - - // now try to find a reasonable non-symbol font - - InitMatchData(); - - PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin(); - for(; it != maPhysicalFontFamilies.end(); ++it ) - { - PhysicalFontFamily* pData = (*it).second; - if( pData->mnMatchType & IMPL_FONT_ATTR_SYMBOL ) - continue; - pFoundData = pData; - if( pData->mnMatchType & (IMPL_FONT_ATTR_DEFAULT|IMPL_FONT_ATTR_STANDARD) ) - break; - } - if( pFoundData ) - return pFoundData; - - // finding any font is better than finding no font at all - it = maPhysicalFontFamilies.begin(); - if( it != maPhysicalFontFamilies.end() ) - pFoundData = (*it).second; - - return pFoundData; -} - -PhysicalFontCollection* PhysicalFontCollection::Clone( bool bScalable, bool bEmbeddable ) const -{ - PhysicalFontCollection* pClonedCollection = new PhysicalFontCollection; - pClonedCollection->mbMapNames = mbMapNames; - pClonedCollection->mpPreMatchHook = mpPreMatchHook; - pClonedCollection->mpFallbackHook = mpFallbackHook; - - // TODO: clone the config-font attributes too? - pClonedCollection->mbMatchData = false; - - PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin(); - for(; it != maPhysicalFontFamilies.end(); ++it ) - { - const PhysicalFontFamily* pFontFace = (*it).second; - pFontFace->UpdateCloneFontList( *pClonedCollection, bScalable, bEmbeddable ); - } - - return pClonedCollection; -} - -ImplGetDevFontList* PhysicalFontCollection::GetDevFontList() const -{ - ImplGetDevFontList* pGetDevFontList = new ImplGetDevFontList; - - PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin(); - for(; it != maPhysicalFontFamilies.end(); ++it ) - { - const PhysicalFontFamily* pFontFamily = (*it).second; - pFontFamily->UpdateDevFontList( *pGetDevFontList ); - } - - return pGetDevFontList; -} - -ImplGetDevSizeList* PhysicalFontCollection::GetDevSizeList( const OUString& rFontName ) const -{ - ImplGetDevSizeList* pGetDevSizeList = new ImplGetDevSizeList( rFontName ); - - PhysicalFontFamily* pFontFamily = FindFontFamily( rFontName ); - if( pFontFamily != NULL ) - { - std::set<int> rHeights; - pFontFamily->GetFontHeights( rHeights ); - - std::set<int>::const_iterator it = rHeights.begin(); - for(; it != rHeights.begin(); ++it ) - pGetDevSizeList->Add( *it ); - } - - return pGetDevSizeList; -} FontSelectPatternAttributes::FontSelectPatternAttributes( const Font& rFont, const OUString& rSearchName, const Size& rSize, float fExactHeight ) @@ -2128,355 +1021,6 @@ ImplFontEntry* ImplFontCache::GetFontEntry( PhysicalFontCollection* pFontList, return pEntry; } -namespace -{ - OUString stripCharSetFromName(const OUString& _aName) - { - // I worry that someone will have a font which *does* have - // e.g. "Greek" legitimately at the end of its name :-( - const char*suffixes[] = - { - " baltic", - " ce", - " cyr", - " greek", - " tur", - " (arabic)", - " (hebrew)", - " (thai)", - " (vietnamese)" - }; - - OUString aName = _aName; - // These can be crazily piled up, e.g. Times New Roman CYR Greek - bool bFinished = false; - while (!bFinished) - { - bFinished = true; - for (size_t i = 0; i < SAL_N_ELEMENTS(suffixes); ++i) - { - size_t nLen = strlen(suffixes[i]); - if (aName.endsWithIgnoreAsciiCaseAsciiL(suffixes[i], nLen)) - { - bFinished = false; - aName = aName.copy(0, aName.getLength() - nLen); - } - } - } - return aName; - } -} - -PhysicalFontFamily* PhysicalFontCollection::ImplFindByFont( FontSelectPattern& rFSD ) const -{ - // give up if no fonts are available - if( !Count() ) - return NULL; - - bool bMultiToken = false; - sal_Int32 nTokenPos = 0; - OUString& aSearchName = rFSD.maSearchName; // TODO: get rid of reference - for(;;) - { - rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos ); - aSearchName = rFSD.maTargetName; - -#if ENABLE_GRAPHITE - // Until features are properly supported, they are appended to the - // font name, so we need to strip them off so the font is found. - sal_Int32 nFeat = aSearchName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX); - OUString aOrigName = rFSD.maTargetName; - OUString aBaseFontName = aSearchName.copy( 0, (nFeat != -1) ? nFeat : aSearchName.getLength() ); - if (nFeat != -1 && - -1 != aSearchName.indexOf(grutils::GrFeatureParser::FEAT_ID_VALUE_SEPARATOR, nFeat)) - { - aSearchName = aBaseFontName; - rFSD.maTargetName = aBaseFontName; - } - -#endif - - GetEnglishSearchFontName( aSearchName ); - ImplFontSubstitute( aSearchName ); - // #114999# special emboldening for Ricoh fonts - // TODO: smarter check for special cases by using PreMatch infrastructure? - if( (rFSD.GetWeight() > WEIGHT_MEDIUM) - && aSearchName.startsWithIgnoreAsciiCase( "hg" ) ) - { - OUString aBoldName; - if( aSearchName.startsWithIgnoreAsciiCase( "hggothicb" ) ) - aBoldName = "hggothice"; - else if( aSearchName.startsWithIgnoreAsciiCase( "hgpgothicb" ) ) - aBoldName = "hgpgothice"; - else if( aSearchName.startsWithIgnoreAsciiCase( "hgminchol" ) ) - aBoldName = "hgminchob"; - else if( aSearchName.startsWithIgnoreAsciiCase( "hgpminchol" ) ) - aBoldName = "hgpminchob"; - else if( aSearchName.equalsIgnoreAsciiCase( "hgminchob" ) ) - aBoldName = "hgminchoe"; - else if( aSearchName.equalsIgnoreAsciiCase( "hgpminchob" ) ) - aBoldName = "hgpminchoe"; - - if( !aBoldName.isEmpty() && ImplFindBySearchName( aBoldName ) ) - { - // the other font is available => use it - aSearchName = aBoldName; - // prevent synthetic emboldening of bold version - rFSD.SetWeight(WEIGHT_DONTKNOW); - } - } - -#if ENABLE_GRAPHITE - // restore the features to make the font selection data unique - rFSD.maTargetName = aOrigName; -#endif - // check if the current font name token or its substitute is valid - PhysicalFontFamily* pFoundData = ImplFindBySearchName( aSearchName ); - if( pFoundData ) - return pFoundData; - - // some systems provide special customization - // e.g. they suggest "serif" as UI-font, but this name cannot be used directly - // because the system wants to map it to another font first, e.g. "Helvetica" -#if ENABLE_GRAPHITE - // use the target name to search in the prematch hook - rFSD.maTargetName = aBaseFontName; -#endif - - // Related: fdo#49271 RTF files often contain weird-ass - // Win 3.1/Win95 style fontnames which attempt to put the - // charset encoding into the filename - // http://www.webcenter.ru/~kazarn/eng/fonts_ttf.htm - OUString sStrippedName = stripCharSetFromName(rFSD.maTargetName); - if (!sStrippedName.equals(rFSD.maTargetName)) - { - rFSD.maTargetName = sStrippedName; - aSearchName = rFSD.maTargetName; - GetEnglishSearchFontName(aSearchName); - pFoundData = ImplFindBySearchName(aSearchName); - if( pFoundData ) - return pFoundData; - } - - if( mpPreMatchHook ) - { - if( mpPreMatchHook->FindFontSubstitute( rFSD ) ) - GetEnglishSearchFontName( aSearchName ); - } -#if ENABLE_GRAPHITE - // the prematch hook uses the target name to search, but we now need - // to restore the features to make the font selection data unique - rFSD.maTargetName = aOrigName; -#endif - pFoundData = ImplFindBySearchName( aSearchName ); - if( pFoundData ) - return pFoundData; - - // break after last font name token was checked unsuccessfully - if( nTokenPos == -1) - break; - bMultiToken = true; - } - - // if the first font was not available find the next available font in - // the semicolon separated list of font names. A font is also considered - // available when there is a matching entry in the Tools->Options->Fonts - // dialog witho neither ALWAYS nor SCREENONLY flags set and the substitution - // font is available - for( nTokenPos = 0; nTokenPos != -1; ) - { - if( bMultiToken ) - { - rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos ); - aSearchName = rFSD.maTargetName; - GetEnglishSearchFontName( aSearchName ); - } - else - nTokenPos = -1; - if( mpPreMatchHook ) - if( mpPreMatchHook->FindFontSubstitute( rFSD ) ) - GetEnglishSearchFontName( aSearchName ); - ImplFontSubstitute( aSearchName ); - PhysicalFontFamily* pFoundData = ImplFindBySearchName( aSearchName ); - if( pFoundData ) - return pFoundData; - } - - // if no font with a directly matching name is available use the - // first font name token and get its attributes to find a replacement - if ( bMultiToken ) - { - nTokenPos = 0; - rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos ); - aSearchName = rFSD.maTargetName; - GetEnglishSearchFontName( aSearchName ); - } - - OUString aSearchShortName; - OUString aSearchFamilyName; - FontWeight eSearchWeight = rFSD.GetWeight(); - FontWidth eSearchWidth = rFSD.GetWidthType(); - sal_uLong nSearchType = 0; - FontSubstConfiguration::getMapName( aSearchName, aSearchShortName, aSearchFamilyName, - eSearchWeight, eSearchWidth, nSearchType ); - - // note: the search name was already translated to english (if possible) - // use the font's shortened name if needed - if ( aSearchShortName != aSearchName ) - { - PhysicalFontFamily* pFoundData = ImplFindBySearchName( aSearchShortName ); - if( pFoundData ) - { -#ifdef UNX - /* #96738# don't use mincho as an replacement for "MS Mincho" on X11: Mincho is - a korean bitmap font that is not suitable here. Use the font replacement table, - that automatically leads to the desired "HG Mincho Light J". Same story for - MS Gothic, there are thai and korean "Gothic" fonts, so we even prefer Andale */ - static OUString aMS_Mincho( "msmincho" ); - static OUString aMS_Gothic( "msgothic" ); - if ((aSearchName != aMS_Mincho) && (aSearchName != aMS_Gothic)) - // TODO: add heuristic to only throw out the fake ms* fonts -#endif - { - return pFoundData; - } - } - } - - // use font fallback - const FontNameAttr* pFontAttr = NULL; - if( !aSearchName.isEmpty() ) - { - // get fallback info using FontSubstConfiguration and - // the target name, it's shortened name and family name in that order - const FontSubstConfiguration& rFontSubst = FontSubstConfiguration::get(); - pFontAttr = rFontSubst.getSubstInfo( aSearchName ); - if ( !pFontAttr && (aSearchShortName != aSearchName) ) - pFontAttr = rFontSubst.getSubstInfo( aSearchShortName ); - if ( !pFontAttr && (aSearchFamilyName != aSearchShortName) ) - pFontAttr = rFontSubst.getSubstInfo( aSearchFamilyName ); - - // try the font substitutions suggested by the fallback info - if( pFontAttr ) - { - PhysicalFontFamily* pFoundData = ImplFindBySubstFontAttr( *pFontAttr ); - if( pFoundData ) - return pFoundData; - } - } - - // if a target symbol font is not available use a default symbol font - if( rFSD.IsSymbolFont() ) - { - LanguageTag aDefaultLanguageTag( OUString( "en")); - aSearchName = DefaultFontConfiguration::get().getDefaultFont( aDefaultLanguageTag, DEFAULTFONT_SYMBOL ); - PhysicalFontFamily* pFoundData = ImplFindByTokenNames( aSearchName ); - if( pFoundData ) - return pFoundData; - } - - // now try the other font name tokens - while( nTokenPos != -1 ) - { - rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos ); - if( rFSD.maTargetName.isEmpty() ) - continue; - - aSearchName = rFSD.maTargetName; - GetEnglishSearchFontName( aSearchName ); - - OUString aTempShortName; - OUString aTempFamilyName; - sal_uLong nTempType = 0; - FontWeight eTempWeight = rFSD.GetWeight(); - FontWidth eTempWidth = WIDTH_DONTKNOW; - FontSubstConfiguration::getMapName( aSearchName, aTempShortName, aTempFamilyName, - eTempWeight, eTempWidth, nTempType ); - - // use a shortend token name if available - if( aTempShortName != aSearchName ) - { - PhysicalFontFamily* pFoundData = ImplFindBySearchName( aTempShortName ); - if( pFoundData ) - return pFoundData; - } - - // use a font name from font fallback list to determine font attributes - // get fallback info using FontSubstConfiguration and - // the target name, it's shortened name and family name in that order - const FontSubstConfiguration& rFontSubst = FontSubstConfiguration::get(); - const FontNameAttr* pTempFontAttr = rFontSubst.getSubstInfo( aSearchName ); - if ( !pTempFontAttr && (aTempShortName != aSearchName) ) - pTempFontAttr = rFontSubst.getSubstInfo( aTempShortName ); - if ( !pTempFontAttr && (aTempFamilyName != aTempShortName) ) - pTempFontAttr = rFontSubst.getSubstInfo( aTempFamilyName ); - - // try the font substitutions suggested by the fallback info - if( pTempFontAttr ) - { - PhysicalFontFamily* pFoundData = ImplFindBySubstFontAttr( *pTempFontAttr ); - if( pFoundData ) - return pFoundData; - if( !pFontAttr ) - pFontAttr = pTempFontAttr; - } - } - - // if still needed use the alias names of the installed fonts - if( mbMapNames ) - { - PhysicalFontFamily* pFoundData = ImplFindByAliasName( rFSD.maTargetName, aSearchShortName ); - if( pFoundData ) - return pFoundData; - } - - // if still needed use the font request's attributes to find a good match - if (MsLangId::isSimplifiedChinese(rFSD.meLanguage)) - nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_SC; - else if (MsLangId::isTraditionalChinese(rFSD.meLanguage)) - nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_TC; - else if (MsLangId::isKorean(rFSD.meLanguage)) - nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_KR; - else if (rFSD.meLanguage == LANGUAGE_JAPANESE) - nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_JP; - else - { - nSearchType |= ImplIsCJKFont( rFSD.GetFamilyName() ); - if( rFSD.IsSymbolFont() ) - nSearchType |= IMPL_FONT_ATTR_SYMBOL; - } - - ImplCalcType( nSearchType, eSearchWeight, eSearchWidth, rFSD.GetFamilyType(), pFontAttr ); - PhysicalFontFamily* pFoundData = ImplFindByAttributes( nSearchType, - eSearchWeight, eSearchWidth, rFSD.GetSlant(), aSearchFamilyName ); - - if( pFoundData ) - { - // overwrite font selection attributes using info from the typeface flags - if( (eSearchWeight >= WEIGHT_BOLD) - && (eSearchWeight > rFSD.GetWeight()) - && (pFoundData->mnTypeFaces & IMPL_DEVFONT_BOLD) ) - rFSD.SetWeight( eSearchWeight ); - else if( (eSearchWeight < WEIGHT_NORMAL) - && (eSearchWeight < rFSD.GetWeight()) - && (eSearchWeight != WEIGHT_DONTKNOW) - && (pFoundData->mnTypeFaces & IMPL_DEVFONT_LIGHT) ) - rFSD.SetWeight( eSearchWeight ); - - if( (nSearchType & IMPL_FONT_ATTR_ITALIC) - && ((rFSD.GetSlant() == ITALIC_DONTKNOW) || (rFSD.GetSlant() == ITALIC_NONE)) - && (pFoundData->mnTypeFaces & IMPL_DEVFONT_ITALIC) ) - rFSD.SetItalic( ITALIC_NORMAL ); - } - else - { - // if still needed fall back to default fonts - pFoundData = FindDefaultFont(); - } - - return pFoundData; -} - ImplFontEntry* ImplFontCache::GetGlyphFallbackFont( PhysicalFontCollection* pFontCollection, FontSelectPattern& rFontSelData, int nFallbackLevel, OUString& rMissingCodes ) { diff --git a/vcl/source/gdi/print.cxx b/vcl/source/gdi/print.cxx index a33ba8766cd8..dca6ef3ee5e2 100644 --- a/vcl/source/gdi/print.cxx +++ b/vcl/source/gdi/print.cxx @@ -43,6 +43,7 @@ #include <svids.hrc> #include <jobset.h> #include <outdev.h> +#include "PhysicalFontCollection.hxx" #include <print.h> #include <comphelper/processfactory.hxx> diff --git a/vcl/source/gdi/virdev.cxx b/vcl/source/gdi/virdev.cxx index 3ef75cf9261e..cf8ab485212e 100644 --- a/vcl/source/gdi/virdev.cxx +++ b/vcl/source/gdi/virdev.cxx @@ -30,6 +30,7 @@ #include <salframe.hxx> #include <salvd.hxx> #include <outdev.h> +#include "PhysicalFontCollection.hxx" #include <svdata.hxx> using namespace ::com::sun::star::uno; diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx index 7ba83e77c294..f56c2e1f821f 100644 --- a/vcl/source/window/window.cxx +++ b/vcl/source/window/window.cxx @@ -68,6 +68,7 @@ #include "window.h" #include "toolbox.h" #include "outdev.h" +#include "PhysicalFontCollection.hxx" #include "brdwin.hxx" #include "helpwin.hxx" #include "sallayout.hxx" diff --git a/vcl/unx/generic/gdi/salgdi3.cxx b/vcl/unx/generic/gdi/salgdi3.cxx index 389db5df6d9e..109c95af68e9 100644 --- a/vcl/unx/generic/gdi/salgdi3.cxx +++ b/vcl/unx/generic/gdi/salgdi3.cxx @@ -50,6 +50,7 @@ #include "generic/printergfx.hxx" #include "impfont.hxx" #include "outdev.h" +#include "PhysicalFontCollection.hxx" #include "PhysicalFontFace.hxx" #include "salframe.hxx" #include "unx/saldata.hxx" diff --git a/vcl/win/source/gdi/salgdi3.cxx b/vcl/win/source/gdi/salgdi3.cxx index e56e6423941c..c88cc5882c8f 100644 --- a/vcl/win/source/gdi/salgdi3.cxx +++ b/vcl/win/source/gdi/salgdi3.cxx @@ -43,6 +43,7 @@ #include "fontsubset.hxx" #include "outdev.h" +#include "PhysicalFontCollection.hxx" #include "PhysicalFontFace.hxx" #include "sft.hxx" #include "win/saldata.hxx" |