summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvo Hinkelmann <ihi@openoffice.org>2010-05-11 11:01:01 +0200
committerIvo Hinkelmann <ihi@openoffice.org>2010-05-11 11:01:01 +0200
commit7c365da7e4dff304ebd1b0fc114587d98ad8a221 (patch)
tree4094aa5a5b9e0bc71e36069d47d8ce63c5469f3e
parent94b7c126456967795956a78e20b17fdbf4fa3799 (diff)
parentf7d1672cb337cc4a48184e6937d94ff631cfb377 (diff)
CWS-TOOLING: integrate CWS gfb4win02
-rw-r--r--vcl/inc/vcl/outfont.hxx6
-rw-r--r--vcl/source/gdi/outdev3.cxx12
-rw-r--r--vcl/win/source/gdi/salgdi3.cxx313
3 files changed, 330 insertions, 1 deletions
diff --git a/vcl/inc/vcl/outfont.hxx b/vcl/inc/vcl/outfont.hxx
index 995fcd6009ff..4bbf7176ddb2 100644
--- a/vcl/inc/vcl/outfont.hxx
+++ b/vcl/inc/vcl/outfont.hxx
@@ -39,6 +39,8 @@
#include <hash_map>
+#include <com/sun/star/linguistic2/XLinguServiceManager.hpp>
+
class ImplDevFontListData;
class ImplGetDevFontList;
class ImplGetDevSizeList;
@@ -186,6 +188,7 @@ public: // TODO: change to private
class VCL_DLLPUBLIC ImplDevFontList
{
private:
+ friend class WinGlyphFallbackSubstititution;
mutable bool mbMatchData; // true if matching attributes are initialized
bool mbMapNames; // true if MapNames are available
@@ -222,6 +225,9 @@ public:
ImplGetDevFontList* GetDevFontList() const;
ImplGetDevSizeList* GetDevSizeList( const String& rFontName ) const;
+ //used by 2-level font fallback
+ ImplDevFontListData* ImplFindByLocale(com::sun::star::lang::Locale lc) const;
+
protected:
void InitMatchData() const;
bool AreMapNamesAvailable() const { return mbMapNames; }
diff --git a/vcl/source/gdi/outdev3.cxx b/vcl/source/gdi/outdev3.cxx
index 630e58a1f2bf..f4fcba72b0c2 100644
--- a/vcl/source/gdi/outdev3.cxx
+++ b/vcl/source/gdi/outdev3.cxx
@@ -1672,6 +1672,18 @@ void ImplDevFontList::InitMatchData() const
}
}
+//----------------------------------------------------------------------------
+ImplDevFontListData* ImplDevFontList::ImplFindByLocale(com::sun::star::lang::Locale lc) const
+{
+ // get the default font for a specified locale
+ const DefaultFontConfiguration& rDefaults = *DefaultFontConfiguration::get();
+ String aDefault = rDefaults.getUserInterfaceFont( lc );
+ ImplDevFontListData* pFontData = ImplFindByTokenNames( aDefault );
+ if( pFontData )
+ return pFontData;
+ return 0;
+}
+
// -----------------------------------------------------------------------
ImplDevFontListData* ImplDevFontList::ImplFindByAttributes( ULONG nSearchType,
diff --git a/vcl/win/source/gdi/salgdi3.cxx b/vcl/win/source/gdi/salgdi3.cxx
index ebe470d3eb7e..1638c4e1bd36 100644
--- a/vcl/win/source/gdi/salgdi3.cxx
+++ b/vcl/win/source/gdi/salgdi3.cxx
@@ -47,11 +47,15 @@
#include "vcl/fontsubset.hxx"
#include "vcl/sallayout.hxx"
+#include "vcl/outdev.h" // for ImplGlyphFallbackFontSubstitution
+#include "unotools/fontcfg.hxx" // for IMPL_FONT_ATTR_SYMBOL
+
#include "rtl/logfile.hxx"
#include "rtl/tencinfo.h"
#include "rtl/textcvt.h"
#include "rtl/bootstrap.hxx"
+#include "i18npool/mslangid.hxx"
#include "osl/module.h"
#include "osl/file.hxx"
@@ -82,7 +86,6 @@
#include <set>
#include <map>
-
using namespace vcl;
static const int MAXFONTHEIGHT = 2048;
@@ -314,6 +317,308 @@ RawFontData::RawFontData( HDC hDC, DWORD nTableTag )
}
}
+// ===========================================================================
+// platform specific font substitution hooks for glyph fallback enhancement
+// TODO: move into i18n module (maybe merge with svx/ucsubset.*
+// or merge with i18nutil/source/utility/unicode_data.h)
+struct Unicode2LangType
+{
+ sal_UCS4 mnMinCode;
+ sal_UCS4 mnMaxCode;
+ LanguageType mnLangID;
+};
+
+// entries marked with default-CJK get replaced with the default-CJK language
+#define LANGUAGE_DEFAULT_CJK 0xFFF0
+
+// map unicode ranges to languages supported by OOo
+// NOTE: due to the binary search used this list must be sorted by mnMinCode
+static Unicode2LangType aLangFromCodeChart[]= {
+ {0x0000, 0x007F, LANGUAGE_ENGLISH}, // Basic Latin
+ {0x0080, 0x024F, LANGUAGE_ENGLISH}, // Latin Extended-A and Latin Extended-B
+ {0x0250, 0x02AF, LANGUAGE_SYSTEM}, // IPA Extensions
+ {0x0370, 0x03FF, LANGUAGE_GREEK}, // Greek
+ {0x0590, 0x05FF, LANGUAGE_HEBREW}, // Hebrew
+ {0x0600, 0x06FF, LANGUAGE_ARABIC_PRIMARY_ONLY}, // Arabic
+ {0x0900, 0x097F, LANGUAGE_HINDI}, // Devanagari
+ {0x0980, 0x09FF, LANGUAGE_BENGALI}, // Bengali
+ {0x0A80, 0x0AFF, LANGUAGE_GUJARATI}, // Gujarati
+ {0x0B00, 0x0B7F, LANGUAGE_ORIYA}, // Oriya
+ {0x0B80, 0x0BFF, LANGUAGE_TAMIL}, // Tamil
+ {0x0C00, 0x0C7F, LANGUAGE_TELUGU}, // Telugu
+ {0x0C80, 0x0CFF, LANGUAGE_KANNADA}, // Kannada
+ {0x0D00, 0x0D7F, LANGUAGE_MALAYALAM}, // Malayalam
+ {0x0D80, 0x0D7F, LANGUAGE_SINHALESE_SRI_LANKA}, // Sinhala
+ {0x0E00, 0x0E7F, LANGUAGE_THAI}, // Thai
+ {0x0E80, 0x0EFF, LANGUAGE_LAO}, // Lao
+ {0x0F00, 0x0FFF, LANGUAGE_TIBETAN}, // Tibetan
+ {0x1000, 0x109F, LANGUAGE_BURMESE}, // Burmese
+ {0x10A0, 0x10FF, LANGUAGE_GEORGIAN}, // Georgian
+ {0x1100, 0x11FF, LANGUAGE_KOREAN}, // Hangul Jamo, Korean-specific
+// {0x1200, 0x139F, LANGUAGE_AMHARIC_ETHIOPIA}, // Ethiopic
+// {0x1200, 0x139F, LANGUAGE_TIGRIGNA_ETHIOPIA}, // Ethiopic
+ {0x13A0, 0x13FF, LANGUAGE_CHEROKEE_UNITED_STATES}, // Cherokee
+// {0x1400, 0x167F, LANGUAGE_CANADIAN_ABORIGINAL}, // Canadian Aboriginial Syllabics
+// {0x1680, 0x169F, LANGUAGE_OGHAM}, // Ogham
+// {0x16A0, 0x16F0, LANGUAGE_RUNIC}, // Runic
+// {0x1700, 0x171F, LANGUAGE_TAGALOG}, // Tagalog
+// {0x1720, 0x173F, LANGUAGE_HANUNOO}, // Hanunoo
+// {0x1740, 0x175F, LANGUAGE_BUHID}, // Buhid
+// {0x1760, 0x177F, LANGUAGE_TAGBANWA}, // Tagbanwa
+ {0x1780, 0x17FF, LANGUAGE_KHMER}, // Khmer
+ {0x18A0, 0x18AF, LANGUAGE_MONGOLIAN}, // Mongolian
+// {0x1900, 0x194F, LANGUAGE_LIMBU}, // Limbu
+// {0x1950, 0x197F, LANGUAGE_TAILE}, // Tai Le
+// {0x1980, 0x19DF, LANGUAGE_TAILUE}, // Tai Lue
+ {0x19E0, 0x19FF, LANGUAGE_KHMER}, // Khmer Symbols
+// {0x1A00, 0x1A1F, LANGUAGE_BUGINESE}, // Buginese/Lontara
+// {0x1B00, 0x1B7F, LANGUAGE_BALINESE}, // Balinese
+// {0x1D00, 0x1DFF, LANGUAGE_NONE}, // Phonetic Symbols
+ {0x1E00, 0x1EFF, LANGUAGE_ENGLISH}, // Latin Extended Additional
+ {0x1F00, 0x1FFF, LANGUAGE_GREEK}, // Greek Extended
+ {0x2C60, 0x2C7F, LANGUAGE_ENGLISH}, // Latin Extended-C
+ {0x2E80, 0x2FFf, LANGUAGE_CHINESE_SIMPLIFIED}, // CJK Radicals Supplement + Kangxi Radical + Ideographic Description Characters
+ {0x3000, 0x303F, LANGUAGE_DEFAULT_CJK}, // CJK Symbols and punctuation
+ {0x3040, 0x30FF, LANGUAGE_JAPANESE}, // Japanese Hiragana + Katakana
+ {0x3100, 0x312F, LANGUAGE_CHINESE_TRADITIONAL}, // Bopomofo
+ {0x3130, 0x318F, LANGUAGE_KOREAN}, // Hangul Compatibility Jamo, Kocrean-specific
+ {0x3190, 0x319F, LANGUAGE_JAPANESE}, // Kanbun
+ {0x31A0, 0x31BF, LANGUAGE_CHINESE_TRADITIONAL}, // Bopomofo Extended
+ {0x31C0, 0x31EF, LANGUAGE_DEFAULT_CJK}, // CJK Ideographs
+ {0x31F0, 0x31FF, LANGUAGE_JAPANESE}, // Japanese Katakana Phonetic Extensions
+ {0x3200, 0x321F, LANGUAGE_KOREAN}, // Parenthesized Hangul
+ {0x3220, 0x325F, LANGUAGE_DEFAULT_CJK}, // Parenthesized Ideographs
+ {0x3260, 0x327F, LANGUAGE_KOREAN}, // Circled Hangul
+ {0x3280, 0x32CF, LANGUAGE_DEFAULT_CJK}, // Circled Ideographs
+ {0x32d0, 0x32FF, LANGUAGE_JAPANESE}, // Japanese Circled Katakana
+ {0x3400, 0x4DBF, LANGUAGE_DEFAULT_CJK}, // CJK Unified Ideographs Extension A
+ {0x4E00, 0x9FCF, LANGUAGE_DEFAULT_CJK}, // Unified CJK Ideographs
+ {0xA720, 0xA7FF, LANGUAGE_ENGLISH}, // Latin Extended-D
+ {0xAC00, 0xD7AF, LANGUAGE_KOREAN}, // Hangul Syllables, Korean-specific
+ {0xF900, 0xFAFF, LANGUAGE_DEFAULT_CJK}, // CJK Compatibility Ideographs
+ {0xFB00, 0xFB4F, LANGUAGE_HEBREW}, // Hebrew Presentation Forms
+ {0xFB50, 0xFDFF, LANGUAGE_ARABIC_PRIMARY_ONLY}, // Arabic Presentation Forms-A
+ {0xFE70, 0xFEFE, LANGUAGE_ARABIC_PRIMARY_ONLY}, // Arabic Presentation Forms-B
+ {0xFF65, 0xFF9F, LANGUAGE_JAPANESE}, // Japanese Halfwidth Katakana variant
+ {0xFFA0, 0xFFDC, LANGUAGE_KOREAN}, // Kocrean halfwidth hangual variant
+ {0x10140, 0x1018F, LANGUAGE_GREEK}, // Ancient Greak numbers
+ {0x1D200, 0x1D24F, LANGUAGE_GREEK}, // Ancient Greek Musical
+ {0x20000, 0x2A6DF, LANGUAGE_DEFAULT_CJK}, // CJK Unified Ideographs Extension B
+ {0x2F800, 0x2FA1F, LANGUAGE_DEFAULT_CJK} // CJK Compatibility Ideographs Supplement
+};
+
+// get language matching to the missing char
+LanguageType MapCharToLanguage( sal_UCS4 uChar )
+{
+ // entries marked with default-CJK get replaced with the prefered CJK language
+ static bool bFirst = true;
+ if( bFirst )
+ {
+ bFirst = false;
+
+ // use method suggested in #i97086# to determnine the systems default language
+ // TODO: move into i18npool or sal/osl/w32/nlsupport.c
+ LanguageType nDefaultLang = 0;
+ HKEY hKey = NULL;
+ LONG lResult = ::RegOpenKeyExA( HKEY_LOCAL_MACHINE,
+ "SYSTEM\\CurrentControlSet\\Control\\Nls\\Language",
+ 0, KEY_QUERY_VALUE, &hKey );
+ char aKeyValBuf[16];
+ DWORD nKeyValSize = sizeof(aKeyValBuf);
+ if( ERROR_SUCCESS == lResult )
+ lResult = RegQueryValueExA( hKey, "Default", NULL, NULL, (LPBYTE)aKeyValBuf, &nKeyValSize );
+ aKeyValBuf[ sizeof(aKeyValBuf)-1 ] = '\0';
+ if( ERROR_SUCCESS == lResult )
+ nDefaultLang = (LanguageType)rtl_str_toInt32( aKeyValBuf, 16 );
+
+ // TODO: use the default-CJK language selected in
+ // Tools->Options->LangSettings->Languages when it becomes available here
+ if( !nDefaultLang )
+ nDefaultLang = Application::GetSettings().GetUILanguage();
+
+ LanguageType nDefaultCJK = LANGUAGE_CHINESE;
+ switch( nDefaultLang )
+ {
+ case LANGUAGE_JAPANESE:
+ case LANGUAGE_KOREAN:
+ case LANGUAGE_KOREAN_JOHAB:
+ case LANGUAGE_CHINESE_SIMPLIFIED:
+ case LANGUAGE_CHINESE_TRADITIONAL:
+ case LANGUAGE_CHINESE_SINGAPORE:
+ case LANGUAGE_CHINESE_HONGKONG:
+ case LANGUAGE_CHINESE_MACAU:
+ nDefaultCJK = nDefaultLang;
+ break;
+ default:
+ nDefaultCJK = LANGUAGE_CHINESE;
+ break;
+ }
+
+ // change the marked entries to prefered language
+ static const int nCount = (sizeof(aLangFromCodeChart) / sizeof(*aLangFromCodeChart));
+ for( int i = 0; i < nCount; ++i )
+ {
+ if( aLangFromCodeChart[ i].mnLangID == LANGUAGE_DEFAULT_CJK )
+ aLangFromCodeChart[ i].mnLangID = nDefaultCJK;
+ }
+ }
+
+ // binary search
+ int nLow = 0;
+ int nHigh = (sizeof(aLangFromCodeChart) / sizeof(*aLangFromCodeChart)) - 1;
+ while( nLow <= nHigh )
+ {
+ int nMiddle = (nHigh + nLow) / 2;
+ if( uChar < aLangFromCodeChart[ nMiddle].mnMinCode )
+ nHigh = nMiddle - 1;
+ else if( uChar > aLangFromCodeChart[ nMiddle].mnMaxCode )
+ nLow = nMiddle + 1;
+ else
+ return aLangFromCodeChart[ nMiddle].mnLangID;
+ }
+
+ return LANGUAGE_DONTKNOW;
+}
+
+class WinGlyphFallbackSubstititution
+: public ImplGlyphFallbackFontSubstitution
+{
+public:
+ explicit WinGlyphFallbackSubstititution( HDC );
+
+ bool FindFontSubstitute( ImplFontSelectData&, rtl::OUString& rMissingChars ) const;
+private:
+ HDC mhDC;
+ bool HasMissingChars( const ImplFontData*, const rtl::OUString& rMissingChars ) const;
+};
+
+inline WinGlyphFallbackSubstititution::WinGlyphFallbackSubstititution( HDC hDC )
+: mhDC( hDC )
+{}
+
+void ImplGetLogFontFromFontSelect( HDC, const ImplFontSelectData*,
+ LOGFONTW&, bool /*bTestVerticalAvail*/ );
+
+// does a font face hold the given missing characters?
+bool WinGlyphFallbackSubstititution::HasMissingChars( const ImplFontData* pFace, const rtl::OUString& rMissingChars ) const
+{
+ const ImplWinFontData* pWinFont = static_cast<const ImplWinFontData*>(pFace);
+ const ImplFontCharMap* pCharMap = pWinFont->GetImplFontCharMap();
+ if( !pCharMap )
+ {
+ // construct a Size structure as the parameter of constructor of class ImplFontSelectData
+ const Size aSize( pFace->GetWidth(), pFace->GetHeight() );
+ // create a ImplFontSelectData object for getting s LOGFONT
+ const ImplFontSelectData aFSD( *pFace, aSize, (float)aSize.Height(), 0, false );
+ // construct log font
+ LOGFONTW aLogFont;
+ ImplGetLogFontFromFontSelect( mhDC, &aFSD, aLogFont, true );
+
+ // create HFONT from log font
+ HFONT hNewFont = ::CreateFontIndirectW( &aLogFont );
+ // select the new font into device
+ HFONT hOldFont = ::SelectFont( mhDC, hNewFont );
+
+ // read CMAP table to update their pCharMap
+ pWinFont->UpdateFromHDC( mhDC );;
+
+ // cleanup temporary font
+ ::SelectFont( mhDC, hOldFont );
+ ::DeleteFont( hNewFont );
+
+ // get the new charmap
+ pCharMap = pWinFont->GetImplFontCharMap();
+ }
+
+ // avoid fonts with unknown CMAP subtables for glyph fallback
+ if( !pCharMap || pCharMap->IsDefaultMap() )
+ return false;
+
+ int nMatchCount = 0;
+ // static const int nMaxMatchCount = 1; // TODO: check more missing characters?
+ const sal_Int32 nStrLen = rMissingChars.getLength();
+ for( sal_Int32 nStrIdx = 0; nStrIdx < nStrLen; ++nStrIdx )
+ {
+ const sal_UCS4 uChar = rMissingChars.iterateCodePoints( &nStrIdx );
+ nMatchCount += pCharMap->HasChar( uChar );
+ break; // for now
+ }
+
+ const bool bHasMatches = (nMatchCount > 0);
+ return bHasMatches;
+}
+
+// find a fallback font for missing characters
+// TODO: should stylistic matches be searched and prefered?
+bool WinGlyphFallbackSubstititution::FindFontSubstitute( ImplFontSelectData& rFontSelData, rtl::OUString& rMissingChars ) const
+{
+ // guess a locale matching to the missing chars
+ com::sun::star::lang::Locale aLocale;
+
+ sal_Int32 nStrIdx = 0;
+ const sal_Int32 nStrLen = rMissingChars.getLength();
+ while( nStrIdx < nStrLen )
+ {
+ const sal_UCS4 uChar = rMissingChars.iterateCodePoints( &nStrIdx );
+ const LanguageType eLang = MapCharToLanguage( uChar );
+ if( eLang == LANGUAGE_DONTKNOW )
+ continue;
+ MsLangId::convertLanguageToLocale( eLang, aLocale );
+ break;
+ }
+
+ // fall back to default UI locale if the missing characters are inconclusive
+ if( nStrIdx >= nStrLen )
+ aLocale = Application::GetSettings().GetUILocale();
+
+ // first level fallback:
+ // try use the locale specific default fonts defined in VCL.xcu
+ const ImplDevFontList* pDevFontList = ImplGetSVData()->maGDIData.mpScreenFontList;
+ /*const*/ ImplDevFontListData* pDevFont = pDevFontList->ImplFindByLocale( aLocale );
+ if( pDevFont )
+ {
+ const ImplFontData* pFace = pDevFont->FindBestFontFace( rFontSelData );
+ if( HasMissingChars( pFace, rMissingChars ) )
+ {
+ rFontSelData.maSearchName = pDevFont->GetSearchName();
+ return true;
+ }
+ }
+
+ // are the missing characters symbols?
+ pDevFont = pDevFontList->ImplFindByAttributes( IMPL_FONT_ATTR_SYMBOL,
+ rFontSelData.meWeight, rFontSelData.meWidthType,
+ rFontSelData.meFamily, rFontSelData.meItalic, rFontSelData.maSearchName );
+ if( pDevFont )
+ {
+ const ImplFontData* pFace = pDevFont->FindBestFontFace( rFontSelData );
+ if( HasMissingChars( pFace, rMissingChars ) )
+ {
+ rFontSelData.maSearchName = pDevFont->GetSearchName();
+ return true;
+ }
+ }
+
+ // last level fallback, check each font type face one by one
+ const ImplGetDevFontList* pTestFontList = pDevFontList->GetDevFontList();
+ // limit the count of fonts to be checked to prevent hangs
+ static const int MAX_GFBFONT_COUNT = 600;
+ int nTestFontCount = pTestFontList->Count();
+ if( nTestFontCount > MAX_GFBFONT_COUNT )
+ nTestFontCount = MAX_GFBFONT_COUNT;
+
+ for( int i = 0; i < nTestFontCount; ++i )
+ {
+ const ImplFontData* pFace = pTestFontList->Get( i );
+ if( !HasMissingChars( pFace, rMissingChars ) )
+ continue;
+ rFontSelData.maSearchName = pFace->maName;
+ return true;
+ }
+
+ return false;
+}
+
// =======================================================================
struct ImplEnumInfo
@@ -903,6 +1208,8 @@ bool ImplWinFontData::IsGSUBstituted( sal_UCS4 cChar ) const
ImplFontCharMap* ImplWinFontData::GetImplFontCharMap() const
{
+ if( !mpUnicodeMap )
+ return NULL;
mpUnicodeMap->AddReference();
return mpUnicodeMap;
}
@@ -2237,6 +2544,10 @@ void WinSalGraphics::GetDevFontList( ImplDevFontList* pFontList )
bImplSalCourierScalable = aInfo.mbImplSalCourierScalable;
bImplSalCourierNew = aInfo.mbImplSalCourierNew;
}
+
+ // set glyph fallback hook
+ static WinGlyphFallbackSubstititution aSubstFallback( mhDC );
+ pFontList->SetFallbackHook( &aSubstFallback );
}
// ----------------------------------------------------------------------------