Plug more leaks (in the test, not the core)
[gnash.git] / libcore / DisplayList.h
blob3cdfe7719dafcaa82c23df0333f0359286862b06
1 // dlist.h: Display list definitions, for Gnash.
2 //
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
4 // 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 "snappingrange.h"
24 #include "DisplayObject.h"
26 #include <string>
27 #include <list>
28 #include <iosfwd>
29 #if GNASH_PARANOIA_LEVEL > 1 && !defined(NDEBUG)
30 #include <set> // for testInvariant
31 #include <algorithm>
32 #include "log.h"
33 #endif
35 // GNASH_PARANOIA_LEVEL:
36 // 0 : (not unimplemented)
37 // 1 : quick assertions
38 // 2 : add testInvariant
40 #ifndef GNASH_PARANOIA_LEVEL
41 # define GNASH_PARANOIA_LEVEL 1
42 #endif
44 namespace gnash {
45 class SWFCxForm;
46 class Renderer;
47 struct ObjectURI;
50 namespace gnash {
52 /// A list of on-stage DisplayObjects, ordered by depth
54 /// Any MovieClip has an associated DisplayList
55 /// that may change from frame to frame due to control
56 /// tags instructing when to add or remove DisplayObjects
57 /// from the stage.
58 ///
59 class DisplayList
62 public:
64 typedef std::list<DisplayObject*> container_type;
65 typedef container_type::iterator iterator;
66 typedef container_type::const_iterator const_iterator;
67 typedef container_type::reverse_iterator reverse_iterator;
68 typedef container_type::const_reverse_iterator const_reverse_iterator;
70 DisplayList() {}
71 ~DisplayList() {}
73 /// Output operator
74 friend std::ostream& operator<< (std::ostream&, const DisplayList&);
76 /// \brief
77 /// Place a new DisplayObject at the specified depth,
78 /// replacing any existing DisplayObject at the same depth.
80 /// If a DisplayObject is replaced, it's unload() method
81 /// is invoked.
82 ///
83 /// If applicable, the event_id::LOAD event
84 /// associated with the given DisplayObject
85 /// is called as last step of addition.
86 ///
87 /// @param ch
88 /// the new DisplayObject to be added into the list.
89 ///
90 /// @param depth
91 /// depth at which the new DisplayObject is placed.
92 void placeDisplayObject(DisplayObject* ch, int depth);
94 /// \brief
95 /// Replace the old DisplayObject at the specified depth with
96 /// the given new DisplayObject.
98 /// Calls unload on the removed DisplayObject.
99 ///
100 /// @param ch
101 /// the new DisplayObject to be put
103 /// @param depth
104 /// depth to be replaced
106 /// @param use_old_cxform
107 /// true: set the new DisplayObject's SWFCxForm to the old one.
108 /// false: keep the new DisplayObject's SWFCxForm.
110 /// @param use_old_matrix
111 /// true: set the new DisplayObject's transformation SWFMatrix to the old one.
112 /// false: keep the new DisplayObject's transformation SWFMatrix.
113 void replaceDisplayObject(DisplayObject* ch, int depth, bool use_old_cxform,
114 bool use_old_matrix);
116 /// \brief
117 /// Change depth of the given DisplayObjects in the list,
118 /// swapping with any existing DisplayObject at target depth.
120 /// List ordering will be maintained by this function.
122 /// Any DisplayObject affected by this operation (none on invalid call,
123 /// 1 if new depth is not occupied, 2 otherwise) will be:
124 /// - bounds invalidated (see DisplayObject::set_invalidated)
125 /// - marked as script-transformed (see DisplayObject::transformedByScript)
126 ///
127 /// @param ch
128 /// The DisplayObject to apply depth swapping to.
129 /// If not found in the list, an error is raised
130 /// and no other action is taken.
132 /// @param depth
133 /// The new depth to assign to the given DisplayObject.
134 /// If occupied by another DisplayObject, the target DisplayObject
135 /// will get the current depth of the first.
136 /// If target depth equals the current depth of DisplayObject, an
137 /// assertion fails, as I think the caller should check this instead.
139 void swapDepths(DisplayObject* ch, int depth);
141 /// \brief
142 /// Updates the transform properties of the object at the
143 /// specified depth, unless its get_accept_anim_moves() returns false.
145 /// See DisplayObject::get_accept_anim_moves()
147 /// @param color_xform
148 /// The color tranform to assign to the DisplayObject at the given depth.
149 /// If NULL the orignial color transform will be kept.
151 /// @param mat
152 /// The SWFMatrix tranform to assign to the DisplayObject at the given depth.
153 /// If NULL the orignial SWFMatrix will be kept.
155 /// @param ratio
156 /// The new ratio value to assign to the DisplayObject at the given depth.
157 /// If NULL the original ratio will be kept.
158 void moveDisplayObject(int depth, const SWFCxForm* color_xform,
159 const SWFMatrix* mat, boost::uint16_t* ratio);
161 /// Removes the object at the specified depth.
163 /// Calls unload on the removed DisplayObject.
164 void removeDisplayObject(int depth);
166 /// Remove all unloaded DisplayObject from the list
168 /// Removed DisplayObjects still in the list are those
169 /// on which onUnload event handlers were defined..
171 /// NOTE: we don't call the function recursively in the
172 /// contained elements, as that should not be needed
173 /// (ie: any inned thing will not be accessible anyway)
174 void removeUnloaded();
176 /// Unload the DisplayObjects in this DisplayList removing
177 /// all but the ones with on onUnload event defined
178 /// (checked by calling ::unload on them) and keeping
179 /// the others, w/out depth-shifting them.
181 /// Return true if any child was kept (as they had onUnload defined)
182 bool unload();
184 /// destroy all DisplayObjects in this DisplayList
185 void destroy();
187 /// Add a DisplayObject in the list, maintaining depth-order
190 /// @param ch
191 /// The DisplayObject to add
193 /// @param replace
194 /// If true the given DisplayObject would replace any
195 /// pre-existing DisplayObject at the same depth.
196 void add(DisplayObject* ch, bool replace);
198 /// Removes the specified DisplayObject
200 /// Other DisplayObjects are left untouched.
201 /// This implements AS3 DisplayObjectContainer.removeChild().
203 /// @param obj The DisplayObject to remove.
204 void removeDisplayObject(DisplayObject* obj);
206 /// Removes the DisplayObject at the specified index
208 /// Other DisplayObjects are left untouched.
209 /// This implements AS3 DisplayObjectContainer.removeChildAt().
211 /// @param index The index from which to remove the DisplayObject.
212 /// @return The DisplayObject removed, or 0 if none was removed.
213 DisplayObject* removeDisplayObjectAt(int index);
215 /// Inserts a DisplayObject at the specified index (depth)
217 /// If a DisplayObject is already at that index, it is moved up.
218 /// This implements AS3 DisplayObjectContainer.addChildAt().
220 /// @param obj The DisplayObject to insert. This should already be
221 /// removed from any other DisplayLists. It should not be
222 /// the owner of this DisplayList or any parent of that
223 /// owner.
224 /// @param index The index at which to insert the DisplayObject.
225 void insertDisplayObject(DisplayObject* obj, int index);
227 /// Adds a DisplayObject at the top of the DisplayList.
229 /// This implements AS3 DisplayObjectContainer.addChild().
231 /// @param obj The DisplayObject to insert. This should already be
232 /// removed from any other DisplayLists. It should not be
233 /// the owner of this DisplayList or any parent of that
234 /// owner.
235 void addDisplayObject(DisplayObject* obj);
237 /// Display the list's DisplayObjects.
239 /// Lower depths are obscured by higher depths.
240 void display(Renderer& renderer, const Transform& xform);
242 void omit_display();
244 /// May return NULL.
245 DisplayObject* getDisplayObjectAtDepth(int depth) const;
247 /// If there are multiples, returns the *first* match only!
249 /// @param st
250 /// The string_table to use for finding
251 /// lowercase equivalent of names if
252 /// `caseless' parameter is true.
253 /// @param uri
254 /// Object identifier
255 /// @param caseless
256 /// Wheter comparison must be case-insensitive.
258 DisplayObject* getDisplayObjectByName(string_table& st,
259 const ObjectURI& uri, bool caseless) const;
261 /// \brief
262 /// Visit each DisplayObject in the list in reverse depth
263 /// order (higher depth first).
265 /// The visitor functor
266 /// will receive a DisplayObject pointer; must return true if
267 /// it wants next item or false
268 /// to exit the loop.
270 /// NOTE: all elements in the list are visited, even
271 /// the removed ones (unloaded)
272 /// TODO: inspect if worth providing an arg to skip removed
273 template <class V> inline void visitBackward(V& visitor);
274 template <class V> inline void visitBackward(V& visitor) const;
276 /// \brief
277 /// Visit each and all DisplayObject in the list.
279 /// Scan happens in arbitrary order, if order is
280 /// important use visitBackward or visitForward
282 /// The visitor functor will receive a DisplayObject pointer,
283 /// it's return value is not used so can return void.
285 /// NOTE: all elements in the list are visited, even
286 /// the removed ones (unloaded)
287 /// TODO: inspect if worth providing an arg to skip removed
288 template <class V> inline void visitAll(V& visitor);
289 template <class V> inline void visitAll(V& visitor) const;
291 /// dump list to logfile/stderr
292 void dump() const;
294 /// Like DisplayObject_instance::add_invalidated_bounds() this method calls the
295 /// method with the same name of all childs.
296 void add_invalidated_bounds(InvalidatedRanges& ranges, bool force);
298 /// Return number of elements in the list
299 size_t size() const {
300 return _charsByDepth.size();
303 /// Return true if the list contains no elements
304 bool empty() const {
305 return _charsByDepth.empty();
308 /// Return the next highest available depth
310 /// Placing an object at the depth returned by
311 /// this function should result in a DisplayObject
312 /// that is displayd above all others
314 int getNextHighestDepth() const;
316 /// \brief
317 /// merge the given display list
318 void mergeDisplayList(DisplayList& newList);
320 bool operator==(const DisplayList& other) const {
321 return _charsByDepth == other._charsByDepth;
324 bool operator!=(const DisplayList& other) const {
325 return _charsByDepth != other._charsByDepth;
328 #if GNASH_PARANOIA_LEVEL > 1 && !defined(NDEBUG)
329 DisplayList::const_iterator nonRemoved() const;
331 void testInvariant() const
333 DisplayList sorted = *this;
335 // check no duplicated depths above non-removed zone.
336 std::set<int> depths;
337 for (const_iterator it = nonRemoved(),
338 itEnd = _charsByDepth.end(); it != itEnd; ++it) {
340 DisplayObject* ch = *it;
341 int depth = ch->get_depth();
342 if (!depths.insert(depth).second) {
343 log_debug("Depth %d is duplicated in DisplayList %p",
344 depth, (const void*)this);
345 std::abort();
348 if (_charsByDepth.empty()) return;
349 // check we didn't screw up ordering
350 assert(std::adjacent_find(_charsByDepth.begin(), _charsByDepth.end(),
351 DepthGreaterThan()) == _charsByDepth.end());
353 #else
354 void testInvariant() const {}
355 #endif
357 private:
359 /// Re-insert a removed-from-stage DisplayObject after appropriately
360 /// shifting its depth based on the DisplayObject::removedDepthOffset
361 /// value.
363 /// PRE-CONDITIONS
364 /// - ch::isUnloaded() returns true (assertion fails otherwise)
365 /// - ch is not already in the list (assertion fails otherwise)
367 /// TODO: inspect what should happen if the target depth is already
368 /// occupied
369 void reinsertRemovedCharacter(DisplayObject* ch);
371 container_type _charsByDepth;
374 template <class V>
375 void
376 DisplayList::visitBackward(V& visitor)
378 for (reverse_iterator it = _charsByDepth.rbegin(),
379 itEnd = _charsByDepth.rend(); it != itEnd; ++it) {
380 if (!visitor(*it)) break;
384 template <class V>
385 void
386 DisplayList::visitBackward(V& visitor) const
388 for (const_reverse_iterator it = _charsByDepth.rbegin(),
389 itEnd = _charsByDepth.rend(); it != itEnd; ++it) {
390 if (!visitor(*it)) break;
394 template <class V>
395 void
396 DisplayList::visitAll(V& visitor)
398 for (iterator it = _charsByDepth.begin(), itEnd = _charsByDepth.end();
399 it != itEnd; ++it) {
401 visitor(*it);
405 template <class V>
406 void
407 DisplayList::visitAll(V& visitor) const
409 for (const_iterator it = _charsByDepth.begin(),
410 itEnd = _charsByDepth.end(); it != itEnd; ++it) {
412 visitor(*it);
416 std::ostream& operator<< (std::ostream&, const DisplayList&);
418 } // namespace gnash
421 #endif // GNASH_DLIST_H
425 // Local Variables:
426 // mode: C++
427 // c-basic-offset: 8
428 // tab-width: 8
429 // indent-tabs-mode: t
430 // End: