From 479b07573269be8c736b8a65b8f5a608254cd0e4 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Sun, 17 Feb 2013 13:37:27 +0100 Subject: Move code from text-toolbar to font-lister in preparation to share code with font-selector/text-edit. (bzr r12131) --- src/libnrtype/font-lister.cpp | 667 ++++++++++++++++++++++++++++++++++++++++-- src/libnrtype/font-lister.h | 203 ++++++++++++- 2 files changed, 837 insertions(+), 33 deletions(-) (limited to 'src/libnrtype') diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp index 04859185c..91671f627 100644 --- a/src/libnrtype/font-lister.cpp +++ b/src/libnrtype/font-lister.cpp @@ -14,11 +14,16 @@ #include "font-lister.h" #include "FontFactory.h" +#include "desktop.h" +#include "desktop-style.h" +#include "document.h" +#include "inkscape.h" +#include "preferences.h" #include "sp-object.h" #include "sp-root.h" -#include "document.h" #include "xml/repr.h" -#include "preferences.h" + +//#define DEBUG_FONT namespace Inkscape { @@ -29,7 +34,7 @@ namespace Inkscape FamilyToStylesMap familyStyleMap; font_factory::Default()->GetUIFamiliesAndStyles(&familyStyleMap); - + // Grab the family names into a list and then sort them std::list familyList; for (FamilyToStylesMap::iterator iter = familyStyleMap.begin(); @@ -47,7 +52,8 @@ namespace Inkscape if (!familyName.empty()) { Gtk::TreeModel::iterator treeModelIter = font_list_store->append(); - (*treeModelIter)[FontList.font] = reinterpret_cast(g_strdup(familyName.c_str())); + //(*treeModelIter)[FontList.family] = reinterpret_cast(g_strdup(familyName.c_str())); + (*treeModelIter)[FontList.family] = familyName; // Now go through the styles GList *styles = NULL; @@ -62,7 +68,21 @@ namespace Inkscape (*treeModelIter)[FontList.onSystem] = true; } } + current_family = "sans-serif"; + current_style = "Normal"; + current_fontspec = "sans-serif"; // Empty style -> Normal + current_fontspec_system = "Sans"; + + /* Create default styles for use when font-family is unknown on system. */ + default_styles = g_list_append( NULL, g_strdup("Normal") ); + default_styles = g_list_append( default_styles, g_strdup("Italic") ); + default_styles = g_list_append( default_styles, g_strdup("Bold") ); + default_styles = g_list_append( default_styles, g_strdup("Bold Italic") ); + font_list_store->thaw_notify(); + + style_list_store = Gtk::ListStore::create (FontStyleList); + style_list_store_trial = Gtk::ListStore::create (FontStyleList); } // Example of how to use "foreach_iter" @@ -70,7 +90,7 @@ namespace Inkscape // FontLister::print_document_font( const Gtk::TreeModel::iterator &iter ) { // Gtk::TreeModel::Row row = *iter; // if( !row[FontList.onSystem] ) { - // std::cout << " Not on system: " << row[FontList.font] << std::endl; + // std::cout << " Not on system: " << row[FontList.family] << std::endl; // return false; // } // return true; @@ -92,23 +112,14 @@ namespace Inkscape while( iter != font_list_store->children().end() ) { Gtk::TreeModel::Row row = *iter; if( !row[FontList.onSystem] ) { - // std::cout << " Not on system: " << row[FontList.font] << std::endl; + // std::cout << " Not on system: " << row[FontList.family] << std::endl; iter = font_list_store->erase( iter ); } else { - // std::cout << " First on system: " << row[FontList.font] << std::endl; + // std::cout << " First on system: " << row[FontList.family] << std::endl; break; } } - /* Create default styles for use when font-family is unknown on system. */ - static GList *default_styles = NULL; - if( default_styles == NULL ) { - default_styles = g_list_append( default_styles, g_strdup("Normal") ); - default_styles = g_list_append( default_styles, g_strdup("Italic") ); - default_styles = g_list_append( default_styles, g_strdup("Bold") ); - default_styles = g_list_append( default_styles, g_strdup("Bold Italic") ); - } - /* Get "font-family"s used in document. */ std::list fontfamilies; update_font_list_recursive( r, &fontfamilies ); @@ -120,7 +131,7 @@ namespace Inkscape /* Insert separator */ if( !fontfamilies.empty() ) { Gtk::TreeModel::iterator treeModelIter = font_list_store->prepend(); - (*treeModelIter)[FontList.font] = "#"; + (*treeModelIter)[FontList.family] = "#"; (*treeModelIter)[FontList.onSystem] = false; } @@ -137,7 +148,7 @@ namespace Inkscape Gtk::TreeModel::iterator iter2 = font_list_store->get_iter( "0" ); while( iter2 != font_list_store->children().end() ) { Gtk::TreeModel::Row row = *iter2; - if( row[FontList.onSystem] && tokens[0].compare( row[FontList.font] ) == 0 ) { + if( row[FontList.onSystem] && tokens[0].compare( row[FontList.family] ) == 0 ) { styles = row[FontList.styles]; break; } @@ -146,7 +157,7 @@ namespace Inkscape } Gtk::TreeModel::iterator treeModelIter = font_list_store->prepend(); - (*treeModelIter)[FontList.font] = reinterpret_cast(g_strdup((*i).c_str())); + (*treeModelIter)[FontList.family] = reinterpret_cast(g_strdup((*i).c_str())); (*treeModelIter)[FontList.styles] = styles; (*treeModelIter)[FontList.onSystem] = false; } @@ -191,7 +202,548 @@ namespace Inkscape } } - Gtk::TreePath + Glib::ustring + FontLister::canonize_fontspec( Glib::ustring fontspec ) { + + // Pass fontspec to and back from Pango to get a the fontspec in + // canonical form. -inkscape-font-specification relies on the + // Pango constructed fontspec not changing form. If it does, + // this is the place to fix it. + PangoFontDescription *descr = pango_font_description_from_string( fontspec.c_str() ); + gchar* canonized = pango_font_description_to_string ( descr ); + Glib::ustring Canonized = canonized; + g_free( canonized ); + pango_font_description_free( descr ); + + // Pango canonized strings remove space after comma between family names. Put it back. + size_t i = 0; + while( (i = Canonized.find(",", i)) != std::string::npos) { + Canonized.replace(i, 1, ", "); + i += 2; + } + + return Canonized; + } + + Glib::ustring + FontLister::system_fontspec( Glib::ustring fontspec ) { + + // Find what Pango thinks is the closest match. + Glib::ustring out = fontspec; + + PangoFontDescription *descr = pango_font_description_from_string(fontspec.c_str()); + font_instance *res = (font_factory::Default())->Face(descr); + if (res->pFont) { + PangoFontDescription *nFaceDesc = pango_font_describe(res->pFont); + out = sp_font_description_get_family(nFaceDesc); + } + pango_font_description_free(descr); + + return out; + } + + std::pair + FontLister::ui_from_fontspec( Glib::ustring fontspec ) { + + PangoFontDescription *descr = pango_font_description_from_string(fontspec.c_str()); + const gchar* family = pango_font_description_get_family(descr); + Glib::ustring Family = family; + + // Pango canonized strings remove space after comma between family names. Put it back. + size_t i = 0; + while( (i = Family.find(",", i)) != std::string::npos) { + Family.replace(i, 1, ", "); + i += 2; + } + + pango_font_description_unset_fields(descr, PANGO_FONT_MASK_FAMILY); + gchar* style = pango_font_description_to_string( descr ); + Glib::ustring Style = style; + pango_font_description_free(descr); + g_free( style ); + + return std::make_pair( Family, Style ); + } + + std::pair + FontLister::selection_update () { + +#ifdef DEBUG_FONT + std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + std::cout << "FontLister::selection_update: entrance" << std::endl; +#endif + // Get fontspec from a selection, preferences, or thin air. + Glib::ustring fontspec; + SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); + + // Directly from stored font specification. + int result = + sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION); + + //std::cout << " Attempting selected style" << std::endl; + if( result != QUERY_STYLE_NOTHING && query->text->font_specification.set ) { + fontspec = query->text->font_specification.value; + //std::cout << " fontspec from query :" << fontspec << ":" << std::endl; + } + + // From style + if( fontspec.empty() ) { + //std::cout << " Attempting desktop style" << std::endl; + int rfamily = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY); + int rstyle = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE); + + // Must have text in selection + if( rfamily != QUERY_STYLE_NOTHING && rstyle != QUERY_STYLE_NOTHING ) { + fontspec = fontspec_from_style( query ); + } + //std::cout << " fontspec from style :" << fontspec << ":" << std::endl; + } + + // From preferences + if( fontspec.empty() ) { + //std::cout << " Attempting preferences" << std::endl; + sp_style_read_from_prefs(query, "/tools/text"); + fontspec = fontspec_from_style( query ); + //std::cout << " fontspec from prefs :" << fontspec << ":" << std::endl; + } + sp_style_unref(query); + + // From thin air + if( fontspec.empty() ) { + //std::cout << " Attempting thin air" << std::endl; + fontspec = current_family + ", " + current_style; + //std::cout << " fontspec from thin air :" << fontspec << ":" << std::endl; + } + + // Do we really need? Removes spaces between font-families. + //current_fontspec = canonize_fontspec( fontspec ); + current_fontspec = fontspec; // Ignore for now + + current_fontspec_system = system_fontspec( current_fontspec ); + + std::pair ui = ui_from_fontspec( current_fontspec ); + set_font_family( ui.first ); + +#ifdef DEBUG_FONT + std::cout << " canonized: :" << current_fontspec << ":" << std::endl; + std::cout << " system: :" << current_fontspec_system << ":" << std::endl; + std::cout << " family: :" << current_family << ":" << std::endl; + std::cout << " style: :" << current_style << ":" << std::endl; + std::cout << "FontLister::selection_update: exit" << std::endl; + std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; +#endif + return std::make_pair( current_family, current_style ); + } + + + // TODO: use to determine font-selector best style + std::pair + FontLister::new_font_family (Glib::ustring new_family, gboolean check_style ) { + +#ifdef DEBUG_FONT + std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + std::cout << "FontLister::new_font_family: " << new_family << std::endl; +#endif + + // No need to do anything if new family is same as old family. + if( new_family.compare( current_family ) == 0 ) { +#ifdef DEBUG_FONT + std::cout << "FontLister::new_font_family: exit: no change in family." << std::endl; + std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; +#endif + return std::make_pair( current_family, current_style ); + } + + // We need to do two things: + // 1. Update style list for new family. + // 2. Select best valid style match to old style. + + // For finding style list, use list of first family in font-family list. + GList* styles = NULL; + Gtk::TreeModel::iterator iter = font_list_store->get_iter( "0" ); + while( iter != font_list_store->children().end() ) { + + Gtk::TreeModel::Row row = *iter; + + if( new_family.compare( row[FontList.family] ) == 0 ) { + styles = row[FontList.styles]; + break; + } + ++iter; + } + + // Newly typed in font-family may not yet be in list... use default list. + // TODO: if font-family is list, check if first family in list is on system + // and set style accordingly. + if( styles == NULL ) { + styles = default_styles; + } + + // Update style list. + // TODO: create a second "temporary" style_list_store for font_selector. + style_list_store->freeze_notify(); + style_list_store->clear(); + + for (GList *l=styles; l; l = l->next) { + Gtk::TreeModel::iterator treeModelIter = style_list_store->append(); + (*treeModelIter)[FontStyleList.styles] = (char*)l->data; + } + + style_list_store->thaw_notify(); + + // Find best match to the style from the old font-family to the + // styles available with the new font. + // TODO: Maybe check if an exact match exists before using Pango. + Glib::ustring best_style = current_style; + if( check_style ) { + //std::cout << " Trying to match: " << current_fontspec << std::endl; + PangoFontDescription *desc_old + = pango_font_description_from_string( current_fontspec.c_str() ); + PangoFontDescription* desc_best = NULL; + + for (GList *l=styles; l; l = l->next) { + Glib::ustring candidate = new_family + ", " + (char*)l->data; + PangoFontDescription* desc_candidate + = pango_font_description_from_string( candidate.c_str() ); + //std::cout << " Testing: " << pango_font_description_to_string( desc_candidate ) << std::endl; + if( pango_font_description_better_match( desc_old, desc_best, desc_candidate ) ) { + pango_font_description_free( desc_best ); + desc_best = desc_candidate; + //std::cout << " ... better: " << std::endl; + } else { + pango_font_description_free( desc_candidate ); + //std::cout << " ... not better: " << std::endl; + } + } + if( desc_best ) { + pango_font_description_unset_fields( desc_best, PANGO_FONT_MASK_FAMILY ); + best_style = pango_font_description_to_string( desc_best ); + } + + if( desc_old ) pango_font_description_free( desc_old ); + if( desc_best ) pango_font_description_free( desc_best ); + } + +#ifdef DEBUG_FONT + std::cout << "FontLister::new_font_family: exit: " << new_family << " " << best_style << std::endl; + std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; +#endif + return std::make_pair( new_family, best_style ); + } + + std::pair + FontLister::set_font_family (Glib::ustring new_family, gboolean check_style) { + +#ifdef DEBUG_FONT + std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + std::cout << "FontLister::set_font_family: " << new_family << std::endl; +#endif + + std::pair ui = new_font_family( new_family, check_style ); + current_family = ui.first; + current_style = ui.second; + current_fontspec = canonize_fontspec( current_family + ", " + current_style ); + current_fontspec_system = system_fontspec( current_fontspec ); + +#ifdef DEBUG_FONT + std::cout << " canonized: :" << current_fontspec << ":" << std::endl; + std::cout << " system: :" << current_fontspec_system << ":" << std::endl; + std::cout << " family: :" << current_family << ":" << std::endl; + std::cout << " style: :" << current_style << ":" << std::endl; + std::cout << "FontLister::set_font_family: end" << std::endl; + std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; +#endif + return ui; + } + + // void + // FontLister::new_font_style (Glib::ustring new_style) { + // // Is this needed? What do we do? + // } + + void + FontLister::set_font_style (Glib::ustring new_style) { + + // TODO: Validate input using Pango. If Pango doesn't recognize a style it will + // attach the "invalid" style to the font-family. + +#ifdef DEBUG_FONT + std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + std::cout << "FontLister:set_font_style: " << new_style << std::endl; +#endif + + current_style = new_style; + current_fontspec = canonize_fontspec( current_family + ", " + current_style ); + current_fontspec_system = system_fontspec( current_fontspec ); + +#ifdef DEBUG_FONT + std::cout << " canonized: :" << current_fontspec << ":" << std::endl; + std::cout << " system: :" << current_fontspec_system << ":" << std::endl; + std::cout << " family: " << current_family << std::endl; + std::cout << " style: " << current_style << std::endl; + std::cout << "FontLister::set_font_style: end" << std::endl; + std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; +#endif + } + + // For use by font-selector where we already know that the style is valid + void + FontLister::set_font (Glib::ustring new_family, Glib::ustring new_style) { + +#ifdef DEBUG_FONT + std::cout << "FonLister::set_font: " << new_family << " " << new_style << std::endl; +#endif + set_font_family( new_family, false ); + set_font_style( new_style ); + } + + // We do this ourselves as we can't rely on FontFactory. + void + FontLister::set_css( SPCSSAttr *css ) { + + //std::cout << "FontLister:set_css: " << std::endl; + + PangoFontDescription *desc = pango_font_description_from_string( current_fontspec.c_str() ); + sp_repr_css_set_property (css, "-inkscape-font-specification", current_fontspec.c_str() ); + sp_repr_css_set_property (css, "font-family", pango_font_description_get_family( desc ) ); + + PangoWeight weight = pango_font_description_get_weight( desc ); + switch ( weight ) { + case PANGO_WEIGHT_THIN: + sp_repr_css_set_property (css, "font-weight", "100" ); + break; + case PANGO_WEIGHT_ULTRALIGHT: + sp_repr_css_set_property (css, "font-weight", "200" ); + break; + case PANGO_WEIGHT_LIGHT: + sp_repr_css_set_property (css, "font-weight", "300" ); + break; + case PANGO_WEIGHT_BOOK: + sp_repr_css_set_property (css, "font-weight", "380" ); + break; + case PANGO_WEIGHT_NORMAL: + sp_repr_css_set_property (css, "font-weight", "normal" ); + break; + case PANGO_WEIGHT_MEDIUM: + sp_repr_css_set_property (css, "font-weight", "500" ); + break; + case PANGO_WEIGHT_SEMIBOLD: + sp_repr_css_set_property (css, "font-weight", "600" ); + break; + case PANGO_WEIGHT_BOLD: + sp_repr_css_set_property (css, "font-weight", "bold" ); + break; + case PANGO_WEIGHT_ULTRABOLD: + sp_repr_css_set_property (css, "font-weight", "800" ); + break; + case PANGO_WEIGHT_HEAVY: + sp_repr_css_set_property (css, "font-weight", "900" ); + break; + case PANGO_WEIGHT_ULTRAHEAVY: + sp_repr_css_set_property (css, "font-weight", "1000" ); + break; + } + + PangoStyle style = pango_font_description_get_style( desc ); + switch ( style ) { + case PANGO_STYLE_NORMAL: + sp_repr_css_set_property (css, "font-style", "normal" ); + break; + case PANGO_STYLE_OBLIQUE: + sp_repr_css_set_property (css, "font-style", "oblique" ); + break; + case PANGO_STYLE_ITALIC: + sp_repr_css_set_property (css, "font-style", "italic" ); + break; + } + + PangoStretch stretch = pango_font_description_get_stretch( desc ); + switch ( stretch ) { + case PANGO_STRETCH_ULTRA_CONDENSED: + sp_repr_css_set_property (css, "font-stretch", "ultra-condensed" ); + break; + case PANGO_STRETCH_EXTRA_CONDENSED: + sp_repr_css_set_property (css, "font-stretch", "extra-condensed" ); + break; + case PANGO_STRETCH_CONDENSED: + sp_repr_css_set_property (css, "font-stretch", "condensed" ); + break; + case PANGO_STRETCH_SEMI_CONDENSED: + sp_repr_css_set_property (css, "font-stretch", "semi-condensed" ); + break; + case PANGO_STRETCH_NORMAL: + sp_repr_css_set_property (css, "font-stretch", "normal" ); + break; + case PANGO_STRETCH_SEMI_EXPANDED: + sp_repr_css_set_property (css, "font-stretch", "semi-expanded" ); + break; + case PANGO_STRETCH_EXPANDED: + sp_repr_css_set_property (css, "font-stretch", "expanded" ); + break; + case PANGO_STRETCH_EXTRA_EXPANDED: + sp_repr_css_set_property (css, "font-stretch", "extra-expanded" ); + break; + case PANGO_STRETCH_ULTRA_EXPANDED: + sp_repr_css_set_property (css, "font-stretch", "ultra-expanded" ); + break; + } + + PangoVariant variant = pango_font_description_get_variant( desc ); + switch ( variant ) { + case PANGO_VARIANT_NORMAL: + sp_repr_css_set_property (css, "font-variant", "normal" ); + break; + case PANGO_VARIANT_SMALL_CAPS: + sp_repr_css_set_property (css, "font-variant", "small-caps" ); + break; + } + } + + // We do this ourselves as we can't rely on FontFactory. + Glib::ustring + FontLister::fontspec_from_style (SPStyle* style) { + + //std::cout << "FontLister:fontspec_from_style: " << std::endl; + + Glib::ustring fontspec; + if (style) { + + // First try to use the font specification if it is set + if (style->text->font_specification.set + && style->text->font_specification.value + && *style->text->font_specification.value) { + + fontspec = style->text->font_specification.value; + + } else { + + fontspec = style->text->font_family.value; + fontspec += ","; + + switch (style->font_weight.computed) { + + case SP_CSS_FONT_WEIGHT_100: + fontspec += " 100"; + break; + + case SP_CSS_FONT_WEIGHT_200: + fontspec += " 200"; + break; + + case SP_CSS_FONT_WEIGHT_300: + fontspec += " 300"; + break; + + case SP_CSS_FONT_WEIGHT_400: + case SP_CSS_FONT_WEIGHT_NORMAL: + //fontspec += " normal"; + break; + + case SP_CSS_FONT_WEIGHT_500: + fontspec += " 500"; + break; + + case SP_CSS_FONT_WEIGHT_600: + fontspec += " 600"; + break; + + case SP_CSS_FONT_WEIGHT_700: + case SP_CSS_FONT_WEIGHT_BOLD: + fontspec += " bold"; + break; + + case SP_CSS_FONT_WEIGHT_800: + fontspec += " 800"; + break; + + case SP_CSS_FONT_WEIGHT_900: + fontspec += " 900"; + break; + + case SP_CSS_FONT_WEIGHT_LIGHTER: + case SP_CSS_FONT_WEIGHT_BOLDER: + default: + g_warning("Unrecognized font_weight.computed value"); + break; + } + + switch (style->font_style.computed) { + case SP_CSS_FONT_STYLE_ITALIC: + fontspec += " italic"; + break; + + case SP_CSS_FONT_STYLE_OBLIQUE: + fontspec += " oblique"; + break; + + case SP_CSS_FONT_STYLE_NORMAL: + default: + //fontspec += " normal"; + break; + } + + switch (style->font_stretch.computed) { + + case SP_CSS_FONT_STRETCH_ULTRA_CONDENSED: + fontspec += " extra_condensed"; + break; + + case SP_CSS_FONT_STRETCH_EXTRA_CONDENSED: + fontspec += " extra_condensed"; + break; + + case SP_CSS_FONT_STRETCH_CONDENSED: + case SP_CSS_FONT_STRETCH_NARROWER: + fontspec += " condensed"; + break; + + case SP_CSS_FONT_STRETCH_SEMI_CONDENSED: + fontspec += " semi_condensed"; + break; + + case SP_CSS_FONT_STRETCH_NORMAL: + //fontspec += " normal"; + break; + + case SP_CSS_FONT_STRETCH_SEMI_EXPANDED: + fontspec += " semi_expanded"; + break; + + case SP_CSS_FONT_STRETCH_EXPANDED: + case SP_CSS_FONT_STRETCH_WIDER: + fontspec += " expanded"; + break; + + case SP_CSS_FONT_STRETCH_EXTRA_EXPANDED: + fontspec += " extra_expanded"; + break; + + case SP_CSS_FONT_STRETCH_ULTRA_EXPANDED: + fontspec += " ultra_expanded"; + break; + + default: + //fontspec += " normal"; + break; + } + + switch (style->font_variant.computed) { + + case SP_CSS_FONT_VARIANT_SMALL_CAPS: + fontspec += "small-caps"; + break; + + default: + //fontspec += "normal"; + break; + } + } + } + return canonize_fontspec( fontspec ); + } + + + Gtk::TreeModel::Row FontLister::get_row_for_font (Glib::ustring family) { Gtk::TreePath path; @@ -201,8 +753,8 @@ namespace Inkscape Gtk::TreeModel::Row row = *iter; - if( family.compare( row[FontList.font] ) == 0 ) { - return font_list_store->get_path( iter ); + if( family.compare( row[FontList.family] ) == 0 ) { + return row; } ++iter; @@ -211,6 +763,65 @@ namespace Inkscape throw FAMILY_NOT_FOUND; } + Gtk::TreePath + FontLister::get_path_for_font (Glib::ustring family) + { + return font_list_store->get_path( get_row_for_font ( family ) ); + } + + /* Returns style string */ + // TODO: Remove or turn into function to be used by new_font_family. + Glib::ustring + FontLister::get_best_style_match (Glib::ustring family, Glib::ustring target_style) { + +#ifdef DEBUG_FONT + std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + std::cout << "FontLister::get_best_style_match: " << family << " : " << target_style << std::endl; +#endif + + Glib::ustring font_string = family + " " + target_style; + + Gtk::TreeModel::Row row; + try { + row = get_row_for_font( family ); + } catch (...) { + //std::cout << " ERROR: can't find family: " << family << std::endl; + return (target_style); + } + + PangoFontDescription* target = pango_font_description_from_string( font_string.c_str() ); + PangoFontDescription* best = NULL; + + //std::cout << " Target: " << pango_font_description_to_string( target ) << std::endl; + + GList* styles = row[FontList.styles]; + for (GList *l=styles; l; l = l->next) { + Glib::ustring font_string_test = family + " " + (char*)l->data; + PangoFontDescription* candidate = pango_font_description_from_string( font_string_test.c_str() ); + // std::cout << " Testing: " << pango_font_description_to_string( candidate ) << std::endl; + if( pango_font_description_better_match( target, best, candidate ) ) { + best = candidate; + } + } + + Glib::ustring best_style; + if( best ) { + //std::cout << " Best: " << pango_font_description_to_string( best ) << std::endl; + pango_font_description_unset_fields( best, PANGO_FONT_MASK_FAMILY ); + best_style = pango_font_description_to_string( best ); + } else { + //std::cout << " Failed: " << family << std::endl; + best_style = target_style; + } + +#ifdef DEBUG_FONT + std::cout << " Returning: " << best_style << std::endl; + std::cout << "FontLister::get_best_style_match: exit" << std::endl; + std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; +#endif + return best_style; + } + FontLister::~FontLister () { }; @@ -220,6 +831,18 @@ namespace Inkscape { return font_list_store; } + + const Glib::RefPtr + FontLister::get_style_list () const + { + return style_list_store; + } + + const Glib::RefPtr + FontLister::get_style_list_trial () const + { + return style_list_store_trial; + } } // Helper functions diff --git a/src/libnrtype/font-lister.h b/src/libnrtype/font-lister.h index 751350407..10a269771 100644 --- a/src/libnrtype/font-lister.h +++ b/src/libnrtype/font-lister.h @@ -25,12 +25,35 @@ class SPObject; class SPDocument; +class SPCSSAttr; +struct SPStyle; namespace Inkscape { /** * This class enumerates fonts using libnrtype into reusable data stores and - * allows for random access to the font list + * allows for random access to the font-family list and the font-style list. + * Setting the font-family updates the font-style list. "Style" in this case + * refers to everything but family and size (e.g. italic/oblique, weight). + * + * This class handles font-family lists and fonts that are not on the system, + * where there is not an entry in the fontInstanceMap. + * + * This class uses the idea of "font_spec". This is a plain text string as used by + * Pango. It is similar to the CSS font shorthand except that font-family comes + * first and in this class the font-size is not used. + * + * This class uses the FontFactory class to get a list of system fonts + * and to find best matches via Pango. The Pango interface is only setup + * to deal with fonts that are on the system so care must be taken. For + * example, best matches should only be done with the first font-family + * in a font-family list. If the first font-family is not on the system + * then a generic font-family should be used (sans-serif -> Sans). + * + * This class is used by the UI interface (text-toolbar, font-select, etc.). + * + * "Font" includes family and style. It should not be used when one + * means font-family. */ class FontLister { @@ -38,13 +61,14 @@ namespace Inkscape enum Exceptions { - FAMILY_NOT_FOUND + FAMILY_NOT_FOUND, + STYLE_NOT_FOUND }; virtual ~FontLister (); - /** GtkTreeModelColumnRecord for the font list Gtk::ListStore + /** GtkTreeModelColumnRecord for the font-family list Gtk::ListStore */ class FontListClass : public Gtk::TreeModelColumnRecord @@ -52,10 +76,9 @@ namespace Inkscape public: /** Column containing the family name */ - Gtk::TreeModelColumn font; + Gtk::TreeModelColumn family; - /** Column containing an std::vector with style names - * for the corresponding family + /** Column containing the styles for each family name. */ Gtk::TreeModelColumn styles; @@ -65,7 +88,7 @@ namespace Inkscape FontListClass () { - add (font); + add (family); add (styles); add (onSystem); } @@ -73,7 +96,24 @@ namespace Inkscape FontListClass FontList; - /** Returns the ListStore with the font names + class FontStyleListClass + : public Gtk::TreeModelColumnRecord + { + public: + /** Column containing the styles + */ + Gtk::TreeModelColumn styles; + + FontStyleListClass () + { + add (styles); + } + }; + + FontStyleListClass FontStyleList; + FontStyleListClass FontStyleListTrial; + + /** Returns the ListStore with the family names * * The return is const and the function is declared as const. * The ListStore is ready to be used after class instantiation @@ -82,6 +122,18 @@ namespace Inkscape const Glib::RefPtr get_font_list () const; + /** Returns the ListStore with the styles + * + */ + const Glib::RefPtr + get_style_list () const; + + /** Returns the ListStore with the styles - trial + * + */ + const Glib::RefPtr + get_style_list_trial () const; + /** Updates font list to include fonts in document * */ @@ -96,13 +148,119 @@ namespace Inkscape static Inkscape::FontLister* get_instance () { - static Inkscape::FontLister* instance = new Inkscape::FontLister(); + static Inkscape::FontLister* instance = new Inkscape::FontLister(); return instance; } - Gtk::TreePath + /** Takes a hand written font spec and returns a Pango generated one in + * standard form. + */ + Glib::ustring canonize_fontspec( Glib::ustring fontspec ); + + /** Find closest system font to given font. + */ + Glib::ustring system_fontspec( Glib::ustring fontspec ); + + /** Gets font-family and style from fontspec. + * font-family and style returned. + */ + std::pair + ui_from_fontspec (Glib::ustring fontspec); + + /** Sets font-family and style after a selection change. + * New font-family and style returned. + */ + std::pair + selection_update (); + + /** Changes font-family, updating style list and attempting to find + * closest style to current_style style (if check_style is true). + * New font-family and style returned. + * Does NOT update current_family and current_style. + * (For potential use in font-selector which doesn't update until + * "Apply" button clicked.) + */ + std::pair + new_font_family (Glib::ustring family, gboolean check_style = true); + + /** Sets font-family, updating style list and attempting + * to find closest style to old current_style. + * New font-family and style returned. + * Updates current_family and current_style. + * (For use in text-toolbar where update is immediate.) + */ + std::pair + set_font_family (Glib::ustring family, gboolean check_style = true); + + Glib::ustring + get_font_family () + { + return current_family; + } + + /* Not Used */ + void + new_font_style (Glib::ustring style); + + /** Sets style. Does not validate style for family. + */ + void + set_font_style (Glib::ustring style); + + Glib::ustring + get_font_style () + { + return current_style; + } + + /** Sets both family and style. Does not attempt to find + * best match for style (assume that style is already valid + * for family). + */ + void + set_font (Glib::ustring family, Glib::ustring style); + + /** Sets both family and style. Does not attempt to find + * best match for style (assume that style is already valid + * for family). + */ + void + new_font (Glib::ustring family, Glib::ustring style); + + std::pair + get_try_font () { + return ( std::make_pair( try_family, try_style ) ); + } + + Glib::ustring + fontspec_from_style (SPStyle* style); + + /** Fill css using current_fontspec. + */ + void + set_css( SPCSSAttr *css ); + + Gtk::TreeModel::Row get_row_for_font (Glib::ustring family); + Gtk::TreePath + get_path_for_font (Glib::ustring family); + + Gtk::TreeModel::Row + get_row_for_style (Glib::ustring style); + + Gtk::TreePath + get_path_for_style (Glib::ustring style); + + std::pair + get_paths (Glib::ustring family, Glib::ustring style); + + /** Return best style match for new font given style for old font. + */ + Glib::ustring + get_best_style_match (Glib::ustring family, Glib::ustring style); + + /* Not Used */ const NRNameList get_name_list () const { @@ -116,7 +274,30 @@ namespace Inkscape NRNameList families; Glib::RefPtr font_list_store; + Glib::RefPtr style_list_store; + Glib::RefPtr style_list_store_trial; + + /** Info for currently selected font (what is shown in the UI). + * May include font-family lists and fonts not on system. + */ + Glib::ustring current_family; + Glib::ustring current_style; + Glib::ustring current_fontspec; + + /** fontspec of system font closest to current_fontspec. + * (What the system will use to display current_fontspec.) + */ + Glib::ustring current_fontspec_system; + + /** Info for proposed font (what is shown in the font-selection UI). + * May include font-family lists and fonts not on system. + */ + Glib::ustring try_family; + Glib::ustring try_style; + /** If a font-family is not on system, this list of styles is used. + */ + GList *default_styles; }; } @@ -125,7 +306,7 @@ namespace Inkscape static gboolean font_lister_separator_func(GtkTreeModel *model, GtkTreeIter *iter, gpointer /*data*/) { gchar* text = 0; - gtk_tree_model_get(model, iter, 0, &text, -1 ); // Column 0: FontList.font + gtk_tree_model_get(model, iter, 0, &text, -1 ); // Column 0: FontList.family return (text && strcmp(text,"#") == 0); } -- cgit v1.2.3 From 7b9700a6e7cd59b45a0707b3225e0b45d5061cfc Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Tue, 19 Feb 2013 11:42:43 +0100 Subject: Small bug fix (fix format of font-family in some cases). (bzr r12133) --- src/libnrtype/font-lister.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libnrtype') diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp index 91671f627..2c22ecff0 100644 --- a/src/libnrtype/font-lister.cpp +++ b/src/libnrtype/font-lister.cpp @@ -503,10 +503,10 @@ namespace Inkscape //std::cout << "FontLister:set_css: " << std::endl; - PangoFontDescription *desc = pango_font_description_from_string( current_fontspec.c_str() ); sp_repr_css_set_property (css, "-inkscape-font-specification", current_fontspec.c_str() ); - sp_repr_css_set_property (css, "font-family", pango_font_description_get_family( desc ) ); + sp_repr_css_set_property (css, "font-family", current_family.c_str() ); //Canonized w/ spaces + PangoFontDescription *desc = pango_font_description_from_string( current_fontspec.c_str() ); PangoWeight weight = pango_font_description_get_weight( desc ); switch ( weight ) { case PANGO_WEIGHT_THIN: -- cgit v1.2.3 From 59732b62d22fa2b395eb0cb0e5fb079ab71e66cb Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Sat, 23 Feb 2013 12:47:01 +0100 Subject: Small step towards fixing font-family scrolling issue (bug 1122553). (bzr r12142) --- src/libnrtype/font-lister.cpp | 67 +++++++++++++++++++++++++++++++++++++++++++ src/libnrtype/font-lister.h | 18 ++++++++++++ 2 files changed, 85 insertions(+) (limited to 'src/libnrtype') diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp index 2c22ecff0..57a019e96 100644 --- a/src/libnrtype/font-lister.cpp +++ b/src/libnrtype/font-lister.cpp @@ -68,6 +68,7 @@ namespace Inkscape (*treeModelIter)[FontList.onSystem] = true; } } + current_family_row = 0; current_family = "sans-serif"; current_style = "Normal"; current_fontspec = "sans-serif"; // Empty style -> Normal @@ -107,6 +108,18 @@ namespace Inkscape font_list_store->freeze_notify(); + /* Find if current row is in document or system part of list */ + gboolean row_is_system = false; + if( current_family_row > -1 ) { + Gtk::TreePath path; + path.push_back( current_family_row ); + Gtk::TreeModel::iterator iter = font_list_store->get_iter( path ); + if( iter ) { + row_is_system = (*iter)[FontList.onSystem]; + // std::cout << " In: row: " << current_family_row << " " << (*iter)[FontList.family] << std::endl; + } + } + /* Clear all old document font-family entries */ Gtk::TreeModel::iterator iter = font_list_store->get_iter( "0" ); while( iter != font_list_store->children().end() ) { @@ -162,6 +175,32 @@ namespace Inkscape (*treeModelIter)[FontList.onSystem] = false; } + /* Now we do a song and dance to find the correct row as the row corresponding + * to the current_family may have changed. We can't simply search for the + * family name in the list since it can occur twice, once in the document + * font family part and once in the system font family part. Above we determined + * which part it is in. + */ + if( current_family_row > -1 ) { + int start = 0; + if( row_is_system ) start = fontfamilies.size(); + int length = font_list_store->children().size(); + for( int i = 0; i < length; ++i ) { + int row = i + start; + if( row >= length ) row -= length; + Gtk::TreePath path; + path.push_back( row ); + Gtk::TreeModel::iterator iter = font_list_store->get_iter( path ); + if( iter ) { + if( current_family.compare( (*iter)[FontList.family] ) == 0 ) { + current_family_row = row; + break; + } + } + } + } + // std::cout << " Out: row: " << current_family_row << " " << current_family << std::endl; + font_list_store->thaw_notify(); } @@ -456,6 +495,34 @@ namespace Inkscape return ui; } + + std::pair + FontLister::set_font_family (int row, gboolean check_style) { + +#ifdef DEBUG_FONT + std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + std::cout << "FontLister::set_font_family( row ): " << row << std::endl; +#endif + + current_family_row = row; + Gtk::TreePath path; + path.push_back( row ); + Glib::ustring new_family = current_family; + Gtk::TreeModel::iterator iter = font_list_store->get_iter( path ); + if( iter ) { + current_family = (*iter)[FontList.family]; + } + + std::pair ui = set_font_family( new_family, check_style ); + +#ifdef DEBUG_FONT + std::cout << "FontLister::set_font_family( row ): end" << std::endl; + std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; +#endif + return ui; + } + + // void // FontLister::new_font_style (Glib::ustring new_style) { // // Is this needed? What do we do? diff --git a/src/libnrtype/font-lister.h b/src/libnrtype/font-lister.h index 10a269771..aaa996247 100644 --- a/src/libnrtype/font-lister.h +++ b/src/libnrtype/font-lister.h @@ -187,17 +187,34 @@ namespace Inkscape * to find closest style to old current_style. * New font-family and style returned. * Updates current_family and current_style. + * Calls new_font_family(). * (For use in text-toolbar where update is immediate.) */ std::pair set_font_family (Glib::ustring family, gboolean check_style = true); + /** Sets font-family from row in list store. + * The row can be used to determine if we are in the + * document or system part of the font-family list. + * This is needed to handle scrolling through the + * font-family list correctly. + * Calls set_font_family(). + */ + std::pair + set_font_family (int row, gboolean check_style = true); + Glib::ustring get_font_family () { return current_family; } + int + get_font_family_row () + { + return current_family_row; + } + /* Not Used */ void new_font_style (Glib::ustring style); @@ -280,6 +297,7 @@ namespace Inkscape /** Info for currently selected font (what is shown in the UI). * May include font-family lists and fonts not on system. */ + int current_family_row; Glib::ustring current_family; Glib::ustring current_style; Glib::ustring current_fontspec; -- cgit v1.2.3 From ae56bd6349992b95e44850a930440f81538545c5 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Sun, 24 Feb 2013 15:31:21 +0100 Subject: Fix for font-family scrolling in text-tool tool-controls (bug 1122553). (bzr r12149) --- src/libnrtype/font-lister.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src/libnrtype') diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp index 57a019e96..5e67c5991 100644 --- a/src/libnrtype/font-lister.cpp +++ b/src/libnrtype/font-lister.cpp @@ -10,7 +10,6 @@ #include #include #include - #include "font-lister.h" #include "FontFactory.h" @@ -364,10 +363,11 @@ namespace Inkscape set_font_family( ui.first ); #ifdef DEBUG_FONT - std::cout << " canonized: :" << current_fontspec << ":" << std::endl; - std::cout << " system: :" << current_fontspec_system << ":" << std::endl; - std::cout << " family: :" << current_family << ":" << std::endl; - std::cout << " style: :" << current_style << ":" << std::endl; + std::cout << " family_row: :" << current_family_row << ":" << std::endl; + std::cout << " canonized: :" << current_fontspec << ":" << std::endl; + std::cout << " system: :" << current_fontspec_system << ":" << std::endl; + std::cout << " family: :" << current_family << ":" << std::endl; + std::cout << " style: :" << current_style << ":" << std::endl; std::cout << "FontLister::selection_update: exit" << std::endl; std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; #endif @@ -485,6 +485,7 @@ namespace Inkscape current_fontspec_system = system_fontspec( current_fontspec ); #ifdef DEBUG_FONT + std::cout << " family_row: :" << current_family_row << ":" << std::endl; std::cout << " canonized: :" << current_fontspec << ":" << std::endl; std::cout << " system: :" << current_fontspec_system << ":" << std::endl; std::cout << " family: :" << current_family << ":" << std::endl; @@ -510,7 +511,7 @@ namespace Inkscape Glib::ustring new_family = current_family; Gtk::TreeModel::iterator iter = font_list_store->get_iter( path ); if( iter ) { - current_family = (*iter)[FontList.family]; + new_family = (*iter)[FontList.family]; } std::pair ui = set_font_family( new_family, check_style ); -- cgit v1.2.3 From f71eb7bbf5a09eb685c655762465cea23f5f9aee Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Fri, 1 Mar 2013 17:48:58 +0100 Subject: Convert font-selector, text-edit, glyphs to use updated font-lister (use fontspec rather than font). (bzr r12164) --- src/libnrtype/font-lister.cpp | 76 +++++++++++++++++++++++++++---------------- src/libnrtype/font-lister.h | 52 ++++++++--------------------- 2 files changed, 62 insertions(+), 66 deletions(-) (limited to 'src/libnrtype') diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp index 5e67c5991..97d3c66d4 100644 --- a/src/libnrtype/font-lister.cpp +++ b/src/libnrtype/font-lister.cpp @@ -82,7 +82,6 @@ namespace Inkscape font_list_store->thaw_notify(); style_list_store = Gtk::ListStore::create (FontStyleList); - style_list_store_trial = Gtk::ListStore::create (FontStyleList); } // Example of how to use "foreach_iter" @@ -375,6 +374,24 @@ namespace Inkscape } + // Set fontspec. If check is false, best style match will not be done. + void + FontLister::set_fontspec (Glib::ustring new_fontspec, gboolean check) { + + std::pair ui = ui_from_fontspec( new_fontspec ); + Glib::ustring new_family = ui.first; + Glib::ustring new_style = ui.second; + +#ifdef DEBUG_FONT + std::cout << "FontLister::set_fontspec: family: " << new_family + << " style:" << new_style << std::endl; +#endif + + set_font_family( new_family, false ); + set_font_style( new_style ); + } + + // TODO: use to determine font-selector best style std::pair FontLister::new_font_family (Glib::ustring new_family, gboolean check_style ) { @@ -419,7 +436,6 @@ namespace Inkscape } // Update style list. - // TODO: create a second "temporary" style_list_store for font_selector. style_list_store->freeze_notify(); style_list_store->clear(); @@ -524,11 +540,6 @@ namespace Inkscape } - // void - // FontLister::new_font_style (Glib::ustring new_style) { - // // Is this needed? What do we do? - // } - void FontLister::set_font_style (Glib::ustring new_style) { @@ -554,27 +565,22 @@ namespace Inkscape #endif } - // For use by font-selector where we already know that the style is valid - void - FontLister::set_font (Glib::ustring new_family, Glib::ustring new_style) { - -#ifdef DEBUG_FONT - std::cout << "FonLister::set_font: " << new_family << " " << new_style << std::endl; -#endif - set_font_family( new_family, false ); - set_font_style( new_style ); - } // We do this ourselves as we can't rely on FontFactory. void - FontLister::set_css( SPCSSAttr *css ) { + FontLister::fill_css( SPCSSAttr *css, Glib::ustring fontspec ) { + + if( fontspec.empty() ) { + fontspec = current_fontspec; + } + std::pair ui = ui_from_fontspec( fontspec ); - //std::cout << "FontLister:set_css: " << std::endl; + Glib::ustring family = ui.first; - sp_repr_css_set_property (css, "-inkscape-font-specification", current_fontspec.c_str() ); - sp_repr_css_set_property (css, "font-family", current_family.c_str() ); //Canonized w/ spaces + sp_repr_css_set_property (css, "-inkscape-font-specification", fontspec.c_str() ); + sp_repr_css_set_property (css, "font-family", family.c_str() ); //Canonized w/ spaces - PangoFontDescription *desc = pango_font_description_from_string( current_fontspec.c_str() ); + PangoFontDescription *desc = pango_font_description_from_string( fontspec.c_str() ); PangoWeight weight = pango_font_description_get_weight( desc ); switch ( weight ) { case PANGO_WEIGHT_THIN: @@ -837,6 +843,26 @@ namespace Inkscape return font_list_store->get_path( get_row_for_font ( family ) ); } + Gtk::TreeModel::Row + FontLister::get_row_for_style (Glib::ustring style) + { + Gtk::TreePath path; + + Gtk::TreeModel::iterator iter = style_list_store->get_iter( "0" ); + while( iter != style_list_store->children().end() ) { + + Gtk::TreeModel::Row row = *iter; + + if( style.compare( row[FontStyleList.styles] ) == 0 ) { + return row; + } + + ++iter; + } + + throw STYLE_NOT_FOUND; + } + /* Returns style string */ // TODO: Remove or turn into function to be used by new_font_family. Glib::ustring @@ -905,12 +931,6 @@ namespace Inkscape { return style_list_store; } - - const Glib::RefPtr - FontLister::get_style_list_trial () const - { - return style_list_store_trial; - } } // Helper functions diff --git a/src/libnrtype/font-lister.h b/src/libnrtype/font-lister.h index aaa996247..5c48bf7a8 100644 --- a/src/libnrtype/font-lister.h +++ b/src/libnrtype/font-lister.h @@ -111,7 +111,6 @@ namespace Inkscape }; FontStyleListClass FontStyleList; - FontStyleListClass FontStyleListTrial; /** Returns the ListStore with the family names * @@ -128,12 +127,6 @@ namespace Inkscape const Glib::RefPtr get_style_list () const; - /** Returns the ListStore with the styles - trial - * - */ - const Glib::RefPtr - get_style_list_trial () const; - /** Updates font list to include fonts in document * */ @@ -173,6 +166,19 @@ namespace Inkscape std::pair selection_update (); + /** Sets current_fontspec, etc. If check is false, won't + * try to find best style match (assumes style in fontspec + * valid for given font-family). + */ + void + set_fontspec (Glib::ustring fontspec, gboolean check=true); + + Glib::ustring + get_fontspec () + { + return current_fontspec; + } + /** Changes font-family, updating style list and attempting to find * closest style to current_style style (if check_style is true). * New font-family and style returned. @@ -215,10 +221,6 @@ namespace Inkscape return current_family_row; } - /* Not Used */ - void - new_font_style (Glib::ustring style); - /** Sets style. Does not validate style for family. */ void @@ -230,32 +232,13 @@ namespace Inkscape return current_style; } - /** Sets both family and style. Does not attempt to find - * best match for style (assume that style is already valid - * for family). - */ - void - set_font (Glib::ustring family, Glib::ustring style); - - /** Sets both family and style. Does not attempt to find - * best match for style (assume that style is already valid - * for family). - */ - void - new_font (Glib::ustring family, Glib::ustring style); - - std::pair - get_try_font () { - return ( std::make_pair( try_family, try_style ) ); - } - Glib::ustring fontspec_from_style (SPStyle* style); /** Fill css using current_fontspec. */ void - set_css( SPCSSAttr *css ); + fill_css( SPCSSAttr *css, Glib::ustring fontspec = "" ); Gtk::TreeModel::Row get_row_for_font (Glib::ustring family); @@ -292,7 +275,6 @@ namespace Inkscape Glib::RefPtr font_list_store; Glib::RefPtr style_list_store; - Glib::RefPtr style_list_store_trial; /** Info for currently selected font (what is shown in the UI). * May include font-family lists and fonts not on system. @@ -307,12 +289,6 @@ namespace Inkscape */ Glib::ustring current_fontspec_system; - /** Info for proposed font (what is shown in the font-selection UI). - * May include font-family lists and fonts not on system. - */ - Glib::ustring try_family; - Glib::ustring try_style; - /** If a font-family is not on system, this list of styles is used. */ GList *default_styles; -- cgit v1.2.3 From 168941350f6b28eab1a60e25682f1e958321ab11 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Mon, 4 Mar 2013 17:24:16 +0100 Subject: Use our own font_description_better_match which takes into account font-stretch and font-variant. (bzr r12171) --- src/libnrtype/font-lister.cpp | 120 +++++++++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 42 deletions(-) (limited to 'src/libnrtype') diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp index 97d3c66d4..1e3ba01e9 100644 --- a/src/libnrtype/font-lister.cpp +++ b/src/libnrtype/font-lister.cpp @@ -449,35 +449,7 @@ namespace Inkscape // Find best match to the style from the old font-family to the // styles available with the new font. // TODO: Maybe check if an exact match exists before using Pango. - Glib::ustring best_style = current_style; - if( check_style ) { - //std::cout << " Trying to match: " << current_fontspec << std::endl; - PangoFontDescription *desc_old - = pango_font_description_from_string( current_fontspec.c_str() ); - PangoFontDescription* desc_best = NULL; - - for (GList *l=styles; l; l = l->next) { - Glib::ustring candidate = new_family + ", " + (char*)l->data; - PangoFontDescription* desc_candidate - = pango_font_description_from_string( candidate.c_str() ); - //std::cout << " Testing: " << pango_font_description_to_string( desc_candidate ) << std::endl; - if( pango_font_description_better_match( desc_old, desc_best, desc_candidate ) ) { - pango_font_description_free( desc_best ); - desc_best = desc_candidate; - //std::cout << " ... better: " << std::endl; - } else { - pango_font_description_free( desc_candidate ); - //std::cout << " ... not better: " << std::endl; - } - } - if( desc_best ) { - pango_font_description_unset_fields( desc_best, PANGO_FONT_MASK_FAMILY ); - best_style = pango_font_description_to_string( desc_best ); - } - - if( desc_old ) pango_font_description_free( desc_old ); - if( desc_best ) pango_font_description_free( desc_best ); - } + Glib::ustring best_style = get_best_style_match( new_family, current_style ); #ifdef DEBUG_FONT std::cout << "FontLister::new_font_family: exit: " << new_family << " " << best_style << std::endl; @@ -863,6 +835,64 @@ namespace Inkscape throw STYLE_NOT_FOUND; } + static gint + compute_distance (const PangoFontDescription *a, + const PangoFontDescription *b ) { + + // Weight: multiples of 100 + gint distance = abs( pango_font_description_get_weight( a ) - + pango_font_description_get_weight( b ) ); + + distance += 10000 * abs( pango_font_description_get_stretch( a ) - + pango_font_description_get_stretch( b ) ); + + PangoStyle style_a = pango_font_description_get_style( a ); + PangoStyle style_b = pango_font_description_get_style( b ); + if( style_a != style_b ) { + if( (style_a == PANGO_STYLE_OBLIQUE && style_b == PANGO_STYLE_ITALIC) || + (style_b == PANGO_STYLE_OBLIQUE && style_a == PANGO_STYLE_ITALIC) ) { + distance += 1000; // Oblique and italic are almost the same + } else { + distance += 100000; // Normal vs oblique/italic, not so similar + } + } + + // Normal vs small-caps + distance += 1000000 * abs( pango_font_description_get_variant( a ) - + pango_font_description_get_variant( b ) ); + return distance; + } + + // This is inspired by pango_font_description_better_match, but that routine + // always returns false if variant or stretch are different. This means, for + // example, that PT Sans Narrow with style Bold Condensed is never matched + // to another font-family with Bold style. + gboolean + font_description_better_match( PangoFontDescription* target, + PangoFontDescription* old_desc, + PangoFontDescription* new_desc ) { + + if( old_desc == NULL ) return true; + if( new_desc == NULL ) return false; + + int old_distance = compute_distance( target, old_desc ); + int new_distance = compute_distance( target, new_desc ); + //std::cout << "font_description_better_match: old: " << old_distance << std::endl; + //std::cout << " new: " << new_distance << std::endl; + + return (new_distance < old_distance ); + } + + // void + // font_description_dump( PangoFontDescription* target ) { + // std::cout << " Font: " << pango_font_description_to_string( target ) << std::endl; + // std::cout << " style: " << pango_font_description_get_style( target ) << std::endl; + // std::cout << " weight: " << pango_font_description_get_weight( target ) << std::endl; + // std::cout << " variant: " << pango_font_description_get_variant( target ) << std::endl; + // std::cout << " stretch: " << pango_font_description_get_stretch( target ) << std::endl; + // std::cout << " gravity: " << pango_font_description_get_gravity( target ) << std::endl; + // } + /* Returns style string */ // TODO: Remove or turn into function to be used by new_font_family. Glib::ustring @@ -873,7 +903,7 @@ namespace Inkscape std::cout << "FontLister::get_best_style_match: " << family << " : " << target_style << std::endl; #endif - Glib::ustring font_string = family + " " + target_style; + Glib::ustring fontspec = family + ", " + target_style; Gtk::TreeModel::Row row; try { @@ -883,31 +913,37 @@ namespace Inkscape return (target_style); } - PangoFontDescription* target = pango_font_description_from_string( font_string.c_str() ); + PangoFontDescription* target = pango_font_description_from_string( fontspec.c_str() ); PangoFontDescription* best = NULL; - //std::cout << " Target: " << pango_font_description_to_string( target ) << std::endl; + //font_description_dump( target ); GList* styles = row[FontList.styles]; for (GList *l=styles; l; l = l->next) { - Glib::ustring font_string_test = family + " " + (char*)l->data; - PangoFontDescription* candidate = pango_font_description_from_string( font_string_test.c_str() ); - // std::cout << " Testing: " << pango_font_description_to_string( candidate ) << std::endl; - if( pango_font_description_better_match( target, best, candidate ) ) { - best = candidate; + Glib::ustring fontspec = family + ", " + (char*)l->data; + PangoFontDescription* candidate = pango_font_description_from_string( fontspec.c_str() ); + //font_description_dump( candidate ); + //std::cout << " " << font_description_better_match( target, best, candidate ) << std::endl; + if( font_description_better_match( target, best, candidate ) ) { + pango_font_description_free( best ); + best = candidate; + //std::cout << " ... better: " << std::endl; + } else { + pango_font_description_free( candidate ); + //std::cout << " ... not better: " << std::endl; } } - Glib::ustring best_style; + Glib::ustring best_style = target_style; if( best ) { - //std::cout << " Best: " << pango_font_description_to_string( best ) << std::endl; pango_font_description_unset_fields( best, PANGO_FONT_MASK_FAMILY ); best_style = pango_font_description_to_string( best ); - } else { - //std::cout << " Failed: " << family << std::endl; - best_style = target_style; } + if( target ) pango_font_description_free( target ); + if( best ) pango_font_description_free( best ); + + #ifdef DEBUG_FONT std::cout << " Returning: " << best_style << std::endl; std::cout << "FontLister::get_best_style_match: exit" << std::endl; -- cgit v1.2.3 From 4a5edfac0c0408d97c1ecd1b547cea87d06ab113 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Thu, 7 Mar 2013 22:03:29 +0100 Subject: Disable "faux" or "synthesized" font faces. (bzr r12177) --- src/libnrtype/FontFactory.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/libnrtype') diff --git a/src/libnrtype/FontFactory.cpp b/src/libnrtype/FontFactory.cpp index a9220d867..a1a9ddc89 100644 --- a/src/libnrtype/FontFactory.cpp +++ b/src/libnrtype/FontFactory.cpp @@ -741,6 +741,11 @@ void font_factory::GetUIFamiliesAndStyles(FamilyToStylesMap *map) continue; } + // Disable synthesized (faux) font faces + if (pango_font_face_is_synthesized(faces[currentFace]) ) { + continue; + } + PangoFontDescription *faceDescr = pango_font_face_describe(faces[currentFace]); if (faceDescr) { Glib::ustring familyUIName = GetUIFamilyString(faceDescr); -- cgit v1.2.3