1 /*
2 * bulia byak <buliabyak@users.sf.net>
3 */
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"));
105 }
108 void
109 sp_repr_css_set_property(SPCSSAttr *css, gchar const *name, gchar const *value)
110 {
111 g_assert(css != NULL);
112 g_assert(name != NULL);
114 sp_repr_set_attr((Node *) css, name, value);
115 }
117 void
118 sp_repr_css_unset_property(SPCSSAttr *css, gchar const *name)
119 {
120 g_assert(css != NULL);
121 g_assert(name != NULL);
123 sp_repr_set_attr((Node *) css, name, "inkscape:unset");
124 }
126 double
127 sp_repr_css_double_property(SPCSSAttr *css, gchar const *name, double defval)
128 {
129 g_assert(css != NULL);
130 g_assert(name != NULL);
132 return sp_repr_get_double_attribute((Node *) css, name, defval);
133 }
135 gchar *
136 sp_repr_css_write_string(SPCSSAttr *css)
137 {
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()));
167 }
169 void
170 sp_repr_css_set(Node *repr, SPCSSAttr *css, gchar const *attr)
171 {
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);
181 }
183 void
184 sp_repr_css_print(SPCSSAttr *css)
185 {
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 }
194 }
196 void
197 sp_repr_css_merge(SPCSSAttr *dst, SPCSSAttr *src)
198 {
199 g_assert(dst != NULL);
200 g_assert(src != NULL);
202 dst->mergeFrom(src, "");
203 }
206 static void
207 sp_repr_css_merge_from_decl(SPCSSAttr *css, CRDeclaration const *const decl)
208 {
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);
215 }
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)
222 {
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);
227 }
229 void
230 sp_repr_css_attr_add_from_string(SPCSSAttr *css, gchar const *p)
231 {
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 }
240 }
242 void
243 sp_repr_css_change(Node *repr, SPCSSAttr *css, gchar const *attr)
244 {
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);
254 }
256 void
257 sp_repr_css_change_recursive(Node *repr, SPCSSAttr *css, gchar const *attr)
258 {
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 }
268 }
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 :