Code

eliminate direct accesses to SPCurve::bpath
[inkscape.git] / src / sp-flowregion.cpp
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;
103 static void
104 sp_flowregion_init (SPFlowregion *group)
106         new (&group->computed) std::vector<Shape*>;
109 static void
110 sp_flowregion_dispose(GObject *object)
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*>();
118 static void
119 sp_flowregion_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
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);
131 /* fixme: hide (Lauris) */
133 static void
134 sp_flowregion_remove_child (SPObject * object, Inkscape::XML::Node * child)
136         if (((SPObjectClass *) (flowregion_parent_class))->remove_child)
137                 (* ((SPObjectClass *) (flowregion_parent_class))->remove_child) (object, child);
139         object->requestModified(SP_OBJECT_MODIFIED_FLAG);
143 static void
144 sp_flowregion_update (SPObject *object, SPCtx *ctx, unsigned int flags)
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();
186 void             SPFlowregion::UpdateComputed(void)
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         }
204 static void
205 sp_flowregion_modified (SPObject *object, guint flags)
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         }
232 static Inkscape::XML::Node *
233 sp_flowregion_write (SPObject *object, Inkscape::XML::Node *repr, guint flags)
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);
258         
259         return repr;
263 static gchar *sp_flowregion_description(SPItem *item)
265         // TRANSLATORS: "Flow region" is an area where text is allowed to flow
266         return g_strdup_printf(_("Flow region"));
269 /*
270  *
271  */
273 GType
274 sp_flowregionexclude_get_type (void)
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;
295 static void
296 sp_flowregionexclude_class_init (SPFlowregionExcludeClass *klass)
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;
319 static void
320 sp_flowregionexclude_init (SPFlowregionExclude *group)
322         group->computed = NULL;
325 static void
326 sp_flowregionexclude_dispose(GObject *object)
328         SPFlowregionExclude *group=(SPFlowregionExclude *)object;
329     if (group->computed) {
330         delete group->computed;
331         group->computed = NULL;
332     }
335 static void
336 sp_flowregionexclude_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
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);
348 /* fixme: hide (Lauris) */
350 static void
351 sp_flowregionexclude_remove_child (SPObject * object, Inkscape::XML::Node * child)
353         if (((SPObjectClass *) (flowregionexclude_parent_class))->remove_child)
354                 (* ((SPObjectClass *) (flowregionexclude_parent_class))->remove_child) (object, child);
356         object->requestModified(SP_OBJECT_MODIFIED_FLAG);
360 static void
361 sp_flowregionexclude_update (SPObject *object, SPCtx *ctx, unsigned int flags)
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();
402 void             SPFlowregionExclude::UpdateComputed(void)
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         }
418 static void
419 sp_flowregionexclude_modified (SPObject *object, guint flags)
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         }
446 static Inkscape::XML::Node *
447 sp_flowregionexclude_write (SPObject *object, Inkscape::XML::Node *repr, guint flags)
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);
472         
473         return repr;
477 static gchar *sp_flowregionexclude_description(SPItem *item)
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"));
486 /*
487  *
488  */
490 static void         UnionShape(Shape **base_shape, Shape const *add_shape)
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         }
504 static void         GetDest(SPObject* child,Shape **computed,NR::Matrix itr_mat)
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         }