[Libreoffice-commits] core.git: 5 commits - include/vcl vcl/generic vcl/headless vcl/inc vcl/Library_vcl.mk vcl/quartz vcl/source vcl/unx vcl/win

Norbert Thiebaud nthiebaud at gmail.com
Thu Mar 20 14:12:34 PDT 2014


 include/vcl/outdev.hxx                     |    4 
 vcl/Library_vcl.mk                         |    3 
 vcl/generic/fontmanager/fontsubst.cxx      |    7 
 vcl/generic/glyphs/gcach_ftyp.cxx          |    7 
 vcl/generic/glyphs/gcach_ftyp.hxx          |    5 
 vcl/generic/glyphs/glyphcache.cxx          |    4 
 vcl/generic/print/genpspgraphics.cxx       |   53 
 vcl/headless/svptext.cxx                   |   35 
 vcl/inc/PhysicalFontCollection.hxx         |   90 +
 vcl/inc/PhysicalFontFace.hxx               |   87 +
 vcl/inc/PhysicalFontFamily.hxx             |   84 +
 vcl/inc/generic/geninst.h                  |    4 
 vcl/inc/generic/genpspgraphics.h           |  110 -
 vcl/inc/generic/glyphcache.hxx             |    6 
 vcl/inc/graphite_layout.hxx                |    5 
 vcl/inc/graphite_serverfont.hxx            |    2 
 vcl/inc/headless/svpgdi.hxx                |    4 
 vcl/inc/magic.h                            |   23 
 vcl/inc/outdev.h                           |   72 -
 vcl/inc/outfont.hxx                        |  113 -
 vcl/inc/quartz/salgdi.h                    |    7 
 vcl/inc/salgdi.hxx                         |    6 
 vcl/inc/sallayout.hxx                      |   15 
 vcl/inc/svdata.hxx                         |    4 
 vcl/inc/unx/salgdi.h                       |    6 
 vcl/inc/win/salgdi.h                       |   16 
 vcl/inc/window.h                           |    4 
 vcl/quartz/ctfonts.cxx                     |    5 
 vcl/quartz/salgdi.cxx                      |    8 
 vcl/source/app/svmain.cxx                  |    3 
 vcl/source/font/PhysicalFontCollection.cxx | 1362 ++++++++++++++++++++
 vcl/source/font/PhysicalFontFace.cxx       |  231 +++
 vcl/source/font/PhysicalFontFamily.cxx     |  298 ++++
 vcl/source/gdi/embeddedfontshelper.cxx     |   22 
 vcl/source/gdi/outdev.cxx                  |   13 
 vcl/source/gdi/outdev3.cxx                 | 1923 +----------------------------
 vcl/source/gdi/pdffontcache.cxx            |    9 
 vcl/source/gdi/pdfwriter_impl.cxx          |   67 -
 vcl/source/gdi/pdfwriter_impl.hxx          |   41 
 vcl/source/gdi/print.cxx                   |   15 
 vcl/source/gdi/virdev.cxx                  |    9 
 vcl/source/window/window.cxx               |   11 
 vcl/unx/generic/gdi/salgdi3.cxx            |   65 
 vcl/win/source/gdi/salgdi3.cxx             |   98 -
 44 files changed, 2663 insertions(+), 2293 deletions(-)

New commits:
commit 7260bcd68726739b5fe26b4d29a1de47e7b0f5a7
Author: Norbert Thiebaud <nthiebaud at gmail.com>
Date:   Thu Mar 20 00:22:26 2014 -0500

    cosmetic: split PhysicalFontFamily/Collection out of outdev3.cxx
    
    Change-Id: Iae8eb15413c0c069c14edd92c94ecb0113d9d371

diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 80c6405..e605343 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 f2f57f4a..deeb791 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 ea6c966..eee46f4 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 515dc0e..d111c28 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 7fd3cd3..e53ac29 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 0000000..9c0c7a1
--- /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 0000000..b1f56de
--- /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 ea7d381..3d1bbc7 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 47188e9..28770f7 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 0000000..7da1d09
--- /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 9baba35..a8f4037 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 12adb7c..798f261 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 f3727ba..57e7480 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 da91204..03e7f50 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 c649cc3..dac4d6e 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 2506d31..ce44ca8 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 6d572b4..3047488 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 0000000..6dcecc5
--- /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 0000000..f0f3307
--- /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 3e4d946..05730b7 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 1939e2e..762f2bd 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 8dd4b92..7de3d81 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 );
-        }
-    }
-

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list