summaryrefslogtreecommitdiff
path: root/vcl/aqua/source/gdi/salatsuifontutils.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/aqua/source/gdi/salatsuifontutils.cxx')
-rw-r--r--vcl/aqua/source/gdi/salatsuifontutils.cxx552
1 files changed, 552 insertions, 0 deletions
diff --git a/vcl/aqua/source/gdi/salatsuifontutils.cxx b/vcl/aqua/source/gdi/salatsuifontutils.cxx
new file mode 100644
index 000000000000..8281c41ceeab
--- /dev/null
+++ b/vcl/aqua/source/gdi/salatsuifontutils.cxx
@@ -0,0 +1,552 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <boost/assert.hpp>
+#include <vector>
+#include <set>
+
+#include "salgdi.h"
+#include "saldata.hxx"
+#include "vcl/svapp.hxx"
+#include "salatsuifontutils.hxx"
+
+// we have to get the font attributes from the name table
+// since neither head's macStyle nor OS/2's panose are easily available
+// during font enumeration. macStyle bits would be not sufficient anyway
+// and SFNT fonts on Mac usually do not contain an OS/2 table.
+static void UpdateAttributesFromPSName( const String& rPSName, ImplDevFontAttributes& rDFA )
+{
+ ByteString aPSName( rPSName, RTL_TEXTENCODING_UTF8 );
+ aPSName.ToLowerAscii();
+
+ // TODO: use a multi-string ignore-case matcher once it becomes available
+ if( (aPSName.Search("regular") != STRING_NOTFOUND)
+ || (aPSName.Search("normal") != STRING_NOTFOUND)
+ || (aPSName.Search("roman") != STRING_NOTFOUND)
+ || (aPSName.Search("medium") != STRING_NOTFOUND)
+ || (aPSName.Search("plain") != STRING_NOTFOUND)
+ || (aPSName.Search("standard") != STRING_NOTFOUND)
+ || (aPSName.Search("std") != STRING_NOTFOUND) )
+ {
+ rDFA.meWidthType = WIDTH_NORMAL;
+ rDFA.meWeight = WEIGHT_NORMAL;
+ rDFA.meItalic = ITALIC_NONE;
+ }
+
+ // heuristics for font weight
+ if (aPSName.Search("extrablack") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_BLACK;
+ else if (aPSName.Search("black") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_BLACK;
+ //else if (aPSName.Search("book") != STRING_NOTFOUND)
+ // rDFA.meWeight = WEIGHT_SEMIBOLD;
+ else if( (aPSName.Search("semibold") != STRING_NOTFOUND)
+ || (aPSName.Search("smbd") != STRING_NOTFOUND))
+ rDFA.meWeight = WEIGHT_SEMIBOLD;
+ else if (aPSName.Search("ultrabold") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_ULTRABOLD;
+ else if (aPSName.Search("extrabold") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_BLACK;
+ else if( (aPSName.Search("bold") != STRING_NOTFOUND)
+ || (aPSName.Search("-bd") != STRING_NOTFOUND))
+ rDFA.meWeight = WEIGHT_BOLD;
+ else if (aPSName.Search("extralight") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_ULTRALIGHT;
+ else if (aPSName.Search("ultralight") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_ULTRALIGHT;
+ else if (aPSName.Search("light") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_LIGHT;
+ else if (aPSName.Search("thin") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_THIN;
+ else if (aPSName.Search("-w3") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_LIGHT;
+ else if (aPSName.Search("-w4") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_SEMILIGHT;
+ else if (aPSName.Search("-w5") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_NORMAL;
+ else if (aPSName.Search("-w6") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_SEMIBOLD;
+ else if (aPSName.Search("-w7") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_BOLD;
+ else if (aPSName.Search("-w8") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_ULTRABOLD;
+ else if (aPSName.Search("-w9") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_BLACK;
+
+ // heuristics for font slant
+ if( (aPSName.Search("italic") != STRING_NOTFOUND)
+ || (aPSName.Search(" ital") != STRING_NOTFOUND)
+ || (aPSName.Search("cursive") != STRING_NOTFOUND)
+ || (aPSName.Search("-it") != STRING_NOTFOUND)
+ || (aPSName.Search("lightit") != STRING_NOTFOUND)
+ || (aPSName.Search("mediumit") != STRING_NOTFOUND)
+ || (aPSName.Search("boldit") != STRING_NOTFOUND)
+ || (aPSName.Search("cnit") != STRING_NOTFOUND)
+ || (aPSName.Search("bdcn") != STRING_NOTFOUND)
+ || (aPSName.Search("bdit") != STRING_NOTFOUND)
+ || (aPSName.Search("condit") != STRING_NOTFOUND)
+ || (aPSName.Search("bookit") != STRING_NOTFOUND)
+ || (aPSName.Search("blackit") != STRING_NOTFOUND) )
+ rDFA.meItalic = ITALIC_NORMAL;
+ if( (aPSName.Search("oblique") != STRING_NOTFOUND)
+ || (aPSName.Search("inclined") != STRING_NOTFOUND)
+ || (aPSName.Search("slanted") != STRING_NOTFOUND) )
+ rDFA.meItalic = ITALIC_OBLIQUE;
+
+ // heuristics for font width
+ if( (aPSName.Search("condensed") != STRING_NOTFOUND)
+ || (aPSName.Search("-cond") != STRING_NOTFOUND)
+ || (aPSName.Search("boldcond") != STRING_NOTFOUND)
+ || (aPSName.Search("boldcn") != STRING_NOTFOUND)
+ || (aPSName.Search("cnit") != STRING_NOTFOUND) )
+ rDFA.meWidthType = WIDTH_CONDENSED;
+ else if (aPSName.Search("narrow") != STRING_NOTFOUND)
+ rDFA.meWidthType = WIDTH_SEMI_CONDENSED;
+ else if (aPSName.Search("expanded") != STRING_NOTFOUND)
+ rDFA.meWidthType = WIDTH_EXPANDED;
+ else if (aPSName.Search("wide") != STRING_NOTFOUND)
+ rDFA.meWidthType = WIDTH_EXPANDED;
+
+ // heuristics for font pitch
+ if( (aPSName.Search("mono") != STRING_NOTFOUND)
+ || (aPSName.Search("courier") != STRING_NOTFOUND)
+ || (aPSName.Search("monaco") != STRING_NOTFOUND)
+ || (aPSName.Search("typewriter") != STRING_NOTFOUND) )
+ rDFA.mePitch = PITCH_FIXED;
+
+ // heuristics for font family type
+ if( (aPSName.Search("script") != STRING_NOTFOUND)
+ || (aPSName.Search("chancery") != STRING_NOTFOUND)
+ || (aPSName.Search("zapfino") != STRING_NOTFOUND))
+ rDFA.meFamily = FAMILY_SCRIPT;
+ else if( (aPSName.Search("comic") != STRING_NOTFOUND)
+ || (aPSName.Search("outline") != STRING_NOTFOUND)
+ || (aPSName.Search("pinpoint") != STRING_NOTFOUND) )
+ rDFA.meFamily = FAMILY_DECORATIVE;
+ else if( (aPSName.Search("sans") != STRING_NOTFOUND)
+ || (aPSName.Search("arial") != STRING_NOTFOUND) )
+ rDFA.meFamily = FAMILY_SWISS;
+ else if( (aPSName.Search("roman") != STRING_NOTFOUND)
+ || (aPSName.Search("times") != STRING_NOTFOUND) )
+ rDFA.meFamily = FAMILY_ROMAN;
+
+ // heuristics for codepoint semantic
+ if( (aPSName.Search("symbol") != STRING_NOTFOUND)
+ || (aPSName.Search("dings") != STRING_NOTFOUND)
+ || (aPSName.Search("dingbats") != STRING_NOTFOUND)
+ || (aPSName.Search("ornaments") != STRING_NOTFOUND)
+ || (aPSName.Search("embellishments") != STRING_NOTFOUND) )
+ rDFA.mbSymbolFlag = true;
+
+ // #i100020# special heuristic for names with single-char styles
+ // NOTE: we are checking name that hasn't been lower-cased
+ if( rPSName.Len() > 3 )
+ {
+ int i = rPSName.Len();
+ sal_Unicode c = rPSName.GetChar( --i );
+ if( c == 'C' ) { // "capitals"
+ rDFA.meFamily = FAMILY_DECORATIVE;
+ c = rPSName.GetChar( --i );
+ }
+ if( c == 'O' ) { // CFF-based OpenType
+ c = rPSName.GetChar( --i );
+ }
+ if( c == 'I' ) { // "italic"
+ rDFA.meItalic = ITALIC_NORMAL;
+ c = rPSName.GetChar( --i );
+ }
+ if( c == 'B' ) // "bold"
+ rDFA.meWeight = WEIGHT_BOLD;
+ if( c == 'C' ) // "capitals"
+ rDFA.meFamily = FAMILY_DECORATIVE;
+ // TODO: check that all single-char styles have been resolved?
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static bool GetDevFontAttributes( ATSUFontID nFontID, ImplDevFontAttributes& rDFA )
+{
+ // all ATSU fonts are device fonts that can be directly rotated
+ rDFA.mbOrientation = true;
+ rDFA.mbDevice = true;
+ rDFA.mnQuality = 0;
+
+ // reset the attributes
+ rDFA.meFamily = FAMILY_DONTKNOW;
+ rDFA.mePitch = PITCH_VARIABLE;
+ rDFA.meWidthType = WIDTH_NORMAL;
+ rDFA.meWeight = WEIGHT_NORMAL;
+ rDFA.meItalic = ITALIC_NONE;
+ rDFA.mbSymbolFlag = false;
+
+ // ignore bitmap fonts
+ ATSFontRef rATSFontRef = FMGetATSFontRefFromFont( nFontID );
+ ByteCount nHeadLen = 0;
+ OSStatus rc = ATSFontGetTable( rATSFontRef, 0x68656164/*head*/, 0, 0, NULL, &nHeadLen );
+ if( (rc != noErr) || (nHeadLen <= 0) )
+ return false;
+
+ // all scalable fonts on this platform are subsettable
+ rDFA.mbSubsettable = true;
+ rDFA.mbEmbeddable = false;
+
+ // prepare iterating over all name strings of the font
+ ItemCount nFontNameCount = 0;
+ rc = ATSUCountFontNames( nFontID, &nFontNameCount );
+ if( rc != noErr )
+ return false;
+ int nBestNameValue = 0;
+ int nBestStyleValue = 0;
+ FontLanguageCode eBestLangCode = 0;
+ const FontLanguageCode eUILangCode = Application::GetSettings().GetUILanguage();
+ typedef std::vector<char> NameBuffer;
+ NameBuffer aNameBuffer( 256 );
+
+ // iterate over all available name strings of the font
+ for( ItemCount nNameIndex = 0; nNameIndex < nFontNameCount; ++nNameIndex )
+ {
+ ByteCount nNameLength = 0;
+
+ FontNameCode eFontNameCode;
+ FontPlatformCode eFontNamePlatform;
+ FontScriptCode eFontNameScript;
+ FontLanguageCode eFontNameLanguage;
+ rc = ATSUGetIndFontName( nFontID, nNameIndex, 0, NULL,
+ &nNameLength, &eFontNameCode, &eFontNamePlatform, &eFontNameScript, &eFontNameLanguage );
+ if( rc != noErr )
+ continue;
+
+ // ignore non-interesting name entries
+ if( (eFontNameCode != kFontFamilyName)
+ && (eFontNameCode != kFontStyleName)
+ && (eFontNameCode != kFontPostscriptName) )
+ continue;
+
+ // heuristic to find the most common font name
+ // prefering default language names or even better the names matching to the UI language
+ int nNameValue = (eFontNameLanguage==eUILangCode) ? 0 : ((eFontNameLanguage==0) ? -10 : -20);
+ rtl_TextEncoding eEncoding = RTL_TEXTENCODING_UNICODE;
+ const int nPlatformEncoding = ((int)eFontNamePlatform << 8) + (int)eFontNameScript;
+ switch( nPlatformEncoding )
+ {
+ case 0x000: nNameValue += 23; break; // Unicode 1.0
+ case 0x001: nNameValue += 24; break; // Unicode 1.1
+ case 0x002: nNameValue += 25; break; // iso10646_1993
+ case 0x003: nNameValue += 26; break; // UCS-2
+ case 0x301: nNameValue += 27; break; // Win UCS-2
+ case 0x004: // UCS-4
+ case 0x30A: nNameValue += 0; // Win-UCS-4
+ eEncoding = RTL_TEXTENCODING_UCS4;
+ break;
+ case 0x100: nNameValue += 21; // Mac Roman
+ eEncoding = RTL_TEXTENCODING_APPLE_ROMAN;
+ break;
+ case 0x300: nNameValue = 0; // Win Symbol encoded name!
+ rDFA.mbSymbolFlag = true; // (often seen for symbol fonts)
+ break;
+ default: nNameValue = 0; // ignore other encodings
+ break;
+ }
+
+ // ignore name entries with no useful encoding
+ if( nNameValue <= 0 )
+ continue;
+ if( nNameLength >= aNameBuffer.size() )
+ continue;
+
+ // get the encoded name
+ aNameBuffer.reserve( nNameLength+1 ); // extra byte helps for debugging
+ rc = ATSUGetIndFontName( nFontID, nNameIndex, nNameLength, &aNameBuffer[0],
+ &nNameLength, &eFontNameCode, &eFontNamePlatform, &eFontNameScript, &eFontNameLanguage );
+ if( rc != noErr )
+ continue;
+
+ // convert to unicode name
+ UniString aUtf16Name;
+ if( eEncoding == RTL_TEXTENCODING_UNICODE ) // we are just interested in UTF16 encoded names
+ aUtf16Name = UniString( (const sal_Unicode*)&aNameBuffer[0], nNameLength/2 );
+ else if( eEncoding == RTL_TEXTENCODING_UCS4 )
+ aUtf16Name = UniString(); // TODO
+ else // assume the non-unicode encoded names are byte encoded
+ aUtf16Name = UniString( &aNameBuffer[0], nNameLength, eEncoding );
+
+ // ignore empty strings
+ if( aUtf16Name.Len() <= 0 )
+ continue;
+
+ // handle the name depending on its namecode
+ switch( eFontNameCode )
+ {
+ case kFontFamilyName:
+ // ignore font names starting with '.'
+ if( aUtf16Name.GetChar(0) == '.' )
+ nNameValue = 0;
+ else if( rDFA.maName.Len() )
+ {
+ // even if a family name is not the one we are looking for
+ // it is still useful as a font name alternative
+ if( rDFA.maMapNames.Len() )
+ rDFA.maMapNames += ';';
+ rDFA.maMapNames += (nBestNameValue < nNameValue) ? rDFA.maName : aUtf16Name;
+ }
+ if( nBestNameValue < nNameValue )
+ {
+ // get the best family name
+ nBestNameValue = nNameValue;
+ eBestLangCode = eFontNameLanguage;
+ rDFA.maName = aUtf16Name;
+ }
+ break;
+ case kFontStyleName:
+ // get a style name matching to the family name
+ if( nBestStyleValue < nNameValue )
+ {
+ nBestStyleValue = nNameValue;
+ rDFA.maStyleName = aUtf16Name;
+ }
+ break;
+ case kFontPostscriptName:
+ // use the postscript name to get some useful info
+ UpdateAttributesFromPSName( aUtf16Name, rDFA );
+ break;
+ default:
+ // TODO: use other name entries too?
+ break;
+ }
+ }
+
+#if 0 // multiple-master fonts are mostly obsolete nowadays
+ // if we still want to support them this should probably be done one frame higher
+ ItemCount nMaxInstances = 0;
+ rc = ATSUCountFontInstances ( nFontID, &nMaxInstances );
+ for( ItemCount nInstanceIndex = 0; nInstanceIndex < nMaxInstances; ++nInstanceIndex )
+ {
+ ItemCount nMaxVariations = 0;
+ rc = ATSUGetFontInstance( nFontID, nInstanceIndex, 0, NULL, NULL, &nMaxVariations );
+ if( (rc == noErr) && (nMaxVariations > 0) )
+ {
+ fprintf(stderr,"\tnMaxVariations=%d\n",(int)nMaxVariations);
+ typedef ::std::vector<ATSUFontVariationAxis> VariationAxisVector;
+ typedef ::std::vector<ATSUFontVariationValue> VariationValueVector;
+ VariationAxisVector aVariationAxes( nMaxVariations );
+ VariationValueVector aVariationValues( nMaxVariations );
+ ItemCount nVariationCount = 0;
+ rc = ATSUGetFontInstance ( nFontID, nInstanceIndex, nMaxVariations,
+ &aVariationAxes[0], &aVariationValues[0], &nVariationCount );
+ fprintf(stderr,"\tnVariationCount=%d\n",(int)nVariationCount);
+ for( ItemCount nVariationIndex = 0; nVariationIndex < nMaxVariations; ++nVariationIndex )
+ {
+ const char* pTag = (const char*)&aVariationAxes[nVariationIndex];
+ fprintf(stderr,"\tvariation[%d] \'%c%c%c%c\' is %d\n", (int)nVariationIndex,
+ pTag[3],pTag[2],pTag[1],pTag[0], (int)aVariationValues[nVariationIndex]);
+ }
+ }
+ }
+#endif
+
+#if 0 // selecting non-defaulted font features is not enabled yet
+ ByteString aFName( rDFA.maName, RTL_TEXTENCODING_UTF8 );
+ ByteString aSName( rDFA.maStyleName, RTL_TEXTENCODING_UTF8 );
+ ItemCount nMaxFeatures = 0;
+ rc = ATSUCountFontFeatureTypes( nFontID, &nMaxFeatures );
+ fprintf(stderr,"Font \"%s\" \"%s\" has %d features\n",aFName.GetBuffer(),aSName.GetBuffer(),rc);
+ if( (rc == noErr) && (nMaxFeatures > 0) )
+ {
+ typedef std::vector<ATSUFontFeatureType> FeatureVector;
+ FeatureVector aFeatureVector( nMaxFeatures );
+ ItemCount nFeatureCount = 0;
+ rc = ATSUGetFontFeatureTypes( nFontID, nMaxFeatures, &aFeatureVector[0], &nFeatureCount );
+ fprintf(stderr,"nFeatureCount=%d\n",(int)nFeatureCount);
+ for( ItemCount nFeatureIndex = 0; nFeatureIndex < nFeatureCount; ++nFeatureIndex )
+ {
+ ItemCount nMaxSelectors = 0;
+ rc = ATSUCountFontFeatureSelectors( nFontID, aFeatureVector[nFeatureIndex], &nMaxSelectors );
+ fprintf(stderr,"\tFeature[%d] = %d has %d selectors\n",
+ (int)nFeatureIndex, (int)aFeatureVector[nFeatureIndex], (int)nMaxSelectors );
+ typedef std::vector<ATSUFontFeatureSelector> SelectorVector;
+ SelectorVector aSelectorVector( nMaxSelectors );
+ typedef std::vector<MacOSBoolean> BooleanVector;
+ BooleanVector aEnabledVector( nMaxSelectors );
+ BooleanVector aExclusiveVector( nMaxSelectors );
+ ItemCount nSelectorCount = 0;
+ rc = ATSUGetFontFeatureSelectors ( nFontID, aFeatureVector[nFeatureIndex], nMaxSelectors,
+ &aSelectorVector[0], &aEnabledVector[0], &nSelectorCount, &aExclusiveVector[0]);
+ for( ItemCount nSelectorIndex = 0; nSelectorIndex < nSelectorCount; ++nSelectorIndex )
+ {
+ FontNameCode eFontNameCode;
+ rc = ATSUGetFontFeatureNameCode( nFontID, aFeatureVector[nFeatureIndex],
+ aSelectorVector[nSelectorIndex], &eFontNameCode );
+ fprintf(stderr,"\t\tselector[%d] n=%d e=%d, x=%d\n",
+ (int)nSelectorIndex, (int)eFontNameCode,
+ aEnabledVector[nSelectorIndex], aExclusiveVector[nSelectorIndex] );
+ }
+ }
+ }
+#endif
+
+ bool bRet = (rDFA.maName.Len() > 0);
+ return bRet;
+}
+
+// =======================================================================
+
+SystemFontList::SystemFontList()
+{
+ // count available system fonts
+ ItemCount nATSUICompatibleFontsAvailable = 0;
+ if( ATSUFontCount(&nATSUICompatibleFontsAvailable) != noErr )
+ return;
+ if( nATSUICompatibleFontsAvailable <= 0 )
+ return;
+
+ // enumerate available system fonts
+ typedef std::vector<ATSUFontID> AtsFontIDVector;
+ AtsFontIDVector aFontIDVector( nATSUICompatibleFontsAvailable );
+ ItemCount nFontItemsCount = 0;
+ if( ATSUGetFontIDs( &aFontIDVector[0], aFontIDVector.capacity(), &nFontItemsCount ) != noErr )
+ return;
+
+ BOOST_ASSERT(nATSUICompatibleFontsAvailable == nFontItemsCount && "Strange I would expect them to be equal");
+
+ // prepare use of the available fonts
+ AtsFontIDVector::const_iterator it = aFontIDVector.begin();
+ for(; it != aFontIDVector.end(); ++it )
+ {
+ const ATSUFontID nFontID = *it;
+ ImplDevFontAttributes aDevFontAttr;
+ if( !GetDevFontAttributes( nFontID, aDevFontAttr ) )
+ continue;
+ ImplMacFontData* pFontData = new ImplMacFontData( aDevFontAttr, nFontID );
+ maFontContainer[ nFontID ] = pFontData;
+ }
+
+ InitGlyphFallbacks();
+}
+
+// -----------------------------------------------------------------------
+
+SystemFontList::~SystemFontList()
+{
+ MacFontContainer::const_iterator it = maFontContainer.begin();
+ for(; it != maFontContainer.end(); ++it )
+ delete (*it).second;
+ maFontContainer.clear();
+
+ ATSUDisposeFontFallbacks( maFontFallbacks );
+}
+
+// -----------------------------------------------------------------------
+
+void SystemFontList::AnnounceFonts( ImplDevFontList& rFontList ) const
+{
+ MacFontContainer::const_iterator it = maFontContainer.begin();
+ for(; it != maFontContainer.end(); ++it )
+ rFontList.Add( (*it).second->Clone() );
+}
+
+// -----------------------------------------------------------------------
+
+// not all fonts are suitable for glyph fallback => sort them
+struct GfbCompare{ bool operator()(const ImplMacFontData*, const ImplMacFontData*); };
+
+inline bool GfbCompare::operator()( const ImplMacFontData* pA, const ImplMacFontData* pB )
+{
+ // use symbol fonts only as last resort
+ bool bPreferA = !pA->IsSymbolFont();
+ bool bPreferB = !pB->IsSymbolFont();
+ if( bPreferA != bPreferB )
+ return bPreferA;
+ // prefer scalable fonts
+ bPreferA = pA->IsScalable();
+ bPreferB = pB->IsScalable();
+ if( bPreferA != bPreferB )
+ return bPreferA;
+ // prefer non-slanted fonts
+ bPreferA = (pA->GetSlant() == ITALIC_NONE);
+ bPreferB = (pB->GetSlant() == ITALIC_NONE);
+ if( bPreferA != bPreferB )
+ return bPreferA;
+ // prefer normal weight fonts
+ bPreferA = (pA->GetWeight() == WEIGHT_NORMAL);
+ bPreferB = (pB->GetWeight() == WEIGHT_NORMAL);
+ if( bPreferA != bPreferB )
+ return bPreferA;
+ // prefer normal width fonts
+ bPreferA = (pA->GetWidthType() == WIDTH_NORMAL);
+ bPreferB = (pB->GetWidthType() == WIDTH_NORMAL);
+ if( bPreferA != bPreferB )
+ return bPreferA;
+ return false;
+}
+
+void SystemFontList::InitGlyphFallbacks()
+{
+ // sort fonts for "glyph fallback"
+ typedef std::multiset<const ImplMacFontData*,GfbCompare> FallbackSet;
+ FallbackSet aFallbackSet;
+ MacFontContainer::const_iterator it = maFontContainer.begin();
+ for(; it != maFontContainer.end(); ++it )
+ {
+ const ImplMacFontData* pIFD = (*it).second;
+ // TODO: subsettable/embeddable glyph fallback only for PDF export?
+ if( pIFD->IsSubsettable() || pIFD->IsEmbeddable() )
+ aFallbackSet.insert( pIFD );
+ }
+
+ // tell ATSU about font preferences for "glyph fallback"
+ typedef std::vector<ATSUFontID> AtsFontIDVector;
+ AtsFontIDVector aFallbackVector;
+ aFallbackVector.reserve( maFontContainer.size() );
+ FallbackSet::const_iterator itFData = aFallbackSet.begin();
+ for(; itFData != aFallbackSet.end(); ++itFData )
+ {
+ const ImplMacFontData* pFontData = (*itFData);
+ ATSUFontID nFontID = (ATSUFontID)pFontData->GetFontId();
+ aFallbackVector.push_back( nFontID );
+ }
+
+ ATSUCreateFontFallbacks( &maFontFallbacks );
+ ATSUSetObjFontFallbacks( maFontFallbacks,
+ aFallbackVector.size(), &aFallbackVector[0], kATSUSequentialFallbacksPreferred );
+}
+
+// -----------------------------------------------------------------------
+
+ImplMacFontData* SystemFontList::GetFontDataFromId( ATSUFontID nFontId ) const
+{
+ MacFontContainer::const_iterator it = maFontContainer.find( nFontId );
+ if( it == maFontContainer.end() )
+ return NULL;
+ return (*it).second;
+}
+
+// -----------------------------------------------------------------------
+