diff options
| author | Tavmjong Bah <tavmjong@free.fr> | 2018-06-11 11:25:39 +0000 |
|---|---|---|
| committer | Tavmjong Bah <tavmjong@free.fr> | 2018-06-11 11:25:39 +0000 |
| commit | 0fd518beb13ed45448492ecc782825412f2cff01 (patch) | |
| tree | b0d98e45c39028053fa30d31c431b7555de51c41 /src | |
| parent | Migrated object-test and sp-gradient-test to gtest (diff) | |
| download | inkscape-0fd518beb13ed45448492ecc782825412f2cff01.tar.gz inkscape-0fd518beb13ed45448492ecc782825412f2cff01.zip | |
Improvements to the Font Features dialog. Better OpenType coverage.
Diffstat (limited to 'src')
| -rw-r--r-- | src/libnrtype/FontInstance.cpp | 3 | ||||
| -rw-r--r-- | src/libnrtype/OpenTypeUtil.cpp | 136 | ||||
| -rw-r--r-- | src/libnrtype/OpenTypeUtil.h | 18 | ||||
| -rw-r--r-- | src/libnrtype/font-instance.h | 9 | ||||
| -rw-r--r-- | src/ui/widget/font-variants.cpp | 202 |
5 files changed, 223 insertions, 145 deletions
diff --git a/src/libnrtype/FontInstance.cpp b/src/libnrtype/FontInstance.cpp index f8ee41108..667478924 100644 --- a/src/libnrtype/FontInstance.cpp +++ b/src/libnrtype/FontInstance.cpp @@ -211,8 +211,7 @@ void font_instance::InitTheFace() #ifndef USE_PANGO_WIN32 - readOpenTypeGsubTable( theFace, openTypeTables, openTypeStylistic, - openTypeLigatures, openTypeNumeric ); + readOpenTypeGsubTable( theFace, openTypeTables ); readOpenTypeFvarAxes( theFace, openTypeVarAxes ); #if PANGO_VERSION_CHECK(1,41,1) diff --git a/src/libnrtype/OpenTypeUtil.cpp b/src/libnrtype/OpenTypeUtil.cpp index 9b7762d67..ffe0807b0 100644 --- a/src/libnrtype/OpenTypeUtil.cpp +++ b/src/libnrtype/OpenTypeUtil.cpp @@ -39,19 +39,31 @@ Glib::ustring extract_tag( guint32 *tag ) { } +void get_glyphs( hb_font_t* font, hb_set_t* set, Glib::ustring& characters) { + + // There is a unicode to glyph mapping function but not the inverse! + hb_codepoint_t codepoint = -1; + while (hb_set_next (set, &codepoint)) { + for (hb_codepoint_t unicode_i = 0; unicode_i < 0xffff; ++unicode_i) { + hb_codepoint_t glyph = 0; + hb_font_get_nominal_glyph (font, unicode_i, &glyph); + if (glyph == codepoint) { + characters += (gunichar)unicode_i; + continue; + } + } + } +} + // Make a list of all tables found in the GSUB // This list includes all tables regardless of script or language. void readOpenTypeGsubTable (const FT_Face ft_face, - std::map<Glib::ustring, int>& tables, - std::map<Glib::ustring, Glib::ustring>& stylistic, - std::map<Glib::ustring, Glib::ustring>& ligatures, - std::map<Glib::ustring, Glib::ustring>& numerical + std::map<Glib::ustring, OTSubstitution>& tables ) { + // std::cout << "readOpenTypeGsubTable: Entrance: " + // << (ft_face->family_name?ft_face->family_name:"null") << std::endl; tables.clear(); - stylistic.clear(); - ligatures.clear(); - numerical.clear(); // Use Harfbuzz, Pango's equivalent calls are deprecated. auto const hb_face = hb_ft_face_create(ft_face, NULL); @@ -64,6 +76,7 @@ void readOpenTypeGsubTable (const FT_Face ft_face, hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GSUB, 0, &script_count, hb_scripts); for(unsigned int i = 0; i < script_count; ++i) { + // std::cout << " Script: " << extract_tag(&hb_scripts[i]) << std::endl; auto language_count = hb_ot_layout_script_get_language_tags(hb_face, HB_OT_TAG_GSUB, i, 0, NULL, NULL); if(language_count > 0) { @@ -71,12 +84,14 @@ void readOpenTypeGsubTable (const FT_Face ft_face, hb_ot_layout_script_get_language_tags(hb_face, HB_OT_TAG_GSUB, i, 0, &language_count, hb_languages); for(unsigned int j = 0; j < language_count; ++j) { + // std::cout << " Language: " << extract_tag(&hb_languages[j]) << std::endl; auto feature_count = hb_ot_layout_language_get_feature_tags(hb_face, HB_OT_TAG_GSUB, i, j, 0, NULL, NULL); auto const hb_features = g_new(hb_tag_t, feature_count + 1); hb_ot_layout_language_get_feature_tags(hb_face, HB_OT_TAG_GSUB, i, j, 0, &feature_count, hb_features); for(unsigned int k = 0; k < feature_count; ++k) { - ++(tables[ extract_tag(&hb_features[k])]); + // std::cout << " Feature: " << extract_tag(&hb_features[k]) << std::endl; + tables[ extract_tag(&hb_features[k])]; } g_free(hb_features); @@ -87,6 +102,7 @@ void readOpenTypeGsubTable (const FT_Face ft_face, } else { // Even if no languages are present there is still the default. + // std::cout << " Language: " << " (dflt)" << std::endl; auto feature_count = hb_ot_layout_language_get_feature_tags(hb_face, HB_OT_TAG_GSUB, i, HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX, 0, NULL, NULL); @@ -96,7 +112,8 @@ void readOpenTypeGsubTable (const FT_Face ft_face, 0, &feature_count, hb_features); for(unsigned int k = 0; k < feature_count; ++k) { - ++(tables[ extract_tag(&hb_features[k])]); + // std::cout << " Feature: " << extract_tag(&hb_features[k]) << std::endl; + tables[ extract_tag(&hb_features[k])]; } g_free(hb_features); @@ -116,6 +133,7 @@ void readOpenTypeGsubTable (const FT_Face ft_face, // Only look at style substitution tables ('salt', 'ss01', etc. but not 'ssty'). // Also look at character substitution tables ('cv01', etc.). bool style = + table.first == "case" /* Case-Sensitive Forms */ || table.first == "salt" /* Stylistic Alternatives */ || table.first == "swsh" /* Swash */ || table.first == "cwsh" /* Contextual Swash */ || @@ -152,6 +170,7 @@ void readOpenTypeGsubTable (const FT_Face ft_face, table.first[3]), &feature_index ) ) { + // std::cout << "Table: " << table.first << std::endl; // std::cout << " Found feature, number: " << feature_index << std::endl; unsigned int lookup_indexes[32]; unsigned int lookup_count = 32; @@ -162,93 +181,56 @@ void readOpenTypeGsubTable (const FT_Face ft_face, lookup_indexes ); // std::cout << " Lookup count: " << count << " total: " << lookup_count << std::endl; - if (count > 0) { - hb_set_t* glyphs_before = NULL; // hb_set_create(); - hb_set_t* glyphs_input = hb_set_create(); // For stylistic - hb_set_t* glyphs_after = NULL; // hb_set_create(); - hb_set_t* glyphs_output = hb_set_create(); // For ligatures + hb_font_t *hb_font = hb_font_create (hb_face); // MOVE THIS OUT OF LOOPS? + + for (int i = 0; i < count; ++i) { + hb_set_t* glyphs_before = hb_set_create(); + hb_set_t* glyphs_input = hb_set_create(); + hb_set_t* glyphs_after = hb_set_create(); + hb_set_t* glyphs_output = hb_set_create(); - // For now, just look at first index hb_ot_layout_lookup_collect_glyphs (hb_face, HB_OT_TAG_GSUB, - lookup_indexes[0], + lookup_indexes[i], glyphs_before, glyphs_input, glyphs_after, glyphs_output ); - hb_font_t *hb_font = hb_font_create (hb_face); + // std::cout << " Populations: " + // << " " << hb_set_get_population (glyphs_before) + // << " " << hb_set_get_population (glyphs_input) + // << " " << hb_set_get_population (glyphs_after) + // << " " << hb_set_get_population (glyphs_output) + // << std::endl; // Without this, all functions return 0, etc. hb_ft_font_set_funcs (hb_font); - Glib::ustring unicode_characters; - - hb_codepoint_t codepoint = -1; - - if (style) { - while (hb_set_next (glyphs_input, &codepoint)) { - - // There is a unicode to glyph mapping function but not the inverse! - for (hb_codepoint_t unicode_i = 0; unicode_i < 0xffff; ++unicode_i) { - hb_codepoint_t glyph = 0; - hb_font_get_nominal_glyph (hb_font, unicode_i, &glyph); - if ( glyph == codepoint) { - unicode_characters += (gunichar)unicode_i; - continue; - } - } - } - stylistic[table.first] = unicode_characters; - } - - // Don't know how to extract all input glyphs... - // glyphs_input contains last input glyph, so just use output. - if (ligature) { - while (hb_set_next (glyphs_output, &codepoint)) { - - // There is a unicode to glyph mapping function but not the inverse! - for (hb_codepoint_t unicode_i = 0; unicode_i < 0xffff; ++unicode_i) { - hb_codepoint_t glyph = 0; - hb_font_get_nominal_glyph (hb_font, unicode_i, &glyph); - if ( glyph == codepoint) { - unicode_characters += (gunichar)unicode_i; - unicode_characters += " "; // Add space - continue; - } - } - } - ligatures[table.first] = unicode_characters; - } - - if (numeric) { - while (hb_set_next (glyphs_output, &codepoint)) { - - // There is a unicode to glyph mapping function but not the inverse! - for (hb_codepoint_t unicode_i = 0; unicode_i < 0xffff; ++unicode_i) { - hb_codepoint_t glyph = 0; - hb_font_get_nominal_glyph (hb_font, unicode_i, &glyph); - if ( glyph == codepoint) { - unicode_characters += (gunichar)unicode_i; - unicode_characters += " "; // Add space - continue; - } - } - } - numerical[table.first] = unicode_characters; - } + get_glyphs (hb_font, glyphs_before, tables[table.first].before); + get_glyphs (hb_font, glyphs_input, tables[table.first].input ); + get_glyphs (hb_font, glyphs_after, tables[table.first].after ); + get_glyphs (hb_font, glyphs_output, tables[table.first].output); + // std::cout << " Before: " << tables[table.first].before.c_str() << std::endl; + // std::cout << " Input: " << tables[table.first].input.c_str() << std::endl; + // std::cout << " After: " << tables[table.first].after.c_str() << std::endl; + // std::cout << " Output: " << tables[table.first].output.c_str() << std::endl; + + hb_set_destroy (glyphs_before); hb_set_destroy (glyphs_input); - hb_font_destroy (hb_font); - } + hb_set_destroy (glyphs_after); + hb_set_destroy (glyphs_output); + + } // End count (lookups) + + hb_font_destroy (hb_font); + } else { // std::cout << " Did not find '" << table.first << "'!" << std::endl; } } } - // for (auto table: res->openTypeSubstitutions) { - // std::cout << table.first << ": " << table.second << std::endl; - // } #else std::cerr << "Requires Harfbuzz 1.2.3 for visualizing alternative glyph OpenType tables. " << "Compiled with: " << HB_VERSION_STRING << "." << std::endl; diff --git a/src/libnrtype/OpenTypeUtil.h b/src/libnrtype/OpenTypeUtil.h index 9a792eb0e..0a249f123 100644 --- a/src/libnrtype/OpenTypeUtil.h +++ b/src/libnrtype/OpenTypeUtil.h @@ -18,6 +18,16 @@ * All three provide variable amounts of access to data. */ +// OpenType substitution +class OTSubstitution { +public: + OTSubstitution() {}; + Glib::ustring before; + Glib::ustring input; + Glib::ustring after; + Glib::ustring output; +}; + // An OpenType fvar axis. class OTVarAxis { public: @@ -53,11 +63,11 @@ inline FT_Fixed FTDoubleToFixed (double value) { return static_cast<FT_Fixed>(value * 65536); } +// This would be better if one had std::vector<OTSubstitution> instead of OTSubstitution where each +// entry corresponded to one substitution (e.g. ff -> ff) but Harfbuzz at the moment cannot return +// individual substitutions. See Harfbuzz issue #673. void readOpenTypeGsubTable (const FT_Face ft_face, - std::map<Glib::ustring, int>& tables, - std::map<Glib::ustring, Glib::ustring>& stylistic, - std::map<Glib::ustring, Glib::ustring>& ligatures, - std::map<Glib::ustring, Glib::ustring>& numeric); + std::map<Glib::ustring, OTSubstitution >& tables); void readOpenTypeFvarAxes (const FT_Face ft_face, std::map<Glib::ustring, OTVarAxis>& axes); diff --git a/src/libnrtype/font-instance.h b/src/libnrtype/font-instance.h index ec26ba358..5cb26aec2 100644 --- a/src/libnrtype/font-instance.h +++ b/src/libnrtype/font-instance.h @@ -39,13 +39,8 @@ public: int nbGlyph, maxGlyph; font_glyph* glyphs; - // Map of OpenType tables found in font (convert to std::set?) - std::map<Glib::ustring, int> openTypeTables; - - // Map of substitutions indexed by table - std::map<Glib::ustring, Glib::ustring> openTypeStylistic; - std::map<Glib::ustring, Glib::ustring> openTypeLigatures; - std::map<Glib::ustring, Glib::ustring> openTypeNumeric; + // Map of OpenType tables found in font. + std::map<Glib::ustring, OTSubstitution> openTypeTables; // Maps for font variations. std::map<Glib::ustring, OTVarAxis> openTypeVarAxes; // Axes with ranges diff --git a/src/ui/widget/font-variants.cpp b/src/ui/widget/font-variants.cpp index 6d1da6d60..abe5add62 100644 --- a/src/ui/widget/font-variants.cpp +++ b/src/ui/widget/font-variants.cpp @@ -340,18 +340,19 @@ namespace Widget { // Add tooltips _feature_entry.set_tooltip_text( _("Feature settings in CSS form. No sanity checking is performed.")); - _feature_list.set_justify( Gtk::JUSTIFY_LEFT ); - _feature_list.set_line_wrap( true ); - _feature_substitutions.set_justify( Gtk::JUSTIFY_LEFT ); _feature_substitutions.set_line_wrap( true ); _feature_substitutions.set_line_wrap_mode( Pango::WRAP_WORD_CHAR ); + _feature_list.set_justify( Gtk::JUSTIFY_LEFT ); + _feature_list.set_line_wrap( true ); + // Add to frame _feature_vbox.pack_start( _feature_entry ); _feature_vbox.pack_start( _feature_label ); - _feature_vbox.pack_start( _feature_list ); _feature_vbox.pack_start( _feature_substitutions ); + _feature_vbox.pack_start( _feature_list ); + _feature_frame.add( _feature_vbox ); pack_start( _feature_frame, Gtk::PACK_SHRINK ); @@ -582,7 +583,7 @@ namespace Widget { font_instance* res = font_factory::Default()->FaceFromFontSpecification( font_spec.c_str() ); if( res ) { - std::map<Glib::ustring,int>::iterator it; + std::map<Glib::ustring, OTSubstitution>::iterator it; if((it = res->openTypeTables.find("liga"))!= res->openTypeTables.end() || (it = res->openTypeTables.find("clig"))!= res->openTypeTables.end()) { @@ -767,20 +768,28 @@ namespace Widget { Glib::ustring markup_dlig; Glib::ustring markup_hlig; Glib::ustring markup_calt; - for (auto table: res->openTypeLigatures) { - - Glib::ustring markup; - markup += "<span font_family='"; - markup += sp_font_description_get_family(res->descr); - markup += "'>"; - markup += Glib::Markup::escape_text(table.second); - markup += "</span>"; - if (table.first == "liga") markup_liga += markup; - if (table.first == "clig") markup_liga += markup; - if (table.first == "dlig") markup_dlig += markup; - if (table.first == "hlig") markup_hlig += markup; - if (table.first == "calt") markup_calt += markup; + for (auto table: res->openTypeTables) { + + if (table.first == "liga" || + table.first == "dlig" || + table.first == "dlig" || + table.first == "hgli" || + table.first == "calt") { + + Glib::ustring markup; + markup += "<span font_family='"; + markup += sp_font_description_get_family(res->descr); + markup += "'>"; + markup += Glib::Markup::escape_text(table.second.output); + markup += "</span>"; + + if (table.first == "liga") markup_liga += markup; + if (table.first == "clig") markup_liga += markup; + if (table.first == "dlig") markup_dlig += markup; + if (table.first == "hlig") markup_hlig += markup; + if (table.first == "calt") markup_calt += markup; + } } _ligatures_label_common.set_markup ( markup_liga.c_str() ); @@ -797,7 +806,8 @@ namespace Widget { Glib::ustring markup_afrc; Glib::ustring markup_ordn; Glib::ustring markup_zero; - for (auto table: res->openTypeNumeric) { + + for (auto table: res->openTypeTables) { Glib::ustring markup; markup += "<span font_family='"; @@ -810,7 +820,7 @@ namespace Widget { table.first == "pnum" || table.first == "tnum") markup += "0123456789"; if (table.first == "zero") markup += "0"; - if (table.first == "ordn") markup += table.second; + if (table.first == "ordn") markup += "[" + table.second.before + "]" + table.second.output; if (table.first == "frac" || table.first == "afrc" ) markup += "1/2 2/3 3/4 4/5 5/6"; // Can we do better? markup += "</span>"; @@ -834,22 +844,24 @@ namespace Widget { _numeric_ordinal_label.set_markup ( markup_ordn.c_str() ); _numeric_slashed_zero_label.set_markup ( markup_zero.c_str() ); - // Make list of tables not handled above... eventually add Gtk::Label with - // this info. - std::map<Glib::ustring,int> table_copy = res->openTypeTables; + // Make list of tables not handled above. + std::map<Glib::ustring, OTSubstitution> table_copy = res->openTypeTables; if( (it = table_copy.find("liga")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("clig")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("dlig")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("hlig")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("calt")) != table_copy.end() ) table_copy.erase( it ); + if( (it = table_copy.find("subs")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("sups")) != table_copy.end() ) table_copy.erase( it ); + if( (it = table_copy.find("smcp")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("c2sc")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("pcap")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("c2pc")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("unic")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("titl")) != table_copy.end() ) table_copy.erase( it ); + if( (it = table_copy.find("lnum")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("onum")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("pnum")) != table_copy.end() ) table_copy.erase( it ); @@ -858,6 +870,7 @@ namespace Widget { if( (it = table_copy.find("afrc")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("ordn")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("zero")) != table_copy.end() ) table_copy.erase( it ); + if( (it = table_copy.find("jp78")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("jp83")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("jp90")) != table_copy.end() ) table_copy.erase( it ); @@ -869,62 +882,141 @@ namespace Widget { if( (it = table_copy.find("ruby")) != table_copy.end() ) table_copy.erase( it ); // An incomplete list of tables that should not be exposed to the user: + if( (it = table_copy.find("abvf")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("abvs")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("akhn")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("blwf")) != table_copy.end() ) table_copy.erase( it ); + if( (it = table_copy.find("blws")) != table_copy.end() ) table_copy.erase( it ); + if( (it = table_copy.find("ccmp")) != table_copy.end() ) table_copy.erase( it ); + if( (it = table_copy.find("cjct")) != table_copy.end() ) table_copy.erase( it ); + if( (it = table_copy.find("dnom")) != table_copy.end() ) table_copy.erase( it ); + if( (it = table_copy.find("dtls")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("fina")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("half")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("haln")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("init")) != table_copy.end() ) table_copy.erase( it ); + if( (it = table_copy.find("isol")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("locl")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("medi")) != table_copy.end() ) table_copy.erase( it ); + if( (it = table_copy.find("nukt")) != table_copy.end() ) table_copy.erase( it ); + if( (it = table_copy.find("numr")) != table_copy.end() ) table_copy.erase( it ); + if( (it = table_copy.find("pref")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("pres")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("pstf")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("psts")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("rlig")) != table_copy.end() ) table_copy.erase( it ); + if( (it = table_copy.find("rkrf")) != table_copy.end() ) table_copy.erase( it ); + if( (it = table_copy.find("rphf")) != table_copy.end() ) table_copy.erase( it ); + if( (it = table_copy.find("rtlm")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("ssty")) != table_copy.end() ) table_copy.erase( it ); if( (it = table_copy.find("vatu")) != table_copy.end() ) table_copy.erase( it ); + std::string markup; + + // GSUB lookup type 1 (1 to 1 mapping). + for (auto table: res->openTypeTables) { + if (table.first == "case" || + table.first == "hist" || + table.first[0] == 's' && table.first[1] == 's' && !(table.first[2] == 't')) { + + if( (it = table_copy.find(table.first)) != table_copy.end() ) table_copy.erase( it ); + + markup += "<span font_weight='bold'>"; + markup += table.first; + markup += "</span>"; + markup += ": "; + + markup += "<span font_family='"; + markup += sp_font_description_get_family(res->descr); + markup += "'>"; + markup += Glib::Markup::escape_text(table.second.input); + markup += "</span>"; + + markup += " <span font_weight='bold'>→</span> "; + + markup += "<span font_family='"; + markup += sp_font_description_get_family(res->descr); + markup += "'>"; + markup += "<span font_features='"; + markup += table.first; + markup += "'>"; + markup += Glib::Markup::escape_text(table.second.input); + markup += "</span>"; + markup += "</span>\n"; + } + } + + // GSUB lookup type 3 (1 to many mapping). Optionally type 1. + for (auto table: res->openTypeTables) { + if (table.first == "salt" || + table.first == "swsh" || + table.first == "cwsh" || + table.first == "ornm" || + table.first == "nalt" || + table.first[0] == 'c' && table.first[1] == 'v') { + + if (table.second.input.length() == 0) { + // This can happen if a table is not in the 'DFLT' script and 'dflt' language. + // We should be using the 'lang' attribute to find the correct tables. + // std::cerr << "FontVariants::open_type_update: " + // << table.first << " has no entries!" << std::endl; + continue; + } + + if( (it = table_copy.find(table.first)) != table_copy.end() ) table_copy.erase( it ); + + // Our lame attempt at determining number of alternative glyphs for one glyph: + int number = table.second.output.length() / table.second.input.length(); + + for (int i = 0; i < number; ++i) { + markup += "<span font_weight='bold'>"; + markup += table.first; + if (i != 0) { + markup += " "; + markup += std::to_string (i + 1); + } + markup += "</span>"; + markup += ": "; + + markup += "<span font_family='"; + markup += sp_font_description_get_family(res->descr); + markup += "'>"; + markup += Glib::Markup::escape_text(table.second.input); + markup += "</span>"; + + markup += " <span font_weight='bold'>→</span> "; + + markup += "<span font_family='"; + markup += sp_font_description_get_family(res->descr); + markup += "'>"; + markup += "<span font_features='"; + markup += table.first; + markup += " "; + markup += std::to_string (i + 1); + markup += "'>"; + markup += Glib::Markup::escape_text(table.second.input); + markup += "</span>"; + markup += "</span>\n"; + } + } + } + + _feature_substitutions.set_markup ( markup.c_str() ); + std::string ott_list = "OpenType tables not included above: "; for(it = table_copy.begin(); it != table_copy.end(); ++it) { - // std::cout << "Other: " << it->first << " Occurrences: " << it->second << std::endl; ott_list += it->first; ott_list += ", "; } - _feature_list.set_text( ott_list.c_str() ); - - // "<span foreground='darkblue'>"; - Glib::ustring markup; - - for (auto table: res->openTypeStylistic) { - - markup += "<span font_weight='bold'>"; - markup += table.first; - markup += "</span>"; - markup += ": "; - - markup += "<span font_family='"; - markup += sp_font_description_get_family(res->descr); - markup += "'>"; - markup += Glib::Markup::escape_text(table.second); - markup += "</span>"; - - markup += " → "; - - markup += "<span font_family='"; - markup += sp_font_description_get_family(res->descr); - markup += "'>"; - markup += "<span font_features='"; - markup += table.first; - markup += "'>"; - markup += Glib::Markup::escape_text(table.second); - markup += "</span>"; - markup += "</span>\n"; - + if (table_copy.size() > 0) { + ott_list.pop_back(); + ott_list.pop_back(); + _feature_list.set_text( ott_list.c_str() ); + } else { + _feature_list.set_text( "" ); } - _feature_substitutions.set_markup ( markup.c_str() ); } else { std::cerr << "FontVariants::update(): Couldn't find font_instance for: " |
