summaryrefslogtreecommitdiffstats
path: root/src/libnrtype
diff options
context:
space:
mode:
authorsu_v <suv-sf@users.sourceforge.net>2013-02-13 18:36:57 +0000
committer~suv <suv-sf@users.sourceforge.net>2013-02-13 18:36:57 +0000
commit77b788bb1c5fa861a3f12c76ad3f17bc8edc35b8 (patch)
tree441f798cf2c8cb3a760c1ecf259f5faff356124c /src/libnrtype
parentchanges_2013_02_01b.patch (diff)
parentBuild. Adding unistd header (fixes compilation on Win32 with OpenSuse cross-c... (diff)
downloadinkscape-77b788bb1c5fa861a3f12c76ad3f17bc8edc35b8.tar.gz
inkscape-77b788bb1c5fa861a3f12c76ad3f17bc8edc35b8.zip
merge from trunk (r12122)
(bzr r11668.1.51)
Diffstat (limited to 'src/libnrtype')
-rw-r--r--src/libnrtype/FontFactory.cpp66
-rw-r--r--src/libnrtype/FontFactory.h3
-rw-r--r--src/libnrtype/FontInstance.cpp4
-rw-r--r--src/libnrtype/Layout-TNG-Output.cpp4
-rw-r--r--src/libnrtype/font-lister.cpp230
-rw-r--r--src/libnrtype/font-lister.h60
6 files changed, 327 insertions, 40 deletions
diff --git a/src/libnrtype/FontFactory.cpp b/src/libnrtype/FontFactory.cpp
index 98904a47a..a9220d867 100644
--- a/src/libnrtype/FontFactory.cpp
+++ b/src/libnrtype/FontFactory.cpp
@@ -28,7 +28,7 @@ typedef INK_UNORDERED_MAP<PangoFontDescription*, font_instance*, font_descr_hash
size_t font_descr_hash::operator()( PangoFontDescription *const &x) const {
int h = 0;
h *= 1128467;
- char const *theF = pango_font_description_get_family(x);
+ char const *theF = sp_font_description_get_family(x);
h += (theF)?g_str_hash(theF):0;
h *= 1128467;
h += (int)pango_font_description_get_style(x);
@@ -42,8 +42,8 @@ size_t font_descr_hash::operator()( PangoFontDescription *const &x) const {
}
bool font_descr_equal::operator()( PangoFontDescription *const&a, PangoFontDescription *const &b) const {
//if ( pango_font_description_equal(a,b) ) return true;
- char const *fa = pango_font_description_get_family(a);
- char const *fb = pango_font_description_get_family(b);
+ char const *fa = sp_font_description_get_family(a);
+ char const *fb = sp_font_description_get_family(b);
if ( ( fa && fb == NULL ) || ( fb && fa == NULL ) ) return false;
if ( fa && fb && strcmp(fa,fb) != 0 ) return false;
if ( pango_font_description_get_style(a) != pango_font_description_get_style(b) ) return false;
@@ -395,6 +395,33 @@ Glib::ustring font_factory::ConstructFontSpecification(font_instance *font)
return pangoString;
}
+/*
+ * Wrap calls to pango_font_description_get_family
+ * and replace some of the pango font names with generic css names
+ * http://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#generic-font-families
+ *
+ * This function should be called in place of pango_font_description_get_family()
+ */
+const char *sp_font_description_get_family(PangoFontDescription const *fontDescr) {
+
+ static std::map<Glib::ustring, Glib::ustring> fontNameMap;
+ std::map<Glib::ustring, Glib::ustring>::iterator it;
+
+ if (fontNameMap.empty()) {
+ fontNameMap.insert(std::make_pair("Sans", "sans-serif"));
+ fontNameMap.insert(std::make_pair("Serif", "serif"));
+ fontNameMap.insert(std::make_pair("Monospace", "monospace"));
+ }
+
+ const char *pangoFamily = pango_font_description_get_family(fontDescr);
+
+ if (pangoFamily && ((it = fontNameMap.find(pangoFamily)) != fontNameMap.end())) {
+ return ((Glib::ustring)it->second).c_str();
+ }
+
+ return pangoFamily;
+}
+
Glib::ustring font_factory::GetUIFamilyString(PangoFontDescription const *fontDescr)
{
Glib::ustring family;
@@ -403,7 +430,8 @@ Glib::ustring font_factory::GetUIFamilyString(PangoFontDescription const *fontDe
if (fontDescr) {
// For now, keep it as family name taken from pango
- const char *pangoFamily = pango_font_description_get_family(fontDescr);
+ const char *pangoFamily = sp_font_description_get_family(fontDescr);
+
if( pangoFamily ) {
family = pangoFamily;
}
@@ -454,7 +482,7 @@ Glib::ustring font_factory::ReplaceFontSpecificationFamily(const Glib::ustring &
// what constitutes a "family" in our own UI may be different from how Pango
// sees it.
- // Find the PangoFontDescription associated with the font specification string.
+ // Find the PangoFontDescription associated with the old font specification string.
PangoStringToDescrMap::iterator it = fontInstanceMap.find(fontSpec);
@@ -464,15 +492,23 @@ Glib::ustring font_factory::ReplaceFontSpecificationFamily(const Glib::ustring &
// Make copy
PangoFontDescription *descr = pango_font_description_copy((*it).second);
- // Grab the UI Family string from the descr
+ // Grab the old UI Family string from the descr
Glib::ustring uiFamily = GetUIFamilyString(descr);
// Replace the UI Family name with the new family name
std::size_t found = fontSpec.find(uiFamily);
if (found != Glib::ustring::npos) {
+
+ // Add comma to end of newFamily... commas at end don't hurt but are
+ // required if the last part of a family name is a valid font style
+ // (e.g. "Arial Black").
+ Glib::ustring newFamilyComma = newFamily;
+ if( *newFamilyComma.rbegin() != ',' ) {
+ newFamilyComma += ",";
+ }
newFontSpec = fontSpec;
newFontSpec.erase(found, uiFamily.size());
- newFontSpec.insert(found, newFamily);
+ newFontSpec.insert(found, newFamilyComma);
// If the new font specification does not exist in the reference maps,
// search for the next best match for the faces in that style
@@ -711,11 +747,13 @@ void font_factory::GetUIFamiliesAndStyles(FamilyToStylesMap *map)
Glib::ustring styleUIName = GetUIStyleString(faceDescr);
if (!familyUIName.empty() && !styleUIName.empty()) {
+
// Find the right place to put the style information, adding
// a map entry for the family name if it doesn't yet exist
FamilyToStylesMap::iterator iter = map->find(familyUIName);
+ // Insert new family
if (iter == map->end()) {
map->insert(std::make_pair(familyUIName, std::list<Glib::ustring>()));
}
@@ -745,6 +783,7 @@ void font_factory::GetUIFamiliesAndStyles(FamilyToStylesMap *map)
ConstructFontSpecification(faceDescr)));
fontInstanceMap.insert(
std::make_pair(ConstructFontSpecification(faceDescr), faceDescr));
+
} else {
pango_font_description_free(faceDescr);
}
@@ -815,7 +854,14 @@ font_instance* font_factory::FaceFromUIStrings(char const *uiFamily, char const
g_assert(uiFamily && uiStyle);
if (uiFamily && uiStyle) {
- Glib::ustring uiString = Glib::ustring(uiFamily) + Glib::ustring(uiStyle);
+
+ // If font list, take only first font in list
+ gchar** tokens = g_strsplit( uiFamily, ",", 0 );
+ g_strstrip( tokens[0] );
+
+ Glib::ustring uiString = Glib::ustring(tokens[0]) + Glib::ustring(uiStyle);
+
+ g_strfreev( tokens );
UIStringToPangoStringMap::iterator uiToPangoIter = fontStringMap.find(uiString);
@@ -854,7 +900,7 @@ font_instance* font_factory::FaceFromPangoString(char const *pangoString)
descr = pango_font_description_from_string(pangoString);
}
- if (descr && (pango_font_description_get_family(descr) != NULL)) {
+ if (descr && (sp_font_description_get_family(descr) != NULL)) {
fontInstance = Face(descr);
}
@@ -902,7 +948,7 @@ font_instance *font_factory::Face(PangoFontDescription *descr, bool canFail)
// workaround for bug #1025565.
// fonts without families blow up Pango.
- if (pango_font_description_get_family(descr) != NULL) {
+ if (sp_font_description_get_family(descr) != NULL) {
nFace = pango_font_map_load_font(fontServer,fontContext,descr);
}
else {
diff --git a/src/libnrtype/FontFactory.h b/src/libnrtype/FontFactory.h
index 42f975ab7..12046079e 100644
--- a/src/libnrtype/FontFactory.h
+++ b/src/libnrtype/FontFactory.h
@@ -54,6 +54,9 @@ struct font_descr_equal : public std::binary_function<PangoFontDescription*, Pan
int style_name_compare(char const *aa, char const *bb);
int family_name_compare(char const *a, char const *b);
+// Wraps calls to pango_font_description_get_family with some name substitution
+const char *sp_font_description_get_family(PangoFontDescription const *fontDescr);
+
// Map type for gathering UI family and style strings
typedef std::map<Glib::ustring, std::list<Glib::ustring> > FamilyToStylesMap;
diff --git a/src/libnrtype/FontInstance.cpp b/src/libnrtype/FontInstance.cpp
index f26b157da..61225ad0c 100644
--- a/src/libnrtype/FontInstance.cpp
+++ b/src/libnrtype/FontInstance.cpp
@@ -285,14 +285,14 @@ unsigned int font_instance::Attribute(const gchar *key, gchar *str, unsigned int
bool b = (weight >= PANGO_WEIGHT_BOLD);
res = g_strdup_printf ("%s%s%s%s",
- pango_font_description_get_family(descr),
+ sp_font_description_get_family(descr),
(b || i || o) ? "-" : "",
(b) ? "Bold" : "",
(i) ? "Italic" : ((o) ? "Oblique" : "") );
free_res = true;
}
} else if ( strcmp(key,"family") == 0 ) {
- res=(char*)pango_font_description_get_family(descr);
+ res=(char*)sp_font_description_get_family(descr);
free_res=false;
} else if ( strcmp(key,"style") == 0 ) {
PangoStyle v=pango_font_description_get_style(descr);
diff --git a/src/libnrtype/Layout-TNG-Output.cpp b/src/libnrtype/Layout-TNG-Output.cpp
index 9e75473ce..e97884f40 100644
--- a/src/libnrtype/Layout-TNG-Output.cpp
+++ b/src/libnrtype/Layout-TNG-Output.cpp
@@ -424,7 +424,7 @@ Glib::ustring Layout::getFontFamily(unsigned span_index) const
return "";
if (_spans[span_index].font) {
- return pango_font_description_get_family(_spans[span_index].font->descr);
+ return sp_font_description_get_family(_spans[span_index].font->descr);
}
return "";
@@ -452,7 +452,7 @@ Glib::ustring Layout::dumpAsText() const
snprintf(line, sizeof(line), " in chunk %d (x=%f, baselineshift=%f)\n", _spans[span_index].in_chunk, _chunks[_spans[span_index].in_chunk].left_x, _spans[span_index].baseline_shift);
result += line;
if (_spans[span_index].font) {
- snprintf(line, sizeof(line), " font '%s' %f %s %s\n", pango_font_description_get_family(_spans[span_index].font->descr), _spans[span_index].font_size, style_to_text(pango_font_description_get_style(_spans[span_index].font->descr)), weight_to_text(pango_font_description_get_weight(_spans[span_index].font->descr)));
+ snprintf(line, sizeof(line), " font '%s' %f %s %s\n", sp_font_description_get_family(_spans[span_index].font->descr), _spans[span_index].font_size, style_to_text(pango_font_description_get_style(_spans[span_index].font->descr)), weight_to_text(pango_font_description_get_weight(_spans[span_index].font->descr)));
result += line;
}
snprintf(line, sizeof(line), " x_start = %f, x_end = %f\n", _spans[span_index].x_start, _spans[span_index].x_end);
diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp
index 710e0b84f..04859185c 100644
--- a/src/libnrtype/font-lister.cpp
+++ b/src/libnrtype/font-lister.cpp
@@ -14,12 +14,19 @@
#include "font-lister.h"
#include "FontFactory.h"
+#include "sp-object.h"
+#include "sp-root.h"
+#include "document.h"
+#include "xml/repr.h"
+#include "preferences.h"
+
namespace Inkscape
{
FontLister::FontLister ()
{
font_list_store = Gtk::ListStore::create (FontList);
-
+ font_list_store->freeze_notify();
+
FamilyToStylesMap familyStyleMap;
font_factory::Default()->GetUIFamiliesAndStyles(&familyStyleMap);
@@ -52,10 +59,156 @@ namespace Inkscape
}
(*treeModelIter)[FontList.styles] = styles;
-
- font_list_store_iter_map.insert(std::make_pair(familyName, Gtk::TreePath(treeModelIter)));
+ (*treeModelIter)[FontList.onSystem] = true;
}
}
+ font_list_store->thaw_notify();
+ }
+
+ // 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.font] << std::endl;
+ // return false;
+ // }
+ // return true;
+ // }
+ // font_list_store->foreach_iter( sigc::mem_fun(*this, &FontLister::print_document_font ));
+
+ void
+ FontLister::update_font_list( SPDocument* document ) {
+
+ SPObject *r = document->getRoot();
+ if( !r ) {
+ return;
+ }
+
+ font_list_store->freeze_notify();
+
+ /* 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.font] << std::endl;
+ iter = font_list_store->erase( iter );
+ } else {
+ // std::cout << " First on system: " << row[FontList.font] << std::endl;
+ break;
+ }
+ }
+
+ /* Create default styles for use when font-family is unknown on system. */
+ static GList *default_styles = NULL;
+ if( default_styles == NULL ) {
+ default_styles = g_list_append( default_styles, g_strdup("Normal") );
+ default_styles = g_list_append( default_styles, g_strdup("Italic") );
+ default_styles = g_list_append( default_styles, g_strdup("Bold") );
+ default_styles = g_list_append( default_styles, g_strdup("Bold Italic") );
+ }
+
+ /* Get "font-family"s used in document. */
+ std::list<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.font] = "#";
+ (*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;
+
+ /* 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[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] && tokens[0].compare( row[FontList.font] ) == 0 ) {
+ styles = row[FontList.styles];
+ break;
+ }
+ ++iter2;
+ }
+ }
+
+ Gtk::TreeModel::iterator treeModelIter = font_list_store->prepend();
+ (*treeModelIter)[FontList.font] = reinterpret_cast<const char*>(g_strdup((*i).c_str()));
+ (*treeModelIter)[FontList.styles] = styles;
+ (*treeModelIter)[FontList.onSystem] = false;
+ }
+
+ font_list_store->thaw_notify();
+ }
+
+ void
+ FontLister::update_font_list_recursive( SPObject *r, std::list<Glib::ustring> *l ) {
+
+ const gchar *style = r->getRepr()->attribute("style");
+ if( style != NULL ) {
+
+ std::vector<Glib::ustring> tokens = Glib::Regex::split_simple(";", style );
+ for( size_t i=0; i < tokens.size(); ++i ) {
+
+ Glib::ustring token = tokens[i];
+ size_t found = token.find("font-family:");
+
+ if( found != Glib::ustring::npos ) {
+
+ // Remove "font-family:"
+ token.erase(found,12);
+
+ // Remove any leading single or double quote
+ if( token[0] == '\'' || token[0] == '"' ) {
+ token.erase(0,1);
+ }
+
+ // Remove any trailing single or double quote
+ if( token[token.length()-1] == '\'' || token[token.length()-1] == '"' ) {
+ token.erase(token.length()-1);
+ }
+
+ l->push_back( token );
+ }
+ }
+ }
+
+ for (SPObject *child = r->firstChild(); child; child = child->getNext()) {
+ update_font_list_recursive( child, l );
+ }
+ }
+
+ Gtk::TreePath
+ FontLister::get_row_for_font (Glib::ustring family)
+ {
+ Gtk::TreePath path;
+
+ Gtk::TreeModel::iterator iter = font_list_store->get_iter( "0" );
+ while( iter != font_list_store->children().end() ) {
+
+ Gtk::TreeModel::Row row = *iter;
+
+ if( family.compare( row[FontList.font] ) == 0 ) {
+ return font_list_store->get_path( iter );
+ }
+
+ ++iter;
+ }
+
+ throw FAMILY_NOT_FOUND;
}
FontLister::~FontLister ()
@@ -69,6 +222,77 @@ namespace Inkscape
}
}
+// Helper functions
+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);
+ //g_free(family);
+ Glib::ustring markup;
+
+ 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 ) {
+ Glib::ustring token = tokens[i];
+ GtkTreeIter iter;
+ gboolean valid;
+ gchar *family = 0;
+ gboolean onSystem = true;
+ gboolean found = false;
+ 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 ) ) {
+
+ gtk_tree_model_get(model, &iter, 0, &family, 2, &onSystem, -1);
+ if( onSystem && token.compare( family ) == 0 ) {
+ found = true;
+ break;
+ }
+ }
+ if( found ) {
+ markup += g_markup_escape_text(token.c_str(), -1);
+ markup += ", ";
+ } else {
+ markup += "<span strikethrough=\"true\" strikethrough_color=\"red\">";
+ markup += g_markup_escape_text(token.c_str(), -1);
+ markup += "</span>";
+ markup += ", ";
+ }
+ }
+ // Remove extra comma and space from end.
+ if( markup.size() >= 2 ) {
+ markup.resize( markup.size()-2 );
+ }
+ markup += "</span>";
+ // std::cout << markup << std::endl;
+ } else {
+ markup = family_escaped;
+ }
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ int show_sample = prefs->getInt("/tools/text/show_sample_in_list", 1);
+ if (show_sample) {
+
+ Glib::ustring sample = prefs->getString("/tools/text/font_sample");
+ Glib::ustring sample_escaped = g_markup_escape_text(sample.data(), -1);
+
+ markup += " <span foreground='gray' font_family='";
+ markup += family_escaped;
+ markup += "'>";
+ markup += sample_escaped;
+ markup += "</span>";
+ }
+
+ g_object_set (G_OBJECT (cell), "markup", markup.c_str(), NULL);
+}
diff --git a/src/libnrtype/font-lister.h b/src/libnrtype/font-lister.h
index c9ab7b21d..751350407 100644
--- a/src/libnrtype/font-lister.h
+++ b/src/libnrtype/font-lister.h
@@ -7,9 +7,11 @@
* Authors:
* Chris Lahey <clahey@ximian.com>
* Lauris Kaplinski <lauris@kaplinski.com>
+ * Tavmjong Bah <tavmjong@free.fr>
*
* Copyright (C) 1999-2001 Ximian, Inc.
* Copyright (C) 2002 Lauris Kaplinski
+ * Copyright (C) 2013 Tavmjong Bah
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
@@ -21,6 +23,9 @@
#include <glibmm/ustring.h>
#include "nr-type-primitives.h"
+class SPObject;
+class SPDocument;
+
namespace Inkscape
{
/**
@@ -54,29 +59,19 @@ namespace Inkscape
*/
Gtk::TreeModelColumn<GList*> styles;
+ /** Column containing flag if font is on system
+ */
+ Gtk::TreeModelColumn<gboolean> onSystem;
+
FontListClass ()
{
add (font);
add (styles);
+ add (onSystem);
}
};
- /* Case-insensitive < compare for standard strings */
- class StringLessThan
- {
- public:
- bool operator () (std::string str1, std::string str2) const
- {
- std::string s1=str1; // Can't transform the originals!
- std::string s2=str2;
- std::transform(s1.begin(), s1.end(), s1.begin(), (int(*)(int)) toupper);
- std::transform(s2.begin(), s2.end(), s2.begin(), (int(*)(int)) toupper);
- return s1<s2;
- }
- };
-
FontListClass FontList;
- typedef std::map<Glib::ustring, Gtk::TreePath, StringLessThan> IterMapType;
/** Returns the ListStore with the font names
*
@@ -87,6 +82,17 @@ namespace Inkscape
const Glib::RefPtr<Gtk::ListStore>
get_font_list () const;
+ /** 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 ()
{
@@ -95,12 +101,7 @@ namespace Inkscape
}
Gtk::TreePath
- get_row_for_font (Glib::ustring family)
- {
- IterMapType::iterator iter = font_list_store_iter_map.find (family);
- if (iter == font_list_store_iter_map.end ()) throw FAMILY_NOT_FOUND;
- return (*iter).second;
- }
+ get_row_for_font (Glib::ustring family);
const NRNameList
get_name_list () const
@@ -108,7 +109,6 @@ namespace Inkscape
return families;
}
-
private:
FontLister ();
@@ -116,11 +116,25 @@ namespace Inkscape
NRNameList families;
Glib::RefPtr<Gtk::ListStore> font_list_store;
- IterMapType font_list_store_iter_map;
};
}
+// Helper functions
+// Separator function (if true, a separator will be drawn)
+static gboolean font_lister_separator_func(GtkTreeModel *model, GtkTreeIter *iter, gpointer /*data*/)
+{
+ gchar* text = 0;
+ gtk_tree_model_get(model, iter, 0, &text, -1 ); // Column 0: FontList.font
+ return (text && strcmp(text,"#") == 0);
+}
+
+void font_lister_cell_data_func(GtkCellLayout */*cell_layout*/,
+ GtkCellRenderer *cell,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer /*data*/);
+
#endif
/*