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 :
|