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