Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
font-lister.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
5/*
6 * Authors:
7 * Chris Lahey <clahey@ximian.com>
8 * Lauris Kaplinski <lauris@kaplinski.com>
9 * Tavmjong Bah <tavmjong@free.fr>
10 * See Git history
11 *
12 * Copyright (C) 1999-2001 Ximian, Inc.
13 * Copyright (C) 2002 Lauris Kaplinski
14 * Copyright (C) 2013 Tavmjong Bah
15 * Copyright (C) 2018+ Authors
16 *
17 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
18 */
19
20#include "font-lister.h"
21
22#include <glibmm/markup.h>
23#include <glibmm/regex.h>
24#include <gtkmm/cellrenderertext.h>
25#include <gtkmm/settings.h>
27#include <string>
28
29#include "font-factory.h"
30#include "desktop.h"
31#include "desktop-style.h"
32#include "document.h"
33#include "inkscape.h"
34#include "preferences.h"
35#include "object/sp-object.h"
36// Following are needed to limit the source of updating font data to text and containers.
37#include "object/sp-root.h"
38#include "object/sp-anchor.h"
39#include "object/sp-text.h"
40#include "object/sp-tspan.h"
41#include "object/sp-textpath.h"
42#include "object/sp-tref.h"
43#include "object/sp-flowtext.h"
44#include "object/sp-flowdiv.h"
47#include "util/document-fonts.h"
48#include "xml/repr.h"
49
50//#define DEBUG_FONT
51
52// CSS dictates that font family names are case insensitive.
53// This should really implement full Unicode case unfolding.
54bool familyNamesAreEqual(const Glib::ustring &a, const Glib::ustring &b)
55{
56 return (a.casefold().compare(b.casefold()) == 0);
57}
58
59namespace Inkscape {
60
62{
63 // Create default styles for use when font-family is unknown on system.
64 default_styles = std::make_shared<Styles>(Styles{
65 {"Normal"},
66 {"Italic"},
67 {"Bold"},
68 {"Bold Italic"}
69 });
70
73
74 style_list_store = Gtk::ListStore::create(font_style_list);
76
77 // Watch gtk for the fonts-changed signal and refresh our pango configuration
78 if (auto settings = Gtk::Settings::get_default()) {
79 settings->property_gtk_fontconfig_timestamp().signal_changed().connect([this]() {
83 new_fonts_signal.emit();
84 });
85 }
86}
87
88FontLister::~FontLister() = default;
89
90bool FontLister::font_installed_on_system(Glib::ustring const &font) const
91{
92 return pango_family_map.find(font) != pango_family_map.end();
93}
94
95void FontLister::init_font_families(int group_offset, int group_size)
96{
97 static bool first_call = true;
98
99 if (first_call)
100 {
101 font_list_store = Gtk::ListStore::create(font_list);
102 first_call = false;
103 }
104
105 if (group_offset <= 0) {
106 font_list_store->clear();
107 if (group_offset == 0)
108 insert_font_family("sans-serif");
109 }
110
111 font_list_store->freeze_notify();
112
113 // Traverse through the family names and set up the list store
114 for (auto const &key_val : pango_family_map) {
115 if (!key_val.first.empty()) {
116 auto row = *font_list_store->append();
117 row[font_list.family] = key_val.first;
118 // we don't set this now (too slow) but the style will be cached if the user
119 // ever decides to use this font
120 row[font_list.styles] = nullptr;
121 // store the pango representation for generating the style
122 row[font_list.pango_family] = key_val.second;
123 row[font_list.onSystem] = true;
124 }
125 }
126
127 font_list_store->thaw_notify();
128}
129
131{
132 // Initialize style store with defaults
133 style_list_store->freeze_notify();
134 style_list_store->clear();
135 for (auto const &style : *default_styles) {
136 auto row = *style_list_store->append();
137 row[font_style_list.cssStyle] = style.css_name;
138 row[font_style_list.displayStyle] = style.display_name;
139 }
140 style_list_store->thaw_notify();
141 update_signal.emit();
142}
143
144std::pair<bool, std::string> FontLister::get_font_count_label() const
145{
146 std::string label;
147 bool all_fonts = false;
148
149 int size = font_list_store->children().size();
150 int total_families = get_font_families_size();
151
152 if (size >= total_families) {
153 label += _("All Fonts");
154 all_fonts = true;
155 } else {
156 label += _("Fonts ");
157 label += std::to_string(size);
158 label += "/";
159 label += std::to_string(total_families);
160 }
161
162 return std::make_pair(all_fonts, label);
163}
164
166{
167 static FontLister instance;
168 return &instance;
169}
170
172bool FontLister::find_string_case_insensitive(std::string const &text, std::string const &pat)
173{
174 auto it = std::search(
175 text.begin(), text.end(),
176 pat.begin(), pat.end(),
177 [] (unsigned char ch1, unsigned char ch2) { return std::toupper(ch1) == std::toupper(ch2); }
178 );
179
180 return it != text.end();
181}
182
183void FontLister::show_results(Glib::ustring const &search_text)
184{
185 // Clear currently selected collections.
187
188 if (search_text == "") {
191 add_document_fonts_at_top(SP_ACTIVE_DOCUMENT);
192 return;
193 }
194
195 // Clear the list store.
196 font_list_store->freeze_notify();
197 font_list_store->clear();
198
199 // Start iterating over the families.
200 // Take advantage of sorted families to speed up the search.
201 for (auto const &[family_str, pango_family] : pango_family_map) {
202 if (find_string_case_insensitive(family_str, search_text)) {
203 auto row = *font_list_store->append();
204 row.set_value(font_list.family, Glib::ustring{family_str});
205
206 // we don't set this now (too slow) but the style will be cached if the user
207 // ever decides to use this font
208 // row.set_value(FontList.styles, nullptr); // not needed: default on new row
209
210 // store the pango representation for generating the style
211 row.set_value(font_list.pango_family, pango_family);
212 row.set_value(font_list.onSystem, true);
213 }
214 }
215
216 // selected_fonts_count = count;
217 add_document_fonts_at_top(SP_ACTIVE_DOCUMENT);
218 font_list_store->thaw_notify();
219 init_default_styles();
220
221 // To update the count of fonts in the label.
222 // update_signal.emit ();
223}
224
225void FontLister::apply_collections(std::set <Glib::ustring>& selected_collections)
226{
227 // Get the master set of fonts present in all the selected collections.
228 std::set <Glib::ustring> fonts;
229
231
232 for (auto const &col : selected_collections) {
233 if (col.raw() == Inkscape::DOCUMENT_FONTS) {
235 for (auto const &font : document_fonts->get_fonts()) {
236 fonts.insert(font);
237 }
238 } else if (col.raw() == Inkscape::RECENTLY_USED_FONTS) {
240 for (auto const &font : recently_used->get_fonts()) {
241 fonts.insert(font);
242 }
243 } else {
244 for (auto const &font : font_collections->get_fonts(col)) {
245 fonts.insert(std::move(font));
246 }
247 }
248 }
249
250 // Freeze the font list.
251 font_list_store->freeze_notify();
252 font_list_store->clear();
253
254 if (fonts.empty()) {
255 // Re-initialize the font list if
256 // initialize_font_list();
257 init_font_families();
258 init_default_styles();
259 add_document_fonts_at_top(SP_ACTIVE_DOCUMENT);
260 return;
261 }
262
263 for (auto const &f : fonts) {
264 auto row = *font_list_store->append();
265 row[font_list.family] = f;
266
267 // we don't set this now (too slow) but the style will be cached if the user
268 // ever decides to use this font
269 row[font_list.styles] = nullptr;
270
271 // store the pango representation for generating the style
272 row[font_list.pango_family] = pango_family_map[f];
273 row[font_list.onSystem] = true;
274 }
275
276 add_document_fonts_at_top(SP_ACTIVE_DOCUMENT);
277 font_list_store->thaw_notify();
278 init_default_styles();
279
280 // To update the count of fonts in the label.
281 update_signal.emit();
282}
283
284// Ensures the style list for a particular family has been created.
285void FontLister::ensureRowStyles(Gtk::TreeModel::iterator iter)
286{
287 auto &row = *iter;
288 if (row.get_value(font_list.styles)) {
289 return;
290 }
291
292 if (row[font_list.pango_family]) {
293 row[font_list.styles] = std::make_shared<Styles>(FontFactory::get().GetUIStyles(row[font_list.pango_family]));
294 } else {
295 row[font_list.styles] = default_styles;
296 }
297}
298
299Glib::ustring FontLister::get_font_family_markup(Gtk::TreeModel::const_iterator const &iter) const
300{
301 auto const &row = *iter;
303
304 Glib::ustring family = row[font_list.family];
305 bool onSystem = row[font_list.onSystem];
306
307 Glib::ustring family_escaped = Glib::Markup::escape_text( family );
308 Glib::ustring markup;
309
310 if (!onSystem) {
311 markup = "<span font-weight='bold'>";
312
313 // See if font-family is on system (separately for each family in font stack).
314 std::vector<Glib::ustring> tokens = Glib::Regex::split_simple("\\s*,\\s*", family);
315
316 for (auto const &token: tokens) {
317 if (font_installed_on_system(token)) {
318 markup += Glib::Markup::escape_text (token);
319 markup += ", ";
320 } else {
321 markup += "<span strikethrough=\"true\" strikethrough_color=\"red\">";
322 markup += Glib::Markup::escape_text (token);
323 markup += "</span>";
324 markup += ", ";
325 }
326 }
327
328 // Remove extra comma and space from end.
329 if (markup.size() >= 2) {
330 markup.resize(markup.size() - 2);
331 }
332 markup += "</span>";
333
334 } else {
335 markup = family_escaped;
336 }
337
338 int show_sample = prefs->getInt("/tools/text/show_sample_in_list", 1);
339 if (show_sample) {
340 Glib::ustring sample = prefs->getString("/tools/text/font_sample");
341 // we setup a small line height to avoid semi hidden fonts (one line height rendering overlap without padding)
342#if PANGO_VERSION_CHECK(1,50,0)
343 markup += " <span foreground='gray' line-height='0.6' font-size='100%' font_family='";
344#else
345 markup += " <span foreground='gray' font_family='";
346#endif
347 markup += family_escaped;
348 markup += "'>";
349 markup += sample;
350 markup += "</span>";
351 }
352
353 // std::cout << "Markup: " << markup << std::endl;
354 return markup;
355}
356
357// Example of how to use "foreach_iter"
358// bool
359// FontLister::print_document_font(Gtk::TreeModel::const_iterator const &iter)
360// {
361// auto const &row = *iter;
362// if(!row[FontList.onSystem]) {
363// std::cout << " Not on system: " << row[FontList.family] << std::endl;
364// return false;
365// }
366// return true;
367// }
368// font_list_store->foreach_iter( sigc::mem_fun(*this, &FontLister::print_document_font ));
369
370// Used to insert a font that was not in the document and not on the system into the font list.
371void FontLister::insert_font_family(Glib::ustring const &new_family)
372{
373 auto styles = default_styles;
374
375 // In case this is a fallback list, check if first font-family on system.
376 std::vector<Glib::ustring> tokens = Glib::Regex::split_simple(",", new_family);
377 if (!tokens.empty() && !tokens[0].empty()) {
378 for (auto &row : font_list_store->children()) {
379 auto row_styles = row.get_value(font_list.styles);
380
381 if (row[font_list.onSystem] && familyNamesAreEqual(tokens[0], row[font_list.family])) {
382 if (!row_styles) {
383 row_styles = std::make_shared<Styles>(FontFactory::get().GetUIStyles(row[font_list.pango_family]));
384 }
385 styles = row_styles;
386 break;
387 }
388 }
389 }
390
391 auto row = *font_list_store->prepend();
392 row[font_list.family] = new_family;
393 row[font_list.styles] = styles;
394 row[font_list.onSystem] = false;
395 row[font_list.pango_family] = nullptr;
396
397 current_family = new_family;
398 current_family_row = 0;
399 current_style = "Normal";
400
401 emit_update();
402}
403
404int FontLister::add_document_fonts_at_top(SPDocument *document)
405{
406 if (!document) {
407 return 0;
408 }
409
410 auto root = document->getRoot();
411 if (!root) {
412 return 0;
413 }
414
415 // Clear all old document font-family entries.
416 {
417 auto children = font_list_store->children();
418 for (auto iter = children.begin(), end = children.end(); iter != end;) {
419 if (!iter->get_value(font_list.onSystem)) {
420 // std::cout << " Not on system: " << row[FontList.family] << std::endl;
421 iter = font_list_store->erase(iter);
422 } else {
423 // std::cout << " First on system: " << row[FontList.family] << std::endl;
424 break;
425 }
426 }
427 }
428
429 // Get "font-family"s and styles used in document.
430 std::map<Glib::ustring, std::set<Glib::ustring>> font_data;
431 update_font_data_recursive(*root, font_data);
432
433 // Insert separator
434 if (!font_data.empty()) {
435 auto row = *font_list_store->prepend();
436 row[font_list.family] = "#";
437 }
438
439 // Insert the document's font families into the store.
440 for (auto const &[data_family, data_styleset] : font_data) {
441 // Ensure the font family is non-empty, and get the part up to the first comma.
442 auto const i = data_family.find_first_of(',');
443 if (i == 0) {
444 continue;
445 }
446 auto const fam = data_family.substr(0, i);
447
448 // Return the system font matching the given family name.
449 auto find_matching_system_font = [this] (Glib::ustring const &fam) -> Gtk::TreeIter<Gtk::TreeRow> {
450 for (auto &row : font_list_store->children()) {
451 if (row[font_list.onSystem] && familyNamesAreEqual(fam, row[font_list.family])) {
452 return row.get_iter();
453 }
454 }
455 return {};
456 };
457
458 // Initialise an empty Styles for this font.
459 Styles data_styles;
460
461 // Populate with the styles of the matching system font, if any.
462 if (auto const iter = find_matching_system_font(fam)) {
463 auto const row = *iter;
464 ensureRowStyles(iter);
465 data_styles = *row.get_value(font_list.styles);
466 }
467
468 // Add additional styles from 'font-variation-settings'; these may not be included in the system font's styles.
469 for (auto const &data_style : data_styleset) {
470 // std::cout << " Inserting: " << j << std::endl;
471
472 bool exists = false;
473 for (auto const &style : data_styles) {
474 if (style.css_name.compare(data_style) == 0) {
475 exists = true;
476 break;
477 }
478 }
479
480 if (!exists) {
481 data_styles.emplace_back(data_style, data_style);
482 }
483 }
484
485 auto row = *font_list_store->prepend();
486 row[font_list.family] = data_family;
487 row[font_list.styles] = std::make_shared<Styles>(std::move(data_styles));
488 /* These are not needed as they are the default values.
489 row.set_value(font_list.onSystem, false); // false if document font
490 row.set_value(font_list.pango_family, nullptr); // CHECK ME (set to pango_family if on system?)
491 */
492 }
493
494 // For document fonts.
495 auto document_fonts = Inkscape::DocumentFonts::get();
496 document_fonts->update_document_fonts(font_data);
497
498 return font_data.size();
499}
500
501void FontLister::update_font_list(SPDocument *document)
502{
503 auto root = document->getRoot();
504 if (!root) {
505 return;
506 }
507
508 font_list_store->freeze_notify();
509
510 /* Find if current row is in document or system part of list */
511 bool row_is_system = false;
512 if (current_family_row > -1) {
513 Gtk::TreePath path;
514 path.push_back(current_family_row);
515 Gtk::TreeModel::iterator iter = font_list_store->get_iter(path);
516 if (iter) {
517 row_is_system = (*iter)[font_list.onSystem];
518 // std::cout << " In: row: " << current_family_row << " " << (*iter)[FontList.family] << std::endl;
519 }
520 }
521
522 int font_data_size = add_document_fonts_at_top(document);
523
524 font_family_row_update(row_is_system ? font_data_size : 0);
525 // std::cout << " Out: row: " << current_family_row << " " << current_family << std::endl;
526
527 font_list_store->thaw_notify();
528 emit_update();
529}
530
531void FontLister::update_font_data_recursive(SPObject &r, std::map<Glib::ustring, std::set<Glib::ustring>> &font_data)
532{
533 // Text nodes (i.e. the content of <text> or <tspan>) do not have their own style.
535 return;
536 }
537
539 auto font_family_char = pango_font_description_get_family(descr);
540 if (font_family_char) {
541 Glib::ustring font_family(font_family_char);
542 pango_font_description_unset_fields(descr, PANGO_FONT_MASK_FAMILY);
543
544 auto font_style_char = pango_font_description_to_string(descr);
545 Glib::ustring font_style(font_style_char);
546 g_free(font_style_char);
547
548 if (!font_family.empty() && !font_style.empty()) {
549 font_data[font_family].insert(font_style);
550 }
551 } else {
552 // We're starting from root and looking at all elements... we should probably white list text/containers.
553 std::cerr << "FontLister::update_font_data_recursive: descr without font family! " << (r.getId()?r.getId():"null") << std::endl;
554 }
555 pango_font_description_free(descr);
556
557 if (is<SPGroup>(&r) ||
558 is<SPAnchor>(&r) ||
559 is<SPRoot>(&r) ||
560 is<SPText>(&r) ||
561 is<SPTSpan>(&r) ||
562 is<SPTextPath>(&r) ||
563 is<SPTRef>(&r) ||
564 is<SPFlowtext>(&r) ||
565 is<SPFlowdiv>(&r) ||
566 is<SPFlowpara>(&r) ||
567 is<SPFlowline>(&r))
568 {
569 for (auto &child: r.children) {
570 update_font_data_recursive(child, font_data);
571 }
572 }
573}
574
575void FontLister::emit_update()
576{
577 if (block) return;
578
579 block = true;
580 update_signal.emit();
581 block = false;
582}
583
584Glib::ustring FontLister::canonize_fontspec(Glib::ustring const &fontspec) const
585{
586 // Pass fontspec to and back from Pango to get a the fontspec in
587 // canonical form. -inkscape-font-specification relies on the
588 // Pango constructed fontspec not changing form. If it does,
589 // this is the place to fix it.
590 PangoFontDescription *descr = pango_font_description_from_string(fontspec.c_str());
591 gchar *canonized = pango_font_description_to_string(descr);
592 Glib::ustring Canonized = canonized;
593 g_free(canonized);
594 pango_font_description_free(descr);
595
596 // Pango canonized strings remove space after comma between family names. Put it back.
597 // But don't add a space inside a 'font-variation-settings' declaration (this breaks Pango).
598 size_t i = 0;
599 while ((i = Canonized.find_first_of(",@", i)) != std::string::npos ) {
600 if (Canonized[i] == '@') // Found start of 'font-variation-settings'.
601 break;
602 Canonized.replace(i, 1, ", ");
603 i += 2;
604 }
605
606 return Canonized;
607}
608
609Glib::ustring FontLister::system_fontspec(Glib::ustring const &fontspec)
610{
611 // Find what Pango thinks is the closest match.
612 Glib::ustring out = fontspec;
613
614 PangoFontDescription *descr = pango_font_description_from_string(fontspec.c_str());
615 auto res = FontFactory::get().Face(descr);
616 if (res) {
617 auto nFaceDesc = pango_font_describe(res->get_font());
618 out = sp_font_description_get_family(nFaceDesc);
619 }
620 pango_font_description_free(descr);
621
622 return out;
623}
624
625std::pair<Glib::ustring, Glib::ustring> FontLister::ui_from_fontspec(Glib::ustring const &fontspec) const
626{
627 PangoFontDescription *descr = pango_font_description_from_string(fontspec.c_str());
628 const gchar *family = pango_font_description_get_family(descr);
629 if (!family)
630 family = "sans-serif";
631 Glib::ustring Family = family;
632
633 // PANGO BUG...
634 // A font spec of Delicious, 500 Italic should result in a family of 'Delicious'
635 // and a style of 'Medium Italic'. It results instead with: a family of
636 // 'Delicious, 500' with a style of 'Medium Italic'. We chop of any weight numbers
637 // at the end of the family: match ",[1-9]00^".
638 Glib::RefPtr<Glib::Regex> weight = Glib::Regex::create(",[1-9]00$");
639 Family = weight->replace(Family, 0, "", Glib::Regex::MatchFlags::PARTIAL);
640
641 // Pango canonized strings remove space after comma between family names. Put it back.
642 size_t i = 0;
643 while ((i = Family.find(",", i)) != std::string::npos) {
644 Family.replace(i, 1, ", ");
645 i += 2;
646 }
647
648 pango_font_description_unset_fields(descr, PANGO_FONT_MASK_FAMILY);
649 gchar *style = pango_font_description_to_string(descr);
650 Glib::ustring Style = style;
651 pango_font_description_free(descr);
652 g_free(style);
653
654 return std::make_pair(Family, Style);
655}
656
657/* Now we do a song and dance to find the correct row as the row corresponding
658 * to the current_family may have changed. We can't simply search for the
659 * family name in the list since it can occur twice, once in the document
660 * font family part and once in the system font family part. Above we determined
661 * which part it is in.
662 */
663void FontLister::font_family_row_update(int start)
664{
665 if (this->current_family_row > -1 && start > -1) {
666 int length = this->font_list_store->children().size();
667 for (int i = 0; i < length; ++i) {
668 int row = i + start;
669 if (row >= length)
670 row -= length;
671 Gtk::TreePath path;
672 path.push_back(row);
673 if (auto iter = font_list_store->get_iter(path)) {
674 if (familyNamesAreEqual(current_family, (*iter)[font_list.family])) {
675 current_family_row = row;
676 break;
677 }
678 }
679 }
680 }
681}
682
683std::pair<Glib::ustring, Glib::ustring> FontLister::selection_update()
684{
685#ifdef DEBUG_FONT
686 std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl;
687 std::cout << "FontLister::selection_update: entrance" << std::endl;
688#endif
689 // Get fontspec from a selection, preferences, or thin air.
690 Glib::ustring fontspec;
691 SPStyle query(SP_ACTIVE_DOCUMENT);
692
693 // Directly from stored font specification.
694 int result =
696
697 //std::cout << " Attempting selected style" << std::endl;
698 if (result != QUERY_STYLE_NOTHING && query.font_specification.set) {
699 fontspec = query.font_specification.value();
700 //std::cout << " fontspec from query :" << fontspec << ":" << std::endl;
701 }
702
703 // From style
704 if (fontspec.empty()) {
705 //std::cout << " Attempting desktop style" << std::endl;
706 int rfamily = sp_desktop_query_style(SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTFAMILY);
707 int rstyle = sp_desktop_query_style(SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTSTYLE);
708
709 // Must have text in selection
710 if (rfamily != QUERY_STYLE_NOTHING && rstyle != QUERY_STYLE_NOTHING) {
711 fontspec = fontspec_from_style(&query);
712 }
713 //std::cout << " fontspec from style :" << fontspec << ":" << std::endl;
714 }
715
716 // From preferences
717 if (fontspec.empty()) {
719 if (prefs->getBool("/tools/text/usecurrent")) {
720 query.mergeCSS(sp_desktop_get_style(SP_ACTIVE_DESKTOP, true));
721 } else {
722 query.readFromPrefs("/tools/text");
723 }
724 fontspec = fontspec_from_style(&query);
725 }
726
727 // From thin air
728 if (fontspec.empty()) {
729 //std::cout << " Attempting thin air" << std::endl;
730 fontspec = current_family + ", " + current_style;
731 //std::cout << " fontspec from thin air :" << fontspec << ":" << std::endl;
732 }
733
734 // Need to update font family row too
735 // Consider the count of document fonts before setting the start point
736 int font_data_size = add_document_fonts_at_top(SP_ACTIVE_DOCUMENT);
737 font_family_row_update(font_data_size);
738
739 std::pair<Glib::ustring, Glib::ustring> ui = ui_from_fontspec(fontspec);
740 set_font_family(ui.first);
741 set_font_style(ui.second);
742
743#ifdef DEBUG_FONT
744 std::cout << " family_row: :" << current_family_row << ":" << std::endl;
745 std::cout << " family: :" << current_family << ":" << std::endl;
746 std::cout << " style: :" << current_style << ":" << std::endl;
747 std::cout << "FontLister::selection_update: exit" << std::endl;
748 std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl;
749#endif
750
751 emit_update();
752
753 return std::make_pair(current_family, current_style);
754}
755
756
757// Set fontspec. If check is false, best style match will not be done.
758void FontLister::set_fontspec(Glib::ustring const &new_fontspec, bool /*check*/)
759{
760 auto const &[new_family, new_style] = ui_from_fontspec(new_fontspec);
761
762#ifdef DEBUG_FONT
763 std::cout << "FontLister::set_fontspec: family: " << new_family
764 << " style:" << new_style << std::endl;
765#endif
766
767 set_font_family(new_family, false, false);
768 set_font_style(new_style, false);
769
770 emit_update();
771}
772
773
774// TODO: use to determine font-selector best style
775// TODO: create new function new_font_family(Gtk::TreeModel::iterator iter)
776std::pair<Glib::ustring, Glib::ustring> FontLister::new_font_family(Glib::ustring const &new_family, bool /*check_style*/)
777{
778#ifdef DEBUG_FONT
779 std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl;
780 std::cout << "FontLister::new_font_family: " << new_family << std::endl;
781#endif
782
783 // No need to do anything if new family is same as old family.
784 if (familyNamesAreEqual(new_family, current_family)) {
785#ifdef DEBUG_FONT
786 std::cout << "FontLister::new_font_family: exit: no change in family." << std::endl;
787 std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl;
788#endif
789 return std::make_pair(current_family, current_style);
790 }
791
792 // We need to do two things:
793 // 1. Update style list for new family.
794 // 2. Select best valid style match to old style.
795
796 // For finding style list, use list of first family in font-family list.
797 std::shared_ptr<Styles> styles;
798 for (auto row : font_list_store->children()) {
799 if (familyNamesAreEqual(new_family, row[font_list.family])) {
800 auto row_styles = row.get_value(font_list.styles);
801 if (!row_styles) {
802 row_styles = std::make_shared<Styles>(FontFactory::get().GetUIStyles(row[font_list.pango_family]));
803 }
804 styles = std::move(row_styles);
805 break;
806 }
807 }
808
809 // Newly typed in font-family may not yet be in list... use default list.
810 // TODO: if font-family is list, check if first family in list is on system
811 // and set style accordingly.
812 if (!styles) {
813 styles = default_styles;
814 }
815
816 // Update style list.
817 style_list_store->freeze_notify();
818 style_list_store->clear();
819
820 for (auto const &style : *styles) {
821 auto row = *style_list_store->append();
822 row[font_style_list.cssStyle] = style.css_name;
823 row[font_style_list.displayStyle] = style.display_name;
824 }
825
826 style_list_store->thaw_notify();
827
828 // Find best match to the style from the old font-family to the
829 // styles available with the new font.
830 // TODO: Maybe check if an exact match exists before using Pango.
831 Glib::ustring best_style = get_best_style_match(new_family, current_style);
832
833#ifdef DEBUG_FONT
834 std::cout << "FontLister::new_font_family: exit: " << new_family << " " << best_style << std::endl;
835 std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl;
836#endif
837 return std::make_pair(new_family, best_style);
838}
839
840void FontLister::set_dragging_family(const Glib::ustring &new_family)
841{
842 dragging_family = new_family;
843}
844
845std::pair<Glib::ustring, Glib::ustring> FontLister::set_font_family(Glib::ustring const &new_family, bool const check_style,
846 bool emit)
847{
848
849#ifdef DEBUG_FONT
850 std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl;
851 std::cout << "FontLister::set_font_family: " << new_family << std::endl;
852#endif
853
854 std::pair<Glib::ustring, Glib::ustring> ui = new_font_family(new_family, check_style);
855 current_family = ui.first;
856 current_style = ui.second;
857
858#ifdef DEBUG_FONT
859 std::cout << " family_row: :" << current_family_row << ":" << std::endl;
860 std::cout << " family: :" << current_family << ":" << std::endl;
861 std::cout << " style: :" << current_style << ":" << std::endl;
862 std::cout << "FontLister::set_font_family: end" << std::endl;
863 std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl;
864#endif
865 if (emit) {
866 emit_update();
867 }
868 return ui;
869}
870
871
872std::pair<Glib::ustring, Glib::ustring> FontLister::set_font_family(int row, bool check_style, bool emit)
873{
874
875#ifdef DEBUG_FONT
876 std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl;
877 std::cout << "FontLister::set_font_family( row ): " << row << std::endl;
878#endif
879
880 current_family_row = row;
881 Gtk::TreePath path;
882 path.push_back(row);
883 Glib::ustring new_family = current_family;
884 if (auto iter = font_list_store->get_iter(path)) {
885 new_family = (*iter)[font_list.family];
886 }
887
888 std::pair<Glib::ustring, Glib::ustring> ui = set_font_family(new_family, check_style, emit);
889
890#ifdef DEBUG_FONT
891 std::cout << "FontLister::set_font_family( row ): end" << std::endl;
892 std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl;
893#endif
894 return ui;
895}
896
897
898void FontLister::set_font_style(Glib::ustring new_style, bool emit)
899{
900// TODO: Validate input using Pango. If Pango doesn't recognize a style it will
901// attach the "invalid" style to the font-family.
902
903#ifdef DEBUG_FONT
904 std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl;
905 std::cout << "FontLister:set_font_style: " << new_style << std::endl;
906#endif
907
908 current_style = std::move(new_style);
909
910#ifdef DEBUG_FONT
911 std::cout << " family: " << current_family << std::endl;
912 std::cout << " style: " << current_style << std::endl;
913 std::cout << "FontLister::set_font_style: end" << std::endl;
914 std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl;
915#endif
916 if (emit) {
917 emit_update();
918 }
919}
920
921
922// We do this ourselves as we can't rely on FontFactory.
923void FontLister::fill_css(SPCSSAttr *css, Glib::ustring fontspec)
924{
925 if (fontspec.empty()) {
926 fontspec = get_fontspec();
927 }
928
929 std::pair<Glib::ustring, Glib::ustring> ui = ui_from_fontspec(fontspec);
930
931 Glib::ustring family = ui.first;
932
933
934 // Font spec is single quoted... for the moment
935 Glib::ustring fontspec_quoted(fontspec);
936 css_quote(fontspec_quoted);
937 sp_repr_css_set_property(css, "-inkscape-font-specification", fontspec_quoted.c_str());
938
939 // Font families needs to be properly quoted in CSS (used unquoted in font-lister)
940 css_font_family_quote(family);
941 sp_repr_css_set_property(css, "font-family", family.c_str());
942
943 PangoFontDescription *desc = pango_font_description_from_string(fontspec.c_str());
944 PangoWeight weight = pango_font_description_get_weight(desc);
945 switch (weight) {
946 case PANGO_WEIGHT_THIN:
947 sp_repr_css_set_property(css, "font-weight", "100");
948 break;
949 case PANGO_WEIGHT_ULTRALIGHT:
950 sp_repr_css_set_property(css, "font-weight", "200");
951 break;
952 case PANGO_WEIGHT_LIGHT:
953 sp_repr_css_set_property(css, "font-weight", "300");
954 break;
955 case PANGO_WEIGHT_SEMILIGHT:
956 sp_repr_css_set_property(css, "font-weight", "350");
957 break;
958 case PANGO_WEIGHT_BOOK:
959 sp_repr_css_set_property(css, "font-weight", "380");
960 break;
961 case PANGO_WEIGHT_NORMAL:
962 sp_repr_css_set_property(css, "font-weight", "normal");
963 break;
964 case PANGO_WEIGHT_MEDIUM:
965 sp_repr_css_set_property(css, "font-weight", "500");
966 break;
967 case PANGO_WEIGHT_SEMIBOLD:
968 sp_repr_css_set_property(css, "font-weight", "600");
969 break;
970 case PANGO_WEIGHT_BOLD:
971 sp_repr_css_set_property(css, "font-weight", "bold");
972 break;
973 case PANGO_WEIGHT_ULTRABOLD:
974 sp_repr_css_set_property(css, "font-weight", "800");
975 break;
976 case PANGO_WEIGHT_HEAVY:
977 sp_repr_css_set_property(css, "font-weight", "900");
978 break;
979 case PANGO_WEIGHT_ULTRAHEAVY:
980 sp_repr_css_set_property(css, "font-weight", "1000");
981 break;
982 default:
983 // Pango can report arbitrary numeric weights, not just those values
984 // with corresponding convenience enums
985 if (weight > 0 && weight < 1000) {
986 sp_repr_css_set_property(css, "font-weight", std::to_string(weight).c_str());
987 }
988 else {
989 g_message("Pango reported font weight of %d ignored (font: '%s').", weight, fontspec.c_str());
990 }
991 break;
992 }
993
994 PangoStyle style = pango_font_description_get_style(desc);
995 switch (style) {
996 case PANGO_STYLE_NORMAL:
997 sp_repr_css_set_property(css, "font-style", "normal");
998 break;
999 case PANGO_STYLE_OBLIQUE:
1000 sp_repr_css_set_property(css, "font-style", "oblique");
1001 break;
1002 case PANGO_STYLE_ITALIC:
1003 sp_repr_css_set_property(css, "font-style", "italic");
1004 break;
1005 }
1006
1007 PangoStretch stretch = pango_font_description_get_stretch(desc);
1008 switch (stretch) {
1009 case PANGO_STRETCH_ULTRA_CONDENSED:
1010 sp_repr_css_set_property(css, "font-stretch", "ultra-condensed");
1011 break;
1012 case PANGO_STRETCH_EXTRA_CONDENSED:
1013 sp_repr_css_set_property(css, "font-stretch", "extra-condensed");
1014 break;
1015 case PANGO_STRETCH_CONDENSED:
1016 sp_repr_css_set_property(css, "font-stretch", "condensed");
1017 break;
1018 case PANGO_STRETCH_SEMI_CONDENSED:
1019 sp_repr_css_set_property(css, "font-stretch", "semi-condensed");
1020 break;
1021 case PANGO_STRETCH_NORMAL:
1022 sp_repr_css_set_property(css, "font-stretch", "normal");
1023 break;
1024 case PANGO_STRETCH_SEMI_EXPANDED:
1025 sp_repr_css_set_property(css, "font-stretch", "semi-expanded");
1026 break;
1027 case PANGO_STRETCH_EXPANDED:
1028 sp_repr_css_set_property(css, "font-stretch", "expanded");
1029 break;
1030 case PANGO_STRETCH_EXTRA_EXPANDED:
1031 sp_repr_css_set_property(css, "font-stretch", "extra-expanded");
1032 break;
1033 case PANGO_STRETCH_ULTRA_EXPANDED:
1034 sp_repr_css_set_property(css, "font-stretch", "ultra-expanded");
1035 break;
1036 }
1037
1038 PangoVariant variant = pango_font_description_get_variant(desc);
1039 switch (variant) {
1040 case PANGO_VARIANT_NORMAL:
1041 sp_repr_css_set_property(css, "font-variant", "normal");
1042 break;
1043 case PANGO_VARIANT_SMALL_CAPS:
1044 sp_repr_css_set_property(css, "font-variant", "small-caps");
1045 break;
1046 }
1047
1048 // Convert Pango variations string to CSS format
1049 const char* str = pango_font_description_get_variations(desc);
1050
1051 std::string variations;
1052
1053 if (str) {
1054
1055 std::vector<Glib::ustring> tokens = Glib::Regex::split_simple(",", str);
1056
1057 Glib::RefPtr<Glib::Regex> regex = Glib::Regex::create("(\\w{4})=([-+]?\\d*\\.?\\d+([eE][-+]?\\d+)?)");
1058 Glib::MatchInfo matchInfo;
1059 for (auto const &token: tokens) {
1060 regex->match(token, matchInfo);
1061 if (matchInfo.matches()) {
1062 variations += "'";
1063 variations += matchInfo.fetch(1).raw();
1064 variations += "' ";
1065 variations += matchInfo.fetch(2).raw();
1066 variations += ", ";
1067 }
1068 }
1069 if (variations.length() >= 2) { // Remove last comma/space
1070 variations.pop_back();
1071 variations.pop_back();
1072 }
1073 }
1074
1075 if (!variations.empty()) {
1076 sp_repr_css_set_property(css, "font-variation-settings", variations.c_str());
1077 } else {
1078 sp_repr_css_unset_property(css, "font-variation-settings" );
1079 }
1080 pango_font_description_free(desc);
1081}
1082
1083Glib::ustring FontLister::fontspec_from_style(SPStyle *style) const
1084{
1086 Glib::ustring fontspec = pango_font_description_to_string( descr );
1087 pango_font_description_free(descr);
1088
1089 //std::cout << "FontLister:fontspec_from_style: " << fontspec << std::endl;
1090
1091 return fontspec;
1092}
1093
1094Gtk::TreeModel::Row FontLister::get_row_for_font(Glib::ustring const &family)
1095{
1096 for (auto const &row : font_list_store->children()) {
1097 if (familyNamesAreEqual(family, row[font_list.family])) {
1098 return row;
1099 }
1100 }
1101
1102 throw Exception::FAMILY_NOT_FOUND;
1103}
1104
1105Gtk::TreePath FontLister::get_path_for_font(Glib::ustring const &family)
1106{
1107 return font_list_store->get_path(get_row_for_font(family).get_iter());
1108}
1109
1110bool FontLister::is_path_for_font(Gtk::TreePath path, Glib::ustring family)
1111{
1112 if (auto iter = font_list_store->get_iter(path)) {
1113 return familyNamesAreEqual(family, (*iter)[font_list.family]);
1114 }
1115
1116 return false;
1117}
1118
1119Gtk::TreeModel::Row FontLister::get_row_for_style(Glib::ustring const &style)
1120{
1121 for (auto const &row : font_list_store->children()) {
1122 if (familyNamesAreEqual(style, row[font_style_list.cssStyle])) {
1123 return row;
1124 }
1125 }
1126
1127 throw Exception::STYLE_NOT_FOUND;
1128}
1129
1131{
1132 // Weight: multiples of 100
1133 gint distance = abs(pango_font_description_get_weight(a) -
1134 pango_font_description_get_weight(b));
1135
1136 distance += 10000 * abs(pango_font_description_get_stretch(a) -
1137 pango_font_description_get_stretch(b));
1138
1139 PangoStyle style_a = pango_font_description_get_style(a);
1140 PangoStyle style_b = pango_font_description_get_style(b);
1141 if (style_a != style_b) {
1142 if ((style_a == PANGO_STYLE_OBLIQUE && style_b == PANGO_STYLE_ITALIC) ||
1143 (style_b == PANGO_STYLE_OBLIQUE && style_a == PANGO_STYLE_ITALIC)) {
1144 distance += 1000; // Oblique and italic are almost the same
1145 } else {
1146 distance += 100000; // Normal vs oblique/italic, not so similar
1147 }
1148 }
1149
1150 // Normal vs small-caps
1151 distance += 1000000 * abs(pango_font_description_get_variant(a) -
1152 pango_font_description_get_variant(b));
1153 return distance;
1154}
1155
1156// This is inspired by pango_font_description_better_match, but that routine
1157// always returns false if variant or stretch are different. This means, for
1158// example, that PT Sans Narrow with style Bold Condensed is never matched
1159// to another font-family with Bold style.
1161{
1162 if (old_desc == nullptr)
1163 return true;
1164 if (new_desc == nullptr)
1165 return false;
1166
1167 int old_distance = compute_distance(target, old_desc);
1168 int new_distance = compute_distance(target, new_desc);
1169 //std::cout << "font_description_better_match: old: " << old_distance << std::endl;
1170 //std::cout << " new: " << new_distance << std::endl;
1171
1172 return (new_distance < old_distance);
1173}
1174
1175// void
1176// font_description_dump( PangoFontDescription* target ) {
1177// std::cout << " Font: " << pango_font_description_to_string( target ) << std::endl;
1178// std::cout << " style: " << pango_font_description_get_style( target ) << std::endl;
1179// std::cout << " weight: " << pango_font_description_get_weight( target ) << std::endl;
1180// std::cout << " variant: " << pango_font_description_get_variant( target ) << std::endl;
1181// std::cout << " stretch: " << pango_font_description_get_stretch( target ) << std::endl;
1182// std::cout << " gravity: " << pango_font_description_get_gravity( target ) << std::endl;
1183// }
1184
1185/* Returns style string */
1186// TODO: Remove or turn into function to be used by new_font_family.
1187Glib::ustring FontLister::get_best_style_match(Glib::ustring const &family, Glib::ustring const &target_style)
1188{
1189
1190#ifdef DEBUG_FONT
1191 std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl;
1192 std::cout << "FontLister::get_best_style_match: " << family << " : " << target_style << std::endl;
1193#endif
1194
1195 Glib::ustring fontspec = family + ", " + target_style;
1196
1197 Gtk::TreeModel::Row row;
1198 try {
1199 row = get_row_for_font(family);
1200 } catch (Exception) {
1201 std::cerr << "FontLister::get_best_style_match(): can't find family: " << family.raw() << std::endl;
1202 return target_style;
1203 }
1204
1205 PangoFontDescription *target = pango_font_description_from_string(fontspec.c_str());
1206 PangoFontDescription *best = nullptr;
1207
1208 //font_description_dump( target );
1209
1210 auto styles = default_styles;
1211 if (row[font_list.onSystem] && !row.get_value(font_list.styles)) {
1212 row[font_list.styles] = std::make_shared<Styles>(FontFactory::get().GetUIStyles(row[font_list.pango_family]));
1213 styles = row[font_list.styles];
1214 }
1215
1216 for (auto const &style : *styles) {
1217 Glib::ustring fontspec = family + ", " + style.css_name;
1218 PangoFontDescription *candidate = pango_font_description_from_string(fontspec.c_str());
1219 //font_description_dump( candidate );
1220 //std::cout << " " << font_description_better_match( target, best, candidate ) << std::endl;
1221 if (font_description_better_match(target, best, candidate)) {
1222 pango_font_description_free(best);
1223 best = candidate;
1224 //std::cout << " ... better: " << std::endl;
1225 } else {
1226 pango_font_description_free(candidate);
1227 //std::cout << " ... not better: " << std::endl;
1228 }
1229 }
1230
1231 Glib::ustring best_style = target_style;
1232 if (best) {
1233 pango_font_description_unset_fields(best, PANGO_FONT_MASK_FAMILY);
1234 best_style = pango_font_description_to_string(best);
1235 }
1236
1237 if (target)
1238 pango_font_description_free(target);
1239 if (best)
1240 pango_font_description_free(best);
1241
1242
1243#ifdef DEBUG_FONT
1244 std::cout << " Returning: " << best_style << std::endl;
1245 std::cout << "FontLister::get_best_style_match: exit" << std::endl;
1246 std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl;
1247#endif
1248 return best_style;
1249}
1250
1251} // namespace Inkscape
1252
1253// Helper functions
1254
1255// Separator function (if true, a separator will be drawn)
1256bool font_lister_separator_func(Glib::RefPtr<Gtk::TreeModel> const &/*model*/,
1257 Gtk::TreeModel::const_iterator const &iter)
1258{
1259
1260 // Of what use is 'model', can we avoid using font_lister?
1262 auto row = *iter;
1263 Glib::ustring entry = row[font_lister->font_list.family];
1264 return entry == "#";
1265}
1266
1267// do nothing on load initialy
1268void font_lister_cell_data_func(Gtk::CellRenderer * /*renderer*/,
1269 Gtk::TreeModel::const_iterator const & /*iter*/)
1270{
1271}
1272
1273// Draw system fonts in dark blue, missing fonts with red strikeout.
1274// Used by both FontSelector and Text toolbar.
1275void font_lister_cell_data_func_markup(Gtk::CellRenderer * const renderer,
1276 Gtk::TreeModel::const_iterator const &iter)
1277{
1279 Glib::ustring markup = font_lister->get_font_family_markup(iter);
1280 renderer->set_property("markup", markup);
1281}
1282
1283// Needed until Text toolbar updated
1284void font_lister_cell_data_func2(Gtk::CellRenderer &cell,
1285 Gtk::TreeModel::const_iterator const &iter,
1286 bool with_markup)
1287{
1288 auto font_lister = Inkscape::FontLister::get_instance();
1289 Glib::ustring family = (*iter)[font_lister->font_list.family];
1290 bool onSystem = (*iter)[font_lister->font_list.onSystem];
1291 auto family_escaped = g_markup_escape_text(family.c_str(), -1);
1292 auto prefs = Inkscape::Preferences::get();
1293 bool dark = prefs->getBool("/theme/darkTheme", false);
1294 Glib::ustring markup;
1295
1296 if (!onSystem) {
1297 markup = "<span font-weight='bold'>";
1298
1299 /* See if font-family on system */
1300 std::vector<Glib::ustring> tokens = Glib::Regex::split_simple("\\s*,\\s*", family);
1301 for (auto const &token : tokens) {
1303
1304 if (found) {
1305 markup += g_markup_escape_text(token.c_str(), -1);
1306 markup += ", ";
1307 } else {
1308 if (dark) {
1309 markup += "<span strikethrough='true' strikethrough_color='salmon'>";
1310 } else {
1311 markup += "<span strikethrough='true' strikethrough_color='red'>";
1312 }
1313 markup += g_markup_escape_text(token.c_str(), -1);
1314 markup += "</span>";
1315 markup += ", ";
1316 }
1317 }
1318 // Remove extra comma and space from end.
1319 if (markup.size() >= 2) {
1320 markup.resize(markup.size() - 2);
1321 }
1322 markup += "</span>";
1323 // std::cout << markup << std::endl;
1324 } else {
1325 markup = family_escaped;
1326 }
1327
1328 int show_sample = prefs->getInt("/tools/text/show_sample_in_list", 1);
1329 if (show_sample) {
1330 Glib::ustring sample = prefs->getString("/tools/text/font_sample");
1331 gchar* sample_escaped = g_markup_escape_text(sample.data(), -1);
1332 if (with_markup) {
1333 markup += " <span alpha='55%";
1334#if PANGO_VERSION_CHECK(1,50,0)
1335 markup += "' font-size='100%' line-height='0.6' font_family='";
1336#else
1337 markup += "' font_family='";
1338#endif
1339 markup += family_escaped;
1340 } else {
1341 markup += " <span alpha='1";
1342 }
1343 markup += "'>";
1344 markup += sample_escaped;
1345 markup += "</span>";
1346 g_free(sample_escaped);
1347 }
1348
1349 cell.set_property("markup", markup);
1350 g_free(family_escaped);
1351}
1352
1353// Draw Face name with face style.
1354void font_lister_style_cell_data_func(Gtk::CellRenderer *const renderer,
1355 Gtk::TreeModel::const_iterator const &iter)
1356{
1358 auto const &row = *iter;
1359
1360 Glib::ustring family = font_lister->get_font_family();
1361 Glib::ustring style = row[font_lister->font_style_list.cssStyle];
1362
1363 Glib::ustring style_escaped = Glib::Markup::escape_text( style );
1364 Glib::ustring font_desc = family + ", " + style;
1365 Glib::ustring markup;
1366
1367 markup = "<span font='" + font_desc + "'>" + style_escaped + "</span>";
1368 // std::cout << " markup: " << markup.raw() << std::endl;
1369
1370 renderer->set_property("markup", markup);
1371}
1372
1373/*
1374 Local Variables:
1375 mode:c++
1376 c-file-style:"stroustrup"
1377 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1378 indent-tabs-mode:nil
1379 fill-column:99
1380 End:
1381*/
1382// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 :
_PangoFontDescription PangoFontDescription
Definition Layout-TNG.h:44
double distance(Shape const *s, Geom::Point const &p)
Definition Shape.cpp:2136
std::shared_ptr< FontInstance > Face(PangoFontDescription *descr, bool canFail=true)
void refreshConfig()
The fontsize used as workaround for hinting.
std::map< std::string, PangoFontFamily * > GetUIFamilies()
std::set< Glib::ustring > const & get_fonts() const
static DocumentFonts * get()
static FontCollections * get()
std::set< Glib::ustring > const & get_fonts(Glib::ustring const &name, bool is_system=false) const
This class enumerates fonts using libnrtype into reusable data stores and allows for random access to...
Definition font-lister.h:84
Glib::ustring get_font_family_markup(Gtk::TreeModel::const_iterator const &iter) const
Get markup for font-family.
std::pair< bool, std::string > get_font_count_label() const
void insert_font_family(Glib::ustring const &new_family)
Inserts a font family or font-fallback list (for use when not already in document or on system).
bool find_string_case_insensitive(std::string const &text, std::string const &pat)
Takes a hand written font spec and returns a Pango generated one in standard form.
int get_font_families_size() const
Glib::RefPtr< Gtk::ListStore > style_list_store
Glib::RefPtr< Gtk::ListStore > font_list_store
std::shared_ptr< Styles > default_styles
If a font-family is not on system, this list of styles is used.
std::vector< StyleNames > Styles
Definition font-lister.h:92
sigc::signal< void()> new_fonts_signal
std::map< std::string, PangoFontFamily * > pango_family_map
The list of fonts, sorted by the order they will appear in the UI.
void init_font_families(int group_offset=-1, int group_size=-1)
int add_document_fonts_at_top(SPDocument *document)
bool font_installed_on_system(Glib::ustring const &font) const
void show_results(Glib::ustring const &search_text)
static Inkscape::FontLister * get_instance()
FontStyleListClass font_style_list
FontListClass font_list
Glib::ustring const & get_font_family() const
sigc::signal< void()> update_signal
Preference storage class.
Definition preferences.h:61
bool getBool(Glib::ustring const &pref_path, bool def=false)
Retrieve a Boolean value.
Glib::ustring getString(Glib::ustring const &pref_path, Glib::ustring const &def="")
Retrieve an UTF-8 string.
static Preferences * get()
Access the singleton Preferences object.
int getInt(Glib::ustring const &pref_path, int def=0)
Retrieve an integer.
static RecentlyUsedFonts * get()
std::list< Glib::ustring > const & get_fonts() const
static FontFactory & get(Args &&... args)
Definition statics.h:153
virtual NodeType type() const =0
Get the type of the node.
Typed SVG document implementation.
Definition document.h:101
SPRoot * getRoot()
Returns our SPRoot.
Definition document.h:200
SPObject is an abstract base class of all of the document nodes at the SVG document level.
Definition sp-object.h:160
char const * getId() const
Returns the objects current ID string.
SPStyle * style
Represents the style properties, whether from presentation attributes, the style attribute,...
Definition sp-object.h:248
Inkscape::XML::Node * getRepr()
Returns the XML representation of tree.
ChildrenList children
Definition sp-object.h:907
An SVG style object.
Definition style.h:45
void mergeCSS(SPCSSAttr *css)
Definition style.cpp:859
T< SPAttr::INKSCAPE_FONT_SPEC, SPIString > font_specification
Full font name, as FontFactory::ConstructFontSpecification would give, for internal use.
Definition style.h:124
void readFromPrefs(Glib::ustring const &path)
Read style properties from preferences.
Definition style.cpp:625
RootCluster root
std::shared_ptr< Css const > css
Css & result
SPCSSAttr * sp_desktop_get_style(SPDesktop *desktop, bool with_text)
Return the desktop's current style.
int sp_desktop_query_style(SPDesktop *desktop, SPStyle *style, int property)
Query the subselection (if any) or selection on the given desktop for the given property,...
@ QUERY_STYLE_PROPERTY_FONT_SPECIFICATION
@ QUERY_STYLE_PROPERTY_FONTSTYLE
@ QUERY_STYLE_PROPERTY_FONTFAMILY
@ QUERY_STYLE_NOTHING
Editable view implementation.
PangoFontDescription * ink_font_description_from_style(SPStyle const *style)
char const * sp_font_description_get_family(PangoFontDescription const *fontDescr)
TODO: insert short description here.
The data describing a single loaded font.
bool font_lister_separator_func(Glib::RefPtr< Gtk::TreeModel > const &, Gtk::TreeModel::const_iterator const &iter)
bool familyNamesAreEqual(const Glib::ustring &a, const Glib::ustring &b)
void font_lister_cell_data_func_markup(Gtk::CellRenderer *const renderer, Gtk::TreeModel::const_iterator const &iter)
void font_lister_cell_data_func(Gtk::CellRenderer *, Gtk::TreeModel::const_iterator const &)
void font_lister_style_cell_data_func(Gtk::CellRenderer *const renderer, Gtk::TreeModel::const_iterator const &iter)
void font_lister_cell_data_func2(Gtk::CellRenderer &cell, Gtk::TreeModel::const_iterator const &iter, bool with_markup)
Font selection widgets.
Geom::Point start
Glib::ustring label
Geom::Point end
@ TEXT_NODE
Text node, e.g. "Some text" in <group>Some text</group> is represented by a text node.
Helper class to stream background task notifications as a series of messages.
static int compute_distance(PangoFontDescription const *a, PangoFontDescription const *b)
Glib::ustring get_fontspec(const Glib::ustring &family, const Glib::ustring &face, const Glib::ustring &variations)
gboolean font_description_better_match(PangoFontDescription *target, PangoFontDescription *old_desc, PangoFontDescription *new_desc)
const std::string DOCUMENT_FONTS
const std::string RECENTLY_USED_FONTS
Singleton class to access the preferences file in a convenient way.
unsigned long weight
Definition quantize.cpp:37
Ocnode * child[8]
Definition quantize.cpp:33
void sp_repr_css_unset_property(SPCSSAttr *css, gchar const *name)
Set a style property to "inkscape:unset".
Definition repr-css.cpp:201
void sp_repr_css_set_property(SPCSSAttr *css, gchar const *name, gchar const *value)
Set a style property to a new value (e.g.
Definition repr-css.cpp:190
C facade to Inkscape::XML::Node.
TODO: insert short description here.
TODO: insert short description here.
SPRoot: SVG <svg> implementation.
TODO: insert short description here.
SVG <tref> implementation, see sp-tref.cpp.
TODO: insert short description here.
Gtk::TreeModelColumn< std::shared_ptr< Styles > > styles
Styles for each family name.
Gtk::TreeModelColumn< Glib::ustring > family
Family name.
Gtk::TreeModelColumn< PangoFontFamily * > pango_family
Not actually a column.
Gtk::TreeModelColumn< bool > onSystem
Whether font is on system.
Gtk::TreeModelColumn< Glib::ustring > cssStyle
Column containing the styles in CSS/Pango format.
Gtk::TreeModelColumn< Glib::ustring > displayStyle
Column containing the styles as Font designer used.
void css_quote(Glib::ustring &val)
Quote and/or escape string for writing to CSS, changing strings in place.
Definition style.cpp:1648
void css_font_family_quote(Glib::ustring &val)
Quote font names in font-family lists, changing string in place.
Definition style.cpp:1687