diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/attributes.cpp | 1 | ||||
| -rw-r--r-- | src/attributes.h | 4 | ||||
| -rw-r--r-- | src/axis-manip.h | 4 | ||||
| -rw-r--r-- | src/desktop-style.cpp | 57 | ||||
| -rw-r--r-- | src/desktop-style.h | 1 | ||||
| -rw-r--r-- | src/dialogs/text-edit.cpp | 19 | ||||
| -rw-r--r-- | src/extension/internal/pdf-cairo.cpp | 2 | ||||
| -rw-r--r-- | src/extension/internal/pdfinput/svg-builder.cpp | 9 | ||||
| -rw-r--r-- | src/extension/internal/ps.cpp | 5 | ||||
| -rw-r--r-- | src/libnrtype/FontFactory.cpp | 528 | ||||
| -rw-r--r-- | src/libnrtype/FontFactory.h | 58 | ||||
| -rw-r--r-- | src/libnrtype/FontInstance.cpp | 6 | ||||
| -rw-r--r-- | src/libnrtype/font-lister.cpp | 87 | ||||
| -rw-r--r-- | src/libnrtype/font-lister.h | 6 | ||||
| -rw-r--r-- | src/persp3d.cpp | 2 | ||||
| -rw-r--r-- | src/sp-text.cpp | 4 | ||||
| -rw-r--r-- | src/style.cpp | 41 | ||||
| -rw-r--r-- | src/style.h | 3 | ||||
| -rw-r--r-- | src/widgets/font-selector.cpp | 156 | ||||
| -rw-r--r-- | src/widgets/toolbox.cpp | 98 | ||||
| -rw-r--r-- | src/xml/repr-css.cpp | 4 |
21 files changed, 851 insertions, 244 deletions
diff --git a/src/attributes.cpp b/src/attributes.cpp index 4169dee51..c00268b96 100644 --- a/src/attributes.cpp +++ b/src/attributes.cpp @@ -321,6 +321,7 @@ static SPStyleProp const props[] = { {SP_ATTR_LAYOUT_OPTIONS,"inkscape:layoutOptions"}, /* CSS2 */ + {SP_PROP_INKSCAPE_FONT_SPEC, "-inkscape-font-specification"}, /* Font */ {SP_PROP_FONT, "font"}, {SP_PROP_FONT_FAMILY, "font-family"}, diff --git a/src/attributes.h b/src/attributes.h index 33e060893..89b3f4d04 100644 --- a/src/attributes.h +++ b/src/attributes.h @@ -23,7 +23,7 @@ unsigned char const *sp_attribute_name(unsigned int id); * True iff k is a property in SVG, i.e. something that can be written either in a style attribute * or as its own XML attribute. */ -#define SP_ATTRIBUTE_IS_CSS(k) (((k) >= SP_PROP_FONT) && ((k) <= SP_PROP_TEXT_RENDERING)) +#define SP_ATTRIBUTE_IS_CSS(k) (((k) >= SP_PROP_INKSCAPE_FONT_SPEC) && ((k) <= SP_PROP_TEXT_RENDERING)) enum SPAttributeEnum { SP_ATTR_INVALID, ///< Must have value 0. @@ -321,6 +321,8 @@ enum SPAttributeEnum { SP_ATTR_LAYOUT_OPTIONS, /* CSS2 */ + /* Custom full font name because Font stuff below is inadequate */ + SP_PROP_INKSCAPE_FONT_SPEC, /* Font */ SP_PROP_FONT, SP_PROP_FONT_FAMILY, diff --git a/src/axis-manip.h b/src/axis-manip.h index 7513bebaf..8fb8fdc8e 100644 --- a/src/axis-manip.h +++ b/src/axis-manip.h @@ -19,8 +19,8 @@ namespace Proj { enum VPState { - FINITE = 0, - INFINITE + VP_FINITE = 0, + VP_INFINITE }; // The X-/Y-/Z-axis corresponds to the first/second/third digit diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index d0cecda03..e56e7fbbe 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -1051,6 +1051,59 @@ objects_query_fontfamily (GSList *objects, SPStyle *style_res) } int +objects_query_fontspecification (GSList *objects, SPStyle *style_res) +{ + bool different = false; + int texts = 0; + + if (style_res->text->font_specification.value) { + g_free(style_res->text->font_specification.value); + style_res->text->font_specification.value = NULL; + } + style_res->text->font_specification.set = FALSE; + + for (GSList const *i = objects; i != NULL; i = i->next) { + SPObject *obj = SP_OBJECT (i->data); + + if (!SP_IS_TEXT(obj) && !SP_IS_FLOWTEXT(obj) + && !SP_IS_TSPAN(obj) && !SP_IS_TREF(obj) && !SP_IS_TEXTPATH(obj) + && !SP_IS_FLOWDIV(obj) && !SP_IS_FLOWPARA(obj) && !SP_IS_FLOWTSPAN(obj)) + continue; + + SPStyle *style = SP_OBJECT_STYLE (obj); + if (!style) continue; + + texts ++; + + if (style_res->text->font_specification.value && style->text->font_specification.value && + strcmp (style_res->text->font_specification.value, style->text->font_specification.value)) { + different = true; // different fonts + } + + if (style_res->text->font_specification.value) { + g_free(style_res->text->font_specification.value); + style_res->text->font_specification.value = NULL; + } + + style_res->text->font_specification.set = TRUE; + style_res->text->font_specification.value = g_strdup(style->text->font_specification.value); + } + + if (texts == 0 || !style_res->text->font_specification.set) + return QUERY_STYLE_NOTHING; + + if (texts > 1) { + if (different) { + return QUERY_STYLE_MULTIPLE_DIFFERENT; + } else { + return QUERY_STYLE_MULTIPLE_SAME; + } + } else { + return QUERY_STYLE_SINGLE; + } +} + +int objects_query_blend (GSList *objects, SPStyle *style_res) { const int empty_prev = -2; @@ -1221,7 +1274,9 @@ sp_desktop_query_style_from_list (GSList *list, SPStyle *style, int property) } else if (property == QUERY_STYLE_PROPERTY_MASTEROPACITY) { return objects_query_opacity (list, style); - + + } else if (property == QUERY_STYLE_PROPERTY_FONT_SPECIFICATION) { + return objects_query_fontspecification (list, style); } else if (property == QUERY_STYLE_PROPERTY_FONTFAMILY) { return objects_query_fontfamily (list, style); } else if (property == QUERY_STYLE_PROPERTY_FONTSTYLE) { diff --git a/src/desktop-style.h b/src/desktop-style.h index 3f201aa28..b99f12fde 100644 --- a/src/desktop-style.h +++ b/src/desktop-style.h @@ -43,6 +43,7 @@ enum { // which property was queried (add when you need more) QUERY_STYLE_PROPERTY_STROKEJOIN, // stroke join QUERY_STYLE_PROPERTY_STROKECAP, // stroke cap QUERY_STYLE_PROPERTY_STROKESTYLE, // markers, dasharray, miterlimit, stroke-width, stroke-cap, stroke-join + QUERY_STYLE_PROPERTY_FONT_SPECIFICATION, //-inkscape-font-specification QUERY_STYLE_PROPERTY_FONTFAMILY, // font-family QUERY_STYLE_PROPERTY_FONTSTYLE, // font style QUERY_STYLE_PROPERTY_FONTNUMBERS, // size, spacings diff --git a/src/dialogs/text-edit.cpp b/src/dialogs/text-edit.cpp index 279c5b5e7..d96583f85 100644 --- a/src/dialogs/text-edit.cpp +++ b/src/dialogs/text-edit.cpp @@ -527,7 +527,11 @@ sp_get_text_dialog_style () font_instance *font = sp_font_selector_get_font (SP_FONT_SELECTOR (fontsel)); if ( font ) { + Glib::ustring fontName = font_factory::Default()->ConstructFontSpecification(font); + sp_repr_css_set_property (css, "-inkscape-font-specification", fontName.c_str()); + gchar c[256]; + font->Family(c, 256); sp_repr_css_set_property (css, "font-family", c); @@ -736,12 +740,15 @@ sp_text_edit_dialog_read_selection ( GtkWidget *dlg, // create temporary style SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); // query style from desktop into it. This returns a result flag and fills query with the style of subselection, if any, or selection - int result_family = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY); - int result_style = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE); + int result_fontspec = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION); + int result_family = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY); + int result_style = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE); int result_numbers = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); // If querying returned nothing, read the style from the text tool prefs (default style for new texts) - if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING) { + // (Ok to not get a font specification - must just rely on the family and style in that case) + if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING + || result_numbers == QUERY_STYLE_NOTHING) { repr = inkscape_get_repr (INKSCAPE, "tools.text"); if (repr) { gtk_widget_set_sensitive (notebook, TRUE); @@ -752,7 +759,11 @@ sp_text_edit_dialog_read_selection ( GtkWidget *dlg, } // FIXME: process result_family/style == QUERY_STYLE_MULTIPLE_DIFFERENT by showing "Many" in the lists - font_instance *font = (font_factory::Default())->Face ( query->text->font_family.value, font_style_to_pos(*query) ); + + // Get a font_instance using the font-specification attribute stored in SPStyle if available + font_instance *font = font_factory::Default()->FaceFromStyle(query); + + if (font) { // the font is oversized, so we need to pass the true size separately sp_font_selector_set_font (SP_FONT_SELECTOR (fontsel), font, query->font_size.computed); diff --git a/src/extension/internal/pdf-cairo.cpp b/src/extension/internal/pdf-cairo.cpp index 4baab1740..ae17a6edd 100644 --- a/src/extension/internal/pdf-cairo.cpp +++ b/src/extension/internal/pdf-cairo.cpp @@ -830,7 +830,7 @@ PrintCairoPDF::text(Inkscape::Extension::Print *mod, char const *text, NR::Point } // create font instance from style and use it - font_instance *tf = (font_factory::Default())->Face(style->text->font_family.value, font_style_to_pos(*style)); + font_instance *tf = font_factory::Default()->FaceFromStyle(style); if (tf == NULL) { // do something g_printf("Warning: trouble getting font_instance\n"); tf = (font_factory::Default())->Face("sans", font_style_to_pos(*style)); diff --git a/src/extension/internal/pdfinput/svg-builder.cpp b/src/extension/internal/pdfinput/svg-builder.cpp index 3d96991a6..076f12906 100644 --- a/src/extension/internal/pdfinput/svg-builder.cpp +++ b/src/extension/internal/pdfinput/svg-builder.cpp @@ -1169,7 +1169,14 @@ void SvgBuilder::_flushText() { break; } else { tspan_node = _xml_doc->createElement("svg:tspan"); - tspan_node->setAttribute("inkscape:font-specification", glyph.font_specification); + + /////// + // Create a font specification string and save the attribute in the style + PangoFontDescription *descr = pango_font_description_from_string(glyph.font_specification); + Glib::ustring properFontSpec = font_factory::Default()->ConstructFontSpecification(descr); + pango_font_description_free(descr); + sp_repr_css_set_property(glyph.style, "-inkscape-font-specification", properFontSpec.c_str()); + // Set style and unref SPCSSAttr if it won't be needed anymore sp_repr_css_change(tspan_node, glyph.style, "style"); if ( glyph.style_changed && i != _glyphs.begin() ) { // Free previous style diff --git a/src/extension/internal/ps.cpp b/src/extension/internal/ps.cpp index fedde86a2..6cc27988d 100644 --- a/src/extension/internal/ps.cpp +++ b/src/extension/internal/ps.cpp @@ -913,7 +913,7 @@ PrintPS::image(Inkscape::Extension::Print *mod, guchar *px, unsigned int w, unsi char const * PrintPS::PSFontName(SPStyle const *style) { - font_instance *tf = (font_factory::Default())->Face(style->text->font_family.value, font_style_to_pos(*style)); + font_instance *tf = font_factory::Default()->FaceFromStyle(style); char const *n; char name_buf[256]; @@ -1273,7 +1273,8 @@ PrintPS::text(Inkscape::Extension::Print *mod, char const *text, NR::Point p, * that's why using PSFontName() method just to get the PS fontname * is not enough and not appropriate */ - font_instance *tf = (font_factory::Default())->Face(style->text->font_family.value, font_style_to_pos(*style)); + font_instance *tf = font_factory::Default()->FaceFromStyle(style); + const gchar *fn = NULL; char name_buf[256]; diff --git a/src/libnrtype/FontFactory.cpp b/src/libnrtype/FontFactory.cpp index 32f71aed0..2d56a1a41 100644 --- a/src/libnrtype/FontFactory.cpp +++ b/src/libnrtype/FontFactory.cpp @@ -11,6 +11,8 @@ #include "FontFactory.h" #include <libnrtype/font-instance.h> +#include <glibmm.h> + #ifdef HAVE_CONFIG_H # include "config.h" @@ -202,8 +204,8 @@ is_swash(char const *s) * Q: Shouldn't this include the other tests such as is_outline, etc.? * Q: Is there a problem with strcasecmp on Win32? Should it use stricmp? */ -static int -style_name_compare(void const *aa, void const *bb) +int +style_name_compare(char const *aa, char const *bb) { char const *a = (char const *) aa; char const *b = (char const *) bb; @@ -254,8 +256,8 @@ static void font_factory_style_list_destructor(NRStyleList *list) /** * On Win32 performs a stricmp(a,b), otherwise does a strcasecmp(a,b) */ -static int -family_name_compare(void const *a, void const *b) +int +family_name_compare(char const *a, char const *b) { #ifndef WIN32 return strcasecmp((*((char const **) a)), (*((char const **) b))); @@ -323,6 +325,349 @@ font_factory::~font_factory(void) //pango_ft2_shutdown_display(); #endif //g_object_unref(fontContext); + + // Delete the pango font pointers in the string to instance map + PangoStringToDescrMap::iterator it = fontInstanceMap.begin(); + while (it != fontInstanceMap.end()) { + pango_font_description_free((*it).second); + it++; + } +} + + +Glib::ustring font_factory::ConstructFontSpecification(PangoFontDescription *font) +{ + Glib::ustring pangoString; + + g_assert(font); + + if (font) { + // Once the format for the font specification is decided, it must be + // kept.. if it is absolutely necessary to change it, the attribute + // it is written to needs to have a new version so the legacy files + // can be read. + + PangoFontDescription *copy = pango_font_description_copy(font); + + pango_font_description_unset_fields (copy, PANGO_FONT_MASK_SIZE); + pangoString = Glib::ustring(pango_font_description_to_string(copy)); + + pango_font_description_free(copy); + + } + + return pangoString; +} + +Glib::ustring font_factory::ConstructFontSpecification(font_instance *font) +{ + Glib::ustring pangoString; + + g_assert(font); + + if (font) { + pangoString = ConstructFontSpecification(font->descr); + } + + return pangoString; +} + +Glib::ustring font_factory::GetUIFamilyString(PangoFontDescription const *fontDescr) +{ + Glib::ustring family; + + g_assert(fontDescr); + + if (fontDescr) { + // For now, keep it as family name taken from pango + family = pango_font_description_get_family(fontDescr); + } + + return family; +} + +Glib::ustring font_factory::GetUIStyleString(PangoFontDescription const *fontDescr) +{ + Glib::ustring style; + + g_assert(fontDescr); + + if (fontDescr) { + PangoFontDescription *fontDescrCopy = pango_font_description_copy(fontDescr); + + pango_font_description_unset_fields(fontDescrCopy, PANGO_FONT_MASK_FAMILY); + pango_font_description_unset_fields(fontDescrCopy, PANGO_FONT_MASK_SIZE); + + // For now, keep it as style name taken from pango + style = pango_font_description_to_string(fontDescrCopy); + + pango_font_description_free(fontDescrCopy); + } + + return style; +} + +Glib::ustring font_factory::ReplaceFontSpecificationFamily(const Glib::ustring & fontSpec, const Glib::ustring & newFamily) +{ + Glib::ustring newFontSpec; + + // Although we are using the string from pango_font_description_to_string for the + // font specification, we definitely cannot just set the new family in the + // PangoFontDescription structure and ask for a new string. This is because + // what constitutes a "family" in our own UI may be different from how Pango + // sees it. + + // Find the PangoFontDescription associated to this fontSpec + PangoStringToDescrMap::iterator it = fontInstanceMap.find(fontSpec); + + g_assert(it != fontInstanceMap.end()); + + if (it != fontInstanceMap.end()) { + PangoFontDescription *descr = pango_font_description_copy((*it).second); + + // Grab the 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) { + newFontSpec = fontSpec; + newFontSpec.erase(found, uiFamily.size()); + newFontSpec.insert(found, newFamily); + + // If the new font specification does not exist in the reference maps, + // search for the next best match for the faces in that style + it = fontInstanceMap.find(newFontSpec); + if (it == fontInstanceMap.end()) { + + PangoFontDescription *newFontDescr = pango_font_description_from_string(newFontSpec.c_str()); + + PangoFontDescription *bestMatchForNewDescr = NULL; + Glib::ustring bestMatchFontDescription; + + bool setFirstFamilyMatch = false; + for (it = fontInstanceMap.begin(); it != fontInstanceMap.end(); it++) { + + Glib::ustring currentFontSpec = (*it).first; + + // Save some time by only looking at the right family + if (currentFontSpec.find(newFamily) != Glib::ustring::npos) { + if (!setFirstFamilyMatch) { + // This ensures that the closest match is at least within the correct + // family rather than the first font in the list + bestMatchForNewDescr = pango_font_description_copy((*it).second); + bestMatchFontDescription = currentFontSpec; + setFirstFamilyMatch = true; + } else { + // Get the font description that corresponds, and + // then see if we've found a better match + PangoFontDescription *possibleMatch = pango_font_description_copy((*it).second); + + if (pango_font_description_better_match( + newFontDescr, bestMatchForNewDescr, possibleMatch)) { + + pango_font_description_free(bestMatchForNewDescr); + bestMatchForNewDescr = possibleMatch; + bestMatchFontDescription = currentFontSpec; + } else { + pango_font_description_free(possibleMatch); + } + } + } + } + + newFontSpec = bestMatchFontDescription; + + pango_font_description_free(newFontDescr); + pango_font_description_free(bestMatchForNewDescr); + } + } + + pango_font_description_free(descr); + } + + return newFontSpec; +} + +Glib::ustring font_factory::FontSpecificationSetItalic(const Glib::ustring & fontSpec, bool turnOn) +{ + Glib::ustring newFontSpec; + + // Find the PangoFontDesecription that goes with this font specification string + PangoStringToDescrMap::iterator it = fontInstanceMap.find(fontSpec); + + g_assert(it != fontInstanceMap.end()); + + if (it != fontInstanceMap.end()) { + // If we did find one, make a copy and set/unset the italic as needed + PangoFontDescription *descr = pango_font_description_copy((*it).second); + + PangoStyle style; + if (turnOn) { + style = PANGO_STYLE_ITALIC; + } else { + style = PANGO_STYLE_NORMAL; + } + pango_font_description_set_style(descr, style); + + newFontSpec = ConstructFontSpecification(descr); + if (fontInstanceMap.find(newFontSpec) == fontInstanceMap.end()) { + // If the new font does not have an italic face, don't + // allow italics to be set! + newFontSpec = fontSpec; + } + + pango_font_description_free(descr); + } + + return newFontSpec; +} + +Glib::ustring font_factory::FontSpecificationSetBold(const Glib::ustring & fontSpec, bool turnOn) +{ + Glib::ustring newFontSpec; + + // Find the PangoFontDesecription that goes with this font specification string + PangoStringToDescrMap::iterator it = fontInstanceMap.find(fontSpec); + + if (it != fontInstanceMap.end()) { + // If we did find one, make a copy and set/unset the bold as needed + PangoFontDescription *descr = pango_font_description_copy((*it).second); + + PangoWeight weight; + if (turnOn) { + weight = PANGO_WEIGHT_BOLD; + } else { + weight = PANGO_WEIGHT_NORMAL; + } + pango_font_description_set_weight(descr, weight); + + newFontSpec = ConstructFontSpecification(descr); + if (fontInstanceMap.find(newFontSpec) == fontInstanceMap.end()) { + // If the new font does not have a bold face, don't + // allow bold to be set! + newFontSpec = fontSpec; + } + + pango_font_description_free(descr); + } + + return newFontSpec; +} + +///// + +static bool StyleNameCompareInternal(Glib::ustring style1, Glib::ustring style2) +{ + return (style_name_compare(style1.c_str(), style2.c_str()) < 0); +} + +void font_factory::GetUIFamiliesAndStyles(FamilyToStylesMap *map) +{ + g_assert(map); + + if (map) { + + // Gather the family names as listed by Pango + PangoFontFamily** families = NULL; + int numFamilies = 0; + pango_font_map_list_families(fontServer, &families, &numFamilies); + + for (int currentFamily=0; currentFamily < numFamilies; currentFamily++) { + + // Gather the styles for this family + PangoFontFace** faces = NULL; + int numFaces = 0; + pango_font_family_list_faces(families[currentFamily], &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 + + if (pango_font_face_get_face_name(faces[currentFace]) == NULL) { + continue; + } + + PangoFontDescription *faceDescr = pango_font_face_describe(faces[currentFace]); + if (faceDescr) { + Glib::ustring familyUIName = GetUIFamilyString(faceDescr); + 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); + + if (iter == map->end()) { + map->insert(std::make_pair(familyUIName, std::list<Glib::ustring>())); + } + + // Insert into the style list and save the info in the reference maps + // only if the style does not yet exist + + bool exists = false; + std::list<Glib::ustring> &styleList = (*map)[familyUIName]; + + for (std::list<Glib::ustring>::iterator it=styleList.begin(); + it != styleList.end(); + it++) { + if (*it == styleUIName) { + exists = true; + break; + } + } + + if (!exists) { + styleList.push_back(styleUIName); + + // Add the string info needed in the reference maps + fontStringMap.insert( + std::make_pair( + Glib::ustring(familyUIName) + Glib::ustring(styleUIName), + ConstructFontSpecification(faceDescr))); + fontInstanceMap.insert( + std::make_pair(ConstructFontSpecification(faceDescr), faceDescr)); + } else { + pango_font_description_free(faceDescr); + } + } else { + pango_font_description_free(faceDescr); + } + } + } + } + + // Sort the style lists + for (FamilyToStylesMap::iterator iter = map->begin() ; iter != map->end(); iter++) { + (*iter).second.sort(StyleNameCompareInternal); + } + } +} + +font_instance* font_factory::FaceFromStyle(SPStyle const *style) +{ + font_instance *font = NULL; + + g_assert(style); + + if (style) { + // First try to use the font specification if it is set + if (style->text->font_specification.set + && style->text->font_specification.value + && *style->text->font_specification.value) { + + font = FaceFromFontSpecification(style->text->font_specification.value); + } + + // If that failed, try using the CSS information in the style + if (!font) { + font = Face(style->text->font_family.value, font_style_to_pos(*style)); + } + } + + return font; } font_instance *font_factory::FaceFromDescr(char const *family, char const *style) @@ -334,6 +679,81 @@ font_instance *font_factory::FaceFromDescr(char const *family, char const *style return res; } +font_instance* font_factory::FaceFromUIStrings(char const *uiFamily, char const *uiStyle) +{ + font_instance *fontInstance = NULL; + + g_assert(uiFamily && uiStyle); + if (uiFamily && uiStyle) { + Glib::ustring uiString = Glib::ustring(uiFamily) + Glib::ustring(uiStyle); + + UIStringToPangoStringMap::iterator uiToPangoIter = fontStringMap.find(uiString); + + if (uiToPangoIter != fontStringMap.end ()) { + PangoStringToDescrMap::iterator pangoToDescrIter = fontInstanceMap.find((*uiToPangoIter).second); + if (pangoToDescrIter != fontInstanceMap.end()) { + // We found the pango description - now we can make a font_instance + PangoFontDescription *tempDescr = pango_font_description_copy((*pangoToDescrIter).second); + fontInstance = Face(tempDescr); + pango_font_description_free(tempDescr); + } + } + } + + return fontInstance; +} + +font_instance* font_factory::FaceFromPangoString(char const *pangoString) +{ + font_instance *fontInstance = NULL; + + g_assert(pangoString); + + if (pangoString) { + PangoFontDescription *descr = NULL; + + // First attempt to find the font specification in the reference map + PangoStringToDescrMap::iterator it = fontInstanceMap.find(Glib::ustring(pangoString)); + if (it != fontInstanceMap.end()) { + descr = pango_font_description_copy((*it).second); + } + + // Or create a font description from the string - this may fail or + // produce unexpected results if the string does not have a good format + if (!descr) { + descr = pango_font_description_from_string(pangoString); + } + + if (descr && (pango_font_description_get_family(descr) != NULL)) { + fontInstance = Face(descr); + } + + if (descr) { + pango_font_description_free(descr); + } + } + + return fontInstance; +} + +font_instance* font_factory::FaceFromFontSpecification(char const *fontSpecification) +{ + font_instance *font = NULL; + + g_assert(fontSpecification); + + if (fontSpecification) { + // How the string is used to reconstruct a font depends on how it + // was constructed in ConstructFontSpecification. As it stands, + // the font specification is a pango-created string + font = FaceFromPangoString(fontSpecification); + } + + return font; +} + + + font_instance *font_factory::Face(PangoFontDescription *descr, bool canFail) { #ifdef USE_PANGO_WIN32 @@ -487,106 +907,6 @@ void font_factory::UnrefFace(font_instance *who) } } -NRNameList *font_factory::Families(NRNameList *flist) -{ - PangoFontFamily** fams = NULL; - int nbFam = 0; - pango_font_map_list_families(fontServer, &fams, &nbFam); - - PANGO_DEBUG("got %d families\n", nbFam); - - flist->length = nbFam; - flist->names = (guchar **)g_malloc(nbFam*sizeof(guchar*)); - flist->destructor = font_factory_name_list_destructor; - - for (int i = 0;i < nbFam;i++) { -// Note: on Windows, pango_font_family_get_name always returns lowercase name. -// As a result the list of fonts in the dialog is lowercase. -// We could work around by loading the font and taking pango_font_description_get_family from its descr (that gives correct case), -// but this is slow, and it's better to fix Pango instead. - flist->names[i]=(guchar*)strdup(pango_font_family_get_name(fams[i])); - } - - qsort(flist->names, nbFam, sizeof(guchar *), family_name_compare); - - g_free(fams); - - return flist; -} - -NRStyleList *font_factory::Styles(gchar const *family, NRStyleList *slist) -{ - PangoFontFamily *theFam = NULL; - - // search available families - { - PangoFontFamily** fams = NULL; - int nbFam = 0; - pango_font_map_list_families(fontServer, &fams, &nbFam); - - for (int i = 0;i < nbFam;i++) { - char const *fname = pango_font_family_get_name(fams[i]); - if ( fname && strcmp(family,fname) == 0 ) { - theFam = fams[i]; - break; - } - } - - g_free(fams); - } - - // nothing found - if ( theFam == NULL ) { - slist->length = 0; - slist->records = NULL; - slist->destructor = NULL; - return slist; - } - - // search faces in the found family - PangoFontFace** faces = NULL; - int nFaces = 0; - pango_font_family_list_faces(theFam, &faces, &nFaces); - - slist->records = (NRStyleRecord *) g_malloc(nFaces * sizeof(NRStyleRecord)); - slist->destructor = font_factory_style_list_destructor; - - int nr = 0; - for (int i = 0; i < nFaces; i++) { - - // no unnamed faces - if (pango_font_face_get_face_name(faces[i]) == NULL) - continue; - PangoFontDescription *nd = pango_font_face_describe(faces[i]); - if (nd == NULL) - continue; - char const *descr = pango_font_description_to_string(nd); - if (descr == NULL) { - pango_font_description_free(nd); - continue; - } - - char const *name = g_strdup(pango_font_face_get_face_name(faces[i])); - pango_font_description_free(nd); - - slist->records[nr].name = name; - slist->records[nr].descr = descr; - nr ++; - } - - slist->length = nr; - - qsort(slist->records, slist->length, sizeof(NRStyleRecord), style_record_compare); - /* effic: Consider doing strdown and all the is_italic etc. tests once off and store the - * results in a table, rather than having the sort invoke multiple is_italic tests per - * record. - */ - - g_free(faces); - - return slist; -} - void font_factory::AddInCache(font_instance *who) { if ( who == NULL ) return; diff --git a/src/libnrtype/FontFactory.h b/src/libnrtype/FontFactory.h index ba0010246..9f4b31a2e 100644 --- a/src/libnrtype/FontFactory.h +++ b/src/libnrtype/FontFactory.h @@ -7,6 +7,8 @@ #ifndef my_font_factory #define my_font_factory +//#include <glibmm/ustring.h> + #include <functional> #include <algorithm> #include <ext/hash_map> @@ -21,7 +23,9 @@ #include <pango/pango.h> #include "nr-type-primitives.h" #include "nr-type-pos-def.h" +#include "font-style-to-pos.h" #include <libnrtype/nrtype-forward.h> +#include "../style.h" /* Freetype */ #ifdef USE_PANGO_WIN32 @@ -31,6 +35,11 @@ #include <freetype/freetype.h> #endif +namespace Glib +{ + class ustring; +} + // the font_factory keeps a hashmap of all the loaded font_instances, and uses the PangoFontDescription // as index (nota: since pango already does that, using the PangoFont could work too) struct font_descr_hash : public std::unary_function<PangoFontDescription*,size_t> { @@ -40,6 +49,13 @@ struct font_descr_equal : public std::binary_function<PangoFontDescription*, Pan bool operator()(PangoFontDescription *const &a, PangoFontDescription *const &b); }; +// Comparison functions for style names +int style_name_compare(char const *aa, char const *bb); +int family_name_compare(char const *a, char const *b); + +// Map type for gathering UI family and style strings +typedef std::map<Glib::ustring, std::list<Glib::ustring> > FamilyToStylesMap; + class font_factory { public: static font_factory *lUsine; /**< The default font_factory; i cannot think of why we would @@ -75,9 +91,32 @@ public: /// Returns the default font_factory. static font_factory* Default(); + + /// Constructs a pango string for use with the fontStringMap (see below) + Glib::ustring ConstructFontSpecification(PangoFontDescription *font); + Glib::ustring ConstructFontSpecification(font_instance *font); + + /// Returns strings to be used in the UI for family and face (or "style" as the column is labeled) + Glib::ustring GetUIFamilyString(PangoFontDescription const *fontDescr); + Glib::ustring GetUIStyleString(PangoFontDescription const *fontDescr); + + /// Modifiers for the font specification (returns new font specification) + Glib::ustring ReplaceFontSpecificationFamily(const Glib::ustring & fontSpec, const Glib::ustring & newFamily); + Glib::ustring FontSpecificationSetItalic(const Glib::ustring & fontSpec, bool turnOn); + Glib::ustring FontSpecificationSetBold(const Glib::ustring & fontSpec, bool turnOn); + + // Gathers all strings needed for UI while storing pango information in + // fontInstanceMap and fontStringMap + void GetUIFamiliesAndStyles(FamilyToStylesMap *map); + + /// Retrieve a font_instance from a style object, first trying to use the font-specification, the CSS information + font_instance* FaceFromStyle(SPStyle const *style); // Various functions to get a font_instance from different descriptions. font_instance* FaceFromDescr(char const *family, char const *style); + font_instance* FaceFromUIStrings(char const *uiFamily, char const *uiStyle); + font_instance* FaceFromPangoString(char const *pangoString); + font_instance* FaceFromFontSpecification(char const *fontSpecification); font_instance* Face(PangoFontDescription *descr, bool canFail=true); font_instance* Face(char const *family, int variant=PANGO_VARIANT_NORMAL, int style=PANGO_STYLE_NORMAL, @@ -88,12 +127,23 @@ public: /// Semi-private: tells the font_factory taht the font_instance 'who' has died and should be removed from loadedFaces void UnrefFace(font_instance* who); - // Queries for the font-selector. - NRNameList* Families(NRNameList *flist); - NRStyleList* Styles(const gchar *family, NRStyleList *slist); - // internal void AddInCache(font_instance *who); + +private: + // These two maps are used for translating between what's in the UI and a pango + // font description. This is necessary because Pango cannot always + // reproduce these structures from the names it gave us in the first place. + + // Key: A string produced by font_factory::ConstructFontSpecification + // Value: The associated PangoFontDescription + typedef std::map<Glib::ustring, PangoFontDescription *> PangoStringToDescrMap; + PangoStringToDescrMap fontInstanceMap; + + // Key: Family name in UI + Style name in UI + // Value: The associated string that should be produced with font_factory::ConstructFontSpecification + typedef std::map<Glib::ustring, Glib::ustring> UIStringToPangoStringMap; + UIStringToPangoStringMap fontStringMap; }; diff --git a/src/libnrtype/FontInstance.cpp b/src/libnrtype/FontInstance.cpp index 0b37b14ec..228a34f83 100644 --- a/src/libnrtype/FontInstance.cpp +++ b/src/libnrtype/FontInstance.cpp @@ -278,8 +278,10 @@ unsigned int font_instance::Attribute(const gchar *key, gchar *str, unsigned int res="normal"; } else if ( v <= PANGO_WEIGHT_BOLD ) { res="bold"; - } else { - res="800"; + } else if ( v <= PANGO_WEIGHT_ULTRABOLD ) { + res="800"; + } else { // HEAVY + res="900"; } free_res=false; } else if ( strcmp(key,"stretch") == 0 ) { diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp index 1a2f6d9c8..a7160f5f0 100644 --- a/src/libnrtype/font-lister.cpp +++ b/src/libnrtype/font-lister.cpp @@ -15,46 +15,63 @@ #include <gtkmm/liststore.h> #include "font-lister.h" +#include "FontFactory.h" namespace Inkscape { - FontLister::FontLister () - { - font_list_store = Gtk::ListStore::create (FontList); - - if (font_factory::Default()->Families(&families)) - { - for (unsigned int i = 0; i < families.length; ++i) - { - Gtk::TreeModel::iterator iter = font_list_store->append(); - (*iter)[FontList.font] = reinterpret_cast<const char*>(families.names[i]); - - NRStyleList styles; - if (font_factory::Default()->Styles (reinterpret_cast<const char*>(families.names[i]), &styles)); - - GList *Styles=0; - for (unsigned int n = 0; n < styles.length; ++n) - { - NRStyleRecord style_record = styles.records[n]; - Styles = g_list_append (Styles, strdup(style_record.name)); - } - - (*iter)[FontList.styles] = Styles; - - font_list_store_iter_map.insert (std::make_pair (reinterpret_cast<const char*>(families.names[i]), Gtk::TreePath (iter))); - } - } - + FontLister::FontLister () + { + font_list_store = Gtk::ListStore::create (FontList); + + 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); + } + 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.font] = reinterpret_cast<const char*>(g_strdup(familyName.c_str())); + + // Now go through the styles + GList *styles = NULL; + std::list<Glib::ustring> &styleStrings = familyStyleMap[familyName]; + for (std::list<Glib::ustring>::iterator it=styleStrings.begin(); + it != styleStrings.end(); + it++) { + styles = g_list_append(styles, g_strdup((*it).c_str())); } + + (*treeModelIter)[FontList.styles] = styles; + + font_list_store_iter_map.insert(std::make_pair(familyName, Gtk::TreePath(treeModelIter))); + } + } + } - FontLister::~FontLister () - { - }; + FontLister::~FontLister () + { + }; - const Glib::RefPtr<Gtk::ListStore> - FontLister::get_font_list () const - { - return font_list_store; - } + const Glib::RefPtr<Gtk::ListStore> + FontLister::get_font_list () const + { + return font_list_store; + } } + + + diff --git a/src/libnrtype/font-lister.h b/src/libnrtype/font-lister.h index 39953c11c..b2d2a3ecf 100644 --- a/src/libnrtype/font-lister.h +++ b/src/libnrtype/font-lister.h @@ -45,7 +45,7 @@ namespace Inkscape public: /** Column containing the family name */ - Gtk::TreeModelColumn<std::string> font; + Gtk::TreeModelColumn<Glib::ustring> font; /** Column containing an std::vector<std::string> with style names * for the corresponding family @@ -60,7 +60,7 @@ namespace Inkscape }; FontListClass FontList; - typedef std::map<std::string, Gtk::TreePath> IterMapType; + typedef std::map<Glib::ustring, Gtk::TreePath> IterMapType; /** Returns the ListStore with the font names * @@ -79,7 +79,7 @@ namespace Inkscape } Gtk::TreePath - get_row_for_font (std::string family) + 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; diff --git a/src/persp3d.cpp b/src/persp3d.cpp index 1029516f7..27701c80d 100644 --- a/src/persp3d.cpp +++ b/src/persp3d.cpp @@ -329,7 +329,7 @@ persp3d_toggle_VPs (std::set<Persp3D *> p, Proj::Axis axis) { void persp3d_set_VP_state (Persp3D *persp, Proj::Axis axis, Proj::VPState state) { - if (persp3d_VP_is_finite(persp, axis) != (state == Proj::FINITE)) { + if (persp3d_VP_is_finite(persp, axis) != (state == Proj::VP_FINITE)) { persp3d_toggle_VP(persp, axis); } } diff --git a/src/sp-text.cpp b/src/sp-text.cpp index 1609afa92..5d1abbb3a 100644 --- a/src/sp-text.cpp +++ b/src/sp-text.cpp @@ -402,8 +402,8 @@ sp_text_description(SPItem *item) SPText *text = (SPText *) item; SPStyle *style = SP_OBJECT_STYLE(text); - font_instance *tf = (font_factory::Default())->Face(style->text->font_family.value, - font_style_to_pos(*style)); + font_instance *tf = font_factory::Default()->FaceFromStyle(style); + char name_buf[256]; char *n; if (tf) { diff --git a/src/style.cpp b/src/style.cpp index 068550878..357fe5f0e 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -715,6 +715,17 @@ sp_style_read(SPStyle *style, SPObject *object, Inkscape::XML::Node *repr) style->stroke_dashoffset_set = FALSE; } } + + /* -inkscape-font-specification */ + if (!style->text_private || !style->text->font_specification.set) { + val = repr->attribute("-inkscape-font-specification"); + if (val) { + if (!style->text_private) sp_style_privatize_text(style); + gchar *val_unquoted = attribute_unquote(val); + sp_style_read_istring(&style->text->font_specification, val_unquoted); + if (val_unquoted) g_free (val_unquoted); + } + } /* font-family */ if (!style->text_private || !style->text->font_family.set) { @@ -817,6 +828,14 @@ sp_style_merge_property(SPStyle *style, gint id, gchar const *val) g_return_if_fail(val != NULL); switch (id) { + case SP_PROP_INKSCAPE_FONT_SPEC: + if (!style->text_private) sp_style_privatize_text(style); + if (!style->text->font_specification.set) { + gchar *val_unquoted = attribute_unquote(val); + sp_style_read_istring(&style->text->font_specification, val_unquoted); + if (val_unquoted) g_free (val_unquoted); + } + break; /* CSS2 */ /* Font */ case SP_PROP_FONT_FAMILY: @@ -1500,6 +1519,13 @@ sp_style_merge_from_parent(SPStyle *const style, SPStyle const *const parent) } } + if (style->text && parent->text) { + if (!style->text->font_specification.set || style->text->font_specification.inherit) { + g_free(style->text->font_specification.value); + style->text->font_specification.value = g_strdup(parent->text->font_specification.value); + } + } + /* Markers - Free the old value and make copy of the new */ for (unsigned i = SP_MARKER_LOC; i < SP_MARKER_LOC_QTY; i++) { if (!style->marker[i].set || style->marker[i].inherit) { @@ -1885,10 +1911,14 @@ sp_style_merge_from_dying_parent(SPStyle *const style, SPStyle const *const pare /* Font */ if (style->text && parent->text) { + sp_style_merge_string_prop_from_dying_parent(style->text->font_specification, + parent->text->font_specification); + sp_style_merge_string_prop_from_dying_parent(style->text->font_family, parent->text->font_family); } + /* Properties that don't inherit by default. Most of these need special handling. */ { /* @@ -2453,7 +2483,7 @@ sp_style_clear(SPStyle *style) style->text = text; style->text_private = text_private; - /* fixme: */ + style->text->font_specification.set = FALSE; style->text->font.set = FALSE; style->text->font_family.set = FALSE; @@ -2633,6 +2663,7 @@ sp_text_style_new() ts->refcount = 1; sp_text_style_clear(ts); + ts->font_specification.value = g_strdup("Bitstream Vera Sans"); ts->font.value = g_strdup("Bitstream Vera Sans"); ts->font_family.value = g_strdup("Bitstream Vera Sans"); @@ -2646,6 +2677,7 @@ sp_text_style_new() static void sp_text_style_clear(SPTextStyle *ts) { + ts->font_specification.set = FALSE; ts->font.set = FALSE; ts->font_family.set = FALSE; } @@ -2661,6 +2693,7 @@ sp_text_style_unref(SPTextStyle *st) st->refcount -= 1; if (st->refcount < 1) { + g_free(st->font_specification.value); g_free(st->font.value); g_free(st->font_family.value); g_free(st); @@ -2680,6 +2713,7 @@ sp_text_style_duplicate_unset(SPTextStyle *st) SPTextStyle *nt = g_new0(SPTextStyle, 1); nt->refcount = 1; + nt->font_specification.value = g_strdup(st->font_specification.value); nt->font.value = g_strdup(st->font.value); nt->font_family.value = g_strdup(st->font_family.value); @@ -2701,6 +2735,7 @@ sp_text_style_write(gchar *p, guint const len, SPTextStyle const *const st, guin flags = SP_STYLE_FLAG_IFSET; d += sp_style_write_istring(p + d, len - d, "font-family", &st->font_family, NULL, flags); + d += sp_style_write_istring(p + d, len - d, "-inkscape-font-specification", &st->font_specification, NULL, flags); return d; } @@ -3797,6 +3832,9 @@ sp_style_unset_property_attrs(SPObject *o) if (style->stroke_dashoffset_set) { repr->setAttribute("stroke-dashoffset", NULL); } + if (style->text_private && style->text->font_specification.set) { + repr->setAttribute("-inkscape-font-specification", NULL); + } if (style->text_private && style->text->font_family.set) { repr->setAttribute("font-family", NULL); } @@ -3856,6 +3894,7 @@ SPCSSAttr * sp_css_attr_unset_text(SPCSSAttr *css) { sp_repr_css_set_property(css, "font", NULL); // not implemented yet + sp_repr_css_set_property(css, "-inkscape-font-specification", NULL); sp_repr_css_set_property(css, "font-size", NULL); sp_repr_css_set_property(css, "font-size-adjust", NULL); // not implemented yet sp_repr_css_set_property(css, "font-style", NULL); diff --git a/src/style.h b/src/style.h index 6e62187bc..47ba6955e 100644 --- a/src/style.h +++ b/src/style.h @@ -538,6 +538,9 @@ struct SPTextStyle { /* CSS font properties */ SPIString font_family; + /* Full font name, as font_factory::ConstructFontSpecification would give */ + SPIString font_specification; + /** \todo fixme: The 'font' property is ugly, and not working (lauris) */ SPIString font; }; diff --git a/src/widgets/font-selector.cpp b/src/widgets/font-selector.cpp index c9e5d0bbb..9da48d0e6 100644 --- a/src/widgets/font-selector.cpp +++ b/src/widgets/font-selector.cpp @@ -353,7 +353,7 @@ static void sp_font_selector_emit_set (SPFontSelector *fsel) if ((!family) || (!style)) return; - font = (font_factory::Default())->FaceFromDescr (family, style); + font = (font_factory::Default())->FaceFromUIStrings (family, style); // FIXME: when a text object uses non-available font, font==NULL and we can't set size // (and the size shown in the widget is invalid). To fix, here we must always get some @@ -386,73 +386,103 @@ GtkWidget *sp_font_selector_new() void sp_font_selector_set_font (SPFontSelector *fsel, font_instance *font, double size) { if (font) - { - gchar family[256]; - font->Family (family, 256); - - Gtk::TreePath path; + { + Gtk::TreePath path; + font_instance *tempFont = NULL; + + Glib::ustring family = font_factory::Default()->GetUIFamilyString(font->descr); + + try { + path = Inkscape::FontLister::get_instance()->get_row_for_font (family); + } catch (...) { + return; + } - try { - path = Inkscape::FontLister::get_instance()->get_row_for_font (family); - } catch (...) { - return; + fsel->block_emit = TRUE; + gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (fsel->family_treeview)), path.gobj()); + gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fsel->family_treeview), path.gobj(), NULL, TRUE, 0.5, 0.5); + fsel->block_emit = FALSE; + + GList *list = 0; + GtkTreeIter iter; + GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW(fsel->family_treeview)); + gtk_tree_model_get_iter (model, &iter, path.gobj()); + gtk_tree_model_get (model, &iter, 1, &list, -1); + + unsigned int currentStyleNumber = 0; + unsigned int bestStyleNumber = 0; + + PangoFontDescription *incomingFont = pango_font_description_copy(font->descr); + pango_font_description_unset_fields(incomingFont, PANGO_FONT_MASK_SIZE); + + char *incomingFontString = pango_font_description_to_string(incomingFont); + + tempFont = (font_factory::Default())->FaceFromUIStrings(family.c_str(), (char*)list->data); + + PangoFontDescription *bestMatchForFont = NULL; + if (tempFont) { + bestMatchForFont = pango_font_description_copy(tempFont->descr); + tempFont->Unref(); + tempFont = NULL; + } + + pango_font_description_unset_fields(bestMatchForFont, PANGO_FONT_MASK_SIZE); + + list = list->next; + + while (list) { + currentStyleNumber++; + + tempFont = font_factory::Default()->FaceFromUIStrings(family.c_str(), (char*)list->data); + + PangoFontDescription *currentMatchForFont = NULL; + if (tempFont) { + currentMatchForFont = pango_font_description_copy(tempFont->descr); + tempFont->Unref(); + tempFont = NULL; } - - fsel->block_emit = TRUE; - gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (fsel->family_treeview)), path.gobj()); - gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fsel->family_treeview), path.gobj(), NULL, TRUE, 0.5, 0.5); - fsel->block_emit = FALSE; - - GList *list = 0; - GtkTreeIter iter; - GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW(fsel->family_treeview)); - gtk_tree_model_get_iter (model, &iter, path.gobj()); - gtk_tree_model_get (model, &iter, 1, &list, -1); - - gchar descr[256]; - font->Name(descr, 256); - std::string descr_best (family); - descr_best += " "; - descr_best += ((char*)list->data); - - PangoFontDescription *descr_ = pango_font_description_from_string(descr); - PangoFontDescription *best_ = pango_font_description_from_string(descr_best.c_str()); - - unsigned int i = 0; - unsigned int best_i = 0; - - // try to find best match with style description (i.e. bold, italic ?) - for (list = list->next ; list ; list = list->next) - { - i++; - std::string descr_try (family); - descr_try += " "; - descr_try += ((char*)list->data); - PangoFontDescription *try_ = pango_font_description_from_string(descr_try.c_str()); - if (pango_font_description_better_match (descr_, best_, try_)) - { - pango_font_description_free (best_); - best_ = pango_font_description_from_string (descr_try.c_str ()); - best_i = i; + + if (currentMatchForFont) { + pango_font_description_unset_fields(currentMatchForFont, PANGO_FONT_MASK_SIZE); + + char *currentMatchString = pango_font_description_to_string(currentMatchForFont); + + if (!strcmp(incomingFontString, currentMatchString) + || pango_font_description_better_match(incomingFont, bestMatchForFont, currentMatchForFont)) { + // Found a better match for the font we are looking for + pango_font_description_free(bestMatchForFont); + bestMatchForFont = pango_font_description_copy(currentMatchForFont); + bestStyleNumber = currentStyleNumber; } - pango_font_description_free(try_); - } - pango_font_description_free(descr_); - pango_font_description_free(best_); - - GtkTreePath *path_c = gtk_tree_path_new (); - gtk_tree_path_append_index (path_c, best_i); - gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (fsel->style_treeview)), path_c); - gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fsel->style_treeview), path_c, NULL, TRUE, 0.5, 0.5); - - if (size != fsel->fontsize) - { - gchar s[8]; - g_snprintf (s, 8, "%.5g", size); // UI, so printf is ok - gtk_entry_set_text (GTK_ENTRY (GTK_BIN(fsel->size)->child), s); - fsel->fontsize = size; + + g_free(currentMatchString); + + pango_font_description_free(currentMatchForFont); } + + list = list->next; + } + + if (bestMatchForFont) + pango_font_description_free(bestMatchForFont); + if (incomingFont) + pango_font_description_free(incomingFont); + g_free(incomingFontString); + + GtkTreePath *path_c = gtk_tree_path_new (); + gtk_tree_path_append_index (path_c, bestStyleNumber); + gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (fsel->style_treeview)), path_c); + gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fsel->style_treeview), path_c, NULL, TRUE, 0.5, 0.5); + + if (size != fsel->fontsize) + { + gchar s[8]; + g_snprintf (s, 8, "%.5g", size); // UI, so printf is ok + gtk_entry_set_text (GTK_ENTRY (GTK_BIN(fsel->size)->child), s); + fsel->fontsize = size; + } } + } font_instance* sp_font_selector_get_font(SPFontSelector *fsel) diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp index 9e9686e77..81eedaeb8 100644 --- a/src/widgets/toolbox.cpp +++ b/src/widgets/toolbox.cpp @@ -76,6 +76,7 @@ #include "document-private.h" #include "desktop-style.h" #include "../libnrtype/font-lister.h" +#include "../libnrtype/font-instance.h" #include "../connection-pool.h" #include "../prefs-utils.h" #include "../inkscape-stock.h" @@ -2360,7 +2361,7 @@ static void box3d_toggle_vp_changed (GtkToggleAction *act, GObject *dataKludge, // in turn, prevent listener from responding g_object_set_data(dataKludge, "freeze", GINT_TO_POINTER(TRUE)); - persp3d_set_VP_state(persp, axis, gtk_toggle_action_get_active(act) ? Proj::INFINITE : Proj::FINITE); + persp3d_set_VP_state(persp, axis, (gtk_toggle_action_get_active(act) ? Proj::VP_INFINITE : Proj::VP_FINITE)); // FIXME: Can we merge this functionality with the one in box3d_persp_tb_event_attr_changed()? gchar *str; @@ -3948,6 +3949,9 @@ sp_text_toolbox_selection_changed (Inkscape::Selection */*selection*/, GObject * { SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); + + int result_fontspec = + sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION); int result_family = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY); @@ -3981,15 +3985,27 @@ sp_text_toolbox_selection_changed (Inkscape::Selection */*selection*/, GObject * GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry")); gtk_entry_set_text (GTK_ENTRY (entry), ""); - } else if (query->text->font_family.value) { + } else if (query->text->font_specification.value || query->text->font_family.value) { GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry")); - gtk_entry_set_text (GTK_ENTRY (entry), query->text->font_family.value); + + // Get the font that corresponds + Glib::ustring familyName; + + font_instance * font = font_factory::Default()->FaceFromStyle(query); + if (font) { + familyName = font_factory::Default()->GetUIFamilyString(font->descr); + font->Unref(); + font = NULL; + } + + gtk_entry_set_text (GTK_ENTRY (entry), familyName.c_str()); Gtk::TreePath path; try { - path = Inkscape::FontLister::get_instance()->get_row_for_font (query->text->font_family.value); + path = Inkscape::FontLister::get_instance()->get_row_for_font (familyName); } catch (...) { + g_warning("Family name %s does not have an entry in the font lister.", familyName.c_str()); return; } @@ -4142,14 +4158,46 @@ sp_text_toolbox_family_changed (GtkTreeSelection *selection, SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); - int result_numbers = - sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); - + int result_fontspec = + sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION); + SPCSSAttr *css = sp_repr_css_attr_new (); - sp_repr_css_set_property (css, "font-family", family); + + std::string fontSpec = query->text->font_specification.value; + if (!fontSpec.empty()) { + Glib::ustring newFontSpec = font_factory::Default()->ReplaceFontSpecificationFamily(fontSpec, family); + if (!newFontSpec.empty() && fontSpec != newFontSpec) { + font_instance *font = font_factory::Default()->FaceFromFontSpecification(newFontSpec.c_str()); + if (font) { + sp_repr_css_set_property (css, "-inkscape-font-specification", newFontSpec.c_str()); + + // Set all the these just in case they were altered when finding the best + // match for the new family and old style... + + gchar c[256]; + + font->Family(c, 256); + sp_repr_css_set_property (css, "font-family", c); + + font->Attribute( "weight", c, 256); + sp_repr_css_set_property (css, "font-weight", c); + + font->Attribute("style", c, 256); + sp_repr_css_set_property (css, "font-style", c); + + font->Attribute("stretch", c, 256); + sp_repr_css_set_property (css, "font-stretch", c); + + font->Attribute("variant", c, 256); + sp_repr_css_set_property (css, "font-variant", c); + + font->Unref(); + } + } + } // If querying returned nothing, read the style from the text tool prefs (default style for new texts) - if (result_numbers == QUERY_STYLE_NOTHING) + if (result_fontspec == QUERY_STYLE_NOTHING) { sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style"); sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb @@ -4264,29 +4312,45 @@ sp_text_toolbox_style_toggled (GtkToggleButton *button, int prop = GPOINTER_TO_INT(data); bool active = gtk_toggle_button_get_active (button); + SPStyle *query = + sp_style_new (SP_ACTIVE_DOCUMENT); + int result_fontspec = + sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION); + + Glib::ustring fontSpec = query->text->font_specification.value; + Glib::ustring newFontSpec; switch (prop) { case 0: { - sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" ); + if (!fontSpec.empty()) { + newFontSpec = font_factory::Default()->FontSpecificationSetBold(fontSpec, active); + } + if (fontSpec != newFontSpec) { + sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" ); + } break; } case 1: { - sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal"); + if (!fontSpec.empty()) { + newFontSpec = font_factory::Default()->FontSpecificationSetItalic(fontSpec, active); + } + if (fontSpec != newFontSpec) { + sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal"); + } break; } } - SPStyle *query = - sp_style_new (SP_ACTIVE_DOCUMENT); - int result_numbers = - sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); + if (!fontSpec.empty()) { + sp_repr_css_set_property (css, "-inkscape-font-specification", fontSpec.c_str()); + } // If querying returned nothing, read the style from the text tool prefs (default style for new texts) - if (result_numbers == QUERY_STYLE_NOTHING) + if (result_fontspec == QUERY_STYLE_NOTHING) { sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style"); } @@ -5200,3 +5264,5 @@ static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* main */ // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : + + diff --git a/src/xml/repr-css.cpp b/src/xml/repr-css.cpp index d3c39e5a2..ec5848366 100644 --- a/src/xml/repr-css.cpp +++ b/src/xml/repr-css.cpp @@ -155,7 +155,9 @@ sp_repr_css_write_string(SPCSSAttr *css) buffer.append(g_quark_to_string(iter->key)); buffer.push_back(':'); - if (!strcmp(g_quark_to_string(iter->key), "font-family")) { // we only quote font-family, as SPStyle does + if (!strcmp(g_quark_to_string(iter->key), "font-family") + || !strcmp(g_quark_to_string(iter->key), "-inkscape-font-specification")) { + // we only quote font-family/font-specification, as SPStyle does gchar *t = g_strdup (iter->value); g_free (t); gchar *val_quoted = css2_escape_quote (iter->value); |
