Added copyright lines for files I've edited this year.
[synfig.git] / synfig-core / trunk / src / synfig / canvas.cpp
index 967bc60..c50b901 100644 (file)
@@ -6,7 +6,7 @@
 **
 **     \legal
 **     Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
-**     Copyright (c) 2007 Chris Moore
+**     Copyright (c) 2007, 2008 Chris Moore
 **
 **     This package is free software; you can redistribute it and/or
 **     modify it under the terms of the GNU General Public License as
@@ -90,6 +90,26 @@ Canvas::on_changed()
 
 Canvas::~Canvas()
 {
+       // we were having a crash where pastecanvas layers were still
+       // refering to a canvas after it had been destroyed;  this code
+       // will stop the pastecanvas layers from refering to the canvas
+       // before the canvas is destroyed
+
+       // the set_sub_canvas(0) ends up deleting the parent-child link,
+       // which deletes the current element from the set we're iterating
+       // through, so we have to make sure we've incremented the iterator
+       // before we mess with the pastecanvas
+       std::set<Node*>::iterator iter = parent_set.begin();
+       while (iter != parent_set.end())
+       {
+               Layer_PasteCanvas* paste_canvas = dynamic_cast<Layer_PasteCanvas*>(*iter);
+               iter++;
+               if(paste_canvas)
+                       paste_canvas->set_sub_canvas(0);
+               else
+                       warning("destroyed canvas has a parent that is not a pastecanvas - please report if repeatable");
+       }
+
        //if(is_inline() && parent_) assert(0);
        _CanvasCounter::counter--;
        clear();
@@ -1170,6 +1190,45 @@ synfig::optimize_layers(Time time, Context context, Canvas::Handle op_canvas, bo
                        dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(true);
                        layer=new_layer;
                }
+               else                                    // not a PasteCanvas - does it use blend method 'Straight'?
+               {
+                       /* when we use the 'straight' blend method, every pixel on the layer affects the layers underneath,
+                        * not just the non-transparent pixels; the following workarea wraps non-pastecanvas layers in a
+                        * new pastecanvas to ensure that the straight blend affects the full plane, not just the area
+                        * within the layer's bounding box
+                        */
+
+                       // \todo: this code probably needs modification to work properly with motionblur and duplicate
+                       etl::handle<Layer_Composite> composite = etl::handle<Layer_Composite>::cast_dynamic(layer);
+
+                       /* some layers (such as circle) don't touch pixels that aren't
+                        * part of the circle, so they don't get blended correctly when
+                        * using a straight blend.  so we encapsulate the circle, and the
+                        * encapsulation layer takes care of the transparent pixels
+                        * for us.  if we do that for all layers, however, then the
+                        * distortion layers no longer work, since they have no
+                        * context to work on.  the Layer::reads_context() method
+                        * returns true for layers which need to be able to see
+                        * their context.  we can't encapsulate those.
+                        */
+                       if (composite &&
+                               Color::is_straight(composite->get_blend_method()) &&
+                               !composite->reads_context())
+                       {
+                               Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
+                               sub_canvas->push_back(composite = composite->clone());
+                               layer = Layer::create("PasteCanvas");
+                               composite->set_description(strprintf("Wrapped clone of '%s'", composite->get_non_empty_description().c_str()));
+                               layer->set_description(strprintf("PasteCanvas wrapper for '%s'", composite->get_non_empty_description().c_str()));
+                               Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
+                               paste_canvas->set_blend_method(composite->get_blend_method());
+                               paste_canvas->set_amount(composite->get_amount());
+                               sub_canvas->set_time(time); // region and outline don't calculate their bounding rects until their time is set
+                               composite->set_blend_method(Color::BLEND_STRAIGHT); // do this before calling set_sub_canvas(), but after set_time()
+                               composite->set_amount(1.0f); // after set_time()
+                               paste_canvas->set_sub_canvas(sub_canvas);
+                       }
+               }
 
                sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,layer));
                //op_canvas->push_back_simple(layer);