diff -ru OOE680_m6.fontconfig/vcl/inc/outdev.h OOE680_m6/vcl/inc/outdev.h --- OOE680_m6.fontconfig/vcl/inc/vcl/outdev.h 2006-12-18 13:00:23.000000000 -0500 +++ OOE680_m6/vcl/inc/vcl/outdev.h 2006-12-19 04:28:08.000000000 -0500 @@ -213,7 +213,7 @@ const Font& rFont, const Size& rSize, ImplFontSubstEntry* pDevSpecific ); ImplFontEntry* GetFallback( ImplDevFontList* pFontList, const Font& rFont, const Size& rSize, - int nFallbackLevel ); + int nFallbackLevel, std::vector &rMissingGlyphs ); void Release( ImplFontEntry* ); void Invalidate(); }; diff -ru OOE680_m6.fontconfig/vcl/inc/outfont.hxx OOE680_m6/vcl/inc/outfont.hxx --- OOE680_m6.fontconfig/vcl/inc/vcl/outfont.hxx 2006-12-18 13:00:23.000000000 -0500 +++ OOE680_m6/vcl/inc/vcl/outfont.hxx 2006-12-19 04:27:48.000000000 -0500 @@ -230,6 +230,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 ); @@ -333,6 +334,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 @@ -343,6 +348,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(); + } }; diff -ru OOE680_m6.fontconfig/vcl/inc/sallayout.hxx OOE680_m6/vcl/inc/sallayout.hxx --- OOE680_m6.fontconfig/vcl/inc/vcl/sallayout.hxx 2006-12-18 13:00:23.000000000 -0500 +++ OOE680_m6/vcl/inc/vcl/sallayout.hxx 2006-12-19 04:28:08.000000000 -0500 @@ -101,6 +101,7 @@ bool GetRun( int* nMinRunPos, int* nEndRunPos, bool* bRTL ) const; bool GetNextPos( int* nCharPos, bool* bRTL ); bool PosIsInRun( int nCharPos ) const; + bool PosIsInAnyRun( int nCharPos ) const; }; // ----------------- diff -ru OOE680_m6.fontconfig/vcl/source/gdi/outdev3.cxx OOE680_m6/vcl/source/gdi/outdev3.cxx --- OOE680_m6.fontconfig/vcl/source/gdi/outdev3.cxx 2006-12-18 13:00:25.000000000 -0500 +++ OOE680_m6/vcl/source/gdi/outdev3.cxx 2006-12-19 04:28:08.000000000 -0500 @@ -168,6 +168,9 @@ #include #include +#include +#include + // ======================================================================= DBG_NAMEEX( OutputDevice ) @@ -2659,6 +2662,121 @@ } } + +// ----------------------------------------------------------------------- + +String GetFcSubstitute(const ImplFontSelectData &rFontSelData, std::vector &rGlyphs) +{ + 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); + } + + ByteString aLangAttrib = MsLangId::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, rGlyphs, 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; + + std::vector aDummy; + String aName(GetFcSubstitute(rFontSelData, aDummy)); + 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, @@ -2696,8 +2814,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!" ); if( pFontFamily ) aFontSelData.maSearchName = pFontFamily->GetSearchName(); @@ -3024,115 +3146,143 @@ // ----------------------------------------------------------------------- ImplFontEntry* ImplFontCache::GetFallback( ImplDevFontList* pFontList, - const Font& rOrigFont, const Size& rSize, int nFallbackLevel ) + const Font& rOrigFont, const Size& rSize, int nFallbackLevel, + std::vector &rMissingGlyphs ) { - // 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 FontNameAttr* fontAttr = FontSubstConfiguration::get()->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", "", - "khmerossystem", "", - "phetsarathot", "", - 0 - }; - - bool bHasEudc = false; - 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; + std::vector aGlyphs(rMissingGlyphs); - // 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( !bHasEudc && !nMaxLevel ) - bHasEudc = (0 == strncmp( *ppNames, "eudc", 5 )); - } - } + // Try cached fallbacks first + if ( !symbolFont && !rMissingGlyphs.empty() ) + { + aSelData.maSearchName = pOrigFontEntry->GetFallbackForUnicode( rMissingGlyphs[0] ); + if ( aSelData.maSearchName.Len() ) + cached = true; + } - // 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 ) - { - ImplDevFontListData* 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; - } + if ( !cached ) + { + String aName; + if (nFallbackLevel != MAX_FALLBACK -1) + aName = GetFcSubstitute( aSelData, aGlyphs ); + else + { + /* + There is no font that can handle this, to be safe let's set a font + which has a known working .notdef glyph + */ + const psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); + std::vector aDummy; + std::vector aNames; + aNames.push_back(String(RTL_CONSTASCII_USTRINGPARAM("Sazanami Gothic"))); + aName = rMgr.Substitute(aNames, aDummy, ByteString(), + psp::italic::Unknown, psp::weight::Unknown, psp::width::Unknown, psp::pitch::Unknown); + if (aName != String(RTL_CONSTASCII_USTRINGPARAM("Sazanami Gothic"))) + { + aNames.clear(); + aNames.push_back(OUString(RTL_CONSTASCII_USTRINGPARAM("DejaVu LGC Sans"))); + aName = rMgr.Substitute(aNames, aDummy, ByteString(), + psp::italic::Unknown, psp::weight::Unknown, psp::width::Unknown, psp::pitch::Unknown); + } + } + if (aName.Len()) + aSelData.maSearchName = aName; + } -#if defined(HDU_DEBUG) - for( int i = 0; i < nMaxLevel; ++i ) + if (!rMissingGlyphs.empty()) + { + std::vector::const_iterator aEnd = aGlyphs.end(); + for (std::vector::const_iterator aI = aGlyphs.begin(); aI != aEnd; ++aI) { - ImplDevFontListData* pFont = pFallbackList[ i ]; - ByteString aFontName( pFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ); - fprintf( stderr, "GlyphFallbackFont[%d] (quality=%05d): \"%s\"\n", - i, pFont->GetMinQuality(), aFontName.GetBuffer() ); + std::vector::iterator aNewEnd = + std::remove(rMissingGlyphs.begin(), rMissingGlyphs.end(), *aI); + if (aNewEnd != rMissingGlyphs.end()) + rMissingGlyphs.erase(aNewEnd); + //In this case only the first missing symbol has been taken into account and is + //known safe to replace + if (cached || symbolFont) + break; } -#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 ) + // 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 { - ImplDevFontListData* pFallbackData = pFontList->GetFallback( nFallbackLevel-1 ); - if( !pFallbackData ) - return NULL; + // find the best matching physical font face + ImplDevFontListData* pFontFamily = pFontList->FindFontFamily( aSelData.maSearchName ); + if (pFontFamily) + { + ImplFontData* pFontData = pFontFamily->FindBestFontFace( aSelData ); - aFallbackFont.SetName( pFallbackData->GetSearchName() ); + // 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 + { + ByteString l( aSelData.maSearchName, RTL_TEXTENCODING_UTF8 ); + //fprintf (stderr, "--- Couldn't get FontFamily for '%s'\n", l.GetBuffer()); + } } - ImplFontEntry* pFallbackFont = Get( pFontList, aFallbackFont, rSize, NULL ); + // Cache the fallback font for each of the missing Unicode chars + if ( !symbolFont && aSelData.maSearchName.Len() ) + { + std::vector::const_iterator aEnd = aGlyphs.end(); + for (std::vector::const_iterator aI = aGlyphs.begin(); aI != aEnd; ++aI) + { + #if 0 + if (!pOrigFontEntry->GetFallbackForUnicode(*aI).Len()) + pOrigFontEntry->AddFallbackForUnicode(*aI, aSelData.maSearchName); + #endif + } + } if( pFallbackFont && !pFallbackFont->mbInit ) { @@ -3142,6 +3270,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; } @@ -6099,7 +6248,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 @@ -6143,6 +6292,12 @@ rLayoutArgs.ResetPos(); } #endif + int nCharPos = -1; + bool bRTL = false; + std::vector aGlyphs; + while (rLayoutArgs.GetNextPos( &nCharPos, &bRTL)) + aGlyphs.push_back(rLayoutArgs.mpStr[ nCharPos ]); + rLayoutArgs.ResetPos(); ImplFontSelectData aFontSelData = mpFontEntry->maFontSelData; Size aFontSize( aFontSelData.mnWidth, aFontSelData.mnHeight ); @@ -6159,7 +6314,7 @@ { // find a font family suited for glyph fallback ImplFontEntry* pFallbackFont = mpFontCache->GetFallback( mpFontList, - maFont, aFontSize, nFallbackLevel-nDevSpecificFallback ); + maFont, aFontSize, nFallbackLevel-nDevSpecificFallback, aGlyphs ); if( !pFallbackFont ) break; diff -ru OOE680_m6.fontconfig/vcl/source/gdi/sallayout.cxx OOE680_m6/vcl/source/gdi/sallayout.cxx --- OOE680_m6.fontconfig/vcl/source/gdi/sallayout.cxx 2006-12-18 13:00:25.000000000 -0500 +++ OOE680_m6/vcl/source/gdi/sallayout.cxx 2006-12-19 04:28:09.000000000 -0500 @@ -456,6 +456,27 @@ return true; } +bool ImplLayoutRuns::PosIsInAnyRun( int nCharPos ) const +{ + bool bRet = false; + int nRunIndex = mnRunIndex; + + ImplLayoutRuns *pThis = const_cast(this); + + pThis->ResetPos(); + + for (size_t i = 0; i < maRuns.size(); i+=2) + { + if ((bRet = PosIsInRun( nCharPos ))) + break; + pThis->NextRun(); + } + + pThis->mnRunIndex = nRunIndex; + return bRet; +} + + // ----------------------------------------------------------------------- bool ImplLayoutRuns::GetNextPos( int* nCharPos, bool* bRightToLeft ) @@ -1694,7 +1715,7 @@ { // find best fallback level for( n = 0; n < nLevel; ++n ) - if( nValid[n] && !maFallbackRuns[n].PosIsInRun( nActiveCharPos ) ) + if( nValid[n] && !maFallbackRuns[n].PosIsInAnyRun( nActiveCharPos ) ) // fallback level n wins when it requested no further fallback break; int nFBLevel = n; @@ -1716,7 +1737,10 @@ if( n > 0 ) { // drop the NotDef glyphs in the base layout run if a fallback run exists - while( maFallbackRuns[ n-1 ].PosIsInRun( nCharPos[0] ) ) + while ( + (maFallbackRuns[ n-1 ].PosIsInRun( nCharPos[0] ) ) && + (!maFallbackRuns[ n ].PosIsInAnyRun( nCharPos[0] ) ) + ) { mpLayouts[0]->DropGlyph( nStartOld[0] ); nStartOld[0] = nStartNew[0]; @@ -1736,6 +1760,7 @@ // proceed to next glyph nStartOld[n] = nStartNew[n]; + int nOrigCharPos = nCharPos[n]; nValid[n] = mpLayouts[n]->GetNextGlyphs( 1, &nDummy, aPos, nStartNew[n], &nGlyphAdv[n], &nCharPos[n] ); @@ -1748,6 +1773,23 @@ break; } + //If the next character is one which belongs to the next level, then we + //are finished here for now, and we'll pick up after the next level has + //been processed + if ((n+1 < nLevel) && (nCharPos[n] != nOrigCharPos)) + { + if (nOrigCharPos < nCharPos[n]) + { + if (nCharPos[n+1] > nOrigCharPos && (nCharPos[n+1] < nCharPos[n])) + break; + } + else if (nOrigCharPos > nCharPos[n]) + { + if (nCharPos[n+1] > nCharPos[n] && (nCharPos[n+1] < nOrigCharPos)) + break; + } + } + // break at end of layout run if( n > 0 ) { diff -ru OOE680_m6.fontconfig/vcl/source/glyphs/gcach_layout.cxx OOE680_m6/vcl/source/glyphs/gcach_layout.cxx --- OOE680_m6.fontconfig/vcl/source/glyphs/gcach_layout.cxx 2006-12-18 13:00:25.000000000 -0500 +++ OOE680_m6/vcl/source/glyphs/gcach_layout.cxx 2006-12-19 04:30:26.000000000 -0500 @@ -402,6 +402,11 @@ // ----------------------------------------------------------------------- +static bool lcl_CharIsJoiner(sal_Unicode cChar) +{ + return ((cChar == 0x200C) || (cChar == 0x200D)); +} + bool IcuLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rArgs ) { LEUnicode* pIcuChars; @@ -514,7 +519,14 @@ if( !nGlyphIndex ) { if( nCharPos >= 0 ) + { rArgs.NeedFallback( nCharPos, bRightToLeft ); + if ( (nCharPos > 0) && lcl_CharIsJoiner(rArgs.mpStr[nCharPos-1]) ) + rArgs.NeedFallback( nCharPos-1, bRightToLeft ); + else if ( (nCharPos + 1 < nEndRunPos) && lcl_CharIsJoiner(rArgs.mpStr[nCharPos+1]) ) + rArgs.NeedFallback( nCharPos+1, bRightToLeft ); + } + if( SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags ) continue; } diff -ru OOE680_m6.fontconfig/vcl/source/window/window.cxx OOE680_m6/vcl/source/window/window.cxx --- OOE680_m6.fontconfig/vcl/source/window/window.cxx 2006-12-18 13:00:26.000000000 -0500 +++ OOE680_m6/vcl/source/window/window.cxx 2006-12-19 04:27:48.000000000 -0500 @@ -201,6 +201,7 @@ #endif #include +#include #include "vcl/lazydelete.hxx" using namespace rtl; @@ -347,6 +348,10 @@ bool Window::ImplCheckUIFont( const Font& rFont ) { + 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 ) ); diff -ru OOE680_m6.fontconfig/vcl/util/makefile.mk OOE680_m6/vcl/util/makefile.mk --- OOE680_m6.fontconfig/vcl/util/makefile.mk 2006-12-18 13:00:28.000000000 -0500 +++ OOE680_m6/vcl/util/makefile.mk 2006-12-19 04:27:48.000000000 -0500 @@ -182,7 +182,7 @@ .IF "$(USE_BUILTIN_RASTERIZER)"!="" LIB1FILES += $(SLB)$/glyphs.lib - SHL1STDLIBS+= $(FREETYPELIB) + SHL1STDLIBS+= $(FREETYPELIB) -lpsp$(VERSION)$(DLLPOSTFIX) .ENDIF # USE_BUILTIN_RASTERIZER SHL1LIBS= $(LIB1TARGET) diff -ru OOE680_m6.fontconfig/psprint/inc/psprint/fontmanager.hxx OOE680_m6/psprint/inc/psprint/fontmanager.hxx --- OOE680_m6.fontconfig/psprint/inc/psprint/fontmanager.hxx 2006-12-18 12:57:27.000000000 -0500 +++ OOE680_m6/psprint/inc/psprint/fontmanager.hxx 2006-12-19 04:30:49.000000000 -0500 @@ -49,6 +49,9 @@ #ifndef _PSPRINT_HELPER_HXX_ #include #endif +#ifndef _STRING_HXX +#include +#endif #ifndef _COM_SUN_STAR_LANG_LOCALE_HPP_ #include @@ -413,7 +416,11 @@ std::hash_multimap< sal_Unicode, sal_uInt8 > m_aUnicodeToAdobecode; std::hash_multimap< sal_uInt8, sal_Unicode > m_aAdobecodeToUnicode; - mutable FontCache* m_pFontCache; + std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash > m_aFontconfigNameToLocalized; + + mutable FontCache* m_pFontCache; + bool m_bFontconfigSuccess; + mutable std::vector< fontID > m_aOverrideFonts; rtl::OString getAfmFile( PrintFont* pFont ) const; @@ -737,6 +744,11 @@ false else */ bool matchFont( FastPrintFontInfo& rInfo, const com::sun::star::lang::Locale& rLocale ); + + String Substitute(const std::vector &rNames, 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 diff -ru OOE680_m6.fontconfig/psprint/source/fontmanager/fontcache.cxx OOE680_m6/psprint/source/fontmanager/fontcache.cxx --- OOE680_m6.fontconfig/psprint/source/fontmanager/fontcache.cxx 2006-12-18 12:57:27.000000000 -0500 +++ OOE680_m6/psprint/source/fontmanager/fontcache.cxx 2006-12-19 04:27:48.000000000 -0500 @@ -682,9 +682,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 ); } diff -ru OOE680_m6.fontconfig/psprint/source/fontmanager/fontconfig.cxx OOE680_m6/psprint/source/fontmanager/fontconfig.cxx --- OOE680_m6.fontconfig/psprint/source/fontmanager/fontconfig.cxx 2006-12-18 12:57:27.000000000 -0500 +++ OOE680_m6/psprint/source/fontmanager/fontconfig.cxx 2006-12-19 04:30:49.000000000 -0500 @@ -47,10 +47,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 @@ -74,6 +76,15 @@ #ifndef _RTL_USTRBUF_HXX #include #endif +#ifndef _OSL_PROCESS_H_ +#include +#endif +#ifndef _RTL_LOCALE_HXX_ +#include +#endif +#include +#include + using namespace psp; using namespace osl; @@ -83,6 +94,7 @@ { oslModule m_pLib; FcConfig* m_pDefConfig; + FcFontSet* m_pOutlineSet; FcBool (*m_pFcInit)(); FcConfig* (*m_pFcConfigGetCurrent)(); @@ -91,18 +103,26 @@ 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); + FcBool (*m_pFcCharSetHasChar)(FcCharSet *, FcChar32); + void (*m_pFcCharSetDestroy)(FcCharSet*); void (*m_pFcFontSetDestroy)(FcFontSet*); FcBool (*m_pFcFontSetAdd)(FcFontSet*,FcPattern*); + void (*m_pFcPatternReference)(FcPattern*); + FcResult (*m_pFcPatternGetCharSet)(const FcPattern*,const char*,int,FcCharSet**); 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*); oslGenericFunction loadSymbol( const char* ); @@ -118,6 +138,7 @@ { return m_pLib != NULL;} FcConfig* getDefConfig() { return m_pDefConfig; } + FcFontSet* getFontSet() { return m_pOutlineSet; } FcBool FcInit() { return m_pFcInit(); } @@ -147,14 +168,37 @@ 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); } + + FcBool FcCharSetHasChar(FcCharSet *fcs, FcChar32 ucs4) + { return m_pFcCharSetHasChar(fcs, ucs4); } + + void FcCharSetDestroy( FcCharSet* pSet ) + { m_pFcCharSetDestroy( pSet );} + 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 FcPatternGetCharSet( const FcPattern* pPattern, const char* object, int n, FcCharSet** s ) + { return m_pFcPatternGetCharSet( pPattern, object, n, s ); } + FcResult FcPatternGetString( const FcPattern* pPattern, const char* object, int n, FcChar8** s ) { return m_pFcPatternGetString( pPattern, object, n, s ); } @@ -168,8 +212,6 @@ { 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 ? m_pFcFontSetMatch( pConfig, ppFontSet, nset, pPattern, pResult ) : 0; } FcBool FcConfigSubstitute( FcConfig* pConfig, FcPattern* pPattern, FcMatchKind eKind ) @@ -178,6 +220,10 @@ { return m_pFcPatternAddInteger( pPattern, pObject, nValue ); } FcBool FcPatternAddString( FcPattern* pPattern, const char* pObject, const FcChar8* pString ) { return m_pFcPatternAddString( pPattern, pObject, pString ); } + FcBool FcPatternAddBool( FcPattern* pPattern, const char* pObject, bool nValue ) + { return m_pFcPatternAddBool( pPattern, pObject, nValue ); } + FcBool FcPatternAddCharSet(FcPattern* pPattern,const char* pObject,const FcCharSet*pCharSet) + { return m_pFcPatternAddCharSet(pPattern,pObject,pCharSet); } }; oslGenericFunction FontCfgWrapper::loadSymbol( const char* pSymbol ) @@ -192,7 +238,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" ) ); @@ -226,12 +273,26 @@ 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_pFcCharSetHasChar = (FcBool(*)(FcCharSet*, FcChar32)) + loadSymbol( "FcCharSetHasChar" ); + m_pFcCharSetDestroy = (void(*)(FcCharSet*)) + loadSymbol( "FcCharSetDestroy" ); m_pFcFontSetDestroy = (void(*)(FcFontSet*)) loadSymbol( "FcFontSetDestroy" ); m_pFcFontSetAdd = (FcBool(*)(FcFontSet*,FcPattern*)) loadSymbol( "FcFontSetAdd" ); + m_pFcPatternReference = (void(*)(FcPattern*)) + loadSymbol( "FcPatternReference" ); + m_pFcPatternGetCharSet = (FcResult(*)(const FcPattern*,const char*,int,FcCharSet**)) + loadSymbol( "FcPatternGetCharSet" ); m_pFcPatternGetString = (FcResult(*)(const FcPattern*,const char*,int,FcChar8**)) loadSymbol( "FcPatternGetString" ); m_pFcPatternGetInteger = (FcResult(*)(const FcPattern*,const char*,int,int*)) @@ -242,14 +303,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" ); @@ -261,17 +324,25 @@ m_pFcPatternCreate && m_pFcPatternDestroy && m_pFcFontList && + m_pFcConfigGetFonts && m_pFcFontSetCreate && + m_pFcCharSetCreate && + m_pFcCharSetAddChar && + m_pFcCharSetHasChar && + m_pFcCharSetDestroy && m_pFcFontSetDestroy && m_pFcFontSetAdd && + m_pFcPatternReference && + m_pFcPatternGetCharSet && m_pFcPatternGetString && m_pFcPatternGetInteger && m_pFcPatternGetDouble && m_pFcPatternGetBool && m_pFcDefaultSubstitute && - m_pFcFontMatch && m_pFcConfigSubstitute && m_pFcPatternAddInteger && + m_pFcPatternAddCharSet && + m_pFcPatternAddBool && m_pFcPatternAddString ) ) { @@ -289,10 +360,35 @@ osl_unloadModule( (oslModule)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( (oslModule)m_pLib ); } @@ -319,6 +415,94 @@ #define FC_EMBEDDED_BITMAP "embeddedbitmap" #endif +namespace +{ + typedef std::pair lang_and_family; + + class localizedsorter + { + rtl::OLocale maLoc; + public: + localizedsorter(rtl_Locale* pLoc) : maLoc(pLoc) {} + FcChar8* bestname(const std::vector &families); + }; + + FcChar8* localizedsorter::bestname(const std::vector &families) + { + FcChar8* candidate = families.begin()->second; + rtl::OString sLangMatch(rtl::OUStringToOString(maLoc.getLanguage().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8)); + rtl::OString sFullMatch = sLangMatch; + sFullMatch += OString('-'); + sFullMatch += rtl::OUStringToOString(maLoc.getCountry().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8); + + std::vector::const_iterator aEnd = families.end(); + bool alreadyclosematch = false; + for (std::vector::const_iterator aIter = families.begin(); aIter != aEnd; ++aIter) + { + const char *pLang = (const char*)aIter->first; + //perfect + if (strcmp(pLang, sFullMatch.getStr()) == 0) + { + candidate = aIter->second; + break; + } + else if ((strcmp(pLang, sLangMatch.getStr()) == 0) && (!alreadyclosematch)) + { + candidate = aIter->second; + alreadyclosematch = true; + } + } + + return candidate; + } + + + FcResult lcl_FamilyFromPattern(FontCfgWrapper& rWrapper, FcPattern* pPattern, FcChar8 **family, + std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash > &aFontconfigNameToLocalized) + { + FcChar8 *origfamily; + FcResult eFamilyRes = rWrapper.FcPatternGetString( pPattern, FC_FAMILY, 0, &origfamily ); + *family = origfamily; + + if( eFamilyRes == FcResultMatch) + { + FcChar8* familylang = NULL; + if (rWrapper.FcPatternGetString( pPattern, FC_FAMILYLANG, 0, &familylang ) == FcResultMatch) + { + std::vector< lang_and_family > lang_and_families; + lang_and_families.push_back(lang_and_family(familylang, *family)); + int k = 1; + while (1) + { + if (rWrapper.FcPatternGetString( pPattern, FC_FAMILYLANG, k, &familylang ) != FcResultMatch) + break; + if (rWrapper.FcPatternGetString( pPattern, FC_FAMILY, k, family ) != FcResultMatch) + break; + lang_and_families.push_back(lang_and_family(familylang, *family)); + ++k; + } + + //possible to-do, sort by UILocale instead of process locale + rtl_Locale* pLoc; + osl_getProcessLocale(&pLoc); + localizedsorter aSorter(pLoc); + *family = aSorter.bestname(lang_and_families); + + std::vector::const_iterator aEnd = lang_and_families.end(); + for (std::vector::const_iterator aIter = lang_and_families.begin(); aIter != aEnd; ++aIter) + { + const char *candidate = (const char*)(aIter->second); + if (strcmp(candidate, (const char*)(*family)) != 0) + aFontconfigNameToLocalized[OString(candidate)] = OString((const char*)(*family)); + } + } + } + + return eFamilyRes; + } +} + + /* * PrintFontManager::initFontconfig */ @@ -331,20 +505,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, - FC_EMBEDDED_BITMAP, - FC_ANTIALIAS, - (void *) NULL ); - FcPattern* pPattern = rWrapper.FcPatternCreate(); - FcFontSet* pFSet = rWrapper.FcFontList( pConfig, pPattern, pOSet ); + FcFontSet* pFSet = rWrapper.getFontSet(); if( pFSet ) { @@ -363,7 +524,7 @@ FcBool outline = false, embitmap = true, antialias = true; FcResult eFileRes = rWrapper.FcPatternGetString( pFSet->fonts[i], FC_FILE, 0, &file ); - FcResult eFamilyRes = rWrapper.FcPatternGetString( pFSet->fonts[i], FC_FAMILY, 0, &family ); + FcResult eFamilyRes = lcl_FamilyFromPattern(rWrapper, pFSet->fonts[i], &family, m_aFontconfigNameToLocalized ); FcResult eStyleRes = rWrapper.FcPatternGetString( pFSet->fonts[i], FC_STYLE, 0, &style ); FcResult eSlantRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_SLANT, 0, &slant ); FcResult eWeightRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_WEIGHT, 0, &weight ); @@ -389,6 +550,8 @@ ); #endif + OSL_ASSERT(eOutRes != FcResultMatch || outline); + // only outline fonts are usable to psprint anyway if( eOutRes == FcResultMatch && ! outline ) continue; @@ -542,14 +705,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 ); @@ -563,39 +718,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; @@ -604,10 +734,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; @@ -624,10 +754,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; @@ -643,10 +773,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; @@ -654,12 +784,148 @@ 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, 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()); + break; + } + + if( rLangAttrib.Len() ) + rWrapper.FcPatternAddString(pPattern, FC_LANG, (FcChar8*)rLangAttrib.GetBuffer()); + + // Add required Unicode characters, if any + if (! rGlyphs.empty() ) + { + FcCharSet *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); + rWrapper.FcCharSetDestroy( 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 ) + { + OString sFamily((sal_Char*)family); + std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash >::const_iterator aI = m_aFontconfigNameToLocalized.find(sFamily); + if (aI != m_aFontconfigNameToLocalized.end()) + sFamily = aI->second; + aName = String( sFamily.getStr(), RTL_TEXTENCODING_UTF8 ); + } + + if (!rGlyphs.empty() ) + { + std::vector aGlyphs; + FcCharSet *unicodes; + if (rWrapper.FcPatternGetCharSet(pSet->fonts[0], FC_CHARSET, 0, &unicodes) == FcResultMatch) + { + std::vector::iterator aGlyphEnd = rGlyphs.end(); + for (std::vector::iterator aGlyphIter = rGlyphs.begin(); + aGlyphIter != aGlyphEnd; ++aGlyphIter) + { + if (rWrapper.FcCharSetHasChar( unicodes, (FcChar32)*aGlyphIter )) + aGlyphs.push_back(*aGlyphIter); + } + } + rGlyphs.swap(aGlyphs); + } + + } + } + 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 ) { diff -ru OOE680_m6.fontconfig/psprint/source/fontmanager/fontmanager.cxx OOE680_m6/psprint/source/fontmanager/fontmanager.cxx --- OOE680_m6.fontconfig/psprint/source/fontmanager/fontmanager.cxx 2006-12-18 12:57:27.000000000 -0500 +++ OOE680_m6/psprint/source/fontmanager/fontmanager.cxx 2006-12-19 04:27:48.000000000 -0500 @@ -1165,7 +1165,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++ ) { @@ -2124,7 +2125,7 @@ #endif // first try fontconfig - bool bFontconfigSuccess = initFontconfig(); + m_bFontconfigSuccess = initFontconfig(); // part one - look for downloadable fonts rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); @@ -2146,7 +2147,7 @@ } // don't search through many directories fontconfig already told us about - if( ! bFontconfigSuccess ) + if( ! m_bFontconfigSuccess ) { Display *pDisplay = (Display*)pInitDisplay; @@ -2239,7 +2240,7 @@ } } #endif /* SOLARIS */ - } // ! bFontconfigSuccess + } // ! m_bFontconfigSuccess // fill XLFD aliases from fonts.alias files initFontsAlias(); diff -ru vcl/inc/sallayout.hxx vcl/inc/sallayout.hxx --- openoffice.org.orig/vcl/inc/vcl/sallayout.hxx 2007-01-11 10:26:04.000000000 +0000 +++ openoffice.org/vcl/inc/vcl/sallayout.hxx 2007-01-11 10:32:50.000000000 +0000 @@ -281,6 +281,8 @@ ImplFontData* GetFallbackFontData( int nFallbackLevel ) const { return mpFallbackFonts[ nFallbackLevel ]; } + void SetInComplete(bool bInComplete = true); + protected: virtual ~MultiSalLayout(); @@ -299,6 +301,7 @@ ImplFontData* mpFallbackFonts[ MAX_FALLBACK ]; ImplLayoutRuns maFallbackRuns[ MAX_FALLBACK ]; int mnLevel; + bool mbInComplete; }; // -------------------- diff -ru vcl/source/gdi/outdev3.cxx vcl/source/gdi/outdev3.cxx --- openoffice.org.orig/vcl/source/gdi/outdev3.cxx 2007-01-11 10:25:53.000000000 +0000 +++ openoffice.org/vcl/source/gdi/outdev3.cxx 2007-01-11 10:38:45.000000000 +0000 @@ -6320,7 +6320,7 @@ aFontSelData.mpFontEntry = pFallbackFont; aFontSelData.mpFontData = pFallbackFont->maFontSelData.mpFontData; - if( mpFontEntry ) + if( mpFontEntry && nFallbackLevel < MAX_FALLBACK-1) { // ignore fallback font if it is the same as the original font if( mpFontEntry->maFontSelData.mpFontData == aFontSelData.mpFontData ) @@ -6348,15 +6348,24 @@ SalLayout* pFallback = mpGraphics->GetTextLayout( rLayoutArgs, nFallbackLevel ); if( pFallback ) { + int nTemp = rLayoutArgs.mnFlags; + + if (nFallbackLevel == MAX_FALLBACK-1) + rLayoutArgs.mnFlags = rLayoutArgs.mnFlags ^= SAL_LAYOUT_FOR_FALLBACK; + if( pFallback->LayoutText( rLayoutArgs ) ) { if( !pMultiSalLayout ) pMultiSalLayout = new MultiSalLayout( *pSalLayout ); pMultiSalLayout->AddFallback( *pFallback, rLayoutArgs.maRuns, aFontSelData.mpFontData ); + if (nFallbackLevel == MAX_FALLBACK-1) + pMultiSalLayout->SetInComplete(); } else pFallback->Release(); + + rLayoutArgs.mnFlags = nTemp; } mpFontCache->Release( pFallbackFont ); diff -ru vcl/source/gdi/sallayout.cxx vcl/source/gdi/sallayout.cxx --- openoffice.org.orig/vcl/source/gdi/sallayout.cxx 2007-01-11 10:25:53.000000000 +0000 +++ openoffice.org/vcl/source/gdi/sallayout.cxx 2007-01-11 10:34:02.000000000 +0000 @@ -1561,13 +1561,20 @@ MultiSalLayout::MultiSalLayout( SalLayout& rBaseLayout ) : SalLayout(), - mnLevel( 1 ) + mnLevel( 1 ), + mbInComplete( false ) { //maFallbackRuns[0].Clear(); mpLayouts[ 0 ] = &rBaseLayout; mnUnitsPerPixel = rBaseLayout.GetUnitsPerPixel(); } +void MultiSalLayout::SetInComplete(bool bInComplete) +{ + mbInComplete = bInComplete; + maFallbackRuns[mnLevel-1] = ImplLayoutRuns(); +} + // ----------------------------------------------------------------------- MultiSalLayout::~MultiSalLayout() @@ -1597,7 +1604,8 @@ { if( mnLevel <= 1 ) return false; - maFallbackRuns[ mnLevel-1 ] = rArgs.maRuns; + if (!mbInComplete) + maFallbackRuns[ mnLevel-1 ] = rArgs.maRuns; return true; } @@ -1683,7 +1691,12 @@ // remove unused parts of component if( n > 0 ) - mpLayouts[n]->Simplify( false ); + { + if (mbInComplete && (n == mnLevel-1)) + mpLayouts[n]->Simplify( true ); + else + mpLayouts[n]->Simplify( false ); + } // prepare merging components nStartNew[ nLevel ] = nStartOld[ nLevel ] = 0;