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
27#include <unotools/fontdefs.hxx>
29
33
34static ImplFontAttrs lcl_IsCJKFont( std::u16string_view rFontName )
35{
36 // Test, if Fontname includes CJK characters --> In this case we
37 // mention that it is a CJK font
38 for(size_t i = 0; i < rFontName.size(); 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
68namespace 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
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
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, u"" );
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 std::u16string_view 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.empty() && (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.size() >= 4) &&
678 (pData->GetMatchFamilyName().getLength() >= 4) &&
679 ((rSearchFamilyName.find( pData->GetMatchFamilyName() ) != std::u16string_view::npos) ||
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
899std::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
917std::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.
933const 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
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;
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
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.IsMicrosoftSymbolEncoded() )
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.IsMicrosoftSymbolEncoded() )
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: */
static ImplFontAttrs lcl_IsCJKFont(std::u16string_view rFontName)
#define MAX_GLYPHFALLBACK
void SetItalic(const FontItalic eItalic)
bool IsMicrosoftSymbolEncoded() const
FontFamily GetFamilyType() const
FontItalic GetItalic() const
void SetWeight(const FontWeight eWeight)
FontWeight GetWeight() const
const OUString & GetFamilyName() const
FontWidth GetWidthType() const
void AddFallbackForUnicode(sal_UCS4 cChar, FontWeight eWeight, const OUString &rFontName, bool bEmbolden, const ItalicMatrix &rMatrix)
bool GetFallbackForUnicode(sal_UCS4 cInChar, FontWeight eInWeight, OUString *pOutFontName, bool *pOutEmbolden, ItalicMatrix *pOutItalicMatrix) const
void IgnoreFallbackForUnicode(sal_UCS4, FontWeight eWeight, std::u16string_view rFontName)
static bool isKorean(LanguageType nLang)
static bool isTraditionalChinese(LanguageType nLang)
static bool isSimplifiedChinese(LanguageType nLang)
static bool IsFuzzing()
OUString getDefaultFont(const LanguageTag &rLanguageTag, DefaultFontType nType) const
static DefaultFontConfiguration & get()
Abstracts the concept of finding the best font to support an incomplete font.
virtual bool FindFontSubstitute(vcl::font::FontSelectPattern &, LogicalFontInstance *pLogicalFont, OUString &rMissingCodes) const =0
void SetPreMatchHook(vcl::font::PreMatchFontSubstitution *)
void Add(vcl::font::PhysicalFontFace *)
vcl::font::PhysicalFontFamily * FindFontFamily(std::u16string_view rFontName) const
vcl::font::PhysicalFontFamily * ImplFindFontFamilyBySearchName(const OUString &) const
void SetFallbackHook(vcl::font::GlyphFallbackFontSubstitution *)
vcl::font::PreMatchFontSubstitution * mpPreMatchHook
vcl::font::GlyphFallbackFontSubstitution * mpFallbackHook
vcl::font::PhysicalFontFamily * FindFontFamilyByAttributes(ImplFontAttrs nSearchType, FontWeight, FontWidth, FontItalic, std::u16string_view rSearchFamily) const
vcl::font::PhysicalFontFamily * FindFontFamilyByTokenNames(std::u16string_view rTokenStr) const
std::unique_ptr< vcl::font::PhysicalFontFaceCollection > GetFontFaceCollection() const
std::shared_ptr< PhysicalFontCollection > Clone() const
vcl::font::PhysicalFontFamily * GetGlyphFallbackFont(vcl::font::FontSelectPattern &, LogicalFontInstance *pLogicalFont, OUString &rMissingCodes, int nFallbackLevel) const
vcl::font::PhysicalFontFamily * FindOrCreateFontFamily(const OUString &rFamilyName)
vcl::font::PhysicalFontFamily * ImplFindFontFamilyBySubstFontAttr(const utl::FontNameAttr &) const
std::unique_ptr< std::array< vcl::font::PhysicalFontFamily *, MAX_GLYPHFALLBACK > > mpFallbackList
vcl::font::PhysicalFontFamily * ImplFindFontFamilyOfDefaultFont() const
abstract base class for physical font faces
void AddFontFace(PhysicalFontFace *)
void UpdateDevFontList(PhysicalFontFaceCollection &) const
void UpdateCloneFontList(PhysicalFontCollection &) const
FontTypeFaces GetTypeFaces() const
void InitMatchData(const utl::FontSubstConfiguration &, const OUString &rSearchName)
static void CalcType(ImplFontAttrs &rType, FontWeight &rWeight, FontWidth &rWidth, FontFamily eFamily, const utl::FontNameAttr *pFontAttr)
Abstracts the concept of a configured font substitution before the availability of the originally sel...
virtual bool FindFontSubstitute(vcl::font::FontSelectPattern &) const =0
float u
ImplFontAttrs
UNOTOOLS_DLLPUBLIC OUString StripScriptFromName(const OUString &rName)
UNOTOOLS_DLLPUBLIC OUString GetEnglishSearchFontName(std::u16string_view rName)
UNOTOOLS_DLLPUBLIC std::u16string_view GetNextFontToken(std::u16string_view rTokenStr, sal_Int32 &rIndex)
FontItalic
ITALIC_NORMAL
ITALIC_NONE
ITALIC_DONTKNOW
FontWidth
WIDTH_DONTKNOW
WIDTH_NORMAL
WEIGHT_BOLD
WEIGHT_NORMAL
WEIGHT_DONTKNOW
WEIGHT_MEDIUM
sal_Int32 nIndex
#define LANGUAGE_JAPANESE
std::unique_ptr< sal_Int32[]> pData
int i
FontWeight
long Long
A PhysicalFontFaceCollection is created by a PhysicalFontCollection and becomes invalid when original...
static ImplFontAttrs lcl_IsCJKFont(std::u16string_view rFontName)
const std::vector< std::pair< OUString, OUString > > aMetricCompatibleMap
static bool FindMetricCompatibleFont(FontSelectPattern &rFontSelData)
void ImplFontSubstitute(OUString &rFontName)
FontWeight Weight
ImplFontAttrs Type
::std::vector< OUString > Substitutions
sal_uInt16 sal_Unicode
sal_uInt32 sal_UCS4
Definition: vclenum.hxx:160