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

Generated by: LCOV version 1.10