Code

Mask/Clippath transformations on masking/unmasking
authorknutux <knutux@users.sourceforge.net>
Wed, 22 Mar 2006 06:22:39 +0000 (06:22 +0000)
committerknutux <knutux@users.sourceforge.net>
Wed, 22 Mar 2006 06:22:39 +0000 (06:22 +0000)
src/selection-chemistry.cpp
src/sp-clippath.cpp
src/sp-clippath.h
src/sp-mask.cpp
src/sp-mask.h

index ba0d89850fd4bc475d80e014cb04ccac6477de26..e7e3ec4a35e25436ccbfc7001efc85d8d52909ec 100644 (file)
@@ -64,7 +64,7 @@
 #include "file.h"
 #include "layer-fns.h"
 #include "context-fns.h"
-#include <set>
+#include <map>
 using NR::X;
 using NR::Y;
 
@@ -2295,7 +2295,7 @@ sp_selection_set_mask(bool apply_clip_path, bool apply_to_layer)
     
     if (apply_to_layer) {
         // all selected items are used for mask, which is applied to a layer
-        apply_to_items = g_slist_prepend (apply_to_items, SP_OBJECT_REPR(desktop->currentLayer()));
+        apply_to_items = g_slist_prepend (apply_to_items, desktop->currentLayer());
 
         for (GSList *i = items; i != NULL; i = i->next) {
             Inkscape::XML::Node *dup = (SP_OBJECT_REPR (i->data))->duplicate();
@@ -2318,12 +2318,12 @@ sp_selection_set_mask(bool apply_clip_path, bool apply_to_layer)
         }
         
         for (i = i->next; i != NULL; i = i->next) {
-            apply_to_items = g_slist_prepend (apply_to_items, SP_OBJECT_REPR (i->data));
+            apply_to_items = g_slist_prepend (apply_to_items, i->data);
         }
     } else {
         GSList *i = NULL;
         for (i = items; NULL != i->next; i = i->next) {
-            apply_to_items = g_slist_prepend (apply_to_items, SP_OBJECT_REPR (i->data));
+            apply_to_items = g_slist_prepend (apply_to_items, i->data);
         }
 
         Inkscape::XML::Node *dup = (SP_OBJECT_REPR (i->data))->duplicate();
@@ -2336,20 +2336,35 @@ sp_selection_set_mask(bool apply_clip_path, bool apply_to_layer)
     }
     
     g_slist_free (items);
+    items = NULL;
             
-    const gchar *mask_id = NULL;
-    if (apply_clip_path) {
-        mask_id = sp_clippath_create(mask_items, document);
-    } else {
-        mask_id = sp_mask_create(mask_items, document);
-    }
-    g_slist_free (mask_items);
-
     gchar const* attributeName = apply_clip_path ? "clip-path" : "mask";
     for (GSList *i = apply_to_items; NULL != i; i = i->next) {
-        ((Inkscape::XML::Node *)i->data)->setAttribute(attributeName, g_strdup_printf("url(#%s)", mask_id));
+        SPItem *item = reinterpret_cast<SPItem *>(i->data);
+        // inverted object transform should be applied to a mask object,
+        // as mask is calculated in user space (after applying transform)
+        NR::Matrix maskTransform (item->transform.inverse());
+
+        GSList *mask_items_dup = NULL;
+        for (GSList *mask_item = mask_items; NULL != mask_item; mask_item = mask_item->next) {
+            Inkscape::XML::Node *dup = reinterpret_cast<Inkscape::XML::Node *>(mask_item->data)->duplicate();
+            mask_items_dup = g_slist_prepend (mask_items_dup, dup);
+        }
+
+        const gchar *mask_id = NULL;
+        if (apply_clip_path) {
+            mask_id = sp_clippath_create(mask_items_dup, document, &maskTransform);
+        } else {
+            mask_id = sp_mask_create(mask_items_dup, document, &maskTransform);
+        }
+
+        g_slist_free (mask_items_dup);
+        mask_items_dup = NULL;
+
+        SP_OBJECT_REPR(i->data)->setAttribute(attributeName, g_strdup_printf("url(#%s)", mask_id));
     }
 
+    g_slist_free (mask_items);
     g_slist_free (apply_to_items);
 
     sp_document_done (document);
