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  const OUString aSearchName;
361 
362  pFoundData = FindFontFamilyByAttributes( nSearchType,
363  eSearchWeight, eSearchWidth, eSearchSlant, aSearchName );
364 
365  if( pFoundData )
366  return pFoundData;
367  }
368 
369  return nullptr;
370 }
371 
373 {
374  // short circuit if already done
375  if( mbMatchData )
376  return;
377  mbMatchData = true;
378 
380  return;
381 
382  // calculate MatchData for all entries
384 
385  for (auto const& family : maPhysicalFontFamilies)
386  {
387  const OUString& rSearchName = family.first;
388  PhysicalFontFamily* pEntry = family.second.get();
389 
390  pEntry->InitMatchData( rFontSubst, rSearchName );
391  }
392 }
393 
395  FontWeight eSearchWeight,
396  FontWidth eSearchWidth,
397  FontItalic eSearchItalic,
398  const OUString& rSearchFamilyName ) const
399 {
400  if( (eSearchItalic != ITALIC_NONE) && (eSearchItalic != ITALIC_DONTKNOW) )
401  nSearchType |= ImplFontAttrs::Italic;
402 
403  // don't bother to match attributes if the attributes aren't worth matching
404  if( nSearchType == ImplFontAttrs::None
405  && ((eSearchWeight == WEIGHT_DONTKNOW) || (eSearchWeight == WEIGHT_NORMAL))
406  && ((eSearchWidth == WIDTH_DONTKNOW) || (eSearchWidth == WIDTH_NORMAL)) )
407  return nullptr;
408 
410  PhysicalFontFamily* pFoundData = nullptr;
411 
412  long nBestMatch = 40000;
413  ImplFontAttrs nBestType = ImplFontAttrs::None;
414 
415  for (auto const& family : maPhysicalFontFamilies)
416  {
417  PhysicalFontFamily* pData = family.second.get();
418 
419  // Get all information about the matching font
420  ImplFontAttrs nMatchType = pData->GetMatchType();
421  FontWeight eMatchWeight= pData->GetMatchWeight();
422  FontWidth eMatchWidth = pData->GetMatchWidth();
423 
424  // Calculate Match Value
425  // 1000000000
426  // 100000000
427  // 10000000 CJK, CTL, None-Latin, Symbol
428  // 1000000 FamilyName, Script, Fixed, -Special, -Decorative,
429  // Titling, Capitals, Outline, Shadow
430  // 100000 Match FamilyName, Serif, SansSerif, Italic,
431  // Width, Weight
432  // 10000 Scalable, Standard, Default,
433  // full, Normal, Knownfont,
434  // Otherstyle, +Special, +Decorative,
435  // 1000 Typewriter, Rounded, Gothic, Schollbook
436  // 100
437  long nTestMatch = 0;
438 
439  // test CJK script attributes
440  if ( nSearchType & ImplFontAttrs::CJK )
441  {
442  // Matching language
443  if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs::CJK_AllLang) )
444  nTestMatch += 10000000*3;
445  if( nMatchType & ImplFontAttrs::CJK )
446  nTestMatch += 10000000*2;
447  if( nMatchType & ImplFontAttrs::Full )
448  nTestMatch += 10000000;
449  }
450  else if ( nMatchType & ImplFontAttrs::CJK )
451  {
452  nTestMatch -= 10000000;
453  }
454 
455  // test CTL script attributes
456  if( nSearchType & ImplFontAttrs::CTL )
457  {
458  if( nMatchType & ImplFontAttrs::CTL )
459  nTestMatch += 10000000*2;
460  if( nMatchType & ImplFontAttrs::Full )
461  nTestMatch += 10000000;
462  }
463  else if ( nMatchType & ImplFontAttrs::CTL )
464  {
465  nTestMatch -= 10000000;
466  }
467 
468  // test LATIN script attributes
469  if( nSearchType & ImplFontAttrs::NoneLatin )
470  {
471  if( nMatchType & ImplFontAttrs::NoneLatin )
472  nTestMatch += 10000000*2;
473  if( nMatchType & ImplFontAttrs::Full )
474  nTestMatch += 10000000;
475  }
476 
477  // test SYMBOL attributes
478  if ( nSearchType & ImplFontAttrs::Symbol )
479  {
480  const OUString& rSearchName = family.first;
481  // prefer some special known symbol fonts
482  if ( rSearchName == "starsymbol" )
483  {
484  nTestMatch += 10000000*6+(10000*3);
485  }
486  else if ( rSearchName == "opensymbol" )
487  {
488  nTestMatch += 10000000*6;
489  }
490  else if ( rSearchName == "starbats" ||
491  rSearchName == "wingdings" ||
492  rSearchName == "monotypesorts" ||
493  rSearchName == "dingbats" ||
494  rSearchName == "zapfdingbats" )
495  {
496  nTestMatch += 10000000*5;
497  }
498  else if ( pData->GetTypeFaces() & FontTypeFaces::Symbol )
499  {
500  nTestMatch += 10000000*4;
501  }
502  else
503  {
504  if( nMatchType & ImplFontAttrs::Symbol )
505  nTestMatch += 10000000*2;
506  if( nMatchType & ImplFontAttrs::Full )
507  nTestMatch += 10000000;
508  }
509  }
511  {
512  nTestMatch -= 10000000;
513  }
514  else if ( nMatchType & ImplFontAttrs::Symbol )
515  {
516  nTestMatch -= 10000;
517  }
518 
519  // match stripped family name
520  if( !rSearchFamilyName.isEmpty() && (rSearchFamilyName == pData->GetMatchFamilyName()) )
521  {
522  nTestMatch += 1000000*3;
523  }
524 
525  // match ALLSCRIPT? attribute
526  if( nSearchType & ImplFontAttrs::AllScript )
527  {
528  if( nMatchType & ImplFontAttrs::AllScript )
529  {
530  nTestMatch += 1000000*2;
531  }
532  if( nSearchType & ImplFontAttrs::AllSubscript )
533  {
534  if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs::AllSubscript) )
535  nTestMatch += 1000000*2;
536  if( ImplFontAttrs::None != ((nSearchType ^ nMatchType) & ImplFontAttrs::BrushScript) )
537  nTestMatch -= 1000000;
538  }
539  }
540  else if( nMatchType & ImplFontAttrs::AllScript )
541  {
542  nTestMatch -= 1000000;
543  }
544 
545  // test MONOSPACE+TYPEWRITER attributes
546  if( nSearchType & ImplFontAttrs::Fixed )
547  {
548  if( nMatchType & ImplFontAttrs::Fixed )
549  nTestMatch += 1000000*2;
550  // a typewriter attribute is even better
551  if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs::Typewriter) )
552  nTestMatch += 10000*2;
553  }
554  else if( nMatchType & ImplFontAttrs::Fixed )
555  {
556  nTestMatch -= 1000000;
557  }
558 
559  // test SPECIAL attribute
560  if( nSearchType & ImplFontAttrs::Special )
561  {
562  if( nMatchType & ImplFontAttrs::Special )
563  {
564  nTestMatch += 10000;
565  }
566  else if( !(nSearchType & ImplFontAttrs::AllSerifStyle) )
567  {
568  if( nMatchType & ImplFontAttrs::Serif )
569  {
570  nTestMatch += 1000*2;
571  }
572  else if( nMatchType & ImplFontAttrs::SansSerif )
573  {
574  nTestMatch += 1000;
575  }
576  }
577  }
578  else if( (nMatchType & ImplFontAttrs::Special) && !(nSearchType & ImplFontAttrs::Symbol) )
579  {
580  nTestMatch -= 1000000;
581  }
582 
583  // test DECORATIVE attribute
584  if( nSearchType & ImplFontAttrs::Decorative )
585  {
586  if( nMatchType & ImplFontAttrs::Decorative )
587  {
588  nTestMatch += 10000;
589  }
590  else if( !(nSearchType & ImplFontAttrs::AllSerifStyle) )
591  {
592  if( nMatchType & ImplFontAttrs::Serif )
593  nTestMatch += 1000*2;
594  else if ( nMatchType & ImplFontAttrs::SansSerif )
595  nTestMatch += 1000;
596  }
597  }
598  else if( nMatchType & ImplFontAttrs::Decorative )
599  {
600  nTestMatch -= 1000000;
601  }
602 
603  // test TITLE+CAPITALS attributes
604  if( nSearchType & (ImplFontAttrs::Titling | ImplFontAttrs::Capitals) )
605  {
606  if( nMatchType & (ImplFontAttrs::Titling | ImplFontAttrs::Capitals) )
607  {
608  nTestMatch += 1000000*2;
609  }
610  if( ImplFontAttrs::None == ((nSearchType^nMatchType) & ImplFontAttrs(ImplFontAttrs::Titling | ImplFontAttrs::Capitals)))
611  {
612  nTestMatch += 1000000;
613  }
614  else if( (nMatchType & (ImplFontAttrs::Titling | ImplFontAttrs::Capitals)) &&
615  (nMatchType & (ImplFontAttrs::Standard | ImplFontAttrs::Default)) )
616  {
617  nTestMatch += 1000000;
618  }
619  }
620  else if( nMatchType & (ImplFontAttrs::Titling | ImplFontAttrs::Capitals) )
621  {
622  nTestMatch -= 1000000;
623  }
624 
625  // test OUTLINE+SHADOW attributes
626  if( nSearchType & (ImplFontAttrs::Outline | ImplFontAttrs::Shadow) )
627  {
628  if( nMatchType & (ImplFontAttrs::Outline | ImplFontAttrs::Shadow) )
629  {
630  nTestMatch += 1000000*2;
631  }
632  if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs(ImplFontAttrs::Outline | ImplFontAttrs::Shadow)) )
633  {
634  nTestMatch += 1000000;
635  }
636  else if( (nMatchType & (ImplFontAttrs::Outline | ImplFontAttrs::Shadow)) &&
637  (nMatchType & (ImplFontAttrs::Standard | ImplFontAttrs::Default)) )
638  {
639  nTestMatch += 1000000;
640  }
641  }
642  else if ( nMatchType & (ImplFontAttrs::Outline | ImplFontAttrs::Shadow) )
643  {
644  nTestMatch -= 1000000;
645  }
646 
647  // test font name substrings
648  // TODO: calculate name matching score using e.g. Levenstein distance
649  if( (rSearchFamilyName.getLength() >= 4) &&
650  (pData->GetMatchFamilyName().getLength() >= 4) &&
651  ((rSearchFamilyName.indexOf( pData->GetMatchFamilyName() ) != -1) ||
652  (pData->GetMatchFamilyName().indexOf( rSearchFamilyName ) != -1)) )
653  {
654  nTestMatch += 5000;
655  }
656  // test SERIF attribute
657  if( nSearchType & ImplFontAttrs::Serif )
658  {
659  if( nMatchType & ImplFontAttrs::Serif )
660  nTestMatch += 1000000*2;
661  else if( nMatchType & ImplFontAttrs::SansSerif )
662  nTestMatch -= 1000000;
663  }
664 
665  // test SANSERIF attribute
666  if( nSearchType & ImplFontAttrs::SansSerif )
667  {
668  if( nMatchType & ImplFontAttrs::SansSerif )
669  nTestMatch += 1000000;
670  else if ( nMatchType & ImplFontAttrs::Serif )
671  nTestMatch -= 1000000;
672  }
673 
674  // test ITALIC attribute
675  if( nSearchType & ImplFontAttrs::Italic )
676  {
677  if( pData->GetTypeFaces() & FontTypeFaces::Italic )
678  nTestMatch += 1000000*3;
679  if( nMatchType & ImplFontAttrs::Italic )
680  nTestMatch += 1000000;
681  }
682  else if( !(nSearchType & ImplFontAttrs::AllScript) &&
683  ((nMatchType & ImplFontAttrs::Italic) ||
684  !(pData->GetTypeFaces() & FontTypeFaces::NoneItalic)) )
685  {
686  nTestMatch -= 1000000*2;
687  }
688 
689  // test WIDTH attribute
690  if( (eSearchWidth != WIDTH_DONTKNOW) && (eSearchWidth != WIDTH_NORMAL) )
691  {
692  if( eSearchWidth < WIDTH_NORMAL )
693  {
694  if( eSearchWidth == eMatchWidth )
695  nTestMatch += 1000000*3;
696  else if( (eMatchWidth < WIDTH_NORMAL) && (eMatchWidth != WIDTH_DONTKNOW) )
697  nTestMatch += 1000000;
698  }
699  else
700  {
701  if( eSearchWidth == eMatchWidth )
702  nTestMatch += 1000000*3;
703  else if( eMatchWidth > WIDTH_NORMAL )
704  nTestMatch += 1000000;
705  }
706  }
707  else if( (eMatchWidth != WIDTH_DONTKNOW) && (eMatchWidth != WIDTH_NORMAL) )
708  {
709  nTestMatch -= 1000000;
710  }
711 
712  // test WEIGHT attribute
713  if( (eSearchWeight != WEIGHT_DONTKNOW) &&
714  (eSearchWeight != WEIGHT_NORMAL) &&
715  (eSearchWeight != WEIGHT_MEDIUM) )
716  {
717  if( eSearchWeight < WEIGHT_NORMAL )
718  {
719  if( pData->GetTypeFaces() & FontTypeFaces::Light )
720  nTestMatch += 1000000;
721  if( (eMatchWeight < WEIGHT_NORMAL) && (eMatchWeight != WEIGHT_DONTKNOW) )
722  nTestMatch += 1000000;
723  }
724  else
725  {
726  if( pData->GetTypeFaces() & FontTypeFaces::Bold )
727  nTestMatch += 1000000;
728  if( eMatchWeight > WEIGHT_BOLD )
729  nTestMatch += 1000000;
730  }
731  }
732  else if( ((eMatchWeight != WEIGHT_DONTKNOW) &&
733  (eMatchWeight != WEIGHT_NORMAL) &&
734  (eMatchWeight != WEIGHT_MEDIUM)) ||
735  !(pData->GetTypeFaces() & FontTypeFaces::Normal) )
736  {
737  nTestMatch -= 1000000;
738  }
739 
740  // prefer scalable fonts
741  if( pData->GetTypeFaces() & FontTypeFaces::Scalable )
742  nTestMatch += 10000*4;
743  else
744  nTestMatch -= 10000*4;
745 
746  // test STANDARD+DEFAULT+FULL+NORMAL attributes
747  if( nMatchType & ImplFontAttrs::Standard )
748  nTestMatch += 10000*2;
749  if( nMatchType & ImplFontAttrs::Default )
750  nTestMatch += 10000;
751  if( nMatchType & ImplFontAttrs::Full )
752  nTestMatch += 10000;
753  if( nMatchType & ImplFontAttrs::Normal )
754  nTestMatch += 10000;
755 
756  // test OTHERSTYLE attribute
757  if( ((nSearchType ^ nMatchType) & ImplFontAttrs::OtherStyle) != ImplFontAttrs::None )
758  {
759  nTestMatch -= 10000;
760  }
761 
762  // test ROUNDED attribute
763  if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs::Rounded) )
764  nTestMatch += 1000;
765 
766  // test TYPEWRITER attribute
767  if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs::Typewriter) )
768  nTestMatch += 1000;
769 
770  // test GOTHIC attribute
771  if( nSearchType & ImplFontAttrs::Gothic )
772  {
773  if( nMatchType & ImplFontAttrs::Gothic )
774  nTestMatch += 1000*3;
775  if( nMatchType & ImplFontAttrs::SansSerif )
776  nTestMatch += 1000*2;
777  }
778 
779  // test SCHOOLBOOK attribute
780  if( nSearchType & ImplFontAttrs::Schoolbook )
781  {
782  if( nMatchType & ImplFontAttrs::Schoolbook )
783  nTestMatch += 1000*3;
784  if( nMatchType & ImplFontAttrs::Serif )
785  nTestMatch += 1000*2;
786  }
787 
788  // compare with best matching font yet
789  if ( nTestMatch > nBestMatch )
790  {
791  pFoundData = pData;
792  nBestMatch = nTestMatch;
793  nBestType = nMatchType;
794  }
795  else if( nTestMatch == nBestMatch )
796  {
797  // some fonts are more suitable defaults
798  if( nMatchType & ImplFontAttrs::Default )
799  {
800  pFoundData = pData;
801  nBestType = nMatchType;
802  }
803  else if( (nMatchType & ImplFontAttrs::Standard) &&
804  !(nBestType & ImplFontAttrs::Default) )
805  {
806  pFoundData = pData;
807  nBestType = nMatchType;
808  }
809  }
810  }
811 
812  return pFoundData;
813 }
814 
816 {
817  // try to find one of the default fonts of the
818  // UNICODE, SANSSERIF, SERIF or FIXED default font lists
819  PhysicalFontFamily* pFoundData = nullptr;
821  {
823  LanguageTag aLanguageTag("en");
824  OUString aFontname = rDefaults.getDefaultFont( aLanguageTag, DefaultFontType::SANS_UNICODE );
825  pFoundData = FindFontFamilyByTokenNames( aFontname );
826 
827  if( pFoundData )
828  return pFoundData;
829 
830  aFontname = rDefaults.getDefaultFont( aLanguageTag, DefaultFontType::SANS );
831  pFoundData = FindFontFamilyByTokenNames( aFontname );
832  if( pFoundData )
833  return pFoundData;
834 
835  aFontname = rDefaults.getDefaultFont( aLanguageTag, DefaultFontType::SERIF );
836  pFoundData = FindFontFamilyByTokenNames( aFontname );
837  if( pFoundData )
838  return pFoundData;
839 
840  aFontname = rDefaults.getDefaultFont( aLanguageTag, DefaultFontType::FIXED );
841  pFoundData = FindFontFamilyByTokenNames( aFontname );
842  if( pFoundData )
843  return pFoundData;
844  }
845 
846  // now try to find a reasonable non-symbol font
847 
849 
850  for (auto const& family : maPhysicalFontFamilies)
851  {
852  PhysicalFontFamily* pData = family.second.get();
853  if( pData->GetMatchType() & ImplFontAttrs::Symbol )
854  continue;
855 
856  pFoundData = pData;
857  if( pData->GetMatchType() & (ImplFontAttrs::Default|ImplFontAttrs::Standard) )
858  break;
859  }
860  if( pFoundData )
861  return pFoundData;
862 
863  // finding any font is better than finding no font at all
864  auto it = maPhysicalFontFamilies.begin();
865  if( it != maPhysicalFontFamilies.end() )
866  pFoundData = (*it).second.get();
867 
868  return pFoundData;
869 }
870 
871 std::shared_ptr<PhysicalFontCollection> PhysicalFontCollection::Clone() const
872 {
873  std::shared_ptr<PhysicalFontCollection> xClonedCollection(new PhysicalFontCollection);
874  xClonedCollection->mpPreMatchHook = mpPreMatchHook;
875  xClonedCollection->mpFallbackHook = mpFallbackHook;
876 
877  // TODO: clone the config-font attributes too?
878  xClonedCollection->mbMatchData = false;
879 
880  for (auto const& family : maPhysicalFontFamilies)
881  {
882  const PhysicalFontFamily* pFontFace = family.second.get();
883  pFontFace->UpdateCloneFontList(*xClonedCollection);
884  }
885 
886  return xClonedCollection;
887 }
888 
889 std::unique_ptr<ImplDeviceFontList> PhysicalFontCollection::GetDeviceFontList() const
890 {
891  std::unique_ptr<ImplDeviceFontList> pDeviceFontList(new ImplDeviceFontList);
892 
893  for (auto const& family : maPhysicalFontFamilies)
894  {
895  const PhysicalFontFamily* pFontFamily = family.second.get();
896  pFontFamily->UpdateDevFontList( *pDeviceFontList );
897  }
898 
899  return pDeviceFontList;
900 }
901 
902 std::unique_ptr<ImplDeviceFontSizeList> PhysicalFontCollection::GetDeviceFontSizeList( const OUString& rFontName ) const
903 {
904  std::unique_ptr<ImplDeviceFontSizeList> pDeviceFontSizeList(new ImplDeviceFontSizeList);
905 
906  PhysicalFontFamily* pFontFamily = FindFontFamily( rFontName );
907  if( pFontFamily != nullptr )
908  {
909  std::set<int> rHeights;
910  pFontFamily->GetFontHeights( rHeights );
911 
912  for( const auto& rHeight : rHeights )
913  pDeviceFontSizeList->Add( rHeight );
914  }
915 
916  return pDeviceFontSizeList;
917 }
918 
919 // These are the metric-compatible replacement fonts that are bundled with
920 // LibreOffice, we prefer them over generic substitutions that might be
921 // provided by the system.
922 static const std::vector<std::pair<OUString, OUString>> aMetricCompatibleMap =
923 {
924  { "Times New Roman", "Liberation Serif" },
925  { "Arial", "Liberation Sans" },
926  { "Arial Narrow", "Liberation Sans Narrow" },
927  { "Courier New", "Liberation Mono" },
928  { "Cambria", "Caladea" },
929  { "Calibri", "Carlito" },
930 };
931 
932 static bool FindMetricCompatibleFont(FontSelectPattern& rFontSelData)
933 {
934  for (const auto& aSub : aMetricCompatibleMap)
935  {
936  if (rFontSelData.maSearchName == GetEnglishSearchFontName(aSub.first))
937  {
938  rFontSelData.maSearchName = aSub.second;
939  return true;
940  }
941  }
942 
943  return false;
944 }
945 
947 {
948  // give up if no fonts are available
949  if( !Count() )
950  return nullptr;
951 
952  if (getenv("SAL_NO_FONT_LOOKUP") != nullptr)
953  {
954  // Hard code the use of Liberation Sans and skip font search.
955  sal_Int32 nIndex = 0;
956  rFSD.maTargetName = GetNextFontToken(rFSD.GetFamilyName(), nIndex);
957  rFSD.maSearchName = "liberationsans";
959  assert(pFont);
960  return pFont;
961  }
962 
963  bool bMultiToken = false;
964  sal_Int32 nTokenPos = 0;
965  OUString& aSearchName = rFSD.maSearchName; // TODO: get rid of reference
966  for(;;)
967  {
968  rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
969  aSearchName = rFSD.maTargetName;
970 
971  // Until features are properly supported, they are appended to the
972  // font name, so we need to strip them off so the font is found.
973  sal_Int32 nFeat = aSearchName.indexOf(FontSelectPattern::FEAT_PREFIX);
974  OUString aOrigName = rFSD.maTargetName;
975  OUString aBaseFontName = aSearchName.copy( 0, (nFeat != -1) ? nFeat : aSearchName.getLength() );
976 
977  if (nFeat != -1)
978  {
979  aSearchName = aBaseFontName;
980  rFSD.maTargetName = aBaseFontName;
981  }
982 
983  aSearchName = GetEnglishSearchFontName( aSearchName );
984  ImplFontSubstitute( aSearchName );
985  // #114999# special emboldening for Ricoh fonts
986  // TODO: smarter check for special cases by using PreMatch infrastructure?
987  if( (rFSD.GetWeight() > WEIGHT_MEDIUM) &&
988  aSearchName.startsWithIgnoreAsciiCase( "hg" ) )
989  {
990  OUString aBoldName;
991  if( aSearchName.startsWithIgnoreAsciiCase( "hggothicb" ) )
992  aBoldName = "hggothice";
993  else if( aSearchName.startsWithIgnoreAsciiCase( "hgpgothicb" ) )
994  aBoldName = "hgpgothice";
995  else if( aSearchName.startsWithIgnoreAsciiCase( "hgminchol" ) )
996  aBoldName = "hgminchob";
997  else if( aSearchName.startsWithIgnoreAsciiCase( "hgpminchol" ) )
998  aBoldName = "hgpminchob";
999  else if( aSearchName.equalsIgnoreAsciiCase( "hgminchob" ) )
1000  aBoldName = "hgminchoe";
1001  else if( aSearchName.equalsIgnoreAsciiCase( "hgpminchob" ) )
1002  aBoldName = "hgpminchoe";
1003 
1004  if( !aBoldName.isEmpty() && ImplFindFontFamilyBySearchName( aBoldName ) )
1005  {
1006  // the other font is available => use it
1007  aSearchName = aBoldName;
1008  // prevent synthetic emboldening of bold version
1009  rFSD.SetWeight(WEIGHT_DONTKNOW);
1010  }
1011  }
1012 
1013  // restore the features to make the font selection data unique
1014  rFSD.maTargetName = aOrigName;
1015 
1016  // check if the current font name token or its substitute is valid
1017  PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySearchName( aSearchName );
1018  if( pFoundData )
1019  return pFoundData;
1020 
1021  // some systems provide special customization
1022  // e.g. they suggest "serif" as UI-font, but this name cannot be used directly
1023  // because the system wants to map it to another font first, e.g. "Helvetica"
1024 
1025  // use the target name to search in the prematch hook
1026  rFSD.maTargetName = aBaseFontName;
1027 
1028  // Related: fdo#49271 RTF files often contain weird-ass
1029  // Win 3.1/Win95 style fontnames which attempt to put the
1030  // charset encoding into the filename
1031  // http://www.webcenter.ru/~kazarn/eng/fonts_ttf.htm
1032  OUString sStrippedName = StripScriptFromName(rFSD.maTargetName);
1033  if (sStrippedName != rFSD.maTargetName)
1034  {
1035  rFSD.maTargetName = sStrippedName;
1036  aSearchName = GetEnglishSearchFontName(rFSD.maTargetName);
1037  pFoundData = ImplFindFontFamilyBySearchName(aSearchName);
1038  if( pFoundData )
1039  return pFoundData;
1040  }
1041 
1042  if (FindMetricCompatibleFont(rFSD) ||
1044  {
1045  aSearchName = GetEnglishSearchFontName(aSearchName);
1046  }
1047 
1048  // the prematch hook uses the target name to search, but we now need
1049  // to restore the features to make the font selection data unique
1050  rFSD.maTargetName = aOrigName;
1051 
1052  pFoundData = ImplFindFontFamilyBySearchName( aSearchName );
1053  if( pFoundData )
1054  return pFoundData;
1055 
1056  // break after last font name token was checked unsuccessfully
1057  if( nTokenPos == -1)
1058  break;
1059  bMultiToken = true;
1060  }
1061 
1062  // if the first font was not available find the next available font in
1063  // the semicolon separated list of font names. A font is also considered
1064  // available when there is a matching entry in the Tools->Options->Fonts
1065  // dialog with neither ALWAYS nor SCREENONLY flags set and the substitution
1066  // font is available
1067  for( nTokenPos = 0; nTokenPos != -1; )
1068  {
1069  if( bMultiToken )
1070  {
1071  rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
1072  aSearchName = GetEnglishSearchFontName( rFSD.maTargetName );
1073  }
1074  else
1075  nTokenPos = -1;
1076  if (FindMetricCompatibleFont(rFSD) ||
1078  {
1079  aSearchName = GetEnglishSearchFontName( aSearchName );
1080  }
1081  ImplFontSubstitute( aSearchName );
1082  PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySearchName( aSearchName );
1083  if( pFoundData )
1084  return pFoundData;
1085  }
1086 
1087  // if no font with a directly matching name is available use the
1088  // first font name token and get its attributes to find a replacement
1089  if ( bMultiToken )
1090  {
1091  nTokenPos = 0;
1092  rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
1093  aSearchName = GetEnglishSearchFontName( rFSD.maTargetName );
1094  }
1095 
1096  OUString aSearchShortName;
1097  OUString aSearchFamilyName;
1098  FontWeight eSearchWeight = rFSD.GetWeight();
1099  FontWidth eSearchWidth = rFSD.GetWidthType();
1100  ImplFontAttrs nSearchType = ImplFontAttrs::None;
1101  utl::FontSubstConfiguration::getMapName( aSearchName, aSearchShortName, aSearchFamilyName,
1102  eSearchWeight, eSearchWidth, nSearchType );
1103 
1104  // note: the search name was already translated to english (if possible)
1105  // use the font's shortened name if needed
1106  if ( aSearchShortName != aSearchName )
1107  {
1108  PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySearchName( aSearchShortName );
1109  if( pFoundData )
1110  {
1111 #ifdef UNX
1112  /* #96738# don't use mincho as a replacement for "MS Mincho" on X11: Mincho is
1113  a korean bitmap font that is not suitable here. Use the font replacement table,
1114  that automatically leads to the desired "HG Mincho Light J". Same story for
1115  MS Gothic, there are thai and korean "Gothic" fonts, so we even prefer Andale */
1116  if ((aSearchName != "msmincho") && (aSearchName != "msgothic"))
1117  // TODO: add heuristic to only throw out the fake ms* fonts
1118 #endif
1119  {
1120  return pFoundData;
1121  }
1122  }
1123  }
1124 
1125  // use font fallback
1126  const utl::FontNameAttr* pFontAttr = nullptr;
1127  if (!aSearchName.isEmpty() && !utl::ConfigManager::IsFuzzing())
1128  {
1129  // get fallback info using FontSubstConfiguration and
1130  // the target name, it's shortened name and family name in that order
1132  pFontAttr = rFontSubst.getSubstInfo( aSearchName );
1133  if ( !pFontAttr && (aSearchShortName != aSearchName) )
1134  pFontAttr = rFontSubst.getSubstInfo( aSearchShortName );
1135  if ( !pFontAttr && (aSearchFamilyName != aSearchShortName) )
1136  pFontAttr = rFontSubst.getSubstInfo( aSearchFamilyName );
1137 
1138  // try the font substitutions suggested by the fallback info
1139  if( pFontAttr )
1140  {
1141  PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySubstFontAttr( *pFontAttr );
1142  if( pFoundData )
1143  return pFoundData;
1144  }
1145  }
1146 
1147  // if a target symbol font is not available use a default symbol font
1148  if( rFSD.IsSymbolFont() )
1149  {
1150  LanguageTag aDefaultLanguageTag("en");
1152  aSearchName = "OpenSymbol";
1153  else
1154  aSearchName = utl::DefaultFontConfiguration::get().getDefaultFont( aDefaultLanguageTag, DefaultFontType::SYMBOL );
1155  PhysicalFontFamily* pFoundData = FindFontFamilyByTokenNames( aSearchName );
1156  if( pFoundData )
1157  return pFoundData;
1158  }
1159 
1160  // now try the other font name tokens
1161  while( nTokenPos != -1 )
1162  {
1163  rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
1164  if( rFSD.maTargetName.isEmpty() )
1165  continue;
1166 
1167  aSearchName = GetEnglishSearchFontName( rFSD.maTargetName );
1168 
1169  OUString aTempShortName;
1170  OUString aTempFamilyName;
1171  ImplFontAttrs nTempType = ImplFontAttrs::None;
1172  FontWeight eTempWeight = rFSD.GetWeight();
1173  FontWidth eTempWidth = WIDTH_DONTKNOW;
1174  utl::FontSubstConfiguration::getMapName( aSearchName, aTempShortName, aTempFamilyName,
1175  eTempWeight, eTempWidth, nTempType );
1176 
1177  // use a shortened token name if available
1178  if( aTempShortName != aSearchName )
1179  {
1180  PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySearchName( aTempShortName );
1181  if( pFoundData )
1182  return pFoundData;
1183  }
1184 
1185  const utl::FontNameAttr* pTempFontAttr = nullptr;
1187  {
1188  // use a font name from font fallback list to determine font attributes
1189  // get fallback info using FontSubstConfiguration and
1190  // the target name, it's shortened name and family name in that order
1192  pTempFontAttr = rFontSubst.getSubstInfo( aSearchName );
1193 
1194  if ( !pTempFontAttr && (aTempShortName != aSearchName) )
1195  pTempFontAttr = rFontSubst.getSubstInfo( aTempShortName );
1196 
1197  if ( !pTempFontAttr && (aTempFamilyName != aTempShortName) )
1198  pTempFontAttr = rFontSubst.getSubstInfo( aTempFamilyName );
1199  }
1200 
1201  // try the font substitutions suggested by the fallback info
1202  if( pTempFontAttr )
1203  {
1204  PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySubstFontAttr( *pTempFontAttr );
1205  if( pFoundData )
1206  return pFoundData;
1207  if( !pFontAttr )
1208  pFontAttr = pTempFontAttr;
1209  }
1210  }
1211 
1212  // if still needed use the font request's attributes to find a good match
1214  nSearchType |= ImplFontAttrs::CJK | ImplFontAttrs::CJK_SC;
1216  nSearchType |= ImplFontAttrs::CJK | ImplFontAttrs::CJK_TC;
1217  else if (MsLangId::isKorean(rFSD.meLanguage))
1218  nSearchType |= ImplFontAttrs::CJK | ImplFontAttrs::CJK_KR;
1219  else if (rFSD.meLanguage == LANGUAGE_JAPANESE)
1220  nSearchType |= ImplFontAttrs::CJK | ImplFontAttrs::CJK_JP;
1221  else
1222  {
1223  nSearchType |= lcl_IsCJKFont( rFSD.GetFamilyName() );
1224  if( rFSD.IsSymbolFont() )
1225  nSearchType |= ImplFontAttrs::Symbol;
1226  }
1227 
1228  PhysicalFontFamily::CalcType( nSearchType, eSearchWeight, eSearchWidth, rFSD.GetFamilyType(), pFontAttr );
1229  PhysicalFontFamily* pFoundData = FindFontFamilyByAttributes( nSearchType,
1230  eSearchWeight, eSearchWidth, rFSD.GetItalic(), aSearchFamilyName );
1231 
1232  if( pFoundData )
1233  {
1234  // overwrite font selection attributes using info from the typeface flags
1235  if( (eSearchWeight >= WEIGHT_BOLD) &&
1236  (eSearchWeight > rFSD.GetWeight()) &&
1237  (pFoundData->GetTypeFaces() & FontTypeFaces::Bold) )
1238  {
1239  rFSD.SetWeight( eSearchWeight );
1240  }
1241  else if( (eSearchWeight < WEIGHT_NORMAL) &&
1242  (eSearchWeight < rFSD.GetWeight()) &&
1243  (eSearchWeight != WEIGHT_DONTKNOW) &&
1244  (pFoundData->GetTypeFaces() & FontTypeFaces::Light) )
1245  {
1246  rFSD.SetWeight( eSearchWeight );
1247  }
1248 
1249  if( (nSearchType & ImplFontAttrs::Italic) &&
1250  ((rFSD.GetItalic() == ITALIC_DONTKNOW) ||
1251  (rFSD.GetItalic() == ITALIC_NONE)) &&
1252  (pFoundData->GetTypeFaces() & FontTypeFaces::Italic) )
1253  {
1254  rFSD.SetItalic( ITALIC_NORMAL );
1255  }
1256  }
1257  else
1258  {
1259  // if still needed fall back to default fonts
1260  pFoundData = ImplFindFontFamilyOfDefaultFont();
1261  }
1262 
1263  return pFoundData;
1264 }
1265 
1266 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1267 
void Add(PhysicalFontFace *)
PhysicalFontFamily * FindOrCreateFontFamily(const OUString &rFamilyName)
ImplFontAttrs Type
std::unique_ptr< ImplDeviceFontSizeList > GetDeviceFontSizeList(const OUString &rFontName) const
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
const FontNameAttr * getSubstInfo(const OUString &rFontName) 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
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
static void getMapName(const OUString &rOrgName, OUString &rShortName, OUString &rFamilyName, FontWeight &rWeight, FontWidth &rWidth, ImplFontAttrs &rType)
WEIGHT_DONTKNOW
FontFamily GetFamilyType() const
void GetFontHeights(std::set< int > &rHeights) const
static FontSubstConfiguration & get()
FontWeight Weight
void SetWeight(const FontWeight eWeight)
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)
int i
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
static 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)