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