X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fstyle.cpp;h=722f1677d6cdbff319a81aafe9b076970dfe0aea;hb=b39ef664c9e65b893c07b3ec794b7e2240f8c251;hp=bd880b857cb4760adaa117b8dd3cf59eb4072643;hpb=761a541468cc0b8a7fcfb8c65784c0896f0f80f4;p=inkscape.git diff --git a/src/style.cpp b/src/style.cpp index bd880b857..722f1677d 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -30,7 +30,6 @@ #include "attributes.h" #include "document.h" #include "extract-uri.h" -#include "marker-status.h" #include "uri-references.h" #include "sp-paint-server.h" #include "streq.h" @@ -118,7 +117,7 @@ static void sp_style_clear(SPStyle *style); static void sp_style_merge_property(SPStyle *style, gint id, gchar const *val); static void sp_style_merge_ipaint(SPStyle *style, SPIPaint *paint, SPIPaint const *parent); -static void sp_style_merge_ifilter(SPStyle *style, SPIFilter *child, SPIFilter const *parent); +static void sp_style_merge_ifilter(SPStyle *style, SPIFilter const *parent); static void sp_style_read_dash(SPStyle *style, gchar const *str); static SPTextStyle *sp_text_style_new(void); @@ -138,7 +137,7 @@ static void sp_style_read_itextdecoration(SPITextDecoration *val, gchar const *s static void sp_style_read_icolor(SPIPaint *paint, gchar const *str, SPStyle *style, SPDocument *document); static void sp_style_read_ipaint(SPIPaint *paint, gchar const *str, SPStyle *style, SPDocument *document); static void sp_style_read_ifontsize(SPIFontSize *val, gchar const *str); -static void sp_style_read_ifilter(SPIFilter *f, gchar const *str, SPStyle *style, SPDocument *document); +static void sp_style_read_ifilter(gchar const *str, SPStyle *style, SPDocument *document); static void sp_style_read_penum(SPIEnum *val, Inkscape::XML::Node *repr, gchar const *key, SPStyleEnum const *dict, bool can_explicitly_inherit); static void sp_style_read_plength(SPILength *val, Inkscape::XML::Node *repr, gchar const *key); @@ -156,11 +155,9 @@ static gint sp_style_write_ilengthornormal(gchar *p, gint const len, gchar const static gint sp_style_write_itextdecoration(gchar *p, gint const len, gchar const *const key, SPITextDecoration const *const val, SPITextDecoration const *const base, guint const flags); static gint sp_style_write_ifilter(gchar *b, gint len, gchar const *key, SPIFilter const *filter, SPIFilter const *base, guint flags); -static void css2_unescape_unquote(SPIString *val); - static void sp_style_paint_clear(SPStyle *style, SPIPaint *paint); -static void sp_style_filter_clear(SPStyle *style, SPIFilter *filter); +static void sp_style_filter_clear(SPStyle *style); #define SPS_READ_IENUM_IF_UNSET(v,s,d,i) if (!(v)->set) {sp_style_read_ienum((v), (s), (d), (i));} #define SPS_READ_PENUM_IF_UNSET(v,r,k,d,i) if (!(v)->set) {sp_style_read_penum((v), (r), (k), (d), (i));} @@ -421,6 +418,9 @@ sp_style_new() new (&style->stroke_release_connection) sigc::connection(); new (&style->stroke_modified_connection) sigc::connection(); + new (&style->filter_release_connection) sigc::connection(); + new (&style->filter_modified_connection) sigc::connection(); + return style; } @@ -478,7 +478,7 @@ sp_style_unref(SPStyle *style) if (style->text) sp_text_style_unref(style->text); sp_style_paint_clear(style, &style->fill); sp_style_paint_clear(style, &style->stroke); - sp_style_filter_clear(style, &style->filter); + sp_style_filter_clear(style); style->fill_release_connection.disconnect(); style->fill_release_connection.~connection(); style->fill_modified_connection.disconnect(); @@ -487,6 +487,10 @@ sp_style_unref(SPStyle *style) style->stroke_release_connection.~connection(); style->stroke_modified_connection.disconnect(); style->stroke_modified_connection.~connection(); + style->filter_modified_connection.disconnect(); + style->filter_modified_connection.~connection(); + style->filter_release_connection.disconnect(); + style->filter_release_connection.~connection(); g_free(style->stroke_dash.dash); g_free(style); } @@ -510,7 +514,7 @@ sp_style_read(SPStyle *style, SPObject *object, Inkscape::XML::Node *repr) style->cloned = true; } - /* 1. Style itself */ + /* 1. Style attribute */ gchar const *val = repr->attribute("style"); if (val != NULL) { sp_style_merge_from_style_string(style, val); @@ -671,8 +675,9 @@ sp_style_read(SPStyle *style, SPObject *object, Inkscape::XML::Node *repr) val = repr->attribute("font-family"); if (val) { if (!style->text_private) sp_style_privatize_text(style); - sp_style_read_istring(&style->text->font_family, val); - css2_unescape_unquote(&style->text->font_family); + gchar *val_unquoted = attribute_unquote(val); + sp_style_read_istring(&style->text->font_family, val_unquoted); + if (val_unquoted) g_free (val_unquoted); } } @@ -680,7 +685,7 @@ sp_style_read(SPStyle *style, SPObject *object, Inkscape::XML::Node *repr) if (!style->filter.set) { val = repr->attribute("filter"); if (val) { - sp_style_read_ifilter(&style->filter, val, style, (object) ? SP_OBJECT_DOCUMENT(object) : NULL); + sp_style_read_ifilter(val, style, (object) ? SP_OBJECT_DOCUMENT(object) : NULL); } } SPS_READ_PENUM_IF_UNSET(&style->enable_background, repr, @@ -771,8 +776,9 @@ sp_style_merge_property(SPStyle *style, gint id, gchar const *val) case SP_PROP_FONT_FAMILY: if (!style->text_private) sp_style_privatize_text(style); if (!style->text->font_family.set) { - sp_style_read_istring(&style->text->font_family, val); - css2_unescape_unquote(&style->text->font_family); + gchar *val_unquoted = attribute_unquote(val); + sp_style_read_istring(&style->text->font_family, val_unquoted); + if (val_unquoted) g_free (val_unquoted); } break; case SP_PROP_FONT_SIZE: @@ -920,7 +926,7 @@ sp_style_merge_property(SPStyle *style, gint id, gchar const *val) /* Filter */ case SP_PROP_FILTER: if (!style->filter.set && !style->filter.inherit) { - sp_style_read_ifilter(&style->filter, val, style, (style->object) ? SP_OBJECT_DOCUMENT(style->object) : NULL); + sp_style_read_ifilter(val, style, (style->object) ? SP_OBJECT_DOCUMENT(style->object) : NULL); } break; case SP_PROP_FLOOD_COLOR: @@ -983,7 +989,6 @@ sp_style_merge_property(SPStyle *style, gint id, gchar const *val) case SP_PROP_MARKER: /* TODO: Call sp_uri_reference_resolve(SPDocument *document, guchar const *uri) */ /* style->marker[SP_MARKER_LOC] = g_quark_from_string(val); */ - marker_status("Setting SP_PROP_MARKER"); if (!style->marker[SP_MARKER_LOC].set) { g_free(style->marker[SP_MARKER_LOC].value); style->marker[SP_MARKER_LOC].value = g_strdup(val); @@ -994,7 +999,6 @@ sp_style_merge_property(SPStyle *style, gint id, gchar const *val) case SP_PROP_MARKER_START: /* TODO: Call sp_uri_reference_resolve(SPDocument *document, guchar const *uri) */ - marker_status("Setting SP_PROP_MARKER_START"); if (!style->marker[SP_MARKER_LOC_START].set) { g_free(style->marker[SP_MARKER_LOC_START].value); style->marker[SP_MARKER_LOC_START].value = g_strdup(val); @@ -1004,7 +1008,6 @@ sp_style_merge_property(SPStyle *style, gint id, gchar const *val) break; case SP_PROP_MARKER_MID: /* TODO: Call sp_uri_reference_resolve(SPDocument *document, guchar const *uri) */ - marker_status("Setting SP_PROP_MARKER_MID"); if (!style->marker[SP_MARKER_LOC_MID].set) { g_free(style->marker[SP_MARKER_LOC_MID].value); style->marker[SP_MARKER_LOC_MID].value = g_strdup(val); @@ -1014,7 +1017,6 @@ sp_style_merge_property(SPStyle *style, gint id, gchar const *val) break; case SP_PROP_MARKER_END: /* TODO: Call sp_uri_reference_resolve(SPDocument *document, guchar const *uri) */ - marker_status("Setting SP_PROP_MARKER_END"); if (!style->marker[SP_MARKER_LOC_END].set) { g_free(style->marker[SP_MARKER_LOC_END].value); style->marker[SP_MARKER_LOC_END].value = g_strdup(val); @@ -1458,8 +1460,8 @@ sp_style_merge_from_parent(SPStyle *const style, SPStyle const *const parent) } /* Filter effects */ - if(style->filter.set && style->filter.inherit) { - sp_style_merge_ifilter(style, &style->filter, &parent->filter); + if (style->filter.inherit) { + sp_style_merge_ifilter(style, &parent->filter); } if(style->enable_background.inherit) { @@ -1930,6 +1932,14 @@ sp_style_merge_from_dying_parent(SPStyle *const style, SPStyle const *const pare style->enable_background.value = parent->enable_background.value; } + if (!style->filter.set || style->filter.inherit) + { + // FIXME: + // instead of just copying over, we need to _really merge_ the two filters by combining their + // filter primitives + sp_style_merge_ifilter(style, &parent->filter); + } + /** \todo * fixme: Check that we correctly handle all properties that don't * inherit by default (as shown in @@ -1987,8 +1997,6 @@ sp_style_merge_from_dying_parent(SPStyle *const style, SPStyle const *const pare * represent it as a normal SPILength; though will need to do something about existing * users of stroke_dash.offset and stroke_dashoffset_set. */ } - - /* TODO: deal with filters */ } @@ -2052,6 +2060,36 @@ sp_style_paint_server_modified(SPObject *obj, guint flags, SPStyle *style) +/** + * Disconnects from filter. + */ +static void +sp_style_filter_release(SPObject *obj, SPStyle *style) +{ + SPFilter *filter=static_cast(obj); + if (style->filter.filter == filter) + { + sp_style_filter_clear(style); + } +} + + +/** + * Emit style modified signal on style's object if the filter changed. + */ +static void +sp_style_filter_modified(SPObject *obj, guint flags, SPStyle *style) +{ + SPFilter *filter=static_cast(obj); + if (style->filter.filter == filter) + { + if (style->object) { + style->object->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + } + } +} + + /** * */ @@ -2116,15 +2154,26 @@ sp_style_merge_ipaint(SPStyle *style, SPIPaint *paint, SPIPaint const *parent) * Filter effects do not inherit by default */ static void -sp_style_merge_ifilter(SPStyle *style, SPIFilter *child, SPIFilter const *parent) +sp_style_merge_ifilter(SPStyle *style, SPIFilter const *parent) { - sp_style_filter_clear(style, child); - child->set = parent->set; - child->inherit = parent->inherit; - child->filter = parent->filter; - child->uri = parent->uri; - sp_object_href(SP_OBJECT(child), style); - style->filter_hreffed = true; + sp_style_filter_clear(style); + style->filter.set = parent->set; + style->filter.inherit = parent->inherit; + style->filter.filter = parent->filter; + style->filter.uri = parent->uri; + if (style->filter.filter) { + if (style->object && !style->cloned) { // href filter for style of non-clones only + sp_object_href(SP_OBJECT(style->filter.filter), style); + style->filter_hreffed = true; + } + if (style->object || style->cloned) { // connect to signals for style of real objects or clones (this excludes temp styles) + SPObject *filter = style->filter.filter; + style->filter_release_connection + = filter->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_style_filter_release), style)); + style->filter_modified_connection + = filter->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_style_filter_modified), style)); + } + } } /** @@ -2184,7 +2233,6 @@ sp_style_write_string(SPStyle const *const style, guint const flags) p += sp_style_write_ienum(p, c + BMAX - p, "stroke-linecap", enum_stroke_linecap, &style->stroke_linecap, NULL, flags); p += sp_style_write_ienum(p, c + BMAX - p, "stroke-linejoin", enum_stroke_linejoin, &style->stroke_linejoin, NULL, flags); - marker_status("sp_style_write_string: Writing markers"); if (style->marker[SP_MARKER_LOC].set) { p += g_snprintf(p, c + BMAX - p, "marker:%s;", style->marker[SP_MARKER_LOC].value); } else if (flags == SP_STYLE_FLAG_ALWAYS) { @@ -2349,7 +2397,6 @@ sp_style_write_difference(SPStyle const *const from, SPStyle const *const to) p += sp_style_write_iscale24(p, c + BMAX - p, "stroke-opacity", &from->stroke_opacity, &to->stroke_opacity, SP_STYLE_FLAG_IFDIFF); /* markers */ - marker_status("sp_style_write_difference: Writing markers"); if (from->marker[SP_MARKER_LOC].value != NULL) { p += g_snprintf(p, c + BMAX - p, "marker:%s;", from->marker[SP_MARKER_LOC].value); } @@ -2403,7 +2450,7 @@ sp_style_clear(SPStyle *style) sp_style_paint_clear(style, &style->fill); sp_style_paint_clear(style, &style->stroke); - sp_style_filter_clear(style, &style->filter); + sp_style_filter_clear(style); if (style->stroke_dash.dash) { g_free(style->stroke_dash.dash); } @@ -2525,10 +2572,8 @@ sp_style_clear(SPStyle *style) } style->filter.set = FALSE; - //Are these really needed? - style->filter.inherit = FALSE; style->filter.uri = NULL; - style->filter.filter = FALSE; + style->filter.filter = NULL; style->enable_background.value = SP_CSS_BACKGROUND_ACCUMULATE; style->enable_background.set = false; @@ -3107,8 +3152,9 @@ sp_style_read_ifontsize(SPIFontSize *val, gchar const *str) * Set SPIFilter object from string. */ static void -sp_style_read_ifilter( SPIFilter *f, gchar const *str, SPStyle * style, SPDocument *document) +sp_style_read_ifilter(gchar const *str, SPStyle * style, SPDocument *document) { + SPIFilter *f = &(style->filter); /* Try all possible values: inherit, none, uri */ if (streq(str, "inherit")) { f->set = TRUE; @@ -3131,16 +3177,20 @@ sp_style_read_ifilter( SPIFilter *f, gchar const *str, SPStyle * style, SPDocume f->inherit = FALSE; f->filter = NULL; if (document) { - SPObject *obj; - obj = sp_uri_reference_resolve(document, str); + SPObject *obj = sp_uri_reference_resolve(document, str); if (SP_IS_FILTER(obj)) { f->filter = SP_FILTER(obj); - sp_object_href(SP_OBJECT(f->filter), style); - style->filter_hreffed = true; - //g_signal_connect(G_OBJECT(f->filter), "release", - // G_CALLBACK(sp_style_filter_release), style); - //g_signal_connect(G_OBJECT(f->filter), "modified", - // G_CALLBACK(sp_style_filter_modified), style); + if (style->object && !style->cloned) { + sp_object_href(obj, style); + style->filter_hreffed = true; + } + if (style->object || style->cloned) { // connect to signals for style of real objects or clones (this excludes temp styles) + SPObject *filter = style->filter.filter; + style->filter_release_connection + = filter->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_style_filter_release), style)); + style->filter_modified_connection + = filter->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_style_filter_modified), style)); + } } else { g_warning("Element '%s' not found or is not a filter", f->uri); } @@ -3302,7 +3352,9 @@ sp_style_write_istring(gchar *p, gint const len, gchar const *const key, if (val->inherit) { return g_snprintf(p, len, "%s:inherit;", key); } else { - return g_snprintf(p, len, "%s:%s;", key, val->value); + gchar *val_quoted = css2_escape_quote(val->value); + return g_snprintf(p, len, "%s:%s;", key, val_quoted); + g_free (val_quoted); } } return 0; @@ -3678,18 +3730,42 @@ sp_style_paint_clear(SPStyle *style, SPIPaint *paint) * Clear filter object, and disconnect style from paintserver (if present). */ static void -sp_style_filter_clear(SPStyle *style, SPIFilter *f) +sp_style_filter_clear(SPStyle *style) { if (style->filter_hreffed) { - sp_object_hunref(SP_OBJECT(f->filter), style); + sp_object_hunref(SP_OBJECT(style->filter.filter), style); style->filter_hreffed = false; } - //style->fill_release_connection.disconnect(); - //style->fill_modified_connection.disconnect(); + style->filter_release_connection.disconnect(); + style->filter_modified_connection.disconnect(); + + style->filter.filter = NULL; +} - f->filter = NULL; - + +// FIXME: Everything below this line belongs in a different file - css-chemistry? + +void +sp_style_set_property_url (SPObject *item, gchar const *property, SPObject *linked, bool recursive) +{ + Inkscape::XML::Node *repr = SP_OBJECT_REPR(item); + + if (repr == NULL) return; + + g_return_if_fail(linked != NULL); + + gchar *val = g_strdup_printf("url(#%s)", SP_OBJECT_ID(linked)); + + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property(css, property, val); + g_free(val); + if (recursive) { + sp_repr_css_change_recursive(repr, css, "style"); + } else { + sp_repr_css_change(repr, css, "style"); + } + sp_repr_css_attr_unref(css); } @@ -3953,28 +4029,63 @@ sp_css_attr_scale(SPCSSAttr *css, double ex) /** - * Remove quotes from SPIString object value. - * - * \todo FIXME: now used for font family, but perhaps this should apply to - * ALL strings (check CSS spec), in which case this should be part of - * read_istring. + * Remove quotes and escapes from a string. Returned value must be g_free'd. + * Note: in CSS (in style= and in stylesheets), unquoting and unescaping is done + * by libcroco, our CSS parser, though it adds a new pair of "" quotes for the strings + * it parsed for us. So this function is only used to remove those quotes and for + * presentation attributes, without any unescaping. (XML unescaping + * (& etc) is done by XML parser.) */ -static void -css2_unescape_unquote(SPIString *val) +gchar * +attribute_unquote(gchar const *val) { - if (val->set && val->value && strlen(val->value) >= 2) { + if (val) { + if (*val == '\'' || *val == '"') { + int l = strlen(val); + if (l >= 2) { + if ( ( val[0] == '"' && val[l - 1] == '"' ) || + ( val[0] == '\'' && val[l - 1] == '\'' ) ) { + return (g_strndup (val+1, l-2)); + } + } + } + } - /// \todo unescape all \-escaped chars + return (val? g_strdup (val) : NULL); +} - int l = strlen(val->value); - if ( ( val->value[0] == '"' && val->value[l - 1] == '"' ) || - ( val->value[0] == '\'' && val->value[l - 1] == '\'' ) ) { - memcpy(val->value, val->value + 1, l - 2); - val->value[l - 2] = '\0'; +/** + * Quote and/or escape string for writing to CSS (style=). Returned value must be g_free'd. + */ +gchar * +css2_escape_quote(gchar const *val) { + + Glib::ustring t; + bool quote = false; + + for (gchar const *i = val; *i; i++) { + if (g_ascii_isalnum(*i) || *i=='-' || *i=='_') { + t.push_back(*i); + } else if (*i=='\'') { + t.push_back('\\'); + t.push_back(*i); + quote = true; + } else { + t.push_back(*i); + quote = true; + } + if (i == val && !g_ascii_isalpha(*i)) { + quote = true; } } -} + if (quote) { // we use the ' quotes so the result can go to the XML attribute + t.insert(t.begin(), '\''); + t.push_back('\''); + } + + return (t.empty() ? NULL : g_strdup (t.c_str())); +} /* Local Variables: