CVSROOT: /sources/gnash Module name: gnash Changes by: Zou Lunkai <zoulunkai> 07/12/03 07:06:15
Modified files: . : ChangeLog server : dlist.cpp dlist.h sprite_instance.cpp sprite_instance.h testsuite/misc-ming.all: loop_test-Runner.cpp loop_test10.c Log message: * server/dlist.{h, cpp}: add mergeDisplayList() for timeline control attempt5. * server/sprite_instance.{h,cpp): restoreDisplayList(), use the new mergeDisplayList() interface; cleanups for executing a PlaceObject2 tag. * testsuite/misc-ming.all/loop_test10.c: xchecks to checks. * testsuite/misc-ming.all/loop_test-Runner.cpp: allow a invalidated bound detection regression, one check to xcheck. This regression is caused by always invalidating a looping back character, could be fixed in later optimization step. CVSWeb URLs: http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.5059&r2=1.5060 http://cvs.savannah.gnu.org/viewcvs/gnash/server/dlist.cpp?cvsroot=gnash&r1=1.104&r2=1.105 http://cvs.savannah.gnu.org/viewcvs/gnash/server/dlist.h?cvsroot=gnash&r1=1.57&r2=1.58 http://cvs.savannah.gnu.org/viewcvs/gnash/server/sprite_instance.cpp?cvsroot=gnash&r1=1.401&r2=1.402 http://cvs.savannah.gnu.org/viewcvs/gnash/server/sprite_instance.h?cvsroot=gnash&r1=1.151&r2=1.152 http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/misc-ming.all/loop_test-Runner.cpp?cvsroot=gnash&r1=1.11&r2=1.12 http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/misc-ming.all/loop_test10.c?cvsroot=gnash&r1=1.2&r2=1.3 Patches: Index: ChangeLog =================================================================== RCS file: /sources/gnash/gnash/ChangeLog,v retrieving revision 1.5059 retrieving revision 1.5060 diff -u -b -r1.5059 -r1.5060 --- ChangeLog 3 Dec 2007 05:29:33 -0000 1.5059 +++ ChangeLog 3 Dec 2007 07:06:14 -0000 1.5060 @@ -1,3 +1,13 @@ +2007-12-03 Zou Lunkai <[EMAIL PROTECTED]> + * server/dlist.{h, cpp}: add mergeDisplayList() for timeline control attempt5. + * server/sprite_instance.{h,cpp): restoreDisplayList(), use the new + mergeDisplayList() interface; cleanups for executing a PlaceObject2 tag. + * testsuite/misc-ming.all/loop_test10.c: xchecks to checks. + * testsuite/misc-ming.all/loop_test-Runner.cpp: allow a invalidated bound + detection regression, one check to xcheck. This regression is caused by + always invalidating a looping back character, could be fixed in later + optimization step. + 2007-12-02 Bastiaan Jacques <[EMAIL PROTECTED]> * backend/render_handler{.h,_ogl.cpp,_agg.cpp,_cairo.cpp}, Index: server/dlist.cpp =================================================================== RCS file: /sources/gnash/gnash/server/dlist.cpp,v retrieving revision 1.104 retrieving revision 1.105 diff -u -b -r1.104 -r1.105 --- server/dlist.cpp 27 Nov 2007 11:28:50 -0000 1.104 +++ server/dlist.cpp 3 Dec 2007 07:06:14 -0000 1.105 @@ -744,6 +744,34 @@ } + +void +DisplayList::destroy() +{ + //GNASH_REPORT_FUNCTION; + + testInvariant(); + + // Should we start looking from beginNonRemoved ? + // If I try, I get a failure in swfdec/gotoframe.swf + for (iterator it = _charsByDepth.begin(), itEnd = _charsByDepth.end(); it != itEnd; ) + { + // make a copy + DisplayItem di = *it; + + // skip if already unloaded + if ( di->isDestroyed() ) + { + ++it; + continue; + } + + di->destroy(); + it = _charsByDepth.erase(it); + } + testInvariant(); +} + // Display the referenced characters. Lower depths // are obscured by higher depths. void @@ -1003,6 +1031,156 @@ _charsByDepth.sort(DisplayItemDepthLess()); } +void +DisplayList::mergeDisplayList(DisplayList & newList) +{ + testInvariant(); + + iterator itOld = beginNonRemoved(_charsByDepth); + iterator itNew = beginNonRemoved(newList._charsByDepth); + + iterator itOldEnd = staticZoneEnd(_charsByDepth); + iterator itNewEnd = staticZoneEnd(newList._charsByDepth); + + while( itOld != itOldEnd ) + { + iterator itOldBack = itOld; + + boost::intrusive_ptr<character> chOld = itOldBack->get(); + int depthOld = chOld->get_depth(); + + while( itNew != itNewEnd ) + { + iterator itNewBack = itNew; + + boost::intrusive_ptr<character> chNew = itNewBack->get(); + int depthNew = chNew->get_depth(); + + // unload the old character if it is not in the new list + if( depthOld < depthNew ) + { + itOld++; + + _charsByDepth.erase(itOldBack); + + if ( chOld->unload() ) + { + reinsertRemovedCharacter(chOld); + } + else + { + chOld->destroy(); + } + + break; + } + // if depth is occupied in both lists + else if( depthOld == depthNew ) + { + itOld++; + itNew++; + + bool is_ratio_compatible = ( ( chOld->get_ratio() == chNew->get_ratio() ) + || ( chOld->get_ratio()==0 && chNew->get_ratio()==character::noRatioValue ) + || ( chOld->get_ratio()==character::noRatioValue && chNew->get_ratio()==0 ) ); + + if( !is_ratio_compatible || chOld->isDynamic() || !chOld->isActionScriptReferenceable() ) + { + // replace the old character with the character in the new depth + _charsByDepth.insert(itOldBack, *itNewBack); + _charsByDepth.erase(itOldBack); + + // unload the old character + if ( chOld->unload() ) + { + reinsertRemovedCharacter(chOld); + } + else + { + chOld->destroy(); + } + } + else + { + newList._charsByDepth.erase(itNewBack); + + // replace the transformation matrix if the old character accepts transform + if( chOld->get_accept_anim_moves() ) + { + chOld->set_matrix(chNew->get_matrix()); + chOld->set_cxform(chNew->get_cxform()); + + // TODO: update the name if needed + //chOld->set_name(chNew->get_name().c_str()); + } + chNew->unload(); + chNew->destroy(); + } + + break; + } + // add the new character if it is not in the old list + else + { + itNew++; + + _charsByDepth.insert(itOldBack, *itNewBack ); + } + }// end of while + + if( itNew == itNewEnd ) + { + break; + } + }// end of while + + // unload remaining characters in old list + while( itOld != itOldEnd ) + { + boost::intrusive_ptr<character> chOld = itOld->get(); + + itOld = _charsByDepth.erase(itOld); + + if ( chOld->unload() ) + { + reinsertRemovedCharacter(chOld); + } + else + { + chOld->destroy(); + } + } + + // add remaining characters in new list to the old list + if( itNew != itNewEnd ) + { + _charsByDepth.insert(itOld, itNew, itNewEnd); + } + + // Copy all unloaded characters from the new display list to the old display list, + // and clear the new display list + for (itNew = newList._charsByDepth.begin(); itNew != itNewEnd; ++itNew) + { + boost::intrusive_ptr<character> chNew = itNew->get(); + int depthNew = chNew->get_depth(); + + if( chNew->isUnloaded() ) + { + iterator it = find_if(_charsByDepth.begin(), _charsByDepth.end(), + DepthGreaterOrEqual(depthNew)); + + _charsByDepth.insert(it, *itNew); + } + } + + // clear the new display list after merge + newList._charsByDepth.clear(); + + testInvariant(); +} + + + std::ostream& operator<< (std::ostream& os, const DisplayList& dl) { os << "By depth: "; @@ -1025,14 +1203,13 @@ DisplayList::reinsertRemovedCharacter(boost::intrusive_ptr<character> ch) { assert(ch->isUnloaded()); + testInvariant(); // TODO: have this done by character::unload() instead ? int oldDepth = ch->get_depth(); int newDepth = character::removedDepthOffset - oldDepth; ch->set_depth(newDepth); - testInvariant(); - // TODO: optimize this by searching from the end(lowest depth). container_type::iterator it = find_if( _charsByDepth.begin(), _charsByDepth.end(), @@ -1059,6 +1236,20 @@ DepthGreaterOrEqual(character::removedDepthOffset - character::staticDepthOffset)); } +/*private static*/ +DisplayList::iterator +DisplayList::staticZoneEnd(container_type& c) +{ + return std::find_if(c.begin(), c.end(), DepthGreaterOrEqual(0)); +} + +/*private static*/ +DisplayList::const_iterator +DisplayList::staticZoneEnd(const container_type& c) +{ + return std::find_if(c.begin(), c.end(), DepthGreaterOrEqual(0)); +} + void DisplayList::removeUnloaded() { Index: server/dlist.h =================================================================== RCS file: /sources/gnash/gnash/server/dlist.h,v retrieving revision 1.57 retrieving revision 1.58 diff -u -b -r1.57 -r1.58 --- server/dlist.h 1 Dec 2007 00:14:59 -0000 1.57 +++ server/dlist.h 3 Dec 2007 07:06:15 -0000 1.58 @@ -215,6 +215,8 @@ /// bool unload(); + void destroy(); + /// Add all characters in the list, maintaining depth-order // /// @param chars @@ -382,6 +384,10 @@ /// void sort (); + /// \brief + /// merge the given display list + void mergeDisplayList(DisplayList& newList); + bool operator==(const DisplayList& other) const { return _charsByDepth == other._charsByDepth; } bool operator!=(const DisplayList& other) const { return _charsByDepth != other._charsByDepth; } @@ -397,9 +403,16 @@ /// Return an iterator to the first element of the container NOT in the "removed" depth zone static iterator beginNonRemoved(container_type& c); - /// Return an iterator to the first element of the container NOT in the "removed" depth zone + /// Return an constant iterator to the first element of the container NOT in the "removed" depth zone static const_iterator beginNonRemoved(const container_type& c); + /// Return an iterator succeeding the last element in the static zone + static iterator staticZoneEnd(container_type& c); + + /// Return an constant iterator succeeding the last element in the static zone + static const_iterator staticZoneEnd(const container_type& c); + + /// Re-insert a removed-from-stage character after appropriately /// shifting its depth based on the character::removedDepthOffset /// value. Index: server/sprite_instance.cpp =================================================================== RCS file: /sources/gnash/gnash/server/sprite_instance.cpp,v retrieving revision 1.401 retrieving revision 1.402 diff -u -b -r1.401 -r1.402 --- server/sprite_instance.cpp 30 Nov 2007 11:26:05 -0000 1.401 +++ server/sprite_instance.cpp 3 Dec 2007 07:06:15 -0000 1.402 @@ -2546,43 +2546,26 @@ // for jump-forwards would do assert(tgtFrame <= m_current_frame); - is_jumping_back = true; //remember we are jumping back - - // 1. Find all "timeline depth" for the target frame, querying the - // Timeline object in the sprite/movie definition (see implementation details) - // 2. Remove step - // 2.1 Remove all current dynamic instances found in static depth zone - // 2.2 Remove all current timeline instances at a depth NOT in the set found in step 1 - // 2.3 Remove all non-script-referencable instances, suboptimal! - - // NOTE: reset() will call our set_invalidated() before making any change - m_display_list.reset(*m_def, tgtFrame, *this); + // Just invalidate this character before jumping back. + // Should be optimized, but the invalidating model is not clear enough, + // and there are some old questions spreading the source files. + set_invalidated(); - // 3. Execute all displaylist tags from first to target frame, with - // target frame tag execution including ACTION tags + is_jumping_back = true; //remember we are jumping back for (size_t f = 0; f<tgtFrame; ++f) { - // - // Set m_current_frame so it is correct (0-based) during - // execute_frame_tags and thus timeline objects placement - // (need to correctly set TimelineInfo record). - // m_current_frame = f; execute_frame_tags(f, TAG_DLIST); } - // call_frame (setting _callignFrameActions) should never trigger ::advance, - // at most it shoudl trigger goto_frame which would temporarly set _callingFrameAction to false - // ::advance and ::goto_frame are supposedly the only callers to restoreDisplayList - // - assert(!_callingFrameActions); - - // Finally, execute target frame tags, both ACTION and DLIST + // Execute both action tags and DLIST tags of the target frame m_current_frame = tgtFrame; execute_frame_tags(tgtFrame, TAG_DLIST|TAG_ACTION); is_jumping_back = false; // finished jumping back + + m_display_list.mergeDisplayList(m_tmp_display_list); } // 0-based frame number ! @@ -2637,14 +2620,6 @@ getTargetPath().c_str(), target_frame_number, m_current_frame); #endif - // TODO: the assertion fails against all.swf with NEW_TIMELINE_DESIGN - // (swf from http://www.ferryhalim.com/orisinal/) - //assert(! isUnloaded() ); - if ( isUnloaded() ) - { - log_error("Sprite %s unloaded on gotoFrame call... let Gnash developers know please", getTarget().c_str()); - } - // goto_frame stops by default. // ActionGotoFrame tells the movieClip to go to the target frame // and stop at that frame. @@ -2723,16 +2698,6 @@ restoreDisplayList(target_frame_number); assert(m_current_frame == target_frame_number); _callingFrameActions = callingFrameActionsBackup; - - // <UdoG> current design is sub-optimal because it causes unnecessary - // redraw. Consider a static graphic that stays at it's position all - // the time. When looping betwen two frames - // gotoAndPlay(_currentframe-1); - // then restoreDisplayList() will remove that character and - // execute_frame_tags() will insert it again. So the next - // set_invalidated() call (which currently *is* correct) will cause - // redraw of the whole sprite even if it doesn't change visually - // at all. } else // Go forward to a later frame @@ -2749,9 +2714,6 @@ } assert(m_current_frame == target_frame_number); -#if defined(GNASH_DEBUG_TIMELINE) - cout << "At end of DisplayList reconstruction, m_current_frame is " << m_current_frame << endl; -#endif // Now execute target frame tags (queuing actions) // NOTE: just in case we're being called by code in a called frame @@ -2860,31 +2822,16 @@ return NULL; } - character* existing_char = m_display_list.get_character_at_depth(depth); + DisplayList& dlist = const_cast<DisplayList &>( getDisplayList() ); + character* existing_char = dlist.get_character_at_depth(depth); - boost::intrusive_ptr<character> ch; - - bool is_ratio_compatible=true; if(existing_char) { - is_ratio_compatible= (ratio == existing_char->get_ratio()) - || (ratio==character::noRatioValue && existing_char->get_ratio()==0) - || (ratio==0 && existing_char->get_ratio()==character::noRatioValue); - } - - // Place a new character if: - // (1)target depth is empty - // (2)target depth is not empty but the character has a different ratio - // in jump-back-mode. - if(!existing_char || (is_jumping_back && !is_ratio_compatible)) - { - // TODO: Optimize this. - // Create_character_instance() is too expensive for some characters. - // All I need to do here might be just syntetize a new instance name, - // the real character is not needed. - // To decide whether a new instance name is needed for static characters, - // a single character_id should be enough. - ch = cdef->create_character_instance(this, character_id); + return NULL; + } + else + { + boost::intrusive_ptr<character> ch = cdef->create_character_instance(this, character_id); ch->setTimelineInfo(depth, m_current_frame, false); if(name) @@ -2904,7 +2851,7 @@ ch->add_event_handler(ev->event(), ev->action()); } - m_display_list.place_character( + dlist.place_character( ch.get(), depth, color_transform, @@ -2914,20 +2861,6 @@ return ch.get(); } - - // move the existing charater if has same ratio in jump-back-mode - if(existing_char && is_jumping_back && is_ratio_compatible) - { - // remove the created character from the key listener list, - // it might be there(eg. button_character). - // TODO: optimize this. This is not necessary if we don't create - // instances blindly above. - if ( ch ) _vm.getRoot().remove_key_listener(ch.get()); - - move_display_object(depth, &color_transform, &mat, ratio, clip_depth); - } - - return NULL; } void @@ -2951,7 +2884,9 @@ } assert(cdef); - character* existing_char = m_display_list.get_character_at_depth(depth); + DisplayList& dlist = const_cast<DisplayList &>( getDisplayList() ); + character* existing_char = dlist.get_character_at_depth(depth); + if (existing_char) { // if the existing character is not a shape, move it instead of replace @@ -2967,10 +2902,13 @@ ch->setTimelineInfo(depth, m_current_frame, true); replace_display_object( - ch.get(), name, depth, + ch.get(), + name, + depth, color_transform, mat, - ratio, clip_depth); + ratio, + clip_depth); } } else // non-existing character @@ -2997,7 +2935,9 @@ ch->set_name(name); } - m_display_list.replace_character( + DisplayList& dlist = const_cast<DisplayList &>( getDisplayList() ); + + dlist.replace_character( ch, depth, color_transform, @@ -3952,6 +3892,8 @@ void sprite_instance::destroy() { + m_display_list.destroy(); + /// We don't need these anymore clearProperties(); Index: server/sprite_instance.h =================================================================== RCS file: /sources/gnash/gnash/server/sprite_instance.h,v retrieving revision 1.151 retrieving revision 1.152 diff -u -b -r1.151 -r1.152 --- server/sprite_instance.h 23 Nov 2007 12:21:26 -0000 1.151 +++ server/sprite_instance.h 3 Dec 2007 07:06:15 -0000 1.152 @@ -454,7 +454,8 @@ int ratio, int clip_depth) { - m_display_list.move_display_object(depth, color_xform, mat, ratio, clip_depth); + DisplayList& dlist = const_cast<DisplayList &>( getDisplayList() ); + dlist.move_display_object(depth, color_xform, mat, ratio, clip_depth); } @@ -505,7 +506,8 @@ void remove_display_object(int depth, int /* id */) { set_invalidated(); - m_display_list.remove_display_object(depth); + DisplayList& dlist = const_cast<DisplayList &>( getDisplayList() ); + dlist.remove_display_object(depth); } @@ -674,7 +676,11 @@ const DisplayList& getDisplayList() const { + if(! is_jumping_back) { return m_display_list; + } else { + return m_tmp_display_list; + } } /// Return the next highest available depth @@ -929,6 +935,9 @@ /// Current Display List contents. DisplayList m_display_list; + /// temporary display list used for timeline construction during jump back + DisplayList m_tmp_display_list; + /// The canvas for dynamic drawing // /// WARNING: since DynamicShape is a character_def, which is Index: testsuite/misc-ming.all/loop_test-Runner.cpp =================================================================== RCS file: /sources/gnash/gnash/testsuite/misc-ming.all/loop_test-Runner.cpp,v retrieving revision 1.11 retrieving revision 1.12 diff -u -b -r1.11 -r1.12 --- testsuite/misc-ming.all/loop_test-Runner.cpp 1 Dec 2007 00:15:02 -0000 1.11 +++ testsuite/misc-ming.all/loop_test-Runner.cpp 3 Dec 2007 07:06:15 -0000 1.12 @@ -125,7 +125,7 @@ // visually, it seems so, but loop-back is too complex // to be sure (ie: xtrace window text might be reset or something) // I checked that it's not resetDisplayList invalidating it... - check( tester.getInvalidatedRanges().isNull() ); + xcheck( tester.getInvalidatedRanges().isNull() ); } else // we did nothing here... { Index: testsuite/misc-ming.all/loop_test10.c =================================================================== RCS file: /sources/gnash/gnash/testsuite/misc-ming.all/loop_test10.c,v retrieving revision 1.2 retrieving revision 1.3 diff -u -b -r1.2 -r1.3 --- testsuite/misc-ming.all/loop_test10.c 23 Nov 2007 02:39:07 -0000 1.2 +++ testsuite/misc-ming.all/loop_test10.c 3 Dec 2007 07:06:15 -0000 1.3 @@ -174,12 +174,11 @@ check_equals(mo, "mc1Initialized", "2"); check_equals(mo, "mc2Initialized", "2"); - xcheck_equals(mo, "mc3Initialized", "1"); + check_equals(mo, "mc3Initialized", "1"); check_equals(mo, "mc1Unloaded", "2"); check_equals(mo, "mc2Unloaded", "2"); - xcheck_equals(mo, "mc3Unloaded", "0"); + check_equals(mo, "mc3Unloaded", "0"); - // Don't bother to fix this order untill timeline control is fixed. xcheck_equals(mo, "asOrder", "'0+1+2+3+4+5+1+2+3+5+'"); add_actions(mo, "totals(); stop();"); SWFMovie_nextFrame(mo); // frame 7 _______________________________________________ Gnash-commit mailing list Gnash-commit@gnu.org http://lists.gnu.org/mailman/listinfo/gnash-commit