@@ -2373,7 +2388,7 @@ void sp_selection_unset_mask(bool apply_clip_path) {
     sp_document_ensure_up_to_date(document);
 
     gchar const* attributeName = apply_clip_path ? "clip-path" : "mask";
-    std::set<SPObject*> referenced_objects;
+    std::map<SPObject*,SPItem*> referenced_objects;
     for (GSList const*i = selection->itemList(); NULL != i; i = i->next) {
         if (remove_original) {
             // remember referenced mask/clippath, so orphaned masks can be moved back to document
@@ -2386,9 +2401,9 @@ void sp_selection_unset_mask(bool apply_clip_path) {
                 uri_ref = item->mask_ref;
             }
 
-            // collect distinct mask object
-            if (NULL != uri_ref && NULL != uri_ref->getObject() && referenced_objects.end() == referenced_objects.find(uri_ref->getObject())) {
-                referenced_objects.insert(uri_ref->getObject());
+            // collect distinct mask object (and associate with item to apply transform)
+            if (NULL != uri_ref && NULL != uri_ref->getObject()) {
+                referenced_objects[uri_ref->getObject()] = item;
             }
         }
 
@@ -2396,8 +2411,8 @@ void sp_selection_unset_mask(bool apply_clip_path) {
     }
 
     // restore mask objects into a document
-    for ( std::set<SPObject*>::iterator it = referenced_objects.begin() ; it != referenced_objects.end() ; ++it) {
-        SPObject *obj = (*it);
+    for ( std::map<SPObject*,SPItem*>::iterator it = referenced_objects.begin() ; it != referenced_objects.end() ; ++it) {
+        SPObject *obj = (*it).first;
         GSList *items_to_move = NULL;
         for (SPObject *child = sp_object_first_child(obj) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
             Inkscape::XML::Node *copy = SP_OBJECT_REPR(child)->duplicate();
@@ -2410,8 +2425,13 @@ void sp_selection_unset_mask(bool apply_clip_path) {
         }
 
         for (GSList *i = items_to_move; NULL != i; i = i->next) {
-            desktop->currentLayer()->appendChildRepr((Inkscape::XML::Node *)i->data);
+            SPItem *item = SP_ITEM(desktop->currentLayer()->appendChildRepr((Inkscape::XML::Node *)i->data));
             selection->add((Inkscape::XML::Node *)i->data);
+
+            // transform mask, so it is moved the same spot there mask was applied
+            NR::Matrix transform (item->transform);
+            transform *= (*it).second->transform;
+            sp_item_write_transform(item, SP_OBJECT_REPR(item), transform);
         }
 
         g_slist_free (items_to_move);
index 33feea8ce2eef50669b8a78841becde558822f69..35e0738791e825f0d29895f236ef6de43999760a 100644 (file)
@@ -371,7 +371,7 @@ sp_clippath_view_list_remove(SPClipPathView *list, SPClipPathView *view)
 
 // Create a mask element (using passed elements), add it to <defs>
 const gchar *
-sp_clippath_create (GSList *reprs, SPDocument *document)
+sp_clippath_create (GSList *reprs, SPDocument *document, NR::Matrix const* applyTransform)
 {
     Inkscape::XML::Node *defsrepr = SP_OBJECT_REPR (SP_DOCUMENT_DEFS (document));
 
@@ -384,7 +384,13 @@ sp_clippath_create (GSList *reprs, SPDocument *document)
     
     for (GSList *it = reprs; it != NULL; it = it->next) {
         Inkscape::XML::Node *node = (Inkscape::XML::Node *)(it->data);
-        clip_path_object->appendChildRepr(node);
+        SPItem *item = SP_ITEM(clip_path_object->appendChildRepr(node));
+        
+        if (NULL != applyTransform) {
+            NR::Matrix transform (item->transform);
+            transform *= (*applyTransform);
+            sp_item_write_transform(item, SP_OBJECT_REPR(item), transform);
+        }
     }
     
     Inkscape::GC::release(repr);
index 0f977a3e8dbe533a5b6bb0f4b0ccd8dd5f0897cd..8f20d788041f7d1962d71680ed938be44d84798f 100644 (file)
@@ -59,6 +59,6 @@ void sp_clippath_hide(SPClipPath *cp, unsigned int key);
 void sp_clippath_set_bbox(SPClipPath *cp, unsigned int key, NRRect *bbox);
 void sp_clippath_get_bbox(SPClipPath *cp, NRRect *bbox, NR::Matrix const &transform, unsigned const flags);
 
-const gchar *sp_clippath_create (GSList *reprs, SPDocument *document);
+const gchar *sp_clippath_create (GSList *reprs, SPDocument *document, NR::Matrix const* applyTransform);
 
 #endif
index 773169d68847d2edfc342c3a55596ed022082831..55b6782939a6465124d6bebbe9ba70f2c65cd04e 100644 (file)
@@ -269,7 +269,7 @@ sp_mask_write (SPObject *object, Inkscape::XML::Node *repr, guint flags)
 
 // Create a mask element (using passed elements), add it to <defs>
 const gchar *
-sp_mask_create (GSList *reprs, SPDocument *document)
+sp_mask_create (GSList *reprs, SPDocument *document, NR::Matrix const* applyTransform)
 {
     Inkscape::XML::Node *defsrepr = SP_OBJECT_REPR (SP_DOCUMENT_DEFS (document));
 
@@ -282,7 +282,13 @@ sp_mask_create (GSList *reprs, SPDocument *document)
     
     for (GSList *it = reprs; it != NULL; it = it->next) {
         Inkscape::XML::Node *node = (Inkscape::XML::Node *)(it->data);
-        mask_object->appendChildRepr(node);
+        SPItem *item = SP_ITEM(mask_object->appendChildRepr(node));
+        
+        if (NULL != applyTransform) {
+            NR::Matrix transform (item->transform);
+            transform *= (*applyTransform);
+            sp_item_write_transform(item, SP_OBJECT_REPR(item), transform);
+        }
     }
     
     Inkscape::GC::release(repr);
index b17ac83997a2e231d187edeadc4790361346b9ac..621029b986fe08037297438c7223f28fe6bdfee6 100644 (file)
@@ -60,6 +60,6 @@ void sp_mask_hide (SPMask *mask, unsigned int key);
 
 void sp_mask_set_bbox (SPMask *mask, unsigned int key, NRRect *bbox);
 
-const gchar *sp_mask_create (GSList *reprs, SPDocument *document);
+const gchar *sp_mask_create (GSList *reprs, SPDocument *document, NR::Matrix const* applyTransform);
 
 #endif