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