1 // MovieClip.h:  Stateful live Sprite instance, for Gnash.
2 //
3 //   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
4 //   Free Software Foundation, Inc
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19 
20 // Stateful live Sprite instance
21 
22 #ifndef GNASH_MOVIECLIP_H
23 #define GNASH_MOVIECLIP_H
24 
25 #ifdef HAVE_CONFIG_H
26 #include "gnashconfig.h"
27 #endif
28 
29 #include <vector>
30 #include <map>
31 #include <string>
32 #include <boost/ptr_container/ptr_list.hpp>
33 #include <boost/intrusive_ptr.hpp>
34 
35 #include "ControlTag.h"
36 #include "movie_definition.h" // for inlines
37 #include "DisplayObjectContainer.h"
38 #include "as_environment.h" // for composition
39 #include "DynamicShape.h" // for composition
40 #include "dsodefs.h" // for DSOEXPORT
41 
42 // Forward declarations
43 namespace gnash {
44     class Movie;
45     class swf_event;
46     class drag_state;
47     class LoadVariablesThread;
48     class GradientRecord;
49     class TextField;
50     class BitmapData_as;
51     class CachedBitmap;
52     class DisplayList;
53     namespace SWF {
54         class PlaceObject2Tag;
55     }
56 }
57 
58 namespace gnash {
59 
60 /// A MovieClip is a container for DisplayObjects.
61 //
62 /// TODO: This class should inherit from Sprite
63 //
64 /// In AS3 is it distinguished from a Sprite by having a timeline, i.e.
65 /// more than one frame. In AS2, there is no Sprite class.
66 //
67 /// There are basically two types of MovieClip: dynamic and non-dynamic.
68 /// Dynamic clips are created using createEmptyMovieClip() or
69 /// duplicateMovieClip(). Non-dynamic MovieClips are parsed from a SWF file.
70 /// The isDynamic() member function is the only way to tell the difference
71 /// (see following paragraph).
72 //
73 /// The presence of a definition (the _def member) reveals whether the
74 /// MovieClip was constructed with an immutable definition or not. MovieClips
75 /// created using createEmptyMovieClip() have no definition. MovieClips
76 /// constructed using duplicateMovieClip() have the same definition as the
77 /// duplicated clip. They are "dynamic", but may have a definition!
78 //
79 /// A MovieClip always has an _swf member. This is the top-level SWF
80 /// (Movie) containing either the definition or the code from
81 /// which the MovieClip was created. The _url member and SWF version are
82 /// dependent on the _swf. Exports are also sought in this Movie.
83 class DSOTEXPORT MovieClip : public DisplayObjectContainer
84 {
85 public:
86 
87     typedef std::vector<TextField*> TextFields;
88 
89     /// A container for textfields, indexed by their variable name
90     typedef std::map<ObjectURI, TextFields, ObjectURI::LessThan>
91         TextFieldIndex;
92 
93     typedef std::map<std::string, std::string> MovieVariables;
94 
95     typedef movie_definition::PlayList PlayList;
96 
97     enum PlayState
98     {
99         PLAYSTATE_PLAY,
100         PLAYSTATE_STOP
101     };
102 
103     /// Construct a MovieClip instance
104     //
105     /// @param def
106     ///     Pointer to the movie_definition this object is an
107     ///     instance of (may be a top-level movie or a sprite).
108     ///     This may be 0 if there is no immutable definition.
109     ///
110     /// @param root
111     /// The "relative" _swf of this sprite, which is the
112     /// instance of top-level sprite defined by the same
113     /// SWF that also contained *this* sprite definition.
114     /// Note that this can be *different* from the top-level
115     /// movie accessible through the VM, in case this sprite
116     /// was defined in an externally loaded movie.
117     ///
118     /// @param parent
119     ///     Parent of the created instance in the display list.
120     ///     May be 0 for top-level movies (_level#).
121     MovieClip(as_object* object, const movie_definition* def,
122             Movie* root, DisplayObject* parent);
123 
124     virtual ~MovieClip();
125 
126     // Return the originating SWF
127     virtual Movie* get_root() const;
128 
129     virtual bool trackAsMenu();
130 
131     /// Queue event in the global action queue.
132     //
133     /// notifyEvent(id) will be called by execution of the queued
134     /// action
135     void queueEvent(const event_id& id, int lvl);
136 
137     void queueLoad();
138 
139     /// Return the _root ActionScript property of this sprite.
140     //
141     /// Relative or absolute is determined by the _lockroot property,
142     /// see getLockRoot and setLockRoot. May return this.
143     virtual MovieClip* getAsRoot();
144 
145     /// Get the composite bounds of all component drawing elements
146     virtual SWFRect getBounds() const;
147 
148     // See dox in DisplayObject.h
149     virtual bool pointInShape(std::int32_t x, std::int32_t y) const;
150 
151     // See dox in DisplayObject.h
152     virtual bool pointInVisibleShape(std::int32_t x, std::int32_t y) const;
153 
154     /// return true if the given point is located in a(this) hitable sprite.
155     ///
156     /// all sprites except mouse-insensitive dynamic masks are hitable.
157     /// _visible property is ignored for hitable DisplayObjects.
158     virtual bool pointInHitableShape(std::int32_t x, std::int32_t y) const;
159 
160     /// Return 0-based index to current frame
get_current_frame()161     size_t get_current_frame() const
162     {
163         return _currentFrame;
164     }
165 
get_frame_count()166     size_t get_frame_count() const
167     {
168         return _def ? _def->get_frame_count() : 1;
169     }
170 
171     /// Return number of completely loaded frames of this sprite/movie
172     //
173     /// Note: the number is also the last frame accessible (frames
174     /// numberes are 1-based)
175     ///
get_loaded_frames()176     size_t get_loaded_frames() const
177     {
178         return _def ? _def->get_loading_frame() : 1;
179     }
180 
181     /// Return total number of bytes in the movie
182     /// (not sprite!)
get_bytes_total()183     size_t get_bytes_total() const
184     {
185         return isDynamic() ? 0 : _def->get_bytes_total();
186     }
187 
188     /// Return number of loaded bytes in the movie
189     /// (not sprite!)
get_bytes_loaded()190     size_t get_bytes_loaded() const
191     {
192         return isDynamic() ? 0 : _def->get_bytes_loaded();
193     }
194 
get_frame_size()195     const SWFRect& get_frame_size() const
196     {
197         static const SWFRect r;
198         return _def ? _def->get_frame_size() : r;
199     }
200 
201     /// Stop or play the sprite.
202     //
203     /// If stopped, any stream sound associated with this sprite
204     /// will also be stopped.
205     ///
206     DSOEXPORT void setPlayState(PlayState s);
207 
getPlayState()208     PlayState getPlayState() const { return _playState; }
209 
210     // delegates to movie_root (possibly wrong)
211     void set_background_color(const rgba& color);
212 
213     /// Return true if we have any mouse event handlers.
214     //
215     /// NOTE: this function currently does not consider
216     ///       general mouse event handlers MOUSE_MOVE, MOUSE
217     virtual bool mouseEnabled() const;
218 
219     /// \brief
220     /// Return the topmost entity that the given point
221     /// covers that can receive mouse events.  NULL if
222     /// none.  Coords are in parent's frame.
223     virtual InteractiveObject* topmostMouseEntity(std::int32_t x,
224             std::int32_t y);
225 
226     // see dox in DisplayObject.h
227     const DisplayObject* findDropTarget(std::int32_t x, std::int32_t y,
228             DisplayObject* dragging) const;
229 
setDropTarget(const std::string & tgt)230     void setDropTarget(const std::string& tgt) {
231         _droptarget = tgt;
232     }
233 
getDropTarget()234     const std::string& getDropTarget() const {
235         return _droptarget;
236     }
237 
238     /// Advance to the next frame of the MovieClip.
239     //
240     /// Actions will be executed or pushed to the queue as necessary.
241     virtual void advance();
242 
243     /// Set the sprite state at the specified frame number.
244     //
245     /// 0-based frame numbers!!
246     ///(in contrast to ActionScript and Flash MX)
247     ///
248     DSOEXPORT void goto_frame(size_t target_frame_number);
249 
250     /// Parse frame spec and return a 0-based frame number.
251     //
252     /// If frame spec cannot be converted to !NAN and !Infinity number
253     /// it will be converted to a string and considered a
254     /// frame label (returns false if referring to an
255     /// unknwown label).
256     ///
257     /// @param frame_spec
258     /// The frame specification.
259     ///
260     /// @param frameno
261     /// The evaluated frame number (0-based)
262     ///
263     /// @return
264     /// True if the frame_spec could be resolved to a frame number.
265     /// False if the frame_spec was invalid.
266     bool get_frame_number(const as_value& frame_spec, size_t& frameno) const;
267 
268     /// Look up the labeled frame, and jump to it.
269     bool goto_labeled_frame(const std::string& label);
270 
271     /// Render this MovieClip.
272     virtual void display(Renderer& renderer, const Transform& xform);
273 
274     /// Draw this MovieClip
275     //
276     /// This is effectively the same as display(), but uses only the passed
277     /// transform.
278     void draw(Renderer& renderer, const Transform& xform);
279 
280     void omit_display();
281 
282     /// Swap depth of the given DisplayObjects in the DisplayList
283     //
284     /// See DisplayList::swapDepths for more info
swapDepths(DisplayObject * ch1,int newdepth)285     void swapDepths(DisplayObject* ch1, int newdepth)
286     {
287         _displayList.swapDepths(ch1, newdepth);
288     }
289 
290     /// Return the DisplayObject at given depth in our DisplayList.
291     //
292     /// @return NULL if the specified depth is available (no chars there)
293     DisplayObject* getDisplayObjectAtDepth(int depth);
294 
295     /// Attach a DisplayObject at the specified depth.
296     DisplayObject* addDisplayListObject(DisplayObject* obj, int depth);
297 
298     /// Place a DisplayObject or mask to the DisplayList.
299     //
300     /// This method instantiates the given DisplayObject definition
301     /// and places it on the stage at the given depth.
302     ///
303     /// If the specified depth is already occupied, it results a no-ops.
304     /// Otherwise, a new DisplayObject will be created and onload handler
305     /// will be triggerred.
306     ///
307     /// @param tag
308     ///     A swf defined placement tag (PlaceObject, or PlaceObject2,
309     ///     or PlaceObject3).
310     ///     No ownership transfer, the tag is still owned by the
311     ///     movie_definition class.
312     ///
313     /// @param dlist
314     ///     The display list to add the DisplayObject to.
315     ///
316     /// @return
317     ///     A pointer to the DisplayObject being added or NULL
318     DisplayObject* add_display_object(const SWF::PlaceObject2Tag* tag,
319             DisplayList& dlist);
320 
321     /// Proxy of DisplayList::moveDisplayObject()
322     void move_display_object(const SWF::PlaceObject2Tag* tag,
323             DisplayList& dlist);
324 
325     /// Proxy of DisplayList::replaceDisplayObject()
326     void replace_display_object(const SWF::PlaceObject2Tag* tag,
327             DisplayList& dlist);
328 
329     /// Proxy of DisplayList::removeDisplayObject()
330     void remove_display_object(const SWF::PlaceObject2Tag* tag,
331             DisplayList& dlist);
332 
333     /// \brief
334     /// Remove the object at the specified depth.
335     //
336     /// NOTE:
337     /// (1)the id parameter is currently unused, but
338     /// required to avoid breaking of inheritance from movie.h.
339     /// (2)the id might be used for specifying a DisplayObject
340     /// in the depth(think about multiple DisplayObjects within the same
341     /// depth, not tested and a rare case)
342     void remove_display_object(int depth, int /*id*/);
343 
344     void unloadMovie();
345 
346     /// Attach the given DisplayObject instance to current display list
347     //
348     /// @param newch    The DisplayObject instance to attach.
349     /// @param depth    The depth to assign to the instance.
350     void attachCharacter(DisplayObject& newch, int depth, as_object* initObject);
351 
352     /// Handle placement event
353     //
354     /// This callback will (not known to be a problem):
355     ///
356     /// (1) Register ourselves with the global instance list
357     /// (2) Take note of our original target path
358     /// (3) Register as listener of core broadcasters
359     /// (4) Execute tags of frame 0
360     ///
361     /// The callback will also (known to be bogus):
362     //
363     /// (1) Construct this instance as an ActionScript object.
364     ///     See constructAsScriptObject() method, including constructing
365     ///     registered class and adding properties.
366     virtual void construct(as_object* initObj = nullptr);
367 
368     /// Mark this sprite as destroyed
369     //
370     /// This is an override of DisplayObject::destroy()
371     ///
372     /// A sprite should be destroyed when is removed from the display
373     /// list and is not more needed for names (target) resolutions.
374     /// Sprites are needed for names resolution whenever themselves
375     /// or a contained object has an onUnload event handler defined,
376     /// in which case we want the event handler to find the 'this'
377     /// variable w/out attempting to rebind it.
378     ///
379     /// When a sprite is destroyed, all its children are also destroyed.
380     ///
381     /// Note: this function will release most memory associated with
382     /// the sprite as no members or drawable should be needed anymore.
383     void destroy();
384 
385     /// Add the given action buffer to the list of action
386     /// buffers to be processed at the end of the next
387     /// frame advance.
add_action_buffer(const action_buffer * a)388     void add_action_buffer(const action_buffer* a)
389     {
390         if (!_callingFrameActions) queueAction(*a);
391         else execute_action(*a);
392     }
393 
394 
395     /// \brief
396     /// Execute the given init action buffer, if not done yet
397     /// for the target DisplayObject id.
398     //
399     /// The action will normally be pushed on queue, but will
400     /// be executed immediately if we are executing actions
401     /// resulting from a callFame instead.
402     ///
403     /// @param a
404     /// The action buffer to execute
405     ///
406     /// @param cid
407     /// The referenced DisplayObject id
408     void execute_init_action_buffer(const action_buffer& a, int cid);
409 
410     /// Execute a single action buffer (DOACTION block)
411     void execute_action(const action_buffer& ab);
412 
to_movie()413     MovieClip* to_movie () { return this; }
414 
415     /// The various methods for sending data in requests.
416     //
417     /// Used in loadMovie, getURL, loadVariables etc.
418     enum VariablesMethod
419     {
420         METHOD_NONE = 0,
421         METHOD_GET,
422         METHOD_POST
423     };
424 
425     // See dox in DisplayObject.h
426     virtual void getLoadedMovie(Movie* newMovie);
427 
428     /// \brief
429     /// Load url-encoded variables from the given url, optionally
430     /// sending variables from this timeline too.
431     //
432     /// A LoadVariablesThread will be started to load and parse variables
433     /// and added to the _loadVariableRequests. Then, at every ::advance_sprite
434     /// any completed threads will be processed
435     /// (see processCompletedLoadVariableRequests)
436     ///
437     /// NOTE: the given url will be security-checked
438     ///
439     /// @param urlstr: The url to load variables from.
440     ///
441     /// @param sendVarsMethod: The VariablesMethod to use. If METHOD_NONE,
442     ///                        no data will be sent.
443     void loadVariables(const std::string& urlstr,
444             VariablesMethod sendVarsMethod);
445 
446     /// Get TextField variables
447     //
448     /// TODO: this is unlikely to be the best way of doing it, and it would
449     /// simplify things if this function could be dropped.
450     bool getTextFieldVariables(const ObjectURI& uri, as_value& val);
451 
452     // Set TextField variables
453     //
454     /// TODO: this is also unlikely to be the best way to do it.
455     bool setTextFieldVariables(const ObjectURI& uri, const as_value& val);
456 
457     /// Search for a named object on the DisplayList
458     //
459     /// These are properties, but not attached as genuine members to the
460     /// MovieClip object. They take priority over DisplayObject magic
461     /// properties and inherited properties, but not over own properties.
462     //
463     /// @param name     Object identifier. This function handles
464     ///                 case-sensitivity.
465     /// @return         The object if found, otherwise 0.
466     DisplayObject* getDisplayListObject(const ObjectURI& uri);
467 
468     /// Overridden to look in DisplayList for a match
469     as_object* pathElement(const ObjectURI& uri);
470 
471     /// Execute the actions for the specified frame.
472     //
473     /// The frame_spec could be an integer or a string.
474     virtual void call_frame_actions(const as_value& frame_spec);
475 
476     /// Duplicate this sprite in its timeline
477     //
478     /// Add the new DisplayObject at a the given depth to this sprite
479     /// parent displaylist.
480     ///
481     /// NOTE: the call will fail for the root movie (no parent).
482     /// NOTE2: any DisplayObject at the given target depth will be
483     ///        replaced by the new DisplayObject
484     /// NOTE3: event handlers will also be copied
485     ///
486     /// @param newname
487     ///     Name for the copy
488     ///
489     /// @param newdepth
490     ///     Depth for the copy
491     ///
492     /// @param init_object
493     ///     If not null, will be used to copy properties over.
494     MovieClip* duplicateMovieClip(const std::string& newname,
495         int newdepth, as_object* init_object = nullptr);
496 
497     /// Called when a mouse event affects this MovieClip
mouseEvent(const event_id & id)498     virtual void mouseEvent(const event_id& id) {
499         notifyEvent(id);
500     }
501 
502     /// Dispatch event handler(s), if any.
503     //
504     /// This handles key, mouse, and specific MovieClip events.
505     /// TODO: split this sensibly.
506     void notifyEvent(const event_id& id);
507 
508     // inherited from DisplayObject class, see dox in DisplayObject.h
get_environment()509     virtual as_environment& get_environment() {
510         return _environment;
511     }
512 
513     /// \brief
514     /// Set a TextField variable to this timeline
515     //
516     /// A TextField variable is a variable that acts
517     /// as a setter/getter for a TextField 'text' member.
518     void set_textfield_variable(const ObjectURI& name, TextField* ch);
519 
520     void add_invalidated_bounds(InvalidatedRanges& ranges, bool force);
521 
getDisplayList()522     const DisplayList& getDisplayList() const {
523             return _displayList;
524     }
525 
526     /// Return the next highest available depth
527     //
528     /// Placing an object at the depth returned by
529     /// this function should result in a DisplayObject
530     /// that is displayd above all others
getNextHighestDepth()531     int getNextHighestDepth() const {
532         return _displayList.getNextHighestDepth();
533     }
534 
535     /// Set the currently playing m_sound_stream_id
536     //
537     // TODO: rename to setStreamingSoundId
538     void setStreamSoundId(int id);
539 
540     /// Remove this sprite from the stage.
541     //
542     /// This function is intended to be called by
543     /// effect of a removeMovieClip() ActionScript call
544     /// and implements the checks required for this specific
545     /// case.
546     ///
547     /// Callers are:
548     /// - The ActionRemoveClip tag handler.
549     /// - The global removeMovieClip(target) function.
550     /// - The MovieClip.removeMovieClip() method.
551     ///
552     /// The removal will not occur if the depth of this
553     /// DisplayObjects is not in the "dynamic" range [0..1048575]
554     /// as described at the following URL:
555     ///
556     /// http://www.senocular.com/flash/tutorials/depths/?page=2
557     ///
558     /// A testcases for this behaviour can be found in
559     ///
560     /// testsuite/misc-ming.all/displaylist_depths_test.swf
561     void removeMovieClip();
562 
563     /// Direct access to the Graphics object for drawing.
graphics()564     DynamicShape& graphics() {
565         set_invalidated();
566         return _drawable;
567     }
568 
569     /// Set focus to this MovieClip
570     //
571     /// @return true if this MovieClip can receive focus.
572     virtual bool handleFocus();
573 
574     /// @} Drawing API
575 
576     /// Set all variables in the given map with their corresponding values
577     DSOEXPORT void setVariables(const MovieVariables& vars);
578 
579     /// Enumerate child DisplayObjects
580     //
581     /// See DisplayObject::enumerateNonProperties for more info.
582     virtual void visitNonProperties(KeyVisitor& v) const;
583 
584     /// Delete DisplayObjects removed from the stage
585     /// from the display lists
586     void cleanupDisplayList();
587 
588     /// Queue the given action buffer
589     //
590     /// The action will be pushed on the current
591     /// global list (see movie_root).
592     ///
593     void queueAction(const action_buffer& buf);
594 
595     /// Construct this instance as an ActionScript object
596     //
597     /// This method invokes the constructor associated with our
598     /// definition, either MovieClip or any user-speficied one
599     /// (see sprite_definition::registerClass).
600     /// It will also invoke the onClipConstruct and onConstruct handlers.
601     void constructAsScriptObject();
602 
603     /// Return true if getAsRoot() should return the *relative* root,
604     /// false otherwise.
getLockRoot()605     bool getLockRoot() const { return _lockroot; }
606 
607     /// Set whether getAsRoot() should return the *relative* root,
608     /// false otherwise. True for relative root.
setLockRoot(bool lr)609     void setLockRoot(bool lr) { _lockroot=lr; }
610 
611     /// Return the version of the SWF this MovieClip was parsed from.
612     virtual int getDefinitionVersion() const;
613 
614 protected:
615 
616     /// Unload all contents in the displaylist and this instance
617     //
618     /// Return true if there was an unloadHandler.
619     virtual bool unloadChildren();
620 
621     /// Mark sprite-specific reachable resources.
622     //
623     /// sprite-specific reachable resources are:
624     ///     - DisplayList items (current, backup and frame0 ones)
625     /// - Canvas for dynamic drawing (_drawable)
626     /// - sprite environment
627     /// - definition the sprite has been instantiated from
628     /// - Textfields having an associated variable registered in this instance.
629     /// - Relative root of this instance (_swf)
630     ///
631     virtual void markOwnResources() const;
632 
633     // Used by BitmapMovie.
placeDisplayObject(DisplayObject * ch,int depth)634     void placeDisplayObject(DisplayObject* ch, int depth) {
635         _displayList.placeDisplayObject(ch, depth);
636     }
637 
638 private:
639 
640     /// Process any completed loadVariables request
641     void processCompletedLoadVariableRequests();
642 
643     /// Process a completed loadVariables request
644     void processCompletedLoadVariableRequest(LoadVariablesThread& request);
645 
646 
647     /// Execute the tags associated with the specified frame.
648     //
649     /// @param frame
650     ///     Frame number. 0-based
651     ///
652     /// @param dlist
653     ///     The display list to have control tags act upon.
654     ///
655     /// @param typeflags
656     ///     Which kind of control tags we want to execute.
657     void executeFrameTags(size_t frame, DisplayList& dlist,
658             int typeflags = SWF::ControlTag::TAG_DLIST |
659                             SWF::ControlTag::TAG_ACTION);
660 
661     void stopStreamSound();
662 
663     /// Return value of the 'enabled' property cast to a boolean value.
664     //
665     /// This is true if not found (undefined to bool evaluates to false).
666     //
667     /// When a MovieClip is "disabled", its handlers of button-like events
668     /// are disabled, and automatic tab ordering won't include it.
669     bool isEnabled() const;
670 
671     /// Check whether a point hits our drawable shape.
672     //
673     /// This is possible because the drawable does not have its own
674     /// transform, so we can use our own. The points are expressed in
675     /// world space.
676     bool hitTestDrawable(std::int32_t x, std::int32_t y) const;
677 
678     /// Advance to a previous frame.
679     //
680     /// This function will basically restore the DisplayList as it supposedly
681     /// was *before* executing tags in target frame and then execute target
682     /// frame tags (both DLIST and ACTION ones).
683     ///
684     /// In practice, it will:
685     ///
686     /// - Remove from current DisplayList:
687     /// - Timeline instances constructed after target frame
688     /// - Timeline instances constructed before or at the target frame but no
689     ///   more at the original depth
690     /// - Dynamic instances found in the static depth zone
691     /// - Execute all displaylist tags from first to one-before target frame,
692     ///   appropriately setting _currentFrame as it goes, finally execute
693     ///   both displaylist and action
694     ///   tags for target frame.
695     ///
696     /// Callers of this methods are:
697     /// - goto_frame (for jump-backs)
698     /// - advance_sprite (for loop-back)
699     ///
700     /// See:
701     //  http://www.gnashdev.org/wiki/index.php/TimelineControl
702     ///              #Timeline_instances
703     ///
704     /// @param targetFrame
705     /// The target frame for which we're willing to restore the static
706     /// DisplayList.
707     /// 0-based.
708     //
709     /// POSTCONDITIONS:
710     ///
711     /// - _currentFrame == targetFrame
712     ///
713     /// TODO: consider using this same function for jump-forward too,
714     ///       with some modifications...
715     ///
716     void restoreDisplayList(size_t targetFrame);
717 
718     /// Increment _currentFrame, and take care of looping.
719     void increment_frame_and_check_for_loop();
720 
721     /// Unregister textfield variables bound to unloaded TextFields
722     void cleanup_textfield_variables();
723 
724     /// This is either sprite_definition (for sprites defined by
725     /// DefineSprite tag) or movie_def_impl (for the top-level movie).
726     const boost::intrusive_ptr<const movie_definition> _def;
727 
728     /// List of loadVariables requests
729     typedef boost::ptr_list<LoadVariablesThread> LoadVariablesThreads;
730 
731     /// List of active loadVariable requests
732     //
733     /// At ::advance_sprite time, all completed requests will
734     /// be processed (variables imported in this timeline scope)
735     /// and removed from the list.
736     LoadVariablesThreads _loadVariableRequests;
737 
738     /// The SWF that this MovieClip belongs to.
739     Movie* _swf;
740 
741     /// The canvas for dynamic drawing
742     DynamicShape _drawable;
743 
744     PlayState _playState;
745 
746     /// This timeline's variable scope
747     as_environment _environment;
748 
749     /// We'll only allocate Textfield variables map if
750     /// we need them (ie: anyone calls set_textfield_variable)
751     ///
752     std::unique_ptr<TextFieldIndex> _text_variables;
753 
754     std::string _droptarget;
755 
756     // 0-based index to current frame
757     size_t _currentFrame;
758 
759     /// soundid for current playing stream. If no stream set to -1
760     int m_sound_stream_id;
761 
762     // true if this sprite reached the last frame and restarted
763     bool _hasLooped;
764 
765     // true if orphaned tags (tags found after last advertised showframe)
766     // have been executed at least once.
767     bool _flushedOrphanedTags;
768 
769     // true is we're calling frame actions
770     bool _callingFrameActions;
771 
772     bool _lockroot;
773 
774     bool _onLoadCalled;
775 };
776 
777 } // end of namespace gnash
778 
779 #endif // GNASH_SPRITE_INSTANCE_H
780