--- openoffice.org.orig/vcl/inc/outdev.h 2005-09-12 13:37:38.000000000 +0100 +++ openoffice.org.orig/vcl/inc/outdev.h 2005-09-12 14:10:15.000000000 +0100 @@ -239,7 +239,8 @@ const Font& rFont, const Size& rSize, ImplFontSubstEntry* pDevSpecific ); ImplFontEntry* GetFallback( ImplDevFontList* pFontList, const Font& rFont, const Size& rSize, - int nFallbackLevel ); + int nFallbackLevel, sal_Unicode *pMissingUnicodes, + int nMissingUnicodes ); void Release( ImplFontEntry* ); void Invalidate(); }; --- openoffice.org.orig/vcl/inc/outfont.hxx 2005-09-12 13:37:38.000000000 +0100 +++ openoffice.org.orig/vcl/inc/outfont.hxx 2005-09-12 14:48:01.000000000 +0100 @@ -252,6 +252,7 @@ ImplDevFontListData* FindFontFamily( const String& rFontName ) const; ImplDevFontListData* ImplFindByFont( ImplFontSelectData&, bool bPrinter, ImplFontSubstEntry* pDevSpecificSubst ) const; ImplDevFontListData* ImplFindBySearchName( const String& ) const; + ImplDevFontListData* ImplGetFontconfigSubstitute( ImplFontSelectData &rFontSelData, ImplFontSubstEntry* pDevSpecific ); bool HasFallbacks() const; void SetFallbacks( ImplDevFontListData**, int nCount ); @@ -354,6 +355,10 @@ ImplFontEntry( const ImplFontSelectData& ); virtual ~ImplFontEntry() {} + // cache of Unicode characters and replacement font names + typedef ::std::hash_map UnicodeFallbackList; + UnicodeFallbackList maUnicodeFallbackList; + public: // TODO: make data members private ImplFontSelectData maFontSelData; // FontSelectionData ImplFontMetricData maMetric; // Font Metric @@ -364,6 +369,16 @@ short mnOwnOrientation; // text angle if lower layers don't rotate text themselves short mnOrientation; // text angle in 3600 system bool mbInit; // true if maMetric member is valid + + void AddFallbackForUnicode( sal_Unicode ch, String fallback ) + { maUnicodeFallbackList[ch] = fallback; } + String GetFallbackForUnicode( sal_Unicode ch ) + { + UnicodeFallbackList::const_iterator it = maUnicodeFallbackList.find( ch ); + if ( it != maUnicodeFallbackList.end() ) + return (*it).second; + return String(); + } }; --- openoffice.org.orig/vcl/source/gdi/outdev3.cxx 2005-09-12 13:37:04.000000000 +0100 +++ openoffice.org.orig/vcl/source/gdi/outdev3.cxx 2005-09-12 15:26:08.000000000 +0100 @@ -185,6 +185,9 @@ #include #include +#include +#include + // ======================================================================= DBG_NAMEEX( OutputDevice ); @@ -2670,6 +2673,124 @@ } } + +// ----------------------------------------------------------------------- + +String GetFcSubstitute(const ImplFontSelectData &rFontSelData, sal_Unicode *pMissingGlyphs=0, int nMissingGlyphs=0) +{ + std::vector aNames; + if( rFontSelData.GetFamilyName().Len() ) + { + sal_uInt16 nIndex = 0; + String aTempName; + do + { + aTempName = GetNextFontToken(rFontSelData.GetFamilyName(), nIndex); + aNames.push_back(aTempName); + } + while (nIndex != STRING_NOTFOUND); + } + + std::vector aGlyphs; + for (int i=0; i < nMissingGlyphs; ++i) + aGlyphs.push_back(pMissingGlyphs[i]); + + ByteString aLangAttrib = ConvertLanguageToIsoByteString( rFontSelData.meLanguage ); + + psp::italic::type eItalic = psp::italic::Unknown; + if( rFontSelData.GetSlant() != ITALIC_DONTKNOW ) + { + switch( rFontSelData.GetSlant() ) + { + case ITALIC_NORMAL: eItalic = psp::italic::Italic; break; + case ITALIC_OBLIQUE: eItalic = psp::italic::Oblique; break; + default: + break; + } + } + + psp::weight::type eWeight = psp::weight::Unknown; + if( rFontSelData.GetWeight() != WEIGHT_DONTKNOW ) + { + switch( rFontSelData.GetWeight() ) + { + case WEIGHT_THIN: eWeight = psp::weight::Thin; break; + case WEIGHT_ULTRALIGHT: eWeight = psp::weight::UltraLight; break; + case WEIGHT_LIGHT: eWeight = psp::weight::Light; break; + case WEIGHT_SEMILIGHT: eWeight = psp::weight::SemiLight; break; + case WEIGHT_NORMAL: eWeight = psp::weight::Normal; break; + case WEIGHT_MEDIUM: eWeight = psp::weight::Medium; break; + case WEIGHT_SEMIBOLD: eWeight = psp::weight::SemiBold; break; + case WEIGHT_BOLD: eWeight = psp::weight::Bold; break; + case WEIGHT_ULTRABOLD: eWeight = psp::weight::UltraBold; break; + case WEIGHT_BLACK: eWeight = psp::weight::Black; break; + default: + break; + } + } + + psp::width::type eWidth = psp::width::Unknown; + if( rFontSelData.GetWidthType() != WIDTH_DONTKNOW ) + { + switch( rFontSelData.GetWidthType() ) + { + case WIDTH_ULTRA_CONDENSED: eWidth = psp::width::UltraCondensed; break; + case WIDTH_EXTRA_CONDENSED: eWidth = psp::width::ExtraCondensed; break; + case WIDTH_CONDENSED: eWidth = psp::width::Condensed; break; + case WIDTH_SEMI_CONDENSED: eWidth = psp::width::SemiCondensed; break; + case WIDTH_NORMAL: eWidth = psp::width::Normal; break; + case WIDTH_SEMI_EXPANDED: eWidth = psp::width::SemiExpanded; break; + case WIDTH_EXPANDED: eWidth = psp::width::Expanded; break; + case WIDTH_EXTRA_EXPANDED: eWidth = psp::width::ExtraExpanded; break; + case WIDTH_ULTRA_EXPANDED: eWidth = psp::width::UltraExpanded; break; + default: + break; + } + } + + psp::pitch::type ePitch = psp::pitch::Unknown; + if( rFontSelData.GetPitch() != PITCH_DONTKNOW ) + { + switch( rFontSelData.GetPitch() ) + { + case PITCH_FIXED: ePitch=psp::pitch::Fixed; break; + case PITCH_VARIABLE: ePitch=psp::pitch::Variable; break; + default: + break; + } + } + + const psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); + return rMgr.Substitute(aNames, aGlyphs, aLangAttrib, eItalic, eWeight, eWidth, ePitch); +} + +// ----------------------------------------------------------------------- + +ImplDevFontListData *ImplDevFontList::ImplGetFontconfigSubstitute( ImplFontSelectData &rFontSelData, ImplFontSubstEntry* pDevSpecific ) +{ + // We dont' actually want to talk to Fontconfig at all for symbol fonts + if (rFontSelData.IsSymbolFont()) + return 0; + // StarSymbol is a unicode font, but it still deserves the symbol flag + if( 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "starsymbol", 10) + || 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "opensymbol", 10) ) + return 0; + + String aName(GetFcSubstitute(rFontSelData)); + if (!aName.Len()) + return 0; + + String aUserName(aName); + ImplGetEnglishSearchFontName( aName ); + ImplFontSubstitute( aName, FONT_SUBSTITUTE_ALWAYS, pDevSpecific ); + ImplDevFontListData *pFontFamily = ImplFindBySearchName( aName ); + if (pFontFamily) + rFontSelData.maTargetName = aUserName; + + return pFontFamily; +} + + // ----------------------------------------------------------------------- ImplFontEntry* ImplFontCache::Get( ImplDevFontList* pFontList, @@ -2707,8 +2828,12 @@ if( !pEntry ) // no direct cache hit { - // find the best matching logical font family and update font selector accordingly - pFontFamily = pFontList->ImplFindByFont( aFontSelData, mbPrinter, pDevSpecific ); + pFontFamily = pFontList->ImplGetFontconfigSubstitute( aFontSelData, pDevSpecific ); + if (!pFontFamily) + { + // find the best matching logical font family and update font selector accordingly + pFontFamily = pFontList->ImplFindByFont( aFontSelData, mbPrinter, pDevSpecific ); + } DBG_ASSERT( (pFontFamily != NULL), "ImplFontCache::Get() No logical font found!" ); aFontSelData.maSearchName = pFontFamily->GetSearchName(); @@ -3028,109 +3153,102 @@ // ----------------------------------------------------------------------- ImplFontEntry* ImplFontCache::GetFallback( ImplDevFontList* pFontList, - const Font& rOrigFont, const Size& rSize, int nFallbackLevel ) + const Font& rOrigFont, const Size& rSize, int nFallbackLevel, + sal_Unicode *pMissingUnicodes, int nMissingUnicodes ) { - // make sure the fontlist knows it's fallbacks - if( !pFontList->HasFallbacks() ) + ImplFontEntry* pFallbackFont = NULL; + bool cached = false; + bool new_entry = false; + bool symbolFont = false; + ImplFontEntry* pOrigFontEntry = Get( pFontList, rOrigFont, rSize, NULL ); + ImplFontSelectData aSelData( rOrigFont, rOrigFont.GetName(), rSize ); + sal_uInt16 nToken = 0; + String aOrigFontName( GetNextFontToken(rOrigFont.GetName(), nToken) ); + + const FontSubstConfigItem& rFontSubst = *FontSubstConfigItem::get(); + const FontNameAttr* fontAttr = rFontSubst.getSubstInfo( aOrigFontName ); + + // We dont' actually want to talk to Fontconfig at all for symbol fonts + if ( pFontList && fontAttr && (fontAttr->Type & IMPL_FONT_ATTR_SYMBOL) ) { - // 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", "timesnewroman", "lucidatypewriter", "lucidasans", "nimbussansl", "", - "shree", "mangal", "raavi", "shruti", "tunga", "latha", "", - "shayyalmt", "naskmt", "", - "david", "nachlieli", "lucidagrande", "", - "norasi", "angsanaupc", "", - 0 - }; - - int nMaxLevel = 0; - int nBestQuality = 0; - ImplDevFontListData** pFallbackList = NULL; - for( const char** ppNames = &aGlyphFallbackList[0];; ++ppNames ) + if ( fontAttr->Substitutions.size() ) { - // 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 + ::std::vector< String >::const_iterator it = fontAttr->Substitutions.begin(); + while ( it != fontAttr->Substitutions.end() ) { - if( nBestQuality > 0 ) - if( ++nMaxLevel >= MAX_FALLBACK ) - break; - if( !ppNames[1] ) + // Since *it is the "search name" like "standardsymbolsl" + // we have to find the Family Name (Standard Symbols L) for Fontconfig + ImplDevFontListData* pFontFamily = pFontList->FindFontFamily( *it ); + if (pFontFamily) + { + aSelData.maSearchName = pFontFamily->GetFamilyName(); break; - nBestQuality = 0; - continue; + } + ++it; } + } + symbolFont = true; + cached = true; + } - // test if the glyph fallback candidate font is available and scalable - String aTokenName( *ppNames, RTL_TEXTENCODING_UTF8 ); - ImplDevFontListData* pFallbackFont = pFontList->FindFontFamily( aTokenName ); - if( !pFallbackFont ) - continue; - if( !pFallbackFont->IsScalable() ) - continue; + // Try cached fallbacks first + if ( !symbolFont && (nMissingUnicodes > 0) ) + { + aSelData.maSearchName = pOrigFontEntry->GetFallbackForUnicode( pMissingUnicodes[0] ); + if ( aSelData.maSearchName.Len() ) + cached = true; + } - // 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 ImplDevFontListData*[ MAX_FALLBACK ]; - pFallbackList[ nMaxLevel ] = pFallbackFont; - } - } + if ( !cached ) + { + String aName(GetFcSubstitute( aSelData, pMissingUnicodes, nMissingUnicodes )); + if (aName.Len()) + aSelData.maSearchName = aName; + } - // sort the fonts for glyph fallback by quality (highest first) - // an insertion sort is good enough for this short list - for( int i = 1, j; i < nMaxLevel; ++i ) - { - ImplDevFontListData* pTestFont = pFallbackList[ i ]; - int nTestQuality = pTestFont->GetMinQuality(); - for( j = i; --j >= 0; ) - if( nTestQuality > pFallbackList[j]->GetMinQuality() ) - pFallbackList[ j+1 ] = pFallbackList[ j ]; - else - break; - pFallbackList[ j+1 ] = pTestFont; - } + // Check our font instance cache first, if not found then + // add this ImplFontSelectData to the cache along with its ImplFontEntry + FontInstanceList::const_iterator it = maFontInstanceList.find( aSelData ); + if (it != maFontInstanceList.end()) + pFallbackFont = (*it).second; + else + { + // find the best matching physical font face + ImplDevFontListData* pFontFamily = pFontList->FindFontFamily( aSelData.maSearchName ); + if (pFontFamily) + { + ImplFontData* pFontData = pFontFamily->FindBestFontFace( aSelData ); -#if defined(HDU_DEBUG) - for( int i = 0; i < nMaxLevel; ++i ) + // create a new logical font instance from this physical font face + aSelData.mpFontData = pFontData; + pFallbackFont = pFontData->CreateFontInstance( aSelData ); + + // if we found a different symbol font we need a symbol conversion table + if( pFontData->IsSymbolFont() ) + if( aSelData.maTargetName != aSelData.maSearchName ) + pFallbackFont->mpConversion = ImplGetRecodeData( aSelData.maTargetName, aSelData.maSearchName ); + + // add the new entry to the cache + maFontInstanceList[ aSelData ] = pFallbackFont; + new_entry = true; + } + else { - ImplDevFontListData* pFont = pFallbackList[ i ]; - ByteString aFontName( pFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ); - fprintf( stderr, "GlyphFallbackFont[%d] (quality=%05d): \"%s\"\n", - i, pFont->GetMinQuality(), aFontName.GetBuffer() ); + ByteString l( aSelData.maSearchName, RTL_TEXTENCODING_UTF8 ); + fprintf (stderr, "--- Couldn't get FontFamily for '%s'\n", l.GetBuffer()); } -#endif - - pFontList->SetFallbacks( pFallbackList, nMaxLevel ); } - Font aFallbackFont = rOrigFont; - - // nFallbackLevel==0 => original font without device specific substitution - // nFallbackLevel>=1 => use a font from the glyph fallback font list - if( nFallbackLevel>=1 ) + // Cache the fallback font for each of the missing Unicode chars + if ( !symbolFont && aSelData.maSearchName.Len() ) { - ImplDevFontListData* pFallbackData = pFontList->GetFallback( nFallbackLevel-1 ); - if( !pFallbackData ) - return NULL; - - aFallbackFont.SetName( pFallbackData->GetSearchName() ); + for ( int i = 0; i < nMissingUnicodes; i++ ) + { + if ( ! pOrigFontEntry->GetFallbackForUnicode(pMissingUnicodes[i]).Len() ) + pOrigFontEntry->AddFallbackForUnicode( pMissingUnicodes[i], aSelData.maSearchName ); + } } - ImplFontEntry* pFallbackFont = Get( pFontList, aFallbackFont, rSize, NULL ); - if( pFallbackFont && !pFallbackFont->mbInit ) { // HACK: maMetrics are irrelevant for fallback fonts, but @@ -3139,6 +3257,27 @@ pFallbackFont->maMetric.maStyleName = String(); } + if ( pFallbackFont && !new_entry ) + { + // increase the font instance's reference count + if( !pFallbackFont->mnRefCount++ ) + --mnRef0Count; + } + +#if 0 + sal_uInt16 nTok = 0; + ByteString n( GetNextFontToken(rOrigFont.GetName(), nTok), RTL_TEXTENCODING_UTF8); + ByteString m; + if (pFallbackFont) + { + nTok = 0; + ByteString tS( GetNextFontToken(pFallbackFont->maFontSelData.mpFontData->GetFamilyName(), nTok), RTL_TEXTENCODING_UTF8 ); + m.Assign( tS ); + } + fprintf (stderr, "Glyph fallback '%s'->'%s' %s\n", n.GetBuffer(), pFallbackFont ? m.GetBuffer() : "none", + new_entry ? "(new)" : "(cached)"); +#endif + return pFallbackFont; } @@ -6105,7 +6244,7 @@ // do glyph fallback if needed // #105768# avoid fallback for very small font sizes if( aLayoutArgs.NeedFallback() ) - if( mpFontEntry && (mpFontEntry->maFontSelData.mnHeight >= 6) ) + if( mpFontEntry && (mpFontEntry->maFontSelData.mnHeight >= 3) ) pSalLayout = ImplGlyphFallbackLayout( pSalLayout, aLayoutArgs ); // position, justify, etc. the layout @@ -6149,6 +6288,17 @@ rLayoutArgs.ResetPos(); } #endif + int nCharPos = -1; + bool bRTL = false; + sal_Unicode *pMissingUnicodes = new sal_Unicode[8]; + int nMissingUnicodes = 0; + + for( int i=0; i<8 && rLayoutArgs.GetNextPos( &nCharPos, &bRTL); ++i ) + { + pMissingUnicodes[i] = rLayoutArgs.mpStr[ nCharPos ]; + nMissingUnicodes++; + } + rLayoutArgs.ResetPos(); ImplFontSelectData aFontSelData = mpFontEntry->maFontSelData; Size aFontSize( aFontSelData.mnWidth, aFontSelData.mnHeight ); @@ -6165,7 +6315,8 @@ { // find a font family suited for glyph fallback ImplFontEntry* pFallbackFont = mpFontCache->GetFallback( mpFontList, - maFont, aFontSize, nFallbackLevel-nDevSpecificFallback ); + maFont, aFontSize, nFallbackLevel-nDevSpecificFallback, + (nMissingUnicodes ? pMissingUnicodes : NULL), nMissingUnicodes ); if( !pFallbackFont ) break; @@ -6217,6 +6368,8 @@ break; } + delete[] pMissingUnicodes; + if( pMultiSalLayout && pMultiSalLayout->LayoutText( rLayoutArgs ) ) pSalLayout = pMultiSalLayout; --- openoffice.org.orig/vcl/source/window/window.cxx 2005-09-12 13:37:04.000000000 +0100 +++ openoffice.org.orig/vcl/source/window/window.cxx 2005-09-12 16:18:20.000000000 +0100 @@ -212,6 +212,7 @@ #endif #include +#include using namespace rtl; using namespace ::com::sun::star::uno; @@ -350,6 +351,10 @@ { ImplInitFontList(); + const psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); + if (rMgr.hasFontconfig()) + return true; + String aTestText; aTestText.Append( Button::GetStandardText( BUTTON_OK ) ); aTestText.Append( Button::GetStandardText( BUTTON_CANCEL ) ); --- openoffice.org.orig/vcl/util/makefile.mk 2005-09-12 13:37:38.000000000 +0100 +++ openoffice.org.orig/vcl/util/makefile.mk 2005-09-12 14:55:10.000000000 +0100 @@ -265,7 +265,7 @@ .ENDIF -SHL1STDLIBS += -lX11 +SHL1STDLIBS += -lX11 -lpsp$(VERSION)$(DLLPOSTFIX) .ENDIF # "$(GUI)"=="UNX" Index: openoffice.org.orig/psprint/uinc/psprint/fontmanager.hxx =================================================================== RCS file: /cvs/gsl/psprint/inc/psprint/fontmanager.hxx,v --- openoffice.org.orig/psprint/uinc/psprint/fontmanager.hxx 5 Aug 2005 13:21:02 -0000 1.24 +++ openoffice.org.orig/psprint/uinc/psprint/fontmanager.hxx 12 Sep 2005 16:21:13 -0000 @@ -75,6 +75,9 @@ #ifndef _PSPRINT_HELPER_HXX_ #include #endif +#ifndef _STRING_HXX +#include +#endif #ifndef _COM_SUN_STAR_LANG_LOCALE_HPP_ #include @@ -419,6 +422,7 @@ std::hash_multimap< sal_uInt8, sal_Unicode > m_aAdobecodeToUnicode; mutable FontCache* m_pFontCache; + bool m_bFontconfigSuccess; rtl::OString getAfmFile( PrintFont* pFont ) const; rtl::OString getFontFile( PrintFont* pFont ) const; @@ -504,10 +508,10 @@ const rtl::OUString& getPSName( fontID nFontID ) const; // get a specific fonts style family - family::type PrintFontManager::getFontFamilyType( fontID nFontID ) const; + family::type getFontFamilyType( fontID nFontID ) const; // get a specific fonts family name aliases - void PrintFontManager::getFontFamilyAliases( fontID nFontID ) const; + void getFontFamilyAliases( fontID nFontID ) const; // get a specific fonts type fonttype::type getFontType( fontID nFontID ) const @@ -729,6 +733,11 @@ false else */ bool matchFont( FastPrintFontInfo& rInfo, const com::sun::star::lang::Locale& rLocale ); + + String Substitute(const std::vector &rNames, const std::vector &rGlyphs, + const ByteString &rLangAttrib, italic::type eItalic, weight::type eWeight, + width::type eWidth, pitch::type ePitch) const; + bool hasFontconfig() const { return m_bFontconfigSuccess; } }; } // namespace Index: openoffice.org.orig/psprint/usource/fontmanager/fontcache.cxx =================================================================== RCS file: /cvs/gsl/psprint/source/fontmanager/fontcache.cxx,v --- openoffice.org.orig/psprint/usource/fontmanager/fontcache.cxx 9 Aug 2005 10:59:38 -0000 1.14 +++ openoffice.org.orig/psprint/usource/fontmanager/fontcache.cxx 12 Sep 2005 16:21:13 -0000 @@ -688,9 +688,9 @@ FontDirMap::const_iterator entry = dir->second.m_aEntries.find( rFile ); if( entry != dir->second.m_aEntries.end() ) { - bSuccess = true; for( FontCacheEntry::const_iterator font = entry->second.m_aEntry.begin(); font != entry->second.m_aEntry.end(); ++font ) { + bSuccess = true; PrintFontManager::PrintFont* pFont = clonePrintFont( *font ); rNewFonts.push_back( pFont ); } Index: openoffice.org.orig/psprint/usource/fontmanager/fontconfig.cxx =================================================================== RCS file: /cvs/gsl/psprint/source/fontmanager/fontconfig.cxx,v --- openoffice.org.orig/psprint/usource/fontmanager/fontconfig.cxx 9 Aug 2005 10:59:52 -0000 1.9 +++ openoffice.org.orig/psprint/usource/fontmanager/fontconfig.cxx 12 Sep 2005 16:21:14 -0000 @@ -70,10 +70,12 @@ typedef void FcObjectSet; typedef void FcPattern; typedef void FcFontSet; +typedef void FcCharSet; typedef int FcResult; typedef int FcBool; typedef int FcMatchKind; typedef char FcChar8; +typedef sal_Int32 FcChar32; #endif #include @@ -106,6 +108,7 @@ { void* m_pLib; FcConfig* m_pDefConfig; + FcFontSet* m_pOutlineSet; FcBool (*m_pFcInit)(); FcConfig* (*m_pFcConfigGetCurrent)(); @@ -114,17 +117,23 @@ FcPattern* (*m_pFcPatternCreate)(); void (*m_pFcPatternDestroy)(FcPattern*); FcFontSet* (*m_pFcFontList)(FcConfig*,FcPattern*,FcObjectSet*); + FcFontSet* (*m_pFcConfigGetFonts)(FcConfig*,FcSetName); FcFontSet* (*m_pFcFontSetCreate)(); + FcCharSet* (*m_pFcCharSetCreate)(); + FcBool (*m_pFcCharSetAddChar)(FcCharSet *, FcChar32); void (*m_pFcFontSetDestroy)(FcFontSet*); FcBool (*m_pFcFontSetAdd)(FcFontSet*,FcPattern*); + void (*m_pFcPatternReference)(FcPattern*); FcResult (*m_pFcPatternGetString)(const FcPattern*,const char*,int,FcChar8**); FcResult (*m_pFcPatternGetInteger)(const FcPattern*,const char*,int,int*); FcResult (*m_pFcPatternGetDouble)(const FcPattern*,const char*,int,double*); FcResult (*m_pFcPatternGetBool)(const FcPattern*,const char*,int,FcBool*); void (*m_pFcDefaultSubstitute)(FcPattern *); - FcPattern* (*m_pFcFontMatch)(FcConfig*,FcPattern*,FcResult*); + FcPattern* (*m_pFcFontSetMatch)(FcConfig*,FcFontSet**, int, FcPattern*,FcResult*); FcBool (*m_pFcConfigSubstitute)(FcConfig*,FcPattern*,FcMatchKind); FcBool (*m_pFcPatternAddInteger)(FcPattern*,const char*,int); + FcBool (*m_pFcPatternAddBool)(FcPattern*,const char*,FcBool); + FcBool (*m_pFcPatternAddCharSet)(FcPattern*,const char*,const FcCharSet*); FcBool (*m_pFcPatternAddString)(FcPattern*,const char*,const FcChar8*); void* loadSymbol( const char* ); @@ -140,6 +149,7 @@ { return m_pLib != NULL;} FcConfig* getDefConfig() { return m_pDefConfig; } + FcFontSet* getFontSet() { return m_pOutlineSet; } FcBool FcInit() { return m_pFcInit(); } @@ -169,14 +179,28 @@ FcFontSet* FcFontList( FcConfig* pConfig, FcPattern* pPattern, FcObjectSet* pSet ) { return m_pFcFontList( pConfig, pPattern, pSet ); } - + + FcFontSet* FcConfigGetFonts( FcConfig* pConfig, FcSetName eSet) + { return m_pFcConfigGetFonts( pConfig, eSet ); } + FcFontSet* FcFontSetCreate() { return m_pFcFontSetCreate(); } + + FcCharSet* FcCharSetCreate() + { return m_pFcCharSetCreate(); } + + FcBool FcCharSetAddChar(FcCharSet *fcs, FcChar32 ucs4) + { return m_pFcCharSetAddChar(fcs, ucs4); } + void FcFontSetDestroy( FcFontSet* pSet ) { m_pFcFontSetDestroy( pSet );} + FcBool FcFontSetAdd( FcFontSet* pSet, FcPattern* pPattern ) { return m_pFcFontSetAdd( pSet, pPattern ); } + void FcPatternReference( FcPattern* pPattern ) + { m_pFcPatternReference( pPattern ); } + FcResult FcPatternGetString( const FcPattern* pPattern, const char* object, int n, FcChar8** s ) { return m_pFcPatternGetString( pPattern, object, n, s ); } @@ -190,12 +214,16 @@ { return m_pFcPatternGetBool( pPattern, object, n, s ); } void FcDefaultSubstitute( FcPattern* pPattern ) { m_pFcDefaultSubstitute( pPattern ); } - FcPattern* FcFontMatch( FcConfig* pConfig, FcPattern* pPattern, FcResult* pResult ) - { return m_pFcFontMatch( pConfig, pPattern, pResult ); } + FcPattern* FcFontSetMatch(FcConfig* pConfig, FcFontSet** ppFontSet, int nset, FcPattern *pPattern, FcResult *pResult) + { return m_pFcFontSetMatch( pConfig, ppFontSet, nset, pPattern, pResult ); } FcBool FcConfigSubstitute( FcConfig* pConfig, FcPattern* pPattern, FcMatchKind eKind ) { return m_pFcConfigSubstitute( pConfig, pPattern, eKind ); } FcBool FcPatternAddInteger( FcPattern* pPattern, const char* pObject, int nValue ) { return m_pFcPatternAddInteger( pPattern, pObject, nValue ); } + FcBool FcPatternAddBool( FcPattern* pPattern, const char* pObject, FcBool b ) + { return m_pFcPatternAddBool( pPattern, pObject, b ); } + FcBool FcPatternAddCharSet( FcPattern* pPattern, const char* pObject, const FcCharSet *c) + { return m_pFcPatternAddCharSet( pPattern, pObject, c ); } FcBool FcPatternAddString( FcPattern* pPattern, const char* pObject, const FcChar8* pString ) { return m_pFcPatternAddString( pPattern, pObject, pString ); } }; @@ -212,7 +240,8 @@ FontCfgWrapper::FontCfgWrapper() : m_pLib( NULL ), - m_pDefConfig( NULL ) + m_pDefConfig( NULL ), + m_pOutlineSet( NULL ) { #ifdef ENABLE_FONTCONFIG OUString aLib( RTL_CONSTASCII_USTRINGPARAM( "libfontconfig.so.1" ) ); @@ -246,12 +275,20 @@ loadSymbol( "FcPatternDestroy" ); m_pFcFontList = (FcFontSet*(*)(FcConfig*,FcPattern*,FcObjectSet*)) loadSymbol( "FcFontList" ); + m_pFcConfigGetFonts = (FcFontSet*(*)(FcConfig*,FcSetName)) + loadSymbol( "FcConfigGetFonts" ); m_pFcFontSetCreate = (FcFontSet*(*)()) loadSymbol( "FcFontSetCreate" ); + m_pFcCharSetCreate = (FcCharSet*(*)()) + loadSymbol( "FcCharSetCreate" ); + m_pFcCharSetAddChar = (FcBool(*)(FcCharSet*, FcChar32)) + loadSymbol( "FcCharSetAddChar" ); m_pFcFontSetDestroy = (void(*)(FcFontSet*)) loadSymbol( "FcFontSetDestroy" ); m_pFcFontSetAdd = (FcBool(*)(FcFontSet*,FcPattern*)) loadSymbol( "FcFontSetAdd" ); + m_pFcPatternReference = (void(*)(FcPattern*)) + loadSymbol( "FcPatternReference" ); m_pFcPatternGetString = (FcResult(*)(const FcPattern*,const char*,int,FcChar8**)) loadSymbol( "FcPatternGetString" ); m_pFcPatternGetInteger = (FcResult(*)(const FcPattern*,const char*,int,int*)) @@ -262,12 +299,16 @@ loadSymbol( "FcPatternGetBool" ); m_pFcDefaultSubstitute = (void(*)(FcPattern *)) loadSymbol( "FcDefaultSubstitute" ); - m_pFcFontMatch = (FcPattern*(*)(FcConfig*,FcPattern*,FcResult*)) - loadSymbol( "FcFontMatch" ); + m_pFcFontSetMatch = (FcPattern*(*)(FcConfig*,FcFontSet**, int, FcPattern*,FcResult*)) + loadSymbol( "FcFontSetMatch" ); m_pFcConfigSubstitute = (FcBool(*)(FcConfig*,FcPattern*,FcMatchKind)) loadSymbol( "FcConfigSubstitute" ); m_pFcPatternAddInteger = (FcBool(*)(FcPattern*,const char*,int)) loadSymbol( "FcPatternAddInteger" ); + m_pFcPatternAddBool = (FcBool(*)(FcPattern*,const char*,FcBool)) + loadSymbol( "FcPatternAddBool" ); + m_pFcPatternAddCharSet = (FcBool(*)(FcPattern*,const char*,const FcCharSet *)) + loadSymbol( "FcPatternAddCharSet" ); m_pFcPatternAddString = (FcBool(*)(FcPattern*,const char*,const FcChar8*)) loadSymbol( "FcPatternAddString" ); @@ -279,17 +320,23 @@ m_pFcPatternCreate && m_pFcPatternDestroy && m_pFcFontList && + m_pFcConfigGetFonts && m_pFcFontSetCreate && + m_pFcCharSetCreate && + m_pFcCharSetAddChar && m_pFcFontSetDestroy && m_pFcFontSetAdd && + m_pFcPatternReference && m_pFcPatternGetString && m_pFcPatternGetInteger && m_pFcPatternGetDouble && m_pFcPatternGetBool && m_pFcDefaultSubstitute && - m_pFcFontMatch && + m_pFcFontSetMatch && m_pFcConfigSubstitute && m_pFcPatternAddInteger && + m_pFcPatternAddCharSet && + m_pFcPatternAddBool && m_pFcPatternAddString ) ) { @@ -307,10 +354,35 @@ osl_unloadModule( m_pLib ); m_pLib = NULL; } + + m_pOutlineSet = FcFontSetCreate(); + + /* + add only acceptable outlined fonts to our config, + for future fontconfig use + */ + FcFontSet *pOrig = FcConfigGetFonts(NULL, FcSetSystem); + + if (!pOrig) + return; + + for( int i = 0; i < pOrig->nfont; ++i ) + { + FcBool outline = false; + FcPattern *pOutlinePattern = pOrig->fonts[i]; + FcResult eOutRes = + FcPatternGetBool( pOutlinePattern, FC_OUTLINE, 0, &outline ); + if (eOutRes == FcResultMatch && !outline) + continue; + FcPatternReference(pOutlinePattern); + FcFontSetAdd(m_pOutlineSet, pOutlinePattern); + } } FontCfgWrapper::~FontCfgWrapper() { + if( m_pOutlineSet ) + FcFontSetDestroy( m_pOutlineSet ); if( m_pLib ) osl_unloadModule( m_pLib ); } @@ -345,18 +417,7 @@ if( ! rWrapper.isValid() ) return false; - FcConfig* pConfig = rWrapper.getDefConfig(); - FcObjectSet* pOSet = rWrapper.FcObjectSetBuild( FC_FAMILY, - FC_STYLE, - FC_SLANT, - FC_WEIGHT, - FC_SPACING, - FC_FILE, - FC_OUTLINE, - FC_INDEX, - (void *) NULL ); - FcPattern* pPattern = rWrapper.FcPatternCreate(); - FcFontSet* pFSet = rWrapper.FcFontList( pConfig, pPattern, pOSet ); + FcFontSet* pFSet = rWrapper.getFontSet(); if( pFSet ) { @@ -399,6 +460,8 @@ ); #endif + OSL_ASSERT(eOutRes != FcResultMatch || outline); + // only outline fonts are usable to psprint anyway if( eOutRes == FcResultMatch && ! outline ) continue; @@ -537,14 +600,6 @@ } } - // cleanup - if( pPattern ) - rWrapper.FcPatternDestroy( pPattern ); - if( pFSet ) - rWrapper.FcFontSetDestroy( pFSet ); - if( pOSet ) - rWrapper.FcObjectSetDestroy( pOSet ); - // how does one get rid of the config ? #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "inserted %d fonts from fontconfig\n", nFonts ); @@ -558,39 +613,14 @@ FontCfgWrapper::release(); } -bool PrintFontManager::matchFont( FastPrintFontInfo& rInfo, const com::sun::star::lang::Locale& rLocale ) +static void addtopattern(FontCfgWrapper& rWrapper, FcPattern *pPattern, + italic::type eItalic, weight::type eWeight, width::type eWidth, pitch::type ePitch) { #ifdef ENABLE_FONTCONFIG - FontCfgWrapper& rWrapper = FontCfgWrapper::get(); - if( ! rWrapper.isValid() ) - return false; - - FcConfig* pConfig = rWrapper.getDefConfig(); - FcPattern* pPattern = rWrapper.FcPatternCreate(); - - OString aLangAttrib; - // populate pattern with font characteristics - if( rLocale.Language.getLength() ) - { - OUStringBuffer aLang(6); - aLang.append( rLocale.Language ); - if( rLocale.Country.getLength() ) - { - aLang.append( sal_Unicode('-') ); - aLang.append( rLocale.Country ); - } - aLangAttrib = OUStringToOString( aLang.makeStringAndClear(), RTL_TEXTENCODING_UTF8 ); - } - if( aLangAttrib.getLength() ) - rWrapper.FcPatternAddString( pPattern, FC_LANG, (FcChar8*)aLangAttrib.getStr() ); - - OString aFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 ); - if( aFamily.getLength() ) - rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)aFamily.getStr() ); - if( rInfo.m_eItalic != italic::Unknown ) + if( eItalic != italic::Unknown ) { int nSlant = FC_SLANT_ROMAN; - switch( rInfo.m_eItalic ) + switch( eItalic ) { case italic::Italic: nSlant = FC_SLANT_ITALIC;break; case italic::Oblique: nSlant = FC_SLANT_OBLIQUE;break; @@ -599,10 +629,10 @@ } rWrapper.FcPatternAddInteger( pPattern, FC_SLANT, nSlant ); } - if( rInfo.m_eWeight != weight::Unknown ) + if( eWeight != weight::Unknown ) { int nWeight = FC_WEIGHT_NORMAL; - switch( rInfo.m_eWeight ) + switch( eWeight ) { case weight::Thin: nWeight = FC_WEIGHT_THIN;break; case weight::UltraLight: nWeight = FC_WEIGHT_ULTRALIGHT;break; @@ -619,10 +649,10 @@ } rWrapper.FcPatternAddInteger( pPattern, FC_WEIGHT, nWeight ); } - if( rInfo.m_eWidth != width::Unknown ) + if( eWidth != width::Unknown ) { int nWidth = FC_WIDTH_NORMAL; - switch( rInfo.m_eWidth ) + switch( eWidth ) { case width::UltraCondensed: nWidth = FC_WIDTH_ULTRACONDENSED;break; case width::ExtraCondensed: nWidth = FC_WIDTH_EXTRACONDENSED;break; @@ -638,10 +668,10 @@ } rWrapper.FcPatternAddInteger( pPattern, FC_WIDTH, nWidth ); } - if( rInfo.m_ePitch != pitch::Unknown ) + if( ePitch != pitch::Unknown ) { int nSpacing = FC_PROPORTIONAL; - switch( rInfo.m_ePitch ) + switch( ePitch ) { case pitch::Fixed: nSpacing = FC_MONO;break; case pitch::Variable: nSpacing = FC_PROPORTIONAL;break; @@ -649,12 +679,122 @@ break; } rWrapper.FcPatternAddInteger( pPattern, FC_SPACING, nSpacing ); + if (nSpacing == FC_MONO) + rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)"monospace"); } +#endif +} + +String PrintFontManager::Substitute(const std::vector &rNames, const std::vector &rGlyphs, + const ByteString &rLangAttrib, italic::type eItalic, weight::type eWeight, + width::type eWidth, pitch::type ePitch) const +{ + String aName; +#ifdef ENABLE_FONTCONFIG + FontCfgWrapper& rWrapper = FontCfgWrapper::get(); + if( ! rWrapper.isValid() ) + return aName; + + FcFontSet* pSet = NULL; + FcPattern* pPattern = rWrapper.FcPatternCreate(); + + // Prefer scalable fonts + rWrapper.FcPatternAddBool( pPattern, FC_SCALABLE, 1 ); + + std::vector::const_iterator aEnd = rNames.end(); + for (std::vector::const_iterator aIter = rNames.begin(); aIter != aEnd; ++aIter) + { + OString maTargetName = OUStringToOString(*aIter, RTL_TEXTENCODING_UTF8); + rWrapper.FcPatternAddString(pPattern, FC_FAMILY, (FcChar8*)maTargetName.getStr()); + } + + if( rLangAttrib.Len() ) + rWrapper.FcPatternAddString(pPattern, FC_LANG, (FcChar8*)rLangAttrib.GetBuffer()); + + // Add required Unicode characters, if any + FcCharSet *unicodes = NULL; + if (! rGlyphs.empty() ) + { + unicodes = rWrapper.FcCharSetCreate(); + std::vector::const_iterator aGlyphEnd = rGlyphs.end(); + for (std::vector::const_iterator aGlyphIter = rGlyphs.begin(); + aGlyphIter != aGlyphEnd; ++aGlyphIter) + { + rWrapper.FcCharSetAddChar( unicodes, (FcChar32)*aGlyphIter ); + } + rWrapper.FcPatternAddCharSet( pPattern, FC_CHARSET, unicodes); + } + + addtopattern(rWrapper, pPattern, eItalic, eWeight, eWidth, ePitch); + + rWrapper.FcConfigSubstitute( NULL, pPattern, FcMatchPattern ); + rWrapper.FcDefaultSubstitute( pPattern ); + FcResult eResult = FcResultNoMatch; + FcFontSet *pFontSet = rWrapper.getFontSet(); + FcPattern* pResult = rWrapper.FcFontSetMatch( NULL, &pFontSet, 1, pPattern, &eResult ); + rWrapper.FcPatternDestroy( pPattern ); + + if( pResult ) + { + pSet = rWrapper.FcFontSetCreate(); + // info: destroying the pSet destroys pResult implicitly + // since pResult was "added" to pSet + rWrapper.FcFontSetAdd( pSet, pResult ); + } + + if( pSet ) + { + if( pSet->nfont > 0 ) + { + //extract the closest match + FcChar8* family = NULL; + FcResult eFileRes = rWrapper.FcPatternGetString( pSet->fonts[0], FC_FAMILY, 0, &family ); + if( eFileRes == FcResultMatch ) + aName = String( (sal_Char*)family, RTL_TEXTENCODING_UTF8 ); + } + } + rWrapper.FcFontSetDestroy( pSet ); +#endif + return aName; +} + +bool PrintFontManager::matchFont( FastPrintFontInfo& rInfo, const com::sun::star::lang::Locale& rLocale ) +{ +#ifdef ENABLE_FONTCONFIG + FontCfgWrapper& rWrapper = FontCfgWrapper::get(); + if( ! rWrapper.isValid() ) + return false; + + FcConfig* pConfig = rWrapper.getDefConfig(); + FcPattern* pPattern = rWrapper.FcPatternCreate(); + + OString aLangAttrib; + // populate pattern with font characteristics + if( rLocale.Language.getLength() ) + { + OUStringBuffer aLang(6); + aLang.append( rLocale.Language ); + if( rLocale.Country.getLength() ) + { + aLang.append( sal_Unicode('-') ); + aLang.append( rLocale.Country ); + } + aLangAttrib = OUStringToOString( aLang.makeStringAndClear(), RTL_TEXTENCODING_UTF8 ); + } + if( aLangAttrib.getLength() ) + rWrapper.FcPatternAddString( pPattern, FC_LANG, (FcChar8*)aLangAttrib.getStr() ); + + OString aFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 ); + if( aFamily.getLength() ) + rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)aFamily.getStr() ); + + addtopattern(rWrapper, pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch); rWrapper.FcConfigSubstitute( pConfig, pPattern, FcMatchPattern ); rWrapper.FcDefaultSubstitute( pPattern ); FcResult eResult = FcResultNoMatch; - FcPattern* pResult = rWrapper.FcFontMatch( pConfig, pPattern, &eResult ); + FcFontSet *pFontSet = rWrapper.getFontSet(); + FcPattern* pResult = rWrapper.FcFontSetMatch( pConfig, &pFontSet, 1, pPattern, &eResult ); bool bSuccess = false; if( pResult ) { Index: openoffice.org.orig/psprint/usource/fontmanager/fontmanager.cxx =================================================================== RCS file: /cvs/gsl/psprint/source/fontmanager/fontmanager.cxx,v --- openoffice.org.orig/psprint/usource/fontmanager/fontmanager.cxx 5 Aug 2005 12:53:31 -0000 1.59 +++ openoffice.org.orig/psprint/usource/fontmanager/fontmanager.cxx 12 Sep 2005 16:21:14 -0000 @@ -1177,7 +1177,8 @@ m_nNextFontID( 1 ), m_pAtoms( new MultiAtomProvider() ), m_nNextDirAtom( 1 ), - m_pFontCache( NULL ) + m_pFontCache( NULL ), + m_bFontconfigSuccess(false) { for( unsigned int i = 0; i < sizeof( aAdobeCodes )/sizeof( aAdobeCodes[0] ); i++ ) { @@ -2129,7 +2130,7 @@ #endif // first try fontconfig - bool bFontconfigSuccess = initFontconfig(); + m_bFontconfigSuccess = initFontconfig(); // part one - look for downloadable fonts rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); @@ -2151,7 +2152,7 @@ } // don't search through many directories fontconfig already told us about - if( ! bFontconfigSuccess ) + if( ! m_bFontconfigSuccess ) { Display *pDisplay = (Display*)pInitDisplay; @@ -2229,7 +2230,7 @@ } } #endif /* SOLARIS */ - } // ! bFontconfigSuccess + } // ! m_bFontconfigSuccess // fill XLFD aliases from fonts.alias files initFontsAlias();