diff options
| author | Liam P. White <inkscapebrony@gmail.com> | 2014-08-17 02:47:53 +0000 |
|---|---|---|
| committer | Liam P. White <inkscapebrony@gmail.com> | 2014-08-17 02:47:53 +0000 |
| commit | 2a2db8af11c2e518bd7bfe520e2f88a7e439d939 (patch) | |
| tree | bdbf9071af198a9b54d698eef9d6a1b77f857d73 | |
| parent | Add 'Show handles' LPE (diff) | |
| download | inkscape-2a2db8af11c2e518bd7bfe520e2f88a7e439d939.tar.gz inkscape-2a2db8af11c2e518bd7bfe520e2f88a7e439d939.zip | |
Merge in font-speedup branch to improve launch times
(bzr r13341.1.140)
| -rw-r--r-- | src/ink-comboboxentry-action.cpp | 18 | ||||
| -rw-r--r-- | src/libnrtype/FontFactory.cpp | 76 | ||||
| -rw-r--r-- | src/libnrtype/FontFactory.h | 10 | ||||
| -rw-r--r-- | src/libnrtype/font-lister.cpp | 1697 | ||||
| -rw-r--r-- | src/libnrtype/font-lister.h | 556 | ||||
| -rw-r--r-- | src/ui/dialog/text-edit.cpp | 6 | ||||
| -rw-r--r-- | src/widgets/font-selector.cpp | 4 | ||||
| -rw-r--r-- | src/widgets/text-toolbar.cpp | 10 |
8 files changed, 1239 insertions, 1138 deletions
diff --git a/src/ink-comboboxentry-action.cpp b/src/ink-comboboxentry-action.cpp index ebd238edc..6ae2a8485 100644 --- a/src/ink-comboboxentry-action.cpp +++ b/src/ink-comboboxentry-action.cpp @@ -383,6 +383,17 @@ GtkWidget* create_tool_item( GtkAction* action ) g_signal_connect( G_OBJECT(comboBoxEntry), "changed", G_CALLBACK(combo_box_changed_cb), action ); + // Optionally add separator function... + if( ink_comboboxentry_action->separator_func != NULL ) { + gtk_combo_box_set_row_separator_func( ink_comboboxentry_action->combobox, + GtkTreeViewRowSeparatorFunc (ink_comboboxentry_action->separator_func), + NULL, NULL ); + } + + // FIXME: once gtk3 migration is done this can be removed + // https://bugzilla.gnome.org/show_bug.cgi?id=734915 + gtk_widget_show_all (comboBoxEntry); + // Optionally add formatting... if( ink_comboboxentry_action->cell_data_func != NULL ) { GtkCellRenderer *cell = gtk_cell_renderer_text_new(); @@ -393,13 +404,6 @@ GtkWidget* create_tool_item( GtkAction* action ) NULL, NULL ); } - // Optionally add separator function... - if( ink_comboboxentry_action->separator_func != NULL ) { - gtk_combo_box_set_row_separator_func( ink_comboboxentry_action->combobox, - GtkTreeViewRowSeparatorFunc (ink_comboboxentry_action->separator_func), - NULL, NULL ); - } - // Optionally widen the combobox width... which widens the drop-down list in list mode. if( ink_comboboxentry_action->extra_width > 0 ) { GtkRequisition req; diff --git a/src/libnrtype/FontFactory.cpp b/src/libnrtype/FontFactory.cpp index 6859a4a5c..c5e68e264 100644 --- a/src/libnrtype/FontFactory.cpp +++ b/src/libnrtype/FontFactory.cpp @@ -513,6 +513,82 @@ static bool StyleNameCompareInternal(const StyleNames &style1, const StyleNames return( StyleNameValue( style1.CssName ) < StyleNameValue( style2.CssName ) ); } +static bool ustringPairSort(std::pair<PangoFontFamily*, Glib::ustring> const& first, std::pair<PangoFontFamily*, Glib::ustring> const& second) +{ + // well, this looks weird. + return first.second < second.second; +} + +void font_factory::GetUIFamilies(std::vector<PangoFontFamily *>& out) +{ + // Gather the family names as listed by Pango + PangoFontFamily** families = NULL; + int numFamilies = 0; + pango_font_map_list_families(fontServer, &families, &numFamilies); + + std::vector<std::pair<PangoFontFamily *, Glib::ustring> > sorted; + + // not size_t + for (int currentFamily = 0; currentFamily < numFamilies; ++currentFamily) { + const char* displayName = pango_font_family_get_name(families[currentFamily]); + + if (displayName == 0 || *displayName == '\0') { + continue; + } + sorted.push_back(std::make_pair(families[currentFamily], displayName)); + } + + std::sort(sorted.begin(), sorted.end(), ustringPairSort); + + for (size_t i = 0; i < sorted.size(); ++i) { + out.push_back(sorted[i].first); + } +} + +GList* font_factory::GetUIStyles(PangoFontFamily * in) +{ + GList* ret = NULL; + // Gather the styles for this family + PangoFontFace** faces = NULL; + int numFaces = 0; + pango_font_family_list_faces(in, &faces, &numFaces); + + for (int currentFace = 0; currentFace < numFaces; currentFace++) { + + // If the face has a name, describe it, and then use the + // description to get the UI family and face strings + const gchar* displayName = pango_font_face_get_face_name(faces[currentFace]); + if (displayName == NULL || *displayName == '\0') { + continue; + } + + PangoFontDescription *faceDescr = pango_font_face_describe(faces[currentFace]); + if (faceDescr) { + Glib::ustring familyUIName = GetUIFamilyString(faceDescr); + Glib::ustring styleUIName = GetUIStyleString(faceDescr); + + // Disable synthesized (faux) font faces except for CSS generic faces + if (pango_font_face_is_synthesized(faces[currentFace]) ) { + if (familyUIName.compare( "sans-serif" ) != 0 && + familyUIName.compare( "serif" ) != 0 && + familyUIName.compare( "monospace" ) != 0 && + familyUIName.compare( "fantasy" ) != 0 && + familyUIName.compare( "cursive" ) != 0 ) { + continue; + } + } + + if (!familyUIName.empty() && !styleUIName.empty()) { + // Add the style information + ret = g_list_append(ret, new StyleNames(styleUIName, displayName)); + } + } + pango_font_description_free(faceDescr); + } + g_free(faces); + return ret; +} + void font_factory::GetUIFamiliesAndStyles(FamilyToStylesMap *map) { g_assert(map); diff --git a/src/libnrtype/FontFactory.h b/src/libnrtype/FontFactory.h index 513ee4bf7..c48ae831a 100644 --- a/src/libnrtype/FontFactory.h +++ b/src/libnrtype/FontFactory.h @@ -23,7 +23,7 @@ #include "nr-type-primitives.h" #include "nr-type-pos-def.h" #include "font-style-to-pos.h" -#include "../style.h" +#include "style.h" /* Freetype */ #ifdef USE_PANGO_WIN32 @@ -123,7 +123,13 @@ public: // Gathers all strings needed for UI while storing pango information in // fontInstanceMap and fontStringMap + // don't use this function, it's too slow void GetUIFamiliesAndStyles(FamilyToStylesMap *map); + + // Helpfully inserts all font families into the provided vector + void GetUIFamilies(std::vector<PangoFontFamily *>& out); + // Retrieves style information about a family in a newly allocated GList. + GList* GetUIStyles(PangoFontFamily * in); /// Retrieve a font_instance from a style object, first trying to use the font-specification, the CSS information font_instance* FaceFromStyle(SPStyle const *style); @@ -177,4 +183,4 @@ private: fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 : diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp index 43c3045b1..07c80054d 100644 --- a/src/libnrtype/font-lister.cpp +++ b/src/libnrtype/font-lister.cpp @@ -1,5 +1,5 @@ #ifdef HAVE_CONFIG_H -# include <config.h> +#include <config.h> #endif #include <gtkmm/treemodel.h> @@ -27,410 +27,432 @@ // CSS dictates that font family names are case insensitive. // This should really implement full Unicode case unfolding. -bool familyNamesAreEqual( const Glib::ustring &a, const Glib::ustring &b ) { +bool familyNamesAreEqual(const Glib::ustring &a, const Glib::ustring &b) +{ + return (a.casefold().compare(b.casefold()) == 0); +} - return( a.casefold().compare( b.casefold() ) == 0 ); +static const char* sp_font_family_get_name(PangoFontFamily* family) +{ + const char* name = pango_font_family_get_name(family); + if (strncmp(name, "Sans", 4) == 0 && strlen(name) == 4) + return "sans-serif"; + if (strncmp(name, "Serif", 5) == 0 && strlen(name) == 5) + return "serif"; + if (strncmp(name, "Monospace", 9) == 0 && strlen(name) == 9) + return "monospace"; + return name; } -namespace Inkscape +namespace Inkscape { + +FontLister::FontLister() { - FontLister::FontLister () - { - font_list_store = Gtk::ListStore::create (FontList); - font_list_store->freeze_notify(); - - FamilyToStylesMap familyStyleMap; - font_factory::Default()->GetUIFamiliesAndStyles(&familyStyleMap); - - // Grab the family names into a list and then sort them - std::list<Glib::ustring> familyList; - for (FamilyToStylesMap::iterator iter = familyStyleMap.begin(); - iter != familyStyleMap.end(); - ++iter) { - familyList.push_back((*iter).first); + font_list_store = Gtk::ListStore::create(FontList); + font_list_store->freeze_notify(); + + /* Create default styles for use when font-family is unknown on system. */ + default_styles = g_list_append(NULL, new StyleNames("Normal")); + default_styles = g_list_append(default_styles, new StyleNames("Italic")); + default_styles = g_list_append(default_styles, new StyleNames("Bold")); + default_styles = g_list_append(default_styles, new StyleNames("Bold Italic")); + + // Get sorted font families from Pango + std::vector<PangoFontFamily *> familyVector; + font_factory::Default()->GetUIFamilies(familyVector); + + // Traverse through the family names and set up the list store + for (size_t i = 0; i < familyVector.size(); ++i) { + const char* displayName = sp_font_family_get_name(familyVector[i]); + + if (displayName == 0 || *displayName == '\0') { + continue; } - familyList.sort(); - // Traverse through the family names and set up the list store (note that - // the styles list that are the map's values are already sorted) - while (!familyList.empty()) { - Glib::ustring familyName = familyList.front(); - familyList.pop_front(); - - if (!familyName.empty()) { - Gtk::TreeModel::iterator treeModelIter = font_list_store->append(); - //(*treeModelIter)[FontList.family] = reinterpret_cast<const char*>(g_strdup(familyName.c_str())); - (*treeModelIter)[FontList.family] = familyName; - - // Now go through the styles - GList *styles = NULL; - std::list<StyleNames> &styleStrings = familyStyleMap[familyName]; - for (std::list<StyleNames>::iterator it=styleStrings.begin(); - it != styleStrings.end(); - ++it) { - // Our own copy - StyleNames *copy = new StyleNames( *it ); - styles = g_list_append(styles, copy); - } - - (*treeModelIter)[FontList.styles] = styles; - (*treeModelIter)[FontList.onSystem] = true; - } + Glib::ustring familyName = displayName; + if (!familyName.empty()) { + Gtk::TreeModel::iterator treeModelIter = font_list_store->append(); + (*treeModelIter)[FontList.family] = familyName; + + // we don't set this now (too slow) but the style will be cached if the user + // ever decides to use this font + (*treeModelIter)[FontList.styles] = NULL; + // store the pango representation for generating the style + (*treeModelIter)[FontList.pango_family] = familyVector[i]; + (*treeModelIter)[FontList.onSystem] = true; } - current_family_row = 0; - 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, new StyleNames( "Normal" ) ); - default_styles = g_list_append( default_styles, new StyleNames( "Italic" ) ); - default_styles = g_list_append( default_styles, new StyleNames( "Bold" ) ); - default_styles = g_list_append( default_styles, new StyleNames( "Bold Italic" ) ); - - font_list_store->thaw_notify(); - - style_list_store = Gtk::ListStore::create (FontStyleList); - - // Initialize style store with defaults - style_list_store->freeze_notify(); - style_list_store->clear(); - for (GList *l=default_styles; l; l = l->next) { - Gtk::TreeModel::iterator treeModelIter = style_list_store->append(); - (*treeModelIter)[FontStyleList.cssStyle] = ((StyleNames*)l->data)->CssName; - (*treeModelIter)[FontStyleList.displayStyle] = ((StyleNames*)l->data)->DisplayName; + } + + current_family_row = 0; + current_family = "sans-serif"; + current_style = "Normal"; + current_fontspec = "sans-serif"; // Empty style -> Normal + current_fontspec_system = "Sans"; + + font_list_store->thaw_notify(); + + style_list_store = Gtk::ListStore::create(FontStyleList); + + // Initialize style store with defaults + style_list_store->freeze_notify(); + style_list_store->clear(); + for (GList *l = default_styles; l; l = l->next) { + Gtk::TreeModel::iterator treeModelIter = style_list_store->append(); + (*treeModelIter)[FontStyleList.cssStyle] = ((StyleNames *)l->data)->CssName; + (*treeModelIter)[FontStyleList.displayStyle] = ((StyleNames *)l->data)->DisplayName; + } + style_list_store->thaw_notify(); +} + +FontLister::~FontLister() +{ + // Delete default_styles + for (GList *l = default_styles; l; l = l->next) { + delete ((StyleNames *)l->data); + } + + // Delete other styles + Gtk::TreeModel::iterator iter = font_list_store->get_iter("0"); + while (iter != font_list_store->children().end()) { + Gtk::TreeModel::Row row = *iter; + GList *styles = row[FontList.styles]; + for (GList *l = styles; l; l = l->next) { + delete ((StyleNames *)l->data); } - style_list_store->thaw_notify(); + ++iter; } +} - FontLister::~FontLister() { +FontLister *FontLister::get_instance() +{ + static Inkscape::FontLister *instance = new Inkscape::FontLister(); + return instance; +} - // Delete default_styles - for (GList *l=default_styles; l; l = l->next) { - delete ((StyleNames*)l->data); +void FontLister::ensureRowStyles(GtkTreeModel* model, GtkTreeIter const* iterator) +{ + Gtk::TreeIter iter(model, iterator); + Gtk::TreeModel::Row row = *iter; + if (!row[FontList.styles]) { + if (row[FontList.pango_family]) { + row[FontList.styles] = font_factory::Default()->GetUIStyles(row[FontList.pango_family]); } + } +} - // Delete other styles - Gtk::TreeModel::iterator iter = font_list_store->get_iter( "0" ); - while( iter != font_list_store->children().end() ) { - Gtk::TreeModel::Row row = *iter; - GList *styles = row[FontList.styles]; - for (GList *l=styles; l; l = l->next) { - delete ((StyleNames*)l->data); +// Example of how to use "foreach_iter" +// bool +// 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.family] << std::endl; +// return false; +// } +// return true; +// } +// font_list_store->foreach_iter( sigc::mem_fun(*this, &FontLister::print_document_font )); + +/* Used to insert a font that was not in the document and not on the system into the font list. */ +void FontLister::insert_font_family(Glib::ustring new_family) +{ + GList *styles = default_styles; + + /* In case this is a fallback list, check if first font-family on system. */ + std::vector<Glib::ustring> tokens = Glib::Regex::split_simple(",", new_family); + if (!tokens.empty() && !tokens[0].empty()) { + 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] && familyNamesAreEqual(tokens[0], row[FontList.family])) { + if (!row[FontList.styles]) { + row[FontList.styles] = font_factory::Default()->GetUIStyles(row[FontList.pango_family]); + } + styles = row[FontList.styles]; + break; } - ++iter; + ++iter2; } } - // Example of how to use "foreach_iter" - // bool - // 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.family] << std::endl; - // return false; - // } - // return true; - // } - // font_list_store->foreach_iter( sigc::mem_fun(*this, &FontLister::print_document_font )); - - /* Used to insert a font that was not in the document and not on the system into the font list. */ - void - FontLister::insert_font_family( Glib::ustring new_family ) { - - GList *styles = default_styles; - - /* In case this is a fallback list, check if first font-family on system. */ - std::vector<Glib::ustring> tokens = Glib::Regex::split_simple(",", new_family ); - if( !tokens.empty() && !tokens[0].empty() ) { - - 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] && familyNamesAreEqual( tokens[0], row[FontList.family] ) ) { - styles = row[FontList.styles]; + Gtk::TreeModel::iterator treeModelIter = font_list_store->prepend(); + (*treeModelIter)[FontList.family] = new_family; + (*treeModelIter)[FontList.styles] = styles; + (*treeModelIter)[FontList.onSystem] = false; +} + +void FontLister::update_font_list(SPDocument *document) +{ + SPObject *r = document->getRoot(); + if (!r) { + return; + } + + 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()) { + Gtk::TreeModel::Row row = *iter; + if (!row[FontList.onSystem]) { + // std::cout << " Not on system: " << row[FontList.family] << std::endl; + iter = font_list_store->erase(iter); + } else { + // std::cout << " First on system: " << row[FontList.family] << std::endl; break; - } - ++iter2; } - } + } + + /* Get "font-family"s used in document. */ + std::list<Glib::ustring> fontfamilies; + update_font_list_recursive(r, &fontfamilies); + + fontfamilies.sort(); + fontfamilies.unique(); + fontfamilies.reverse(); + - Gtk::TreeModel::iterator treeModelIter = font_list_store->prepend(); - (*treeModelIter)[FontList.family] = reinterpret_cast<const char*>(g_strdup(new_family.c_str())); - (*treeModelIter)[FontList.styles] = styles; - (*treeModelIter)[FontList.onSystem] = false; + /* Insert separator */ + if (!fontfamilies.empty()) { + Gtk::TreeModel::iterator treeModelIter = font_list_store->prepend(); + (*treeModelIter)[FontList.family] = "#"; + (*treeModelIter)[FontList.onSystem] = false; } - void - FontLister::update_font_list( SPDocument* document ) { - - SPObject *r = document->getRoot(); - if( !r ) { - return; - } - - 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() ) { - Gtk::TreeModel::Row row = *iter; - if( !row[FontList.onSystem] ) { - // std::cout << " Not on system: " << row[FontList.family] << std::endl; - iter = font_list_store->erase( iter ); - } else { - // std::cout << " First on system: " << row[FontList.family] << std::endl; - break; - } - } - - /* Get "font-family"s used in document. */ - std::list<Glib::ustring> fontfamilies; - update_font_list_recursive( r, &fontfamilies ); - - fontfamilies.sort(); - fontfamilies.unique(); - fontfamilies.reverse(); - - /* Insert separator */ - if( !fontfamilies.empty() ) { - Gtk::TreeModel::iterator treeModelIter = font_list_store->prepend(); - (*treeModelIter)[FontList.family] = "#"; - (*treeModelIter)[FontList.onSystem] = false; - } - - /* Insert font-family's in document. */ - std::list<Glib::ustring>::iterator i; - for( i = fontfamilies.begin(); i != fontfamilies.end(); ++i) { - - GList *styles = default_styles; + /* Insert font-family's in document. */ + std::list<Glib::ustring>::iterator i; + for (i = fontfamilies.begin(); i != fontfamilies.end(); ++i) { + + GList *styles = default_styles; /* See if font-family (or first in fallback list) is on system. If so, get styles. */ - std::vector<Glib::ustring> tokens = Glib::Regex::split_simple(",", *i ); - if( !tokens.empty() && !tokens[0].empty() ) { - - 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] && familyNamesAreEqual( tokens[0], row[FontList.family] ) ) { - styles = row[FontList.styles]; - break; - } - ++iter2; - } - } - - Gtk::TreeModel::iterator treeModelIter = font_list_store->prepend(); - (*treeModelIter)[FontList.family] = reinterpret_cast<const char*>(g_strdup((*i).c_str())); - (*treeModelIter)[FontList.styles] = styles; - (*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( familyNamesAreEqual( current_family, (*iter)[FontList.family] ) ) { - current_family_row = row; - break; - } - } - } - } - // std::cout << " Out: row: " << current_family_row << " " << current_family << std::endl; - - font_list_store->thaw_notify(); + std::vector<Glib::ustring> tokens = Glib::Regex::split_simple(",", *i); + if (!tokens.empty() && !tokens[0].empty()) { + + 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] && familyNamesAreEqual(tokens[0], row[FontList.family])) { + if (!row[FontList.styles]) { + row[FontList.styles] = font_factory::Default()->GetUIStyles(row[FontList.pango_family]); + } + styles = row[FontList.styles]; + break; + } + ++iter2; + } + } + + Gtk::TreeModel::iterator treeModelIter = font_list_store->prepend(); + (*treeModelIter)[FontList.family] = reinterpret_cast<const char *>(g_strdup((*i).c_str())); + (*treeModelIter)[FontList.styles] = styles; + (*treeModelIter)[FontList.onSystem] = false; + } - void - FontLister::update_font_list_recursive( SPObject *r, std::list<Glib::ustring> *l ) { + /* 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 (familyNamesAreEqual(current_family, (*iter)[FontList.family])) { + current_family_row = row; + break; + } + } + } + } + // std::cout << " Out: row: " << current_family_row << " " << current_family << std::endl; - const gchar *font_family = r->style->font_family.value; - if( font_family ) { - l->push_back( Glib::ustring( font_family ) ); - } + font_list_store->thaw_notify(); +} - for (SPObject *child = r->firstChild(); child; child = child->getNext()) { - update_font_list_recursive( child, l ); - } +void FontLister::update_font_list_recursive(SPObject *r, std::list<Glib::ustring> *l) +{ + const gchar *font_family = r->style->font_family.value; + if (font_family) { + l->push_back(Glib::ustring(font_family)); } - 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; + for (SPObject *child = r->firstChild(); child; child = child->getNext()) { + update_font_list_recursive(child, l); } +} + +Glib::ustring FontLister::canonize_fontspec(Glib::ustring fontspec) +{ - Glib::ustring - FontLister::system_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; + } - // Find what Pango thinks is the closest match. - Glib::ustring out = fontspec; + return Canonized; +} - PangoFontDescription *descr = pango_font_description_from_string(fontspec.c_str()); - font_instance *res = (font_factory::Default())->Face(descr); - if (res->pFont) { +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; } + pango_font_description_free(descr); + + return out; +} - std::pair<Glib::ustring, Glib::ustring> - 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); - if(!family) - family = "sans-serif"; - Glib::ustring Family = family; - - // PANGO BUG... - // A font spec of Delicious, 500 Italic should result in a family of 'Delicious' - // and a style of 'Medium Italic'. It results instead with: a family of - // 'Delicious, 500' with a style of 'Medium Italic'. We chop of any weight numbers - // at the end of the family: match ",[1-9]00^". - Glib::RefPtr<Glib::Regex> weight = Glib::Regex::create(",[1-9]00$"); - Family = weight->replace( Family, 0, "", Glib::REGEX_MATCH_PARTIAL ); - - // 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<Glib::ustring, Glib::ustring> 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); + if (!family) + family = "sans-serif"; + Glib::ustring Family = family; + + // PANGO BUG... + // A font spec of Delicious, 500 Italic should result in a family of 'Delicious' + // and a style of 'Medium Italic'. It results instead with: a family of + // 'Delicious, 500' with a style of 'Medium Italic'. We chop of any weight numbers + // at the end of the family: match ",[1-9]00^". + Glib::RefPtr<Glib::Regex> weight = Glib::Regex::create(",[1-9]00$"); + Family = weight->replace(Family, 0, "", Glib::REGEX_MATCH_PARTIAL); + + // 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; } - std::pair<Glib::ustring, Glib::ustring> - FontLister::selection_update () { + 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<Glib::ustring, Glib::ustring> FontLister::selection_update() +{ #ifdef DEBUG_FONT - std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; - std::cout << "FontLister::selection_update: entrance" << std::endl; + 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->font_specification.set ) { - fontspec = query->font_specification.value; - //std::cout << " fontspec from query :" << fontspec << ":" << std::endl; - } - - // From style - if( fontspec.empty() ) { + // 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->font_specification.set) { + fontspec = query->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() ) { + 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); + fontspec = fontspec_from_style(query); + //std::cout << " fontspec from prefs :" << fontspec << ":" << std::endl; + } + sp_style_unref(query); - // From thin air - if( fontspec.empty() ) { + // 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 + 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 ); + current_fontspec_system = system_fontspec(current_fontspec); - std::pair<Glib::ustring, Glib::ustring> ui = ui_from_fontspec( current_fontspec ); - set_font_family( ui.first ); - set_font_style( ui.second ); + std::pair<Glib::ustring, Glib::ustring> ui = ui_from_fontspec(current_fontspec); + set_font_family(ui.first); + set_font_style(ui.second); #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; - std::cout << " style: :" << current_style << ":" << std::endl; - std::cout << "FontLister::selection_update: exit" << std::endl; - std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << 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 - return std::make_pair( current_family, current_style ); - } - + return std::make_pair(current_family, current_style); +} + // Set fontspec. If check is false, best style match will not be done. -void FontLister::set_fontspec(Glib::ustring new_fontspec, gboolean /*check*/) +void FontLister::set_fontspec(Glib::ustring new_fontspec, bool /*check*/) { - std::pair<Glib::ustring,Glib::ustring> ui = ui_from_fontspec( new_fontspec ); + std::pair<Glib::ustring, Glib::ustring> ui = ui_from_fontspec(new_fontspec); Glib::ustring new_family = ui.first; Glib::ustring new_style = ui.second; @@ -439,13 +461,13 @@ void FontLister::set_fontspec(Glib::ustring new_fontspec, gboolean /*check*/) << " style:" << new_style << std::endl; #endif - set_font_family( new_family, false ); - set_font_style( new_style ); + set_font_family(new_family, false); + set_font_style(new_style); } // TODO: use to determine font-selector best style -std::pair<Glib::ustring, Glib::ustring> FontLister::new_font_family (Glib::ustring new_family, gboolean /*check_style*/ ) +std::pair<Glib::ustring, Glib::ustring> FontLister::new_font_family(Glib::ustring new_family, bool /*check_style*/) { #ifdef DEBUG_FONT std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; @@ -453,12 +475,12 @@ std::pair<Glib::ustring, Glib::ustring> FontLister::new_font_family (Glib::ustri #endif // No need to do anything if new family is same as old family. - if ( familyNamesAreEqual( new_family, current_family ) ) { + if (familyNamesAreEqual(new_family, current_family)) { #ifdef DEBUG_FONT - std::cout << "FontLister::new_font_family: exit: no change in family." << std::endl; - std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; + 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 ); + return std::make_pair(current_family, current_style); } // We need to do two things: @@ -466,596 +488,597 @@ std::pair<Glib::ustring, Glib::ustring> FontLister::new_font_family (Glib::ustri // 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() ) { + 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; + Gtk::TreeModel::Row row = *iter; - if( familyNamesAreEqual( new_family, row[FontList.family] ) ) { + if (familyNamesAreEqual(new_family, row[FontList.family])) { + if (!row[FontList.styles]) { + row[FontList.styles] = font_factory::Default()->GetUIStyles(row[FontList.pango_family]); + } styles = row[FontList.styles]; break; - } - ++iter; + } + ++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; + if (styles == NULL) { + styles = default_styles; } - + // Update style list. 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.cssStyle] = ((StyleNames*)l->data)->CssName; - (*treeModelIter)[FontStyleList.displayStyle] = ((StyleNames*)l->data)->DisplayName; + for (GList *l = styles; l; l = l->next) { + Gtk::TreeModel::iterator treeModelIter = style_list_store->append(); + (*treeModelIter)[FontStyleList.cssStyle] = ((StyleNames *)l->data)->CssName; + (*treeModelIter)[FontStyleList.displayStyle] = ((StyleNames *)l->data)->DisplayName; } 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 = get_best_style_match( new_family, current_style ); + 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; std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; #endif - return std::make_pair( new_family, best_style ); + return std::make_pair(new_family, best_style); } - - std::pair<Glib::ustring, Glib::ustring> - FontLister::set_font_family (Glib::ustring new_family, gboolean check_style) { + +std::pair<Glib::ustring, Glib::ustring> FontLister::set_font_family(Glib::ustring new_family, bool check_style) +{ #ifdef DEBUG_FONT - std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; - std::cout << "FontLister::set_font_family: " << new_family << std::endl; + std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + std::cout << "FontLister::set_font_family: " << new_family << std::endl; #endif - std::pair<Glib::ustring, Glib::ustring> 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 ); + std::pair<Glib::ustring, Glib::ustring> 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 << " 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::set_font_family: end" << std::endl; - std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << 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::set_font_family: end" << std::endl; + std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; #endif - return ui; - } - + return ui; +} - std::pair<Glib::ustring, Glib::ustring> - FontLister::set_font_family (int row, gboolean check_style) { + +std::pair<Glib::ustring, Glib::ustring> FontLister::set_font_family(int row, bool check_style) +{ #ifdef DEBUG_FONT - std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; - std::cout << "FontLister::set_font_family( row ): " << row << std::endl; + 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 ) { - new_family = (*iter)[FontList.family]; - } + 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) { + new_family = (*iter)[FontList.family]; + } - std::pair<Glib::ustring, Glib::ustring> ui = set_font_family( new_family, check_style ); + std::pair<Glib::ustring, Glib::ustring> 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; + std::cout << "FontLister::set_font_family( row ): end" << std::endl; + std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; #endif - return ui; - } + return ui; +} - void - FontLister::set_font_style (Glib::ustring new_style) { +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. +// 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; + 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 ); + 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; + 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 +} + + +// We do this ourselves as we can't rely on FontFactory. +void FontLister::fill_css(SPCSSAttr *css, Glib::ustring fontspec) +{ + + if (fontspec.empty()) { + fontspec = current_fontspec; + } + std::pair<Glib::ustring, Glib::ustring> ui = ui_from_fontspec(fontspec); + + Glib::ustring family = ui.first; + + + // Font spec is single quoted... for the moment + Glib::ustring fontspec_quoted(fontspec); + css_quote(fontspec_quoted); + sp_repr_css_set_property(css, "-inkscape-font-specification", fontspec_quoted.c_str()); + + // Font families needs to be properly quoted in CSS (used unquoted in font-lister) + css_font_family_quote(family); + sp_repr_css_set_property(css, "font-family", family.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: + 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; + } - // We do this ourselves as we can't rely on FontFactory. - void - FontLister::fill_css( SPCSSAttr *css, Glib::ustring fontspec ) { - - if( fontspec.empty() ) { - fontspec = current_fontspec; - } - std::pair<Glib::ustring,Glib::ustring> ui = ui_from_fontspec( fontspec ); - - Glib::ustring family = ui.first; - - - // Font spec is single quoted... for the moment - Glib::ustring fontspec_quoted( fontspec ); - css_quote( fontspec_quoted ); - sp_repr_css_set_property (css, "-inkscape-font-specification", fontspec_quoted.c_str() ); - - // Font families needs to be properly quoted in CSS (used unquoted in font-lister) - css_font_family_quote( family ); - sp_repr_css_set_property (css, "font-family", family.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: - 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; - } + 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) { +// 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; + //std::cout << "FontLister:fontspec_from_style: " << std::endl; - Glib::ustring fontspec; - if (style) { + Glib::ustring fontspec; + if (style) { - // First try to use the font specification if it is set - if (style->font_specification.set - && style->font_specification.value - && *style->font_specification.value) { + // First try to use the font specification if it is set + if (style->font_specification.set && style->font_specification.value && *style->font_specification.value) { - fontspec = style->font_specification.value; + fontspec = style->font_specification.value; } else { - fontspec = style->font_family.value; - fontspec += ","; - - // Use weight names as defined by Pango - switch (style->font_weight.computed) { + fontspec = style->font_family.value; + fontspec += ","; - case SP_CSS_FONT_WEIGHT_100: - fontspec += " Thin"; - break; - - case SP_CSS_FONT_WEIGHT_200: - fontspec += " Ultra-Light"; - break; + // Use weight names as defined by Pango + switch (style->font_weight.computed) { - case SP_CSS_FONT_WEIGHT_300: - fontspec += " Light"; - break; + case SP_CSS_FONT_WEIGHT_100: + fontspec += " Thin"; + break; - case SP_CSS_FONT_WEIGHT_400: - case SP_CSS_FONT_WEIGHT_NORMAL: - //fontspec += " normal"; - break; - - case SP_CSS_FONT_WEIGHT_500: - fontspec += " Medium"; - break; - - case SP_CSS_FONT_WEIGHT_600: - fontspec += " Semi-Bold"; - break; - - case SP_CSS_FONT_WEIGHT_700: - case SP_CSS_FONT_WEIGHT_BOLD: - fontspec += " Bold"; - break; - - case SP_CSS_FONT_WEIGHT_800: - fontspec += " Ultra-Bold"; - break; - - case SP_CSS_FONT_WEIGHT_900: - fontspec += " Heavy"; - 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 ); - } + case SP_CSS_FONT_WEIGHT_200: + fontspec += " Ultra-Light"; + break; + case SP_CSS_FONT_WEIGHT_300: + fontspec += " Light"; + break; - Gtk::TreeModel::Row - FontLister::get_row_for_font (Glib::ustring family) - { - Gtk::TreePath path; + case SP_CSS_FONT_WEIGHT_400: + case SP_CSS_FONT_WEIGHT_NORMAL: + //fontspec += " normal"; + break; + + case SP_CSS_FONT_WEIGHT_500: + fontspec += " Medium"; + break; + + case SP_CSS_FONT_WEIGHT_600: + fontspec += " Semi-Bold"; + break; - Gtk::TreeModel::iterator iter = font_list_store->get_iter( "0" ); - while( iter != font_list_store->children().end() ) { + case SP_CSS_FONT_WEIGHT_700: + case SP_CSS_FONT_WEIGHT_BOLD: + fontspec += " Bold"; + break; - Gtk::TreeModel::Row row = *iter; + case SP_CSS_FONT_WEIGHT_800: + fontspec += " Ultra-Bold"; + break; - if( familyNamesAreEqual( family, row[FontList.family] ) ) { - return row; - } + case SP_CSS_FONT_WEIGHT_900: + fontspec += " Heavy"; + break; - ++iter; - } + case SP_CSS_FONT_WEIGHT_LIGHTER: + case SP_CSS_FONT_WEIGHT_BOLDER: + default: + g_warning("Unrecognized font_weight.computed value"); + break; + } - throw FAMILY_NOT_FOUND; - } + switch (style->font_style.computed) { + case SP_CSS_FONT_STYLE_ITALIC: + fontspec += " italic"; + break; - Gtk::TreePath - FontLister::get_path_for_font (Glib::ustring family) - { - return font_list_store->get_path( get_row_for_font ( family ) ); + 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_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 FontLister::get_row_for_font(Glib::ustring family) +{ + Gtk::TreePath path; - Gtk::TreeModel::Row row = *iter; + Gtk::TreeModel::iterator iter = font_list_store->get_iter("0"); + while (iter != font_list_store->children().end()) { - if( familyNamesAreEqual( style, row[FontStyleList.cssStyle] ) ) { - return row; - } + Gtk::TreeModel::Row row = *iter; - ++iter; - } + if (familyNamesAreEqual(family, row[FontList.family])) { + return row; + } - throw STYLE_NOT_FOUND; + ++iter; } - 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; + 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)); +} + +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 (familyNamesAreEqual(style, row[FontStyleList.cssStyle])) { + return row; + } + + ++iter; } - // 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 ) { + throw STYLE_NOT_FOUND; +} + +static gint compute_distance(const PangoFontDescription *a, const PangoFontDescription *b) +{ - if( old_desc == NULL ) return true; - if( new_desc == NULL ) return false; + // Weight: multiples of 100 + gint distance = abs(pango_font_description_get_weight(a) - + pango_font_description_get_weight(b)); - 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; + distance += 10000 * abs(pango_font_description_get_stretch(a) - + pango_font_description_get_stretch(b)); - return (new_distance < old_distance ); + 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 + } } - // 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 - FontLister::get_best_style_match (Glib::ustring family, Glib::ustring target_style) { + // Normal vs small-caps + distance += 1000000 * abs(pango_font_description_get_variant(a) - + pango_font_description_get_variant(b)); + return distance; +} -#ifdef DEBUG_FONT - std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; - std::cout << "FontLister::get_best_style_match: " << family << " : " << target_style << std::endl; -#endif +// 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; - Glib::ustring fontspec = 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( fontspec.c_str() ); - PangoFontDescription* best = NULL; - - //font_description_dump( target ); - - GList* styles = row[FontList.styles]; - for (GList *l=styles; l; l = l->next) { - 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 = target_style; - if( best ) { - pango_font_description_unset_fields( best, PANGO_FONT_MASK_FAMILY ); - best_style = pango_font_description_to_string( best ); - } - - if( target ) pango_font_description_free( target ); - if( best ) pango_font_description_free( best ); + 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 FontLister::get_best_style_match(Glib::ustring family, Glib::ustring 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; + std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + std::cout << "FontLister::get_best_style_match: " << family << " : " << target_style << std::endl; #endif - return best_style; - } - const Glib::RefPtr<Gtk::ListStore> - FontLister::get_font_list () const + Glib::ustring fontspec = family + ", " + target_style; + + Gtk::TreeModel::Row row; + try { - return font_list_store; + row = get_row_for_font(family); } - - const Glib::RefPtr<Gtk::ListStore> - FontLister::get_style_list () const + catch (...) { - return style_list_store; + //std::cout << " ERROR: can't find family: " << family << std::endl; + return (target_style); } + + PangoFontDescription *target = pango_font_description_from_string(fontspec.c_str()); + PangoFontDescription *best = NULL; + + //font_description_dump( target ); + + if (!row[FontList.styles]) { + row[FontList.styles] = font_factory::Default()->GetUIStyles(row[FontList.pango_family]); + } + GList *styles = row[FontList.styles]; + for (GList *l = styles; l; l = l->next) { + 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 = target_style; + if (best) { + pango_font_description_unset_fields(best, PANGO_FONT_MASK_FAMILY); + best_style = pango_font_description_to_string(best); + } + + 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; + std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; +#endif + return best_style; } +const Glib::RefPtr<Gtk::ListStore> FontLister::get_font_list() const +{ + return font_list_store; +} + +const Glib::RefPtr<Gtk::ListStore> FontLister::get_style_list() const +{ + return style_list_store; +} + +} // namespace Inkscape + // Helper functions // Separator function (if true, a separator will be drawn) -gboolean font_lister_separator_func(GtkTreeModel *model, - GtkTreeIter *iter, - gpointer /*data*/) +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.family - return (text && strcmp(text,"#") == 0); + gchar *text = 0; + gtk_tree_model_get(model, iter, 0, &text, -1); // Column 0: FontList.family + return (text && strcmp(text, "#") == 0); } -void font_lister_cell_data_func(GtkCellLayout */*cell_layout*/, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer /*data*/) +void font_lister_cell_data_func(GtkCellLayout * /*cell_layout*/, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer /*data*/) { gchar *family; gboolean onSystem = false; gtk_tree_model_get(model, iter, 0, &family, 2, &onSystem, -1); - Glib::ustring family_escaped = g_markup_escape_text(family, -1); + gchar* family_escaped = g_markup_escape_text(family, -1); //g_free(family); Glib::ustring markup; - if( !onSystem ) { + if (!onSystem) { markup = "<span foreground='darkblue'>"; /* See if font-family on system */ - std::vector<Glib::ustring> tokens = Glib::Regex::split_simple("\\s*,\\s*", family_escaped ); - for( size_t i=0; i < tokens.size(); ++i ) { + std::vector<Glib::ustring> tokens = Glib::Regex::split_simple("\\s*,\\s*", family_escaped); + for (size_t i = 0; i < tokens.size(); ++i) { Glib::ustring token = tokens[i]; @@ -1064,17 +1087,17 @@ void font_lister_cell_data_func(GtkCellLayout */*cell_layout*/, gchar *family = 0; gboolean onSystem = true; gboolean found = false; - for( valid = gtk_tree_model_get_iter_first( GTK_TREE_MODEL(model), &iter ); + for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); valid; - valid = gtk_tree_model_iter_next( GTK_TREE_MODEL(model), &iter ) ) { + valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter)) { gtk_tree_model_get(model, &iter, 0, &family, 2, &onSystem, -1); - if( onSystem && familyNamesAreEqual( token, family ) ) { + if (onSystem && familyNamesAreEqual(token, family)) { found = true; break; } } - if( found ) { + if (found) { markup += g_markup_escape_text(token.c_str(), -1); markup += ", "; } else { @@ -1085,13 +1108,13 @@ void font_lister_cell_data_func(GtkCellLayout */*cell_layout*/, } } // Remove extra comma and space from end. - if( markup.size() >= 2 ) { - markup.resize( markup.size()-2 ); + if (markup.size() >= 2) { + markup.resize(markup.size() - 2); } markup += "</span>"; // std::cout << markup << std::endl; } else { - markup = family_escaped; + markup = family_escaped; } Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -1099,7 +1122,7 @@ void font_lister_cell_data_func(GtkCellLayout */*cell_layout*/, if (show_sample) { Glib::ustring sample = prefs->getString("/tools/text/font_sample"); - Glib::ustring sample_escaped = g_markup_escape_text(sample.data(), -1); + Glib::ustring sample_escaped = Glib::Markup::escape_text(sample); markup += " <span foreground='gray' font_family='"; markup += family_escaped; @@ -1108,8 +1131,10 @@ void font_lister_cell_data_func(GtkCellLayout */*cell_layout*/, markup += "</span>"; } - g_object_set (G_OBJECT (cell), "markup", markup.c_str(), NULL); + g_object_set(G_OBJECT(cell), "markup", markup.c_str(), NULL); + g_free(family_escaped); } + /* Local Variables: mode:c++ @@ -1119,4 +1144,4 @@ void font_lister_cell_data_func(GtkCellLayout */*cell_layout*/, fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 : diff --git a/src/libnrtype/font-lister.h b/src/libnrtype/font-lister.h index c89dab550..18e0d4b6e 100644 --- a/src/libnrtype/font-lister.h +++ b/src/libnrtype/font-lister.h @@ -28,294 +28,280 @@ class SPDocument; class SPCSSAttr; class SPStyle; -namespace Inkscape -{ - /** - * This class enumerates fonts using libnrtype into reusable data stores and - * 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 - { - public: - - enum Exceptions - { - FAMILY_NOT_FOUND, - STYLE_NOT_FOUND - }; - - - virtual ~FontLister (); - - /** GtkTreeModelColumnRecord for the font-family list Gtk::ListStore - */ - class FontListClass - : public Gtk::TreeModelColumnRecord - { - public: - /** Column containing the family name - */ - Gtk::TreeModelColumn<Glib::ustring> family; - - /** Column containing the styles for each family name. - */ - Gtk::TreeModelColumn<GList*> styles; - - /** Column containing flag if font is on system - */ - Gtk::TreeModelColumn<gboolean> onSystem; - - FontListClass () - { - add (family); - add (styles); - add (onSystem); - } - }; - - FontListClass FontList; - - class FontStyleListClass - : public Gtk::TreeModelColumnRecord - { - public: - /** Column containing the styles as Font designer used. - */ - Gtk::TreeModelColumn<Glib::ustring> displayStyle; - - /** Column containing the styles in CSS/Pango format. - */ - Gtk::TreeModelColumn<Glib::ustring> cssStyle; - - FontStyleListClass () - { - add (cssStyle); - add (displayStyle); - } - }; - - FontStyleListClass FontStyleList; - - /** 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 - * and should not (cannot) be modified. - */ - const Glib::RefPtr<Gtk::ListStore> - get_font_list () const; - - /** Returns the ListStore with the styles - * - */ - const Glib::RefPtr<Gtk::ListStore> - get_style_list () const; - - /** Inserts a font family or font-fallback list (for use when not - * already in document or on system). - */ - void - insert_font_family ( Glib::ustring new_family ); - - /** Updates font list to include fonts in document - * - */ - void - update_font_list ( SPDocument* document); - - private: - void - update_font_list_recursive( SPObject *r, std::list<Glib::ustring> *l ); - - public: - static Inkscape::FontLister* - get_instance () - { - static Inkscape::FontLister* instance = new Inkscape::FontLister(); - return instance; - } - - /** 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<Glib::ustring, Glib::ustring> - ui_from_fontspec (Glib::ustring fontspec); - - /** Sets font-family and style after a selection change. - * New font-family and style returned. - */ - std::pair<Glib::ustring, Glib::ustring> - 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. - * Does NOT update current_family and current_style. - * (For potential use in font-selector which doesn't update until - * "Apply" button clicked.) - */ - std::pair<Glib::ustring, Glib::ustring> - 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. - * Calls new_font_family(). - * (For use in text-toolbar where update is immediate.) - */ - std::pair<Glib::ustring, Glib::ustring> - 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<Glib::ustring, Glib::ustring> - 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; - } - - /** Sets style. Does not validate style for family. - */ - void - set_font_style (Glib::ustring style); - - Glib::ustring - get_font_style () - { - return current_style; - } - - Glib::ustring - fontspec_from_style (SPStyle* style); - - /** Fill css using current_fontspec. - */ - void - fill_css( SPCSSAttr *css, Glib::ustring fontspec = "" ); - - 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<Gtk::TreePath, Gtk::TreePath> - 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 - { - return families; - } - - private: - - FontLister (); - - NRNameList families; - - Glib::RefPtr<Gtk::ListStore> font_list_store; - Glib::RefPtr<Gtk::ListStore> style_list_store; - - /** 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; - - /** fontspec of system font closest to current_fontspec. - * (What the system will use to display current_fontspec.) - */ - Glib::ustring current_fontspec_system; - - /** If a font-family is not on system, this list of styles is used. - */ - GList *default_styles; - }; -} +namespace Inkscape { + +/** + * This class enumerates fonts using libnrtype into reusable data stores and + * 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 { +public: + enum Exceptions { + FAMILY_NOT_FOUND, + STYLE_NOT_FOUND + }; + + virtual ~FontLister(); + + /** + * GtkTreeModelColumnRecord for the font-family list Gtk::ListStore + */ + struct FontListClass : public Gtk::TreeModelColumnRecord { + /** + * Column containing the family name + */ + Gtk::TreeModelColumn<Glib::ustring> family; + + /** + * Column containing the styles for each family name. + */ + Gtk::TreeModelColumn<GList *> styles; + + /** + * Column containing flag if font is on system + */ + Gtk::TreeModelColumn<bool> onSystem; + + /** + * Not actually a column. + * Necessary for quick initialization of FontLister, + * we initially store the pango family and if the + * font style is actually used we'll cache it in + * %styles. + */ + Gtk::TreeModelColumn<PangoFontFamily *> pango_family; + + FontListClass() + { + add(family); + add(styles); + add(onSystem); + add(pango_family); + } + }; + + FontListClass FontList; + + struct FontStyleListClass : public Gtk::TreeModelColumnRecord { + /** + * Column containing the styles as Font designer used. + */ + Gtk::TreeModelColumn<Glib::ustring> displayStyle; + + /** + * Column containing the styles in CSS/Pango format. + */ + Gtk::TreeModelColumn<Glib::ustring> cssStyle; + + FontStyleListClass() + { + add(cssStyle); + add(displayStyle); + } + }; + + FontStyleListClass FontStyleList; + + /** + * @return 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 + * and should not be modified. + */ + const Glib::RefPtr<Gtk::ListStore> get_font_list() const; + + /** + * @return the ListStore with the styles + */ + const Glib::RefPtr<Gtk::ListStore> get_style_list() const; + + /** + * Inserts a font family or font-fallback list (for use when not + * already in document or on system). + */ + void insert_font_family(Glib::ustring new_family); + + /** + * Updates font list to include fonts in document. + */ + void update_font_list(SPDocument *document); + +public: + static Inkscape::FontLister *get_instance(); + + /** + * 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<Glib::ustring, Glib::ustring> ui_from_fontspec(Glib::ustring fontspec); + + /** + * Sets font-family and style after a selection change. + * New font-family and style returned. + */ + std::pair<Glib::ustring, Glib::ustring> 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, bool 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. + * Does NOT update current_family and current_style. + * (For potential use in font-selector which doesn't update until + * "Apply" button clicked.) + */ + std::pair<Glib::ustring, Glib::ustring> new_font_family(Glib::ustring family, bool 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. + * Calls new_font_family(). + * (For use in text-toolbar where update is immediate.) + */ + std::pair<Glib::ustring, Glib::ustring> set_font_family(Glib::ustring family, bool 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<Glib::ustring, Glib::ustring> set_font_family(int row, bool check_style = true); + + Glib::ustring get_font_family() + { + return current_family; + } + + int get_font_family_row() + { + return current_family_row; + } + + /** + * Sets style. Does not validate style for family. + */ + void set_font_style(Glib::ustring style); + + Glib::ustring get_font_style() + { + return current_style; + } + + Glib::ustring fontspec_from_style(SPStyle *style); + + /** + * Fill css using current_fontspec. + */ + void fill_css(SPCSSAttr *css, Glib::ustring fontspec = ""); + + 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<Gtk::TreePath, Gtk::TreePath> 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); + + void ensureRowStyles(GtkTreeModel* model, GtkTreeIter const* iter); + +private: + FontLister(); + + void update_font_list_recursive(SPObject *r, std::list<Glib::ustring> *l); + + Glib::RefPtr<Gtk::ListStore> font_list_store; + Glib::RefPtr<Gtk::ListStore> style_list_store; + + /** + * 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; + + /** + * fontspec of system font closest to current_fontspec. + * (What the system will use to display current_fontspec.) + */ + Glib::ustring current_fontspec_system; + + /** + * If a font-family is not on system, this list of styles is used. + */ + GList *default_styles; +}; + +} // namespace Inkscape // Helper functions gboolean font_lister_separator_func(GtkTreeModel *model, - GtkTreeIter *iter, - gpointer /*data*/); + GtkTreeIter *iter, + gpointer /*data*/); -void font_lister_cell_data_func(GtkCellLayout */*cell_layout*/, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer /*data*/); +void font_lister_cell_data_func(GtkCellLayout * /*cell_layout*/, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer /*data*/); #endif @@ -328,4 +314,4 @@ void font_lister_cell_data_func(GtkCellLayout */*cell_layout*/, fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 : diff --git a/src/ui/dialog/text-edit.cpp b/src/ui/dialog/text-edit.cpp index c1ebb32e0..e44809c65 100644 --- a/src/ui/dialog/text-edit.cpp +++ b/src/ui/dialog/text-edit.cpp @@ -344,9 +344,9 @@ void TextEdit::onReadSelection ( gboolean dostyle, gboolean /*docontent*/ ) Inkscape::FontLister* fontlister = Inkscape::FontLister::get_instance(); - // This is done for us by text-toolbar. No need to do it twice. - // fontlister->update_font_list( sp_desktop_document( SP_ACTIVE_DESKTOP )); - // fontlister->selection_update(); + // This is normally done for us by text-toolbar but only when we are in text editing context + fontlister->update_font_list(sp_desktop_document(this->desktop)); + fontlister->selection_update(); Glib::ustring fontspec = fontlister->get_fontspec(); diff --git a/src/widgets/font-selector.cpp b/src/widgets/font-selector.cpp index ccaf93e55..c9a52ef11 100644 --- a/src/widgets/font-selector.cpp +++ b/src/widgets/font-selector.cpp @@ -303,6 +303,9 @@ static void sp_font_selector_family_select_row(GtkTreeSelection *selection, GtkTreeModel *model; GtkTreeIter iter; if (!gtk_tree_selection_get_selected (selection, &model, &iter)) return; + + Inkscape::FontLister *fontlister = Inkscape::FontLister::get_instance(); + fontlister->ensureRowStyles(model, &iter); // Next get family name with its style list gchar *family; @@ -310,7 +313,6 @@ static void sp_font_selector_family_select_row(GtkTreeSelection *selection, gtk_tree_model_get (model, &iter, 0, &family, 1, &list, -1); // Find best style match for selected family with current style (e.g. of selected text). - Inkscape::FontLister *fontlister = Inkscape::FontLister::get_instance(); Glib::ustring style = fontlister->get_font_style(); Glib::ustring best = fontlister->get_best_style_match (family, style); diff --git a/src/widgets/text-toolbar.cpp b/src/widgets/text-toolbar.cpp index 408babf06..88f698bc4 100644 --- a/src/widgets/text-toolbar.cpp +++ b/src/widgets/text-toolbar.cpp @@ -819,7 +819,7 @@ static void sp_text_set_sizes(GtkListStore* model_size, int unit) * It is called whenever a text selection is changed, including stepping cursor * through text, or setting focus to text. */ -static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/, GObject *tbl) +static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/, GObject *tbl, bool subselection = false) // don't bother to update font list if subsel changed { #ifdef DEBUG_TEXT static int count = 0; @@ -859,7 +859,9 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/ INK_COMBOBOXENTRY_ACTION( g_object_get_data( tbl, "TextFontStyleAction" ) ); Inkscape::FontLister* fontlister = Inkscape::FontLister::get_instance(); - fontlister->update_font_list( sp_desktop_document( SP_ACTIVE_DESKTOP )); + if (!subselection) { + fontlister->update_font_list( sp_desktop_document( SP_ACTIVE_DESKTOP )); + } fontlister->selection_update(); // Update font list, but only if widget already created. @@ -1154,7 +1156,7 @@ static void sp_text_toolbox_selection_modified(Inkscape::Selection *selection, g static void sp_text_toolbox_subselection_changed (gpointer /*tc*/, GObject *tbl) { - sp_text_toolbox_selection_changed (NULL, tbl); + sp_text_toolbox_selection_changed (NULL, tbl, true); } // TODO: possibly share with font-selector by moving most code to font-lister (passing family name) @@ -1640,7 +1642,7 @@ static void text_toolbox_watch_ec(SPDesktop* desktop, Inkscape::UI::Tools::ToolB if (SP_IS_TEXT_CONTEXT(ec)) { // Watch selection - c_selection_changed = sp_desktop_selection(desktop)->connectChanged(bind(ptr_fun(sp_text_toolbox_selection_changed), holder)); + c_selection_changed = sp_desktop_selection(desktop)->connectChanged(bind(ptr_fun(sp_text_toolbox_selection_changed), holder, false)); c_selection_modified = sp_desktop_selection (desktop)->connectModified(bind(ptr_fun(sp_text_toolbox_selection_modified), holder)); c_subselection_changed = desktop->connectToolSubselectionChanged(bind(ptr_fun(sp_text_toolbox_subselection_changed), holder)); } else { |
