1 #define __SP_FLOWREGION_C__
3 /*
4 */
6 #ifdef HAVE_CONFIG_H
7 # include "config.h"
8 #endif
9 #include <glibmm/i18n.h>
11 #include <xml/repr.h>
12 #include "display/curve.h"
13 #include "sp-shape.h"
14 #include "sp-text.h"
15 #include "sp-use.h"
16 #include "style.h"
18 #include "sp-flowregion.h"
20 #include "display/canvas-bpath.h"
23 #include "livarot/Path.h"
24 #include "livarot/Shape.h"
26 static void sp_flowregion_class_init (SPFlowregionClass *klass);
27 static void sp_flowregion_init (SPFlowregion *group);
28 static void sp_flowregion_dispose (GObject *object);
30 static void sp_flowregion_child_added (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * ref);
31 static void sp_flowregion_remove_child (SPObject * object, Inkscape::XML::Node * child);
32 static void sp_flowregion_update (SPObject *object, SPCtx *ctx, guint flags);
33 static void sp_flowregion_modified (SPObject *object, guint flags);
34 static Inkscape::XML::Node *sp_flowregion_write (SPObject *object, Inkscape::XML::Node *repr, guint flags);
36 static gchar * sp_flowregion_description (SPItem * item);
38 static SPItemClass * flowregion_parent_class;
40 static void sp_flowregionexclude_class_init (SPFlowregionExcludeClass *klass);
41 static void sp_flowregionexclude_init (SPFlowregionExclude *group);
42 static void sp_flowregionexclude_dispose (GObject *object);
44 static void sp_flowregionexclude_child_added (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * ref);
45 static void sp_flowregionexclude_remove_child (SPObject * object, Inkscape::XML::Node * child);
46 static void sp_flowregionexclude_update (SPObject *object, SPCtx *ctx, guint flags);
47 static void sp_flowregionexclude_modified (SPObject *object, guint flags);
48 static Inkscape::XML::Node *sp_flowregionexclude_write (SPObject *object, Inkscape::XML::Node *repr, guint flags);
50 static gchar * sp_flowregionexclude_description (SPItem * item);
52 static SPItemClass * flowregionexclude_parent_class;
55 static void GetDest(SPObject* child,Shape **computed,NR::Matrix itr_mat);
57 GType
58 sp_flowregion_get_type (void)
59 {
60 static GType group_type = 0;
61 if (!group_type) {
62 GTypeInfo group_info = {
63 sizeof (SPFlowregionClass),
64 NULL, /* base_init */
65 NULL, /* base_finalize */
66 (GClassInitFunc) sp_flowregion_class_init,
67 NULL, /* class_finalize */
68 NULL, /* class_data */
69 sizeof (SPFlowregion),
70 16, /* n_preallocs */
71 (GInstanceInitFunc) sp_flowregion_init,
72 NULL, /* value_table */
73 };
74 group_type = g_type_register_static (SP_TYPE_ITEM, "SPFlowregion", &group_info, (GTypeFlags)0);
75 }
76 return group_type;
77 }
79 static void
80 sp_flowregion_class_init (SPFlowregionClass *klass)
81 {
82 GObjectClass * object_class;
83 SPObjectClass * sp_object_class;
84 SPItemClass * item_class;
86 object_class = (GObjectClass *) klass;
87 sp_object_class = (SPObjectClass *) klass;
88 item_class = (SPItemClass *) klass;
90 flowregion_parent_class = (SPItemClass *)g_type_class_ref (SP_TYPE_ITEM);
92 object_class->dispose = sp_flowregion_dispose;
94 sp_object_class->child_added = sp_flowregion_child_added;
95 sp_object_class->remove_child = sp_flowregion_remove_child;
96 sp_object_class->update = sp_flowregion_update;
97 sp_object_class->modified = sp_flowregion_modified;
98 sp_object_class->write = sp_flowregion_write;
100 item_class->description = sp_flowregion_description;
101 }
103 static void
104 sp_flowregion_init (SPFlowregion *group)
105 {
106 new (&group->computed) std::vector<Shape*>;
107 }
109 static void
110 sp_flowregion_dispose(GObject *object)
111 {
112 SPFlowregion *group=(SPFlowregion *)object;
113 for (std::vector<Shape*>::iterator it = group->computed.begin() ; it != group->computed.end() ; it++)
114 delete *it;
115 group->computed.~vector<Shape*>();
116 }
118 static void
119 sp_flowregion_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
120 {
121 SPItem *item;
123 item = SP_ITEM (object);
125 if (((SPObjectClass *) (flowregion_parent_class))->child_added)
126 (* ((SPObjectClass *) (flowregion_parent_class))->child_added) (object, child, ref);
128 object->requestModified(SP_OBJECT_MODIFIED_FLAG);
129 }
131 /* fixme: hide (Lauris) */
133 static void
134 sp_flowregion_remove_child (SPObject * object, Inkscape::XML::Node * child)
135 {
136 if (((SPObjectClass *) (flowregion_parent_class))->remove_child)
137 (* ((SPObjectClass *) (flowregion_parent_class))->remove_child) (object, child);
139 object->requestModified(SP_OBJECT_MODIFIED_FLAG);
140 }
143 static void
144 sp_flowregion_update (SPObject *object, SPCtx *ctx, unsigned int flags)
145 {
146 SPFlowregion *group;
147 SPObject *child;
148 SPItemCtx *ictx, cctx;
149 GSList *l;
151 group = SP_FLOWREGION (object);
152 ictx = (SPItemCtx *) ctx;
153 cctx = *ictx;
155 if (((SPObjectClass *) (flowregion_parent_class))->update)
156 ((SPObjectClass *) (flowregion_parent_class))->update (object, ctx, flags);
158 if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
159 flags &= SP_OBJECT_MODIFIED_CASCADE;
161 l = NULL;
162 for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
163 g_object_ref (G_OBJECT (child));
164 l = g_slist_prepend (l, child);
165 }
166 l = g_slist_reverse (l);
167 while (l) {
168 child = SP_OBJECT (l->data);
169 l = g_slist_remove (l, child);
170 if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
171 if (SP_IS_ITEM (child)) {
172 SPItem const &chi = *SP_ITEM(child);
173 cctx.i2doc = chi.transform * ictx->i2doc;
174 cctx.i2vp = chi.transform * ictx->i2vp;
175 child->updateDisplay((SPCtx *)&cctx, flags);
176 } else {
177 child->updateDisplay(ctx, flags);
178 }
179 }
180 g_object_unref (G_OBJECT (child));
181 }
183 group->UpdateComputed();
184 }
186 void SPFlowregion::UpdateComputed(void)
187 {
188 SPObject* object=SP_OBJECT(this);
190 NR::Matrix itr_mat=sp_item_i2root_affine (SP_ITEM(object));
191 itr_mat=itr_mat.inverse();
193 for (std::vector<Shape*>::iterator it = computed.begin() ; it != computed.end() ; it++)
194 delete *it;
195 computed.clear();
197 for (SPObject* child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
198 Shape *shape = NULL;
199 GetDest(child,&shape,itr_mat);
200 computed.push_back(shape);
201 }
202 }
204 static void
205 sp_flowregion_modified (SPObject *object, guint flags)
206 {
207 SPFlowregion *group;
208 SPObject *child;
209 GSList *l;
211 group = SP_FLOWREGION (object);
213 if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
214 flags &= SP_OBJECT_MODIFIED_CASCADE;
216 l = NULL;
217 for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
218 g_object_ref (G_OBJECT (child));
219 l = g_slist_prepend (l, child);
220 }
221 l = g_slist_reverse (l);
222 while (l) {
223 child = SP_OBJECT (l->data);
224 l = g_slist_remove (l, child);
225 if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
226 child->emitModified(flags);
227 }
228 g_object_unref (G_OBJECT (child));
229 }
230 }
232 static Inkscape::XML::Node *
233 sp_flowregion_write (SPObject *object, Inkscape::XML::Node *repr, guint flags)
234 {
235 if (flags & SP_OBJECT_WRITE_BUILD) {
236 if ( repr == NULL ) repr = sp_repr_new ("svg:flowRegion");
238 GSList *l = NULL;
239 for ( SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
240 Inkscape::XML::Node *crepr = child->updateRepr(NULL, flags);
241 if (crepr) l = g_slist_prepend(l, crepr);
242 }
244 while (l) {
245 repr->addChild((Inkscape::XML::Node *) l->data, NULL);
246 Inkscape::GC::release((Inkscape::XML::Node *) l->data);
247 l = g_slist_remove(l, l->data);
248 }
250 } else {
251 for ( SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
252 child->updateRepr(flags);
253 }
254 }
256 if (((SPObjectClass *) (flowregion_parent_class))->write)
257 ((SPObjectClass *) (flowregion_parent_class))->write (object, repr, flags);
259 return repr;
260 }
263 static gchar *sp_flowregion_description(SPItem *item)
264 {
265 // TRANSLATORS: "Flow region" is an area where text is allowed to flow
266 return g_strdup_printf(_("Flow region"));
267 }
269 /*
270 *
271 */
273 GType
274 sp_flowregionexclude_get_type (void)
275 {
276 static GType group_type = 0;
277 if (!group_type) {
278 GTypeInfo group_info = {
279 sizeof (SPFlowregionExcludeClass),
280 NULL, /* base_init */
281 NULL, /* base_finalize */
282 (GClassInitFunc) sp_flowregionexclude_class_init,
283 NULL, /* class_finalize */
284 NULL, /* class_data */
285 sizeof (SPFlowregionExclude),
286 16, /* n_preallocs */
287 (GInstanceInitFunc) sp_flowregionexclude_init,
288 NULL, /* value_table */
289 };
290 group_type = g_type_register_static (SP_TYPE_ITEM, "SPFlowregionExclude", &group_info, (GTypeFlags)0);
291 }
292 return group_type;
293 }
295 static void
296 sp_flowregionexclude_class_init (SPFlowregionExcludeClass *klass)
297 {
298 GObjectClass * object_class;
299 SPObjectClass * sp_object_class;
300 SPItemClass * item_class;
302 object_class = (GObjectClass *) klass;
303 sp_object_class = (SPObjectClass *) klass;
304 item_class = (SPItemClass *) klass;
306 flowregionexclude_parent_class = (SPItemClass *)g_type_class_ref (SP_TYPE_ITEM);
308 object_class->dispose = sp_flowregionexclude_dispose;
310 sp_object_class->child_added = sp_flowregionexclude_child_added;
311 sp_object_class->remove_child = sp_flowregionexclude_remove_child;
312 sp_object_class->update = sp_flowregionexclude_update;
313 sp_object_class->modified = sp_flowregionexclude_modified;
314 sp_object_class->write = sp_flowregionexclude_write;
316 item_class->description = sp_flowregionexclude_description;
317 }
319 static void
320 sp_flowregionexclude_init (SPFlowregionExclude *group)
321 {
322 group->computed = NULL;
323 }
325 static void
326 sp_flowregionexclude_dispose(GObject *object)
327 {
328 SPFlowregionExclude *group=(SPFlowregionExclude *)object;
329 if (group->computed) {
330 delete group->computed;
331 group->computed = NULL;
332 }
333 }
335 static void
336 sp_flowregionexclude_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
337 {
338 SPItem *item;
340 item = SP_ITEM (object);
342 if (((SPObjectClass *) (flowregionexclude_parent_class))->child_added)
343 (* ((SPObjectClass *) (flowregionexclude_parent_class))->child_added) (object, child, ref);
345 object->requestModified(SP_OBJECT_MODIFIED_FLAG);
346 }
348 /* fixme: hide (Lauris) */
350 static void
351 sp_flowregionexclude_remove_child (SPObject * object, Inkscape::XML::Node * child)
352 {
353 if (((SPObjectClass *) (flowregionexclude_parent_class))->remove_child)
354 (* ((SPObjectClass *) (flowregionexclude_parent_class))->remove_child) (object, child);
356 object->requestModified(SP_OBJECT_MODIFIED_FLAG);
357 }
360 static void
361 sp_flowregionexclude_update (SPObject *object, SPCtx *ctx, unsigned int flags)
362 {
363 SPFlowregionExclude *group;
364 SPObject *child;
365 SPItemCtx *ictx, cctx;
366 GSList *l;
368 group = SP_FLOWREGIONEXCLUDE (object);
369 ictx = (SPItemCtx *) ctx;
370 cctx = *ictx;
372 if (((SPObjectClass *) (flowregionexclude_parent_class))->update)
373 ((SPObjectClass *) (flowregionexclude_parent_class))->update (object, ctx, flags);
375 if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
376 flags &= SP_OBJECT_MODIFIED_CASCADE;
378 l = NULL;
379 for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
380 g_object_ref (G_OBJECT (child));
381 l = g_slist_prepend (l, child);
382 }
383 l = g_slist_reverse (l);
384 while (l) {
385 child = SP_OBJECT (l->data);
386 l = g_slist_remove (l, child);
387 if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
388 if (SP_IS_ITEM (child)) {
389 SPItem const &chi = *SP_ITEM(child);
390 cctx.i2doc = chi.transform * ictx->i2doc;
391 cctx.i2vp = chi.transform * ictx->i2vp;
392 child->updateDisplay((SPCtx *)&cctx, flags);
393 } else {
394 child->updateDisplay(ctx, flags);
395 }
396 }
397 g_object_unref (G_OBJECT (child));
398 }
400 group->UpdateComputed();
401 }
402 void SPFlowregionExclude::UpdateComputed(void)
403 {
404 SPObject* object=SP_OBJECT(this);
406 if (computed) {
407 delete computed;
408 computed = NULL;
409 }
410 NR::Matrix itr_mat=sp_item_i2root_affine (SP_ITEM(object));
411 itr_mat=itr_mat.inverse();
413 for (SPObject* child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
414 GetDest(child,&computed,itr_mat);
415 }
416 }
418 static void
419 sp_flowregionexclude_modified (SPObject *object, guint flags)
420 {
421 SPFlowregionExclude *group;
422 SPObject *child;
423 GSList *l;
425 group = SP_FLOWREGIONEXCLUDE (object);
427 if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
428 flags &= SP_OBJECT_MODIFIED_CASCADE;
430 l = NULL;
431 for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
432 g_object_ref (G_OBJECT (child));
433 l = g_slist_prepend (l, child);
434 }
435 l = g_slist_reverse (l);
436 while (l) {
437 child = SP_OBJECT (l->data);
438 l = g_slist_remove (l, child);
439 if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
440 child->emitModified(flags);
441 }
442 g_object_unref (G_OBJECT (child));
443 }
444 }
446 static Inkscape::XML::Node *
447 sp_flowregionexclude_write (SPObject *object, Inkscape::XML::Node *repr, guint flags)
448 {
449 if (flags & SP_OBJECT_WRITE_BUILD) {
450 if ( repr == NULL ) repr = sp_repr_new ("svg:flowRegionExclude");
452 GSList *l = NULL;
453 for ( SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
454 Inkscape::XML::Node *crepr = child->updateRepr(NULL, flags);
455 if (crepr) l = g_slist_prepend(l, crepr);
456 }
458 while (l) {
459 repr->addChild((Inkscape::XML::Node *) l->data, NULL);
460 Inkscape::GC::release((Inkscape::XML::Node *) l->data);
461 l = g_slist_remove(l, l->data);
462 }
464 } else {
465 for ( SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
466 child->updateRepr(flags);
467 }
468 }
470 if (((SPObjectClass *) (flowregionexclude_parent_class))->write)
471 ((SPObjectClass *) (flowregionexclude_parent_class))->write (object, repr, flags);
473 return repr;
474 }
477 static gchar *sp_flowregionexclude_description(SPItem *item)
478 {
479 /* TRANSLATORS: A region "cut out of" a flow region; text is not allowed to flow inside the
480 * flow excluded region. flowRegionExclude in SVG 1.2: see
481 * http://www.w3.org/TR/2004/WD-SVG12-20041027/flow.html#flowRegion-elem and
482 * http://www.w3.org/TR/2004/WD-SVG12-20041027/flow.html#flowRegionExclude-elem. */
483 return g_strdup_printf(_("Flow excluded region"));
484 }
486 /*
487 *
488 */
490 static void UnionShape(Shape **base_shape, Shape const *add_shape)
491 {
492 if (*base_shape == NULL)
493 *base_shape = new Shape;
494 if ( (*base_shape)->hasEdges() == false ) {
495 (*base_shape)->Copy(const_cast<Shape*>(add_shape));
496 } else if ( add_shape->hasEdges() ) {
497 Shape* temp=new Shape;
498 temp->Booleen(const_cast<Shape*>(add_shape), *base_shape, bool_op_union);
499 delete *base_shape;
500 *base_shape = temp;
501 }
502 }
504 static void GetDest(SPObject* child,Shape **computed,NR::Matrix itr_mat)
505 {
506 if ( child == NULL ) return;
508 SPCurve *curve=NULL;
510 SPObject* u_child=child;
511 if ( SP_IS_USE(u_child) ) {
512 u_child=SP_USE(u_child)->child;
513 }
514 if ( SP_IS_SHAPE (u_child) ) {
515 curve = sp_shape_get_curve (SP_SHAPE (u_child));
516 } else if ( SP_IS_TEXT (u_child) ) {
517 curve = SP_TEXT (u_child)->getNormalizedBpath ();
518 }
520 if ( curve ) {
521 Path* temp=new Path;
522 NR::Matrix tr_mat=sp_item_i2root_affine (SP_ITEM(u_child));
523 tr_mat=itr_mat*tr_mat;
524 temp->LoadArtBPath(SP_CURVE_BPATH(curve),tr_mat,true);
525 Shape* n_shp=new Shape;
526 temp->Convert(0.25);
527 temp->Fill(n_shp,0);
528 Shape* uncross=new Shape;
529 SPStyle* style=SP_OBJECT_STYLE(u_child);
530 if ( style && style->fill_rule.computed == SP_WIND_RULE_EVENODD ) {
531 uncross->ConvertToShape(n_shp,fill_oddEven);
532 } else {
533 uncross->ConvertToShape(n_shp,fill_nonZero);
534 }
535 UnionShape(computed, uncross);
536 delete uncross;
537 delete n_shp;
538 delete temp;
539 sp_curve_unref(curve);
540 } else {
541 // printf("no curve\n");
542 }
543 }