/*
7 * bulia byak <buliabyak@users.sf.net>
9 * Copyright (C) 2018 Authors
10 * Released under GNU GPL v2+, read the file
'COPYING' for more information.
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>
25#ifndef PANGO_ENABLE_ENGINE
26#define PANGO_ENABLE_ENGINE
29#include <unordered_map>
31#include <glibmm/i18n.h>
33#include <fontconfig/fontconfig.h>
35#include <pango/pangofc-fontmap.h>
36#include <pango/pangoft2.h>
37#include <pango/pango-ot.h>
59 pango_font_description_set_family(descr, style->
font_family.value());
64 pango_font_description_set_style(descr, PANGO_STYLE_ITALIC);
68 pango_font_description_set_style(descr, PANGO_STYLE_OBLIQUE);
73 pango_font_description_set_style(descr, PANGO_STYLE_NORMAL);
79 pango_font_description_set_weight(descr, PANGO_WEIGHT_THIN);
83 pango_font_description_set_weight(descr, PANGO_WEIGHT_ULTRALIGHT);
87 pango_font_description_set_weight(descr, PANGO_WEIGHT_LIGHT);
92 pango_font_description_set_weight(descr, PANGO_WEIGHT_NORMAL);
96 pango_font_description_set_weight(descr, PANGO_WEIGHT_MEDIUM);
100 pango_font_description_set_weight(descr, PANGO_WEIGHT_SEMIBOLD);
105 pango_font_description_set_weight(descr, PANGO_WEIGHT_BOLD);
109 pango_font_description_set_weight(descr, PANGO_WEIGHT_ULTRABOLD);
113 pango_font_description_set_weight(descr, PANGO_WEIGHT_HEAVY);
120 pango_font_description_set_weight(descr,
static_cast<PangoWeight
>(style->
font_weight.computed));
123 g_warning(
"FaceFromStyle: Unrecognized font_weight.computed value");
124 pango_font_description_set_weight(descr, PANGO_WEIGHT_NORMAL);
132 pango_font_description_set_stretch(descr, PANGO_STRETCH_ULTRA_CONDENSED);
136 pango_font_description_set_stretch(descr, PANGO_STRETCH_EXTRA_CONDENSED);
140 pango_font_description_set_stretch(descr, PANGO_STRETCH_CONDENSED);
144 pango_font_description_set_stretch(descr, PANGO_STRETCH_SEMI_CONDENSED);
148 pango_font_description_set_stretch(descr, PANGO_STRETCH_NORMAL);
152 pango_font_description_set_stretch(descr, PANGO_STRETCH_SEMI_EXPANDED);
156 pango_font_description_set_stretch(descr, PANGO_STRETCH_EXPANDED);
160 pango_font_description_set_stretch(descr, PANGO_STRETCH_EXTRA_EXPANDED);
164 pango_font_description_set_stretch(descr, PANGO_STRETCH_ULTRA_EXPANDED);
169 g_warning(
"FaceFromStyle: Unrecognized font_stretch.computed value");
170 pango_font_description_set_stretch(descr, PANGO_STRETCH_NORMAL);
176 pango_font_description_set_variant(descr, PANGO_VARIANT_SMALL_CAPS);
181 pango_font_description_set_variant(descr, PANGO_VARIANT_NORMAL);
197#define PANGO_DEBUG noop
203 FcPatternAddBool(pattern,
"FC_OUTLINE", FcTrue);
210 : fontServer(pango_ft2_font_map_new())
211 , fontContext(pango_font_map_create_context(fontServer))
214 pango_ft2_font_map_set_resolution(PANGO_FT2_FONT_MAP(
fontServer), 72, 72);
215#if PANGO_VERSION_CHECK(1,48,0)
231 pango_fc_font_map_config_changed(PANGO_FC_FONT_MAP(
fontServer));
236 Glib::ustring pangoString;
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);
253 pango_font_description_free(copy);
261 Glib::ustring pangoString;
281 static auto const fontNameMap = std::map<std::string, std::string>{
282 {
"Sans",
"sans-serif" },
283 {
"Serif",
"serif" },
284 {
"Monospace",
"monospace" }
287 char const *pangoFamily = pango_font_description_get_family(fontDescr);
290 if (
auto it = fontNameMap.find(pangoFamily); it != fontNameMap.end()) {
291 return it->second.c_str();
300 auto descr = pango_font_description_new();
301 pango_font_description_set_family(descr, font.c_str());
303 auto descr2 = pango_font_describe(fontinstance->get_font());
305 pango_font_description_free(descr);
311 Glib::ustring family;
320 family = pangoFamily;
336 pango_font_description_unset_fields(fontDescrCopy, PANGO_FONT_MASK_FAMILY);
337 pango_font_description_unset_fields(fontDescrCopy, PANGO_FONT_MASK_SIZE);
340 char *fontDescrAsString = pango_font_description_to_string(fontDescrCopy);
341 style = fontDescrAsString;
342 g_free(fontDescrAsString);
343 pango_font_description_free(fontDescrCopy);
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);
367 std::vector<std::string> ret;
368 PangoFontFamily **families =
nullptr;
370 pango_font_map_list_families(
fontServer, &families, &numFamilies);
372 for (
int currentFamily = 0; currentFamily < numFamilies; ++currentFamily) {
373 ret.emplace_back(pango_font_family_get_name(families[currentFamily]));
388 std::map<std::string, PangoFontFamily *>
result;
391 PangoFontFamily **families =
nullptr;
393 pango_font_map_list_families(
fontServer, &families, &numFamilies);
395 for (
int currentFamily = 0; currentFamily < numFamilies; ++currentFamily) {
396 char const *displayName = pango_font_family_get_name(families[currentFamily]);
398 if (!displayName || *displayName ==
'\0') {
399 std::cerr <<
"FontFactory::GetUIFamilies: Missing displayName! " << std::endl;
402 if (!g_utf8_validate(displayName, -1,
nullptr)) {
404 std::cerr <<
"FontFactory::GetUIFamilies: Illegal characters in displayName. ";
405 std::cerr <<
"Ignoring font '" << displayName <<
"'" << std::endl;
408 result.emplace(displayName, families[currentFamily]);
417 std::vector<Glib::RefPtr<Pango::FontFamily>> sorted;
418 sorted.reserve(list.size());
420 for (
auto&& family : list) {
421 auto name = family->get_name();
423 std::cerr <<
"FontFactory::get_font_families - Missing font family name! " << std::endl;
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;
432 sorted.emplace_back(family);
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();
445 std::cerr <<
"FontFactory::GetUIStyles(): PangoFontFamily is NULL" << std::endl;
450 PangoFontFace **faces =
nullptr;
452 pango_font_family_list_faces(in, &faces, &numFaces);
454 std::vector<StyleNames>
result;
456 for (
int currentFace = 0; currentFace < numFaces; currentFace++) {
460 char const *displayName = pango_font_face_get_face_name(faces[currentFace]);
462 if (!displayName || *displayName ==
'\0') {
463 std::cerr <<
"FontFactory::GetUIStyles: Missing displayName! " << std::endl;
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 ) {
500 size_t f = styleUIName.find(
"Book" );
501 if( f != Glib::ustring::npos ) {
502 styleUIName.replace( f, 4,
"Normal" );
504 f = styleUIName.find(
"Semi-Light" );
505 if( f != Glib::ustring::npos ) {
506 styleUIName.replace( f, 10,
"Light" );
508 f = styleUIName.find(
"Ultra-Heavy" );
509 if( f != Glib::ustring::npos ) {
510 styleUIName.replace( f, 11,
"Heavy" );
514 for (
auto const &tmp :
result) {
515 if (tmp.css_name.compare(styleUIName) == 0) {
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;
525 if (!exists && !familyUIName.empty() && !styleUIName.empty()) {
527 result.emplace_back(styleUIName, displayName);
530 pango_font_description_free(faceDescr);
535 std::sort(
result.begin(),
result.end(), [] (
auto &a,
auto &b) {
536 return StyleNameValue(a.css_name) < StyleNameValue(b.css_name);
544 std::shared_ptr<FontInstance> font;
562 font =
Face(temp_descr);
563 pango_font_description_free(temp_descr);
573 pango_font_description_set_family(temp_descr,family);
574 auto res =
Face(temp_descr);
575 pango_font_description_free(temp_descr);
581 std::shared_ptr<FontInstance> fontInstance;
583 g_assert(pangoString);
593 fontInstance =
Face(descr);
595 pango_font_description_free(descr);
604 std::shared_ptr<FontInstance> font;
606 g_assert(fontSpecification);
608 if (fontSpecification) {
620 pango_font_description_set_size(descr,
fontSize * PANGO_SCALE);
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);
633 pango_font_description_set_size(descr,
fontSize * PANGO_SCALE);
636 if (
auto res =
loaded.lookup(descr)) {
641 auto fallback = [&] {
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);
646 pango_font_description_set_family(descr,
"sans-serif");
647 return Face(descr,
false);
649 throw std::runtime_error(std::string(
"Could not load any face for font ") + pango_font_description_to_string(descr));
655 g_warning(
"%s", _(
"Ignoring font without family that will crash Pango"));
662 auto descr_copy = pango_font_description_copy(descr);
665 std::make_unique<FontInstance>(
693 static std::vector<char const *>
const allowed_ext = {
"ttf",
"otf"};
694 std::vector<std::string> files;
696 for (
auto const &file : files) {
697 wchar_t *file_utf16 = (
wchar_t*) g_utf8_to_utf16 (file.c_str(), -1, NULL, NULL, NULL);
699 g_warning(
"Cannot convert path %s to UTF16", file.c_str());
702 int result = AddFontResourceExW(file_utf16, FR_PRIVATE, 0);
704 g_info(
"Font File: %s added sucessfully.", file.c_str());
706 g_warning(
"Font File: %s wasn't added sucessfully", file.c_str());
716 g_info(
"Fonts dir '%s' does not exist and will be ignored.", utf8dir);
723 dir = g_win32_locale_filename_from_utf8(utf8dir);
725 dir = g_filename_from_utf8(utf8dir, -1,
nullptr,
nullptr,
nullptr);
729 g_warning (
"Could not retrieve ACP path for '%s'", utf8dir);
731 g_warning (
"Could not retrieve FS-encoded path for '%s'", utf8dir);
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);
739 g_info(
"Fonts dir '%s' added successfully.", utf8dir);
740 pango_fc_font_map_config_changed(PANGO_FC_FONT_MAP(
fontServer));
742 g_warning(
"Could not add fonts dir '%s'.", utf8dir);
751 g_warning(
"Font file '%s' does not exist and will be ignored.", utf8file);
757 file = g_win32_locale_filename_from_utf8(utf8file);
759 file = g_filename_from_utf8(utf8file, -1,
nullptr,
nullptr,
nullptr);
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);
766 g_info(
"Font file '%s' added successfully.", utf8file);
767 pango_fc_font_map_config_changed(PANGO_FC_FONT_MAP(
fontServer));
769 g_warning(
"Could not add font file '%s'.", utf8file);
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;
796 hash += family ? g_str_hash(family) : 0;
798 hash += (size_t)pango_font_description_get_style(x);
800 hash += (size_t)pango_font_description_get_variant(x);
802 hash += (size_t)pango_font_description_get_weight(x);
804 hash += (size_t)pango_font_description_get_stretch(x);
806 auto const variations = pango_font_description_get_variations(x);
807 hash += variations ? g_str_hash(variations) : 0;
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()));
824 FcConfigSubstitute(conf, pat, FcMatchPattern);
825 FcDefaultSubstitute(pat);
829 FcPattern *match = FcFontMatch(conf, pat, &
result);
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);
837 FcPatternDestroy(match);
839 FcPatternDestroy(pat);
_PangoFontDescription PangoFontDescription
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.
static FontFactory & get(Args &&... args)
T< SPAttr::FONT_WEIGHT, SPIEnum< SPCSSFontWeight > > font_weight
Weight of the font.
T< SPAttr::FONT_FAMILY, SPIString > font_family
Font family.
T< SPAttr::INKSCAPE_FONT_SPEC, SPIString > font_specification
Full font name, as FontFactory::ConstructFontSpecification would give, for internal use.
T< SPAttr::FONT_STYLE, SPIEnum< SPCSSFontStyle > > font_style
Font style.
T< SPAttr::FONT_VARIANT, SPIEnum< SPCSSFontVariant > > font_variant
Which substyle of the font (CSS 2.
T< SPAttr::FONT_STRETCH, SPIEnum< SPCSSFontStretch > > font_stretch
Stretch of the font.
T< SPAttr::FONT_VARIATION_SETTINGS, SPIFontVariationSettings > font_variation_settings
Font variation settings (Low level access to OpenType variable font design-coordinate values)
PangoFontDescription * ink_font_description_from_style(SPStyle const *style)
char const * sp_font_description_get_family(PangoFontDescription const *fontDescr)
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)
bool file_test(char const *utf8name, GFileTest test)
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
@ SP_CSS_FONT_VARIANT_NORMAL
@ SP_CSS_FONT_STYLE_NORMAL
@ SP_CSS_FONT_STYLE_OBLIQUE
@ SP_CSS_FONT_STYLE_ITALIC
@ SP_CSS_FONT_STRETCH_EXTRA_EXPANDED
@ SP_CSS_FONT_STRETCH_ULTRA_EXPANDED
@ SP_CSS_FONT_STRETCH_EXPANDED
@ SP_CSS_FONT_STRETCH_SEMI_EXPANDED
@ SP_CSS_FONT_STRETCH_NARROWER
@ SP_CSS_FONT_STRETCH_WIDER
@ SP_CSS_FONT_STRETCH_SEMI_CONDENSED
@ SP_CSS_FONT_STRETCH_NORMAL
@ SP_CSS_FONT_STRETCH_EXTRA_CONDENSED
@ SP_CSS_FONT_STRETCH_CONDENSED
@ SP_CSS_FONT_STRETCH_ULTRA_CONDENSED
@ SP_CSS_FONT_WEIGHT_LIGHTER
@ SP_CSS_FONT_WEIGHT_NORMAL
@ SP_CSS_FONT_WEIGHT_BOLD
@ SP_CSS_FONT_WEIGHT_BOLDER