Update with current status
[gnash.git] / libcore / DisplayList.h
blob9561500c2b550a29d469b5eb39d5f443083cea72
1 // dlist.h: Display list definitions, 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 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
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
20 #ifndef GNASH_DLIST_H
21 #define GNASH_DLIST_H
23 #include <list>
24 #include <iosfwd>
25 #if GNASH_PARANOIA_LEVEL > 1 && !defined(NDEBUG)
26 #include "DisplayObject.h"
27 #include <set> // for testInvariant
28 #include <algorithm>
29 #include "log.h"
30 #endif
32 #include "snappingrange.h"
33 #include "dsodefs.h" // for DSOTEXPORT
36 // GNASH_PARANOIA_LEVEL:
37 // 0 : (not unimplemented)
38 // 1 : quick assertions
39 // 2 : add testInvariant
41 #ifndef GNASH_PARANOIA_LEVEL
42 # define GNASH_PARANOIA_LEVEL 1
43 #endif
45 namespace gnash {
46 class SWFCxForm;
47 class Renderer;
48 struct ObjectURI;
49 class Transform;
50 class string_table;
51 class DisplayObject;
52 class SWFMatrix;
55 namespace gnash {
57 /// A list of on-stage DisplayObjects, ordered by depth
59 /// Any MovieClip has an associated DisplayList
60 /// that may change from frame to frame due to control
61 /// tags instructing when to add or remove DisplayObjects
62 /// from the stage.
63 ///
64 class DisplayList
67 public:
69 typedef std::list<DisplayObject*> container_type;
70 typedef container_type::iterator iterator;
71 typedef container_type::const_iterator const_iterator;
72 typedef container_type::reverse_iterator reverse_iterator;
73 typedef container_type::const_reverse_iterator const_reverse_iterator;
75 DisplayList() {}
76 ~DisplayList() {}
78 /// Output operator
79 friend std::ostream& operator<< (std::ostream&, const DisplayList&);
81 /// \brief
82 /// Place a new DisplayObject at the specified depth,
83 /// replacing any existing DisplayObject at the same depth.
85 /// If a DisplayObject is replaced, it's unload() method
86 /// is invoked.
87 ///
88 /// If applicable, the event_id::LOAD event
89 /// associated with the given DisplayObject
90 /// is called as last step of addition.
91 ///
92 /// @param ch
93 /// the new DisplayObject to be added into the list.
94 ///
95 /// @param depth
96 /// depth at which the new DisplayObject is placed.
97 DSOTEXPORT void placeDisplayObject(DisplayObject* ch, int depth);
99 /// \brief
100 /// Replace the old DisplayObject at the specified depth with
101 /// the given new DisplayObject.
103 /// Calls unload on the removed DisplayObject.
105 /// @param ch
106 /// the new DisplayObject to be put
108 /// @param depth
109 /// depth to be replaced
111 /// @param use_old_cxform
112 /// true: set the new DisplayObject's SWFCxForm to the old one.
113 /// false: keep the new DisplayObject's SWFCxForm.
115 /// @param use_old_matrix
116 /// true: set the new DisplayObject's transformation SWFMatrix to the old one.
117 /// false: keep the new DisplayObject's transformation SWFMatrix.
118 void replaceDisplayObject(DisplayObject* ch, int depth, bool use_old_cxform,
119 bool use_old_matrix);
121 /// \brief
122 /// Change depth of the given DisplayObjects in the list,
123 /// swapping with any existing DisplayObject at target depth.
125 /// List ordering will be maintained by this function.
127 /// Any DisplayObject affected by this operation (none on invalid call,
128 /// 1 if new depth is not occupied, 2 otherwise) will be:
129 /// - bounds invalidated (see DisplayObject::set_invalidated)
130 /// - marked as script-transformed (see DisplayObject::transformedByScript)
131 ///
132 /// @param ch
133 /// The DisplayObject to apply depth swapping to.
134 /// If not found in the list, an error is raised
135 /// and no other action is taken.
137 /// @param depth
138 /// The new depth to assign to the given DisplayObject.
139 /// If occupied by another DisplayObject, the target DisplayObject
140 /// will get the current depth of the first.
141 /// If target depth equals the current depth of DisplayObject, an
142 /// assertion fails, as I think the caller should check this instead.
144 void swapDepths(DisplayObject* ch, int depth);
146 /// \brief
147 /// Updates the transform properties of the object at the
148 /// specified depth, unless its get_accept_anim_moves() returns false.
150 /// See DisplayObject::get_accept_anim_moves()
152 /// @param color_xform
153 /// The color tranform to assign to the DisplayObject at the given depth.
154 /// If NULL the orignial color transform will be kept.
156 /// @param mat
157 /// The SWFMatrix tranform to assign to the DisplayObject at the given depth.
158 /// If NULL the orignial SWFMatrix will be kept.
160 /// @param ratio
161 /// The new ratio value to assign to the DisplayObject at the given depth.
162 /// If NULL the original ratio will be kept.
163 void moveDisplayObject(int depth, const SWFCxForm* color_xform,
164 const SWFMatrix* mat, std::uint16_t* ratio);
166 /// Removes the object at the specified depth.
168 /// Calls unload on the removed DisplayObject.
169 void removeDisplayObject(int depth);
171 /// Remove all unloaded DisplayObject from the list
173 /// Removed DisplayObjects still in the list are those
174 /// on which onUnload event handlers were defined..
176 /// NOTE: we don't call the function recursively in the
177 /// contained elements, as that should not be needed
178 /// (ie: any inned thing will not be accessible anyway)
179 void removeUnloaded();
181 /// Unload the DisplayObjects in this DisplayList removing
182 /// all but the ones with on onUnload event defined
183 /// (checked by calling ::unload on them) and keeping
184 /// the others, w/out depth-shifting them.
186 /// Return true if any child was kept (as they had onUnload defined)
187 bool unload();
189 /// destroy all DisplayObjects in this DisplayList
190 void destroy();
192 /// Add a DisplayObject in the list, maintaining depth-order
195 /// @param ch
196 /// The DisplayObject to add
198 /// @param replace
199 /// If true the given DisplayObject would replace any
200 /// pre-existing DisplayObject at the same depth.
201 void add(DisplayObject* ch, bool replace);
203 /// Inserts a DisplayObject at the specified index (depth)
205 /// If a DisplayObject is already at that index, it is moved up.
206 /// This implements AS3 DisplayObjectContainer.addChildAt().
208 /// @param obj The DisplayObject to insert. This should already be
209 /// removed from any other DisplayLists. It should not be
210 /// the owner of this DisplayList or any parent of that
211 /// owner.
212 /// @param index The index at which to insert the DisplayObject.
213 void insertDisplayObject(DisplayObject* obj, int index);
215 /// Display the list's DisplayObjects.
217 /// Lower depths are obscured by higher depths.
218 void display(Renderer& renderer, const Transform& xform);
220 void omit_display();
222 /// May return NULL.
223 DSOTEXPORT DisplayObject* getDisplayObjectAtDepth(int depth) const;
225 /// If there are multiples, returns the *first* match only!
227 /// @param st
228 /// The string_table to use for finding
229 /// lowercase equivalent of names if
230 /// `caseless' parameter is true.
231 /// @param uri
232 /// Object identifier
233 /// @param caseless
234 /// Wheter comparison must be case-insensitive.
236 DSOTEXPORT DisplayObject* getDisplayObjectByName(string_table& st,
237 const ObjectURI& uri, bool caseless) const;
239 /// \brief
240 /// Visit each DisplayObject in the list in reverse depth
241 /// order (higher depth first).
243 /// The visitor functor
244 /// will receive a DisplayObject pointer; must return true if
245 /// it wants next item or false
246 /// to exit the loop.
248 /// NOTE: all elements in the list are visited, even
249 /// the removed ones (unloaded)
250 /// TODO: inspect if worth providing an arg to skip removed
251 template <class V> inline void visitBackward(V& visitor);
252 template <class V> inline void visitBackward(V& visitor) const;
254 /// \brief
255 /// Visit each and all DisplayObject in the list.
257 /// Scan happens in arbitrary order, if order is
258 /// important use visitBackward or visitForward
260 /// The visitor functor will receive a DisplayObject pointer,
261 /// it's return value is not used so can return void.
263 /// NOTE: all elements in the list are visited, even
264 /// the removed ones (unloaded)
265 /// TODO: inspect if worth providing an arg to skip removed
266 template <class V> inline void visitAll(V& visitor);
267 template <class V> inline void visitAll(V& visitor) const;
269 /// Like DisplayObject_instance::add_invalidated_bounds() this method calls the
270 /// method with the same name of all childs.
271 void add_invalidated_bounds(InvalidatedRanges& ranges, bool force);
273 /// Return number of elements in the list
274 size_t size() const {
275 return _charsByDepth.size();
278 /// Return true if the list contains no elements
279 bool empty() const {
280 return _charsByDepth.empty();
283 /// Return the next highest available depth
285 /// Placing an object at the depth returned by
286 /// this function should result in a DisplayObject
287 /// that is displayd above all others
289 int getNextHighestDepth() const;
291 /// Merge the given display list
293 /// Call set_invalidated on the given DisplayObject if this list changes
295 void mergeDisplayList(DisplayList& newList, DisplayObject& o);
297 bool operator==(const DisplayList& other) const {
298 return _charsByDepth == other._charsByDepth;
301 bool operator!=(const DisplayList& other) const {
302 return _charsByDepth != other._charsByDepth;
305 #if GNASH_PARANOIA_LEVEL > 1 && !defined(NDEBUG)
306 DisplayList::const_iterator nonRemoved() const;
308 void testInvariant() const
310 DisplayList sorted = *this;
312 // check no duplicated depths above non-removed zone.
313 std::set<int> depths;
314 for (const_iterator it = nonRemoved(),
315 itEnd = _charsByDepth.end(); it != itEnd; ++it) {
317 DisplayObject* ch = *it;
318 int depth = ch->get_depth();
319 if (!depths.insert(depth).second) {
320 log_debug("Depth %d is duplicated in DisplayList %p",
321 depth, (const void*)this);
322 std::abort();
325 if (_charsByDepth.empty()) return;
326 // check we didn't screw up ordering
327 assert(std::adjacent_find(_charsByDepth.begin(), _charsByDepth.end(),
328 DepthGreaterThan()) == _charsByDepth.end());
330 #else
331 void testInvariant() const {}
332 #endif
334 private:
336 /// Re-insert a removed-from-stage DisplayObject after appropriately
337 /// shifting its depth based on the DisplayObject::removedDepthOffset
338 /// value.
340 /// PRE-CONDITIONS
341 /// - ch::isUnloaded() returns true (assertion fails otherwise)
342 /// - ch is not already in the list (assertion fails otherwise)
344 /// TODO: inspect what should happen if the target depth is already
345 /// occupied
346 void reinsertRemovedCharacter(DisplayObject* ch);
348 container_type _charsByDepth;
351 template <class V>
352 void
353 DisplayList::visitBackward(V& visitor)
355 for (reverse_iterator it = _charsByDepth.rbegin(),
356 itEnd = _charsByDepth.rend(); it != itEnd; ++it) {
357 if (!visitor(*it)) break;
361 template <class V>
362 void
363 DisplayList::visitBackward(V& visitor) const
365 for (const_reverse_iterator it = _charsByDepth.rbegin(),
366 itEnd = _charsByDepth.rend(); it != itEnd; ++it) {
367 if (!visitor(*it)) break;
371 template <class V>
372 void
373 DisplayList::visitAll(V& visitor)
375 for (DisplayObject* ch : _charsByDepth) {
376 visitor(ch);
380 template <class V>
381 void
382 DisplayList::visitAll(V& visitor) const
384 for (DisplayObject* const ch : _charsByDepth) {
385 visitor(ch);
389 DSOTEXPORT std::ostream& operator<< (std::ostream&, const DisplayList&);
391 } // namespace gnash
394 #endif // GNASH_DLIST_H
398 // Local Variables:
399 // mode: C++
400 // c-basic-offset: 8
401 // tab-width: 8
402 // indent-tabs-mode: t
403 // End: