LCOV - code coverage report
Current view: top level - vcl/source/font - PhysicalFontCollection.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 218 638 34.2 %
Date: 2014-11-03 Functions: 17 23 73.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <sal/types.h>
      21             : 
      22             : #include <vector>
      23             : 
      24             : #include <i18nlangtag/mslangid.hxx>
      25             : #include <tools/debug.hxx>
      26             : 
      27             : #include <config_graphite.h>
      28             : #if ENABLE_GRAPHITE
      29             : #include "graphite_features.hxx"
      30             : #endif
      31             : 
      32             : #include "magic.h"
      33             : #include "outdev.h"
      34             : #include "outfont.hxx"
      35             : #include "PhysicalFontFace.hxx"
      36             : 
      37             : #include "PhysicalFontCollection.hxx"
      38             : 
      39           0 : static unsigned lcl_IsCJKFont( const OUString& rFontName )
      40             : {
      41             :     // Test, if Fontname includes CJK characters --> In this case we
      42             :     // mention that it is a CJK font
      43           0 :     for(int i = 0; i < rFontName.getLength(); i++)
      44             :     {
      45           0 :         const sal_Unicode ch = rFontName[i];
      46             :         // japanese
      47           0 :         if ( ((ch >= 0x3040) && (ch <= 0x30FF)) ||
      48           0 :              ((ch >= 0x3190) && (ch <= 0x319F)) )
      49           0 :             return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_JP;
      50             : 
      51             :         // korean
      52           0 :         if ( ((ch >= 0xAC00) && (ch <= 0xD7AF)) ||
      53           0 :              ((ch >= 0x3130) && (ch <= 0x318F)) ||
      54           0 :              ((ch >= 0x1100) && (ch <= 0x11FF)) )
      55           0 :             return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_KR;
      56             : 
      57             :         // chinese
      58           0 :         if ( ((ch >= 0x3400) && (ch <= 0x9FFF)) )
      59           0 :             return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_TC|IMPL_FONT_ATTR_CJK_SC;
      60             : 
      61             :         // cjk
      62           0 :         if ( ((ch >= 0x3000) && (ch <= 0xD7AF)) ||
      63           0 :              ((ch >= 0xFF00) && (ch <= 0xFFEE)) )
      64           0 :             return IMPL_FONT_ATTR_CJK;
      65             : 
      66             :     }
      67             : 
      68           0 :     return 0;
      69             : }
      70             : 
      71        7143 : PhysicalFontCollection::PhysicalFontCollection()
      72             :     : mbMatchData( false )
      73             :     , mbMapNames( false )
      74             :     , mpPreMatchHook( NULL )
      75             :     , mpFallbackHook( NULL )
      76             :     , mpFallbackList( NULL )
      77        7143 :     , mnFallbackCount( -1 )
      78        7143 : {}
      79             : 
      80       21285 : PhysicalFontCollection::~PhysicalFontCollection()
      81             : {
      82        7095 :     Clear();
      83       14190 : }
      84             : 
      85        1092 : void PhysicalFontCollection::SetPreMatchHook( ImplPreMatchFontSubstitution* pHook )
      86             : {
      87        1092 :     mpPreMatchHook = pHook;
      88        1092 : }
      89             : 
      90        1092 : void PhysicalFontCollection::SetFallbackHook( ImplGlyphFallbackFontSubstitution* pHook )
      91             : {
      92        1092 :     mpFallbackHook = pHook;
      93        1092 : }
      94             : 
      95       13923 : void PhysicalFontCollection::Clear()
      96             : {
      97             :     // remove fallback lists
      98       13923 :     delete[] mpFallbackList;
      99       13923 :     mpFallbackList = NULL;
     100       13923 :     mnFallbackCount = -1;
     101             : 
     102             :     // clear all entries in the device font list
     103       13923 :     PhysicalFontFamilies::iterator it = maPhysicalFontFamilies.begin();
     104      370223 :     for(; it != maPhysicalFontFamilies.end(); ++it )
     105             :     {
     106      356300 :         PhysicalFontFamily* pEntry = (*it).second;
     107      356300 :         delete pEntry;
     108             :     }
     109             : 
     110       13923 :     maPhysicalFontFamilies.clear();
     111             : 
     112             :     // match data must be recalculated too
     113       13923 :     mbMatchData = false;
     114       13923 : }
     115             : 
     116         116 : void PhysicalFontCollection::InitGenericGlyphFallback( void ) const
     117             : {
     118             :     // normalized family names of fonts suited for glyph fallback
     119             :     // if a font is available related fonts can be ignored
     120             :     // TODO: implement dynamic lists
     121             :     static const char* aGlyphFallbackList[] = {
     122             :         // empty strings separate the names of unrelated fonts
     123             :         "eudc", "",
     124             :         "arialunicodems", "cyberbit", "code2000", "",
     125             :         "andalesansui", "",
     126             :         "starsymbol", "opensymbol", "",
     127             :         "msmincho", "fzmingti", "fzheiti", "ipamincho", "sazanamimincho", "kochimincho", "",
     128             :         "sunbatang", "sundotum", "baekmukdotum", "gulim", "batang", "dotum", "",
     129             :         "hgmincholightj", "msunglightsc", "msunglighttc", "hymyeongjolightk", "",
     130             :         "tahoma", "dejavusans", "timesnewroman", "liberationsans", "",
     131             :         "shree", "mangal", "",
     132             :         "raavi", "shruti", "tunga", "",
     133             :         "latha", "gautami", "kartika", "vrinda", "",
     134             :         "shayyalmt", "naskmt", "scheherazade", "",
     135             :         "david", "nachlieli", "lucidagrande", "",
     136             :         "norasi", "angsanaupc", "",
     137             :         "khmerossystem", "",
     138             :         "muktinarrow", "",
     139             :         "phetsarathot", "",
     140             :         "padauk", "pinlonmyanmar", "",
     141             :         "iskoolapota", "lklug", "",
     142             :         0
     143             :     };
     144             : 
     145         116 :     bool bHasEudc = false;
     146         116 :     int nMaxLevel = 0;
     147         116 :     int nBestQuality = 0;
     148         116 :     PhysicalFontFamily** pFallbackList = NULL;
     149             : 
     150        8120 :     for( const char** ppNames = &aGlyphFallbackList[0];; ++ppNames )
     151             :     {
     152             :         // advance to next sub-list when end-of-sublist marker
     153        8120 :         if( !**ppNames ) // #i46456# check for empty string, i.e., deref string itself not only ptr to it
     154             :         {
     155        2204 :             if( nBestQuality > 0 )
     156         232 :                 if( ++nMaxLevel >= MAX_FALLBACK )
     157         116 :                     break;
     158             : 
     159        2204 :             if( !ppNames[1] )
     160         116 :                 break;
     161             : 
     162        2088 :             nBestQuality = 0;
     163        9744 :             continue;
     164             :         }
     165             : 
     166             :         // test if the glyph fallback candidate font is available and scalable
     167        5916 :         OUString aTokenName( *ppNames, strlen(*ppNames), RTL_TEXTENCODING_UTF8 );
     168        5916 :         PhysicalFontFamily* pFallbackFont = FindFontFamily( aTokenName );
     169             : 
     170        5916 :         if( !pFallbackFont )
     171        5568 :             continue;
     172             : 
     173         348 :         if( !pFallbackFont->IsScalable() )
     174           0 :             continue;
     175             : 
     176             :         // keep the best font of the glyph fallback sub-list
     177         348 :         if( nBestQuality < pFallbackFont->GetMinQuality() )
     178             :         {
     179         232 :             nBestQuality = pFallbackFont->GetMinQuality();
     180             :             // store available glyph fallback fonts
     181         232 :             if( !pFallbackList )
     182         116 :                 pFallbackList = new PhysicalFontFamily*[ MAX_FALLBACK ];
     183             : 
     184         232 :             pFallbackList[ nMaxLevel ] = pFallbackFont;
     185         232 :             if( !bHasEudc && !nMaxLevel )
     186         116 :                 bHasEudc = !strncmp( *ppNames, "eudc", 5 );
     187             :         }
     188        8352 :     }
     189             : 
     190             : #ifdef SAL_FONTENUM_STABLE_ON_PLATFORM // #i113472#
     191             :     // sort the list of fonts for glyph fallback by quality (highest first)
     192             :     // #i33947# keep the EUDC font at the front of the list
     193             :     // an insertion sort is good enough for this short list
     194             :     const int nSortStart = bHasEudc ? 1 : 0;
     195             :     for( int i = nSortStart+1, j; i < nMaxLevel; ++i )
     196             :     {
     197             :         PhysicalFontFamily* pTestFont = pFallbackList[ i ];
     198             :         int nTestQuality = pTestFont->GetMinQuality();
     199             : 
     200             :         for( j = i; --j >= nSortStart; )
     201             :         {
     202             :             if( nTestQuality > pFallbackList[j]->GetMinQuality() )
     203             :                 pFallbackList[ j+1 ] = pFallbackList[ j ];
     204             :             else
     205             :                 break;
     206             :         }
     207             :         pFallbackList[ j+1 ] = pTestFont;
     208             :     }
     209             : #endif
     210             : 
     211         116 :     mnFallbackCount = nMaxLevel;
     212         116 :     mpFallbackList  = pFallbackList;
     213         116 : }
     214             : 
     215        4744 : PhysicalFontFamily* PhysicalFontCollection::GetGlyphFallbackFont( FontSelectPattern& rFontSelData,
     216             :                                                                   OUString& rMissingCodes,
     217             :                                                                   int nFallbackLevel ) const
     218             : {
     219        4744 :     PhysicalFontFamily* pFallbackData = NULL;
     220             : 
     221             :     // find a matching font candidate for platform specific glyph fallback
     222        4744 :     if( mpFallbackHook )
     223             :     {
     224             :         // check cache for the first matching entry
     225             :         // to avoid calling the expensive fallback hook (#i83491#)
     226        4744 :         sal_UCS4 cChar = 0;
     227        4744 :         bool bCached = true;
     228        4744 :         sal_Int32 nStrIndex = 0;
     229       10634 :         while( nStrIndex < rMissingCodes.getLength() )
     230             :         {
     231        2476 :             cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
     232        2476 :             bCached = rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName );
     233             : 
     234             :             // ignore entries which don't have a fallback
     235        2476 :             if( !bCached || !rFontSelData.maSearchName.isEmpty() )
     236        1330 :                 break;
     237             :         }
     238             : 
     239        4744 :         if( bCached )
     240             :         {
     241             :             // there is a matching fallback in the cache
     242             :             // so update rMissingCodes with codepoints not yet resolved by this fallback
     243        4166 :             int nRemainingLength = 0;
     244        4166 :             sal_UCS4* pRemainingCodes = (sal_UCS4*)alloca( rMissingCodes.getLength() * sizeof(sal_UCS4) );
     245        4166 :             OUString aFontName;
     246             : 
     247        8522 :             while( nStrIndex < rMissingCodes.getLength() )
     248             :             {
     249         190 :                 cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
     250         190 :                 bCached = rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &aFontName );
     251         190 :                 if( !bCached || (rFontSelData.maSearchName != aFontName) )
     252           0 :                     pRemainingCodes[ nRemainingLength++ ] = cChar;
     253             :             }
     254        4166 :             rMissingCodes = OUString( pRemainingCodes, nRemainingLength );
     255             :         }
     256             :         else
     257             :         {
     258         578 :             OUString aOldMissingCodes = rMissingCodes;
     259             : 
     260             :             // call the hook to query the best matching glyph fallback font
     261         578 :             if( mpFallbackHook->FindFontSubstitute( rFontSelData, rMissingCodes ) )
     262             :                 // apply outdev3.cxx specific fontname normalization
     263         460 :                 rFontSelData.maSearchName = GetEnglishSearchFontName( rFontSelData.maSearchName );
     264             :             else
     265         118 :                 rFontSelData.maSearchName = "";
     266             : 
     267             :             // See fdo#32665 for an example. FreeSerif that has glyphs in normal
     268             :             // font, but not in the italic or bold version
     269         578 :             bool bSubSetOfFontRequiresPropertyFaking = rFontSelData.mbEmbolden || rFontSelData.maItalicMatrix != ItalicMatrix();
     270             : 
     271             :             // Cache the result even if there was no match, unless its from part of a font for which the properties need
     272             :             // to be faked. We need to rework this cache to take into account that fontconfig can return different fonts
     273             :             // for different input sizes, weights, etc. Basically the cache is way to naive
     274         990 :             if (!bSubSetOfFontRequiresPropertyFaking)
     275             :             {
     276             :                 for(;;)
     277             :                 {
     278         990 :                      if( !rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName ) )
     279         968 :                          rFontSelData.mpFontEntry->AddFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
     280         990 :                      if( nStrIndex >= aOldMissingCodes.getLength() )
     281         578 :                          break;
     282         412 :                      cChar = aOldMissingCodes.iterateCodePoints( &nStrIndex );
     283             :                 }
     284         578 :                 if( !rFontSelData.maSearchName.isEmpty() )
     285             :                 {
     286             :                     // remove cache entries that were still not resolved
     287        1622 :                     for( nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
     288             :                     {
     289         702 :                         cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
     290         702 :                         rFontSelData.mpFontEntry->IgnoreFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
     291             :                     }
     292             :                 }
     293         578 :             }
     294             :         }
     295             : 
     296             :         // find the matching device font
     297        4744 :         if( !rFontSelData.maSearchName.isEmpty() )
     298        1288 :             pFallbackData = FindFontFamily( rFontSelData.maSearchName );
     299             :     }
     300             : 
     301             :     // else find a matching font candidate for generic glyph fallback
     302        4744 :     if( !pFallbackData )
     303             :     {
     304             :         // initialize font candidates for generic glyph fallback if needed
     305        3456 :         if( mnFallbackCount < 0 )
     306         116 :             InitGenericGlyphFallback();
     307             : 
     308             :         // TODO: adjust nFallbackLevel by number of levels resolved by the fallback hook
     309        3456 :         if( nFallbackLevel < mnFallbackCount )
     310        2228 :             pFallbackData = mpFallbackList[ nFallbackLevel ];
     311             :     }
     312             : 
     313        4744 :     return pFallbackData;
     314             : }
     315             : 
     316      165984 : void PhysicalFontCollection::Add( PhysicalFontFace* pNewData )
     317             : {
     318      165984 :     OUString aSearchName = GetEnglishSearchFontName( pNewData->GetFamilyName() );
     319             : 
     320      165984 :     PhysicalFontFamily* pFoundData = FindOrCreateFamily( aSearchName );
     321             : 
     322      165984 :     bool bKeepNewData = pFoundData->AddFontFace( pNewData );
     323             : 
     324      165984 :     if( !bKeepNewData )
     325        8112 :         delete pNewData;
     326      165984 : }
     327             : 
     328             : // find the font from the normalized font family name
     329     2170575 : PhysicalFontFamily* PhysicalFontCollection::ImplFindBySearchName( const OUString& rSearchName ) const
     330             : {
     331             :     // must be called with a normalized name.
     332             :     assert( GetEnglishSearchFontName( rSearchName ) == rSearchName );
     333             : 
     334     2170575 :     PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.find( rSearchName );
     335     2170575 :     if( it == maPhysicalFontFamilies.end() )
     336     2028745 :         return NULL;
     337             : 
     338      141830 :     PhysicalFontFamily* pFoundData = (*it).second;
     339      141830 :     return pFoundData;
     340             : }
     341             : 
     342           0 : PhysicalFontFamily* PhysicalFontCollection::ImplFindByAliasName(const OUString& rSearchName,
     343             :     const OUString& rShortName) const
     344             : {
     345             :     // short circuit for impossible font name alias
     346           0 :     if (rSearchName.isEmpty())
     347           0 :         return NULL;
     348             : 
     349             :     // short circuit if no alias names are available
     350           0 :     if (!mbMapNames)
     351           0 :         return NULL;
     352             : 
     353             :     // use the font's alias names to find the font
     354             :     // TODO: get rid of linear search
     355           0 :     PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin();
     356           0 :     while( it != maPhysicalFontFamilies.end() )
     357             :     {
     358           0 :         PhysicalFontFamily* pData = (*it).second;
     359           0 :         if( pData->GetAliasNames().isEmpty() )
     360           0 :             continue;
     361             : 
     362             :         // if one alias name matches we found a matching font
     363           0 :         OUString aTempName;
     364           0 :         sal_Int32 nIndex = 0;
     365             : 
     366           0 :         do
     367             :         {
     368           0 :             aTempName = GetNextFontToken( pData->GetAliasNames(), nIndex );
     369             :            // Test, if the Font name match with one of the mapping names
     370           0 :            if ( (aTempName == rSearchName) || (aTempName == rShortName) )
     371           0 :               return pData;
     372             :         }
     373           0 :         while ( nIndex != -1 );
     374           0 :      }
     375             : 
     376           0 :      return NULL;
     377             : }
     378             : 
     379       12066 : PhysicalFontFamily* PhysicalFontCollection::FindFontFamily( const OUString& rFontName ) const
     380             : {
     381       12066 :     return ImplFindBySearchName( GetEnglishSearchFontName( rFontName ) );
     382             : }
     383             : 
     384      469984 : PhysicalFontFamily *PhysicalFontCollection::FindOrCreateFamily( const OUString &rFamilyName )
     385             : {
     386      469984 :     PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.find( rFamilyName );
     387      469984 :     PhysicalFontFamily* pFoundData = NULL;
     388             : 
     389      469984 :     if( it != maPhysicalFontFamilies.end() )
     390      111384 :         pFoundData = (*it).second;
     391             : 
     392      469984 :     if( !pFoundData )
     393             :     {
     394      358600 :         pFoundData = new PhysicalFontFamily( rFamilyName );
     395      358600 :         maPhysicalFontFamilies[ rFamilyName ] = pFoundData;
     396             :     }
     397             : 
     398      469984 :     return pFoundData;
     399             : }
     400             : 
     401           0 : PhysicalFontFamily* PhysicalFontCollection::ImplFindByTokenNames(const OUString& rTokenStr) const
     402             : {
     403           0 :     PhysicalFontFamily* pFoundData = NULL;
     404             : 
     405             :     // use normalized font name tokens to find the font
     406           0 :     for( sal_Int32 nTokenPos = 0; nTokenPos != -1; )
     407             :     {
     408           0 :         OUString aFamilyName = GetNextFontToken( rTokenStr, nTokenPos );
     409           0 :         if( aFamilyName.isEmpty() )
     410           0 :             continue;
     411             : 
     412           0 :         pFoundData = FindFontFamily( aFamilyName );
     413             : 
     414           0 :         if( pFoundData )
     415           0 :             break;
     416           0 :     }
     417             : 
     418           0 :     return pFoundData;
     419             : }
     420             : 
     421         700 : PhysicalFontFamily* PhysicalFontCollection::ImplFindBySubstFontAttr( const utl::FontNameAttr& rFontAttr ) const
     422             : {
     423         700 :     PhysicalFontFamily* pFoundData = NULL;
     424             : 
     425             :     // use the font substitutions suggested by the FontNameAttr to find the font
     426         700 :     ::std::vector< OUString >::const_iterator it = rFontAttr.Substitutions.begin();
     427         796 :     for(; it != rFontAttr.Substitutions.end(); ++it )
     428             :     {
     429         796 :         pFoundData = FindFontFamily( *it );
     430         796 :         if( pFoundData )
     431         700 :             return pFoundData;
     432             :     }
     433             : 
     434             :     // use known attributes from the configuration to find a matching substitute
     435           0 :     const sal_uLong nSearchType = rFontAttr.Type;
     436           0 :     if( nSearchType != 0 )
     437             :     {
     438           0 :         const FontWeight eSearchWeight = rFontAttr.Weight;
     439           0 :         const FontWidth  eSearchWidth  = rFontAttr.Width;
     440           0 :         const FontItalic eSearchSlant  = ITALIC_DONTKNOW;
     441           0 :         const OUString aSearchName;
     442             : 
     443             :         pFoundData = ImplFindByAttributes( nSearchType,
     444           0 :             eSearchWeight, eSearchWidth, eSearchSlant, aSearchName );
     445             : 
     446           0 :         if( pFoundData )
     447           0 :             return pFoundData;
     448             :     }
     449             : 
     450           0 :     return NULL;
     451             : }
     452             : 
     453           0 : void PhysicalFontCollection::InitMatchData() const
     454             : {
     455             :     // short circuit if already done
     456           0 :     if( mbMatchData )
     457           0 :         return;
     458           0 :     mbMatchData = true;
     459             : 
     460             :     // calculate MatchData for all entries
     461           0 :     const utl::FontSubstConfiguration& rFontSubst = utl::FontSubstConfiguration::get();
     462             : 
     463           0 :     PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin();
     464           0 :     for(; it != maPhysicalFontFamilies.end(); ++it )
     465             :     {
     466           0 :         const OUString& rSearchName = (*it).first;
     467           0 :         PhysicalFontFamily* pEntry = (*it).second;
     468             : 
     469           0 :         pEntry->InitMatchData( rFontSubst, rSearchName );
     470             :     }
     471             : }
     472             : 
     473           0 : PhysicalFontFamily* PhysicalFontCollection::ImplFindByAttributes( sal_uLong nSearchType,
     474             :                                                                   FontWeight eSearchWeight,
     475             :                                                                   FontWidth eSearchWidth,
     476             :                                                                   FontItalic eSearchItalic,
     477             :                                                                   const OUString& rSearchFamilyName ) const
     478             : {
     479           0 :     if( (eSearchItalic != ITALIC_NONE) && (eSearchItalic != ITALIC_DONTKNOW) )
     480           0 :         nSearchType |= IMPL_FONT_ATTR_ITALIC;
     481             : 
     482             :     // don't bother to match attributes if the attributes aren't worth matching
     483           0 :     if( !nSearchType
     484           0 :     && ((eSearchWeight == WEIGHT_DONTKNOW) || (eSearchWeight == WEIGHT_NORMAL))
     485           0 :     && ((eSearchWidth == WIDTH_DONTKNOW) || (eSearchWidth == WIDTH_NORMAL)) )
     486           0 :         return NULL;
     487             : 
     488           0 :     InitMatchData();
     489           0 :     PhysicalFontFamily* pFoundData = NULL;
     490             : 
     491             :     long    nTestMatch;
     492           0 :     long    nBestMatch = 40000;
     493           0 :     sal_uLong   nBestType = 0;
     494             : 
     495           0 :     PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin();
     496           0 :     for(; it != maPhysicalFontFamilies.end(); ++it )
     497             :     {
     498           0 :         PhysicalFontFamily* pData = (*it).second;
     499             : 
     500             :         // Get all information about the matching font
     501           0 :         sal_uLong   nMatchType  = pData->GetMatchType();
     502           0 :         FontWeight  eMatchWeight= pData->GetMatchWeight();
     503           0 :         FontWidth   eMatchWidth = pData->GetMatchWidth();
     504             : 
     505             :         // Calculate Match Value
     506             :         // 1000000000
     507             :         //  100000000
     508             :         //   10000000   CJK, CTL, None-Latin, Symbol
     509             :         //    1000000   FamilyName, Script, Fixed, -Special, -Decorative,
     510             :         //              Titling, Capitals, Outline, Shadow
     511             :         //     100000   Match FamilyName, Serif, SansSerif, Italic,
     512             :         //              Width, Weight
     513             :         //      10000   Scalable, Standard, Default,
     514             :         //              full, Normal, Knownfont,
     515             :         //              Otherstyle, +Special, +Decorative,
     516             :         //       1000   Typewriter, Rounded, Gothic, Schollbook
     517             :         //        100
     518           0 :         nTestMatch = 0;
     519             : 
     520             :         // test CJK script attributes
     521           0 :         if ( nSearchType & IMPL_FONT_ATTR_CJK )
     522             :         {
     523             :             // Matching language
     524           0 :             if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_CJK_ALLLANG) )
     525           0 :                 nTestMatch += 10000000*3;
     526           0 :             if( nMatchType & IMPL_FONT_ATTR_CJK )
     527           0 :                 nTestMatch += 10000000*2;
     528           0 :             if( nMatchType & IMPL_FONT_ATTR_FULL )
     529           0 :                 nTestMatch += 10000000;
     530             :         }
     531           0 :         else if ( nMatchType & IMPL_FONT_ATTR_CJK )
     532             :         {
     533           0 :             nTestMatch -= 10000000;
     534             :         }
     535             : 
     536             :         // test CTL script attributes
     537           0 :         if( nSearchType & IMPL_FONT_ATTR_CTL )
     538             :         {
     539           0 :             if( nMatchType & IMPL_FONT_ATTR_CTL )
     540           0 :                 nTestMatch += 10000000*2;
     541           0 :             if( nMatchType & IMPL_FONT_ATTR_FULL )
     542           0 :                 nTestMatch += 10000000;
     543             :         }
     544           0 :         else if ( nMatchType & IMPL_FONT_ATTR_CTL )
     545             :         {
     546           0 :             nTestMatch -= 10000000;
     547             :         }
     548             : 
     549             :         // test LATIN script attributes
     550           0 :         if( nSearchType & IMPL_FONT_ATTR_NONELATIN )
     551             :         {
     552           0 :             if( nMatchType & IMPL_FONT_ATTR_NONELATIN )
     553           0 :                 nTestMatch += 10000000*2;
     554           0 :             if( nMatchType & IMPL_FONT_ATTR_FULL )
     555           0 :                 nTestMatch += 10000000;
     556             :         }
     557             : 
     558             :         // test SYMBOL attributes
     559           0 :         if ( nSearchType & IMPL_FONT_ATTR_SYMBOL )
     560             :         {
     561           0 :             const OUString& rSearchName = it->first;
     562             :             // prefer some special known symbol fonts
     563           0 :             if ( rSearchName == "starsymbol" )
     564             :             {
     565           0 :                 nTestMatch += 10000000*6+(10000*3);
     566             :             }
     567           0 :             else if ( rSearchName == "opensymbol" )
     568             :             {
     569           0 :                 nTestMatch += 10000000*6;
     570             :             }
     571           0 :             else if ( rSearchName == "starbats" ||
     572           0 :                       rSearchName == "wingdings" ||
     573           0 :                       rSearchName == "monotypesorts" ||
     574           0 :                       rSearchName == "dingbats" ||
     575           0 :                       rSearchName == "zapfdingbats" )
     576             :             {
     577           0 :                 nTestMatch += 10000000*5;
     578             :             }
     579           0 :             else if ( pData->GetTypeFaces() & FONT_FAMILY_SYMBOL )
     580             :             {
     581           0 :                 nTestMatch += 10000000*4;
     582             :             }
     583             :             else
     584             :             {
     585           0 :                 if( nMatchType & IMPL_FONT_ATTR_SYMBOL )
     586           0 :                     nTestMatch += 10000000*2;
     587           0 :                 if( nMatchType & IMPL_FONT_ATTR_FULL )
     588           0 :                     nTestMatch += 10000000;
     589             :             }
     590             :         }
     591           0 :         else if ( (pData->GetTypeFaces() & (FONT_FAMILY_SYMBOL | FONT_FAMILY_NONESYMBOL)) == FONT_FAMILY_SYMBOL )
     592             :         {
     593           0 :             nTestMatch -= 10000000;
     594             :         }
     595           0 :         else if ( nMatchType & IMPL_FONT_ATTR_SYMBOL )
     596             :         {
     597           0 :             nTestMatch -= 10000;
     598             :         }
     599             : 
     600             :         // match stripped family name
     601           0 :         if( !rSearchFamilyName.isEmpty() && (rSearchFamilyName == pData->GetMatchFamilyName()) )
     602             :         {
     603           0 :             nTestMatch += 1000000*3;
     604             :         }
     605             : 
     606             :         // match ALLSCRIPT? attribute
     607           0 :         if( nSearchType & IMPL_FONT_ATTR_ALLSCRIPT )
     608             :         {
     609           0 :             if( nMatchType & IMPL_FONT_ATTR_ALLSCRIPT )
     610             :             {
     611           0 :                 nTestMatch += 1000000*2;
     612             :             }
     613           0 :             if( nSearchType & IMPL_FONT_ATTR_ALLSUBSCRIPT )
     614             :             {
     615           0 :                 if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_ALLSUBSCRIPT) )
     616           0 :                     nTestMatch += 1000000*2;
     617           0 :                 if( 0 != ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_BRUSHSCRIPT) )
     618           0 :                     nTestMatch -= 1000000;
     619             :             }
     620             :         }
     621           0 :         else if( nMatchType & IMPL_FONT_ATTR_ALLSCRIPT )
     622             :         {
     623           0 :             nTestMatch -= 1000000;
     624             :         }
     625             : 
     626             :         // test MONOSPACE+TYPEWRITER attributes
     627           0 :         if( nSearchType & IMPL_FONT_ATTR_FIXED )
     628             :         {
     629           0 :             if( nMatchType & IMPL_FONT_ATTR_FIXED )
     630           0 :                 nTestMatch += 1000000*2;
     631             :             // a typewriter attribute is even better
     632           0 :             if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_TYPEWRITER) )
     633           0 :                 nTestMatch += 10000*2;
     634             :         }
     635           0 :         else if( nMatchType & IMPL_FONT_ATTR_FIXED )
     636             :         {
     637           0 :             nTestMatch -= 1000000;
     638             :         }
     639             : 
     640             :         // test SPECIAL attribute
     641           0 :         if( nSearchType & IMPL_FONT_ATTR_SPECIAL )
     642             :         {
     643           0 :             if( nMatchType & IMPL_FONT_ATTR_SPECIAL )
     644             :             {
     645           0 :                 nTestMatch += 10000;
     646             :             }
     647           0 :             else if( !(nSearchType & IMPL_FONT_ATTR_ALLSERIFSTYLE) )
     648             :             {
     649           0 :                  if( nMatchType & IMPL_FONT_ATTR_SERIF )
     650             :                  {
     651           0 :                      nTestMatch += 1000*2;
     652             :                  }
     653           0 :                  else if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
     654             :                  {
     655           0 :                      nTestMatch += 1000;
     656             :                  }
     657             :              }
     658             :         }
     659           0 :         else if( (nMatchType & IMPL_FONT_ATTR_SPECIAL) && !(nSearchType & IMPL_FONT_ATTR_SYMBOL) )
     660             :         {
     661           0 :             nTestMatch -= 1000000;
     662             :         }
     663             : 
     664             :         // test DECORATIVE attribute
     665           0 :         if( nSearchType & IMPL_FONT_ATTR_DECORATIVE )
     666             :         {
     667           0 :             if( nMatchType & IMPL_FONT_ATTR_DECORATIVE )
     668             :             {
     669           0 :                 nTestMatch += 10000;
     670             :             }
     671           0 :             else if( !(nSearchType & IMPL_FONT_ATTR_ALLSERIFSTYLE) )
     672             :             {
     673           0 :                 if( nMatchType & IMPL_FONT_ATTR_SERIF )
     674           0 :                     nTestMatch += 1000*2;
     675           0 :                 else if ( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
     676           0 :                     nTestMatch += 1000;
     677             :             }
     678             :         }
     679           0 :         else if( nMatchType & IMPL_FONT_ATTR_DECORATIVE )
     680             :         {
     681           0 :             nTestMatch -= 1000000;
     682             :         }
     683             : 
     684             :         // test TITLE+CAPITALS attributes
     685           0 :         if( nSearchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) )
     686             :         {
     687           0 :             if( nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) )
     688             :             {
     689           0 :                 nTestMatch += 1000000*2;
     690             :             }
     691           0 :             if( 0 == ((nSearchType^nMatchType) & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS)))
     692             :             {
     693           0 :                 nTestMatch += 1000000;
     694             :             }
     695           0 :             else if( (nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS)) &&
     696           0 :                      (nMatchType & (IMPL_FONT_ATTR_STANDARD | IMPL_FONT_ATTR_DEFAULT)) )
     697             :             {
     698           0 :                 nTestMatch += 1000000;
     699             :             }
     700             :         }
     701           0 :         else if( nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) )
     702             :         {
     703           0 :             nTestMatch -= 1000000;
     704             :         }
     705             : 
     706             :         // test OUTLINE+SHADOW attributes
     707           0 :         if( nSearchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) )
     708             :         {
     709           0 :             if( nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) )
     710             :             {
     711           0 :                 nTestMatch += 1000000*2;
     712             :             }
     713           0 :             if( 0 == ((nSearchType ^ nMatchType) & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW)) )
     714             :             {
     715           0 :                 nTestMatch += 1000000;
     716             :             }
     717           0 :             else if( (nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW)) &&
     718           0 :                      (nMatchType & (IMPL_FONT_ATTR_STANDARD | IMPL_FONT_ATTR_DEFAULT)) )
     719             :             {
     720           0 :                 nTestMatch += 1000000;
     721             :             }
     722             :         }
     723           0 :         else if ( nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) )
     724             :         {
     725           0 :             nTestMatch -= 1000000;
     726             :         }
     727             : 
     728             :         // test font name substrings
     729             :         // TODO: calculate name matching score using e.g. Levenstein distance
     730           0 :         if( (rSearchFamilyName.getLength() >= 4) &&
     731           0 :             (pData->GetMatchFamilyName().getLength() >= 4) &&
     732           0 :             ((rSearchFamilyName.indexOf( pData->GetMatchFamilyName() ) != -1) ||
     733           0 :              (pData->GetMatchFamilyName().indexOf( rSearchFamilyName ) != -1)) )
     734             :         {
     735           0 :             nTestMatch += 5000;
     736             :         }
     737             :         // test SERIF attribute
     738           0 :         if( nSearchType & IMPL_FONT_ATTR_SERIF )
     739             :         {
     740           0 :             if( nMatchType & IMPL_FONT_ATTR_SERIF )
     741           0 :                 nTestMatch += 1000000*2;
     742           0 :             else if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
     743           0 :                 nTestMatch -= 1000000;
     744             :         }
     745             : 
     746             :         // test SANSERIF attribute
     747           0 :         if( nSearchType & IMPL_FONT_ATTR_SANSSERIF )
     748             :         {
     749           0 :             if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
     750           0 :                 nTestMatch += 1000000;
     751           0 :             else if ( nMatchType & IMPL_FONT_ATTR_SERIF )
     752           0 :                 nTestMatch -= 1000000;
     753             :         }
     754             : 
     755             :         // test ITALIC attribute
     756           0 :         if( nSearchType & IMPL_FONT_ATTR_ITALIC )
     757             :         {
     758           0 :             if( pData->GetTypeFaces() & FONT_FAMILY_ITALIC )
     759           0 :                 nTestMatch += 1000000*3;
     760           0 :             if( nMatchType & IMPL_FONT_ATTR_ITALIC )
     761           0 :                 nTestMatch += 1000000;
     762             :         }
     763           0 :         else if( !(nSearchType & IMPL_FONT_ATTR_ALLSCRIPT) &&
     764           0 :                  ((nMatchType & IMPL_FONT_ATTR_ITALIC) ||
     765           0 :                   !(pData->GetTypeFaces() & FONT_FAMILY_NONEITALIC)) )
     766             :         {
     767           0 :             nTestMatch -= 1000000*2;
     768             :         }
     769             : 
     770             :         // test WIDTH attribute
     771           0 :         if( (eSearchWidth != WIDTH_DONTKNOW) && (eSearchWidth != WIDTH_NORMAL) )
     772             :         {
     773           0 :             if( eSearchWidth < WIDTH_NORMAL )
     774             :             {
     775           0 :                 if( eSearchWidth == eMatchWidth )
     776           0 :                     nTestMatch += 1000000*3;
     777           0 :                 else if( (eMatchWidth < WIDTH_NORMAL) && (eMatchWidth != WIDTH_DONTKNOW) )
     778           0 :                     nTestMatch += 1000000;
     779             :             }
     780             :             else
     781             :             {
     782           0 :                 if( eSearchWidth == eMatchWidth )
     783           0 :                     nTestMatch += 1000000*3;
     784           0 :                 else if( eMatchWidth > WIDTH_NORMAL )
     785           0 :                     nTestMatch += 1000000;
     786             :             }
     787             :         }
     788           0 :         else if( (eMatchWidth != WIDTH_DONTKNOW) && (eMatchWidth != WIDTH_NORMAL) )
     789             :         {
     790           0 :             nTestMatch -= 1000000;
     791             :         }
     792             : 
     793             :         // test WEIGHT attribute
     794           0 :         if( (eSearchWeight != WEIGHT_DONTKNOW) &&
     795           0 :             (eSearchWeight != WEIGHT_NORMAL) &&
     796             :             (eSearchWeight != WEIGHT_MEDIUM) )
     797             :         {
     798           0 :             if( eSearchWeight < WEIGHT_NORMAL )
     799             :             {
     800           0 :                 if( pData->GetTypeFaces() & FONT_FAMILY_LIGHT )
     801           0 :                     nTestMatch += 1000000;
     802           0 :                 if( (eMatchWeight < WEIGHT_NORMAL) && (eMatchWeight != WEIGHT_DONTKNOW) )
     803           0 :                     nTestMatch += 1000000;
     804             :             }
     805             :             else
     806             :             {
     807           0 :                 if( pData->GetTypeFaces() & FONT_FAMILY_BOLD )
     808           0 :                     nTestMatch += 1000000;
     809           0 :                 if( eMatchWeight > WEIGHT_BOLD )
     810           0 :                     nTestMatch += 1000000;
     811             :             }
     812             :         }
     813           0 :         else if( ((eMatchWeight != WEIGHT_DONTKNOW) &&
     814           0 :                   (eMatchWeight != WEIGHT_NORMAL) &&
     815           0 :                   (eMatchWeight != WEIGHT_MEDIUM)) ||
     816           0 :                  !(pData->GetTypeFaces() & FONT_FAMILY_NORMAL) )
     817             :         {
     818           0 :             nTestMatch -= 1000000;
     819             :         }
     820             : 
     821             :         // prefer scalable fonts
     822           0 :         if( pData->GetTypeFaces() & FONT_FAMILY_SCALABLE )
     823           0 :             nTestMatch += 10000*4;
     824             :         else
     825           0 :             nTestMatch -= 10000*4;
     826             : 
     827             :         // test STANDARD+DEFAULT+FULL+NORMAL attributes
     828           0 :         if( nMatchType & IMPL_FONT_ATTR_STANDARD )
     829           0 :             nTestMatch += 10000*2;
     830           0 :         if( nMatchType & IMPL_FONT_ATTR_DEFAULT )
     831           0 :             nTestMatch += 10000;
     832           0 :         if( nMatchType & IMPL_FONT_ATTR_FULL )
     833           0 :             nTestMatch += 10000;
     834           0 :         if( nMatchType & IMPL_FONT_ATTR_NORMAL )
     835           0 :             nTestMatch += 10000;
     836             : 
     837             :         // test OTHERSTYLE attribute
     838           0 :         if( ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_OTHERSTYLE) != 0 )
     839             :         {
     840           0 :             nTestMatch -= 10000;
     841             :         }
     842             : 
     843             :         // test ROUNDED attribute
     844           0 :         if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_ROUNDED) )
     845           0 :             nTestMatch += 1000;
     846             : 
     847             :         // test TYPEWRITER attribute
     848           0 :         if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_TYPEWRITER) )
     849           0 :             nTestMatch += 1000;
     850             : 
     851             :         // test GOTHIC attribute
     852           0 :         if( nSearchType & IMPL_FONT_ATTR_GOTHIC )
     853             :         {
     854           0 :             if( nMatchType & IMPL_FONT_ATTR_GOTHIC )
     855           0 :                 nTestMatch += 1000*3;
     856           0 :             if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
     857           0 :                 nTestMatch += 1000*2;
     858             :         }
     859             : 
     860             :         // test SCHOOLBOOK attribute
     861           0 :         if( nSearchType & IMPL_FONT_ATTR_SCHOOLBOOK )
     862             :         {
     863           0 :             if( nMatchType & IMPL_FONT_ATTR_SCHOOLBOOK )
     864           0 :                 nTestMatch += 1000*3;
     865           0 :             if( nMatchType & IMPL_FONT_ATTR_SERIF )
     866           0 :                 nTestMatch += 1000*2;
     867             :         }
     868             : 
     869             :         // compare with best matching font yet
     870           0 :         if ( nTestMatch > nBestMatch )
     871             :         {
     872           0 :             pFoundData  = pData;
     873           0 :             nBestMatch  = nTestMatch;
     874           0 :             nBestType   = nMatchType;
     875             :         }
     876           0 :         else if( nTestMatch == nBestMatch )
     877             :         {
     878             :             // some fonts are more suitable defaults
     879           0 :             if( nMatchType & IMPL_FONT_ATTR_DEFAULT )
     880             :             {
     881           0 :                 pFoundData  = pData;
     882           0 :                 nBestType   = nMatchType;
     883             :             }
     884           0 :             else if( (nMatchType & IMPL_FONT_ATTR_STANDARD) &&
     885           0 :                     !(nBestType & IMPL_FONT_ATTR_DEFAULT) )
     886             :             {
     887           0 :                  pFoundData  = pData;
     888           0 :                  nBestType   = nMatchType;
     889             :             }
     890             :         }
     891             :     }
     892             : 
     893           0 :     return pFoundData;
     894             : }
     895             : 
     896           0 : PhysicalFontFamily* PhysicalFontCollection::FindDefaultFont() const
     897             : {
     898             :     // try to find one of the default fonts of the
     899             :     // UNICODE, SANSSERIF, SERIF or FIXED default font lists
     900           0 :     const utl::DefaultFontConfiguration& rDefaults = utl::DefaultFontConfiguration::get();
     901           0 :     LanguageTag aLanguageTag( OUString( "en"));
     902           0 :     OUString aFontname = rDefaults.getDefaultFont( aLanguageTag, DEFAULTFONT_SANS_UNICODE );
     903           0 :     PhysicalFontFamily* pFoundData = ImplFindByTokenNames( aFontname );
     904             : 
     905           0 :     if( pFoundData )
     906           0 :         return pFoundData;
     907             : 
     908           0 :     aFontname = rDefaults.getDefaultFont( aLanguageTag, DEFAULTFONT_SANS );
     909           0 :     pFoundData = ImplFindByTokenNames( aFontname );
     910           0 :     if( pFoundData )
     911           0 :         return pFoundData;
     912             : 
     913           0 :     aFontname = rDefaults.getDefaultFont( aLanguageTag, DEFAULTFONT_SERIF );
     914           0 :     pFoundData = ImplFindByTokenNames( aFontname );
     915           0 :     if( pFoundData )
     916           0 :         return pFoundData;
     917             : 
     918           0 :     aFontname = rDefaults.getDefaultFont( aLanguageTag, DEFAULTFONT_FIXED );
     919           0 :     pFoundData = ImplFindByTokenNames( aFontname );
     920           0 :     if( pFoundData )
     921           0 :         return pFoundData;
     922             : 
     923             :     // now try to find a reasonable non-symbol font
     924             : 
     925           0 :     InitMatchData();
     926             : 
     927           0 :     PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin();
     928           0 :     for(; it !=  maPhysicalFontFamilies.end(); ++it )
     929             :     {
     930           0 :         PhysicalFontFamily* pData = (*it).second;
     931           0 :         if( pData->GetMatchType() & IMPL_FONT_ATTR_SYMBOL )
     932           0 :             continue;
     933             : 
     934           0 :         pFoundData = pData;
     935           0 :         if( pData->GetMatchType() & (IMPL_FONT_ATTR_DEFAULT|IMPL_FONT_ATTR_STANDARD) )
     936           0 :             break;
     937             :     }
     938           0 :     if( pFoundData )
     939           0 :         return pFoundData;
     940             : 
     941             :     // finding any font is better than finding no font at all
     942           0 :     it = maPhysicalFontFamilies.begin();
     943           0 :     if( it !=  maPhysicalFontFamilies.end() )
     944           0 :         pFoundData = (*it).second;
     945             : 
     946           0 :     return pFoundData;
     947             : }
     948             : 
     949        6090 : PhysicalFontCollection* PhysicalFontCollection::Clone( bool bScalable, bool bEmbeddable ) const
     950             : {
     951        6090 :     PhysicalFontCollection* pClonedCollection = new PhysicalFontCollection;
     952        6090 :     pClonedCollection->mbMapNames     = mbMapNames;
     953        6090 :     pClonedCollection->mpPreMatchHook = mpPreMatchHook;
     954        6090 :     pClonedCollection->mpFallbackHook = mpFallbackHook;
     955             : 
     956             :     // TODO: clone the config-font attributes too?
     957        6090 :     pClonedCollection->mbMatchData    = false;
     958             : 
     959        6090 :     PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin();
     960      310090 :     for(; it != maPhysicalFontFamilies.end(); ++it )
     961             :     {
     962      304000 :         const PhysicalFontFamily* pFontFace = (*it).second;
     963      304000 :         pFontFace->UpdateCloneFontList( *pClonedCollection, bScalable, bEmbeddable );
     964             :     }
     965             : 
     966        6090 :     return pClonedCollection;
     967             : }
     968             : 
     969        8012 : ImplGetDevFontList* PhysicalFontCollection::GetDevFontList() const
     970             : {
     971        8012 :     ImplGetDevFontList* pGetDevFontList = new ImplGetDevFontList;
     972             : 
     973        8012 :     PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin();
     974      408212 :     for(; it != maPhysicalFontFamilies.end(); ++it )
     975             :     {
     976      400200 :         const PhysicalFontFamily* pFontFamily = (*it).second;
     977      400200 :         pFontFamily->UpdateDevFontList( *pGetDevFontList );
     978             :     }
     979             : 
     980        8012 :     return pGetDevFontList;
     981             : }
     982             : 
     983        2058 : ImplGetDevSizeList* PhysicalFontCollection::GetDevSizeList( const OUString& rFontName ) const
     984             : {
     985        2058 :     ImplGetDevSizeList* pGetDevSizeList = new ImplGetDevSizeList( rFontName );
     986             : 
     987        2058 :     PhysicalFontFamily* pFontFamily = FindFontFamily( rFontName );
     988        2058 :     if( pFontFamily != NULL )
     989             :     {
     990        2048 :         std::set<int> rHeights;
     991        2048 :         pFontFamily->GetFontHeights( rHeights );
     992             : 
     993        2048 :         std::set<int>::const_iterator it = rHeights.begin();
     994        2048 :         for(; it != rHeights.begin(); ++it )
     995        2048 :             pGetDevSizeList->Add( *it );
     996             :     }
     997             : 
     998        2058 :     return pGetDevSizeList;
     999             : }
    1000             : 
    1001       23884 : PhysicalFontFamily* PhysicalFontCollection::ImplFindByFont( FontSelectPattern& rFSD ) const
    1002             : {
    1003             :     // give up if no fonts are available
    1004       23884 :     if( !Count() )
    1005           0 :         return NULL;
    1006             : 
    1007       23884 :     bool bMultiToken = false;
    1008       23884 :     sal_Int32 nTokenPos = 0;
    1009       23884 :     OUString& aSearchName = rFSD.maSearchName; // TODO: get rid of reference
    1010             :     for(;;)
    1011             :     {
    1012       23884 :         rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
    1013       23884 :         aSearchName = rFSD.maTargetName;
    1014             : 
    1015             : #if ENABLE_GRAPHITE
    1016             :         // Until features are properly supported, they are appended to the
    1017             :         // font name, so we need to strip them off so the font is found.
    1018       23884 :         sal_Int32 nFeat = aSearchName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX);
    1019       23884 :         OUString aOrigName = rFSD.maTargetName;
    1020       23884 :         OUString aBaseFontName = aSearchName.copy( 0, (nFeat != -1) ? nFeat : aSearchName.getLength() );
    1021             : 
    1022       23884 :         if (nFeat != -1 &&
    1023           0 :             -1 != aSearchName.indexOf(grutils::GrFeatureParser::FEAT_ID_VALUE_SEPARATOR, nFeat))
    1024             :         {
    1025           0 :             aSearchName = aBaseFontName;
    1026           0 :             rFSD.maTargetName = aBaseFontName;
    1027             :         }
    1028             : 
    1029             : #endif
    1030             : 
    1031       23884 :         aSearchName = GetEnglishSearchFontName( aSearchName );
    1032       23884 :         ImplFontSubstitute( aSearchName );
    1033             :         // #114999# special emboldening for Ricoh fonts
    1034             :         // TODO: smarter check for special cases by using PreMatch infrastructure?
    1035       27596 :         if( (rFSD.GetWeight() > WEIGHT_MEDIUM) &&
    1036        3712 :             aSearchName.startsWithIgnoreAsciiCase( "hg" ) )
    1037             :         {
    1038           0 :             OUString aBoldName;
    1039           0 :             if( aSearchName.startsWithIgnoreAsciiCase( "hggothicb" ) )
    1040           0 :                 aBoldName = "hggothice";
    1041           0 :             else if( aSearchName.startsWithIgnoreAsciiCase( "hgpgothicb" ) )
    1042           0 :                 aBoldName = "hgpgothice";
    1043           0 :             else if( aSearchName.startsWithIgnoreAsciiCase( "hgminchol" ) )
    1044           0 :                 aBoldName = "hgminchob";
    1045           0 :             else if( aSearchName.startsWithIgnoreAsciiCase( "hgpminchol" ) )
    1046           0 :                 aBoldName = "hgpminchob";
    1047           0 :             else if( aSearchName.equalsIgnoreAsciiCase( "hgminchob" ) )
    1048           0 :                 aBoldName = "hgminchoe";
    1049           0 :             else if( aSearchName.equalsIgnoreAsciiCase( "hgpminchob" ) )
    1050           0 :                 aBoldName = "hgpminchoe";
    1051             : 
    1052           0 :             if( !aBoldName.isEmpty() && ImplFindBySearchName( aBoldName ) )
    1053             :             {
    1054             :                 // the other font is available => use it
    1055           0 :                 aSearchName = aBoldName;
    1056             :                 // prevent synthetic emboldening of bold version
    1057           0 :                 rFSD.SetWeight(WEIGHT_DONTKNOW);
    1058           0 :             }
    1059             :         }
    1060             : 
    1061             : #if ENABLE_GRAPHITE
    1062             :         // restore the features to make the font selection data unique
    1063       23884 :         rFSD.maTargetName = aOrigName;
    1064             : #endif
    1065             :         // check if the current font name token or its substitute is valid
    1066       23884 :         PhysicalFontFamily* pFoundData = ImplFindBySearchName( aSearchName );
    1067       23884 :         if( pFoundData )
    1068        7945 :             return pFoundData;
    1069             : 
    1070             :         // some systems provide special customization
    1071             :         // e.g. they suggest "serif" as UI-font, but this name cannot be used directly
    1072             :         //      because the system wants to map it to another font first, e.g. "Helvetica"
    1073             : #if ENABLE_GRAPHITE
    1074             :         // use the target name to search in the prematch hook
    1075       15939 :         rFSD.maTargetName = aBaseFontName;
    1076             : #endif
    1077             : 
    1078             :         // Related: fdo#49271 RTF files often contain weird-ass
    1079             :         // Win 3.1/Win95 style fontnames which attempt to put the
    1080             :         // charset encoding into the filename
    1081             :         // http://www.webcenter.ru/~kazarn/eng/fonts_ttf.htm
    1082       15939 :         OUString sStrippedName = StripScriptFromName(rFSD.maTargetName);
    1083       15939 :         if (sStrippedName != rFSD.maTargetName)
    1084             :         {
    1085          10 :             rFSD.maTargetName = sStrippedName;
    1086          10 :             aSearchName = GetEnglishSearchFontName(rFSD.maTargetName);
    1087          10 :             pFoundData = ImplFindBySearchName(aSearchName);
    1088          10 :             if( pFoundData )
    1089           0 :                 return pFoundData;
    1090             :         }
    1091             : 
    1092       15939 :         if( mpPreMatchHook )
    1093             :         {
    1094       15939 :             if( mpPreMatchHook->FindFontSubstitute( rFSD ) )
    1095       15239 :                 aSearchName = GetEnglishSearchFontName( aSearchName );
    1096             :         }
    1097             : #if ENABLE_GRAPHITE
    1098             :         // the prematch hook uses the target name to search, but we now need
    1099             :         // to restore the features to make the font selection data unique
    1100       15939 :         rFSD.maTargetName = aOrigName;
    1101             : #endif
    1102       15939 :         pFoundData = ImplFindBySearchName( aSearchName );
    1103       15939 :         if( pFoundData )
    1104       15239 :             return pFoundData;
    1105             : 
    1106             :         // break after last font name token was checked unsuccessfully
    1107         700 :         if( nTokenPos == -1)
    1108         700 :             break;
    1109           0 :         bMultiToken = true;
    1110           0 :     }
    1111             : 
    1112             :     // if the first font was not available find the next available font in
    1113             :     // the semicolon separated list of font names. A font is also considered
    1114             :     // available when there is a matching entry in the Tools->Options->Fonts
    1115             :     // dialog witho neither ALWAYS nor SCREENONLY flags set and the substitution
    1116             :     // font is available
    1117        2100 :     for( nTokenPos = 0; nTokenPos != -1; )
    1118             :     {
    1119         700 :         if( bMultiToken )
    1120             :         {
    1121           0 :             rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
    1122           0 :             aSearchName = GetEnglishSearchFontName( rFSD.maTargetName );
    1123             :         }
    1124             :         else
    1125         700 :             nTokenPos = -1;
    1126         700 :         if( mpPreMatchHook )
    1127         700 :             if( mpPreMatchHook->FindFontSubstitute( rFSD ) )
    1128           0 :                 aSearchName = GetEnglishSearchFontName( aSearchName );
    1129         700 :         ImplFontSubstitute( aSearchName );
    1130         700 :         PhysicalFontFamily* pFoundData = ImplFindBySearchName( aSearchName );
    1131         700 :         if( pFoundData )
    1132           0 :             return pFoundData;
    1133             :     }
    1134             : 
    1135             :     // if no font with a directly matching name is available use the
    1136             :     // first font name token and get its attributes to find a replacement
    1137         700 :     if ( bMultiToken )
    1138             :     {
    1139           0 :         nTokenPos = 0;
    1140           0 :         rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
    1141           0 :         aSearchName = GetEnglishSearchFontName( rFSD.maTargetName );
    1142             :     }
    1143             : 
    1144         700 :     OUString      aSearchShortName;
    1145        1400 :     OUString      aSearchFamilyName;
    1146         700 :     FontWeight  eSearchWeight   = rFSD.GetWeight();
    1147         700 :     FontWidth   eSearchWidth    = rFSD.GetWidthType();
    1148         700 :     sal_uLong   nSearchType     = 0;
    1149             :     utl::FontSubstConfiguration::getMapName( aSearchName, aSearchShortName, aSearchFamilyName,
    1150         700 :                                              eSearchWeight, eSearchWidth, nSearchType );
    1151             : 
    1152             :     // note: the search name was already translated to english (if possible)
    1153             :     // use the font's shortened name if needed
    1154         700 :     if ( aSearchShortName != aSearchName )
    1155             :     {
    1156           0 :        PhysicalFontFamily* pFoundData = ImplFindBySearchName( aSearchShortName );
    1157           0 :        if( pFoundData )
    1158             :        {
    1159             : #ifdef UNX
    1160             :             /* #96738# don't use mincho as an replacement for "MS Mincho" on X11: Mincho is
    1161             :             a korean bitmap font that is not suitable here. Use the font replacement table,
    1162             :             that automatically leads to the desired "HG Mincho Light J". Same story for
    1163             :             MS Gothic, there are thai and korean "Gothic" fonts, so we even prefer Andale */
    1164           0 :             static OUString aMS_Mincho( "msmincho" );
    1165           0 :             static OUString aMS_Gothic( "msgothic" );
    1166           0 :             if ((aSearchName != aMS_Mincho) && (aSearchName != aMS_Gothic))
    1167             :                 // TODO: add heuristic to only throw out the fake ms* fonts
    1168             : #endif
    1169             :             {
    1170           0 :                 return pFoundData;
    1171             :             }
    1172             :         }
    1173             :     }
    1174             : 
    1175             :     // use font fallback
    1176         700 :     const utl::FontNameAttr* pFontAttr = NULL;
    1177         700 :     if( !aSearchName.isEmpty() )
    1178             :     {
    1179             :         // get fallback info using FontSubstConfiguration and
    1180             :         // the target name, it's shortened name and family name in that order
    1181         700 :         const utl::FontSubstConfiguration& rFontSubst = utl::FontSubstConfiguration::get();
    1182         700 :         pFontAttr = rFontSubst.getSubstInfo( aSearchName );
    1183         700 :         if ( !pFontAttr && (aSearchShortName != aSearchName) )
    1184           0 :             pFontAttr = rFontSubst.getSubstInfo( aSearchShortName );
    1185         700 :         if ( !pFontAttr && (aSearchFamilyName != aSearchShortName) )
    1186           0 :             pFontAttr = rFontSubst.getSubstInfo( aSearchFamilyName );
    1187             : 
    1188             :         // try the font substitutions suggested by the fallback info
    1189         700 :         if( pFontAttr )
    1190             :         {
    1191         700 :             PhysicalFontFamily* pFoundData = ImplFindBySubstFontAttr( *pFontAttr );
    1192         700 :             if( pFoundData )
    1193         700 :                 return pFoundData;
    1194             :         }
    1195             :     }
    1196             : 
    1197             :     // if a target symbol font is not available use a default symbol font
    1198           0 :     if( rFSD.IsSymbolFont() )
    1199             :     {
    1200           0 :         LanguageTag aDefaultLanguageTag( OUString( "en"));
    1201           0 :         aSearchName = utl::DefaultFontConfiguration::get().getDefaultFont( aDefaultLanguageTag, DEFAULTFONT_SYMBOL );
    1202           0 :         PhysicalFontFamily* pFoundData = ImplFindByTokenNames( aSearchName );
    1203           0 :         if( pFoundData )
    1204           0 :             return pFoundData;
    1205             :     }
    1206             : 
    1207             :     // now try the other font name tokens
    1208           0 :     while( nTokenPos != -1 )
    1209             :     {
    1210           0 :         rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
    1211           0 :         if( rFSD.maTargetName.isEmpty() )
    1212           0 :             continue;
    1213             : 
    1214           0 :         aSearchName = GetEnglishSearchFontName( rFSD.maTargetName );
    1215             : 
    1216           0 :         OUString      aTempShortName;
    1217           0 :         OUString      aTempFamilyName;
    1218           0 :         sal_uLong   nTempType   = 0;
    1219           0 :         FontWeight  eTempWeight = rFSD.GetWeight();
    1220           0 :         FontWidth   eTempWidth  = WIDTH_DONTKNOW;
    1221             :         utl::FontSubstConfiguration::getMapName( aSearchName, aTempShortName, aTempFamilyName,
    1222           0 :                                                  eTempWeight, eTempWidth, nTempType );
    1223             : 
    1224             :         // use a shortend token name if available
    1225           0 :         if( aTempShortName != aSearchName )
    1226             :         {
    1227           0 :             PhysicalFontFamily* pFoundData = ImplFindBySearchName( aTempShortName );
    1228           0 :             if( pFoundData )
    1229           0 :                 return pFoundData;
    1230             :         }
    1231             : 
    1232             :         // use a font name from font fallback list to determine font attributes
    1233             :         // get fallback info using FontSubstConfiguration and
    1234             :         // the target name, it's shortened name and family name in that order
    1235           0 :         const utl::FontSubstConfiguration& rFontSubst = utl::FontSubstConfiguration::get();
    1236           0 :         const utl::FontNameAttr* pTempFontAttr = rFontSubst.getSubstInfo( aSearchName );
    1237             : 
    1238           0 :         if ( !pTempFontAttr && (aTempShortName != aSearchName) )
    1239           0 :             pTempFontAttr = rFontSubst.getSubstInfo( aTempShortName );
    1240             : 
    1241           0 :         if ( !pTempFontAttr && (aTempFamilyName != aTempShortName) )
    1242           0 :             pTempFontAttr = rFontSubst.getSubstInfo( aTempFamilyName );
    1243             : 
    1244             :         // try the font substitutions suggested by the fallback info
    1245           0 :         if( pTempFontAttr )
    1246             :         {
    1247           0 :             PhysicalFontFamily* pFoundData = ImplFindBySubstFontAttr( *pTempFontAttr );
    1248           0 :             if( pFoundData )
    1249           0 :                 return pFoundData;
    1250           0 :             if( !pFontAttr )
    1251           0 :                 pFontAttr = pTempFontAttr;
    1252             :         }
    1253           0 :     }
    1254             : 
    1255             :     // if still needed use the alias names of the installed fonts
    1256           0 :     if( mbMapNames )
    1257             :     {
    1258           0 :         PhysicalFontFamily* pFoundData = ImplFindByAliasName( rFSD.maTargetName, aSearchShortName );
    1259           0 :         if( pFoundData )
    1260           0 :             return pFoundData;
    1261             :     }
    1262             : 
    1263             :     // if still needed use the font request's attributes to find a good match
    1264           0 :     if (MsLangId::isSimplifiedChinese(rFSD.meLanguage))
    1265           0 :         nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_SC;
    1266           0 :     else if (MsLangId::isTraditionalChinese(rFSD.meLanguage))
    1267           0 :         nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_TC;
    1268           0 :     else if (MsLangId::isKorean(rFSD.meLanguage))
    1269           0 :         nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_KR;
    1270           0 :     else if (rFSD.meLanguage == LANGUAGE_JAPANESE)
    1271           0 :         nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_JP;
    1272             :     else
    1273             :     {
    1274           0 :         nSearchType |= lcl_IsCJKFont( rFSD.GetFamilyName() );
    1275           0 :         if( rFSD.IsSymbolFont() )
    1276           0 :             nSearchType |= IMPL_FONT_ATTR_SYMBOL;
    1277             :     }
    1278             : 
    1279           0 :     PhysicalFontFamily::CalcType( nSearchType, eSearchWeight, eSearchWidth, rFSD.GetFamilyType(), pFontAttr );
    1280             :     PhysicalFontFamily* pFoundData = ImplFindByAttributes( nSearchType,
    1281           0 :         eSearchWeight, eSearchWidth, rFSD.GetSlant(), aSearchFamilyName );
    1282             : 
    1283           0 :     if( pFoundData )
    1284             :     {
    1285             :         // overwrite font selection attributes using info from the typeface flags
    1286           0 :         if( (eSearchWeight >= WEIGHT_BOLD) &&
    1287           0 :             (eSearchWeight > rFSD.GetWeight()) &&
    1288           0 :             (pFoundData->GetTypeFaces() & FONT_FAMILY_BOLD) )
    1289             :         {
    1290           0 :             rFSD.SetWeight( eSearchWeight );
    1291             :         }
    1292           0 :         else if( (eSearchWeight < WEIGHT_NORMAL) &&
    1293           0 :                  (eSearchWeight < rFSD.GetWeight()) &&
    1294           0 :                  (eSearchWeight != WEIGHT_DONTKNOW) &&
    1295           0 :                  (pFoundData->GetTypeFaces() & FONT_FAMILY_LIGHT) )
    1296             :         {
    1297           0 :             rFSD.SetWeight( eSearchWeight );
    1298             :         }
    1299             : 
    1300           0 :         if( (nSearchType & IMPL_FONT_ATTR_ITALIC) &&
    1301           0 :             ((rFSD.GetSlant() == ITALIC_DONTKNOW) ||
    1302           0 :              (rFSD.GetSlant() == ITALIC_NONE)) &&
    1303           0 :             (pFoundData->GetTypeFaces() & FONT_FAMILY_ITALIC) )
    1304             :         {
    1305           0 :             rFSD.SetItalic( ITALIC_NORMAL );
    1306             :         }
    1307             :     }
    1308             :     else
    1309             :     {
    1310             :         // if still needed fall back to default fonts
    1311           0 :         pFoundData = FindDefaultFont();
    1312             :     }
    1313             : 
    1314         700 :     return pFoundData;
    1315             : }
    1316             : 
    1317             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
    1318             : 

Generated by: LCOV version 1.10