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"
18 #include "sp-title.h"
19 #include "sp-desc.h"
21 #include "sp-flowregion.h"
23 #include "display/canvas-bpath.h"
26 #include "livarot/Path.h"
27 #include "livarot/Shape.h"
29 static void sp_flowregion_class_init (SPFlowregionClass *klass);
30 static void sp_flowregion_init (SPFlowregion *group);
31 static void sp_flowregion_dispose (GObject *object);
33 static void sp_flowregion_child_added (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * ref);
34 static void sp_flowregion_remove_child (SPObject * object, Inkscape::XML::Node * child);
35 static void sp_flowregion_update (SPObject *object, SPCtx *ctx, guint flags);
36 static void sp_flowregion_modified (SPObject *object, guint flags);
37 static Inkscape::XML::Node *sp_flowregion_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
39 static gchar * sp_flowregion_description (SPItem * item);
41 static SPItemClass * flowregion_parent_class;
43 static void sp_flowregionexclude_class_init (SPFlowregionExcludeClass *klass);
44 static void sp_flowregionexclude_init (SPFlowregionExclude *group);
45 static void sp_flowregionexclude_dispose (GObject *object);
47 static void sp_flowregionexclude_child_added (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * ref);
48 static void sp_flowregionexclude_remove_child (SPObject * object, Inkscape::XML::Node * child);
49 static void sp_flowregionexclude_update (SPObject *object, SPCtx *ctx, guint flags);
50 static void sp_flowregionexclude_modified (SPObject *object, guint flags);
51 static Inkscape::XML::Node *sp_flowregionexclude_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
53 static gchar * sp_flowregionexclude_description (SPItem * item);
55 static SPItemClass * flowregionexclude_parent_class;
58 static void GetDest(SPObject* child,Shape **computed,NR::Matrix itr_mat);
60 GType
61 sp_flowregion_get_type (void)
62 {
63 static GType group_type = 0;
64 if (!group_type) {
65 GTypeInfo group_info = {
66 sizeof (SPFlowregionClass),
67 NULL, /* base_init */
68 NULL, /* base_finalize */
69 (GClassInitFunc) sp_flowregion_class_init,
70 NULL, /* class_finalize */
71 NULL, /* class_data */
72 sizeof (SPFlowregion),
73 16, /* n_preallocs */
74 (GInstanceInitFunc) sp_flowregion_init,
75 NULL, /* value_table */
76 };
77 group_type = g_type_register_static (SP_TYPE_ITEM, "SPFlowregion", &group_info, (GTypeFlags)0);
78 }
79 return group_type;
80 }
82 static void
83 sp_flowregion_class_init (SPFlowregionClass *klass)
84 {
85 GObjectClass * object_class;
86 SPObjectClass * sp_object_class;
87 SPItemClass * item_class;
89 object_class = (GObjectClass *) klass;
90 sp_object_class = (SPObjectClass *) klass;
91 item_class = (SPItemClass *) klass;
93 flowregion_parent_class = (SPItemClass *)g_type_class_ref (SP_TYPE_ITEM);
95 object_class->dispose = sp_flowregion_dispose;
97 sp_object_class->child_added = sp_flowregion_child_added;
98 sp_object_class->remove_child = sp_flowregion_remove_child;
99 sp_object_class->update = sp_flowregion_update;
100 sp_object_class->modified = sp_flowregion_modified;
101 sp_object_class->write = sp_flowregion_write;
103 item_class->description = sp_flowregion_description;
104 }
106 static void
107 sp_flowregion_init (SPFlowregion *group)
108 {
109 new (&group->computed) std::vector<Shape*>;
110 }
112 static void
113 sp_flowregion_dispose(GObject *object)
114 {
115 SPFlowregion *group=(SPFlowregion *)object;
116 for (std::vector<Shape*>::iterator it = group->computed.begin() ; it != group->computed.end() ; it++)
117 delete *it;
118 group->computed.~vector<Shape*>();
119 }
121 static void
122 sp_flowregion_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
123 {
124 SPItem *item;
126 item = SP_ITEM (object);
128 if (((SPObjectClass *) (flowregion_parent_class))->child_added)
129 (* ((SPObjectClass *) (flowregion_parent_class))->child_added) (object, child, ref);
131 object->requestModified(SP_OBJECT_MODIFIED_FLAG);
132 }
134 /* fixme: hide (Lauris) */
136 static void
137 sp_flowregion_remove_child (SPObject * object, Inkscape::XML::Node * child)
138 {
139 if (((SPObjectClass *) (flowregion_parent_class))->remove_child)
140 (* ((SPObjectClass *) (flowregion_parent_class))->remove_child) (object, child);
142 object->requestModified(SP_OBJECT_MODIFIED_FLAG);
143 }
146 static void
147 sp_flowregion_update (SPObject *object, SPCtx *ctx, unsigned int flags)
148 {
149 SPFlowregion *group;
150 SPObject *child;
151 SPItemCtx *ictx, cctx;
152 GSList *l;
154 group = SP_FLOWREGION (object);
155 ictx = (SPItemCtx *) ctx;
156 cctx = *ictx;
158 if (((SPObjectClass *) (flowregion_parent_class))->update)
159 ((SPObjectClass *) (flowregion_parent_class))->update (object, ctx, flags);
161 if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
162 flags &= SP_OBJECT_MODIFIED_CASCADE;
164 l = NULL;
165 for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
166 g_object_ref (G_OBJECT (child));
167 l = g_slist_prepend (l, child);
168 }
169 l = g_slist_reverse (l);
170 while (l) {
171 child = SP_OBJECT (l->data);
172 l = g_slist_remove (l, child);
173 if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
174 if (SP_IS_ITEM (child)) {
175 SPItem const &chi = *SP_ITEM(child);
176 cctx.i2doc = chi.transform * ictx->i2doc;
177 cctx.i2vp = chi.transform * ictx->i2vp;
178 child->updateDisplay((SPCtx *)&cctx, flags);
179 } else {
180 child->updateDisplay(ctx, flags);
181 }
182 }
183 g_object_unref (G_OBJECT (child));
184 }
186 group->UpdateComputed();
187 }
189 void SPFlowregion::UpdateComputed(void)
190 {
191 SPObject* object=SP_OBJECT(this);
193 NR::Matrix itr_mat (sp_item_i2root_affine (SP_ITEM(object)));
194 itr_mat = itr_mat.inverse();
196 for (std::vector<Shape*>::iterator it = computed.begin() ; it != computed.end() ; it++)
197 delete *it;
198 computed.clear();
200 for (SPObject* child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
201 Shape *shape = NULL;
202 GetDest(child,&shape,itr_mat);
203 computed.push_back(shape);
204 }
205 }
207 static void
208 sp_flowregion_modified (SPObject *object, guint flags)
209 {
210 SPFlowregion *group;
211 SPObject *child;
212 GSList *l;
214 group = SP_FLOWREGION (object);
216 if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
217 flags &= SP_OBJECT_MODIFIED_CASCADE;
219 l = NULL;
220 for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
221 g_object_ref (G_OBJECT (child));
222 l = g_slist_prepend (l, child);
223 }
224 l = g_slist_reverse (l);
225 while (l) {
226 child = SP_OBJECT (l->data);
227 l = g_slist_remove (l, child);
228 if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
229 child->emitModified(flags);
230 }
231 g_object_unref (G_OBJECT (child));
232 }
233 }
235 static Inkscape::XML::Node *
236 sp_flowregion_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
237 {
238 if (flags & SP_OBJECT_WRITE_BUILD) {
239 if ( repr == NULL ) {
240 repr = xml_doc->createElement("svg:flowRegion");
241 }
243 GSList *l = NULL;
244 for ( SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
245 if (SP_IS_TITLE(child) || SP_IS_DESC(child)) continue;
246 Inkscape::XML::Node *crepr = child->updateRepr(xml_doc, NULL, flags);
247 if (crepr) l = g_slist_prepend(l, crepr);
248 }
250 while (l) {
251 repr->addChild((Inkscape::XML::Node *) l->data, NULL);
252 Inkscape::GC::release((Inkscape::XML::Node *) l->data);
253 l = g_slist_remove(l, l->data);
254 }
256 } else {
257 for ( SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
258 if (SP_IS_TITLE(child) || SP_IS_DESC(child)) continue;
259 child->updateRepr(flags);
260 }
261 }
263 if (((SPObjectClass *) (flowregion_parent_class))->write)
264 ((SPObjectClass *) (flowregion_parent_class))->write (object, xml_doc, repr, flags);
266 return repr;
267 }
270 static gchar *sp_flowregion_description(SPItem */*item*/)
271 {
272 // TRANSLATORS: "Flow region" is an area where text is allowed to flow
273 return g_strdup_printf(_("Flow region"));
274 }
276 /*
277 *
278 */
280 GType
281 sp_flowregionexclude_get_type (void)
282 {
283 static GType group_type = 0;
284 if (!group_type) {
285 GTypeInfo group_info = {
286 sizeof (SPFlowregionExcludeClass),
287 NULL, /* base_init */
288 NULL, /* base_finalize */
289 (GClassInitFunc) sp_flowregionexclude_class_init,
290 NULL, /* class_finalize */
291 NULL, /* class_data */
292 sizeof (SPFlowregionExclude),
293 16, /* n_preallocs */
294 (GInstanceInitFunc) sp_flowregionexclude_init,
295 NULL, /* value_table */
296 };
297 group_type = g_type_register_static (SP_TYPE_ITEM, "SPFlowregionExclude", &group_info, (GTypeFlags)0);
298 }
299 return group_type;
300 }
302 static void
303 sp_flowregionexclude_class_init (SPFlowregionExcludeClass *klass)
304 {
305 GObjectClass * object_class;
306 SPObjectClass * sp_object_class;
307 SPItemClass * item_class;
309 object_class = (GObjectClass *) klass;
310 sp_object_class = (SPObjectClass *) klass;
311 item_class = (SPItemClass *) klass;
313 flowregionexclude_parent_class = (SPItemClass *)g_type_class_ref (SP_TYPE_ITEM);
315 object_class->dispose = sp_flowregionexclude_dispose;
317 sp_object_class->child_added = sp_flowregionexclude_child_added;
318 sp_object_class->remove_child = sp_flowregionexclude_remove_child;
319 sp_object_class->update = sp_flowregionexclude_update;
320 sp_object_class->modified = sp_flowregionexclude_modified;
321 sp_object_class->write = sp_flowregionexclude_write;
323 item_class->description = sp_flowregionexclude_description;
324 }
326 static void
327 sp_flowregionexclude_init (SPFlowregionExclude *group)
328 {
329 group->computed = NULL;
330 }
332 static void
333 sp_flowregionexclude_dispose(GObject *object)
334 {
335 SPFlowregionExclude *group=(SPFlowregionExclude *)object;
336 if (group->computed) {
337 delete group->computed;
338 group->computed = NULL;
339 }
340 }
342 static void
343 sp_flowregionexclude_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
344 {
345 SPItem *item;
347 item = SP_ITEM (object);
349 if (((SPObjectClass *) (flowregionexclude_parent_class))->child_added)
350 (* ((SPObjectClass *) (flowregionexclude_parent_class))->child_added) (object, child, ref);
352 object->requestModified(SP_OBJECT_MODIFIED_FLAG);
353 }
355 /* fixme: hide (Lauris) */
357 static void
358 sp_flowregionexclude_remove_child (SPObject * object, Inkscape::XML::Node * child)
359 {
360 if (((SPObjectClass *) (flowregionexclude_parent_class))->remove_child)
361 (* ((SPObjectClass *) (flowregionexclude_parent_class))->remove_child) (object, child);
363 object->requestModified(SP_OBJECT_MODIFIED_FLAG);
364 }
367 static void
368 sp_flowregionexclude_update (SPObject *object, SPCtx *ctx, unsigned int flags)
369 {
370 SPFlowregionExclude *group;
371 SPObject *child;
372 SPItemCtx *ictx, cctx;
373 GSList *l;
375 group = SP_FLOWREGIONEXCLUDE (object);
376 ictx = (SPItemCtx *) ctx;
377 cctx = *ictx;
379 if (((SPObjectClass *) (flowregionexclude_parent_class))->update)
380 ((SPObjectClass *) (flowregionexclude_parent_class))->update (object, ctx, flags);
382 if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
383 flags &= SP_OBJECT_MODIFIED_CASCADE;
385 l = NULL;
386 for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
387 g_object_ref (G_OBJECT (child));
388 l = g_slist_prepend (l, child);
389 }
390 l = g_slist_reverse (l);
391 while (l) {
392 child = SP_OBJECT (l->data);
393 l = g_slist_remove (l, child);
394 if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
395 if (SP_IS_ITEM (child)) {
396 SPItem const &chi = *SP_ITEM(child);
397 cctx.i2doc = chi.transform * ictx->i2doc;
398 cctx.i2vp = chi.transform * ictx->i2vp;
399 child->updateDisplay((SPCtx *)&cctx, flags);
400 } else {
401 child->updateDisplay(ctx, flags);
402 }
403 }
404 g_object_unref (G_OBJECT (child));
405 }
407 group->UpdateComputed();
408 }
409 void SPFlowregionExclude::UpdateComputed(void)
410 {
411 SPObject* object=SP_OBJECT(this);
413 if (computed) {
414 delete computed;
415 computed = NULL;
416 }
417 NR::Matrix itr_mat (sp_item_i2root_affine (SP_ITEM(object)));
418 itr_mat = itr_mat.inverse();
420 for (SPObject* child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
421 GetDest(child,&computed,itr_mat);
422 }
423 }
425 static void
426 sp_flowregionexclude_modified (SPObject *object, guint flags)
427 {
428 SPFlowregionExclude *group;
429 SPObject *child;
430 GSList *l;
432 group = SP_FLOWREGIONEXCLUDE (object);
434 if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
435 flags &= SP_OBJECT_MODIFIED_CASCADE;
437 l = NULL;
438 for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
439 g_object_ref (G_OBJECT (child));
440 l = g_slist_prepend (l, child);
441 }
442 l = g_slist_reverse (l);
443 while (l) {
444 child = SP_OBJECT (l->data);
445 l = g_slist_remove (l, child);
446 if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
447 child->emitModified(flags);
448 }
449 g_object_unref (G_OBJECT (child));
450 }
451 }
453 static Inkscape::XML::Node *
454 sp_flowregionexclude_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
455 {
456 if (flags & SP_OBJECT_WRITE_BUILD) {
457 if ( repr == NULL ) {
458 repr = xml_doc->createElement("svg:flowRegionExclude");
459 }
461 GSList *l = NULL;
462 for ( SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
463 Inkscape::XML::Node *crepr = child->updateRepr(xml_doc, NULL, flags);
464 if (crepr) l = g_slist_prepend(l, crepr);
465 }
467 while (l) {
468 repr->addChild((Inkscape::XML::Node *) l->data, NULL);
469 Inkscape::GC::release((Inkscape::XML::Node *) l->data);
470 l = g_slist_remove(l, l->data);
471 }
473 } else {
474 for ( SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
475 child->updateRepr(flags);
476 }
477 }
479 if (((SPObjectClass *) (flowregionexclude_parent_class))->write)
480 ((SPObjectClass *) (flowregionexclude_parent_class))->write (object, xml_doc, repr, flags);
482 return repr;
483 }
486 static gchar *sp_flowregionexclude_description(SPItem */*item*/)
487 {
488 /* TRANSLATORS: A region "cut out of" a flow region; text is not allowed to flow inside the
489 * flow excluded region. flowRegionExclude in SVG 1.2: see
490 * http://www.w3.org/TR/2004/WD-SVG12-20041027/flow.html#flowRegion-elem and
491 * http://www.w3.org/TR/2004/WD-SVG12-20041027/flow.html#flowRegionExclude-elem. */
492 return g_strdup_printf(_("Flow excluded region"));
493 }
495 /*
496 *
497 */
499 static void UnionShape(Shape **base_shape, Shape const *add_shape)
500 {
501 if (*base_shape == NULL)
502 *base_shape = new Shape;
503 if ( (*base_shape)->hasEdges() == false ) {
504 (*base_shape)->Copy(const_cast<Shape*>(add_shape));
505 } else if ( add_shape->hasEdges() ) {
506 Shape* temp=new Shape;
507 temp->Booleen(const_cast<Shape*>(add_shape), *base_shape, bool_op_union);
508 delete *base_shape;
509 *base_shape = temp;
510 }
511 }
513 static void GetDest(SPObject* child,Shape **computed,NR::Matrix itr_mat)
514 {
515 if ( child == NULL ) return;
517 SPCurve *curve=NULL;
519 SPObject* u_child=child;
520 if ( SP_IS_USE(u_child) ) {
521 u_child=SP_USE(u_child)->child;
522 }
523 if ( SP_IS_SHAPE (u_child) ) {
524 curve = sp_shape_get_curve (SP_SHAPE (u_child));
525 } else if ( SP_IS_TEXT (u_child) ) {
526 curve = SP_TEXT (u_child)->getNormalizedBpath ();
527 }
529 if ( curve ) {
530 Path* temp=new Path;
531 Geom::Matrix tr_mat = sp_item_i2root_affine (SP_ITEM(u_child));
532 tr_mat = (Geom::Matrix)itr_mat * tr_mat;
533 temp->LoadPathVector(curve->get_pathvector(), tr_mat, true);
534 Shape* n_shp=new Shape;
535 temp->Convert(0.25);
536 temp->Fill(n_shp,0);
537 Shape* uncross=new Shape;
538 SPStyle* style=SP_OBJECT_STYLE(u_child);
539 if ( style && style->fill_rule.computed == SP_WIND_RULE_EVENODD ) {
540 uncross->ConvertToShape(n_shp,fill_oddEven);
541 } else {
542 uncross->ConvertToShape(n_shp,fill_nonZero);
543 }
544 UnionShape(computed, uncross);
545 delete uncross;
546 delete n_shp;
547 delete temp;
548 curve->unref();
549 } else {
550 // printf("no curve\n");
551 }
552 }