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"
17 #include "document.h"
19 #include "sp-flowregion.h"
21 #include "display/canvas-bpath.h"
24 #include "livarot/Path.h"
25 #include "livarot/Shape.h"
27 static void sp_flowregion_class_init (SPFlowregionClass *klass);
28 static void sp_flowregion_init (SPFlowregion *group);
29 static void sp_flowregion_dispose (GObject *object);
31 static void sp_flowregion_child_added (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * ref);
32 static void sp_flowregion_remove_child (SPObject * object, Inkscape::XML::Node * child);
33 static void sp_flowregion_update (SPObject *object, SPCtx *ctx, guint flags);
34 static void sp_flowregion_modified (SPObject *object, guint flags);
35 static Inkscape::XML::Node *sp_flowregion_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
37 static gchar * sp_flowregion_description (SPItem * item);
39 static SPItemClass * flowregion_parent_class;
41 static void sp_flowregionexclude_class_init (SPFlowregionExcludeClass *klass);
42 static void sp_flowregionexclude_init (SPFlowregionExclude *group);
43 static void sp_flowregionexclude_dispose (GObject *object);
45 static void sp_flowregionexclude_child_added (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * ref);
46 static void sp_flowregionexclude_remove_child (SPObject * object, Inkscape::XML::Node * child);
47 static void sp_flowregionexclude_update (SPObject *object, SPCtx *ctx, guint flags);
48 static void sp_flowregionexclude_modified (SPObject *object, guint flags);
49 static Inkscape::XML::Node *sp_flowregionexclude_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
51 static gchar * sp_flowregionexclude_description (SPItem * item);
53 static SPItemClass * flowregionexclude_parent_class;
56 static void GetDest(SPObject* child,Shape **computed,NR::Matrix itr_mat);
58 GType
59 sp_flowregion_get_type (void)
60 {
61 static GType group_type = 0;
62 if (!group_type) {
63 GTypeInfo group_info = {
64 sizeof (SPFlowregionClass),
65 NULL, /* base_init */
66 NULL, /* base_finalize */
67 (GClassInitFunc) sp_flowregion_class_init,
68 NULL, /* class_finalize */
69 NULL, /* class_data */
70 sizeof (SPFlowregion),
71 16, /* n_preallocs */
72 (GInstanceInitFunc) sp_flowregion_init,
73 NULL, /* value_table */
74 };
75 group_type = g_type_register_static (SP_TYPE_ITEM, "SPFlowregion", &group_info, (GTypeFlags)0);
76 }
77 return group_type;
78 }
80 static void
81 sp_flowregion_class_init (SPFlowregionClass *klass)
82 {
83 GObjectClass * object_class;
84 SPObjectClass * sp_object_class;
85 SPItemClass * item_class;
87 object_class = (GObjectClass *) klass;
88 sp_object_class = (SPObjectClass *) klass;
89 item_class = (SPItemClass *) klass;
91 flowregion_parent_class = (SPItemClass *)g_type_class_ref (SP_TYPE_ITEM);
93 object_class->dispose = sp_flowregion_dispose;
95 sp_object_class->child_added = sp_flowregion_child_added;
96 sp_object_class->remove_child = sp_flowregion_remove_child;
97 sp_object_class->update = sp_flowregion_update;
98 sp_object_class->modified = sp_flowregion_modified;
99 sp_object_class->write = sp_flowregion_write;
101 item_class->description = sp_flowregion_description;
102 }
104 static void
105 sp_flowregion_init (SPFlowregion *group)
106 {
107 new (&group->computed) std::vector<Shape*>;
108 }
110 static void
111 sp_flowregion_dispose(GObject *object)
112 {
113 SPFlowregion *group=(SPFlowregion *)object;
114 for (std::vector<Shape*>::iterator it = group->computed.begin() ; it != group->computed.end() ; it++)
115 delete *it;
116 group->computed.~vector<Shape*>();
117 }
119 static void
120 sp_flowregion_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
121 {
122 SPItem *item;
124 item = SP_ITEM (object);
126 if (((SPObjectClass *) (flowregion_parent_class))->child_added)
127 (* ((SPObjectClass *) (flowregion_parent_class))->child_added) (object, child, ref);
129 object->requestModified(SP_OBJECT_MODIFIED_FLAG);
130 }
132 /* fixme: hide (Lauris) */
134 static void
135 sp_flowregion_remove_child (SPObject * object, Inkscape::XML::Node * child)
136 {
137 if (((SPObjectClass *) (flowregion_parent_class))->remove_child)
138 (* ((SPObjectClass *) (flowregion_parent_class))->remove_child) (object, child);
140 object->requestModified(SP_OBJECT_MODIFIED_FLAG);
141 }
144 static void
145 sp_flowregion_update (SPObject *object, SPCtx *ctx, unsigned int flags)
146 {
147 SPFlowregion *group;
148 SPObject *child;
149 SPItemCtx *ictx, cctx;
150 GSList *l;
152 group = SP_FLOWREGION (object);
153 ictx = (SPItemCtx *) ctx;
154 cctx = *ictx;
156 if (((SPObjectClass *) (flowregion_parent_class))->update)
157 ((SPObjectClass *) (flowregion_parent_class))->update (object, ctx, flags);
159 if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
160 flags &= SP_OBJECT_MODIFIED_CASCADE;
162 l = NULL;
163 for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
164 g_object_ref (G_OBJECT (child));
165 l = g_slist_prepend (l, child);
166 }
167 l = g_slist_reverse (l);
168 while (l) {
169 child = SP_OBJECT (l->data);
170 l = g_slist_remove (l, child);
171 if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
172 if (SP_IS_ITEM (child)) {
173 SPItem const &chi = *SP_ITEM(child);
174 cctx.i2doc = chi.transform * ictx->i2doc;
175 cctx.i2vp = chi.transform * ictx->i2vp;
176 child->updateDisplay((SPCtx *)&cctx, flags);
177 } else {
178 child->updateDisplay(ctx, flags);
179 }
180 }
181 g_object_unref (G_OBJECT (child));
182 }
184 group->UpdateComputed();
185 }
187 void SPFlowregion::UpdateComputed(void)
188 {
189 SPObject* object=SP_OBJECT(this);
191 NR::Matrix itr_mat = from_2geom(sp_item_i2root_affine (SP_ITEM(object)));
192 itr_mat = itr_mat.inverse();
194 for (std::vector<Shape*>::iterator it = computed.begin() ; it != computed.end() ; it++)
195 delete *it;
196 computed.clear();
198 for (SPObject* child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
199 Shape *shape = NULL;
200 GetDest(child,&shape,itr_mat);
201 computed.push_back(shape);
202 }
203 }
205 static void
206 sp_flowregion_modified (SPObject *object, guint flags)
207 {
208 SPFlowregion *group;
209 SPObject *child;
210 GSList *l;
212 group = SP_FLOWREGION (object);
214 if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
215 flags &= SP_OBJECT_MODIFIED_CASCADE;
217 l = NULL;
218 for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
219 g_object_ref (G_OBJECT (child));
220 l = g_slist_prepend (l, child);
221 }
222 l = g_slist_reverse (l);
223 while (l) {
224 child = SP_OBJECT (l->data);
225 l = g_slist_remove (l, child);
226 if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
227 child->emitModified(flags);
228 }
229 g_object_unref (G_OBJECT (child));
230 }
231 }
233 static Inkscape::XML::Node *
234 sp_flowregion_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
235 {
236 if (flags & SP_OBJECT_WRITE_BUILD) {
237 if ( repr == NULL ) {
238 repr = xml_doc->createElement("svg:flowRegion");
239 }
241 GSList *l = NULL;
242 for ( SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
243 Inkscape::XML::Node *crepr = child->updateRepr(xml_doc, NULL, flags);
244 if (crepr) l = g_slist_prepend(l, crepr);
245 }
247 while (l) {
248 repr->addChild((Inkscape::XML::Node *) l->data, NULL);
249 Inkscape::GC::release((Inkscape::XML::Node *) l->data);
250 l = g_slist_remove(l, l->data);
251 }
253 } else {
254 for ( SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
255 child->updateRepr(flags);
256 }
257 }
259 if (((SPObjectClass *) (flowregion_parent_class))->write)
260 ((SPObjectClass *) (flowregion_parent_class))->write (object, xml_doc, repr, flags);
262 return repr;
263 }
266 static gchar *sp_flowregion_description(SPItem */*item*/)
267 {
268 // TRANSLATORS: "Flow region" is an area where text is allowed to flow
269 return g_strdup_printf(_("Flow region"));
270 }
272 /*
273 *
274 */
276 GType
277 sp_flowregionexclude_get_type (void)
278 {
279 static GType group_type = 0;
280 if (!group_type) {
281 GTypeInfo group_info = {
282 sizeof (SPFlowregionExcludeClass),
283 NULL, /* base_init */
284 NULL, /* base_finalize */
285 (GClassInitFunc) sp_flowregionexclude_class_init,
286 NULL, /* class_finalize */
287 NULL, /* class_data */
288 sizeof (SPFlowregionExclude),
289 16, /* n_preallocs */
290 (GInstanceInitFunc) sp_flowregionexclude_init,
291 NULL, /* value_table */
292 };
293 group_type = g_type_register_static (SP_TYPE_ITEM, "SPFlowregionExclude", &group_info, (GTypeFlags)0);
294 }
295 return group_type;
296 }
298 static void
299 sp_flowregionexclude_class_init (SPFlowregionExcludeClass *klass)
300 {
301 GObjectClass * object_class;
302 SPObjectClass * sp_object_class;
303 SPItemClass * item_class;
305 object_class = (GObjectClass *) klass;
306 sp_object_class = (SPObjectClass *) klass;
307 item_class = (SPItemClass *) klass;
309 flowregionexclude_parent_class = (SPItemClass *)g_type_class_ref (SP_TYPE_ITEM);
311 object_class->dispose = sp_flowregionexclude_dispose;
313 sp_object_class->child_added = sp_flowregionexclude_child_added;
314 sp_object_class->remove_child = sp_flowregionexclude_remove_child;
315 sp_object_class->update = sp_flowregionexclude_update;
316 sp_object_class->modified = sp_flowregionexclude_modified;
317 sp_object_class->write = sp_flowregionexclude_write;
319 item_class->description = sp_flowregionexclude_description;
320 }
322 static void
323 sp_flowregionexclude_init (SPFlowregionExclude *group)
324 {
325 group->computed = NULL;
326 }
328 static void
329 sp_flowregionexclude_dispose(GObject *object)
330 {
331 SPFlowregionExclude *group=(SPFlowregionExclude *)object;
332 if (group->computed) {
333 delete group->computed;
334 group->computed = NULL;
335 }
336 }
338 static void
339 sp_flowregionexclude_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
340 {
341 SPItem *item;
343 item = SP_ITEM (object);
345 if (((SPObjectClass *) (flowregionexclude_parent_class))->child_added)
346 (* ((SPObjectClass *) (flowregionexclude_parent_class))->child_added) (object, child, ref);
348 object->requestModified(SP_OBJECT_MODIFIED_FLAG);
349 }
351 /* fixme: hide (Lauris) */
353 static void
354 sp_flowregionexclude_remove_child (SPObject * object, Inkscape::XML::Node * child)
355 {
356 if (((SPObjectClass *) (flowregionexclude_parent_class))->remove_child)
357 (* ((SPObjectClass *) (flowregionexclude_parent_class))->remove_child) (object, child);
359 object->requestModified(SP_OBJECT_MODIFIED_FLAG);
360 }
363 static void
364 sp_flowregionexclude_update (SPObject *object, SPCtx *ctx, unsigned int flags)
365 {
366 SPFlowregionExclude *group;
367 SPObject *child;
368 SPItemCtx *ictx, cctx;
369 GSList *l;
371 group = SP_FLOWREGIONEXCLUDE (object);
372 ictx = (SPItemCtx *) ctx;
373 cctx = *ictx;
375 if (((SPObjectClass *) (flowregionexclude_parent_class))->update)
376 ((SPObjectClass *) (flowregionexclude_parent_class))->update (object, ctx, flags);
378 if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
379 flags &= SP_OBJECT_MODIFIED_CASCADE;
381 l = NULL;
382 for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
383 g_object_ref (G_OBJECT (child));
384 l = g_slist_prepend (l, child);
385 }
386 l = g_slist_reverse (l);
387 while (l) {
388 child = SP_OBJECT (l->data);
389 l = g_slist_remove (l, child);
390 if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
391 if (SP_IS_ITEM (child)) {
392 SPItem const &chi = *SP_ITEM(child);
393 cctx.i2doc = chi.transform * ictx->i2doc;
394 cctx.i2vp = chi.transform * ictx->i2vp;
395 child->updateDisplay((SPCtx *)&cctx, flags);
396 } else {
397 child->updateDisplay(ctx, flags);
398 }
399 }
400 g_object_unref (G_OBJECT (child));
401 }
403 group->UpdateComputed();
404 }
405 void SPFlowregionExclude::UpdateComputed(void)
406 {
407 SPObject* object=SP_OBJECT(this);
409 if (computed) {
410 delete computed;
411 computed = NULL;
412 }
413 NR::Matrix itr_mat = from_2geom(sp_item_i2root_affine (SP_ITEM(object)));
414 itr_mat = itr_mat.inverse();
416 for (SPObject* child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
417 GetDest(child,&computed,itr_mat);
418 }
419 }
421 static void
422 sp_flowregionexclude_modified (SPObject *object, guint flags)
423 {
424 SPFlowregionExclude *group;
425 SPObject *child;
426 GSList *l;
428 group = SP_FLOWREGIONEXCLUDE (object);
430 if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
431 flags &= SP_OBJECT_MODIFIED_CASCADE;
433 l = NULL;
434 for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
435 g_object_ref (G_OBJECT (child));
436 l = g_slist_prepend (l, child);
437 }
438 l = g_slist_reverse (l);
439 while (l) {
440 child = SP_OBJECT (l->data);
441 l = g_slist_remove (l, child);
442 if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
443 child->emitModified(flags);
444 }
445 g_object_unref (G_OBJECT (child));
446 }
447 }
449 static Inkscape::XML::Node *
450 sp_flowregionexclude_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
451 {
452 if (flags & SP_OBJECT_WRITE_BUILD) {
453 if ( repr == NULL ) {
454 repr = xml_doc->createElement("svg:flowRegionExclude");
455 }
457 GSList *l = NULL;
458 for ( SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
459 Inkscape::XML::Node *crepr = child->updateRepr(xml_doc, NULL, flags);
460 if (crepr) l = g_slist_prepend(l, crepr);
461 }
463 while (l) {
464 repr->addChild((Inkscape::XML::Node *) l->data, NULL);
465 Inkscape::GC::release((Inkscape::XML::Node *) l->data);
466 l = g_slist_remove(l, l->data);
467 }
469 } else {
470 for ( SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
471 child->updateRepr(flags);
472 }
473 }
475 if (((SPObjectClass *) (flowregionexclude_parent_class))->write)
476 ((SPObjectClass *) (flowregionexclude_parent_class))->write (object, xml_doc, repr, flags);
478 return repr;
479 }
482 static gchar *sp_flowregionexclude_description(SPItem */*item*/)
483 {
484 /* TRANSLATORS: A region "cut out of" a flow region; text is not allowed to flow inside the
485 * flow excluded region. flowRegionExclude in SVG 1.2: see
486 * http://www.w3.org/TR/2004/WD-SVG12-20041027/flow.html#flowRegion-elem and
487 * http://www.w3.org/TR/2004/WD-SVG12-20041027/flow.html#flowRegionExclude-elem. */
488 return g_strdup_printf(_("Flow excluded region"));
489 }
491 /*
492 *
493 */
495 static void UnionShape(Shape **base_shape, Shape const *add_shape)
496 {
497 if (*base_shape == NULL)
498 *base_shape = new Shape;
499 if ( (*base_shape)->hasEdges() == false ) {
500 (*base_shape)->Copy(const_cast<Shape*>(add_shape));
501 } else if ( add_shape->hasEdges() ) {
502 Shape* temp=new Shape;
503 temp->Booleen(const_cast<Shape*>(add_shape), *base_shape, bool_op_union);
504 delete *base_shape;
505 *base_shape = temp;
506 }
507 }
509 static void GetDest(SPObject* child,Shape **computed,NR::Matrix itr_mat)
510 {
511 if ( child == NULL ) return;
513 SPCurve *curve=NULL;
515 SPObject* u_child=child;
516 if ( SP_IS_USE(u_child) ) {
517 u_child=SP_USE(u_child)->child;
518 }
519 if ( SP_IS_SHAPE (u_child) ) {
520 curve = sp_shape_get_curve (SP_SHAPE (u_child));
521 } else if ( SP_IS_TEXT (u_child) ) {
522 curve = SP_TEXT (u_child)->getNormalizedBpath ();
523 }
525 if ( curve ) {
526 Path* temp=new Path;
527 Geom::Matrix tr_mat = sp_item_i2root_affine (SP_ITEM(u_child));
528 tr_mat = to_2geom(itr_mat) * tr_mat;
529 temp->LoadPathVector(curve->get_pathvector(), tr_mat, true);
530 Shape* n_shp=new Shape;
531 temp->Convert(0.25);
532 temp->Fill(n_shp,0);
533 Shape* uncross=new Shape;
534 SPStyle* style=SP_OBJECT_STYLE(u_child);
535 if ( style && style->fill_rule.computed == SP_WIND_RULE_EVENODD ) {
536 uncross->ConvertToShape(n_shp,fill_oddEven);
537 } else {
538 uncross->ConvertToShape(n_shp,fill_nonZero);
539 }
540 UnionShape(computed, uncross);
541 delete uncross;
542 delete n_shp;
543 delete temp;
544 curve->unref();
545 } else {
546 // printf("no curve\n");
547 }
548 }