1 //
2 //   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 //   Free Software Foundation, Inc
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 
19 
20 #ifndef GNASH_DISPLAY_OBJECT_H
21 #define GNASH_DISPLAY_OBJECT_H
22 
23 #ifdef HAVE_CONFIG_H
24 #include "gnashconfig.h" // USE_SWFTREE
25 #endif
26 
27 #include <vector>
28 #include <map>
29 #include <string>
30 #include <cassert>
31 #include <cstdint> // For C99 int types
32 #include <boost/noncopyable.hpp>
33 #include <boost/logic/tribool.hpp>
34 
35 #include "ObjectURI.h"
36 #include "GC.h"
37 #include "Transform.h"
38 #include "event_id.h"
39 #include "SWFRect.h"
40 #include "SWFMatrix.h"
41 #include "SWFCxForm.h"
42 #include "dsodefs.h"
43 #include "snappingrange.h"
44 #ifdef USE_SWFTREE
45 # include "tree.hh"
46 #endif
47 
48 
49 //#define DEBUG_SET_INVALIDATED 1
50 
51 // Forward declarations
52 namespace gnash {
53     class MovieClip;
54     class movie_root;
55     class fn_call;
56     class Movie;
57     class ExecutableCode;
58     class action_buffer;
59     class movie_definition;
60     class StaticText;
61     class InteractiveObject;
62     class Renderer;
63     class as_object;
64     class as_value;
65     class as_environment;
66     class DisplayObject;
67     class KeyVisitor;
68     namespace SWF {
69         class TextRecord;
70     }
71 }
72 
73 namespace gnash {
74 
75 /// Returns true if the DisplayObject is referenceable in ActionScript
76 //
77 /// A DisplayObject is referenceable if it has an associated object.
78 bool isReferenceable(const DisplayObject& d);
79 
80 /// Set special properties
81 //
82 /// This sets the magic properties of DisplayObjects.
83 //
84 /// @param key      The string table key of the property to set.
85 /// @param obj      The DisplayObject whose property should be set
86 /// @param val      An as_value representing the new value of the property.
87 ///                 Some values may be rejected.
88 bool setDisplayObjectProperty(DisplayObject& obj, const ObjectURI& uri,
89         const as_value& val);
90 
91 /// Get special properties
92 //
93 /// This gets the magic properties of DisplayObjects and handles special
94 /// MovieClip properties such as DisplayList members.
95 //
96 /// @param key      The uri of the property to get.
97 /// @param obj      The DisplayObject whose property should be got
98 /// @param val      An as_value to be set to the value of the property.
99 bool getDisplayObjectProperty(DisplayObject& obj, const ObjectURI& uri,
100         as_value& val);
101 
102 /// Get a property by its numeric index.
103 //
104 /// Used by ASHandlers to get the DisplayObject properties indexed by number
105 //
106 /// @param index    The index of the property to get.
107 /// @param o        The DisplayObject whose property should be got
108 /// @param val      An as_value to be set to the value of the property.
109 void getIndexedProperty(size_t index, DisplayObject& o, as_value& val);
110 
111 /// Set a property by its numeric index.
112 //
113 /// Used by ASHandlers to set the DisplayObject properties indexed by number
114 //
115 /// @param index    The index of the property to set.
116 /// @param o        The DisplayObject whose property should be set
117 /// @param val      An as_value representing the new value of the property.
118 ///                 Some values may be rejected.
119 void setIndexedProperty(size_t index, DisplayObject& o, const as_value& val);
120 
121 /// Copy SWFMatrix and caches from given DisplayObjecta
122 //
123 /// @param from     The DisplayObject to copy from
124 /// @param to       The DisplayObject to copy to.
125 void copyMatrix(const DisplayObject& from, DisplayObject& to);
126 
127 /// Get concatenated SWFMatrix (all ancestor transforms and our SWFMatrix)
128 //
129 /// Maps from our local space into "world" space
130 /// (i.e. root movie space).
131 //
132 /// @param includeRoot      Whether the transform of the Stage (_root)
133 ///                         should be concatenated. This is required to be
134 ///                         false for pointInBounds.
135 SWFMatrix getWorldMatrix(const DisplayObject& d, bool includeRoot = true);
136 
137 /// Get concatenated color transform of a DisplayObject
138 //
139 /// Maps from our local space into normal color space.
140 SWFCxForm getWorldCxForm(const DisplayObject& d);
141 
142 /// DisplayObject is the base class for all DisplayList objects.
143 //
144 /// It represents a single active element in a movie. This class does not
145 /// supply any interactivity. The hierarchy of DisplayObjects in a movie
146 /// provides all visual elements in a SWF. The DisplayObject hierarchy
147 /// is independent of ActionScript resources, but can be controlled via AS.
148 //
149 /// DisplayObjects that can be controlled through ActionScript have an
150 /// associated as_object. DisplayObjects such as Shape, do not have an
151 /// associated object and cannot be referenced in AS.
152 //
153 /// Derived classes include InteractiveObject, StaticText, Bitmap,
154 /// Video, and Shape.
155 //
156 /// All DisplayObjects may be constructed during SWF parsing. In this case
157 /// they are constructed using an immutable, non-copyable SWF::DefinitionTag.
158 /// This tag should never be changed!
159 //
160 /// Most DisplayObjects may also be constructed dynamically. In AS3, Bitmaps
161 /// and Shapes can be dynamically created. Dynamically-created DisplayObjects
162 /// must not have a SWF::DefinitionTag!
163 //
164 /// The presence of a definition tag may be used to distinguish static from
165 /// dynamic DisplayObjects, but tags are not always stored. They are not
166 /// stored in most InteractiveObjects because most properties can be
167 /// overridden during SWF execution.
168 class DSOTEXPORT DisplayObject : public GcResource, boost::noncopyable
169 {
170 public:
171 
172     /// Construct a DisplayObject
173     //
174     /// @param mr       The movie_root containing the DisplayObject hierarchy.
175     ///                 All DisplayObjects may need movie_root resources.
176     /// @param object   An object to be associated with this DisplayObject.
177     ///                 If this is non-null, the DisplayObject will be
178     ///                 referenceable in ActionScript. Referenceable
179     ///                 DisplayObjects may access AS resources through their
180     ///                 associated object.
181     /// @param parent   The parent of the new DisplayObject. This may be null.
182     DisplayObject(movie_root& mr, as_object* object, DisplayObject* parent);
183 
~DisplayObject()184     virtual ~DisplayObject() {}
185 
186     /// The lowest placeable and accessible depth for a DisplayObject.
187     /// Macromedia Flash help says: depth starts at -16383 (0x3FFF)
188     ///
189     /// See: http://www.senocular.com/flash/tutorials/depths/?page=2
190     //
191     /// See also http://www.kirupa.com/developer/actionscript/depths2.htm
192     //
193     /// The only way to exceed these bounds is with createEmptyMoveClip(),
194     /// which can be placed at any depth within +/- 2**31.
195     static const int lowerAccessibleBound = -16384;
196 
197     /// This is the maximum depth a MovieClip DisplayObject can be placed
198     /// at (attachMovie). Kirupa (see above) says 2130690045, but this
199     /// seems not to be included in the range.
200     static const int upperAccessibleBound = 2130690044;
201 
202     /// This is the amount added to displaylist tag defined depths.
203     /// DisplayObjects placed by tags (vs. DisplayObjects instantiated by
204     /// ActionScript) always have negative depths by effect of this offset.
205     static const int staticDepthOffset = lowerAccessibleBound;
206 
207     /// This is the offset at which DisplayObject's depth is
208     /// shifted when a DisplayObject is removed from stage but
209     /// an onUnload event handler is defined.
210     ///
211     /// Example: a DisplayObject at depth 60 gets moved to
212     ///          depth -32829 (-32769-60) when unloaded and
213     ///          an onUnload event handler is defined for it
214     ///          or any of its childs.
215     ///
216     /// So, to recap:
217     ///   1:  -32769 to -16385 are removed
218     ///   2:  -16384 to      0 are statics
219     ///   3:  Max depth for a PlaceObject call is 16384 (which becomes
220     ///       0 in the statics)
221     /// (all of the above correct?)
222     static const int removedDepthOffset = -32769;
223 
224     /// This value is used for m_clip_depth when
225     /// the DisplayObject is not a layer mask.
226     //
227     /// Depths below -16384 are illegal, so this
228     /// value should not collide with real depths.
229     ///
230     static const int noClipDepthValue = -1000000;
231 
232     /// Return a reference to the variable scope of this DisplayObject.
get_environment()233     virtual as_environment& get_environment() {
234         // MovieClip must override this
235         // and any other DisplayObject will have
236         // a parent!
237         assert(_parent != nullptr);
238         return _parent->get_environment();
239     }
240 
241     /// Enumerate any non-proper properties
242     //
243     /// This function allows enumeration of properties that are
244     /// derived from the DisplayObject type, e.g. DisplayList members.
245     ///
246     /// The default implementation adds nothing
visitNonProperties(KeyVisitor &)247     virtual void visitNonProperties(KeyVisitor&) const {}
248 
249     /// \brief
250     /// Return the parent of this DisplayObject, or NULL if
251     /// the DisplayObject has no parent.
parent()252     DisplayObject* parent() const
253     {
254         return _parent;
255     }
256 
257     /// Set the parent of this DisplayObject
258     //
259     /// In AS3, DisplayObjects may be created before being attached to
260     /// a parent. In AS2, this is only used for external movies
set_parent(DisplayObject * parent)261     void set_parent(DisplayObject* parent)
262     {
263         _parent = parent;
264     }
265 
to_movie()266     virtual MovieClip* to_movie() { return nullptr; }
267 
get_depth()268     int get_depth() const { return _depth; }
269 
set_depth(int d)270     void set_depth(int d) { _depth = d; }
271 
272     /// Get sound volume for this DisplayObject
getVolume()273     int getVolume() const { return _volume; }
274 
275     /// Set sound volume for this DisplayObject
setVolume(int vol)276     void setVolume(int vol) { _volume = vol; }
277 
278     /// Get concatenated sound volume for this DisplayObject
279     //
280     /// NOTE: the concatenated volume does NOT include
281     ///       global volume settings, which is the one
282     ///       controlled by Sound instances created passing
283     ///       null, undefined or no argument to constructor.
284     ///
285     int getWorldVolume() const;
286 
287     /// DisplayObjects can return the version of the SWF they were parsed from.
getDefinitionVersion()288     virtual int getDefinitionVersion() const {
289         return -1;
290     }
291 
transform()292     const Transform& transform() const {
293         return _transform;
294     }
295 
296 
297     /// Set local transform SWFMatrix for this DisplayObject
298     //
299     /// @param m the new SWFMatrix to assign to this DisplayObject
300     ///
301     /// @param updateCache if true, updates the cache values
302     ///        from the SWFMatrix (only if SWFMatrix != current SWFMatrix)
303     ///
304     void setMatrix(const SWFMatrix& m, bool updateCache = false);
305 
306     /// Set the xscale value of current SWFMatrix
307     //
308     /// This is used when setting _xscale.
309     /// See xscale_getset.
310     ///
311     /// @param factor scale factor, in percent
312     ///
313     void set_x_scale(double factor);
314 
315     /// Set the yscale value of current SWFMatrix
316     //
317     /// This is used when setting _yscale
318     /// See yscale_getset.
319     ///
320     /// @param factor scale factor, in percent
321     ///
322     void set_y_scale(double factor);
323 
324     /// Set the rotation value of current SWFMatrix
325     //
326     ///
327     /// This is used when setting _rotation
328     /// See rotation_getset
329     ///
330     /// @param rot rotation in degrees. will be trimmed to
331     ///        the -180 .. 180 range, can be passed outside it.
332     ///
333     void set_rotation(double rot);
334 
335     /// Set the width of this DisplayObject, modifying its SWFMatrix
336     //
337     /// This is used when setting _width
338     ///
339     /// @param w new width, in TWIPS.
340     //
341     /// TextField does this differently (caches not updated).
342     virtual void setWidth(double width);
343 
344     /// Set the height of this DisplayObject, modifying its SWFMatrix
345     //
346     /// This is used when setting _height
347     ///
348     /// @param h new height, in TWIPS.
349     ///
350     virtual void setHeight(double height);
351 
setCxForm(const SWFCxForm & cx)352     void setCxForm(const SWFCxForm& cx)
353     {
354         if (_transform.colorTransform != cx) {
355             set_invalidated();
356             _transform.colorTransform = cx;
357         }
358     }
359 
get_ratio()360     std::uint16_t get_ratio() const { return _ratio; }
361 
set_ratio(std::uint16_t r)362     void set_ratio(std::uint16_t r) {
363         if (r != _ratio) set_invalidated();
364         _ratio = r;
365     }
366 
367     /// Returns the clipping depth (if any) of this DisplayObject.
368     /// The parameter tells us to use the DisplayObject as a mask for
369     /// all the objects contained in the display list from _depth
370     /// to m_clipping_depth inclusive.
371     ///
372     /// The value returned by get_clip_depth() is only valid when isMaskLayer()
373     /// returns true!
374     ///
get_clip_depth()375     int get_clip_depth() const { return m_clip_depth; }
376 
377     /// See get_clip_depth()
set_clip_depth(int d)378     void set_clip_depth(int d)
379     {
380         m_clip_depth = d;
381     }
382 
383     /// Returns true when the DisplayObject (and its childs) is used as a mask
384     /// for other DisplayObjects at higher depth (up to get_clip_depth).
385     /// isMaskLayer() does not return true when one of its
386     /// parents is a mask and the DisplayObject itself is not.
387     ///
388     /// See also isDynamicMask() and isMask()
389     ///
isMaskLayer()390     bool isMaskLayer() const
391     {
392         return (m_clip_depth != noClipDepthValue && !_maskee);
393     }
394 
395     /// Returns true when the DisplayObject (and its childs) is used as a mask
396     /// for another DisplayObject.
397     /// isDynamicMask() does not return true when one of its
398     /// parents is a mask and the DisplayObject itself is not.
399     ///
400     /// NOTE: there's no way to obtain the maskee from a dynamic mask
401     ///
402     /// See also isMaskLayer() and isMask()
403     ///
isDynamicMask()404     bool isDynamicMask() const
405     {
406         return (_maskee);
407     }
408 
409     /// Return the DisplayObject masking this instance (if any)
getMask()410     DisplayObject* getMask() const
411     {
412 #if GNASH_PARANOIA_LEVEL > 1
413         if (_mask) assert(_mask->_maskee == this);
414 #endif
415         return _mask;
416     }
417 
418     /// Register a DisplayObject as a mask for this instance.
419     ///
420     /// @param mask The DisplayObject to use as a mask, possibly NULL.
421     /// A reference to us will be registered with the mask, if
422     /// not null, so it'll know it's a mask for us, and would stop
423     /// being a mask for anything else.
424     ///
425     void setMask(DisplayObject* mask);
426 
427     /// Set DisplayObject name, initializing the original target member
set_name(const ObjectURI & uri)428     void set_name(const ObjectURI& uri) {
429         _name = uri;
430     }
431 
get_name()432     const ObjectURI& get_name() const { return _name; }
433 
434     /// Get the built-in function handlers code for the given event
435     //
436     /// NOTE: this function is only for getting statically-defined
437     ///       event handlers, which are the ones attached to a DisplayObject
438     ///       with a PlaceObject2. It's the DisplayObject's responsibility
439     ///       to properly fetch any user-defined event handler, which
440     ///       are the ones attached to a DisplayObject with ActionScript code.
441     ///
442     std::unique_ptr<ExecutableCode> get_event_handler(const event_id& id) const;
443 
444     /// Set a built-in function handler for the given event
445     //
446     /// Mark the DisplayObject as having mouse or Key event
447     /// handlers if this is the case.
448     ///
449     /// NOTE: this function is only for registering statically-defined
450     ///       event handlers, which are the ones attached to a DisplayObject
451     ///       with a PlaceObject2. It's the DisplayObject's responsibility
452     ///       to properly invoke any user-defined event handler, which
453     ///       are the ones attached to a DisplayObject with ActionScript code.
454     ///
455     /// @param id
456     /// The event triggering the handler.
457     ///
458     /// @param code
459     /// An action buffer to execute when given event is triggered.
460     /// The buffer is externally owned (not copied), make sure it
461     /// is kept alive for the whole lifetime of this DisplayObject.
462     ///
463     void add_event_handler(const event_id& id, const action_buffer& code);
464 
465     /// Render the DisplayObject.
466     //
467     /// All DisplayObjects must have a display() function.
468 	virtual void display(Renderer& renderer, const Transform& xform) = 0;
469 
470     /// Search for StaticText objects
471     //
472     /// If this is a StaticText object and contains SWF::TextRecords, these
473     /// are written to the passed parameter.
474     /// @ return    0 if this object is not a StaticText or contains no text.
getStaticText(std::vector<const SWF::TextRecord * > &,size_t &)475     virtual StaticText* getStaticText(std::vector<const SWF::TextRecord*>&,
476             size_t&) {
477         return nullptr;
478     }
479 
480 	virtual SWFRect getBounds() const = 0;
481 
482     /// Return true if the given point falls in this DisplayObject's bounds
483     //
484     /// @param x        Point x coordinate in world space
485     /// @param y        Point y coordinate in world space
486     /// @return         Whether (x, y) is within the DisplayObject's bounds.
487     ///                 This ignores _root's transform.
pointInBounds(std::int32_t x,std::int32_t y)488     bool pointInBounds(std::int32_t x, std::int32_t y) const
489     {
490         SWFRect bounds = getBounds();
491         const SWFMatrix wm = getWorldMatrix(*this, false);
492         wm.transform(bounds);
493         return bounds.point_test(x, y);
494     }
495 
496     /// Return true if the given point falls in this DisplayObject's shape
497     //
498     /// @param x        Point x coordinate in world space
499     /// @param y        Point y coordinate in world space
500     /// @return         Whether (x, y) is within the DisplayObject's bounds.
501 	virtual bool pointInShape(std::int32_t  x, std::int32_t  y) const = 0;
502 
503     /// true if the given point falls in this DisplayObject's visible shape
504     //
505     /// Point coordinates are in world TWIPS
506     ///
507     /// The default implementation returns false if the DisplayObject is
508     /// not visible, calling pointInShape() otherwise.
509     ///
510     /// Note that this is good for simple DisplayObjects but needs
511     /// to be overridden for DisplayObjects with childs. When a
512     /// DisplayObject has childs it must take into account the case
513     /// in which some childs are visible and some are not.
514     ///
pointInVisibleShape(std::int32_t x,std::int32_t y)515     virtual bool pointInVisibleShape(std::int32_t x, std::int32_t y) const
516     {
517         if (!visible()) return false;
518         if (isDynamicMask() || isMaskLayer()) return false;
519         return pointInShape(x, y);
520     }
521 
522     /// Return the relative root of this DisplayObject
523     //
524     /// The "relative" is the Movie created by
525     /// the same SWF definition that contained the
526     /// definition of this DisplayObject.
527     ///
528     /// The default implementation is to invoke get_root
529     /// against this DisplayObject's parent.
530     ///
get_root()531     virtual Movie* get_root() const {
532         return parent()->get_root();
533     }
534 
535     /// Return the _root ActionScript property of this DisplayObject.
536     //
537     /// By default calls get_root(). The resulting MovieClip may be passed
538     /// to actionscript methods, so it is not const. As the override in
539     /// MovieClip may return this, the method cannot be const either.
540     virtual MovieClip* getAsRoot();
541 
542     /// Find the object which is one degree removed from us,
543     /// given the relative pathname.
544     ///
545     /// If the pathname is "..", then return our parent.
546     /// If the pathname is ".", then return ourself.    If
547     /// the pathname is "_level0" or "_root", then return
548     /// the root movie.
549     ///
550     /// Otherwise, the name should refer to one our our
551     /// named DisplayObjects, so we return it.
552     ///
553     /// NOTE: In ActionScript 2.0, top level names (like
554     /// "_root" and "_level0") are CASE SENSITIVE.
555     /// Character names in a display list are CASE
556     /// SENSITIVE. Member names are CASE INSENSITIVE.    Gah.
557     ///
558     /// In ActionScript 1.0, everything seems to be CASE
559     /// INSENSITIVE.
560     ///
561     virtual as_object* pathElement(const ObjectURI& uri);
562 
563     /// \brief
564     /// Return true if PlaceObjects tag are allowed to move
565     /// this DisplayObject.
566     //
567     /// Once a DisplayObject has been transformed by ActionScript,
568     /// further transformation trought non-action SWF constrol tags
569     /// is not allowed.
570     ///
571     /// See scriptTransformed()
572     ///
get_accept_anim_moves()573     bool get_accept_anim_moves() const
574     {
575         return ! _scriptTransformed && ! _dynamicallyCreated;
576     }
577 
578     /// Was this DisplayObject dynamically created ?
579     //
580     /// "Dynamically created" means created trough ActionScript.
581     ///
582     /// NOTE, With current code:
583     /// - Characters created by means of a loadMovie are
584     ///     NOT set as dynamic (should check if they should)
585     /// - Characters created by attachMovie ARE dynamic
586     /// - Characters created by duplicateMovieClip ARE dynamic
587     /// - Characters created by createEmptyMovieClip ARE dynamic
588     /// - Characters created by new Video ARE dynamic
589     /// - Characters created by createTextField ARE dynamic
590     ///
591     ///
isDynamic()592     bool isDynamic() const {
593         return _dynamicallyCreated;
594     }
595 
596     /// Mark this DisplayObject as dynamically created
setDynamic()597     void setDynamic() {
598         _dynamicallyCreated = true;
599     }
600 
601     /// \brief
602     /// Call this function when the sprite has been
603     /// transformed due to ActionScript code.
604     //
605     /// This information will be used while executing
606     /// PlaceObject tags in that ActionScript-transformed
607     /// DisplayObjects won't be allowed to be moved.
608     ///
609     /// TODO: make protected
610     ///
transformedByScript()611     void transformedByScript()
612     {
613         _scriptTransformed = true;
614     }
615 
616     /// Set whether this DisplayObject should be rendered
617     //
618     /// TODO: handle all visible getter/setters in DisplayObject, not in
619     /// subclasses, and drop this / make it private.
620     void set_visible(bool visible);
621 
622     // Return true if this DisplayObject should be rendered
visible()623     bool visible() const { return _visible; }
624 
625     /// Return true if an handler for the given event is defined
626     //
627     /// NOTE that we look for both clip-defined and user-defined
628     /// handlers, which is likely error prone since we're doing
629     /// this in a non-virtual function. Main use for this method
630     /// is for being called by ::unload() to verify an Unload handler
631     /// is available.
632     bool hasEventHandler(const event_id& id) const;
633 
634 	/// DisplayObjects are not a mouse entity by default.
635     //
636     /// Override this function for InteractiveObjects.
topmostMouseEntity(std::int32_t,std::int32_t)637 	virtual InteractiveObject* topmostMouseEntity(std::int32_t,
638             std::int32_t) {
639         return nullptr;
640     }
641 
642     /// Find highest depth DisplayObject whose shape contains the given
643     /// point and is not the DisplayObject being dragged or any of its childs.
644     //
645     /// Point coordinates in global twips.
findDropTarget(std::int32_t x,std::int32_t y,DisplayObject * dragging)646     virtual const DisplayObject* findDropTarget(std::int32_t x,
647             std::int32_t y, DisplayObject* dragging) const
648     {
649         if (this != dragging && visible() && pointInVisibleShape(x, y)) {
650             return this;
651         }
652 
653         return nullptr;
654     }
655 
656     /// Return whether this DisplayObject has been invalidated or not
invalidated()657     bool invalidated() const {
658         return _invalidated;
659     }
660 
661     /// Return whether this DisplayObject has and invalidated child or not
childInvalidated()662     bool childInvalidated() const {
663         return _child_invalidated;
664     }
665 
666     /// Notify a change in the DisplayObject's appearance.
update()667     virtual void update() {
668         set_invalidated();
669     }
670 
671     /// \brief
672     /// This function marks the DisplayObject as being modified in aspect
673     /// and keeps track of current invalidated bounds the first time
674     /// it's called after each call to clear_invalidated().
675     //
676     /// Call this function *before* any change in this DisplayObject
677     /// that modifies its rendering. This information will be used
678     /// to detect visual changes that need to be redrawn.
679     ///
680     /// It is *important* to call this function *before* the change
681     /// rather then after as it will also take care of updating the
682     /// previously invalidated bounds (m_old_invalidated_bounds)
683     ///
684     /// Calling this function multiple time is a no-op, unless
685     /// clear_invalidated() is called in between.
686     ///
687     /// NOTE: Marking a DisplayObject as invalidated automatically marks
688     ///             its parent as being invalidated.
689     ///
690     /// @see \ref region_update
691     ///
692     void set_invalidated();
693     void set_invalidated(const char* debug_file, int debug_line);
694 
695 
696     /// Calls set_invalidated() and extends old_invalidated_ranges to the
697     /// given value so that also this area gets re-rendered (used when
698     /// replacing DisplayObjects).
699     void extend_invalidated_bounds(const InvalidatedRanges& ranges);
700 
701 
702     /// Called by a child to signalize it has changed visibily. The
703     /// difference to set_invalidated() is that *this* DisplayObject does
704     /// not need to redraw itself completely. This function will
705     /// recursively inform all its parents of the change.
706     void set_child_invalidated();
707 
708     /// Clear invalidated flag and reset m_old_invalidated_bounds to null.
709     ///
710     /// It is very important that each DisplayObject with any m_XXXX_invalidated
711     /// flag set calls clear_invalidated() during the rendering of one frame.
712     /// Basically this means each call to display() must match a call to
713     /// clear_invalidated. This includes no-op display() calls, i.e. when the
714     /// DisplayObject is outside of the screen. The DisplayList must still call
715     /// clear_invalidated() even if display() is not necessary.
716     ///
717     /// Not doing so will result in a stale invalidated flag which in turn will
718     /// prevent the parent to be informed when this DisplayObject (or a
719     /// child) is invalidated again (see set_invalidated() recursion).
clear_invalidated()720     void clear_invalidated() {
721         _invalidated = false;
722         _child_invalidated = false;
723         m_old_invalidated_ranges.setNull();
724     }
725 
726     /// \brief
727     /// Add the DisplayObject's invalidated bounds *to* the given ranges list.
728     //
729     /// NOTE that this method should include the bounds that it
730     /// covered the last time clear_invalidated() was called,
731     /// as those need to be rerendered as well (to clear the region
732     /// previously occupied by this DisplayObject).
733     ///
734     /// That's why it returns the *union* of old_invalidated_ranges and
735     /// the current bounds. The function is also used internally by
736     /// set_invalidated() to update m_old_invalidated_ranges itself (you may
737     /// notice some kind of circular reference), but that's no problem since
738     /// old_invalidated_ranges is NULL during that call.
739     ///
740     /// It is used to determine what area needs to be re-rendered.
741     /// The coordinates are world coordinates (in TWIPS).
742     /// Only instances with _invalidated flag set are checked unless
743     /// force is set.
744     ///
745     virtual void add_invalidated_bounds(InvalidatedRanges& ranges, bool force);
746 
747     /// Called instead of display() when the DisplayObject is not visible
748     /// on stage.
749     /// Used to clear the invalidated flags.
omit_display()750     virtual void omit_display() { clear_invalidated(); };
751 
752     /// Callback invoked whenever a DisplayObject is placed on stage
753     //
754     /// This function must be called when the DisplayObject is placed on
755     /// stage for the first time.
756     ///
757     /// The DisplayObject version of this call sets the original target
758     /// of the DisplayObject, for soft references to work.
759     /// If you override the method remember to call saveOriginalTarget()
760     /// as the first thing.
761     ///
762     /// This handles all ActionScript construction and initialization events.
763     virtual void construct(as_object* /*init*/ = nullptr)
764     {
765         saveOriginalTarget();
766     }
767 
768     /// Unload this instance from the stage.
769     //
770     /// This function must be called when the DisplayObject is removed
771     /// from the stage.
772     /// It will take care of properly calling
773     /// unload against any child DisplayObjects and queuing the
774     /// 'UNLOAD' event handler.
775     ///
776     /// @return true if any onUnload event handler was defined
777     ///                 by either this or any child DisplayObjects, false
778     ///                 otherwise.
779     bool unload();
780 
781     /// Accept a loaded Movie
782     virtual void getLoadedMovie(Movie* newMovie);
783 
784     /// Return true if this DisplayObject was unloaded from the stage
unloaded()785     bool unloaded() const {
786         return _unloaded;
787     }
788 
789     /// Mark this DisplayObject as destroyed
790     //
791     /// A DisplayObject should be destroyed when is removed from the display
792     /// list and is not more needed for names (target) resolutions.
793     /// Sprites are needed for names resolution whenever themselves
794     /// or a contained object has an onUnload event handler defined,
795     /// in which case we want the event handler to find the 'this'
796     /// variable w/out attempting to rebind it.
797     ///
798     /// Note: this function can safely release most memory associated
799     ///             with the DisplayObject as it will not be needed anymore.
800     ///
801     virtual void destroy();
802 
803     /// Return true if this DisplayObject was destroyed.
804     //
805     /// See destroy() for more info.
806     ///
isDestroyed()807     bool isDestroyed() const { return _destroyed; }
808 
809     /// Returns true when the DisplayObject bounds intersect with the current
810     /// rendering clipping area.
811     ///
812     /// There is no need to do any rendering for this DisplayObject when this
813     /// function returns false because the renderer will not change any pixels
814     /// in the area where this DisplayObject is placed.
815     bool boundsInClippingArea(Renderer& renderer) const;
816 
817     /// Return full path to this object, in slash notation
818     //
819     /// e.g. "/sprite1/sprite2/ourSprite"
820     ///
821     std::string getTargetPath() const;
822 
823     /// Return original target path to this object, in dot notation
824     /// as of at construction time.
825     //
826     /// This is needed to properly dereference dangling soft-references
827     /// See testcase misc-swfc.all/soft_reference_test1.sc
828     ///
getOrigTarget()829     const std::string& getOrigTarget() const
830     {
831         return _origTarget;
832     }
833 
834     /// Return full path to this object, in dot notation
835     //
836     /// e.g. "_level0.sprite1.sprite2.ourSprite"
837     ///
838     std::string DSOEXPORT getTarget() const;
839 
840     /// Return true if this DisplayObject is a selectable TextField
841     //
842     /// This method is used by Gui to set up an appropriate cursor
843     /// for input textfields.
844     ///
isSelectableTextField()845     virtual bool isSelectableTextField() const { return false; }
846 
847     /// \brief
848     /// Return true if this DisplayObject allows turning the cursor
849     /// into an hand shape when it happens to be the one receiving
850     /// mouse events.
851     bool DSOEXPORT allowHandCursor() const;
852 
853 #ifdef USE_SWFTREE
854     typedef tree<std::pair<std::string, std::string> > InfoTree;
855     /// Append DisplayObject info in the tree
856     //
857     /// @param tr
858     /// The tree to append movie to
859     ///
860     /// @param it
861     /// The iterator to append info to.
862     ///
863     /// @return iterator the appended subtree
864     virtual InfoTree::iterator getMovieInfo(InfoTree& tr,
865             InfoTree::iterator it);
866 #endif
867 
868     /// Used to assign a name to unnamed instances
869     ObjectURI getNextUnnamedInstanceName();
870 
871     enum BlendMode
872     {
873         BLENDMODE_UNDEFINED = 0,
874         BLENDMODE_NORMAL = 1,
875         BLENDMODE_LAYER,
876         BLENDMODE_MULTIPLY,
877         BLENDMODE_SCREEN,
878         BLENDMODE_LIGHTEN,
879         BLENDMODE_DARKEN,
880         BLENDMODE_DIFFERENCE,
881         BLENDMODE_ADD,
882         BLENDMODE_SUBTRACT,
883         BLENDMODE_INVERT,
884         BLENDMODE_ALPHA,
885         BLENDMODE_ERASE,
886         BLENDMODE_OVERLAY,
887         BLENDMODE_HARDLIGHT = 14
888     };
889 
getBlendMode()890     BlendMode getBlendMode() const {
891         return _blendMode;
892     }
893 
setBlendMode(BlendMode bm)894     void setBlendMode(BlendMode bm) {
895         _blendMode = bm;
896     }
897 
898     // action_buffer is externally owned
899     typedef std::vector<const action_buffer*> BufferList;
900     typedef std::map<event_id, BufferList> Events;
901 
902     /// Set the current focus to this DisplayObject.
903     //
904     /// @return false if the DisplayObject cannot receive focus, true if it can
905     ///         (and does).
906     //
907     /// Button, Textfield and MovieClip can receive focus. In SWF6 and above,
908     /// MovieClip can only receive focus if the focusEnabled property
909     /// evaluates to true.
handleFocus()910     virtual bool handleFocus() {
911         return false;
912     }
913 
914     /// Some DisplayObjects require actions on losing focus.
915     //
916     /// Default is a no-op. TextField implements this function.
killFocus()917     virtual void killFocus() {}
918 
rotation()919     double rotation() const {
920         return _rotation;
921     }
922 
scaleX()923     double scaleX() const {
924         return _xscale;
925     }
926 
scaleY()927     double scaleY() const {
928         return _yscale;
929     }
930 
object()931     as_object* object() const {
932         return _object;
933     }
934 
935     /// Getter-setter for blendMode.
936     static as_value blendMode(const fn_call& fn);
937 
938     /// Mark all reachable resources.
939     //
940     /// Try not to override this function in derived classes. This always
941     /// marks the base class's resources and calls markOwnResources() to
942     /// take care of any further GC resources.
943     virtual void markReachableResources() const;
944 
945     /// Called by markReachableResources()
946     //
947     /// DisplayObjects should mark their own resources in this function.
markOwnResources()948     virtual void markOwnResources() const {}
949 
focusRect()950     boost::tribool focusRect() const {
951         return _focusRect;
952     }
953 
focusRect(boost::tribool focus)954     void focusRect(boost::tribool focus) {
955         _focusRect = focus;
956     }
957 
958 protected:
959 
960     /// Render a dynamic mask for a specified DisplayObject
961     //
962     /// Dynamic masks are rendered out-of-turn when the object they are masking
963     /// is drawn.
964     //
965     /// A MaskRenderer object should be constructed at the beginning of
966     /// relevant display() functions; it then takes care of rendering the
967     /// mask with the appropriate transform and cleaning up afterwards.
968     class MaskRenderer
969     {
970     public:
971         MaskRenderer(Renderer& r, const DisplayObject& o);
972         ~MaskRenderer();
973     private:
974         Renderer& _renderer;
975         DisplayObject* _mask;
976     };
977 
unloadChildren()978     virtual bool unloadChildren() { return false; }
979 
980     /// Get the movie_root to which this DisplayObject belongs.
stage()981     movie_root& stage() const {
982         return _stage;
983     }
984 
985     /// Register currently computable target as
986     /// the "original" one. This will be used by
987     /// soft references (as_value) and should be
988     /// called as soon as the stagePlacementCallback
989     /// is invoked.
990     ///
saveOriginalTarget()991     void saveOriginalTarget()
992     {
993         _origTarget=getTarget();
994     }
995 
get_event_handlers()996     const Events& get_event_handlers() const
997     {
998         return _event_handlers;
999     }
1000 
1001     void set_event_handlers(const Events& copyfrom);
1002 
1003     /// Name of this DisplayObject (if any)
1004     ObjectURI _name;
1005 
1006     DisplayObject* _parent;
1007 
1008     /// look for '.', 'this',    '..', '_parent', '_level0' and '_root'
1009     //
1010     /// NOTE: case insensitive up to SWF6, sensitive from SWF7 up
1011     ///
1012     as_object* getPathElementSeparator(string_table::key key);
1013 
1014     /// \brief
1015     /// Bounds of this DisplayObject instance before first invalidation
1016     /// since last call to clear_invalidated().
1017     ///
1018     /// This stores the bounds of the DisplayObject before it has been
1019     /// changed, ie. the position when set_invalidated() is being called.
1020     /// While drawing, both the old and the new bounds are updated (rendered).
1021     /// When moving a DisplayObject A to B then both the position A needs
1022     /// to be re-rendered (to reveal the backgrond) and the position B
1023     /// needs to be re-rendered (to show the DisplayObject in its new
1024     /// position). The bounds may be identical or overlap, but
1025     /// SnappingRanges takes care of that.
1026     ///
1027     /// Will be set by set_invalidated() and used by
1028     /// get_invalidated_bounds().
1029     InvalidatedRanges m_old_invalidated_ranges;
1030 
1031 private:
1032 
1033     /// Register a DisplayObject masked by this instance
1034     void setMaskee(DisplayObject* maskee);
1035 
1036     /// The as_object to which this DisplayObject is attached.
1037     as_object* _object;
1038 
1039     /// The movie_root to which this DisplayObject belongs.
1040     movie_root& _stage;
1041 
1042     Transform _transform;
1043 
1044     Events _event_handlers;
1045 
1046     /// Cache values for ActionScript access.
1047     /// NOTE: not all DisplayObjects need this, just the
1048     ///       ones which are ActionScript-referenceable
1049     double _xscale, _yscale, _rotation;
1050 
1051     /// The depth of this DisplayObject.
1052     std::int32_t _depth;
1053 
1054     boost::tribool _focusRect;
1055 
1056     /// Volume control associated to this DisplayObject
1057     //
1058     /// This is used by Sound objects
1059     ///
1060     /// NOTE: probably only ActionScript-referenceable DisplayObjects
1061     ///       need this (assuming soft ref don't rebind to other
1062     ///       kind of DisplayObjects).
1063     ///
1064     int _volume;
1065 
1066     std::uint16_t _ratio;
1067     int m_clip_depth;
1068 
1069     /// The DisplayObject masking this instance (if any)
1070     DisplayObject* _mask;
1071 
1072     /// The DisplayObject masked by this instance (if any)
1073     DisplayObject* _maskee;
1074 
1075     /// Original target, as at construction time
1076     std::string _origTarget;
1077 
1078     BlendMode _blendMode;
1079 
1080     bool _visible;
1081 
1082     /// Whether this DisplayObject has been transformed by ActionScript code
1083     //
1084     /// Once we've been moved by ActionScript,
1085     /// Don't accept moves from anim tags (PlaceObject)
1086     ///
1087     /// See get_accept_anim_moves() function
1088     ///
1089     bool _scriptTransformed;
1090 
1091     bool _dynamicallyCreated;
1092 
1093     /// Set to yes when this instance has been unloaded
1094     bool _unloaded;
1095 
1096     /// This flag should be set to true by a call to destroy()
1097     bool _destroyed;
1098 
1099     /// \brief
1100     /// Set when the visual aspect of this particular DisplayObject or movie
1101     /// has been changed and redrawing is necessary.
1102     //
1103     /// This is initialized to true as the initial state for
1104     /// any DisplayObject is the "invisible" state (it wasn't there)
1105     /// so it starts in invalidated mode.
1106     ///
1107     bool _invalidated;
1108 
1109     /// Just like _invalidated but set when a child is invalidated instead
1110     /// of this DisplayObject instance. _invalidated and _child_invalidated
1111     /// can be set at the same time.
1112     bool _child_invalidated;
1113 
1114 
1115 };
1116 
1117 /// Get local transform SWFMatrix for this DisplayObject
1118 inline const SWFMatrix&
getMatrix(const DisplayObject & o)1119 getMatrix(const DisplayObject& o)
1120 {
1121     return o.transform().matrix;
1122 }
1123 
1124 inline const SWFCxForm&
getCxForm(const DisplayObject & o)1125 getCxForm(const DisplayObject& o)
1126 {
1127     return o.transform().colorTransform;
1128 }
1129 
1130 inline SWFMatrix
getWorldMatrix(const DisplayObject & d,bool includeRoot)1131 getWorldMatrix(const DisplayObject& d, bool includeRoot)
1132 {
1133     SWFMatrix m = d.parent() ?
1134         getWorldMatrix(*d.parent(), includeRoot) : SWFMatrix();
1135 
1136     if (d.parent() || includeRoot) m.concatenate(getMatrix(d));
1137     return m;
1138 }
1139 
1140 inline SWFCxForm
getWorldCxForm(const DisplayObject & d)1141 getWorldCxForm(const DisplayObject& d)
1142 {
1143     SWFCxForm cx = d.parent() ? getWorldCxForm(*d.parent()) : SWFCxForm();
1144     cx.concatenate(getCxForm(d));
1145     return cx;
1146 }
1147 
1148 inline bool
isReferenceable(const DisplayObject & d)1149 isReferenceable(const DisplayObject& d)
1150 {
1151     return d.object();
1152 }
1153 
1154 /// Return the as_object associated with a DisplayObject if it exists
1155 //
1156 /// @param d    The DisplayObject to check. May be null.
1157 /// @return     null if either the DisplayObject or the associated object is
1158 ///             null. Otherwise the associated object.
1159 inline as_object*
getObject(const DisplayObject * d)1160 getObject(const DisplayObject* d)
1161 {
1162     return d ? d->object() : nullptr;
1163 }
1164 
1165 /// Stream operator for DisplayObject blend mode.
1166 std::ostream&
1167 operator<<(std::ostream& o, DisplayObject::BlendMode bm);
1168 
1169 } // end namespace gnash
1170 
1171 
1172 #ifdef DEBUG_SET_INVALIDATED
1173 #define set_invalidated() set_invalidated(__FILE__, __LINE__)
1174 #endif
1175 
1176 
1177 #endif // GNASH_CHARACTER_H
1178 
1179 
1180 // Local Variables:
1181 // mode: C++
1182 // indent-tabs-mode: t
1183 // End:
1184