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 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);
374 Canvas::find_value_node(const String &id)
377 ValueNode::Handle::cast_const(
378 const_cast<const Canvas*>(this)->find_value_node(id)
382 ValueNode::ConstHandle
383 Canvas::find_value_node(const String &id)const
385 if(is_inline() && parent_)
386 return parent_->find_value_node(id);
389 throw Exception::IDNotFound("Empty ID");
391 // If we do not have any resolution, then we assume that the
392 // request is for this immediate canvas
393 if(id.find_first_of(':')==string::npos && id.find_first_of('#')==string::npos)
394 return value_node_list_.find(id);
396 String canvas_id(id,0,id.rfind(':'));
397 String value_node_id(id,id.rfind(':')+1);
398 if(canvas_id.empty())
400 //synfig::warning("constfind:value_node_id: "+value_node_id);
401 //synfig::warning("constfind:canvas_id: "+canvas_id);
403 return find_canvas(canvas_id)->value_node_list_.find(value_node_id);
407 Canvas::surefind_value_node(const String &id)
409 if(is_inline() && parent_)
410 return parent_->surefind_value_node(id);
413 throw Exception::IDNotFound("Empty ID");
415 // If we do not have any resolution, then we assume that the
416 // request is for this immediate canvas
417 if(id.find_first_of(':')==string::npos && id.find_first_of('#')==string::npos)
418 return value_node_list_.surefind(id);
420 String canvas_id(id,0,id.rfind(':'));
421 String value_node_id(id,id.rfind(':')+1);
422 if(canvas_id.empty())
425 return surefind_canvas(canvas_id)->value_node_list_.surefind(value_node_id);
429 Canvas::add_value_node(ValueNode::Handle x, const String &id)
431 if(is_inline() && parent_)
432 return parent_->add_value_node(x,id);
433 // throw runtime_error("You cannot add a ValueNode to an inline Canvas");
436 throw runtime_error("ValueNode is already exported");
439 throw Exception::BadLinkName("Empty ID");
441 if(id.find_first_of(':',0)!=string::npos)
442 throw Exception::BadLinkName("Bad character");
446 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
447 throw Exception::IDNotFound("add_value_node()");
449 throw Exception::IDAlreadyExists(id);
451 catch(Exception::IDNotFound)
455 x->set_parent_canvas(this);
457 if(!value_node_list_.add(x))
459 synfig::error("Unable to add ValueNode");
460 throw std::runtime_error("Unable to add ValueNode");
469 Canvas::rename_value_node(ValueNode::Handle x, const String &id)
472 throw Exception::BadLinkName("Empty ID");
474 if(id.find_first_of(": ",0)!=string::npos)
475 throw Exception::BadLinkName("Bad character");
479 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
480 throw Exception::IDNotFound("rename_value_node");
481 throw Exception::IDAlreadyExists(id);
483 catch(Exception::IDNotFound)
493 Canvas::remove_value_node(ValueNode::Handle x)
495 if(is_inline() && parent_)
496 return parent_->remove_value_node(x);
497 // throw Exception::IDNotFound("Canvas::remove_value_node() was called from an inline canvas");
500 throw Exception::IDNotFound("Canvas::remove_value_node() was passed empty handle");
502 if(!value_node_list_.erase(x))
503 throw Exception::IDNotFound("Canvas::remove_value_node(): ValueNode was not found inside of this canvas");
505 //x->set_parent_canvas(0);
512 Canvas::surefind_canvas(const String &id)
514 if(is_inline() && parent_)
515 return parent_->surefind_canvas(id);
520 // If the ID contains a "#" character, then a filename is
521 // expected on the left side.
522 if(id.find_first_of('#')!=string::npos)
524 // If '#' is the first character, remove it
525 // and attempt to parse the ID again.
527 return surefind_canvas(String(id,1));
529 //! \todo This needs a lot more optimization
530 String file_name(id,0,id.find_first_of('#'));
531 String external_id(id,id.find_first_of('#')+1);
533 file_name=unix_to_local_path(file_name);
535 Canvas::Handle external_canvas;
537 // If the composition is already open, then use it.
538 if(externals_.count(file_name))
539 external_canvas=externals_[file_name];
542 if(is_absolute_path(file_name))
543 external_canvas=open_canvas(file_name);
545 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name);
548 throw Exception::FileNotFound(file_name);
549 externals_[file_name]=external_canvas;
552 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
555 // If we do not have any resolution, then we assume that the
556 // request is for this immediate canvas
557 if(id.find_first_of(':')==string::npos)
559 Children::iterator iter;
561 // Search for the image in the image list,
562 // and return it if it is found
563 for(iter=children().begin();iter!=children().end();iter++)
564 if(id==(*iter)->get_id())
567 // Create a new canvas and return it
568 //synfig::warning("Implicitly creating canvas named "+id);
569 return new_child_canvas(id);
572 // If the first character is the separator, then
573 // this references the root canvas.
575 return get_root()->surefind_canvas(string(id,1));
577 // Now we know that the requested Canvas is in a child
578 // of this canvas. We have to find that canvas and
579 // call "find_canvas" on it, and return the result.
581 String canvas_name=string(id,0,id.find_first_of(':'));
583 Canvas::Handle child_canvas=surefind_canvas(canvas_name);
585 return child_canvas->surefind_canvas(string(id,id.find_first_of(':')+1));
589 Canvas::find_canvas(const String &id)
592 Canvas::Handle::cast_const(
593 const_cast<const Canvas*>(this)->find_canvas(id)
598 Canvas::find_canvas(const String &id)const
600 if(is_inline() && parent_)return parent_->find_canvas(id);
605 // If the ID contains a "#" character, then a filename is
606 // expected on the left side.
607 if(id.find_first_of('#')!=string::npos)
609 // If '#' is the first character, remove it
610 // and attempt to parse the ID again.
612 return find_canvas(String(id,1));
614 //! \todo This needs a lot more optimization
615 String file_name(id,0,id.find_first_of('#'));
616 String external_id(id,id.find_first_of('#')+1);
618 file_name=unix_to_local_path(file_name);
620 Canvas::Handle external_canvas;
622 // If the composition is already open, then use it.
623 if(externals_.count(file_name))
624 external_canvas=externals_[file_name];
627 if(is_absolute_path(file_name))
628 external_canvas=open_canvas(file_name);
630 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name);
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));
675 return new Canvas("Untitled");
679 Canvas::push_back(etl::handle<Layer> x)
681 // int i(x->count());
683 //if(x->count()!=i+1)synfig::info("push_back before %d, after %d",i,x->count());
687 Canvas::push_front(etl::handle<Layer> x)
689 // int i(x->count());
691 //if(x->count()!=i+1)synfig::error("push_front before %d, after %d",i,x->count());
695 Canvas::insert(iterator iter,etl::handle<Layer> x)
697 // int i(x->count());
698 CanvasBase::insert(iter,x);
700 /*if(x->count()!=i+1)
702 synfig::error(__FILE__":%d: Canvas::insert(): ***FAILURE*** before %d, after %d",__LINE__,i,x->count());
704 //throw runtime_error("Canvas Insertion Failed");
713 LooseHandle correct_canvas(this);
714 //while(correct_canvas->is_inline())correct_canvas=correct_canvas->parent();
715 Layer::LooseHandle loose_layer(x);
717 add_connection(loose_layer,
718 sigc::connection::connection(
719 x->signal_added_to_group().connect(
723 &Canvas::add_group_pair),
725 add_connection(loose_layer,
726 sigc::connection::connection(
727 x->signal_removed_from_group().connect(
731 &Canvas::remove_group_pair),
735 if(!x->get_group().empty())
736 add_group_pair(x->get_group(),x);
743 Canvas::push_back_simple(etl::handle<Layer> x)
745 CanvasBase::insert(end(),x);
750 Canvas::erase(iterator iter)
752 if(!(*iter)->get_group().empty())
753 remove_group_pair((*iter)->get_group(),(*iter));
755 // HACK: We really shouldn't be wiping
756 // out these signals entirely. We should
757 // only be removing the specific connections
758 // that we made. At the moment, I'm too
759 // lazy to add the code to keep track
760 // of those connections, and no one else
761 // is using these signals, so I'll just
762 // leave these next two lines like they
763 // are for now - darco 07-30-2004
765 // so don't wipe them out entirely
766 // - dooglus 09-21-2007
767 disconnect_connections(*iter);
769 if(!op_flag_)remove_child(iter->get());
771 CanvasBase::erase(iter);
772 if(!op_flag_)changed();
776 Canvas::clone(const GUID& deriv_guid)const
783 name=get_id()+"_CLONE";
785 throw runtime_error("Cloning of non-inline canvases is not yet supported");
788 Handle canvas(new Canvas(name));
792 canvas->is_inline_=true;
793 // \todo this was setting parent_=0 - is there a reason for that?
794 // this was causing bug 1838132, where cloning an inline canvas that contains an imported image fails
795 // it was failing to ascertain the absolute pathname of the imported image, since it needs the pathname
796 // of the canvas to get that, which is stored in the parent canvas
797 canvas->parent_=parent();
798 //canvas->set_inline(parent());
801 canvas->set_guid(get_guid()^deriv_guid);
804 for(iter=begin();iter!=end();++iter)
806 Layer::Handle layer((*iter)->clone(deriv_guid));
809 assert(layer.count()==1);
811 canvas->push_back(layer);
812 if(!(layer.count()>1))
814 synfig::error("Canvas::clone(): Cloned layer insertion failure!");
815 synfig::error("Canvas::clone(): \tlayer.count()=%d",layer.count());
816 synfig::error("Canvas::clone(): \tlayer->get_name()=%s",layer->get_name().c_str());
817 synfig::error("Canvas::clone(): \tbefore size()=%d",presize);
818 synfig::error("Canvas::clone(): \tafter size()=%d",size());
820 assert(layer.count()>1);
824 synfig::error("Unable to clone layer");
828 canvas->signal_group_pair_removed().clear();
829 canvas->signal_group_pair_added().clear();
835 Canvas::set_inline(LooseHandle parent)
837 if(is_inline_ && parent_)
846 // Have the parent inherit all of the group stuff
848 std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
850 for(iter=group_db_.begin();iter!=group_db_.end();++iter)
852 parent->group_db_[iter->first].insert(iter->second.begin(),iter->second.end());
855 rend_desc()=parent->rend_desc();
859 Canvas::create_inline(Handle parent)
862 //if(parent->is_inline())
863 // return create_inline(parent->parent());
865 Handle canvas(new Canvas("inline"));
866 canvas->set_inline(parent);
871 Canvas::new_child_canvas()
873 if(is_inline() && parent_)
874 return parent_->new_child_canvas();
875 // runtime_error("You cannot create a child Canvas in an inline Canvas");
877 // Create a new canvas
878 children().push_back(create());
879 Canvas::Handle canvas(children().back());
881 canvas->parent_=this;
883 canvas->rend_desc()=rend_desc();
889 Canvas::new_child_canvas(const String &id)
891 if(is_inline() && parent_)
892 return parent_->new_child_canvas(id);
893 // runtime_error("You cannot create a child Canvas in an inline Canvas");
895 // Create a new canvas
896 children().push_back(create());
897 Canvas::Handle canvas(children().back());
900 canvas->parent_=this;
901 canvas->rend_desc()=rend_desc();
907 Canvas::add_child_canvas(Canvas::Handle child_canvas, const synfig::String& id)
909 if(is_inline() && parent_)
910 return parent_->add_child_canvas(child_canvas,id);
912 if(child_canvas->parent() && !child_canvas->is_inline())
913 throw std::runtime_error("Cannot add child canvas because it belongs to someone else!");
916 throw runtime_error("Invalid ID");
921 throw Exception::IDAlreadyExists(id);
923 catch(Exception::IDNotFound)
925 if(child_canvas->is_inline())
926 child_canvas->is_inline_=false;
927 child_canvas->id_=id;
928 children().push_back(child_canvas);
929 child_canvas->parent_=this;
936 Canvas::remove_child_canvas(Canvas::Handle child_canvas)
938 if(is_inline() && parent_)
939 return parent_->remove_child_canvas(child_canvas);
941 if(child_canvas->parent_!=this)
942 throw runtime_error("Given child does not belong to me");
944 if(find(children().begin(),children().end(),child_canvas)==children().end())
945 throw Exception::IDNotFound(child_canvas->get_id());
947 children().remove(child_canvas);
949 child_canvas->parent_=0;
953 Canvas::set_file_name(const String &file_name)
956 parent()->set_file_name(file_name);
959 file_name_=file_name;
960 signal_file_name_changed_();
965 Canvas::signal_file_name_changed()
968 return signal_file_name_changed();
970 return signal_file_name_changed_;
974 Canvas::get_file_name()const
977 return parent()->get_file_name();
982 Canvas::get_file_path()const
985 return parent()->get_file_path();
986 return dirname(file_name_);
991 Canvas::get_meta_data(const String& key)const
993 if(!meta_data_.count(key))
995 return meta_data_.find(key)->second;
999 Canvas::set_meta_data(const String& key, const String& data)
1001 if(meta_data_[key]!=data)
1003 meta_data_[key]=data;
1004 signal_meta_data_changed()(key);
1005 signal_meta_data_changed(key)();
1010 Canvas::erase_meta_data(const String& key)
1012 if(meta_data_.count(key))
1014 meta_data_.erase(key);
1015 signal_meta_data_changed()(key);
1016 signal_meta_data_changed(key)();
1021 Canvas::get_meta_data_keys()const
1023 std::list<String> ret;
1025 std::map<String,String>::const_iterator iter;
1027 for(iter=meta_data_.begin();!(iter==meta_data_.end());++iter)
1028 ret.push_back(iter->first);
1033 /* note - the "Motion Blur" and "Duplicate" layers need the dynamic
1034 parameters of any PasteCanvas layers they loop over to be
1035 maintained. When the variables in the following function
1036 refer to "motion blur", they mean either of these two
1039 synfig::optimize_layers(Time time, Context context, Canvas::Handle op_canvas, bool seen_motion_blur_in_parent)
1043 std::vector< std::pair<float,Layer::Handle> > sort_list;
1044 int i, motion_blur_i=0; // motion_blur_i is for resolving which layer comes first in the event of a z_depth tie
1045 float motion_blur_z_depth=0; // the z_depth of the least deep motion blur layer in this context
1046 bool seen_motion_blur_locally = false;
1047 bool motion_blurred; // the final result - is this layer blurred or not?
1049 // If the parent didn't cause us to already be motion blurred,
1050 // check whether there's a motion blur in this context,
1051 // and if so, calculate its z_depth.
1052 if (!seen_motion_blur_in_parent)
1053 for(iter=context,i=0;*iter;iter++,i++)
1055 Layer::Handle layer=*iter;
1057 // If the layer isn't active, don't worry about it
1058 if(!layer->active())
1061 // Any layer with an amount of zero is implicitly disabled.
1062 ValueBase value(layer->get_param("amount"));
1063 if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1066 if(layer->get_name()=="MotionBlur" || layer->get_name()=="duplicate")
1068 float z_depth(layer->get_z_depth()*1.0001+i);
1070 // If we've seen a motion blur before in this context...
1071 if (seen_motion_blur_locally)
1073 // ... then we're only interested in this one if it's less deep...
1074 if (z_depth < motion_blur_z_depth)
1076 motion_blur_z_depth = z_depth;
1080 // ... otherwise we're always interested in it.
1083 motion_blur_z_depth = z_depth;
1085 seen_motion_blur_locally = true;
1090 // Go ahead and start romping through the canvas to paste
1091 for(iter=context,i=0;*iter;iter++,i++)
1093 Layer::Handle layer=*iter;
1094 float z_depth(layer->get_z_depth()*1.0001+i);
1096 // If the layer isn't active, don't worry about it
1097 if(!layer->active())
1100 // Any layer with an amount of zero is implicitly disabled.
1101 ValueBase value(layer->get_param("amount"));
1102 if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1105 // note: this used to include "&& paste_canvas->get_time_offset()==0", but then
1106 // time-shifted layers weren't being sorted by z-depth (bug #1806852)
1107 if(layer->get_name()=="PasteCanvas")
1109 Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1111 // we need to blur the sub canvas if:
1112 // our parent is blurred,
1113 // or the child is lower than a local blur,
1114 // or the child is at the same z_depth as a local blur, but later in the context
1117 if (seen_motion_blur_in_parent) synfig::info("seen BLUR in parent\n");
1118 else if (seen_motion_blur_locally)
1119 if (z_depth > motion_blur_z_depth) synfig::info("paste is deeper than BLUR\n");
1120 else if (z_depth == motion_blur_z_depth) { synfig::info("paste is same depth as BLUR\n");
1121 if (i > motion_blur_i) synfig::info("paste is physically deeper than BLUR\n");
1122 else synfig::info("paste is less physically deep than BLUR\n");
1123 } else synfig::info("paste is less deep than BLUR\n");
1124 else synfig::info("no BLUR at all\n");
1127 motion_blurred = (seen_motion_blur_in_parent ||
1128 (seen_motion_blur_locally &&
1129 (z_depth > motion_blur_z_depth ||
1130 (z_depth == motion_blur_z_depth && i > motion_blur_i))));
1132 Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
1133 Canvas::Handle paste_sub_canvas = paste_canvas->get_sub_canvas();
1134 if(paste_sub_canvas)
1135 optimize_layers(time, paste_sub_canvas->get_context(),sub_canvas,motion_blurred);
1137 // \todo: uncommenting the following breaks the rendering of at least examples/backdrop.sifz quite severely
1138 // #define SYNFIG_OPTIMIZE_PASTE_CANVAS
1139 #ifdef SYNFIG_OPTIMIZE_PASTE_CANVAS
1140 Canvas::iterator sub_iter;
1142 // Determine if we can just remove the paste canvas altogether
1143 if (paste_canvas->get_blend_method() == Color::BLEND_COMPOSITE &&
1144 paste_canvas->get_amount() == 1.0f &&
1145 paste_canvas->get_zoom() == 0 &&
1146 paste_canvas->get_time_offset() == 0 &&
1147 paste_canvas->get_origin() == Point(0,0) )
1149 for(sub_iter=sub_canvas->begin();sub_iter!=sub_canvas->end();++sub_iter)
1151 Layer* layer=sub_iter->get();
1153 // any layers that deform end up breaking things
1154 // so do things the old way if we run into anything like this
1155 if(!dynamic_cast<Layer_NoDeform*>(layer))
1158 ValueBase value(layer->get_param("blend_method"));
1159 if(value.get_type()!=ValueBase::TYPE_INTEGER || value.get(int())!=(int)Color::BLEND_COMPOSITE)
1163 // It has turned out that we don't need a paste canvas
1164 // layer, so just go ahead and add all the layers onto
1165 // the current stack and be done with it
1166 while(sub_canvas->size())
1168 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,sub_canvas->front()));
1169 //op_canvas->push_back_simple(sub_canvas->front());
1170 sub_canvas->pop_front();
1176 #endif // SYNFIG_OPTIMIZE_PASTE_CANVAS
1178 Layer::Handle new_layer(Layer::create("PasteCanvas"));
1179 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(false);
1182 Layer::DynamicParamList dynamic_param_list(paste_canvas->dynamic_param_list());
1183 for(Layer::DynamicParamList::const_iterator iter(dynamic_param_list.begin()); iter != dynamic_param_list.end(); ++iter)
1184 new_layer->connect_dynamic_param(iter->first, iter->second);
1186 Layer::ParamList param_list(paste_canvas->get_param_list());
1187 //param_list.erase("canvas");
1188 new_layer->set_param_list(param_list);
1189 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_sub_canvas(sub_canvas);
1190 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(true);
1193 else // not a PasteCanvas - does it use blend method 'Straight'?
1195 /* when we use the 'straight' blend method, every pixel on the layer affects the layers underneath,
1196 * not just the non-transparent pixels; the following workarea wraps non-pastecanvas layers in a
1197 * new pastecanvas to ensure that the straight blend affects the full plane, not just the area
1198 * within the layer's bounding box
1201 // \todo: this code probably needs modification to work properly with motionblur and duplicate
1202 etl::handle<Layer_Composite> composite = etl::handle<Layer_Composite>::cast_dynamic(layer);
1204 /* some layers (such as circle) don't touch pixels that aren't
1205 * part of the circle, so they don't get blended correctly when
1206 * using a straight blend. so we encapsulate the circle, and the
1207 * encapsulation layer takes care of the transparent pixels
1208 * for us. if we do that for all layers, however, then the
1209 * distortion layers no longer work, since they have no
1210 * context to work on. the Layer::reads_context() method
1211 * returns true for layers which need to be able to see
1212 * their context. we can't encapsulate those.
1215 Color::is_straight(composite->get_blend_method()) &&
1216 !composite->reads_context())
1218 Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
1219 sub_canvas->push_back(composite = composite->clone());
1220 layer = Layer::create("PasteCanvas");
1221 composite->set_description(strprintf("Wrapped clone of '%s'", composite->get_non_empty_description().c_str()));
1222 layer->set_description(strprintf("PasteCanvas wrapper for '%s'", composite->get_non_empty_description().c_str()));
1223 Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1224 paste_canvas->set_blend_method(composite->get_blend_method());
1225 paste_canvas->set_amount(composite->get_amount());
1226 sub_canvas->set_time(time); // region and outline don't calculate their bounding rects until their time is set
1227 composite->set_blend_method(Color::BLEND_STRAIGHT); // do this before calling set_sub_canvas(), but after set_time()
1228 composite->set_amount(1.0f); // after set_time()
1229 paste_canvas->set_sub_canvas(sub_canvas);
1233 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,layer));
1234 //op_canvas->push_back_simple(layer);
1238 stable_sort(sort_list.begin(),sort_list.end());
1239 std::vector< std::pair<float,Layer::Handle> >::iterator iter2;
1240 for(iter2=sort_list.begin();iter2!=sort_list.end();++iter2)
1241 op_canvas->push_back_simple(iter2->second);
1242 op_canvas->op_flag_=true;
1246 Canvas::get_times_vfunc(Node::time_set &set) const
1248 const_iterator i = begin(),
1251 for(; i != iend; ++i)
1253 const Node::time_set &tset = (*i)->get_times();
1254 set.insert(tset.begin(),tset.end());
1258 std::set<etl::handle<Layer> >
1259 Canvas::get_layers_in_group(const String&group)
1261 if(is_inline() && parent_)
1262 return parent_->get_layers_in_group(group);
1264 if(group_db_.count(group)==0)
1265 return std::set<etl::handle<Layer> >();
1266 return group_db_.find(group)->second;
1270 Canvas::get_groups()const
1272 if(is_inline() && parent_)
1273 return parent_->get_groups();
1275 std::set<String> ret;
1276 std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
1277 for(iter=group_db_.begin();iter!=group_db_.end();++iter)
1278 ret.insert(iter->first);
1283 Canvas::get_group_count()const
1285 if(is_inline() && parent_)
1286 return parent_->get_group_count();
1288 return group_db_.size();
1292 Canvas::add_group_pair(String group, etl::handle<Layer> layer)
1294 group_db_[group].insert(layer);
1295 if(group_db_[group].size()==1)
1296 signal_group_added()(group);
1298 signal_group_changed()(group);
1300 signal_group_pair_added()(group,layer);
1302 if(is_inline() && parent_)
1303 return parent_->add_group_pair(group,layer);
1307 Canvas::remove_group_pair(String group, etl::handle<Layer> layer)
1309 group_db_[group].erase(layer);
1311 signal_group_pair_removed()(group,layer);
1313 if(group_db_[group].empty())
1315 group_db_.erase(group);
1316 signal_group_removed()(group);
1319 signal_group_changed()(group);
1321 if(is_inline() && parent_)
1322 return parent_->remove_group_pair(group,layer);
1326 Canvas::add_connection(etl::loose_handle<Layer> layer, sigc::connection connection)
1328 connections_[layer].push_back(connection);
1332 Canvas::disconnect_connections(etl::loose_handle<Layer> layer)
1334 std::vector<sigc::connection>::iterator iter;
1335 for(iter=connections_[layer].begin();iter!=connections_[layer].end();++iter)
1337 connections_[layer].clear();
1341 Canvas::rename_group(const String&old_name,const String&new_name)
1343 if(is_inline() && parent_)
1344 return parent_->rename_group(old_name,new_name);
1347 std::map<String,std::set<etl::handle<Layer> > >::iterator iter;
1348 iter=group_db_.find(old_name);
1349 if(iter!=group_db_.end())
1350 for(++iter;iter!=group_db_.end() && iter->first.find(old_name)==0;iter=group_db_.find(old_name),++iter)
1352 String name(iter->first,old_name.size(),String::npos);
1354 rename_group(iter->first,name);
1358 std::set<etl::handle<Layer> > layers(get_layers_in_group(old_name));
1359 std::set<etl::handle<Layer> >::iterator iter;
1361 for(iter=layers.begin();iter!=layers.end();++iter)
1363 (*iter)->remove_from_group(old_name);
1364 (*iter)->add_to_group(new_name);