From: bryce Date: Sat, 5 Jan 2008 10:38:18 +0000 (+0000) Subject: Applying Gail's patch for font-specification X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=5834db43b21308e958a2fdbbec082b1a4f019a38;p=inkscape.git Applying Gail's patch for font-specification (Closes LP: #169973) - New attribute in an object's style string called -inkscape-font-specification stores full font name - This will be useful when we can support fonts that don't fit into the confines of CSS (if either pango enhances their PangoFontDescription structure, or we can get around its limitations) - Framework in place to separate font families from their "styles" (faces) in the text and font dialog - need only the code that does the actual separation - Text and Styles dialog shows only fonts it can handle --- 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 @@ -1050,6 +1050,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) { @@ -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 +#include + #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())); + } + + // 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 &styleList = (*map)[familyUIName]; + + for (std::list::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 + #include #include #include @@ -21,7 +23,9 @@ #include #include "nr-type-primitives.h" #include "nr-type-pos-def.h" +#include "font-style-to-pos.h" #include +#include "../style.h" /* Freetype */ #ifdef USE_PANGO_WIN32 @@ -31,6 +35,11 @@ #include #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 { @@ -40,6 +49,13 @@ struct font_descr_equal : public std::binary_function > 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 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 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 #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(families.names[i]); - - NRStyleList styles; - if (font_factory::Default()->Styles (reinterpret_cast(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(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 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(g_strdup(familyName.c_str())); + + // Now go through the styles + GList *styles = NULL; + std::list &styleStrings = familyStyleMap[familyName]; + for (std::list::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 - FontLister::get_font_list () const - { - return font_list_store; - } + const Glib::RefPtr + 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 font; + Gtk::TreeModelColumn font; /** Column containing an std::vector with style names * for the corresponding family @@ -60,7 +60,7 @@ namespace Inkscape }; FontListClass FontList; - typedef std::map IterMapType; + typedef std::map 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 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);