Code

create inkview on dist
[inkscape.git] / src / sp-symbol.cpp
1 #define __SP_SYMBOL_C__
3 /*
4  * SVG <symbol> implementation
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *
9  * Copyright (C) 1999-2003 Lauris Kaplinski
10  *
11  * Released under GNU GPL, read the file 'COPYING' for more information
12  */
14 #include "config.h"
16 #include "libnr/nr-matrix-fns.h"
17 #include "libnr/nr-matrix-ops.h"
18 #include "display/nr-arena-group.h"
19 #include "xml/repr.h"
20 #include "attributes.h"
21 #include "print.h"
22 #include "sp-symbol.h"
23 #include "document.h"
25 static void sp_symbol_class_init (SPSymbolClass *klass);
26 static void sp_symbol_init (SPSymbol *symbol);
28 static void sp_symbol_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
29 static void sp_symbol_release (SPObject *object);
30 static void sp_symbol_set (SPObject *object, unsigned int key, const gchar *value);
31 static void sp_symbol_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref);
32 static void sp_symbol_update (SPObject *object, SPCtx *ctx, guint flags);
33 static void sp_symbol_modified (SPObject *object, guint flags);
34 static Inkscape::XML::Node *sp_symbol_write (SPObject *object, Inkscape::XML::Node *repr, guint flags);
36 static NRArenaItem *sp_symbol_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags);
37 static void sp_symbol_hide (SPItem *item, unsigned int key);
38 static void sp_symbol_bbox(SPItem const *item, NRRect *bbox, NR::Matrix const &transform, unsigned const flags);
39 static void sp_symbol_print (SPItem *item, SPPrintContext *ctx);
41 static SPGroupClass *parent_class;
43 GType
44 sp_symbol_get_type (void)
45 {
46         static GType type = 0;
47         if (!type) {
48                 GTypeInfo info = {
49                         sizeof (SPSymbolClass),
50                         NULL, NULL,
51                         (GClassInitFunc) sp_symbol_class_init,
52                         NULL, NULL,
53                         sizeof (SPSymbol),
54                         16,
55                         (GInstanceInitFunc) sp_symbol_init,
56                         NULL,   /* value_table */
57                 };
58                 type = g_type_register_static (SP_TYPE_GROUP, "SPSymbol", &info, (GTypeFlags)0);
59         }
60         return type;
61 }
63 static void
64 sp_symbol_class_init (SPSymbolClass *klass)
65 {
66         GObjectClass *object_class;
67         SPObjectClass *sp_object_class;
68         SPItemClass *sp_item_class;
70         object_class = G_OBJECT_CLASS (klass);
71         sp_object_class = (SPObjectClass *) klass;
72         sp_item_class = (SPItemClass *) klass;
74         parent_class = (SPGroupClass *)g_type_class_ref (SP_TYPE_GROUP);
76         sp_object_class->build = sp_symbol_build;
77         sp_object_class->release = sp_symbol_release;
78         sp_object_class->set = sp_symbol_set;
79         sp_object_class->child_added = sp_symbol_child_added;
80         sp_object_class->update = sp_symbol_update;
81         sp_object_class->modified = sp_symbol_modified;
82         sp_object_class->write = sp_symbol_write;
84         sp_item_class->show = sp_symbol_show;
85         sp_item_class->hide = sp_symbol_hide;
86         sp_item_class->bbox = sp_symbol_bbox;
87         sp_item_class->print = sp_symbol_print;
88 }
90 static void
91 sp_symbol_init (SPSymbol *symbol)
92 {
93         symbol->viewBox_set = FALSE;
95         nr_matrix_set_identity (&symbol->c2p);
96 }
98 static void
99 sp_symbol_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
101         SPGroup *group;
102         SPSymbol *symbol;
104         group = (SPGroup *) object;
105         symbol = (SPSymbol *) object;
107         sp_object_read_attr (object, "viewBox");
108         sp_object_read_attr (object, "preserveAspectRatio");
110         if (((SPObjectClass *) parent_class)->build)
111                 ((SPObjectClass *) parent_class)->build (object, document, repr);
114 static void
115 sp_symbol_release (SPObject *object)
117         SPSymbol * symbol;
119         symbol = (SPSymbol *) object;
121         if (((SPObjectClass *) parent_class)->release)
122                 ((SPObjectClass *) parent_class)->release (object);
125 static void
126 sp_symbol_set (SPObject *object, unsigned int key, const gchar *value)
128         SPItem *item;
129         SPSymbol *symbol;
131         item = SP_ITEM (object);
132         symbol = SP_SYMBOL (object);
134         switch (key) {
135         case SP_ATTR_VIEWBOX:
136                 if (value) {
137                         double x, y, width, height;
138                         char *eptr;
139                         /* fixme: We have to take original item affine into account */
140                         /* fixme: Think (Lauris) */
141                         eptr = (gchar *) value;
142                         x = g_ascii_strtod (eptr, &eptr);
143                         while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++;
144                         y = g_ascii_strtod (eptr, &eptr);
145                         while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++;
146                         width = g_ascii_strtod (eptr, &eptr);
147                         while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++;
148                         height = g_ascii_strtod (eptr, &eptr);
149                         while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++;
150                         if ((width > 0) && (height > 0)) {
151                                 /* Set viewbox */
152                                 symbol->viewBox.x0 = x;
153                                 symbol->viewBox.y0 = y;
154                                 symbol->viewBox.x1 = x + width;
155                                 symbol->viewBox.y1 = y + height;
156                                 symbol->viewBox_set = TRUE;
157                         } else {
158                                 symbol->viewBox_set = FALSE;
159                         }
160                 } else {
161                         symbol->viewBox_set = FALSE;
162                 }
163                 object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
164                 break;
165         case SP_ATTR_PRESERVEASPECTRATIO:
166                 /* Do setup before, so we can use break to escape */
167                 symbol->aspect_set = FALSE;
168                 symbol->aspect_align = SP_ASPECT_NONE;
169                 symbol->aspect_clip = SP_ASPECT_MEET;
170                 object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
171                 if (value) {
172                         int len;
173                         gchar c[256];
174                         const gchar *p, *e;
175                         unsigned int align, clip;
176                         p = value;
177                         while (*p && *p == 32) p += 1;
178                         if (!*p) break;
179                         e = p;
180                         while (*e && *e != 32) e += 1;
181                         len = e - p;
182                         if (len > 8) break;
183                         memcpy (c, value, len);
184                         c[len] = 0;
185                         /* Now the actual part */
186                         if (!strcmp (c, "none")) {
187                                 align = SP_ASPECT_NONE;
188                         } else if (!strcmp (c, "xMinYMin")) {
189                                 align = SP_ASPECT_XMIN_YMIN;
190                         } else if (!strcmp (c, "xMidYMin")) {
191                                 align = SP_ASPECT_XMID_YMIN;
192                         } else if (!strcmp (c, "xMaxYMin")) {
193                                 align = SP_ASPECT_XMAX_YMIN;
194                         } else if (!strcmp (c, "xMinYMid")) {
195                                 align = SP_ASPECT_XMIN_YMID;
196                         } else if (!strcmp (c, "xMidYMid")) {
197                                 align = SP_ASPECT_XMID_YMID;
198                         } else if (!strcmp (c, "xMaxYMin")) {
199                                 align = SP_ASPECT_XMAX_YMID;
200                         } else if (!strcmp (c, "xMinYMax")) {
201                                 align = SP_ASPECT_XMIN_YMAX;
202                         } else if (!strcmp (c, "xMidYMax")) {
203                                 align = SP_ASPECT_XMID_YMAX;
204                         } else if (!strcmp (c, "xMaxYMax")) {
205                                 align = SP_ASPECT_XMAX_YMAX;
206                         } else {
207                                 break;
208                         }
209                         clip = SP_ASPECT_MEET;
210                         while (*e && *e == 32) e += 1;
211                         if (e) {
212                                 if (!strcmp (e, "meet")) {
213                                         clip = SP_ASPECT_MEET;
214                                 } else if (!strcmp (e, "slice")) {
215                                         clip = SP_ASPECT_SLICE;
216                                 } else {
217                                         break;
218                                 }
219                         }
220                         symbol->aspect_set = TRUE;
221                         symbol->aspect_align = align;
222                         symbol->aspect_clip = clip;
223                 }
224                 break;
225         default:
226                 if (((SPObjectClass *) parent_class)->set)
227                         ((SPObjectClass *) parent_class)->set (object, key, value);
228                 break;
229         }
232 static void
233 sp_symbol_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
235         SPSymbol *symbol;
236         SPGroup *group;
238         symbol = (SPSymbol *) object;
239         group = (SPGroup *) object;
241         if (((SPObjectClass *) (parent_class))->child_added)
242                 ((SPObjectClass *) (parent_class))->child_added (object, child, ref);
245 static void
246 sp_symbol_update (SPObject *object, SPCtx *ctx, guint flags)
248         SPItem *item;
249         SPSymbol *symbol;
250         SPItemCtx *ictx, rctx;
251         SPItemView *v;
253         item = SP_ITEM (object);
254         symbol = SP_SYMBOL (object);
255         ictx = (SPItemCtx *) ctx;
257         if (SP_OBJECT_IS_CLONED (object)) {
258                 /* Cloned <symbol> is actually renderable */
260                 /* fixme: We have to set up clip here too */
262                 /* Create copy of item context */
263                 rctx = *ictx;
265                 /* Calculate child to parent transformation */
266                 /* Apply parent <use> translation (set up as vewport) */
267                 nr_matrix_set_translate (&symbol->c2p, rctx.vp.x0, rctx.vp.y0);
269                 if (symbol->viewBox_set) {
270                         double x, y, width, height;
271                         NRMatrix q;
272                         /* Determine actual viewbox in viewport coordinates */
273                         if (symbol->aspect_align == SP_ASPECT_NONE) {
274                                 x = 0.0;
275                                 y = 0.0;
276                                 width = rctx.vp.x1 - rctx.vp.x0;
277                                 height = rctx.vp.y1 - rctx.vp.y0;
278                         } else {
279                                 double scalex, scaley, scale;
280                                 /* Things are getting interesting */
281                                 scalex = (rctx.vp.x1 - rctx.vp.x0) / (symbol->viewBox.x1 - symbol->viewBox.x0);
282                                 scaley = (rctx.vp.y1 - rctx.vp.y0) / (symbol->viewBox.y1 - symbol->viewBox.y0);
283                                 scale = (symbol->aspect_clip == SP_ASPECT_MEET) ? MIN (scalex, scaley) : MAX (scalex, scaley);
284                                 width = (symbol->viewBox.x1 - symbol->viewBox.x0) * scale;
285                                 height = (symbol->viewBox.y1 - symbol->viewBox.y0) * scale;
286                                 /* Now place viewbox to requested position */
287                                 switch (symbol->aspect_align) {
288                                 case SP_ASPECT_XMIN_YMIN:
289                                         x = 0.0;
290                                         y = 0.0;
291                                         break;
292                                 case SP_ASPECT_XMID_YMIN:
293                                         x = 0.5 * ((rctx.vp.x1 - rctx.vp.x0) - width);
294                                         y = 0.0;
295                                         break;
296                                 case SP_ASPECT_XMAX_YMIN:
297                                         x = 1.0 * ((rctx.vp.x1 - rctx.vp.x0) - width);
298                                         y = 0.0;
299                                         break;
300                                 case SP_ASPECT_XMIN_YMID:
301                                         x = 0.0;
302                                         y = 0.5 * ((rctx.vp.y1 - rctx.vp.y0) - height);
303                                         break;
304                                 case SP_ASPECT_XMID_YMID:
305                                         x = 0.5 * ((rctx.vp.x1 - rctx.vp.x0) - width);
306                                         y = 0.5 * ((rctx.vp.y1 - rctx.vp.y0) - height);
307                                         break;
308                                 case SP_ASPECT_XMAX_YMID:
309                                         x = 1.0 * ((rctx.vp.x1 - rctx.vp.x0) - width);
310                                         y = 0.5 * ((rctx.vp.y1 - rctx.vp.y0) - height);
311                                         break;
312                                 case SP_ASPECT_XMIN_YMAX:
313                                         x = 0.0;
314                                         y = 1.0 * ((rctx.vp.y1 - rctx.vp.y0) - height);
315                                         break;
316                                 case SP_ASPECT_XMID_YMAX:
317                                         x = 0.5 * ((rctx.vp.x1 - rctx.vp.x0) - width);
318                                         y = 1.0 * ((rctx.vp.y1 - rctx.vp.y0) - height);
319                                         break;
320                                 case SP_ASPECT_XMAX_YMAX:
321                                         x = 1.0 * ((rctx.vp.x1 - rctx.vp.x0) - width);
322                                         y = 1.0 * ((rctx.vp.y1 - rctx.vp.y0) - height);
323                                         break;
324                                 default:
325                                         x = 0.0;
326                                         y = 0.0;
327                                         break;
328                                 }
329                         }
330                         /* Compose additional transformation from scale and position */
331                         q.c[0] = width / (symbol->viewBox.x1 - symbol->viewBox.x0);
332                         q.c[1] = 0.0;
333                         q.c[2] = 0.0;
334                         q.c[3] = height / (symbol->viewBox.y1 - symbol->viewBox.y0);
335                         q.c[4] = -symbol->viewBox.x0 * q.c[0] + x;
336                         q.c[5] = -symbol->viewBox.y0 * q.c[3] + y;
337                         /* Append viewbox transformation */
338                         nr_matrix_multiply (&symbol->c2p, &q, &symbol->c2p);
339                 }
341                 rctx.i2doc = symbol->c2p * rctx.i2doc;
343                 /* If viewBox is set initialize child viewport */
344                 /* Otherwise <use> has set it up already */
345                 if (symbol->viewBox_set) {
346                         rctx.vp.x0 = symbol->viewBox.x0;
347                         rctx.vp.y0 = symbol->viewBox.y0;
348                         rctx.vp.x1 = symbol->viewBox.x1;
349                         rctx.vp.y1 = symbol->viewBox.y1;
350                         rctx.i2vp = NR::identity();
351                 }
353                 /* And invoke parent method */
354                 if (((SPObjectClass *) (parent_class))->update)
355                         ((SPObjectClass *) (parent_class))->update (object, (SPCtx *) &rctx, flags);
357                 /* As last step set additional transform of arena group */
358                 for (v = item->display; v != NULL; v = v->next) {
359                         nr_arena_group_set_child_transform(NR_ARENA_GROUP(v->arenaitem), &symbol->c2p);
360                 }
361         } else {
362                 /* No-op */
363                 if (((SPObjectClass *) (parent_class))->update)
364                         ((SPObjectClass *) (parent_class))->update (object, ctx, flags);
365         }
368 static void
369 sp_symbol_modified (SPObject *object, guint flags)
371         SPSymbol *symbol;
373         symbol = SP_SYMBOL (object);
375         if (((SPObjectClass *) (parent_class))->modified)
376                 (* ((SPObjectClass *) (parent_class))->modified) (object, flags);
379 static Inkscape::XML::Node *
380 sp_symbol_write (SPObject *object, Inkscape::XML::Node *repr, guint flags)
382         SPSymbol *symbol;
384         symbol = SP_SYMBOL (object);
386         if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
387                 Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(object));
388                 repr = xml_doc->createElement("svg:symbol");
389         }
391         repr->setAttribute("viewBox", object->repr->attribute("viewBox"));
392         repr->setAttribute("preserveAspectRatio", object->repr->attribute("preserveAspectRatio"));
394         if (((SPObjectClass *) (parent_class))->write)
395                 ((SPObjectClass *) (parent_class))->write (object, repr, flags);
397         return repr;
400 static NRArenaItem *
401 sp_symbol_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags)
403         SPSymbol *symbol;
404         NRArenaItem *ai;
406         symbol = SP_SYMBOL (item);
408         if (SP_OBJECT_IS_CLONED (symbol)) {
409                 /* Cloned <symbol> is actually renderable */
410                 if (((SPItemClass *) (parent_class))->show) {
411                         ai = ((SPItemClass *) (parent_class))->show (item, arena, key, flags);
412                         if (ai) {
413                                 nr_arena_group_set_child_transform(NR_ARENA_GROUP(ai), &symbol->c2p);
414                         }
415                 } else {
416                         ai = NULL;
417                 }
418         } else {
419                 ai = NULL;
420         }
422         return ai;
425 static void
426 sp_symbol_hide (SPItem *item, unsigned int key)
428         SPSymbol *symbol;
430         symbol = SP_SYMBOL (item);
432         if (SP_OBJECT_IS_CLONED (symbol)) {
433                 /* Cloned <symbol> is actually renderable */
434                 if (((SPItemClass *) (parent_class))->hide)
435                         ((SPItemClass *) (parent_class))->hide (item, key);
436         }
439 static void
440 sp_symbol_bbox(SPItem const *item, NRRect *bbox, NR::Matrix const &transform, unsigned const flags)
442         SPSymbol const *symbol = SP_SYMBOL(item);
444         if (SP_OBJECT_IS_CLONED (symbol)) {
445                 /* Cloned <symbol> is actually renderable */
447                 if (((SPItemClass *) (parent_class))->bbox) {
448                         NR::Matrix const a( symbol->c2p * transform );
449                         ((SPItemClass *) (parent_class))->bbox(item, bbox, a, flags);
450                 }
451         }
454 static void
455 sp_symbol_print (SPItem *item, SPPrintContext *ctx)
457         SPSymbol *symbol = SP_SYMBOL(item);
458         if (SP_OBJECT_IS_CLONED (symbol)) {
459                 /* Cloned <symbol> is actually renderable */
461                 sp_print_bind(ctx, &symbol->c2p, 1.0);
463                 if (((SPItemClass *) (parent_class))->print) {
464                         ((SPItemClass *) (parent_class))->print (item, ctx);
465                 }
467                 sp_print_release (ctx);
468         }