Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
font-factory.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
/*
5 * Authors:
6 * fred
7 * bulia byak <buliabyak@users.sf.net>
8 *
9 * Copyright (C) 2018 Authors
10 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
11 */
12
13#include <memory>
14#include <pango/pango-font.h>
15#include <pango/pango-fontmap.h>
16#include <pangomm/fontdescription.h>
17#include <pangomm/fontfamily.h>
18#include <pangomm/fontmap.h>
19#include <vector>
21#ifdef HAVE_CONFIG_H
22#include "config.h" // only include where actually required!
23#endif
24
25#ifndef PANGO_ENABLE_ENGINE
26#define PANGO_ENABLE_ENGINE
27#endif
28
29#include <unordered_map>
30
31#include <glibmm/i18n.h>
32
33#include <fontconfig/fontconfig.h>
34
35#include <pango/pangofc-fontmap.h>
36#include <pango/pangoft2.h>
37#include <pango/pango-ot.h>
38
39#include "io/sys.h"
40#include "io/resource.h"
41
45
46#include "util/statics.h"
47
48#ifdef _WIN32
49#undef NOGDI
50#include <glibmm.h>
51#include <windows.h>
52#endif
53
54// User must free return value.
56{
57 PangoFontDescription *descr = pango_font_description_new();
58
59 pango_font_description_set_family(descr, style->font_family.value());
60
61 // This duplicates Layout::EnumConversionItem... perhaps we can share code?
62 switch (style->font_style.computed) {
64 pango_font_description_set_style(descr, PANGO_STYLE_ITALIC);
65 break;
66
68 pango_font_description_set_style(descr, PANGO_STYLE_OBLIQUE);
69 break;
70
72 default:
73 pango_font_description_set_style(descr, PANGO_STYLE_NORMAL);
74 break;
75 }
76
77 switch (style->font_weight.computed) {
79 pango_font_description_set_weight(descr, PANGO_WEIGHT_THIN);
80 break;
81
83 pango_font_description_set_weight(descr, PANGO_WEIGHT_ULTRALIGHT);
84 break;
85
87 pango_font_description_set_weight(descr, PANGO_WEIGHT_LIGHT);
88 break;
89
92 pango_font_description_set_weight(descr, PANGO_WEIGHT_NORMAL);
93 break;
94
96 pango_font_description_set_weight(descr, PANGO_WEIGHT_MEDIUM);
97 break;
98
100 pango_font_description_set_weight(descr, PANGO_WEIGHT_SEMIBOLD);
101 break;
102
105 pango_font_description_set_weight(descr, PANGO_WEIGHT_BOLD);
106 break;
107
109 pango_font_description_set_weight(descr, PANGO_WEIGHT_ULTRABOLD);
110 break;
111
113 pango_font_description_set_weight(descr, PANGO_WEIGHT_HEAVY);
114 break;
115
118 default:
119 if (style->font_weight.computed > 0 && style->font_weight.computed <= 1000) {
120 pango_font_description_set_weight(descr, static_cast<PangoWeight>(style->font_weight.computed));
121 }
122 else {
123 g_warning("FaceFromStyle: Unrecognized font_weight.computed value");
124 pango_font_description_set_weight(descr, PANGO_WEIGHT_NORMAL);
125 }
126 break;
127 }
128 // PANGO_WIEGHT_ULTRAHEAVY not used (not CSS2)
129
130 switch (style->font_stretch.computed) {
132 pango_font_description_set_stretch(descr, PANGO_STRETCH_ULTRA_CONDENSED);
133 break;
134
136 pango_font_description_set_stretch(descr, PANGO_STRETCH_EXTRA_CONDENSED);
137 break;
138
140 pango_font_description_set_stretch(descr, PANGO_STRETCH_CONDENSED);
141 break;
142
144 pango_font_description_set_stretch(descr, PANGO_STRETCH_SEMI_CONDENSED);
145 break;
146
148 pango_font_description_set_stretch(descr, PANGO_STRETCH_NORMAL);
149 break;
150
152 pango_font_description_set_stretch(descr, PANGO_STRETCH_SEMI_EXPANDED);
153 break;
154
156 pango_font_description_set_stretch(descr, PANGO_STRETCH_EXPANDED);
157 break;
158
160 pango_font_description_set_stretch(descr, PANGO_STRETCH_EXTRA_EXPANDED);
161 break;
162
164 pango_font_description_set_stretch(descr, PANGO_STRETCH_ULTRA_EXPANDED);
165
168 default:
169 g_warning("FaceFromStyle: Unrecognized font_stretch.computed value");
170 pango_font_description_set_stretch(descr, PANGO_STRETCH_NORMAL);
171 break;
172 }
173
174 switch (style->font_variant.computed) {
176 pango_font_description_set_variant(descr, PANGO_VARIANT_SMALL_CAPS);
177 break;
178
180 default:
181 pango_font_description_set_variant(descr, PANGO_VARIANT_NORMAL);
182 break;
183 }
184
185 // Check if not empty as Pango will add @ to string even if empty (bug in Pango?).
186 if (!style->font_variation_settings.axes.empty()) {
187 pango_font_description_set_variations(descr, style->font_variation_settings.toString().c_str());
188 }
189
190 return descr;
191}
192
194
195static void noop(...) {}
196//#define PANGO_DEBUG g_print
197#define PANGO_DEBUG noop
198
200// the substitute function to tell fontconfig to enforce outline fonts
201static void FactorySubstituteFunc(FcPattern *pattern, gpointer /*data*/)
202{
203 FcPatternAddBool(pattern, "FC_OUTLINE", FcTrue);
204 //char *fam = NULL;
205 //FcPatternGetString(pattern, "FC_FAMILY",0, &fam);
206 //printf("subst_f on %s\n",fam);
207}
208
210 : fontServer(pango_ft2_font_map_new())
211 , fontContext(pango_font_map_create_context(fontServer))
212{
213 _font_map = Glib::wrap(fontServer);
214 pango_ft2_font_map_set_resolution(PANGO_FT2_FONT_MAP(fontServer), 72, 72);
215#if PANGO_VERSION_CHECK(1,48,0)
216 pango_fc_font_map_set_default_substitute(PANGO_FC_FONT_MAP(fontServer), FactorySubstituteFunc, this, nullptr);
217#else
218 pango_ft2_font_map_set_default_substitute(PANGO_FT2_FONT_MAP(fontServer), FactorySubstituteFunc, this, nullptr);
219#endif
220}
221
223{
224 loaded.clear();
225 g_object_unref(fontContext);
226 fontServer = 0; // freed by _font_map
227}
228
230{
231 pango_fc_font_map_config_changed(PANGO_FC_FONT_MAP(fontServer));
232}
233
235{
236 Glib::ustring pangoString;
237
238 g_assert(font);
239
240 if (font) {
241 // Once the format for the font specification is decided, it must be
242 // kept.. if it is absolutely necessary to change it, the attribute
243 // it is written to needs to have a new version so the legacy files
244 // can be read.
245
246 PangoFontDescription *copy = pango_font_description_copy(font);
247
248 pango_font_description_unset_fields(copy, PANGO_FONT_MASK_SIZE);
249 char *copyAsString = pango_font_description_to_string(copy);
250 pangoString = copyAsString;
251 g_free(copyAsString);
252
253 pango_font_description_free(copy);
254 }
255
256 return pangoString;
257}
258
260{
261 Glib::ustring pangoString;
262
263 g_assert(font);
264
265 if (font) {
266 pangoString = ConstructFontSpecification(font->get_descr());
267 }
268
269 return pangoString;
270}
271
272/*
273 * Wrap calls to pango_font_description_get_family
274 * and replace some of the pango font names with generic css names
275 * http://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#generic-font-families
276 *
277 * This function should be called in place of pango_font_description_get_family()
278 */
280{
281 static auto const fontNameMap = std::map<std::string, std::string>{
282 { "Sans", "sans-serif" },
283 { "Serif", "serif" },
284 { "Monospace", "monospace" }
285 };
286
287 char const *pangoFamily = pango_font_description_get_family(fontDescr);
288
289 if (pangoFamily) {
290 if (auto it = fontNameMap.find(pangoFamily); it != fontNameMap.end()) {
291 return it->second.c_str();
292 }
293 }
294
295 return pangoFamily;
296}
297
298std::string getSubstituteFontName(std::string const &font)
299{
300 auto descr = pango_font_description_new();
301 pango_font_description_set_family(descr, font.c_str());
302 auto fontinstance = FontFactory::get().Face(descr);
303 auto descr2 = pango_font_describe(fontinstance->get_font());
304 auto name = std::string(sp_font_description_get_family(descr2));
305 pango_font_description_free(descr);
306 return name;
307}
308
310{
311 Glib::ustring family;
312
313 g_assert(fontDescr);
314
315 if (fontDescr) {
316 // For now, keep it as family name taken from pango
317 char const *pangoFamily = sp_font_description_get_family(fontDescr);
318
319 if (pangoFamily) {
320 family = pangoFamily;
321 }
322 }
323
324 return family;
325}
326
328{
329 Glib::ustring style;
330
331 g_assert(fontDescr);
332
333 if (fontDescr) {
334 PangoFontDescription *fontDescrCopy = pango_font_description_copy(fontDescr);
335
336 pango_font_description_unset_fields(fontDescrCopy, PANGO_FONT_MASK_FAMILY);
337 pango_font_description_unset_fields(fontDescrCopy, PANGO_FONT_MASK_SIZE);
338
339 // For now, keep it as style name taken from pango
340 char *fontDescrAsString = pango_font_description_to_string(fontDescrCopy);
341 style = fontDescrAsString;
342 g_free(fontDescrAsString);
343 pango_font_description_free(fontDescrCopy);
344 }
345
346 return style;
347}
348
349// Calculate a Style "value" based on CSS values for ordering styles.
350static int StyleNameValue(Glib::ustring const &style)
351{
352 PangoFontDescription *pfd = pango_font_description_from_string (style.c_str());
353 int value =
354 pango_font_description_get_weight (pfd) * 1000000 +
355 pango_font_description_get_style (pfd) * 10000 +
356 pango_font_description_get_stretch(pfd) * 100 +
357 pango_font_description_get_variant(pfd);
358 pango_font_description_free (pfd);
359 return value;
360}
361
365std::vector<std::string> FontFactory::GetAllFontNames()
366{
367 std::vector<std::string> ret;
368 PangoFontFamily **families = nullptr;
369 int numFamilies = 0;
370 pango_font_map_list_families(fontServer, &families, &numFamilies);
371 // When pango version is newer, this can become a c++11 loop
372 for (int currentFamily = 0; currentFamily < numFamilies; ++currentFamily) {
373 ret.emplace_back(pango_font_family_get_name(families[currentFamily]));
374 }
375 return ret;
376}
377
378/*
379 * Returns true if the font family is in the local font server map.
380 */
381bool FontFactory::hasFontFamily(const std::string &family)
382{
383 return getSubstituteFontName(family) == family;
384}
385
386std::map<std::string, PangoFontFamily *> FontFactory::GetUIFamilies()
387{
388 std::map<std::string, PangoFontFamily *> result;
389
390 // Gather the family names as listed by Pango
391 PangoFontFamily **families = nullptr;
392 int numFamilies = 0;
393 pango_font_map_list_families(fontServer, &families, &numFamilies);
394
395 for (int currentFamily = 0; currentFamily < numFamilies; ++currentFamily) {
396 char const *displayName = pango_font_family_get_name(families[currentFamily]);
397
398 if (!displayName || *displayName == '\0') {
399 std::cerr << "FontFactory::GetUIFamilies: Missing displayName! " << std::endl;
400 continue;
401 }
402 if (!g_utf8_validate(displayName, -1, nullptr)) {
403 // TODO: can can do anything about this or does it always indicate broken fonts that should not be used?
404 std::cerr << "FontFactory::GetUIFamilies: Illegal characters in displayName. ";
405 std::cerr << "Ignoring font '" << displayName << "'" << std::endl;
406 continue;
407 }
408 result.emplace(displayName, families[currentFamily]);
409 }
410
411 g_free(families);
412 return result;
413}
414
415std::vector<Glib::RefPtr<Pango::FontFamily>> FontFactory::get_font_families() {
416 auto list = _font_map->list_families();
417 std::vector<Glib::RefPtr<Pango::FontFamily>> sorted;
418 sorted.reserve(list.size());
419
420 for (auto&& family : list) {
421 auto name = family->get_name();
422 if (name.empty()) {
423 std::cerr << "FontFactory::get_font_families - Missing font family name! " << std::endl;
424 continue;
425 }
426 if (!g_utf8_validate(name.c_str(), -1, nullptr)) {
427 std::cerr << "FontFactory::get_font_families - Illegal characters in font family name ";
428 std::cerr << "Ignoring font '" << name << "'" << std::endl;
429 continue;
430 }
431
432 sorted.emplace_back(family);
433 }
434
435 std::sort(sorted.begin(), sorted.end(), [](const Glib::RefPtr<Pango::FontFamily>& a, const Glib::RefPtr<Pango::FontFamily>& b){
436 return a->get_name() < b->get_name();
437 });
438
439 return sorted;
440}
441
442std::vector<StyleNames> FontFactory::GetUIStyles(PangoFontFamily *in)
443{
444 if (!in) {
445 std::cerr << "FontFactory::GetUIStyles(): PangoFontFamily is NULL" << std::endl;
446 return {};
447 }
448
449 // Gather the styles for this family
450 PangoFontFace **faces = nullptr;
451 int numFaces = 0;
452 pango_font_family_list_faces(in, &faces, &numFaces);
453
454 std::vector<StyleNames> result;
455
456 for (int currentFace = 0; currentFace < numFaces; currentFace++) {
457
458 // If the face has a name, describe it, and then use the
459 // description to get the UI family and face strings
460 char const *displayName = pango_font_face_get_face_name(faces[currentFace]);
461 // std::cout << "Display Name: " << displayName << std::endl;
462 if (!displayName || *displayName == '\0') {
463 std::cerr << "FontFactory::GetUIStyles: Missing displayName! " << std::endl;
464 continue;
465 }
466
467 PangoFontDescription *faceDescr = pango_font_face_describe(faces[currentFace]);
468 if (faceDescr) {
469 Glib::ustring familyUIName = GetUIFamilyString(faceDescr);
470 Glib::ustring styleUIName = GetUIStyleString(faceDescr);
471 // std::cout << " " << familyUIName << " styleUIName: " << styleUIName << " displayName: " << displayName << std::endl;
472
473 // Disable synthesized (faux) font faces except for CSS generic faces
474 if (pango_font_face_is_synthesized(faces[currentFace]) ) {
475 if (familyUIName.compare("sans-serif") != 0 &&
476 familyUIName.compare("serif" ) != 0 &&
477 familyUIName.compare("monospace" ) != 0 &&
478 familyUIName.compare("fantasy" ) != 0 &&
479 familyUIName.compare("cursive" ) != 0 ) {
480 continue;
481 }
482 }
483
484 // Pango breaks the 1 to 1 mapping between Pango weights and CSS weights by
485 // adding Semi-Light (as of 1.36.7), Book (as of 1.24), and Ultra-Heavy (as of
486 // 1.24). We need to map these weights to CSS weights. Book and Ultra-Heavy
487 // are rarely used. Semi-Light (350) is problematic as it is halfway between
488 // Light (300) and Normal (400) and if care is not taken it is converted to
489 // Normal, rather than Light.
490 //
491 // Note: The ultimate solution to handling various weight in the same
492 // font family is to support the @font rules from CSS.
493 //
494 // Additional notes, helpful for debugging:
495 // Pango's FC backend:
496 // Weights defined in fontconfig/fontconfig.h
497 // String equivalents in src/fcfreetype.c
498 // Weight set from os2->usWeightClass
499 // Use Fontforge: Element->Font Info...->OS/2->Misc->Weight Class to check font weight
500 size_t f = styleUIName.find( "Book" );
501 if( f != Glib::ustring::npos ) {
502 styleUIName.replace( f, 4, "Normal" );
503 }
504 f = styleUIName.find( "Semi-Light" );
505 if( f != Glib::ustring::npos ) {
506 styleUIName.replace( f, 10, "Light" );
507 }
508 f = styleUIName.find( "Ultra-Heavy" );
509 if( f != Glib::ustring::npos ) {
510 styleUIName.replace( f, 11, "Heavy" );
511 }
512
513 bool exists = false;
514 for (auto const &tmp : result) {
515 if (tmp.css_name.compare(styleUIName) == 0) {
516 exists = true;
517 std::cerr << "Warning: Font face with same CSS values already added: "
518 << familyUIName.raw() << " " << styleUIName.raw()
519 << " (" << tmp.display_name.raw()
520 << ", " << displayName << ")" << std::endl;
521 break;
522 }
523 }
524
525 if (!exists && !familyUIName.empty() && !styleUIName.empty()) {
526 // Add the style information
527 result.emplace_back(styleUIName, displayName);
528 }
529 }
530 pango_font_description_free(faceDescr);
531 }
532 g_free(faces);
533
534 // Sort the style list
535 std::sort(result.begin(), result.end(), [] (auto &a, auto &b) {
536 return StyleNameValue(a.css_name) < StyleNameValue(b.css_name);
537 });
538
539 return result;
540}
541
542std::shared_ptr<FontInstance> FontFactory::FaceFromStyle(SPStyle const *style)
543{
544 std::shared_ptr<FontInstance> font;
545
546 g_assert(style);
547
548 if (style) {
549
550 // First try to use the font specification if it is set
551 char const *val;
552 if (style->font_specification.set
553 && (val = style->font_specification.value())
554 && val[0]) {
555
556 font = FaceFromFontSpecification(val);
557 }
558
559 // If that failed, try using the CSS information in the style
560 if (!font) {
561 auto temp_descr = ink_font_description_from_style(style);
562 font = Face(temp_descr);
563 pango_font_description_free(temp_descr);
564 }
565 }
566
567 return font;
568}
569
570std::shared_ptr<FontInstance> FontFactory::FaceFromDescr(char const *family, char const *style)
571{
572 PangoFontDescription *temp_descr = pango_font_description_from_string(style);
573 pango_font_description_set_family(temp_descr,family);
574 auto res = Face(temp_descr);
575 pango_font_description_free(temp_descr);
576 return res;
577}
578
579std::shared_ptr<FontInstance> FontFactory::FaceFromPangoString(char const *pangoString)
580{
581 std::shared_ptr<FontInstance> fontInstance;
582
583 g_assert(pangoString);
584
585 if (pangoString) {
586
587 // Create a font description from the string - this may fail or
588 // produce unexpected results if the string does not have a good format
589 PangoFontDescription *descr = pango_font_description_from_string(pangoString);
590
591 if (descr) {
593 fontInstance = Face(descr);
594 }
595 pango_font_description_free(descr);
596 }
597 }
598
599 return fontInstance;
600}
601
602std::shared_ptr<FontInstance> FontFactory::FaceFromFontSpecification(char const *fontSpecification)
603{
604 std::shared_ptr<FontInstance> font;
605
606 g_assert(fontSpecification);
607
608 if (fontSpecification) {
609 // How the string is used to reconstruct a font depends on how it
610 // was constructed in ConstructFontSpecification. As it stands,
611 // the font specification is a pango-created string
612 font = FaceFromPangoString(fontSpecification);
613 }
614
615 return font;
616}
617
618std::unique_ptr<FontInstance> FontFactory::create_face(PangoFontDescription* descr) {
619 // Mandatory huge size (hinting workaround).
620 pango_font_description_set_size(descr, fontSize * PANGO_SCALE);
621
622 if (!sp_font_description_get_family(descr)) {
623 return {};
624 }
625
626 auto descr_copy = pango_font_description_copy(descr);
627 return std::make_unique<FontInstance>(pango_font_map_load_font(fontServer, fontContext, descr), descr_copy);
628}
629
630std::shared_ptr<FontInstance> FontFactory::Face(PangoFontDescription *descr, bool canFail)
631{
632 // Mandatory huge size (hinting workaround).
633 pango_font_description_set_size(descr, fontSize * PANGO_SCALE);
634
635 // Check if already loaded.
636 if (auto res = loaded.lookup(descr)) {
637 return res;
638 }
639
640 // Handle failures by falling back to sans-serif. If even that fails, throw.
641 auto fallback = [&] {
642 if (canFail) {
643 auto const tc = pango_font_description_to_string(descr);
644 PANGO_DEBUG("Falling back from %s to 'sans-serif' because InstallFace failed\n", tc);
645 g_free(tc);
646 pango_font_description_set_family(descr, "sans-serif");
647 return Face(descr, false);
648 } else {
649 throw std::runtime_error(std::string("Could not load any face for font ") + pango_font_description_to_string(descr));
650 }
651 };
652
653 // Workaround for bug #1025565: fonts without families blow up Pango.
654 if (!sp_font_description_get_family(descr)) {
655 g_warning("%s", _("Ignoring font without family that will crash Pango"));
656 return fallback();
657 }
658
659 // Create the face.
660 // Note: The descr of the returned pangofont may differ from what was asked. We use the original as the map key.
661 try {
662 auto descr_copy = pango_font_description_copy(descr);
663 return loaded.add(
664 descr_copy,
665 std::make_unique<FontInstance>(
666 pango_font_map_load_font(fontServer, fontContext, descr),
667 descr_copy
668 )
669 );
670 } catch (FontInstance::CtorException const &) {
671 return fallback();
672 }
673}
674
675// Not used, need to add variations if ever used.
676// std::shared_ptr<FontInstance> FontFactory::Face(char const *family, int variant, int style, int weight, int stretch, int /*size*/, int /*spacing*/)
677// {
678// // std::cout << "FontFactory::Face(family, variant, style, weight, stretch)" << std::endl;
679// PangoFontDescription *temp_descr = pango_font_description_new();
680// pango_font_description_set_family(temp_descr,family);
681// pango_font_description_set_weight(temp_descr,(PangoWeight)weight);
682// pango_font_description_set_stretch(temp_descr,(PangoStretch)stretch);
683// pango_font_description_set_style(temp_descr,(PangoStyle)style);
684// pango_font_description_set_variant(temp_descr,(PangoVariant)variant);
685// auto res = Face(temp_descr);
686// pango_font_description_free(temp_descr);
687// return res;
688// }
689
690# ifdef _WIN32
691void FontFactory::AddFontFilesWin32(char const *directory_path)
692{
693 static std::vector<char const *> const allowed_ext = {"ttf", "otf"};
694 std::vector<std::string> files;
695 Inkscape::IO::Resource::get_filenames_from_path(files, directory_path, allowed_ext, {});
696 for (auto const &file : files) {
697 wchar_t *file_utf16 = (wchar_t*) g_utf8_to_utf16 (file.c_str(), -1, NULL, NULL, NULL);
698 if (!file_utf16) {
699 g_warning("Cannot convert path %s to UTF16", file.c_str());
700 continue;
701 }
702 int result = AddFontResourceExW(file_utf16, FR_PRIVATE, 0);
703 if (result != 0) {
704 g_info("Font File: %s added sucessfully.", file.c_str());
705 } else {
706 g_warning("Font File: %s wasn't added sucessfully", file.c_str());
707 }
708 g_free(file_utf16);
709 }
710}
711# endif
712
713void FontFactory::AddFontsDir(char const *utf8dir)
714{
715 if (!Inkscape::IO::file_test(utf8dir, G_FILE_TEST_IS_DIR)) {
716 g_info("Fonts dir '%s' does not exist and will be ignored.", utf8dir);
717 return;
718 }
719
720 gchar *dir;
721# ifdef _WIN32
722 AddFontFilesWin32(utf8dir);
723 dir = g_win32_locale_filename_from_utf8(utf8dir);
724# else
725 dir = g_filename_from_utf8(utf8dir, -1, nullptr, nullptr, nullptr);
726# endif
727 if (!dir) {
728# ifdef _WIN32
729 g_warning ("Could not retrieve ACP path for '%s'", utf8dir);
730# else
731 g_warning ("Could not retrieve FS-encoded path for '%s'", utf8dir);
732# endif
733 }
734
735 FcConfig *conf = nullptr;
736 conf = pango_fc_font_map_get_config(PANGO_FC_FONT_MAP(fontServer));
737 FcBool res = FcConfigAppFontAddDir(conf, (FcChar8 const *)dir);
738 if (res == FcTrue) {
739 g_info("Fonts dir '%s' added successfully.", utf8dir);
740 pango_fc_font_map_config_changed(PANGO_FC_FONT_MAP(fontServer));
741 } else {
742 g_warning("Could not add fonts dir '%s'.", utf8dir);
743 }
744
745 g_free(dir);
746}
747
748void FontFactory::AddFontFile(char const *utf8file)
749{
750 if (!Inkscape::IO::file_test(utf8file, G_FILE_TEST_IS_REGULAR)) {
751 g_warning("Font file '%s' does not exist and will be ignored.", utf8file);
752 return;
753 }
754
755 gchar *file;
756# ifdef _WIN32
757 file = g_win32_locale_filename_from_utf8(utf8file);
758# else
759 file = g_filename_from_utf8(utf8file, -1, nullptr, nullptr, nullptr);
760# endif
761
762 FcConfig *conf = nullptr;
763 conf = pango_fc_font_map_get_config(PANGO_FC_FONT_MAP(fontServer));
764 FcBool res = FcConfigAppFontAddFile(conf, (FcChar8 const *)file);
765 if (res == FcTrue) {
766 g_info("Font file '%s' added successfully.", utf8file);
767 pango_fc_font_map_config_changed(PANGO_FC_FONT_MAP(fontServer));
768 } else {
769 g_warning("Could not add font file '%s'.", utf8file);
770 }
771
772 g_free(file);
773}
774
776{
777 // return pango_font_description_equal(a, b);
778 auto const fa = sp_font_description_get_family(a);
779 auto const fb = sp_font_description_get_family(b);
780 if ((bool)fa != (bool)fb) return false;
781 if (fa && fb && std::strcmp(fa, fb) != 0) return false;
782 if (pango_font_description_get_style(a) != pango_font_description_get_style(b) ) return false;
783 if (pango_font_description_get_variant(a) != pango_font_description_get_variant(b)) return false;
784 if (pango_font_description_get_weight(a) != pango_font_description_get_weight(b) ) return false;
785 if (pango_font_description_get_stretch(a) != pango_font_description_get_stretch(b)) return false;
786 if (g_strcmp0(pango_font_description_get_variations(a),
787 pango_font_description_get_variations(b) ) != 0) return false;
788 return true;
789}
790
792{
793 // Need to avoid using the size field.
794 size_t hash = 0;
795 auto const family = sp_font_description_get_family(x);
796 hash += family ? g_str_hash(family) : 0;
797 hash *= 1128467;
798 hash += (size_t)pango_font_description_get_style(x);
799 hash *= 1128467;
800 hash += (size_t)pango_font_description_get_variant(x);
801 hash *= 1128467;
802 hash += (size_t)pango_font_description_get_weight(x);
803 hash *= 1128467;
804 hash += (size_t)pango_font_description_get_stretch(x);
805 hash *= 1128467;
806 auto const variations = pango_font_description_get_variations(x);
807 hash += variations ? g_str_hash(variations) : 0;
808 return hash;
809}
810
815PangoFontDescription *FontFactory::parsePostscriptName(std::string const &name, bool substitute)
816{
817 PangoFontDescription *ret = nullptr;
818
819 // Use our local inkscape font-config setup, to include custom font dirs
820 FcConfig *conf = pango_fc_font_map_get_config(PANGO_FC_FONT_MAP(fontServer));
821 FcPattern *pat = FcNameParse(reinterpret_cast<const unsigned char *>((std::string(":postscriptname=") + name).c_str()));
822
823 // These must be called before FcFontMatch, see FontConfig docs.
824 FcConfigSubstitute(conf, pat, FcMatchPattern);
825 FcDefaultSubstitute(pat);
826
827 // We match the pattern and return the results
828 FcResult result;
829 FcPattern *match = FcFontMatch(conf, pat, &result);
830 if (match) {
831 // To block mis-matching we check the postscript name matches itself
832 FcChar8 *output;
833 FcPatternGetString(match, FC_POSTSCRIPT_NAME, 0, &output);
834 if (substitute || (output && name == (char *)output)) {
835 ret = pango_fc_font_description_from_pattern(match, false);
836 }
837 FcPatternDestroy(match);
838 }
839 FcPatternDestroy(pat);
840 return ret;
841}
842
843/*
844 Local Variables:
845 mode:c++
846 c-file-style:"stroustrup"
847 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
848 indent-tabs-mode:nil
849 fill-column:99
850 End:
851*/
852// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
_PangoFontDescription PangoFontDescription
Definition Layout-TNG.h:44
TODO: insert short description here.
std::shared_ptr< FontInstance > FaceFromStyle(SPStyle const *style)
Retrieve a FontInstance from a style object, first trying to use the font-specification,...
std::shared_ptr< FontInstance > FaceFromPangoString(char const *pangoString)
PangoContext * fontContext
PangoFontDescription * parsePostscriptName(std::string const &name, bool substitute)
Use font config to parse the postscript name found in pdf/ps files and return font config family and ...
void AddFontFile(char const *utf8file)
Add a an additional font.
Glib::ustring GetUIFamilyString(PangoFontDescription const *fontDescr)
Returns strings to be used in the UI for family and face (or "style" as the column is labeled)
Glib::ustring ConstructFontSpecification(PangoFontDescription *font)
Constructs a pango string for use with the fontStringMap (see below)
std::shared_ptr< FontInstance > Face(PangoFontDescription *descr, bool canFail=true)
Glib::ustring GetUIStyleString(PangoFontDescription const *fontDescr)
std::vector< std::string > GetAllFontNames()
Returns a list of all font names available in this font config.
Inkscape::Util::cached_map< PangoFontDescription *, FontInstance, Hash, Compare > loaded
std::shared_ptr< FontInstance > FaceFromDescr(char const *family, char const *style)
PangoFontMap * fontServer
std::vector< StyleNames > GetUIStyles(PangoFontFamily *in)
void refreshConfig()
The fontsize used as workaround for hinting.
bool hasFontFamily(std::string const &family)
void AddFontsDir(char const *utf8dir)
Add a directory from which to include additional fonts.
std::shared_ptr< FontInstance > FaceFromFontSpecification(char const *fontSpecification)
std::unique_ptr< FontInstance > create_face(PangoFontDescription *descr)
std::vector< Glib::RefPtr< Pango::FontFamily > > get_font_families()
static constexpr double fontSize
std::map< std::string, PangoFontFamily * > GetUIFamilies()
Glib::RefPtr< Pango::FontMap > _font_map
void AddFontFilesWin32(char const *directory_path)
FontInstance provides metrics, OpenType data, and glyph curves/pixbufs for a font.
auto get_descr() const
static FontFactory & get(Args &&... args)
Definition statics.h:153
An SVG style object.
Definition style.h:45
T< SPAttr::FONT_WEIGHT, SPIEnum< SPCSSFontWeight > > font_weight
Weight of the font.
Definition style.h:112
T< SPAttr::FONT_FAMILY, SPIString > font_family
Font family.
Definition style.h:120
T< SPAttr::INKSCAPE_FONT_SPEC, SPIString > font_specification
Full font name, as FontFactory::ConstructFontSpecification would give, for internal use.
Definition style.h:124
T< SPAttr::FONT_STYLE, SPIEnum< SPCSSFontStyle > > font_style
Font style.
Definition style.h:108
T< SPAttr::FONT_VARIANT, SPIEnum< SPCSSFontVariant > > font_variant
Which substyle of the font (CSS 2.
Definition style.h:110
T< SPAttr::FONT_STRETCH, SPIEnum< SPCSSFontStretch > > font_stretch
Stretch of the font.
Definition style.h:114
T< SPAttr::FONT_VARIATION_SETTINGS, SPIFontVariationSettings > font_variation_settings
Font variation settings (Low level access to OpenType variable font design-coordinate values)
Definition style.h:143
Css & result
PangoFontDescription * ink_font_description_from_style(SPStyle const *style)
char const * sp_font_description_get_family(PangoFontDescription const *fontDescr)
static void noop(...)
static void FactorySubstituteFunc(FcPattern *pattern, gpointer)
static int StyleNameValue(Glib::ustring const &style)
std::string getSubstituteFontName(std::string const &font)
TODO: insert short description here.
PangoFontDescription * ink_font_description_from_style(SPStyle const *style)
char const * sp_font_description_get_family(PangoFontDescription const *fontDescr)
std::string getSubstituteFontName(std::string const &font)
The data describing a single loaded font.
void get_filenames_from_path(std::vector< std::string > &files, std::string const &path, std::vector< const char * > const &extensions, std::vector< const char * > const &exclusions)
Definition resource.cpp:331
bool file_test(char const *utf8name, GFileTest test)
Definition sys.cpp:116
Inkscape::IO::Resource - simple resource API.
Static objects with destruction before main() exit.
bool operator()(PangoFontDescription const *a, PangoFontDescription const *b) const
size_t operator()(PangoFontDescription const *x) const
Exception thrown if construction fails.
@ SP_CSS_FONT_VARIANT_SMALL_CAPS
Definition style-enums.h:68
@ SP_CSS_FONT_VARIANT_NORMAL
Definition style-enums.h:67
@ SP_CSS_FONT_STYLE_NORMAL
Definition style-enums.h:61
@ SP_CSS_FONT_STYLE_OBLIQUE
Definition style-enums.h:63
@ SP_CSS_FONT_STYLE_ITALIC
Definition style-enums.h:62
@ SP_CSS_FONT_STRETCH_EXTRA_EXPANDED
Definition style-enums.h:95
@ SP_CSS_FONT_STRETCH_ULTRA_EXPANDED
Definition style-enums.h:96
@ SP_CSS_FONT_STRETCH_EXPANDED
Definition style-enums.h:94
@ SP_CSS_FONT_STRETCH_SEMI_EXPANDED
Definition style-enums.h:93
@ SP_CSS_FONT_STRETCH_NARROWER
Definition style-enums.h:97
@ SP_CSS_FONT_STRETCH_WIDER
Definition style-enums.h:98
@ SP_CSS_FONT_STRETCH_SEMI_CONDENSED
Definition style-enums.h:91
@ SP_CSS_FONT_STRETCH_NORMAL
Definition style-enums.h:92
@ SP_CSS_FONT_STRETCH_EXTRA_CONDENSED
Definition style-enums.h:89
@ SP_CSS_FONT_STRETCH_CONDENSED
Definition style-enums.h:90
@ SP_CSS_FONT_STRETCH_ULTRA_CONDENSED
Definition style-enums.h:88
@ SP_CSS_FONT_WEIGHT_LIGHTER
Definition style-enums.h:83
@ SP_CSS_FONT_WEIGHT_NORMAL
Definition style-enums.h:81
@ SP_CSS_FONT_WEIGHT_BOLD
Definition style-enums.h:82
@ SP_CSS_FONT_WEIGHT_400
Definition style-enums.h:75
@ SP_CSS_FONT_WEIGHT_300
Definition style-enums.h:74
@ SP_CSS_FONT_WEIGHT_100
Definition style-enums.h:72
@ SP_CSS_FONT_WEIGHT_200
Definition style-enums.h:73
@ SP_CSS_FONT_WEIGHT_900
Definition style-enums.h:80
@ SP_CSS_FONT_WEIGHT_700
Definition style-enums.h:78
@ SP_CSS_FONT_WEIGHT_800
Definition style-enums.h:79
@ SP_CSS_FONT_WEIGHT_500
Definition style-enums.h:76
@ SP_CSS_FONT_WEIGHT_BOLDER
Definition style-enums.h:84
@ SP_CSS_FONT_WEIGHT_600
Definition style-enums.h:77
Glib::ustring name
Definition toolbars.cpp:55