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 bool keep_going = true;
95 // we were having a crash where pastecanvas layers were still
96 // refering to a canvas after it had been destroyed; this code
97 // will stop the pastecanvas layers from refering to the canvas
98 // before the canvas is destroyed
100 // the set_sub_canvas(0) ends up deleting the parent-child link,
101 // which modifies the set we're iterating through, invalidating
102 // the set iterator. the outer while loop makes sure that we
103 // recreate the set iterator each time the set itself is modified
106 keep_going = false; // only keep going if we find a pastecanvas parent to clear
107 for (std::set<Node*>::iterator iter = parent_set.begin(); iter != parent_set.end(); iter++)
109 Layer_PasteCanvas* paste_canvas = dynamic_cast<Layer_PasteCanvas*>(*iter);
112 paste_canvas->set_sub_canvas(0);
114 break; // out of the for loop to the while loop
117 warning("destroyed canvas has a parent that is not a pastecanvas - please report if repeatable");
121 //if(is_inline() && parent_) assert(0);
122 _CanvasCounter::counter--;
130 return CanvasBase::end()-1;
133 Canvas::const_iterator
136 return CanvasBase::end()-1;
139 Canvas::reverse_iterator
142 return CanvasBase::rbegin()+1;
145 Canvas::const_reverse_iterator
146 Canvas::rbegin()const
148 return CanvasBase::rbegin()+1;
154 return CanvasBase::size()-1;
162 Layer::Handle layer(front());
163 //if(layer->count()>2)synfig::info("before layer->count()=%d",layer->count());
166 //if(layer->count()>1)synfig::info("after layer->count()=%d",layer->count());
168 //CanvasBase::clear();
170 // We need to keep a blank handle at the
171 // end of the image list, and acts at
172 // the bottom. Without it, the layers
173 // would just continue going when polled
175 CanvasBase::push_back(Layer::Handle());
183 return CanvasBase::size()<=1;
189 return *(CanvasBase::end()-1);
192 const Layer::Handle &
195 return *(CanvasBase::end()-1);
199 Canvas::get_context()const
204 const ValueNodeList &
205 Canvas::value_node_list()const
207 if(is_inline() && parent_)
208 return parent_->value_node_list();
209 return value_node_list_;
213 Canvas::keyframe_list()
215 if(is_inline() && parent_)
216 return parent_->keyframe_list();
217 return keyframe_list_;
221 Canvas::keyframe_list()const
223 if(is_inline() && parent_)
224 return parent_->keyframe_list();
225 return keyframe_list_;
229 Canvas::find_layer(const Point &pos)
231 return get_context().hit_check(pos);
235 valid_id(const String &x)
237 static const char bad_chars[]=" :#@$^&()*";
240 if(!x.empty() && x[0]>='0' && x[0]<='9')
243 for(i=0;i<sizeof(bad_chars);i++)
244 if(x.find_first_of(bad_chars[i])!=string::npos)
251 Canvas::set_id(const String &x)
253 if(is_inline() && parent_)
254 throw runtime_error("Inline Canvas cannot have an ID");
257 throw runtime_error("Invalid ID");
259 signal_id_changed_();
263 Canvas::set_name(const String &x)
266 signal_meta_data_changed()("name");
267 signal_meta_data_changed("name")();
271 Canvas::set_author(const String &x)
274 signal_meta_data_changed()("author");
275 signal_meta_data_changed("author")();
279 Canvas::set_description(const String &x)
282 signal_meta_data_changed()("description");
283 signal_meta_data_changed("description")();
287 Canvas::set_time(Time t)const
289 if(is_dirty_ || !get_time().is_equal(t))
294 synfig::info("is_dirty_=%d",is_dirty_);
295 synfig::info("get_time()=%f",(float)get_time());
296 synfig::info("t=%f",(float)t);
301 const_cast<Canvas&>(*this).cur_time_=t;
304 get_context().set_time(t);
310 Canvas::get_root()const
312 return parent_?parent_->get_root().get():const_cast<synfig::Canvas *>(this);
316 Canvas::get_depth(etl::handle<Layer> layer)const
320 for(iter=begin();iter!=end();++iter,i++)
329 Canvas::get_relative_id(etl::loose_handle<const Canvas> x)const
331 if(x->get_root()==this)
333 if(is_inline() && parent_)
334 return parent_->_get_relative_id(x);
335 return _get_relative_id(x);
339 Canvas::_get_relative_id(etl::loose_handle<const Canvas> x)const
341 if(is_inline() && parent_)
342 return parent_->_get_relative_id(x);
347 if(parent()==x.get())
352 const Canvas* canvas=this;
354 for(;!canvas->is_root();canvas=canvas->parent().get())
355 id=':'+canvas->get_id()+id;
357 if(x && get_root()!=x->get_root())
359 //String file_name=get_file_name();
360 //String file_path=x->get_file_path();
363 if(is_absolute_path(get_file_name()))
364 file_name=etl::relative_path(x->get_file_path(),get_file_name());
366 file_name=get_file_name();
368 // If the path of X is inside of file_name,
370 //if(file_name.size()>file_path.size())
371 // if(file_path==String(file_name,0,file_path.size()))
372 // file_name.erase(0,file_path.size()+1);
382 Canvas::find_value_node(const String &id)
385 ValueNode::Handle::cast_const(
386 const_cast<const Canvas*>(this)->find_value_node(id)
390 ValueNode::ConstHandle
391 Canvas::find_value_node(const String &id)const
393 if(is_inline() && parent_)
394 return parent_->find_value_node(id);
397 throw Exception::IDNotFound("Empty ID");
399 // If we do not have any resolution, then we assume that the
400 // request is for this immediate canvas
401 if(id.find_first_of(':')==string::npos && id.find_first_of('#')==string::npos)
402 return value_node_list_.find(id);
404 String canvas_id(id,0,id.rfind(':'));
405 String value_node_id(id,id.rfind(':')+1);
406 if(canvas_id.empty())
408 //synfig::warning("constfind:value_node_id: "+value_node_id);
409 //synfig::warning("constfind:canvas_id: "+canvas_id);
411 return find_canvas(canvas_id)->value_node_list_.find(value_node_id);
415 Canvas::surefind_value_node(const String &id)
417 if(is_inline() && parent_)
418 return parent_->surefind_value_node(id);
421 throw Exception::IDNotFound("Empty ID");
423 // If we do not have any resolution, then we assume that the
424 // request is for this immediate canvas
425 if(id.find_first_of(':')==string::npos && id.find_first_of('#')==string::npos)
426 return value_node_list_.surefind(id);
428 String canvas_id(id,0,id.rfind(':'));
429 String value_node_id(id,id.rfind(':')+1);
430 if(canvas_id.empty())
433 return surefind_canvas(canvas_id)->value_node_list_.surefind(value_node_id);
437 Canvas::add_value_node(ValueNode::Handle x, const String &id)
439 if(is_inline() && parent_)
440 return parent_->add_value_node(x,id);
441 // throw runtime_error("You cannot add a ValueNode to an inline Canvas");
444 throw runtime_error("ValueNode is already exported");
447 throw Exception::BadLinkName("Empty ID");
449 if(id.find_first_of(':',0)!=string::npos)
450 throw Exception::BadLinkName("Bad character");
454 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
455 throw Exception::IDNotFound("add_value_node()");
457 throw Exception::IDAlreadyExists(id);
459 catch(Exception::IDNotFound)
463 x->set_parent_canvas(this);
465 if(!value_node_list_.add(x))
467 synfig::error("Unable to add ValueNode");
468 throw std::runtime_error("Unable to add ValueNode");
477 Canvas::rename_value_node(ValueNode::Handle x, const String &id)
480 throw Exception::BadLinkName("Empty ID");
482 if(id.find_first_of(": ",0)!=string::npos)
483 throw Exception::BadLinkName("Bad character");
487 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
488 throw Exception::IDNotFound("rename_value_node");
489 throw Exception::IDAlreadyExists(id);
491 catch(Exception::IDNotFound)
501 Canvas::remove_value_node(ValueNode::Handle x)
503 if(is_inline() && parent_)
504 return parent_->remove_value_node(x);
505 // throw Exception::IDNotFound("Canvas::remove_value_node() was called from an inline canvas");
508 throw Exception::IDNotFound("Canvas::remove_value_node() was passed empty handle");
510 if(!value_node_list_.erase(x))
511 throw Exception::IDNotFound("Canvas::remove_value_node(): ValueNode was not found inside of this canvas");
513 //x->set_parent_canvas(0);
520 Canvas::surefind_canvas(const String &id)
522 if(is_inline() && parent_)
523 return parent_->surefind_canvas(id);
528 // If the ID contains a "#" character, then a filename is
529 // expected on the left side.
530 if(id.find_first_of('#')!=string::npos)
532 // If '#' is the first character, remove it
533 // and attempt to parse the ID again.
535 return surefind_canvas(String(id,1));
537 //! \todo This needs a lot more optimization
538 String file_name(id,0,id.find_first_of('#'));
539 String external_id(id,id.find_first_of('#')+1);
541 file_name=unix_to_local_path(file_name);
543 Canvas::Handle external_canvas;
545 // If the composition is already open, then use it.
546 if(externals_.count(file_name))
547 external_canvas=externals_[file_name];
550 if(is_absolute_path(file_name))
551 external_canvas=open_canvas(file_name);
553 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name);
556 throw Exception::FileNotFound(file_name);
557 externals_[file_name]=external_canvas;
560 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
563 // If we do not have any resolution, then we assume that the
564 // request is for this immediate canvas
565 if(id.find_first_of(':')==string::npos)
567 Children::iterator iter;
569 // Search for the image in the image list,
570 // and return it if it is found
571 for(iter=children().begin();iter!=children().end();iter++)
572 if(id==(*iter)->get_id())
575 // Create a new canvas and return it
576 //synfig::warning("Implicitly creating canvas named "+id);
577 return new_child_canvas(id);
580 // If the first character is the separator, then
581 // this references the root canvas.
583 return get_root()->surefind_canvas(string(id,1));
585 // Now we know that the requested Canvas is in a child
586 // of this canvas. We have to find that canvas and
587 // call "find_canvas" on it, and return the result.
589 String canvas_name=string(id,0,id.find_first_of(':'));
591 Canvas::Handle child_canvas=surefind_canvas(canvas_name);
593 return child_canvas->surefind_canvas(string(id,id.find_first_of(':')+1));
597 Canvas::find_canvas(const String &id)
600 Canvas::Handle::cast_const(
601 const_cast<const Canvas*>(this)->find_canvas(id)
606 Canvas::find_canvas(const String &id)const
608 if(is_inline() && parent_)return parent_->find_canvas(id);
613 // If the ID contains a "#" character, then a filename is
614 // expected on the left side.
615 if(id.find_first_of('#')!=string::npos)
617 // If '#' is the first character, remove it
618 // and attempt to parse the ID again.
620 return find_canvas(String(id,1));
622 //! \todo This needs a lot more optimization
623 String file_name(id,0,id.find_first_of('#'));
624 String external_id(id,id.find_first_of('#')+1);
626 file_name=unix_to_local_path(file_name);
628 Canvas::Handle external_canvas;
630 // If the composition is already open, then use it.
631 if(externals_.count(file_name))
632 external_canvas=externals_[file_name];
635 if(is_absolute_path(file_name))
636 external_canvas=open_canvas(file_name);
638 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name);
641 throw Exception::FileNotFound(file_name);
642 externals_[file_name]=external_canvas;
645 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
648 // If we do not have any resolution, then we assume that the
649 // request is for this immediate canvas
650 if(id.find_first_of(':')==string::npos)
652 Children::const_iterator iter;
654 // Search for the image in the image list,
655 // and return it if it is found
656 for(iter=children().begin();iter!=children().end();iter++)
657 if(id==(*iter)->get_id())
660 throw Exception::IDNotFound("Child Canvas in Parent Canvas: (child)"+id);
663 // If the first character is the separator, then
664 // this references the root canvas.
665 if(id.find_first_of(':')==0)
666 return get_root()->find_canvas(string(id,1));
668 // Now we know that the requested Canvas is in a child
669 // of this canvas. We have to find that canvas and
670 // call "find_canvas" on it, and return the result.
672 String canvas_name=string(id,0,id.find_first_of(':'));
674 Canvas::ConstHandle child_canvas=find_canvas(canvas_name);
676 return child_canvas->find_canvas(string(id,id.find_first_of(':')+1));
683 return new Canvas("Untitled");
687 Canvas::push_back(etl::handle<Layer> x)
689 // int i(x->count());
691 //if(x->count()!=i+1)synfig::info("push_back before %d, after %d",i,x->count());
695 Canvas::push_front(etl::handle<Layer> x)
697 // int i(x->count());
699 //if(x->count()!=i+1)synfig::error("push_front before %d, after %d",i,x->count());
703 Canvas::insert(iterator iter,etl::handle<Layer> x)
705 // int i(x->count());
706 CanvasBase::insert(iter,x);
708 /*if(x->count()!=i+1)
710 synfig::error(__FILE__":%d: Canvas::insert(): ***FAILURE*** before %d, after %d",__LINE__,i,x->count());
712 //throw runtime_error("Canvas Insertion Failed");
721 LooseHandle correct_canvas(this);
722 //while(correct_canvas->is_inline())correct_canvas=correct_canvas->parent();
723 Layer::LooseHandle loose_layer(x);
725 add_connection(loose_layer,
726 sigc::connection::connection(
727 x->signal_added_to_group().connect(
731 &Canvas::add_group_pair),
733 add_connection(loose_layer,
734 sigc::connection::connection(
735 x->signal_removed_from_group().connect(
739 &Canvas::remove_group_pair),
743 if(!x->get_group().empty())
744 add_group_pair(x->get_group(),x);
751 Canvas::push_back_simple(etl::handle<Layer> x)
753 CanvasBase::insert(end(),x);
758 Canvas::erase(iterator iter)
760 if(!(*iter)->get_group().empty())
761 remove_group_pair((*iter)->get_group(),(*iter));
763 // HACK: We really shouldn't be wiping
764 // out these signals entirely. We should
765 // only be removing the specific connections
766 // that we made. At the moment, I'm too
767 // lazy to add the code to keep track
768 // of those connections, and no one else
769 // is using these signals, so I'll just
770 // leave these next two lines like they
771 // are for now - darco 07-30-2004
773 // so don't wipe them out entirely
774 // - dooglus 09-21-2007
775 disconnect_connections(*iter);
777 if(!op_flag_)remove_child(iter->get());
779 CanvasBase::erase(iter);
780 if(!op_flag_)changed();
784 Canvas::clone(const GUID& deriv_guid)const
791 name=get_id()+"_CLONE";
793 throw runtime_error("Cloning of non-inline canvases is not yet supported");
796 Handle canvas(new Canvas(name));
800 canvas->is_inline_=true;
801 // \todo this was setting parent_=0 - is there a reason for that?
802 // this was causing bug 1838132, where cloning an inline canvas that contains an imported image fails
803 // it was failing to ascertain the absolute pathname of the imported image, since it needs the pathname
804 // of the canvas to get that, which is stored in the parent canvas
805 canvas->parent_=parent();
806 //canvas->set_inline(parent());
809 canvas->set_guid(get_guid()^deriv_guid);
812 for(iter=begin();iter!=end();++iter)
814 Layer::Handle layer((*iter)->clone(deriv_guid));
817 assert(layer.count()==1);
819 canvas->push_back(layer);
820 if(!(layer.count()>1))
822 synfig::error("Canvas::clone(): Cloned layer insertion failure!");
823 synfig::error("Canvas::clone(): \tlayer.count()=%d",layer.count());
824 synfig::error("Canvas::clone(): \tlayer->get_name()=%s",layer->get_name().c_str());
825 synfig::error("Canvas::clone(): \tbefore size()=%d",presize);
826 synfig::error("Canvas::clone(): \tafter size()=%d",size());
828 assert(layer.count()>1);
832 synfig::error("Unable to clone layer");
836 canvas->signal_group_pair_removed().clear();
837 canvas->signal_group_pair_added().clear();
843 Canvas::set_inline(LooseHandle parent)
845 if(is_inline_ && parent_)
854 // Have the parent inherit all of the group stuff
856 std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
858 for(iter=group_db_.begin();iter!=group_db_.end();++iter)
860 parent->group_db_[iter->first].insert(iter->second.begin(),iter->second.end());
863 rend_desc()=parent->rend_desc();
867 Canvas::create_inline(Handle parent)
870 //if(parent->is_inline())
871 // return create_inline(parent->parent());
873 Handle canvas(new Canvas("inline"));
874 canvas->set_inline(parent);
879 Canvas::new_child_canvas()
881 if(is_inline() && parent_)
882 return parent_->new_child_canvas();
883 // runtime_error("You cannot create a child Canvas in an inline Canvas");
885 // Create a new canvas
886 children().push_back(create());
887 Canvas::Handle canvas(children().back());
889 canvas->parent_=this;
891 canvas->rend_desc()=rend_desc();
897 Canvas::new_child_canvas(const String &id)
899 if(is_inline() && parent_)
900 return parent_->new_child_canvas(id);
901 // runtime_error("You cannot create a child Canvas in an inline Canvas");
903 // Create a new canvas
904 children().push_back(create());
905 Canvas::Handle canvas(children().back());
908 canvas->parent_=this;
909 canvas->rend_desc()=rend_desc();
915 Canvas::add_child_canvas(Canvas::Handle child_canvas, const synfig::String& id)
917 if(is_inline() && parent_)
918 return parent_->add_child_canvas(child_canvas,id);
920 if(child_canvas->parent() && !child_canvas->is_inline())
921 throw std::runtime_error("Cannot add child canvas because it belongs to someone else!");
924 throw runtime_error("Invalid ID");
929 throw Exception::IDAlreadyExists(id);
931 catch(Exception::IDNotFound)
933 if(child_canvas->is_inline())
934 child_canvas->is_inline_=false;
935 child_canvas->id_=id;
936 children().push_back(child_canvas);
937 child_canvas->parent_=this;
944 Canvas::remove_child_canvas(Canvas::Handle child_canvas)
946 if(is_inline() && parent_)
947 return parent_->remove_child_canvas(child_canvas);
949 if(child_canvas->parent_!=this)
950 throw runtime_error("Given child does not belong to me");
952 if(find(children().begin(),children().end(),child_canvas)==children().end())
953 throw Exception::IDNotFound(child_canvas->get_id());
955 children().remove(child_canvas);
957 child_canvas->parent_=0;
961 Canvas::set_file_name(const String &file_name)
964 parent()->set_file_name(file_name);
967 file_name_=file_name;
968 signal_file_name_changed_();
973 Canvas::signal_file_name_changed()
976 return signal_file_name_changed();
978 return signal_file_name_changed_;
982 Canvas::get_file_name()const
985 return parent()->get_file_name();
990 Canvas::get_file_path()const
993 return parent()->get_file_path();
994 return dirname(file_name_);
999 Canvas::get_meta_data(const String& key)const
1001 if(!meta_data_.count(key))
1003 return meta_data_.find(key)->second;
1007 Canvas::set_meta_data(const String& key, const String& data)
1009 if(meta_data_[key]!=data)
1011 meta_data_[key]=data;
1012 signal_meta_data_changed()(key);
1013 signal_meta_data_changed(key)();
1018 Canvas::erase_meta_data(const String& key)
1020 if(meta_data_.count(key))
1022 meta_data_.erase(key);
1023 signal_meta_data_changed()(key);
1024 signal_meta_data_changed(key)();
1029 Canvas::get_meta_data_keys()const
1031 std::list<String> ret;
1033 std::map<String,String>::const_iterator iter;
1035 for(iter=meta_data_.begin();!(iter==meta_data_.end());++iter)
1036 ret.push_back(iter->first);
1041 /* note - the "Motion Blur" and "Duplicate" layers need the dynamic
1042 parameters of any PasteCanvas layers they loop over to be
1043 maintained. When the variables in the following function
1044 refer to "motion blur", they mean either of these two
1047 synfig::optimize_layers(Time time, Context context, Canvas::Handle op_canvas, bool seen_motion_blur_in_parent)
1051 std::vector< std::pair<float,Layer::Handle> > sort_list;
1052 int i, motion_blur_i=0; // motion_blur_i is for resolving which layer comes first in the event of a z_depth tie
1053 float motion_blur_z_depth=0; // the z_depth of the least deep motion blur layer in this context
1054 bool seen_motion_blur_locally = false;
1055 bool motion_blurred; // the final result - is this layer blurred or not?
1057 // If the parent didn't cause us to already be motion blurred,
1058 // check whether there's a motion blur in this context,
1059 // and if so, calculate its z_depth.
1060 if (!seen_motion_blur_in_parent)
1061 for(iter=context,i=0;*iter;iter++,i++)
1063 Layer::Handle layer=*iter;
1065 // If the layer isn't active, don't worry about it
1066 if(!layer->active())
1069 // Any layer with an amount of zero is implicitly disabled.
1070 ValueBase value(layer->get_param("amount"));
1071 if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1074 if(layer->get_name()=="MotionBlur" || layer->get_name()=="duplicate")
1076 float z_depth(layer->get_z_depth()*1.0001+i);
1078 // If we've seen a motion blur before in this context...
1079 if (seen_motion_blur_locally)
1081 // ... then we're only interested in this one if it's less deep...
1082 if (z_depth < motion_blur_z_depth)
1084 motion_blur_z_depth = z_depth;
1088 // ... otherwise we're always interested in it.
1091 motion_blur_z_depth = z_depth;
1093 seen_motion_blur_locally = true;
1098 // Go ahead and start romping through the canvas to paste
1099 for(iter=context,i=0;*iter;iter++,i++)
1101 Layer::Handle layer=*iter;
1102 float z_depth(layer->get_z_depth()*1.0001+i);
1104 // If the layer isn't active, don't worry about it
1105 if(!layer->active())
1108 // Any layer with an amount of zero is implicitly disabled.
1109 ValueBase value(layer->get_param("amount"));
1110 if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1113 // note: this used to include "&& paste_canvas->get_time_offset()==0", but then
1114 // time-shifted layers weren't being sorted by z-depth (bug #1806852)
1115 if(layer->get_name()=="PasteCanvas")
1117 Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1119 // we need to blur the sub canvas if:
1120 // our parent is blurred,
1121 // or the child is lower than a local blur,
1122 // or the child is at the same z_depth as a local blur, but later in the context
1125 if (seen_motion_blur_in_parent) synfig::info("seen BLUR in parent\n");
1126 else if (seen_motion_blur_locally)
1127 if (z_depth > motion_blur_z_depth) synfig::info("paste is deeper than BLUR\n");
1128 else if (z_depth == motion_blur_z_depth) { synfig::info("paste is same depth as BLUR\n");
1129 if (i > motion_blur_i) synfig::info("paste is physically deeper than BLUR\n");
1130 else synfig::info("paste is less physically deep than BLUR\n");
1131 } else synfig::info("paste is less deep than BLUR\n");
1132 else synfig::info("no BLUR at all\n");
1135 motion_blurred = (seen_motion_blur_in_parent ||
1136 (seen_motion_blur_locally &&
1137 (z_depth > motion_blur_z_depth ||
1138 (z_depth == motion_blur_z_depth && i > motion_blur_i))));
1140 Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
1141 Canvas::Handle paste_sub_canvas = paste_canvas->get_sub_canvas();
1142 if(paste_sub_canvas)
1143 optimize_layers(time, paste_sub_canvas->get_context(),sub_canvas,motion_blurred);
1145 // \todo: uncommenting the following breaks the rendering of at least examples/backdrop.sifz quite severely
1146 // #define SYNFIG_OPTIMIZE_PASTE_CANVAS
1147 #ifdef SYNFIG_OPTIMIZE_PASTE_CANVAS
1148 Canvas::iterator sub_iter;
1150 // Determine if we can just remove the paste canvas altogether
1151 if (paste_canvas->get_blend_method() == Color::BLEND_COMPOSITE &&
1152 paste_canvas->get_amount() == 1.0f &&
1153 paste_canvas->get_zoom() == 0 &&
1154 paste_canvas->get_time_offset() == 0 &&
1155 paste_canvas->get_origin() == Point(0,0) )
1157 for(sub_iter=sub_canvas->begin();sub_iter!=sub_canvas->end();++sub_iter)
1159 Layer* layer=sub_iter->get();
1161 // any layers that deform end up breaking things
1162 // so do things the old way if we run into anything like this
1163 if(!dynamic_cast<Layer_NoDeform*>(layer))
1166 ValueBase value(layer->get_param("blend_method"));
1167 if(value.get_type()!=ValueBase::TYPE_INTEGER || value.get(int())!=(int)Color::BLEND_COMPOSITE)
1171 // It has turned out that we don't need a paste canvas
1172 // layer, so just go ahead and add all the layers onto
1173 // the current stack and be done with it
1174 while(sub_canvas->size())
1176 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,sub_canvas->front()));
1177 //op_canvas->push_back_simple(sub_canvas->front());
1178 sub_canvas->pop_front();
1184 #endif // SYNFIG_OPTIMIZE_PASTE_CANVAS
1186 Layer::Handle new_layer(Layer::create("PasteCanvas"));
1187 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(false);
1190 Layer::DynamicParamList dynamic_param_list(paste_canvas->dynamic_param_list());
1191 for(Layer::DynamicParamList::const_iterator iter(dynamic_param_list.begin()); iter != dynamic_param_list.end(); ++iter)
1192 new_layer->connect_dynamic_param(iter->first, iter->second);
1194 Layer::ParamList param_list(paste_canvas->get_param_list());
1195 //param_list.erase("canvas");
1196 new_layer->set_param_list(param_list);
1197 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_sub_canvas(sub_canvas);
1198 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(true);
1201 else // not a PasteCanvas - does it use blend method 'Straight'?
1203 /* when we use the 'straight' blend method, every pixel on the layer affects the layers underneath,
1204 * not just the non-transparent pixels; the following workarea wraps non-pastecanvas layers in a
1205 * new pastecanvas to ensure that the straight blend affects the full plane, not just the area
1206 * within the layer's bounding box
1209 // \todo: this code probably needs modification to work properly with motionblur and duplicate
1210 etl::handle<Layer_Composite> composite = etl::handle<Layer_Composite>::cast_dynamic(layer);
1212 /* some layers (such as circle) don't touch pixels that aren't
1213 * part of the circle, so they don't get blended correctly when
1214 * using a straight blend. so we encapsulate the circle, and the
1215 * encapsulation layer takes care of the transparent pixels
1216 * for us. if we do that for all layers, however, then the
1217 * distortion layers no longer work, since they have no
1218 * context to work on. the Layer::reads_context() method
1219 * returns true for layers which need to be able to see
1220 * their context. we can't encapsulate those.
1223 Color::is_straight(composite->get_blend_method()) &&
1224 !composite->reads_context())
1226 Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
1227 sub_canvas->push_back(composite = composite->clone());
1228 layer = Layer::create("PasteCanvas");
1229 composite->set_description(strprintf("Wrapped clone of '%s'", composite->get_non_empty_description().c_str()));
1230 layer->set_description(strprintf("PasteCanvas wrapper for '%s'", composite->get_non_empty_description().c_str()));
1231 Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1232 paste_canvas->set_blend_method(composite->get_blend_method());
1233 paste_canvas->set_amount(composite->get_amount());
1234 sub_canvas->set_time(time); // region and outline don't calculate their bounding rects until their time is set
1235 composite->set_blend_method(Color::BLEND_STRAIGHT); // do this before calling set_sub_canvas(), but after set_time()
1236 composite->set_amount(1.0f); // after set_time()
1237 paste_canvas->set_sub_canvas(sub_canvas);
1241 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,layer));
1242 //op_canvas->push_back_simple(layer);
1246 stable_sort(sort_list.begin(),sort_list.end());
1247 std::vector< std::pair<float,Layer::Handle> >::iterator iter2;
1248 for(iter2=sort_list.begin();iter2!=sort_list.end();++iter2)
1249 op_canvas->push_back_simple(iter2->second);
1250 op_canvas->op_flag_=true;
1254 Canvas::get_times_vfunc(Node::time_set &set) const
1256 const_iterator i = begin(),
1259 for(; i != iend; ++i)
1261 const Node::time_set &tset = (*i)->get_times();
1262 set.insert(tset.begin(),tset.end());
1266 std::set<etl::handle<Layer> >
1267 Canvas::get_layers_in_group(const String&group)
1269 if(is_inline() && parent_)
1270 return parent_->get_layers_in_group(group);
1272 if(group_db_.count(group)==0)
1273 return std::set<etl::handle<Layer> >();
1274 return group_db_.find(group)->second;
1278 Canvas::get_groups()const
1280 if(is_inline() && parent_)
1281 return parent_->get_groups();
1283 std::set<String> ret;
1284 std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
1285 for(iter=group_db_.begin();iter!=group_db_.end();++iter)
1286 ret.insert(iter->first);
1291 Canvas::get_group_count()const
1293 if(is_inline() && parent_)
1294 return parent_->get_group_count();
1296 return group_db_.size();
1300 Canvas::add_group_pair(String group, etl::handle<Layer> layer)
1302 group_db_[group].insert(layer);
1303 if(group_db_[group].size()==1)
1304 signal_group_added()(group);
1306 signal_group_changed()(group);
1308 signal_group_pair_added()(group,layer);
1310 if(is_inline() && parent_)
1311 return parent_->add_group_pair(group,layer);
1315 Canvas::remove_group_pair(String group, etl::handle<Layer> layer)
1317 group_db_[group].erase(layer);
1319 signal_group_pair_removed()(group,layer);
1321 if(group_db_[group].empty())
1323 group_db_.erase(group);
1324 signal_group_removed()(group);
1327 signal_group_changed()(group);
1329 if(is_inline() && parent_)
1330 return parent_->remove_group_pair(group,layer);
1334 Canvas::add_connection(etl::loose_handle<Layer> layer, sigc::connection connection)
1336 connections_[layer].push_back(connection);
1340 Canvas::disconnect_connections(etl::loose_handle<Layer> layer)
1342 std::vector<sigc::connection>::iterator iter;
1343 for(iter=connections_[layer].begin();iter!=connections_[layer].end();++iter)
1345 connections_[layer].clear();
1349 Canvas::rename_group(const String&old_name,const String&new_name)
1351 if(is_inline() && parent_)
1352 return parent_->rename_group(old_name,new_name);
1355 std::map<String,std::set<etl::handle<Layer> > >::iterator iter;
1356 iter=group_db_.find(old_name);
1357 if(iter!=group_db_.end())
1358 for(++iter;iter!=group_db_.end() && iter->first.find(old_name)==0;iter=group_db_.find(old_name),++iter)
1360 String name(iter->first,old_name.size(),String::npos);
1362 rename_group(iter->first,name);
1366 std::set<etl::handle<Layer> > layers(get_layers_in_group(old_name));
1367 std::set<etl::handle<Layer> >::iterator iter;
1369 for(iter=layers.begin();iter!=layers.end();++iter)
1371 (*iter)->remove_from_group(old_name);
1372 (*iter)->add_to_group(new_name);