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