1 /* === S Y N F I G ========================================================= */
3 ** \brief Canvas Class Member Definitions
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
11 ** This package is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU General Public License as
13 ** published by the Free Software Foundation; either version 2 of
14 ** the License, or (at your option) any later version.
16 ** This package is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** General Public License for more details.
22 /* ========================================================================= */
24 /* === H E A D E R S ======================================================= */
26 #define SYNFIG_NO_ANGLE
38 #include "exception.h"
41 #include "layer_pastecanvas.h"
42 #include <sigc++/bind.h>
46 using namespace synfig;
50 namespace synfig { extern Canvas::Handle open_canvas(const String &filename); };
52 /* === M A C R O S ========================================================= */
60 synfig::error("%d canvases not yet deleted!",counter);
64 int _CanvasCounter::counter(0);
66 /* === G L O B A L S ======================================================= */
68 /* === P R O C E D U R E S ================================================= */
70 /* === M E T H O D S ======================================================= */
72 Canvas::Canvas(const String &id):
74 version_ (CURRENT_CANVAS_VERSION),
80 _CanvasCounter::counter++;
93 // we were having a crash where pastecanvas layers were still
94 // refering to a canvas after it had been destroyed; this code
95 // will stop the pastecanvas layers from refering to the canvas
96 // before the canvas is destroyed
98 // the set_sub_canvas(0) ends up deleting the parent-child link,
99 // which deletes the current element from the set we're iterating
100 // through, so we have to make sure we've incremented the iterator
101 // before we mess with the pastecanvas
102 std::set<Node*>::iterator iter = parent_set.begin();
103 while (iter != parent_set.end())
105 Layer_PasteCanvas* paste_canvas = dynamic_cast<Layer_PasteCanvas*>(*iter);
108 paste_canvas->set_sub_canvas(0);
110 warning("destroyed canvas has a parent that is not a pastecanvas - please report if repeatable");
113 //if(is_inline() && parent_) assert(0);
114 _CanvasCounter::counter--;
122 return CanvasBase::end()-1;
125 Canvas::const_iterator
128 return CanvasBase::end()-1;
131 Canvas::reverse_iterator
134 return CanvasBase::rbegin()+1;
137 Canvas::const_reverse_iterator
138 Canvas::rbegin()const
140 return CanvasBase::rbegin()+1;
146 return CanvasBase::size()-1;
154 Layer::Handle layer(front());
155 //if(layer->count()>2)synfig::info("before layer->count()=%d",layer->count());
158 //if(layer->count()>1)synfig::info("after layer->count()=%d",layer->count());
160 //CanvasBase::clear();
162 // We need to keep a blank handle at the
163 // end of the image list, and acts at
164 // the bottom. Without it, the layers
165 // would just continue going when polled
167 CanvasBase::push_back(Layer::Handle());
175 return CanvasBase::size()<=1;
181 return *(CanvasBase::end()-1);
184 const Layer::Handle &
187 return *(CanvasBase::end()-1);
191 Canvas::get_context()const
196 const ValueNodeList &
197 Canvas::value_node_list()const
199 if(is_inline() && parent_)
200 return parent_->value_node_list();
201 return value_node_list_;
205 Canvas::keyframe_list()
207 if(is_inline() && parent_)
208 return parent_->keyframe_list();
209 return keyframe_list_;
213 Canvas::keyframe_list()const
215 if(is_inline() && parent_)
216 return parent_->keyframe_list();
217 return keyframe_list_;
221 Canvas::find_layer(const Point &pos)
223 return get_context().hit_check(pos);
227 valid_id(const String &x)
229 static const char bad_chars[]=" :#@$^&()*";
232 if(!x.empty() && x[0]>='0' && x[0]<='9')
235 for(i=0;i<sizeof(bad_chars);i++)
236 if(x.find_first_of(bad_chars[i])!=string::npos)
243 Canvas::set_id(const String &x)
245 if(is_inline() && parent_)
246 throw runtime_error("Inline Canvas cannot have an ID");
249 throw runtime_error("Invalid ID");
251 signal_id_changed_();
255 Canvas::set_name(const String &x)
258 signal_meta_data_changed()("name");
259 signal_meta_data_changed("name")();
263 Canvas::set_author(const String &x)
266 signal_meta_data_changed()("author");
267 signal_meta_data_changed("author")();
271 Canvas::set_description(const String &x)
274 signal_meta_data_changed()("description");
275 signal_meta_data_changed("description")();
279 Canvas::set_time(Time t)const
281 if(is_dirty_ || !get_time().is_equal(t))
286 synfig::info("is_dirty_=%d",is_dirty_);
287 synfig::info("get_time()=%f",(float)get_time());
288 synfig::info("t=%f",(float)t);
293 const_cast<Canvas&>(*this).cur_time_=t;
296 get_context().set_time(t);
302 Canvas::get_root()const
304 return parent_?parent_->get_root().get():const_cast<synfig::Canvas *>(this);
308 Canvas::get_depth(etl::handle<Layer> layer)const
312 for(iter=begin();iter!=end();++iter,i++)
321 Canvas::get_relative_id(etl::loose_handle<const Canvas> x)const
323 if(x->get_root()==this)
325 if(is_inline() && parent_)
326 return parent_->_get_relative_id(x);
327 return _get_relative_id(x);
331 Canvas::_get_relative_id(etl::loose_handle<const Canvas> x)const
333 if(is_inline() && parent_)
334 return parent_->_get_relative_id(x);
339 if(parent()==x.get())
344 const Canvas* canvas=this;
346 for(;!canvas->is_root();canvas=canvas->parent().get())
347 id=':'+canvas->get_id()+id;
349 if(x && get_root()!=x->get_root())
351 //String file_name=get_file_name();
352 //String file_path=x->get_file_path();
355 if(is_absolute_path(get_file_name()))
356 file_name=etl::relative_path(x->get_file_path(),get_file_name());
358 file_name=get_file_name();
360 // If the path of X is inside of file_name,
362 //if(file_name.size()>file_path.size())
363 // if(file_path==String(file_name,0,file_path.size()))
364 // file_name.erase(0,file_path.size()+1);
373 Canvas::find_value_node(const String &id)
376 ValueNode::Handle::cast_const(
377 const_cast<const Canvas*>(this)->find_value_node(id)
381 ValueNode::ConstHandle
382 Canvas::find_value_node(const String &id)const
384 if(is_inline() && parent_)
385 return parent_->find_value_node(id);
388 throw Exception::IDNotFound("Empty ID");
390 // If we do not have any resolution, then we assume that the
391 // request is for this immediate canvas
392 if(id.find_first_of(':')==string::npos && id.find_first_of('#')==string::npos)
393 return value_node_list_.find(id);
395 String canvas_id(id,0,id.rfind(':'));
396 String value_node_id(id,id.rfind(':')+1);
397 if(canvas_id.empty())
399 //synfig::warning("constfind:value_node_id: "+value_node_id);
400 //synfig::warning("constfind:canvas_id: "+canvas_id);
402 return find_canvas(canvas_id)->value_node_list_.find(value_node_id);
406 Canvas::surefind_value_node(const String &id)
408 if(is_inline() && parent_)
409 return parent_->surefind_value_node(id);
412 throw Exception::IDNotFound("Empty ID");
414 // If we do not have any resolution, then we assume that the
415 // request is for this immediate canvas
416 if(id.find_first_of(':')==string::npos && id.find_first_of('#')==string::npos)
417 return value_node_list_.surefind(id);
419 String canvas_id(id,0,id.rfind(':'));
420 String value_node_id(id,id.rfind(':')+1);
421 if(canvas_id.empty())
424 return surefind_canvas(canvas_id)->value_node_list_.surefind(value_node_id);
428 Canvas::add_value_node(ValueNode::Handle x, const String &id)
430 if(is_inline() && parent_)
431 return parent_->add_value_node(x,id);
432 // throw runtime_error("You cannot add a ValueNode to an inline Canvas");
435 throw runtime_error("ValueNode is already exported");
438 throw Exception::BadLinkName("Empty ID");
440 if(id.find_first_of(':',0)!=string::npos)
441 throw Exception::BadLinkName("Bad character");
445 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
446 throw Exception::IDNotFound("add_value_node()");
448 throw Exception::IDAlreadyExists(id);
450 catch(Exception::IDNotFound)
454 x->set_parent_canvas(this);
456 if(!value_node_list_.add(x))
458 synfig::error("Unable to add ValueNode");
459 throw std::runtime_error("Unable to add ValueNode");
468 Canvas::rename_value_node(ValueNode::Handle x, const String &id)
471 throw Exception::BadLinkName("Empty ID");
473 if(id.find_first_of(": ",0)!=string::npos)
474 throw Exception::BadLinkName("Bad character");
478 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
479 throw Exception::IDNotFound("rename_value_node");
480 throw Exception::IDAlreadyExists(id);
482 catch(Exception::IDNotFound)
492 Canvas::remove_value_node(ValueNode::Handle x)
494 if(is_inline() && parent_)
495 return parent_->remove_value_node(x);
496 // throw Exception::IDNotFound("Canvas::remove_value_node() was called from an inline canvas");
499 throw Exception::IDNotFound("Canvas::remove_value_node() was passed empty handle");
501 if(!value_node_list_.erase(x))
502 throw Exception::IDNotFound("Canvas::remove_value_node(): ValueNode was not found inside of this canvas");
504 //x->set_parent_canvas(0);
510 Canvas::surefind_canvas(const String &id)
512 if(is_inline() && parent_)
513 return parent_->surefind_canvas(id);
518 // If the ID contains a "#" character, then a filename is
519 // expected on the left side.
520 if(id.find_first_of('#')!=string::npos)
522 // If '#' is the first character, remove it
523 // and attempt to parse the ID again.
525 return surefind_canvas(String(id,1));
527 //! \todo This needs a lot more optimization
528 String file_name(id,0,id.find_first_of('#'));
529 String external_id(id,id.find_first_of('#')+1);
531 file_name=unix_to_local_path(file_name);
533 Canvas::Handle external_canvas;
535 // If the composition is already open, then use it.
536 if(externals_.count(file_name))
537 external_canvas=externals_[file_name];
540 if(is_absolute_path(file_name))
541 external_canvas=open_canvas(file_name);
543 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name);
546 throw Exception::FileNotFound(file_name);
547 externals_[file_name]=external_canvas;
550 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
553 // If we do not have any resolution, then we assume that the
554 // request is for this immediate canvas
555 if(id.find_first_of(':')==string::npos)
557 Children::iterator iter;
559 // Search for the image in the image list,
560 // and return it if it is found
561 for(iter=children().begin();iter!=children().end();iter++)
562 if(id==(*iter)->get_id())
565 // Create a new canvas and return it
566 //synfig::warning("Implicitly creating canvas named "+id);
567 return new_child_canvas(id);
570 // If the first character is the separator, then
571 // this references the root canvas.
573 return get_root()->surefind_canvas(string(id,1));
575 // Now we know that the requested Canvas is in a child
576 // of this canvas. We have to find that canvas and
577 // call "find_canvas" on it, and return the result.
579 String canvas_name=string(id,0,id.find_first_of(':'));
581 Canvas::Handle child_canvas=surefind_canvas(canvas_name);
583 return child_canvas->surefind_canvas(string(id,id.find_first_of(':')+1));
587 Canvas::find_canvas(const String &id)
590 Canvas::Handle::cast_const(
591 const_cast<const Canvas*>(this)->find_canvas(id)
596 Canvas::find_canvas(const String &id)const
598 if(is_inline() && parent_)return parent_->find_canvas(id);
603 // If the ID contains a "#" character, then a filename is
604 // expected on the left side.
605 if(id.find_first_of('#')!=string::npos)
607 // If '#' is the first character, remove it
608 // and attempt to parse the ID again.
610 return find_canvas(String(id,1));
612 //! \todo This needs a lot more optimization
613 String file_name(id,0,id.find_first_of('#'));
614 String external_id(id,id.find_first_of('#')+1);
616 file_name=unix_to_local_path(file_name);
618 Canvas::Handle external_canvas;
620 // If the composition is already open, then use it.
621 if(externals_.count(file_name))
622 external_canvas=externals_[file_name];
625 if(is_absolute_path(file_name))
626 external_canvas=open_canvas(file_name);
628 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name);
631 throw Exception::FileNotFound(file_name);
632 externals_[file_name]=external_canvas;
635 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
638 // If we do not have any resolution, then we assume that the
639 // request is for this immediate canvas
640 if(id.find_first_of(':')==string::npos)
642 Children::const_iterator iter;
644 // Search for the image in the image list,
645 // and return it if it is found
646 for(iter=children().begin();iter!=children().end();iter++)
647 if(id==(*iter)->get_id())
650 throw Exception::IDNotFound("Child Canvas in Parent Canvas: (child)"+id);
653 // If the first character is the separator, then
654 // this references the root canvas.
655 if(id.find_first_of(':')==0)
656 return get_root()->find_canvas(string(id,1));
658 // Now we know that the requested Canvas is in a child
659 // of this canvas. We have to find that canvas and
660 // call "find_canvas" on it, and return the result.
662 String canvas_name=string(id,0,id.find_first_of(':'));
664 Canvas::ConstHandle child_canvas=find_canvas(canvas_name);
666 return child_canvas->find_canvas(string(id,id.find_first_of(':')+1));
672 return new Canvas("Untitled");
676 Canvas::push_back(etl::handle<Layer> x)
678 // int i(x->count());
680 //if(x->count()!=i+1)synfig::info("push_back before %d, after %d",i,x->count());
684 Canvas::push_front(etl::handle<Layer> x)
686 // int i(x->count());
688 //if(x->count()!=i+1)synfig::error("push_front before %d, after %d",i,x->count());
692 Canvas::insert(iterator iter,etl::handle<Layer> x)
694 // int i(x->count());
695 CanvasBase::insert(iter,x);
697 /*if(x->count()!=i+1)
699 synfig::error(__FILE__":%d: Canvas::insert(): ***FAILURE*** before %d, after %d",__LINE__,i,x->count());
701 //throw runtime_error("Canvas Insertion Failed");
708 LooseHandle correct_canvas(this);
709 //while(correct_canvas->is_inline())correct_canvas=correct_canvas->parent();
710 Layer::LooseHandle loose_layer(x);
712 add_connection(loose_layer,
713 sigc::connection::connection(
714 x->signal_added_to_group().connect(
718 &Canvas::add_group_pair),
720 add_connection(loose_layer,
721 sigc::connection::connection(
722 x->signal_removed_from_group().connect(
726 &Canvas::remove_group_pair),
729 if(!x->get_group().empty())
730 add_group_pair(x->get_group(),x);
736 Canvas::push_back_simple(etl::handle<Layer> x)
738 CanvasBase::insert(end(),x);
743 Canvas::erase(iterator iter)
745 if(!(*iter)->get_group().empty())
746 remove_group_pair((*iter)->get_group(),(*iter));
748 // HACK: We really shouldn't be wiping
749 // out these signals entirely. We should
750 // only be removing the specific connections
751 // that we made. At the moment, I'm too
752 // lazy to add the code to keep track
753 // of those connections, and no one else
754 // is using these signals, so I'll just
755 // leave these next two lines like they
756 // are for now - darco 07-30-2004
758 // so don't wipe them out entirely
759 // - dooglus 09-21-2007
760 disconnect_connections(*iter);
762 if(!op_flag_)remove_child(iter->get());
764 CanvasBase::erase(iter);
765 if(!op_flag_)changed();
769 Canvas::clone(const GUID& deriv_guid)const
776 name=get_id()+"_CLONE";
778 throw runtime_error("Cloning of non-inline canvases is not yet supported");
781 Handle canvas(new Canvas(name));
785 canvas->is_inline_=true;
786 // \todo this was setting parent_=0 - is there a reason for that?
787 // this was causing bug 1838132, where cloning an inline canvas that contains an imported image fails
788 // it was failing to ascertain the absolute pathname of the imported image, since it needs the pathname
789 // of the canvas to get that, which is stored in the parent canvas
790 canvas->parent_=parent();
791 //canvas->set_inline(parent());
794 canvas->set_guid(get_guid()^deriv_guid);
797 for(iter=begin();iter!=end();++iter)
799 Layer::Handle layer((*iter)->clone(deriv_guid));
802 assert(layer.count()==1);
804 canvas->push_back(layer);
805 if(!(layer.count()>1))
807 synfig::error("Canvas::clone(): Cloned layer insertion failure!");
808 synfig::error("Canvas::clone(): \tlayer.count()=%d",layer.count());
809 synfig::error("Canvas::clone(): \tlayer->get_name()=%s",layer->get_name().c_str());
810 synfig::error("Canvas::clone(): \tbefore size()=%d",presize);
811 synfig::error("Canvas::clone(): \tafter size()=%d",size());
813 assert(layer.count()>1);
817 synfig::error("Unable to clone layer");
821 canvas->signal_group_pair_removed().clear();
822 canvas->signal_group_pair_added().clear();
828 Canvas::set_inline(LooseHandle parent)
830 if(is_inline_ && parent_)
839 // Have the parent inherit all of the group stuff
841 std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
843 for(iter=group_db_.begin();iter!=group_db_.end();++iter)
845 parent->group_db_[iter->first].insert(iter->second.begin(),iter->second.end());
848 rend_desc()=parent->rend_desc();
852 Canvas::create_inline(Handle parent)
855 //if(parent->is_inline())
856 // return create_inline(parent->parent());
858 Handle canvas(new Canvas("inline"));
859 canvas->set_inline(parent);
864 Canvas::new_child_canvas()
866 if(is_inline() && parent_)
867 return parent_->new_child_canvas();
868 // runtime_error("You cannot create a child Canvas in an inline Canvas");
870 // Create a new canvas
871 children().push_back(create());
872 Canvas::Handle canvas(children().back());
874 canvas->parent_=this;
876 canvas->rend_desc()=rend_desc();
882 Canvas::new_child_canvas(const String &id)
884 if(is_inline() && parent_)
885 return parent_->new_child_canvas(id);
886 // runtime_error("You cannot create a child Canvas in an inline Canvas");
888 // Create a new canvas
889 children().push_back(create());
890 Canvas::Handle canvas(children().back());
893 canvas->parent_=this;
894 canvas->rend_desc()=rend_desc();
900 Canvas::add_child_canvas(Canvas::Handle child_canvas, const synfig::String& id)
902 if(is_inline() && parent_)
903 return parent_->add_child_canvas(child_canvas,id);
905 if(child_canvas->parent() && !child_canvas->is_inline())
906 throw std::runtime_error("Cannot add child canvas because it belongs to someone else!");
909 throw runtime_error("Invalid ID");
914 throw Exception::IDAlreadyExists(id);
916 catch(Exception::IDNotFound)
918 if(child_canvas->is_inline())
919 child_canvas->is_inline_=false;
920 child_canvas->id_=id;
921 children().push_back(child_canvas);
922 child_canvas->parent_=this;
929 Canvas::remove_child_canvas(Canvas::Handle child_canvas)
931 if(is_inline() && parent_)
932 return parent_->remove_child_canvas(child_canvas);
934 if(child_canvas->parent_!=this)
935 throw runtime_error("Given child does not belong to me");
937 if(find(children().begin(),children().end(),child_canvas)==children().end())
938 throw Exception::IDNotFound(child_canvas->get_id());
940 children().remove(child_canvas);
942 child_canvas->parent_=0;
946 Canvas::set_file_name(const String &file_name)
949 parent()->set_file_name(file_name);
952 file_name_=file_name;
953 signal_file_name_changed_();
958 Canvas::signal_file_name_changed()
961 return signal_file_name_changed();
963 return signal_file_name_changed_;
967 Canvas::get_file_name()const
970 return parent()->get_file_name();
975 Canvas::get_file_path()const
978 return parent()->get_file_path();
979 return dirname(file_name_);
983 Canvas::get_meta_data(const String& key)const
985 if(!meta_data_.count(key))
987 return meta_data_.find(key)->second;
991 Canvas::set_meta_data(const String& key, const String& data)
993 if(meta_data_[key]!=data)
995 meta_data_[key]=data;
996 signal_meta_data_changed()(key);
997 signal_meta_data_changed(key)();
1002 Canvas::erase_meta_data(const String& key)
1004 if(meta_data_.count(key))
1006 meta_data_.erase(key);
1007 signal_meta_data_changed()(key);
1008 signal_meta_data_changed(key)();
1013 Canvas::get_meta_data_keys()const
1015 std::list<String> ret;
1017 std::map<String,String>::const_iterator iter;
1019 for(iter=meta_data_.begin();!(iter==meta_data_.end());++iter)
1020 ret.push_back(iter->first);
1025 /* note - the "Motion Blur" and "Duplicate" layers need the dynamic
1026 parameters of any PasteCanvas layers they loop over to be
1027 maintained. When the variables in the following function
1028 refer to "motion blur", they mean either of these two
1031 synfig::optimize_layers(Time time, Context context, Canvas::Handle op_canvas, bool seen_motion_blur_in_parent)
1035 std::vector< std::pair<float,Layer::Handle> > sort_list;
1036 int i, motion_blur_i=0; // motion_blur_i is for resolving which layer comes first in the event of a z_depth tie
1037 float motion_blur_z_depth=0; // the z_depth of the least deep motion blur layer in this context
1038 bool seen_motion_blur_locally = false;
1039 bool motion_blurred; // the final result - is this layer blurred or not?
1041 // If the parent didn't cause us to already be motion blurred,
1042 // check whether there's a motion blur in this context,
1043 // and if so, calculate its z_depth.
1044 if (!seen_motion_blur_in_parent)
1045 for(iter=context,i=0;*iter;iter++,i++)
1047 Layer::Handle layer=*iter;
1049 // If the layer isn't active, don't worry about it
1050 if(!layer->active())
1053 // Any layer with an amount of zero is implicitly disabled.
1054 ValueBase value(layer->get_param("amount"));
1055 if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1058 if(layer->get_name()=="MotionBlur" || layer->get_name()=="duplicate")
1060 float z_depth(layer->get_z_depth()*1.0001+i);
1062 // If we've seen a motion blur before in this context...
1063 if (seen_motion_blur_locally)
1065 // ... then we're only interested in this one if it's less deep...
1066 if (z_depth < motion_blur_z_depth)
1068 motion_blur_z_depth = z_depth;
1072 // ... otherwise we're always interested in it.
1075 motion_blur_z_depth = z_depth;
1077 seen_motion_blur_locally = true;
1082 // Go ahead and start romping through the canvas to paste
1083 for(iter=context,i=0;*iter;iter++,i++)
1085 Layer::Handle layer=*iter;
1086 float z_depth(layer->get_z_depth()*1.0001+i);
1088 // If the layer isn't active, don't worry about it
1089 if(!layer->active())
1092 // Any layer with an amount of zero is implicitly disabled.
1093 ValueBase value(layer->get_param("amount"));
1094 if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1097 // note: this used to include "&& paste_canvas->get_time_offset()==0", but then
1098 // time-shifted layers weren't being sorted by z-depth (bug #1806852)
1099 if(layer->get_name()=="PasteCanvas")
1101 Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1103 // we need to blur the sub canvas if:
1104 // our parent is blurred,
1105 // or the child is lower than a local blur,
1106 // or the child is at the same z_depth as a local blur, but later in the context
1109 if (seen_motion_blur_in_parent) synfig::info("seen BLUR in parent\n");
1110 else if (seen_motion_blur_locally)
1111 if (z_depth > motion_blur_z_depth) synfig::info("paste is deeper than BLUR\n");
1112 else if (z_depth == motion_blur_z_depth) { synfig::info("paste is same depth as BLUR\n");
1113 if (i > motion_blur_i) synfig::info("paste is physically deeper than BLUR\n");
1114 else synfig::info("paste is less physically deep than BLUR\n");
1115 } else synfig::info("paste is less deep than BLUR\n");
1116 else synfig::info("no BLUR at all\n");
1119 motion_blurred = (seen_motion_blur_in_parent ||
1120 (seen_motion_blur_locally &&
1121 (z_depth > motion_blur_z_depth ||
1122 (z_depth == motion_blur_z_depth && i > motion_blur_i))));
1124 Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
1125 Canvas::Handle paste_sub_canvas = paste_canvas->get_sub_canvas();
1126 if(paste_sub_canvas)
1127 optimize_layers(time, paste_sub_canvas->get_context(),sub_canvas,motion_blurred);
1129 // \todo: uncommenting the following breaks the rendering of at least examples/backdrop.sifz quite severely
1130 // #define SYNFIG_OPTIMIZE_PASTE_CANVAS
1131 #ifdef SYNFIG_OPTIMIZE_PASTE_CANVAS
1132 Canvas::iterator sub_iter;
1134 // Determine if we can just remove the paste canvas altogether
1135 if (paste_canvas->get_blend_method() == Color::BLEND_COMPOSITE &&
1136 paste_canvas->get_amount() == 1.0f &&
1137 paste_canvas->get_zoom() == 0 &&
1138 paste_canvas->get_time_offset() == 0 &&
1139 paste_canvas->get_origin() == Point(0,0) )
1141 for(sub_iter=sub_canvas->begin();sub_iter!=sub_canvas->end();++sub_iter)
1143 Layer* layer=sub_iter->get();
1145 // any layers that deform end up breaking things
1146 // so do things the old way if we run into anything like this
1147 if(!dynamic_cast<Layer_NoDeform*>(layer))
1150 ValueBase value(layer->get_param("blend_method"));
1151 if(value.get_type()!=ValueBase::TYPE_INTEGER || value.get(int())!=(int)Color::BLEND_COMPOSITE)
1155 // It has turned out that we don't need a paste canvas
1156 // layer, so just go ahead and add all the layers onto
1157 // the current stack and be done with it
1158 while(sub_canvas->size())
1160 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,sub_canvas->front()));
1161 //op_canvas->push_back_simple(sub_canvas->front());
1162 sub_canvas->pop_front();
1168 #endif // SYNFIG_OPTIMIZE_PASTE_CANVAS
1170 Layer::Handle new_layer(Layer::create("PasteCanvas"));
1171 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(false);
1174 Layer::DynamicParamList dynamic_param_list(paste_canvas->dynamic_param_list());
1175 for(Layer::DynamicParamList::const_iterator iter(dynamic_param_list.begin()); iter != dynamic_param_list.end(); ++iter)
1176 new_layer->connect_dynamic_param(iter->first, iter->second);
1178 Layer::ParamList param_list(paste_canvas->get_param_list());
1179 //param_list.erase("canvas");
1180 new_layer->set_param_list(param_list);
1181 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_sub_canvas(sub_canvas);
1182 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(true);
1185 else // not a PasteCanvas - does it use blend method 'Straight'?
1187 /* when we use the 'straight' blend method, every pixel on the layer affects the layers underneath,
1188 * not just the non-transparent pixels; the following workarea wraps non-pastecanvas layers in a
1189 * new pastecanvas to ensure that the straight blend affects the full plane, not just the area
1190 * within the layer's bounding box
1193 // \todo: this code probably needs modification to work properly with motionblur and duplicate
1194 etl::handle<Layer_Composite> composite = etl::handle<Layer_Composite>::cast_dynamic(layer);
1196 /* some layers (such as circle) don't touch pixels that aren't
1197 * part of the circle, so they don't get blended correctly when
1198 * using a straight blend. so we encapsulate the circle, and the
1199 * encapsulation layer takes care of the transparent pixels
1200 * for us. if we do that for all layers, however, then the
1201 * distortion layers no longer work, since they have no
1202 * context to work on. the Layer::reads_context() method
1203 * returns true for layers which need to be able to see
1204 * their context. we can't encapsulate those.
1207 Color::is_straight(composite->get_blend_method()) &&
1208 !composite->reads_context())
1210 Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
1211 sub_canvas->push_back(composite = composite->clone());
1212 layer = Layer::create("PasteCanvas");
1213 composite->set_description(strprintf("Wrapped clone of '%s'", composite->get_non_empty_description().c_str()));
1214 layer->set_description(strprintf("PasteCanvas wrapper for '%s'", composite->get_non_empty_description().c_str()));
1215 Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1216 paste_canvas->set_blend_method(composite->get_blend_method());
1217 paste_canvas->set_amount(composite->get_amount());
1218 sub_canvas->set_time(time); // region and outline don't calculate their bounding rects until their time is set
1219 composite->set_blend_method(Color::BLEND_STRAIGHT); // do this before calling set_sub_canvas(), but after set_time()
1220 composite->set_amount(1.0f); // after set_time()
1221 paste_canvas->set_sub_canvas(sub_canvas);
1225 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,layer));
1226 //op_canvas->push_back_simple(layer);
1230 stable_sort(sort_list.begin(),sort_list.end());
1231 std::vector< std::pair<float,Layer::Handle> >::iterator iter2;
1232 for(iter2=sort_list.begin();iter2!=sort_list.end();++iter2)
1233 op_canvas->push_back_simple(iter2->second);
1234 op_canvas->op_flag_=true;
1238 Canvas::get_times_vfunc(Node::time_set &set) const
1240 const_iterator i = begin(),
1243 for(; i != iend; ++i)
1245 const Node::time_set &tset = (*i)->get_times();
1246 set.insert(tset.begin(),tset.end());
1250 std::set<etl::handle<Layer> >
1251 Canvas::get_layers_in_group(const String&group)
1253 if(is_inline() && parent_)
1254 return parent_->get_layers_in_group(group);
1256 if(group_db_.count(group)==0)
1257 return std::set<etl::handle<Layer> >();
1258 return group_db_.find(group)->second;
1262 Canvas::get_groups()const
1264 if(is_inline() && parent_)
1265 return parent_->get_groups();
1267 std::set<String> ret;
1268 std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
1269 for(iter=group_db_.begin();iter!=group_db_.end();++iter)
1270 ret.insert(iter->first);
1275 Canvas::get_group_count()const
1277 if(is_inline() && parent_)
1278 return parent_->get_group_count();
1280 return group_db_.size();
1284 Canvas::add_group_pair(String group, etl::handle<Layer> layer)
1286 group_db_[group].insert(layer);
1287 if(group_db_[group].size()==1)
1288 signal_group_added()(group);
1290 signal_group_changed()(group);
1292 signal_group_pair_added()(group,layer);
1294 if(is_inline() && parent_)
1295 return parent_->add_group_pair(group,layer);
1299 Canvas::remove_group_pair(String group, etl::handle<Layer> layer)
1301 group_db_[group].erase(layer);
1303 signal_group_pair_removed()(group,layer);
1305 if(group_db_[group].empty())
1307 group_db_.erase(group);
1308 signal_group_removed()(group);
1311 signal_group_changed()(group);
1313 if(is_inline() && parent_)
1314 return parent_->remove_group_pair(group,layer);
1318 Canvas::add_connection(etl::loose_handle<Layer> layer, sigc::connection connection)
1320 connections_[layer].push_back(connection);
1324 Canvas::disconnect_connections(etl::loose_handle<Layer> layer)
1326 std::vector<sigc::connection>::iterator iter;
1327 for(iter=connections_[layer].begin();iter!=connections_[layer].end();++iter)
1329 connections_[layer].clear();
1333 Canvas::rename_group(const String&old_name,const String&new_name)
1335 if(is_inline() && parent_)
1336 return parent_->rename_group(old_name,new_name);
1339 std::map<String,std::set<etl::handle<Layer> > >::iterator iter;
1340 iter=group_db_.find(old_name);
1341 if(iter!=group_db_.end())
1342 for(++iter;iter!=group_db_.end() && iter->first.find(old_name)==0;iter=group_db_.find(old_name),++iter)
1344 String name(iter->first,old_name.size(),String::npos);
1346 rename_group(iter->first,name);
1350 std::set<etl::handle<Layer> > layers(get_layers_in_group(old_name));
1351 std::set<etl::handle<Layer> >::iterator iter;
1353 for(iter=layers.begin();iter!=layers.end();++iter)
1355 (*iter)->remove_from_group(old_name);
1356 (*iter)->add_to_group(new_name);