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

Generated by: LCOV version 1.11