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
97 for (std::set<Node*>::iterator iter = parent_set.begin(); iter != parent_set.end(); iter++)
99 Layer_PasteCanvas* paste_canvas = dynamic_cast<Layer_PasteCanvas*>(*iter);
101 paste_canvas->set_sub_canvas(0);
103 warning("destroyed canvas has a parent that is not a pastecanvas - please report if repeatable");
106 //if(is_inline() && parent_) assert(0);
107 _CanvasCounter::counter--;
115 return CanvasBase::end()-1;
118 Canvas::const_iterator
121 return CanvasBase::end()-1;
124 Canvas::reverse_iterator
127 return CanvasBase::rbegin()+1;
130 Canvas::const_reverse_iterator
131 Canvas::rbegin()const
133 return CanvasBase::rbegin()+1;
139 return CanvasBase::size()-1;
147 Layer::Handle layer(front());
148 //if(layer->count()>2)synfig::info("before layer->count()=%d",layer->count());
151 //if(layer->count()>1)synfig::info("after layer->count()=%d",layer->count());
153 //CanvasBase::clear();
155 // We need to keep a blank handle at the
156 // end of the image list, and acts at
157 // the bottom. Without it, the layers
158 // would just continue going when polled
160 CanvasBase::push_back(Layer::Handle());
168 return CanvasBase::size()<=1;
174 return *(CanvasBase::end()-1);
177 const Layer::Handle &
180 return *(CanvasBase::end()-1);
184 Canvas::get_context()const
189 const ValueNodeList &
190 Canvas::value_node_list()const
192 if(is_inline() && parent_)
193 return parent_->value_node_list();
194 return value_node_list_;
198 Canvas::keyframe_list()
200 if(is_inline() && parent_)
201 return parent_->keyframe_list();
202 return keyframe_list_;
206 Canvas::keyframe_list()const
208 if(is_inline() && parent_)
209 return parent_->keyframe_list();
210 return keyframe_list_;
214 Canvas::find_layer(const Point &pos)
216 return get_context().hit_check(pos);
220 valid_id(const String &x)
222 static const char bad_chars[]=" :#@$^&()*";
225 if(!x.empty() && x[0]>='0' && x[0]<='9')
228 for(i=0;i<sizeof(bad_chars);i++)
229 if(x.find_first_of(bad_chars[i])!=string::npos)
236 Canvas::set_id(const String &x)
238 if(is_inline() && parent_)
239 throw runtime_error("Inline Canvas cannot have an ID");
242 throw runtime_error("Invalid ID");
244 signal_id_changed_();
248 Canvas::set_name(const String &x)
251 signal_meta_data_changed()("name");
252 signal_meta_data_changed("name")();
256 Canvas::set_author(const String &x)
259 signal_meta_data_changed()("author");
260 signal_meta_data_changed("author")();
264 Canvas::set_description(const String &x)
267 signal_meta_data_changed()("description");
268 signal_meta_data_changed("description")();
272 Canvas::set_time(Time t)const
274 if(is_dirty_ || !get_time().is_equal(t))
279 synfig::info("is_dirty_=%d",is_dirty_);
280 synfig::info("get_time()=%f",(float)get_time());
281 synfig::info("t=%f",(float)t);
286 const_cast<Canvas&>(*this).cur_time_=t;
289 get_context().set_time(t);
295 Canvas::get_root()const
297 return parent_?parent_->get_root().get():const_cast<synfig::Canvas *>(this);
301 Canvas::get_depth(etl::handle<Layer> layer)const
305 for(iter=begin();iter!=end();++iter,i++)
314 Canvas::get_relative_id(etl::loose_handle<const Canvas> x)const
316 if(x->get_root()==this)
318 if(is_inline() && parent_)
319 return parent_->_get_relative_id(x);
320 return _get_relative_id(x);
324 Canvas::_get_relative_id(etl::loose_handle<const Canvas> x)const
326 if(is_inline() && parent_)
327 return parent_->_get_relative_id(x);
332 if(parent()==x.get())
337 const Canvas* canvas=this;
339 for(;!canvas->is_root();canvas=canvas->parent().get())
340 id=':'+canvas->get_id()+id;
342 if(x && get_root()!=x->get_root())
344 //String file_name=get_file_name();
345 //String file_path=x->get_file_path();
348 if(is_absolute_path(get_file_name()))
349 file_name=etl::relative_path(x->get_file_path(),get_file_name());
351 file_name=get_file_name();
353 // If the path of X is inside of file_name,
355 //if(file_name.size()>file_path.size())
356 // if(file_path==String(file_name,0,file_path.size()))
357 // file_name.erase(0,file_path.size()+1);
367 Canvas::find_value_node(const String &id)
370 ValueNode::Handle::cast_const(
371 const_cast<const Canvas*>(this)->find_value_node(id)
375 ValueNode::ConstHandle
376 Canvas::find_value_node(const String &id)const
378 if(is_inline() && parent_)
379 return parent_->find_value_node(id);
382 throw Exception::IDNotFound("Empty ID");
384 // If we do not have any resolution, then we assume that the
385 // request is for this immediate canvas
386 if(id.find_first_of(':')==string::npos && id.find_first_of('#')==string::npos)
387 return value_node_list_.find(id);
389 String canvas_id(id,0,id.rfind(':'));
390 String value_node_id(id,id.rfind(':')+1);
391 if(canvas_id.empty())
393 //synfig::warning("constfind:value_node_id: "+value_node_id);
394 //synfig::warning("constfind:canvas_id: "+canvas_id);
396 return find_canvas(canvas_id)->value_node_list_.find(value_node_id);
400 Canvas::surefind_value_node(const String &id)
402 if(is_inline() && parent_)
403 return parent_->surefind_value_node(id);
406 throw Exception::IDNotFound("Empty ID");
408 // If we do not have any resolution, then we assume that the
409 // request is for this immediate canvas
410 if(id.find_first_of(':')==string::npos && id.find_first_of('#')==string::npos)
411 return value_node_list_.surefind(id);
413 String canvas_id(id,0,id.rfind(':'));
414 String value_node_id(id,id.rfind(':')+1);
415 if(canvas_id.empty())
418 return surefind_canvas(canvas_id)->value_node_list_.surefind(value_node_id);
422 Canvas::add_value_node(ValueNode::Handle x, const String &id)
424 if(is_inline() && parent_)
425 return parent_->add_value_node(x,id);
426 // throw runtime_error("You cannot add a ValueNode to an inline Canvas");
429 throw runtime_error("ValueNode is already exported");
432 throw Exception::BadLinkName("Empty ID");
434 if(id.find_first_of(':',0)!=string::npos)
435 throw Exception::BadLinkName("Bad character");
439 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
440 throw Exception::IDNotFound("add_value_node()");
442 throw Exception::IDAlreadyExists(id);
444 catch(Exception::IDNotFound)
448 x->set_parent_canvas(this);
450 if(!value_node_list_.add(x))
452 synfig::error("Unable to add ValueNode");
453 throw std::runtime_error("Unable to add ValueNode");
462 Canvas::rename_value_node(ValueNode::Handle x, const String &id)
465 throw Exception::BadLinkName("Empty ID");
467 if(id.find_first_of(": ",0)!=string::npos)
468 throw Exception::BadLinkName("Bad character");
472 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
473 throw Exception::IDNotFound("rename_value_node");
474 throw Exception::IDAlreadyExists(id);
476 catch(Exception::IDNotFound)
486 Canvas::remove_value_node(ValueNode::Handle x)
488 if(is_inline() && parent_)
489 return parent_->remove_value_node(x);
490 // throw Exception::IDNotFound("Canvas::remove_value_node() was called from an inline canvas");
493 throw Exception::IDNotFound("Canvas::remove_value_node() was passed empty handle");
495 if(!value_node_list_.erase(x))
496 throw Exception::IDNotFound("Canvas::remove_value_node(): ValueNode was not found inside of this canvas");
498 //x->set_parent_canvas(0);
505 Canvas::surefind_canvas(const String &id)
507 if(is_inline() && parent_)
508 return parent_->surefind_canvas(id);
513 // If the ID contains a "#" character, then a filename is
514 // expected on the left side.
515 if(id.find_first_of('#')!=string::npos)
517 // If '#' is the first character, remove it
518 // and attempt to parse the ID again.
520 return surefind_canvas(String(id,1));
522 //! \todo This needs a lot more optimization
523 String file_name(id,0,id.find_first_of('#'));
524 String external_id(id,id.find_first_of('#')+1);
526 file_name=unix_to_local_path(file_name);
528 Canvas::Handle external_canvas;
530 // If the composition is already open, then use it.
531 if(externals_.count(file_name))
532 external_canvas=externals_[file_name];
535 if(is_absolute_path(file_name))
536 external_canvas=open_canvas(file_name);
538 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name);
541 throw Exception::FileNotFound(file_name);
542 externals_[file_name]=external_canvas;
545 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
548 // If we do not have any resolution, then we assume that the
549 // request is for this immediate canvas
550 if(id.find_first_of(':')==string::npos)
552 Children::iterator iter;
554 // Search for the image in the image list,
555 // and return it if it is found
556 for(iter=children().begin();iter!=children().end();iter++)
557 if(id==(*iter)->get_id())
560 // Create a new canvas and return it
561 //synfig::warning("Implicitly creating canvas named "+id);
562 return new_child_canvas(id);
565 // If the first character is the separator, then
566 // this references the root canvas.
568 return get_root()->surefind_canvas(string(id,1));
570 // Now we know that the requested Canvas is in a child
571 // of this canvas. We have to find that canvas and
572 // call "find_canvas" on it, and return the result.
574 String canvas_name=string(id,0,id.find_first_of(':'));
576 Canvas::Handle child_canvas=surefind_canvas(canvas_name);
578 return child_canvas->surefind_canvas(string(id,id.find_first_of(':')+1));
582 Canvas::find_canvas(const String &id)
585 Canvas::Handle::cast_const(
586 const_cast<const Canvas*>(this)->find_canvas(id)
591 Canvas::find_canvas(const String &id)const
593 if(is_inline() && parent_)return parent_->find_canvas(id);
598 // If the ID contains a "#" character, then a filename is
599 // expected on the left side.
600 if(id.find_first_of('#')!=string::npos)
602 // If '#' is the first character, remove it
603 // and attempt to parse the ID again.
605 return find_canvas(String(id,1));
607 //! \todo This needs a lot more optimization
608 String file_name(id,0,id.find_first_of('#'));
609 String external_id(id,id.find_first_of('#')+1);
611 file_name=unix_to_local_path(file_name);
613 Canvas::Handle external_canvas;
615 // If the composition is already open, then use it.
616 if(externals_.count(file_name))
617 external_canvas=externals_[file_name];
620 if(is_absolute_path(file_name))
621 external_canvas=open_canvas(file_name);
623 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name);
626 throw Exception::FileNotFound(file_name);
627 externals_[file_name]=external_canvas;
630 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
633 // If we do not have any resolution, then we assume that the
634 // request is for this immediate canvas
635 if(id.find_first_of(':')==string::npos)
637 Children::const_iterator iter;
639 // Search for the image in the image list,
640 // and return it if it is found
641 for(iter=children().begin();iter!=children().end();iter++)
642 if(id==(*iter)->get_id())
645 throw Exception::IDNotFound("Child Canvas in Parent Canvas: (child)"+id);
648 // If the first character is the separator, then
649 // this references the root canvas.
650 if(id.find_first_of(':')==0)
651 return get_root()->find_canvas(string(id,1));
653 // Now we know that the requested Canvas is in a child
654 // of this canvas. We have to find that canvas and
655 // call "find_canvas" on it, and return the result.
657 String canvas_name=string(id,0,id.find_first_of(':'));
659 Canvas::ConstHandle child_canvas=find_canvas(canvas_name);
661 return child_canvas->find_canvas(string(id,id.find_first_of(':')+1));
668 return new Canvas("Untitled");
672 Canvas::push_back(etl::handle<Layer> x)
674 // int i(x->count());
676 //if(x->count()!=i+1)synfig::info("push_back before %d, after %d",i,x->count());
680 Canvas::push_front(etl::handle<Layer> x)
682 // int i(x->count());
684 //if(x->count()!=i+1)synfig::error("push_front before %d, after %d",i,x->count());
688 Canvas::insert(iterator iter,etl::handle<Layer> x)
690 // int i(x->count());
691 CanvasBase::insert(iter,x);
693 /*if(x->count()!=i+1)
695 synfig::error(__FILE__":%d: Canvas::insert(): ***FAILURE*** before %d, after %d",__LINE__,i,x->count());
697 //throw runtime_error("Canvas Insertion Failed");
706 LooseHandle correct_canvas(this);
707 //while(correct_canvas->is_inline())correct_canvas=correct_canvas->parent();
708 Layer::LooseHandle loose_layer(x);
710 add_connection(loose_layer,
711 sigc::connection::connection(
712 x->signal_added_to_group().connect(
716 &Canvas::add_group_pair),
718 add_connection(loose_layer,
719 sigc::connection::connection(
720 x->signal_removed_from_group().connect(
724 &Canvas::remove_group_pair),
728 if(!x->get_group().empty())
729 add_group_pair(x->get_group(),x);
736 Canvas::push_back_simple(etl::handle<Layer> x)
738 CanvasBase::insert(end(),x);
743 Canvas::erase(iterator iter)
745 if(!(*iter)->get_group().empty())
746 remove_group_pair((*iter)->get_group(),(*iter));
748 // HACK: We really shouldn't be wiping
749 // out these signals entirely. We should
750 // only be removing the specific connections
751 // that we made. At the moment, I'm too
752 // lazy to add the code to keep track
753 // of those connections, and no one else
754 // is using these signals, so I'll just
755 // leave these next two lines like they
756 // are for now - darco 07-30-2004
758 // so don't wipe them out entirely
759 // - dooglus 09-21-2007
760 disconnect_connections(*iter);
762 if(!op_flag_)remove_child(iter->get());
764 CanvasBase::erase(iter);
765 if(!op_flag_)changed();
769 Canvas::clone(const GUID& deriv_guid)const
776 name=get_id()+"_CLONE";
778 throw runtime_error("Cloning of non-inline canvases is not yet supported");
781 Handle canvas(new Canvas(name));
785 canvas->is_inline_=true;
786 // \todo this was setting parent_=0 - is there a reason for that?
787 // this was causing bug 1838132, where cloning an inline canvas that contains an imported image fails
788 // it was failing to ascertain the absolute pathname of the imported image, since it needs the pathname
789 // of the canvas to get that, which is stored in the parent canvas
790 canvas->parent_=parent();
791 //canvas->set_inline(parent());
794 canvas->set_guid(get_guid()^deriv_guid);
797 for(iter=begin();iter!=end();++iter)
799 Layer::Handle layer((*iter)->clone(deriv_guid));
802 assert(layer.count()==1);
804 canvas->push_back(layer);
805 if(!(layer.count()>1))
807 synfig::error("Canvas::clone(): Cloned layer insertion failure!");
808 synfig::error("Canvas::clone(): \tlayer.count()=%d",layer.count());
809 synfig::error("Canvas::clone(): \tlayer->get_name()=%s",layer->get_name().c_str());
810 synfig::error("Canvas::clone(): \tbefore size()=%d",presize);
811 synfig::error("Canvas::clone(): \tafter size()=%d",size());
813 assert(layer.count()>1);
817 synfig::error("Unable to clone layer");
821 canvas->signal_group_pair_removed().clear();
822 canvas->signal_group_pair_added().clear();
828 Canvas::set_inline(LooseHandle parent)
830 if(is_inline_ && parent_)
839 // Have the parent inherit all of the group stuff
841 std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
843 for(iter=group_db_.begin();iter!=group_db_.end();++iter)
845 parent->group_db_[iter->first].insert(iter->second.begin(),iter->second.end());
848 rend_desc()=parent->rend_desc();
852 Canvas::create_inline(Handle parent)
855 //if(parent->is_inline())
856 // return create_inline(parent->parent());
858 Handle canvas(new Canvas("inline"));
859 canvas->set_inline(parent);
864 Canvas::new_child_canvas()
866 if(is_inline() && parent_)
867 return parent_->new_child_canvas();
868 // runtime_error("You cannot create a child Canvas in an inline Canvas");
870 // Create a new canvas
871 children().push_back(create());
872 Canvas::Handle canvas(children().back());
874 canvas->parent_=this;
876 canvas->rend_desc()=rend_desc();
882 Canvas::new_child_canvas(const String &id)
884 if(is_inline() && parent_)
885 return parent_->new_child_canvas(id);
886 // runtime_error("You cannot create a child Canvas in an inline Canvas");
888 // Create a new canvas
889 children().push_back(create());
890 Canvas::Handle canvas(children().back());
893 canvas->parent_=this;
894 canvas->rend_desc()=rend_desc();
900 Canvas::add_child_canvas(Canvas::Handle child_canvas, const synfig::String& id)
902 if(is_inline() && parent_)
903 return parent_->add_child_canvas(child_canvas,id);
905 if(child_canvas->parent() && !child_canvas->is_inline())
906 throw std::runtime_error("Cannot add child canvas because it belongs to someone else!");
909 throw runtime_error("Invalid ID");
914 throw Exception::IDAlreadyExists(id);
916 catch(Exception::IDNotFound)
918 if(child_canvas->is_inline())
919 child_canvas->is_inline_=false;
920 child_canvas->id_=id;
921 children().push_back(child_canvas);
922 child_canvas->parent_=this;
929 Canvas::remove_child_canvas(Canvas::Handle child_canvas)
931 if(is_inline() && parent_)
932 return parent_->remove_child_canvas(child_canvas);
934 if(child_canvas->parent_!=this)
935 throw runtime_error("Given child does not belong to me");
937 if(find(children().begin(),children().end(),child_canvas)==children().end())
938 throw Exception::IDNotFound(child_canvas->get_id());
940 children().remove(child_canvas);
942 child_canvas->parent_=0;
946 Canvas::set_file_name(const String &file_name)
949 parent()->set_file_name(file_name);
952 file_name_=file_name;
953 signal_file_name_changed_();
958 Canvas::signal_file_name_changed()
961 return signal_file_name_changed();
963 return signal_file_name_changed_;
967 Canvas::get_file_name()const
970 return parent()->get_file_name();
975 Canvas::get_file_path()const
978 return parent()->get_file_path();
979 return dirname(file_name_);
984 Canvas::get_meta_data(const String& key)const
986 if(!meta_data_.count(key))
988 return meta_data_.find(key)->second;
992 Canvas::set_meta_data(const String& key, const String& data)
994 if(meta_data_[key]!=data)
996 meta_data_[key]=data;
997 signal_meta_data_changed()(key);
998 signal_meta_data_changed(key)();
1003 Canvas::erase_meta_data(const String& key)
1005 if(meta_data_.count(key))
1007 meta_data_.erase(key);
1008 signal_meta_data_changed()(key);
1009 signal_meta_data_changed(key)();
1014 Canvas::get_meta_data_keys()const
1016 std::list<String> ret;
1018 std::map<String,String>::const_iterator iter;
1020 for(iter=meta_data_.begin();!(iter==meta_data_.end());++iter)
1021 ret.push_back(iter->first);
1026 /* note - the "Motion Blur" and "Duplicate" layers need the dynamic
1027 parameters of any PasteCanvas layers they loop over to be
1028 maintained. When the variables in the following function
1029 refer to "motion blur", they mean either of these two
1032 synfig::optimize_layers(Time time, Context context, Canvas::Handle op_canvas, bool seen_motion_blur_in_parent)
1036 std::vector< std::pair<float,Layer::Handle> > sort_list;
1037 int i, motion_blur_i=0; // motion_blur_i is for resolving which layer comes first in the event of a z_depth tie
1038 float motion_blur_z_depth=0; // the z_depth of the least deep motion blur layer in this context
1039 bool seen_motion_blur_locally = false;
1040 bool motion_blurred; // the final result - is this layer blurred or not?
1042 // If the parent didn't cause us to already be motion blurred,
1043 // check whether there's a motion blur in this context,
1044 // and if so, calculate its z_depth.
1045 if (!seen_motion_blur_in_parent)
1046 for(iter=context,i=0;*iter;iter++,i++)
1048 Layer::Handle layer=*iter;
1050 // If the layer isn't active, don't worry about it
1051 if(!layer->active())
1054 // Any layer with an amount of zero is implicitly disabled.
1055 ValueBase value(layer->get_param("amount"));
1056 if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1059 if(layer->get_name()=="MotionBlur" || layer->get_name()=="duplicate")
1061 float z_depth(layer->get_z_depth()*1.0001+i);
1063 // If we've seen a motion blur before in this context...
1064 if (seen_motion_blur_locally)
1066 // ... then we're only interested in this one if it's less deep...
1067 if (z_depth < motion_blur_z_depth)
1069 motion_blur_z_depth = z_depth;
1073 // ... otherwise we're always interested in it.
1076 motion_blur_z_depth = z_depth;
1078 seen_motion_blur_locally = true;
1083 // Go ahead and start romping through the canvas to paste
1084 for(iter=context,i=0;*iter;iter++,i++)
1086 Layer::Handle layer=*iter;
1087 float z_depth(layer->get_z_depth()*1.0001+i);
1089 // If the layer isn't active, don't worry about it
1090 if(!layer->active())
1093 // Any layer with an amount of zero is implicitly disabled.
1094 ValueBase value(layer->get_param("amount"));
1095 if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1098 // note: this used to include "&& paste_canvas->get_time_offset()==0", but then
1099 // time-shifted layers weren't being sorted by z-depth (bug #1806852)
1100 if(layer->get_name()=="PasteCanvas")
1102 Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1104 // we need to blur the sub canvas if:
1105 // our parent is blurred,
1106 // or the child is lower than a local blur,
1107 // or the child is at the same z_depth as a local blur, but later in the context
1110 if (seen_motion_blur_in_parent) synfig::info("seen BLUR in parent\n");
1111 else if (seen_motion_blur_locally)
1112 if (z_depth > motion_blur_z_depth) synfig::info("paste is deeper than BLUR\n");
1113 else if (z_depth == motion_blur_z_depth) { synfig::info("paste is same depth as BLUR\n");
1114 if (i > motion_blur_i) synfig::info("paste is physically deeper than BLUR\n");
1115 else synfig::info("paste is less physically deep than BLUR\n");
1116 } else synfig::info("paste is less deep than BLUR\n");
1117 else synfig::info("no BLUR at all\n");
1120 motion_blurred = (seen_motion_blur_in_parent ||
1121 (seen_motion_blur_locally &&
1122 (z_depth > motion_blur_z_depth ||
1123 (z_depth == motion_blur_z_depth && i > motion_blur_i))));
1125 Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
1126 Canvas::Handle paste_sub_canvas = paste_canvas->get_sub_canvas();
1127 if(paste_sub_canvas)
1128 optimize_layers(time, paste_sub_canvas->get_context(),sub_canvas,motion_blurred);
1130 // \todo: uncommenting the following breaks the rendering of at least examples/backdrop.sifz quite severely
1131 // #define SYNFIG_OPTIMIZE_PASTE_CANVAS
1132 #ifdef SYNFIG_OPTIMIZE_PASTE_CANVAS
1133 Canvas::iterator sub_iter;
1135 // Determine if we can just remove the paste canvas altogether
1136 if (paste_canvas->get_blend_method() == Color::BLEND_COMPOSITE &&
1137 paste_canvas->get_amount() == 1.0f &&
1138 paste_canvas->get_zoom() == 0 &&
1139 paste_canvas->get_time_offset() == 0 &&
1140 paste_canvas->get_origin() == Point(0,0) )
1142 for(sub_iter=sub_canvas->begin();sub_iter!=sub_canvas->end();++sub_iter)
1144 Layer* layer=sub_iter->get();
1146 // any layers that deform end up breaking things
1147 // so do things the old way if we run into anything like this
1148 if(!dynamic_cast<Layer_NoDeform*>(layer))
1151 ValueBase value(layer->get_param("blend_method"));
1152 if(value.get_type()!=ValueBase::TYPE_INTEGER || value.get(int())!=(int)Color::BLEND_COMPOSITE)
1156 // It has turned out that we don't need a paste canvas
1157 // layer, so just go ahead and add all the layers onto
1158 // the current stack and be done with it
1159 while(sub_canvas->size())
1161 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,sub_canvas->front()));
1162 //op_canvas->push_back_simple(sub_canvas->front());
1163 sub_canvas->pop_front();
1169 #endif // SYNFIG_OPTIMIZE_PASTE_CANVAS
1171 Layer::Handle new_layer(Layer::create("PasteCanvas"));
1172 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(false);
1175 Layer::DynamicParamList dynamic_param_list(paste_canvas->dynamic_param_list());
1176 for(Layer::DynamicParamList::const_iterator iter(dynamic_param_list.begin()); iter != dynamic_param_list.end(); ++iter)
1177 new_layer->connect_dynamic_param(iter->first, iter->second);
1179 Layer::ParamList param_list(paste_canvas->get_param_list());
1180 //param_list.erase("canvas");
1181 new_layer->set_param_list(param_list);
1182 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_sub_canvas(sub_canvas);
1183 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(true);
1186 else // not a PasteCanvas - does it use blend method 'Straight'?
1188 /* when we use the 'straight' blend method, every pixel on the layer affects the layers underneath,
1189 * not just the non-transparent pixels; the following workarea wraps non-pastecanvas layers in a
1190 * new pastecanvas to ensure that the straight blend affects the full plane, not just the area
1191 * within the layer's bounding box
1194 // \todo: this code probably needs modification to work properly with motionblur and duplicate
1195 etl::handle<Layer_Composite> composite = etl::handle<Layer_Composite>::cast_dynamic(layer);
1197 /* some layers (such as circle) don't touch pixels that aren't
1198 * part of the circle, so they don't get blended correctly when
1199 * using a straight blend. so we encapsulate the circle, and the
1200 * encapsulation layer takes care of the transparent pixels
1201 * for us. if we do that for all layers, however, then the
1202 * distortion layers no longer work, since they have no
1203 * context to work on. the Layer::reads_context() method
1204 * returns true for layers which need to be able to see
1205 * their context. we can't encapsulate those.
1208 Color::is_straight(composite->get_blend_method()) &&
1209 !composite->reads_context())
1211 Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
1212 sub_canvas->push_back(composite = composite->clone());
1213 layer = Layer::create("PasteCanvas");
1214 composite->set_description(strprintf("Wrapped clone of '%s'", composite->get_non_empty_description().c_str()));
1215 layer->set_description(strprintf("PasteCanvas wrapper for '%s'", composite->get_non_empty_description().c_str()));
1216 Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1217 paste_canvas->set_blend_method(composite->get_blend_method());
1218 paste_canvas->set_amount(composite->get_amount());
1219 sub_canvas->set_time(time); // region and outline don't calculate their bounding rects until their time is set
1220 composite->set_blend_method(Color::BLEND_STRAIGHT); // do this before calling set_sub_canvas(), but after set_time()
1221 composite->set_amount(1.0f); // after set_time()
1222 paste_canvas->set_sub_canvas(sub_canvas);
1226 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,layer));
1227 //op_canvas->push_back_simple(layer);
1231 stable_sort(sort_list.begin(),sort_list.end());
1232 std::vector< std::pair<float,Layer::Handle> >::iterator iter2;
1233 for(iter2=sort_list.begin();iter2!=sort_list.end();++iter2)
1234 op_canvas->push_back_simple(iter2->second);
1235 op_canvas->op_flag_=true;
1239 Canvas::get_times_vfunc(Node::time_set &set) const
1241 const_iterator i = begin(),
1244 for(; i != iend; ++i)
1246 const Node::time_set &tset = (*i)->get_times();
1247 set.insert(tset.begin(),tset.end());
1251 std::set<etl::handle<Layer> >
1252 Canvas::get_layers_in_group(const String&group)
1254 if(is_inline() && parent_)
1255 return parent_->get_layers_in_group(group);
1257 if(group_db_.count(group)==0)
1258 return std::set<etl::handle<Layer> >();
1259 return group_db_.find(group)->second;
1263 Canvas::get_groups()const
1265 if(is_inline() && parent_)
1266 return parent_->get_groups();
1268 std::set<String> ret;
1269 std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
1270 for(iter=group_db_.begin();iter!=group_db_.end();++iter)
1271 ret.insert(iter->first);
1276 Canvas::get_group_count()const
1278 if(is_inline() && parent_)
1279 return parent_->get_group_count();
1281 return group_db_.size();
1285 Canvas::add_group_pair(String group, etl::handle<Layer> layer)
1287 group_db_[group].insert(layer);
1288 if(group_db_[group].size()==1)
1289 signal_group_added()(group);
1291 signal_group_changed()(group);
1293 signal_group_pair_added()(group,layer);
1295 if(is_inline() && parent_)
1296 return parent_->add_group_pair(group,layer);
1300 Canvas::remove_group_pair(String group, etl::handle<Layer> layer)
1302 group_db_[group].erase(layer);
1304 signal_group_pair_removed()(group,layer);
1306 if(group_db_[group].empty())
1308 group_db_.erase(group);
1309 signal_group_removed()(group);
1312 signal_group_changed()(group);
1314 if(is_inline() && parent_)
1315 return parent_->remove_group_pair(group,layer);
1319 Canvas::add_connection(etl::loose_handle<Layer> layer, sigc::connection connection)
1321 connections_[layer].push_back(connection);
1325 Canvas::disconnect_connections(etl::loose_handle<Layer> layer)
1327 std::vector<sigc::connection>::iterator iter;
1328 for(iter=connections_[layer].begin();iter!=connections_[layer].end();++iter)
1330 connections_[layer].clear();
1334 Canvas::rename_group(const String&old_name,const String&new_name)
1336 if(is_inline() && parent_)
1337 return parent_->rename_group(old_name,new_name);
1340 std::map<String,std::set<etl::handle<Layer> > >::iterator iter;
1341 iter=group_db_.find(old_name);
1342 if(iter!=group_db_.end())
1343 for(++iter;iter!=group_db_.end() && iter->first.find(old_name)==0;iter=group_db_.find(old_name),++iter)
1345 String name(iter->first,old_name.size(),String::npos);
1347 rename_group(iter->first,name);
1351 std::set<etl::handle<Layer> > layers(get_layers_in_group(old_name));
1352 std::set<etl::handle<Layer> >::iterator iter;
1354 for(iter=layers.begin();iter!=layers.end();++iter)
1356 (*iter)->remove_from_group(old_name);
1357 (*iter)->add_to_group(new_name);