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 "loadcanvas.h"
43 #include <sigc++/bind.h>
47 using namespace synfig;
51 namespace synfig { extern Canvas::Handle open_canvas(const String &filename, String &errors, String &warnings); };
53 /* === M A C R O S ========================================================= */
55 #define ALLOW_CLONE_NON_INLINE_CANVASES
63 synfig::error("%d canvases not yet deleted!",counter);
67 int _CanvasCounter::counter(0);
69 /* === G L O B A L S ======================================================= */
71 /* === P R O C E D U R E S ================================================= */
73 /* === M E T H O D S ======================================================= */
75 Canvas::Canvas(const String &id):
77 version_ (CURRENT_CANVAS_VERSION),
83 _CanvasCounter::counter++;
96 // we were having a crash where pastecanvas layers were still
97 // refering to a canvas after it had been destroyed; this code
98 // will stop the pastecanvas layers from refering to the canvas
99 // before the canvas is destroyed
101 // the set_sub_canvas(0) ends up deleting the parent-child link,
102 // which deletes the current element from the set we're iterating
103 // through, so we have to make sure we've incremented the iterator
104 // before we mess with the pastecanvas
105 std::set<Node*>::iterator iter = parent_set.begin();
106 while (iter != parent_set.end())
108 Layer_PasteCanvas* paste_canvas = dynamic_cast<Layer_PasteCanvas*>(*iter);
111 paste_canvas->set_sub_canvas(0);
113 warning("destroyed canvas has a parent that is not a pastecanvas - please report if repeatable");
116 //if(is_inline() && parent_) assert(0);
117 _CanvasCounter::counter--;
125 return CanvasBase::end()-1;
128 Canvas::const_iterator
131 return CanvasBase::end()-1;
134 Canvas::reverse_iterator
137 return CanvasBase::rbegin()+1;
140 Canvas::const_reverse_iterator
141 Canvas::rbegin()const
143 return CanvasBase::rbegin()+1;
149 return CanvasBase::size()-1;
157 Layer::Handle layer(front());
158 //if(layer->count()>2)synfig::info("before layer->count()=%d",layer->count());
161 //if(layer->count()>1)synfig::info("after layer->count()=%d",layer->count());
163 //CanvasBase::clear();
165 // We need to keep a blank handle at the
166 // end of the image list, and acts at
167 // the bottom. Without it, the layers
168 // would just continue going when polled
170 CanvasBase::push_back(Layer::Handle());
178 return CanvasBase::size()<=1;
184 return *(CanvasBase::end()-1);
187 const Layer::Handle &
190 return *(CanvasBase::end()-1);
194 Canvas::get_context()const
199 const ValueNodeList &
200 Canvas::value_node_list()const
202 if(is_inline() && parent_)
203 return parent_->value_node_list();
204 return value_node_list_;
208 Canvas::keyframe_list()
210 if(is_inline() && parent_)
211 return parent_->keyframe_list();
212 return keyframe_list_;
216 Canvas::keyframe_list()const
218 if(is_inline() && parent_)
219 return parent_->keyframe_list();
220 return keyframe_list_;
224 Canvas::find_layer(const Point &pos)
226 return get_context().hit_check(pos);
230 valid_id(const String &x)
232 static const char bad_chars[]=" :#@$^&()*";
235 if(!x.empty() && x[0]>='0' && x[0]<='9')
238 for(i=0;i<sizeof(bad_chars);i++)
239 if(x.find_first_of(bad_chars[i])!=string::npos)
246 Canvas::set_id(const String &x)
248 if(is_inline() && parent_)
249 throw runtime_error("Inline Canvas cannot have an ID");
252 throw runtime_error("Invalid ID");
254 signal_id_changed_();
258 Canvas::set_name(const String &x)
261 signal_meta_data_changed()("name");
262 signal_meta_data_changed("name")();
266 Canvas::set_author(const String &x)
269 signal_meta_data_changed()("author");
270 signal_meta_data_changed("author")();
274 Canvas::set_description(const String &x)
277 signal_meta_data_changed()("description");
278 signal_meta_data_changed("description")();
282 Canvas::set_time(Time t)const
284 if(is_dirty_ || !get_time().is_equal(t))
289 synfig::info("is_dirty_=%d",is_dirty_);
290 synfig::info("get_time()=%f",(float)get_time());
291 synfig::info("t=%f",(float)t);
296 const_cast<Canvas&>(*this).cur_time_=t;
299 get_context().set_time(t);
305 Canvas::get_root()const
307 return parent_?parent_->get_root().get():const_cast<synfig::Canvas *>(this);
311 Canvas::get_depth(etl::handle<Layer> layer)const
315 for(iter=begin();iter!=end();++iter,i++)
324 Canvas::get_relative_id(etl::loose_handle<const Canvas> x)const
326 if(x->get_root()==this)
328 if(is_inline() && parent_)
329 return parent_->_get_relative_id(x);
330 return _get_relative_id(x);
334 Canvas::_get_relative_id(etl::loose_handle<const Canvas> x)const
336 if(is_inline() && parent_)
337 return parent_->_get_relative_id(x);
342 if(parent()==x.get())
347 const Canvas* canvas=this;
349 for(;!canvas->is_root();canvas=canvas->parent().get())
350 id=':'+canvas->get_id()+id;
352 if(x && get_root()!=x->get_root())
354 //String file_name=get_file_name();
355 //String file_path=x->get_file_path();
358 if(is_absolute_path(get_file_name()))
359 file_name=etl::relative_path(x->get_file_path(),get_file_name());
361 file_name=get_file_name();
363 // If the path of X is inside of file_name,
365 //if(file_name.size()>file_path.size())
366 // if(file_path==String(file_name,0,file_path.size()))
367 // file_name.erase(0,file_path.size()+1);
376 Canvas::find_value_node(const String &id)
379 ValueNode::Handle::cast_const(
380 const_cast<const Canvas*>(this)->find_value_node(id)
384 ValueNode::ConstHandle
385 Canvas::find_value_node(const String &id)const
387 if(is_inline() && parent_)
388 return parent_->find_value_node(id);
391 throw Exception::IDNotFound("Empty ID");
393 // If we do not have any resolution, then we assume that the
394 // request is for this immediate canvas
395 if(id.find_first_of(':')==string::npos && id.find_first_of('#')==string::npos)
396 return value_node_list_.find(id);
398 String canvas_id(id,0,id.rfind(':'));
399 String value_node_id(id,id.rfind(':')+1);
400 if(canvas_id.empty())
402 //synfig::warning("constfind:value_node_id: "+value_node_id);
403 //synfig::warning("constfind:canvas_id: "+canvas_id);
406 return find_canvas(canvas_id, warnings)->value_node_list_.find(value_node_id);
410 Canvas::surefind_value_node(const String &id)
412 if(is_inline() && parent_)
413 return parent_->surefind_value_node(id);
416 throw Exception::IDNotFound("Empty ID");
418 // If we do not have any resolution, then we assume that the
419 // request is for this immediate canvas
420 if(id.find_first_of(':')==string::npos && id.find_first_of('#')==string::npos)
421 return value_node_list_.surefind(id);
423 String canvas_id(id,0,id.rfind(':'));
424 String value_node_id(id,id.rfind(':')+1);
425 if(canvas_id.empty())
429 return surefind_canvas(canvas_id,warnings)->value_node_list_.surefind(value_node_id);
433 Canvas::add_value_node(ValueNode::Handle x, const String &id)
435 if(is_inline() && parent_)
436 return parent_->add_value_node(x,id);
437 // throw runtime_error("You cannot add a ValueNode to an inline Canvas");
440 throw runtime_error("ValueNode is already exported");
443 throw Exception::BadLinkName("Empty ID");
445 if(id.find_first_of(':',0)!=string::npos)
446 throw Exception::BadLinkName("Bad character");
450 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
451 throw Exception::IDNotFound("add_value_node()");
453 throw Exception::IDAlreadyExists(id);
455 catch(Exception::IDNotFound)
459 x->set_parent_canvas(this);
461 if(!value_node_list_.add(x))
463 synfig::error("Unable to add ValueNode");
464 throw std::runtime_error("Unable to add ValueNode");
473 Canvas::rename_value_node(ValueNode::Handle x, const String &id)
476 throw Exception::BadLinkName("Empty ID");
478 if(id.find_first_of(": ",0)!=string::npos)
479 throw Exception::BadLinkName("Bad character");
483 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
484 throw Exception::IDNotFound("rename_value_node");
485 throw Exception::IDAlreadyExists(id);
487 catch(Exception::IDNotFound)
497 Canvas::remove_value_node(ValueNode::Handle x)
499 if(is_inline() && parent_)
500 return parent_->remove_value_node(x);
501 // throw Exception::IDNotFound("Canvas::remove_value_node() was called from an inline canvas");
504 throw Exception::IDNotFound("Canvas::remove_value_node() was passed empty handle");
506 if(!value_node_list_.erase(x))
507 throw Exception::IDNotFound("Canvas::remove_value_node(): ValueNode was not found inside of this canvas");
509 //x->set_parent_canvas(0);
515 Canvas::surefind_canvas(const String &id, String &warnings)
517 if(is_inline() && parent_)
518 return parent_->surefind_canvas(id,warnings);
523 // If the ID contains a "#" character, then a filename is
524 // expected on the left side.
525 if(id.find_first_of('#')!=string::npos)
527 // If '#' is the first character, remove it
528 // and attempt to parse the ID again.
530 return surefind_canvas(String(id,1),warnings);
532 //! \todo This needs a lot more optimization
533 String file_name(id,0,id.find_first_of('#'));
534 String external_id(id,id.find_first_of('#')+1);
536 file_name=unix_to_local_path(file_name);
538 Canvas::Handle external_canvas;
540 // If the composition is already open, then use it.
541 if(externals_.count(file_name))
542 external_canvas=externals_[file_name];
546 if(is_absolute_path(file_name))
547 external_canvas=open_canvas(file_name, errors, warnings);
549 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name, errors, warnings);
552 throw runtime_error(errors);
553 externals_[file_name]=external_canvas;
556 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id, warnings));
559 // If we do not have any resolution, then we assume that the
560 // request is for this immediate canvas
561 if(id.find_first_of(':')==string::npos)
563 Children::iterator iter;
565 // Search for the image in the image list,
566 // and return it if it is found
567 for(iter=children().begin();iter!=children().end();iter++)
568 if(id==(*iter)->get_id())
571 // Create a new canvas and return it
572 //synfig::warning("Implicitly creating canvas named "+id);
573 return new_child_canvas(id);
576 // If the first character is the separator, then
577 // this references the root canvas.
579 return get_root()->surefind_canvas(string(id,1),warnings);
581 // Now we know that the requested Canvas is in a child
582 // of this canvas. We have to find that canvas and
583 // call "find_canvas" on it, and return the result.
585 String canvas_name=string(id,0,id.find_first_of(':'));
587 Canvas::Handle child_canvas=surefind_canvas(canvas_name,warnings);
589 return child_canvas->surefind_canvas(string(id,id.find_first_of(':')+1),warnings);
593 Canvas::find_canvas(const String &id, String &warnings)
596 Canvas::Handle::cast_const(
597 const_cast<const Canvas*>(this)->find_canvas(id, warnings)
602 Canvas::find_canvas(const String &id, String &warnings)const
604 if(is_inline() && parent_)
605 return parent_->find_canvas(id, warnings);
610 // If the ID contains a "#" character, then a filename is
611 // expected on the left side.
612 if(id.find_first_of('#')!=string::npos)
614 // If '#' is the first character, remove it
615 // and attempt to parse the ID again.
617 return find_canvas(String(id,1), warnings);
619 //! \todo This needs a lot more optimization
620 String file_name(id,0,id.find_first_of('#'));
621 String external_id(id,id.find_first_of('#')+1);
623 file_name=unix_to_local_path(file_name);
625 Canvas::Handle external_canvas;
627 // If the composition is already open, then use it.
628 if(externals_.count(file_name))
629 external_canvas=externals_[file_name];
632 String errors, warnings;
633 if(is_absolute_path(file_name))
634 external_canvas=open_canvas(file_name, errors, warnings);
636 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name, errors, warnings);
639 throw runtime_error(errors);
640 externals_[file_name]=external_canvas;
643 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id, warnings));
646 // If we do not have any resolution, then we assume that the
647 // request is for this immediate canvas
648 if(id.find_first_of(':')==string::npos)
650 Children::const_iterator iter;
652 // Search for the image in the image list,
653 // and return it if it is found
654 for(iter=children().begin();iter!=children().end();iter++)
655 if(id==(*iter)->get_id())
658 throw Exception::IDNotFound("Child Canvas in Parent Canvas: (child)"+id);
661 // If the first character is the separator, then
662 // this references the root canvas.
664 return get_root()->find_canvas(string(id,1), warnings);
666 // Now we know that the requested Canvas is in a child
667 // of this canvas. We have to find that canvas and
668 // call "find_canvas" on it, and return the result.
670 String canvas_name=string(id,0,id.find_first_of(':'));
672 Canvas::ConstHandle child_canvas=find_canvas(canvas_name, warnings);
674 return child_canvas->find_canvas(string(id,id.find_first_of(':')+1), warnings);
680 return new Canvas("Untitled");
684 Canvas::push_back(etl::handle<Layer> x)
686 // int i(x->count());
688 //if(x->count()!=i+1)synfig::info("push_back before %d, after %d",i,x->count());
692 Canvas::push_front(etl::handle<Layer> x)
694 // int i(x->count());
696 //if(x->count()!=i+1)synfig::error("push_front before %d, after %d",i,x->count());
700 Canvas::insert(iterator iter,etl::handle<Layer> x)
702 // int i(x->count());
703 CanvasBase::insert(iter,x);
705 /*if(x->count()!=i+1)
707 synfig::error(__FILE__":%d: Canvas::insert(): ***FAILURE*** before %d, after %d",__LINE__,i,x->count());
709 //throw runtime_error("Canvas Insertion Failed");
716 LooseHandle correct_canvas(this);
717 //while(correct_canvas->is_inline())correct_canvas=correct_canvas->parent();
718 Layer::LooseHandle loose_layer(x);
720 add_connection(loose_layer,
721 sigc::connection::connection(
722 x->signal_added_to_group().connect(
726 &Canvas::add_group_pair),
728 add_connection(loose_layer,
729 sigc::connection::connection(
730 x->signal_removed_from_group().connect(
734 &Canvas::remove_group_pair),
737 if(!x->get_group().empty())
738 add_group_pair(x->get_group(),x);
744 Canvas::push_back_simple(etl::handle<Layer> x)
746 CanvasBase::insert(end(),x);
751 Canvas::erase(iterator iter)
753 if(!(*iter)->get_group().empty())
754 remove_group_pair((*iter)->get_group(),(*iter));
756 // HACK: We really shouldn't be wiping
757 // out these signals entirely. We should
758 // only be removing the specific connections
759 // that we made. At the moment, I'm too
760 // lazy to add the code to keep track
761 // of those connections, and no one else
762 // is using these signals, so I'll just
763 // leave these next two lines like they
764 // are for now - darco 07-30-2004
766 // so don't wipe them out entirely
767 // - dooglus 09-21-2007
768 disconnect_connections(*iter);
770 if(!op_flag_)remove_child(iter->get());
772 CanvasBase::erase(iter);
773 if(!op_flag_)changed();
777 Canvas::clone(const GUID& deriv_guid)const
784 name=get_id()+"_CLONE";
786 #ifndef ALLOW_CLONE_NON_INLINE_CANVASES
787 throw runtime_error("Cloning of non-inline canvases is not yet supported");
788 #endif // ALLOW_CLONE_NON_INLINE_CANVASES
791 Handle canvas(new Canvas(name));
795 canvas->is_inline_=true;
796 // \todo this was setting parent_=0 - is there a reason for that?
797 // this was causing bug 1838132, where cloning an inline canvas that contains an imported image fails
798 // it was failing to ascertain the absolute pathname of the imported image, since it needs the pathname
799 // of the canvas to get that, which is stored in the parent canvas
800 canvas->parent_=parent();
801 canvas->rend_desc() = rend_desc();
802 //canvas->set_inline(parent());
805 canvas->set_guid(get_guid()^deriv_guid);
808 for(iter=begin();iter!=end();++iter)
810 Layer::Handle layer((*iter)->clone(deriv_guid));
813 assert(layer.count()==1);
815 canvas->push_back(layer);
816 if(!(layer.count()>1))
818 synfig::error("Canvas::clone(): Cloned layer insertion failure!");
819 synfig::error("Canvas::clone(): \tlayer.count()=%d",layer.count());
820 synfig::error("Canvas::clone(): \tlayer->get_name()=%s",layer->get_name().c_str());
821 synfig::error("Canvas::clone(): \tbefore size()=%d",presize);
822 synfig::error("Canvas::clone(): \tafter size()=%d",size());
824 assert(layer.count()>1);
828 synfig::error("Unable to clone layer");
832 canvas->signal_group_pair_removed().clear();
833 canvas->signal_group_pair_added().clear();
839 Canvas::set_inline(LooseHandle parent)
841 if(is_inline_ && parent_)
850 // Have the parent inherit all of the group stuff
852 std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
854 for(iter=group_db_.begin();iter!=group_db_.end();++iter)
856 parent->group_db_[iter->first].insert(iter->second.begin(),iter->second.end());
859 rend_desc()=parent->rend_desc();
863 Canvas::create_inline(Handle parent)
866 //if(parent->is_inline())
867 // return create_inline(parent->parent());
869 Handle canvas(new Canvas("inline"));
870 canvas->set_inline(parent);
875 Canvas::new_child_canvas()
877 if(is_inline() && parent_)
878 return parent_->new_child_canvas();
879 // runtime_error("You cannot create a child Canvas in an inline Canvas");
881 // Create a new canvas
882 children().push_back(create());
883 Canvas::Handle canvas(children().back());
885 canvas->parent_=this;
887 canvas->rend_desc()=rend_desc();
893 Canvas::new_child_canvas(const String &id)
895 if(is_inline() && parent_)
896 return parent_->new_child_canvas(id);
897 // runtime_error("You cannot create a child Canvas in an inline Canvas");
899 // Create a new canvas
900 children().push_back(create());
901 Canvas::Handle canvas(children().back());
904 canvas->parent_=this;
905 canvas->rend_desc()=rend_desc();
911 Canvas::add_child_canvas(Canvas::Handle child_canvas, const synfig::String& id)
913 if(is_inline() && parent_)
914 return parent_->add_child_canvas(child_canvas,id);
916 if(child_canvas->parent() && !child_canvas->is_inline())
917 throw std::runtime_error("Cannot add child canvas because it belongs to someone else!");
920 throw runtime_error("Invalid ID");
925 find_canvas(id, warnings);
926 throw Exception::IDAlreadyExists(id);
928 catch(Exception::IDNotFound)
930 if(child_canvas->is_inline())
931 child_canvas->is_inline_=false;
932 child_canvas->id_=id;
933 children().push_back(child_canvas);
934 child_canvas->parent_=this;
941 Canvas::remove_child_canvas(Canvas::Handle child_canvas)
943 if(is_inline() && parent_)
944 return parent_->remove_child_canvas(child_canvas);
946 if(child_canvas->parent_!=this)
947 throw runtime_error("Given child does not belong to me");
949 if(find(children().begin(),children().end(),child_canvas)==children().end())
950 throw Exception::IDNotFound(child_canvas->get_id());
952 children().remove(child_canvas);
954 child_canvas->parent_=0;
958 Canvas::set_file_name(const String &file_name)
961 parent()->set_file_name(file_name);
964 String old_name(file_name_);
965 file_name_=file_name;
967 // when a canvas is made, its name is ""
968 // then, before it's saved or even edited, it gets a name like "Synfig Animation 23", in the local language
969 // we don't want to register the canvas' filename in the canvas map until it gets a real filename
972 file_name_=file_name;
973 std::map<synfig::String, etl::loose_handle<Canvas> >::iterator iter;
974 for(iter=get_open_canvas_map().begin();iter!=get_open_canvas_map().end();++iter)
975 if(iter->second==this)
977 if (iter == get_open_canvas_map().end())
978 CanvasParser::register_canvas_in_map(this, file_name);
980 signal_file_name_changed_();
986 Canvas::signal_file_name_changed()
989 return parent()->signal_file_name_changed();
991 return signal_file_name_changed_;
995 Canvas::get_file_name()const
998 return parent()->get_file_name();
1003 Canvas::get_file_path()const
1006 return parent()->get_file_path();
1007 return dirname(file_name_);
1011 Canvas::get_meta_data(const String& key)const
1013 if(!meta_data_.count(key))
1015 return meta_data_.find(key)->second;
1019 Canvas::set_meta_data(const String& key, const String& data)
1021 if(meta_data_[key]!=data)
1023 meta_data_[key]=data;
1024 signal_meta_data_changed()(key);
1025 signal_meta_data_changed(key)();
1030 Canvas::erase_meta_data(const String& key)
1032 if(meta_data_.count(key))
1034 meta_data_.erase(key);
1035 signal_meta_data_changed()(key);
1036 signal_meta_data_changed(key)();
1041 Canvas::get_meta_data_keys()const
1043 std::list<String> ret;
1045 std::map<String,String>::const_iterator iter;
1047 for(iter=meta_data_.begin();!(iter==meta_data_.end());++iter)
1048 ret.push_back(iter->first);
1053 /* note - the "Motion Blur" and "Duplicate" layers need the dynamic
1054 parameters of any PasteCanvas layers they loop over to be
1055 maintained. When the variables in the following function
1056 refer to "motion blur", they mean either of these two
1059 synfig::optimize_layers(Time time, Context context, Canvas::Handle op_canvas, bool seen_motion_blur_in_parent)
1063 std::vector< std::pair<float,Layer::Handle> > sort_list;
1064 int i, motion_blur_i=0; // motion_blur_i is for resolving which layer comes first in the event of a z_depth tie
1065 float motion_blur_z_depth=0; // the z_depth of the least deep motion blur layer in this context
1066 bool seen_motion_blur_locally = false;
1067 bool motion_blurred; // the final result - is this layer blurred or not?
1069 // If the parent didn't cause us to already be motion blurred,
1070 // check whether there's a motion blur in this context,
1071 // and if so, calculate its z_depth.
1072 if (!seen_motion_blur_in_parent)
1073 for(iter=context,i=0;*iter;iter++,i++)
1075 Layer::Handle layer=*iter;
1077 // If the layer isn't active, don't worry about it
1078 if(!layer->active())
1081 // Any layer with an amount of zero is implicitly disabled.
1082 ValueBase value(layer->get_param("amount"));
1083 if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1086 if(layer->get_name()=="MotionBlur" || layer->get_name()=="duplicate")
1088 float z_depth(layer->get_z_depth()*1.0001+i);
1090 // If we've seen a motion blur before in this context...
1091 if (seen_motion_blur_locally)
1093 // ... then we're only interested in this one if it's less deep...
1094 if (z_depth < motion_blur_z_depth)
1096 motion_blur_z_depth = z_depth;
1100 // ... otherwise we're always interested in it.
1103 motion_blur_z_depth = z_depth;
1105 seen_motion_blur_locally = true;
1110 // Go ahead and start romping through the canvas to paste
1111 for(iter=context,i=0;*iter;iter++,i++)
1113 Layer::Handle layer=*iter;
1114 float z_depth(layer->get_z_depth()*1.0001+i);
1116 // If the layer isn't active, don't worry about it
1117 if(!layer->active())
1120 // Any layer with an amount of zero is implicitly disabled.
1121 ValueBase value(layer->get_param("amount"));
1122 if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1125 // note: this used to include "&& paste_canvas->get_time_offset()==0", but then
1126 // time-shifted layers weren't being sorted by z-depth (bug #1806852)
1127 if(layer->get_name()=="PasteCanvas")
1129 Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1131 // we need to blur the sub canvas if:
1132 // our parent is blurred,
1133 // or the child is lower than a local blur,
1134 // or the child is at the same z_depth as a local blur, but later in the context
1137 if (seen_motion_blur_in_parent) synfig::info("seen BLUR in parent\n");
1138 else if (seen_motion_blur_locally)
1139 if (z_depth > motion_blur_z_depth) synfig::info("paste is deeper than BLUR\n");
1140 else if (z_depth == motion_blur_z_depth) { synfig::info("paste is same depth as BLUR\n");
1141 if (i > motion_blur_i) synfig::info("paste is physically deeper than BLUR\n");
1142 else synfig::info("paste is less physically deep than BLUR\n");
1143 } else synfig::info("paste is less deep than BLUR\n");
1144 else synfig::info("no BLUR at all\n");
1147 motion_blurred = (seen_motion_blur_in_parent ||
1148 (seen_motion_blur_locally &&
1149 (z_depth > motion_blur_z_depth ||
1150 (z_depth == motion_blur_z_depth && i > motion_blur_i))));
1152 Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
1153 Canvas::Handle paste_sub_canvas = paste_canvas->get_sub_canvas();
1154 if(paste_sub_canvas)
1155 optimize_layers(time, paste_sub_canvas->get_context(),sub_canvas,motion_blurred);
1157 // \todo: uncommenting the following breaks the rendering of at least examples/backdrop.sifz quite severely
1158 // #define SYNFIG_OPTIMIZE_PASTE_CANVAS
1159 #ifdef SYNFIG_OPTIMIZE_PASTE_CANVAS
1160 Canvas::iterator sub_iter;
1162 // Determine if we can just remove the paste canvas altogether
1163 if (paste_canvas->get_blend_method() == Color::BLEND_COMPOSITE &&
1164 paste_canvas->get_amount() == 1.0f &&
1165 paste_canvas->get_zoom() == 0 &&
1166 paste_canvas->get_time_offset() == 0 &&
1167 paste_canvas->get_origin() == Point(0,0) )
1169 for(sub_iter=sub_canvas->begin();sub_iter!=sub_canvas->end();++sub_iter)
1171 Layer* layer=sub_iter->get();
1173 // any layers that deform end up breaking things
1174 // so do things the old way if we run into anything like this
1175 if(!dynamic_cast<Layer_NoDeform*>(layer))
1178 ValueBase value(layer->get_param("blend_method"));
1179 if(value.get_type()!=ValueBase::TYPE_INTEGER || value.get(int())!=(int)Color::BLEND_COMPOSITE)
1183 // It has turned out that we don't need a paste canvas
1184 // layer, so just go ahead and add all the layers onto
1185 // the current stack and be done with it
1186 while(sub_canvas->size())
1188 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,sub_canvas->front()));
1189 //op_canvas->push_back_simple(sub_canvas->front());
1190 sub_canvas->pop_front();
1196 #endif // SYNFIG_OPTIMIZE_PASTE_CANVAS
1198 Layer::Handle new_layer(Layer::create("PasteCanvas"));
1199 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(false);
1202 Layer::DynamicParamList dynamic_param_list(paste_canvas->dynamic_param_list());
1203 for(Layer::DynamicParamList::const_iterator iter(dynamic_param_list.begin()); iter != dynamic_param_list.end(); ++iter)
1204 new_layer->connect_dynamic_param(iter->first, iter->second);
1206 Layer::ParamList param_list(paste_canvas->get_param_list());
1207 //param_list.erase("canvas");
1208 new_layer->set_param_list(param_list);
1209 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_sub_canvas(sub_canvas);
1210 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(true);
1213 else // not a PasteCanvas - does it use blend method 'Straight'?
1215 /* when we use the 'straight' blend method, every pixel on the layer affects the layers underneath,
1216 * not just the non-transparent pixels; the following workarea wraps non-pastecanvas layers in a
1217 * new pastecanvas to ensure that the straight blend affects the full plane, not just the area
1218 * within the layer's bounding box
1221 // \todo: this code probably needs modification to work properly with motionblur and duplicate
1222 etl::handle<Layer_Composite> composite = etl::handle<Layer_Composite>::cast_dynamic(layer);
1224 /* some layers (such as circle) don't touch pixels that aren't
1225 * part of the circle, so they don't get blended correctly when
1226 * using a straight blend. so we encapsulate the circle, and the
1227 * encapsulation layer takes care of the transparent pixels
1228 * for us. if we do that for all layers, however, then the
1229 * distortion layers no longer work, since they have no
1230 * context to work on. the Layer::reads_context() method
1231 * returns true for layers which need to be able to see
1232 * their context. we can't encapsulate those.
1235 Color::is_straight(composite->get_blend_method()) &&
1236 !composite->reads_context())
1238 Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
1239 sub_canvas->push_back(composite = composite->clone());
1240 layer = Layer::create("PasteCanvas");
1241 composite->set_description(strprintf("Wrapped clone of '%s'", composite->get_non_empty_description().c_str()));
1242 layer->set_description(strprintf("PasteCanvas wrapper for '%s'", composite->get_non_empty_description().c_str()));
1243 Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1244 paste_canvas->set_blend_method(composite->get_blend_method());
1245 paste_canvas->set_amount(composite->get_amount());
1246 sub_canvas->set_time(time); // region and outline don't calculate their bounding rects until their time is set
1247 composite->set_blend_method(Color::BLEND_STRAIGHT); // do this before calling set_sub_canvas(), but after set_time()
1248 composite->set_amount(1.0f); // after set_time()
1249 paste_canvas->set_sub_canvas(sub_canvas);
1253 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,layer));
1254 //op_canvas->push_back_simple(layer);
1258 stable_sort(sort_list.begin(),sort_list.end());
1259 std::vector< std::pair<float,Layer::Handle> >::iterator iter2;
1260 for(iter2=sort_list.begin();iter2!=sort_list.end();++iter2)
1261 op_canvas->push_back_simple(iter2->second);
1262 op_canvas->op_flag_=true;
1266 Canvas::get_times_vfunc(Node::time_set &set) const
1268 const_iterator i = begin(),
1271 for(; i != iend; ++i)
1273 const Node::time_set &tset = (*i)->get_times();
1274 set.insert(tset.begin(),tset.end());
1278 std::set<etl::handle<Layer> >
1279 Canvas::get_layers_in_group(const String&group)
1281 if(is_inline() && parent_)
1282 return parent_->get_layers_in_group(group);
1284 if(group_db_.count(group)==0)
1285 return std::set<etl::handle<Layer> >();
1286 return group_db_.find(group)->second;
1290 Canvas::get_groups()const
1292 if(is_inline() && parent_)
1293 return parent_->get_groups();
1295 std::set<String> ret;
1296 std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
1297 for(iter=group_db_.begin();iter!=group_db_.end();++iter)
1298 ret.insert(iter->first);
1303 Canvas::get_group_count()const
1305 if(is_inline() && parent_)
1306 return parent_->get_group_count();
1308 return group_db_.size();
1312 Canvas::add_group_pair(String group, etl::handle<Layer> layer)
1314 group_db_[group].insert(layer);
1315 if(group_db_[group].size()==1)
1316 signal_group_added()(group);
1318 signal_group_changed()(group);
1320 signal_group_pair_added()(group,layer);
1322 if(is_inline() && parent_)
1323 return parent_->add_group_pair(group,layer);
1327 Canvas::remove_group_pair(String group, etl::handle<Layer> layer)
1329 group_db_[group].erase(layer);
1331 signal_group_pair_removed()(group,layer);
1333 if(group_db_[group].empty())
1335 group_db_.erase(group);
1336 signal_group_removed()(group);
1339 signal_group_changed()(group);
1341 if(is_inline() && parent_)
1342 return parent_->remove_group_pair(group,layer);
1346 Canvas::add_connection(etl::loose_handle<Layer> layer, sigc::connection connection)
1348 connections_[layer].push_back(connection);
1352 Canvas::disconnect_connections(etl::loose_handle<Layer> layer)
1354 std::vector<sigc::connection>::iterator iter;
1355 for(iter=connections_[layer].begin();iter!=connections_[layer].end();++iter)
1357 connections_[layer].clear();
1361 Canvas::rename_group(const String&old_name,const String&new_name)
1363 if(is_inline() && parent_)
1364 return parent_->rename_group(old_name,new_name);
1367 std::map<String,std::set<etl::handle<Layer> > >::iterator iter;
1368 iter=group_db_.find(old_name);
1369 if(iter!=group_db_.end())
1370 for(++iter;iter!=group_db_.end() && iter->first.find(old_name)==0;iter=group_db_.find(old_name),++iter)
1372 String name(iter->first,old_name.size(),String::npos);
1374 rename_group(iter->first,name);
1378 std::set<etl::handle<Layer> > layers(get_layers_in_group(old_name));
1379 std::set<etl::handle<Layer> >::iterator iter;
1381 for(iter=layers.begin();iter!=layers.end();++iter)
1383 (*iter)->remove_from_group(old_name);
1384 (*iter)->add_to_group(new_name);