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, String &errors); };
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];
541 if(is_absolute_path(file_name))
542 external_canvas=open_canvas(file_name, errors);
544 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name, errors);
547 throw Exception::FileNotFound(file_name);
548 externals_[file_name]=external_canvas;
551 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
554 // If we do not have any resolution, then we assume that the
555 // request is for this immediate canvas
556 if(id.find_first_of(':')==string::npos)
558 Children::iterator iter;
560 // Search for the image in the image list,
561 // and return it if it is found
562 for(iter=children().begin();iter!=children().end();iter++)
563 if(id==(*iter)->get_id())
566 // Create a new canvas and return it
567 //synfig::warning("Implicitly creating canvas named "+id);
568 return new_child_canvas(id);
571 // If the first character is the separator, then
572 // this references the root canvas.
574 return get_root()->surefind_canvas(string(id,1));
576 // Now we know that the requested Canvas is in a child
577 // of this canvas. We have to find that canvas and
578 // call "find_canvas" on it, and return the result.
580 String canvas_name=string(id,0,id.find_first_of(':'));
582 Canvas::Handle child_canvas=surefind_canvas(canvas_name);
584 return child_canvas->surefind_canvas(string(id,id.find_first_of(':')+1));
588 Canvas::find_canvas(const String &id)
591 Canvas::Handle::cast_const(
592 const_cast<const Canvas*>(this)->find_canvas(id)
597 Canvas::find_canvas(const String &id)const
599 if(is_inline() && parent_)return parent_->find_canvas(id);
604 // If the ID contains a "#" character, then a filename is
605 // expected on the left side.
606 if(id.find_first_of('#')!=string::npos)
608 // If '#' is the first character, remove it
609 // and attempt to parse the ID again.
611 return find_canvas(String(id,1));
613 //! \todo This needs a lot more optimization
614 String file_name(id,0,id.find_first_of('#'));
615 String external_id(id,id.find_first_of('#')+1);
617 file_name=unix_to_local_path(file_name);
619 Canvas::Handle external_canvas;
621 // If the composition is already open, then use it.
622 if(externals_.count(file_name))
623 external_canvas=externals_[file_name];
627 if(is_absolute_path(file_name))
628 external_canvas=open_canvas(file_name, errors);
630 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name, errors);
633 throw Exception::FileNotFound(file_name);
634 externals_[file_name]=external_canvas;
637 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
640 // If we do not have any resolution, then we assume that the
641 // request is for this immediate canvas
642 if(id.find_first_of(':')==string::npos)
644 Children::const_iterator iter;
646 // Search for the image in the image list,
647 // and return it if it is found
648 for(iter=children().begin();iter!=children().end();iter++)
649 if(id==(*iter)->get_id())
652 throw Exception::IDNotFound("Child Canvas in Parent Canvas: (child)"+id);
655 // If the first character is the separator, then
656 // this references the root canvas.
657 if(id.find_first_of(':')==0)
658 return get_root()->find_canvas(string(id,1));
660 // Now we know that the requested Canvas is in a child
661 // of this canvas. We have to find that canvas and
662 // call "find_canvas" on it, and return the result.
664 String canvas_name=string(id,0,id.find_first_of(':'));
666 Canvas::ConstHandle child_canvas=find_canvas(canvas_name);
668 return child_canvas->find_canvas(string(id,id.find_first_of(':')+1));
674 return new Canvas("Untitled");
678 Canvas::push_back(etl::handle<Layer> x)
680 // int i(x->count());
682 //if(x->count()!=i+1)synfig::info("push_back before %d, after %d",i,x->count());
686 Canvas::push_front(etl::handle<Layer> x)
688 // int i(x->count());
690 //if(x->count()!=i+1)synfig::error("push_front before %d, after %d",i,x->count());
694 Canvas::insert(iterator iter,etl::handle<Layer> x)
696 // int i(x->count());
697 CanvasBase::insert(iter,x);
699 /*if(x->count()!=i+1)
701 synfig::error(__FILE__":%d: Canvas::insert(): ***FAILURE*** before %d, after %d",__LINE__,i,x->count());
703 //throw runtime_error("Canvas Insertion Failed");
710 LooseHandle correct_canvas(this);
711 //while(correct_canvas->is_inline())correct_canvas=correct_canvas->parent();
712 Layer::LooseHandle loose_layer(x);
714 add_connection(loose_layer,
715 sigc::connection::connection(
716 x->signal_added_to_group().connect(
720 &Canvas::add_group_pair),
722 add_connection(loose_layer,
723 sigc::connection::connection(
724 x->signal_removed_from_group().connect(
728 &Canvas::remove_group_pair),
731 if(!x->get_group().empty())
732 add_group_pair(x->get_group(),x);
738 Canvas::push_back_simple(etl::handle<Layer> x)
740 CanvasBase::insert(end(),x);
745 Canvas::erase(iterator iter)
747 if(!(*iter)->get_group().empty())
748 remove_group_pair((*iter)->get_group(),(*iter));
750 // HACK: We really shouldn't be wiping
751 // out these signals entirely. We should
752 // only be removing the specific connections
753 // that we made. At the moment, I'm too
754 // lazy to add the code to keep track
755 // of those connections, and no one else
756 // is using these signals, so I'll just
757 // leave these next two lines like they
758 // are for now - darco 07-30-2004
760 // so don't wipe them out entirely
761 // - dooglus 09-21-2007
762 disconnect_connections(*iter);
764 if(!op_flag_)remove_child(iter->get());
766 CanvasBase::erase(iter);
767 if(!op_flag_)changed();
771 Canvas::clone(const GUID& deriv_guid)const
778 name=get_id()+"_CLONE";
780 throw runtime_error("Cloning of non-inline canvases is not yet supported");
783 Handle canvas(new Canvas(name));
787 canvas->is_inline_=true;
788 // \todo this was setting parent_=0 - is there a reason for that?
789 // this was causing bug 1838132, where cloning an inline canvas that contains an imported image fails
790 // it was failing to ascertain the absolute pathname of the imported image, since it needs the pathname
791 // of the canvas to get that, which is stored in the parent canvas
792 canvas->parent_=parent();
793 canvas->rend_desc() = rend_desc();
794 //canvas->set_inline(parent());
797 canvas->set_guid(get_guid()^deriv_guid);
800 for(iter=begin();iter!=end();++iter)
802 Layer::Handle layer((*iter)->clone(deriv_guid));
805 assert(layer.count()==1);
807 canvas->push_back(layer);
808 if(!(layer.count()>1))
810 synfig::error("Canvas::clone(): Cloned layer insertion failure!");
811 synfig::error("Canvas::clone(): \tlayer.count()=%d",layer.count());
812 synfig::error("Canvas::clone(): \tlayer->get_name()=%s",layer->get_name().c_str());
813 synfig::error("Canvas::clone(): \tbefore size()=%d",presize);
814 synfig::error("Canvas::clone(): \tafter size()=%d",size());
816 assert(layer.count()>1);
820 synfig::error("Unable to clone layer");
824 canvas->signal_group_pair_removed().clear();
825 canvas->signal_group_pair_added().clear();
831 Canvas::set_inline(LooseHandle parent)
833 if(is_inline_ && parent_)
842 // Have the parent inherit all of the group stuff
844 std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
846 for(iter=group_db_.begin();iter!=group_db_.end();++iter)
848 parent->group_db_[iter->first].insert(iter->second.begin(),iter->second.end());
851 rend_desc()=parent->rend_desc();
855 Canvas::create_inline(Handle parent)
858 //if(parent->is_inline())
859 // return create_inline(parent->parent());
861 Handle canvas(new Canvas("inline"));
862 canvas->set_inline(parent);
867 Canvas::new_child_canvas()
869 if(is_inline() && parent_)
870 return parent_->new_child_canvas();
871 // runtime_error("You cannot create a child Canvas in an inline Canvas");
873 // Create a new canvas
874 children().push_back(create());
875 Canvas::Handle canvas(children().back());
877 canvas->parent_=this;
879 canvas->rend_desc()=rend_desc();
885 Canvas::new_child_canvas(const String &id)
887 if(is_inline() && parent_)
888 return parent_->new_child_canvas(id);
889 // runtime_error("You cannot create a child Canvas in an inline Canvas");
891 // Create a new canvas
892 children().push_back(create());
893 Canvas::Handle canvas(children().back());
896 canvas->parent_=this;
897 canvas->rend_desc()=rend_desc();
903 Canvas::add_child_canvas(Canvas::Handle child_canvas, const synfig::String& id)
905 if(is_inline() && parent_)
906 return parent_->add_child_canvas(child_canvas,id);
908 if(child_canvas->parent() && !child_canvas->is_inline())
909 throw std::runtime_error("Cannot add child canvas because it belongs to someone else!");
912 throw runtime_error("Invalid ID");
917 throw Exception::IDAlreadyExists(id);
919 catch(Exception::IDNotFound)
921 if(child_canvas->is_inline())
922 child_canvas->is_inline_=false;
923 child_canvas->id_=id;
924 children().push_back(child_canvas);
925 child_canvas->parent_=this;
932 Canvas::remove_child_canvas(Canvas::Handle child_canvas)
934 if(is_inline() && parent_)
935 return parent_->remove_child_canvas(child_canvas);
937 if(child_canvas->parent_!=this)
938 throw runtime_error("Given child does not belong to me");
940 if(find(children().begin(),children().end(),child_canvas)==children().end())
941 throw Exception::IDNotFound(child_canvas->get_id());
943 children().remove(child_canvas);
945 child_canvas->parent_=0;
949 Canvas::set_file_name(const String &file_name)
952 parent()->set_file_name(file_name);
955 file_name_=file_name;
956 signal_file_name_changed_();
961 Canvas::signal_file_name_changed()
964 return signal_file_name_changed();
966 return signal_file_name_changed_;
970 Canvas::get_file_name()const
973 return parent()->get_file_name();
978 Canvas::get_file_path()const
981 return parent()->get_file_path();
982 return dirname(file_name_);
986 Canvas::get_meta_data(const String& key)const
988 if(!meta_data_.count(key))
990 return meta_data_.find(key)->second;
994 Canvas::set_meta_data(const String& key, const String& data)
996 if(meta_data_[key]!=data)
998 meta_data_[key]=data;
999 signal_meta_data_changed()(key);
1000 signal_meta_data_changed(key)();
1005 Canvas::erase_meta_data(const String& key)
1007 if(meta_data_.count(key))
1009 meta_data_.erase(key);
1010 signal_meta_data_changed()(key);
1011 signal_meta_data_changed(key)();
1016 Canvas::get_meta_data_keys()const
1018 std::list<String> ret;
1020 std::map<String,String>::const_iterator iter;
1022 for(iter=meta_data_.begin();!(iter==meta_data_.end());++iter)
1023 ret.push_back(iter->first);
1028 /* note - the "Motion Blur" and "Duplicate" layers need the dynamic
1029 parameters of any PasteCanvas layers they loop over to be
1030 maintained. When the variables in the following function
1031 refer to "motion blur", they mean either of these two
1034 synfig::optimize_layers(Time time, Context context, Canvas::Handle op_canvas, bool seen_motion_blur_in_parent)
1038 std::vector< std::pair<float,Layer::Handle> > sort_list;
1039 int i, motion_blur_i=0; // motion_blur_i is for resolving which layer comes first in the event of a z_depth tie
1040 float motion_blur_z_depth=0; // the z_depth of the least deep motion blur layer in this context
1041 bool seen_motion_blur_locally = false;
1042 bool motion_blurred; // the final result - is this layer blurred or not?
1044 // If the parent didn't cause us to already be motion blurred,
1045 // check whether there's a motion blur in this context,
1046 // and if so, calculate its z_depth.
1047 if (!seen_motion_blur_in_parent)
1048 for(iter=context,i=0;*iter;iter++,i++)
1050 Layer::Handle layer=*iter;
1052 // If the layer isn't active, don't worry about it
1053 if(!layer->active())
1056 // Any layer with an amount of zero is implicitly disabled.
1057 ValueBase value(layer->get_param("amount"));
1058 if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1061 if(layer->get_name()=="MotionBlur" || layer->get_name()=="duplicate")
1063 float z_depth(layer->get_z_depth()*1.0001+i);
1065 // If we've seen a motion blur before in this context...
1066 if (seen_motion_blur_locally)
1068 // ... then we're only interested in this one if it's less deep...
1069 if (z_depth < motion_blur_z_depth)
1071 motion_blur_z_depth = z_depth;
1075 // ... otherwise we're always interested in it.
1078 motion_blur_z_depth = z_depth;
1080 seen_motion_blur_locally = true;
1085 // Go ahead and start romping through the canvas to paste
1086 for(iter=context,i=0;*iter;iter++,i++)
1088 Layer::Handle layer=*iter;
1089 float z_depth(layer->get_z_depth()*1.0001+i);
1091 // If the layer isn't active, don't worry about it
1092 if(!layer->active())
1095 // Any layer with an amount of zero is implicitly disabled.
1096 ValueBase value(layer->get_param("amount"));
1097 if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1100 // note: this used to include "&& paste_canvas->get_time_offset()==0", but then
1101 // time-shifted layers weren't being sorted by z-depth (bug #1806852)
1102 if(layer->get_name()=="PasteCanvas")
1104 Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1106 // we need to blur the sub canvas if:
1107 // our parent is blurred,
1108 // or the child is lower than a local blur,
1109 // or the child is at the same z_depth as a local blur, but later in the context
1112 if (seen_motion_blur_in_parent) synfig::info("seen BLUR in parent\n");
1113 else if (seen_motion_blur_locally)
1114 if (z_depth > motion_blur_z_depth) synfig::info("paste is deeper than BLUR\n");
1115 else if (z_depth == motion_blur_z_depth) { synfig::info("paste is same depth as BLUR\n");
1116 if (i > motion_blur_i) synfig::info("paste is physically deeper than BLUR\n");
1117 else synfig::info("paste is less physically deep than BLUR\n");
1118 } else synfig::info("paste is less deep than BLUR\n");
1119 else synfig::info("no BLUR at all\n");
1122 motion_blurred = (seen_motion_blur_in_parent ||
1123 (seen_motion_blur_locally &&
1124 (z_depth > motion_blur_z_depth ||
1125 (z_depth == motion_blur_z_depth && i > motion_blur_i))));
1127 Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
1128 Canvas::Handle paste_sub_canvas = paste_canvas->get_sub_canvas();
1129 if(paste_sub_canvas)
1130 optimize_layers(time, paste_sub_canvas->get_context(),sub_canvas,motion_blurred);
1132 // \todo: uncommenting the following breaks the rendering of at least examples/backdrop.sifz quite severely
1133 // #define SYNFIG_OPTIMIZE_PASTE_CANVAS
1134 #ifdef SYNFIG_OPTIMIZE_PASTE_CANVAS
1135 Canvas::iterator sub_iter;
1137 // Determine if we can just remove the paste canvas altogether
1138 if (paste_canvas->get_blend_method() == Color::BLEND_COMPOSITE &&
1139 paste_canvas->get_amount() == 1.0f &&
1140 paste_canvas->get_zoom() == 0 &&
1141 paste_canvas->get_time_offset() == 0 &&
1142 paste_canvas->get_origin() == Point(0,0) )
1144 for(sub_iter=sub_canvas->begin();sub_iter!=sub_canvas->end();++sub_iter)
1146 Layer* layer=sub_iter->get();
1148 // any layers that deform end up breaking things
1149 // so do things the old way if we run into anything like this
1150 if(!dynamic_cast<Layer_NoDeform*>(layer))
1153 ValueBase value(layer->get_param("blend_method"));
1154 if(value.get_type()!=ValueBase::TYPE_INTEGER || value.get(int())!=(int)Color::BLEND_COMPOSITE)
1158 // It has turned out that we don't need a paste canvas
1159 // layer, so just go ahead and add all the layers onto
1160 // the current stack and be done with it
1161 while(sub_canvas->size())
1163 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,sub_canvas->front()));
1164 //op_canvas->push_back_simple(sub_canvas->front());
1165 sub_canvas->pop_front();
1171 #endif // SYNFIG_OPTIMIZE_PASTE_CANVAS
1173 Layer::Handle new_layer(Layer::create("PasteCanvas"));
1174 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(false);
1177 Layer::DynamicParamList dynamic_param_list(paste_canvas->dynamic_param_list());
1178 for(Layer::DynamicParamList::const_iterator iter(dynamic_param_list.begin()); iter != dynamic_param_list.end(); ++iter)
1179 new_layer->connect_dynamic_param(iter->first, iter->second);
1181 Layer::ParamList param_list(paste_canvas->get_param_list());
1182 //param_list.erase("canvas");
1183 new_layer->set_param_list(param_list);
1184 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_sub_canvas(sub_canvas);
1185 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(true);
1188 else // not a PasteCanvas - does it use blend method 'Straight'?
1190 /* when we use the 'straight' blend method, every pixel on the layer affects the layers underneath,
1191 * not just the non-transparent pixels; the following workarea wraps non-pastecanvas layers in a
1192 * new pastecanvas to ensure that the straight blend affects the full plane, not just the area
1193 * within the layer's bounding box
1196 // \todo: this code probably needs modification to work properly with motionblur and duplicate
1197 etl::handle<Layer_Composite> composite = etl::handle<Layer_Composite>::cast_dynamic(layer);
1199 /* some layers (such as circle) don't touch pixels that aren't
1200 * part of the circle, so they don't get blended correctly when
1201 * using a straight blend. so we encapsulate the circle, and the
1202 * encapsulation layer takes care of the transparent pixels
1203 * for us. if we do that for all layers, however, then the
1204 * distortion layers no longer work, since they have no
1205 * context to work on. the Layer::reads_context() method
1206 * returns true for layers which need to be able to see
1207 * their context. we can't encapsulate those.
1210 Color::is_straight(composite->get_blend_method()) &&
1211 !composite->reads_context())
1213 Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
1214 sub_canvas->push_back(composite = composite->clone());
1215 layer = Layer::create("PasteCanvas");
1216 composite->set_description(strprintf("Wrapped clone of '%s'", composite->get_non_empty_description().c_str()));
1217 layer->set_description(strprintf("PasteCanvas wrapper for '%s'", composite->get_non_empty_description().c_str()));
1218 Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1219 paste_canvas->set_blend_method(composite->get_blend_method());
1220 paste_canvas->set_amount(composite->get_amount());
1221 sub_canvas->set_time(time); // region and outline don't calculate their bounding rects until their time is set
1222 composite->set_blend_method(Color::BLEND_STRAIGHT); // do this before calling set_sub_canvas(), but after set_time()
1223 composite->set_amount(1.0f); // after set_time()
1224 paste_canvas->set_sub_canvas(sub_canvas);
1228 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,layer));
1229 //op_canvas->push_back_simple(layer);
1233 stable_sort(sort_list.begin(),sort_list.end());
1234 std::vector< std::pair<float,Layer::Handle> >::iterator iter2;
1235 for(iter2=sort_list.begin();iter2!=sort_list.end();++iter2)
1236 op_canvas->push_back_simple(iter2->second);
1237 op_canvas->op_flag_=true;
1241 Canvas::get_times_vfunc(Node::time_set &set) const
1243 const_iterator i = begin(),
1246 for(; i != iend; ++i)
1248 const Node::time_set &tset = (*i)->get_times();
1249 set.insert(tset.begin(),tset.end());
1253 std::set<etl::handle<Layer> >
1254 Canvas::get_layers_in_group(const String&group)
1256 if(is_inline() && parent_)
1257 return parent_->get_layers_in_group(group);
1259 if(group_db_.count(group)==0)
1260 return std::set<etl::handle<Layer> >();
1261 return group_db_.find(group)->second;
1265 Canvas::get_groups()const
1267 if(is_inline() && parent_)
1268 return parent_->get_groups();
1270 std::set<String> ret;
1271 std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
1272 for(iter=group_db_.begin();iter!=group_db_.end();++iter)
1273 ret.insert(iter->first);
1278 Canvas::get_group_count()const
1280 if(is_inline() && parent_)
1281 return parent_->get_group_count();
1283 return group_db_.size();
1287 Canvas::add_group_pair(String group, etl::handle<Layer> layer)
1289 group_db_[group].insert(layer);
1290 if(group_db_[group].size()==1)
1291 signal_group_added()(group);
1293 signal_group_changed()(group);
1295 signal_group_pair_added()(group,layer);
1297 if(is_inline() && parent_)
1298 return parent_->add_group_pair(group,layer);
1302 Canvas::remove_group_pair(String group, etl::handle<Layer> layer)
1304 group_db_[group].erase(layer);
1306 signal_group_pair_removed()(group,layer);
1308 if(group_db_[group].empty())
1310 group_db_.erase(group);
1311 signal_group_removed()(group);
1314 signal_group_changed()(group);
1316 if(is_inline() && parent_)
1317 return parent_->remove_group_pair(group,layer);
1321 Canvas::add_connection(etl::loose_handle<Layer> layer, sigc::connection connection)
1323 connections_[layer].push_back(connection);
1327 Canvas::disconnect_connections(etl::loose_handle<Layer> layer)
1329 std::vector<sigc::connection>::iterator iter;
1330 for(iter=connections_[layer].begin();iter!=connections_[layer].end();++iter)
1332 connections_[layer].clear();
1336 Canvas::rename_group(const String&old_name,const String&new_name)
1338 if(is_inline() && parent_)
1339 return parent_->rename_group(old_name,new_name);
1342 std::map<String,std::set<etl::handle<Layer> > >::iterator iter;
1343 iter=group_db_.find(old_name);
1344 if(iter!=group_db_.end())
1345 for(++iter;iter!=group_db_.end() && iter->first.find(old_name)==0;iter=group_db_.find(old_name),++iter)
1347 String name(iter->first,old_name.size(),String::npos);
1349 rename_group(iter->first,name);
1353 std::set<etl::handle<Layer> > layers(get_layers_in_group(old_name));
1354 std::set<etl::handle<Layer> >::iterator iter;
1356 for(iter=layers.begin();iter!=layers.end();++iter)
1358 (*iter)->remove_from_group(old_name);
1359 (*iter)->add_to_group(new_name);