Code

switch repr-css to using libcroco, same as SPStyle uses, instead of its own hacky...
[inkscape.git] / src / xml / repr-css.cpp
1 /*
2  *   bulia byak <buliabyak@users.sf.net>
3 */ 
4  
5 #define SP_REPR_CSS_C
8 #include <glibmm/ustring.h>
10 #include "xml/repr.h"
11 #include "xml/simple-node.h"
12 #include "style.h"
13 #include "libcroco/cr-sel-eng.h"
15 using Inkscape::Util::List;
16 using Inkscape::XML::AttributeRecord;
17 using Inkscape::XML::SimpleNode;
18 using Inkscape::XML::Node;
19 using Inkscape::XML::NodeType;
21 struct SPCSSAttrImpl : public SimpleNode, public SPCSSAttr {
22 public:
23     SPCSSAttrImpl() : SimpleNode(g_quark_from_static_string("css")) {}
25     NodeType type() const { return Inkscape::XML::ELEMENT_NODE; }
27 protected:
28     SimpleNode *_duplicate() const { return new SPCSSAttrImpl(*this); }
29 };
31 static void sp_repr_css_add_components(SPCSSAttr *css, Node *repr, gchar const *attr);
33 SPCSSAttr *
34 sp_repr_css_attr_new()
35 {
36     return new SPCSSAttrImpl();
37 }
39 void
40 sp_repr_css_attr_unref(SPCSSAttr *css)
41 {
42     g_assert(css != NULL);
43     Inkscape::GC::release((Node *) css);
44 }
46 SPCSSAttr *sp_repr_css_attr(Node *repr, gchar const *attr)
47 {
48     g_assert(repr != NULL);
49     g_assert(attr != NULL);
51     SPCSSAttr *css = sp_repr_css_attr_new();
52     sp_repr_css_add_components(css, repr, attr);
53     return css;
54 }
56 SPCSSAttr *sp_repr_css_attr_inherited(Node *repr, gchar const *attr)
57 {
58     g_assert(repr != NULL);
59     g_assert(attr != NULL);
61     SPCSSAttr *css = sp_repr_css_attr_new();
63     sp_repr_css_add_components(css, repr, attr);
64     Node *current = sp_repr_parent(repr);
66     while (current) {
67         sp_repr_css_add_components(css, current, attr);
68         current = sp_repr_parent(current);
69     }
71     return css;
72 }
74 static void
75 sp_repr_css_add_components(SPCSSAttr *css, Node *repr, gchar const *attr)
76 {
77     g_assert(css != NULL);
78     g_assert(repr != NULL);
79     g_assert(attr != NULL);
81     char const *data = repr->attribute(attr);
82     sp_repr_css_attr_add_from_string(css, data);
83 }
85 char const *
86 sp_repr_css_property(SPCSSAttr *css, gchar const *name, gchar const *defval)
87 {
88     g_assert(css != NULL);
89     g_assert(name != NULL);
91     char const *attr = ((Node *)css)->attribute(name);
92     return ( attr == NULL
93              ? defval
94              : attr );
95 }
97 bool
98 sp_repr_css_property_is_unset(SPCSSAttr *css, gchar const *name)
99 {
100     g_assert(css != NULL);
101     g_assert(name != NULL);
103     char const *attr = ((Node *)css)->attribute(name);
104     return (attr && !strcmp(attr, "inkscape:unset"));
108 void
109 sp_repr_css_set_property(SPCSSAttr *css, gchar const *name, gchar const *value)
111     g_assert(css != NULL);
112     g_assert(name != NULL);
114     sp_repr_set_attr((Node *) css, name, value);
117 void
118 sp_repr_css_unset_property(SPCSSAttr *css, gchar const *name)
120     g_assert(css != NULL);
121     g_assert(name != NULL);
123     sp_repr_set_attr((Node *) css, name, "inkscape:unset");
126 double
127 sp_repr_css_double_property(SPCSSAttr *css, gchar const *name, double defval)
129     g_assert(css != NULL);
130     g_assert(name != NULL);
132     return sp_repr_get_double_attribute((Node *) css, name, defval);
135 gchar *
136 sp_repr_css_write_string(SPCSSAttr *css)
138     Glib::ustring buffer;
140     for ( List<AttributeRecord const> iter = css->attributeList() ;
141           iter ; ++iter )
142     {
143         if (iter->value && !strcmp(iter->value, "inkscape:unset")) {
144             continue;
145         }
147         buffer.append(g_quark_to_string(iter->key));
148         buffer.push_back(':');
149         if (!strcmp(g_quark_to_string(iter->key), "font-family")) { // we only quote font-family, as SPStyle does
150             gchar *t = g_strdup (iter->value);
151             g_free (t);
152             gchar *val_quoted = css2_escape_quote (iter->value);
153             if (val_quoted) {
154                 buffer.append(val_quoted);
155                 g_free (val_quoted);
156             }
157         } else {
158             buffer.append(iter->value); // unquoted
159         }
161         if (rest(iter)) {
162             buffer.push_back(';');
163         }
164     }
166     return (buffer.empty() ? NULL : g_strdup (buffer.c_str()));
169 void
170 sp_repr_css_set(Node *repr, SPCSSAttr *css, gchar const *attr)
172     g_assert(repr != NULL);
173     g_assert(css != NULL);
174     g_assert(attr != NULL);
176     gchar *value = sp_repr_css_write_string(css);
178     repr->setAttribute(attr, value);
180     if (value) g_free (value);
183 void
184 sp_repr_css_print(SPCSSAttr *css)
186     for ( List<AttributeRecord const> iter = css->attributeList() ;
187           iter ; ++iter )
188     {
189         g_print(g_quark_to_string(iter->key));
190         g_print(":\t");
191         g_print(iter->value);
192         g_print("\n");
193     }
196 void
197 sp_repr_css_merge(SPCSSAttr *dst, SPCSSAttr *src)
199     g_assert(dst != NULL);
200     g_assert(src != NULL);
202     dst->mergeFrom(src, "");
206 static void
207 sp_repr_css_merge_from_decl(SPCSSAttr *css, CRDeclaration const *const decl)
209     guchar *const str_value_unsigned = cr_term_to_string(decl->value);
210     gchar *const str_value = reinterpret_cast<gchar *>(str_value_unsigned);
211     gchar *value_unquoted = attribute_unquote (str_value); // libcroco returns strings quoted in ""
212     sp_repr_set_attr((Node *) css, decl->property->stryng->str, value_unquoted);
213     g_free(value_unquoted);
214     g_free(str_value);
217 /**
218  * \pre decl_list != NULL
219  */
220 static void
221 sp_repr_css_merge_from_decl_list(SPCSSAttr *css, CRDeclaration const *const decl_list)
223     if (decl_list->next) {
224         sp_repr_css_merge_from_decl_list(css, decl_list->next);
225     }
226     sp_repr_css_merge_from_decl(css, decl_list);
229 void
230 sp_repr_css_attr_add_from_string(SPCSSAttr *css, gchar const *p)
232     if (p != NULL) {
233         CRDeclaration *const decl_list
234             = cr_declaration_parse_list_from_buf(reinterpret_cast<guchar const *>(p), CR_UTF_8);
235         if (decl_list) {
236             sp_repr_css_merge_from_decl_list(css, decl_list);
237             cr_declaration_destroy(decl_list);
238         }
239     }
242 void
243 sp_repr_css_change(Node *repr, SPCSSAttr *css, gchar const *attr)
245     g_assert(repr != NULL);
246     g_assert(css != NULL);
247     g_assert(attr != NULL);
249     SPCSSAttr *current = sp_repr_css_attr(repr, attr);
250     sp_repr_css_merge(current, css);
251     sp_repr_css_set(repr, current, attr);
253     sp_repr_css_attr_unref(current);
256 void
257 sp_repr_css_change_recursive(Node *repr, SPCSSAttr *css, gchar const *attr)
259     g_assert(repr != NULL);
260     g_assert(css != NULL);
261     g_assert(attr != NULL);
263     sp_repr_css_change(repr, css, attr);
265     for (Node *child = repr->firstChild(); child != NULL; child = child->next()) {
266         sp_repr_css_change_recursive(child, css, attr);
267     }
271 /*
272   Local Variables:
273   mode:c++
274   c-file-style:"stroustrup"
275   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
276   indent-tabs-mode:nil
277   fill-column:99
278   End:
279 */
280 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :