1 /*
2     Ming, an SWF output library
3     Copyright (C) 2002  Opaque Industries - http://www.opaque.net/
4 
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 of the License, or (at your option) any later version.
9 
10     This library 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 GNU
13     Lesser General Public License for more details.
14 
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 
20 #include <stdlib.h>
21 /* not used? #include <string.h> */
22 #include <math.h>
23 
24 #include "blocks/placeobject.h"
25 #include "blocks/character.h"
26 #include "blocks/matrix.h"
27 #include "displaylist.h"
28 #include "position.h"
29 #include "blocks/soundstream.h"
30 #include "blocks/outputblock.h"
31 #include "blocks/button.h"
32 #include "blocks/videostream.h"
33 #include "blocks/blocktypes.h"
34 #include "blocks/filter.h"
35 #include "blocks/sprite.h"
36 #include "blocks/scalinggrid.h"
37 #include "libming.h"
38 
39 #define ITEM_NEW						(1<<0)
40 #define ITEM_REMOVED				(1<<1)
41 #define ITEM_TRANSFORMED		(1<<2)
42 #define ITEM_CXFORMCHANGED	(1<<3)
43 #define ITEM_RATIOCHANGED		(1<<4)
44 
45 #define ITEM_CHANGED	(ITEM_TRANSFORMED|ITEM_CXFORMCHANGED|ITEM_RATIOCHANGED|ITEM_NEW)
46 
47 struct SWFDisplayList_s
48 {
49 	SWFSoundStream soundStream;
50 	SWFDisplayItem head;
51 	SWFDisplayItem tail;
52 	byte isSprite;
53 	int depth;
54 };
55 
56 
57 void
destroySWFDisplayItem(SWFDisplayItem displayItem)58 destroySWFDisplayItem(SWFDisplayItem displayItem)
59 {
60 	if ( displayItem->position )
61 		destroySWFPosition(displayItem->position);
62 
63 	if ( displayItem->matrix )
64 		destroySWFMatrix(displayItem->matrix);
65 
66 	/* character is freed in blocklist */
67 
68 	free(displayItem);
69 }
70 
71 
72 void
destroySWFDisplayList(SWFDisplayList displayList)73 destroySWFDisplayList(SWFDisplayList displayList)
74 {
75 	SWFDisplayItem item = displayList->head, next;
76 
77 	while ( item != NULL )
78 	{
79 		next = item->next;
80 		destroySWFDisplayItem(item);
81 		item = next;
82 	}
83 
84 	free(displayList);
85 }
86 
87 
88 SWFDisplayList
newSWFDisplayList()89 newSWFDisplayList()
90 {
91 	SWFDisplayList list = (SWFDisplayList)malloc(sizeof(struct SWFDisplayList_s));
92 
93 	/* If malloc failed, return NULL to signify this */
94 	if (NULL == list)
95 		return NULL;
96 
97 	list->isSprite = FALSE;
98 	list->head = NULL;
99 	list->tail = NULL;
100 	list->soundStream = NULL;
101 	list->depth = 0;
102 
103 	return list;
104 }
105 
106 
107 SWFDisplayList
newSWFSpriteDisplayList()108 newSWFSpriteDisplayList()
109 {
110 	SWFDisplayList list = (SWFDisplayList)malloc(sizeof(struct SWFDisplayList_s));
111 
112 	/* If malloc failed, return NULL to signify this */
113 	if (NULL == list)
114 		return NULL;
115 
116 	list->isSprite = TRUE;
117 	list->head = NULL;
118 	list->tail = NULL;
119 	list->soundStream = NULL;
120 	list->depth = 0;
121 
122 	return list;
123 }
124 
125 void
SWFDisplayItem_replace(SWFDisplayItem item,SWFCharacter character)126 SWFDisplayItem_replace(SWFDisplayItem item, SWFCharacter character)
127 {
128 	item->character = character;
129 
130 	if ( item->block )
131 		destroySWFPlaceObject2Block(item->block);
132 	item->block = newSWFPlaceObject2Block(item->depth);
133 	item->flags = ITEM_NEW;
134 	item->isPlaced = 0;
135 	SWFPlaceObject2Block_setMove(item->block);
136 	SWFPlaceObject2Block_setCharacter(item->block, character);
137 }
138 
139 SWFDisplayItem
SWFDisplayList_add(SWFDisplayList list,SWFBlockList blocklist,SWFCharacter character)140 SWFDisplayList_add(SWFDisplayList list, SWFBlockList blocklist, SWFCharacter character)
141 {
142 	SWFDisplayItem item = (SWFDisplayItem) malloc(sizeof(struct SWFDisplayItem_s));
143 
144 	/* If malloc failed, return NULL to signify this */
145 	if (NULL == item)
146 		return NULL;
147 
148 	item->flags = ITEM_NEW;
149 	item->next = NULL;
150 	item->depth = ++list->depth;
151 
152 	item->matrix = newSWFMatrix(1, 0, 0, 1, 0, 0);
153 
154 	/* If newSWFMatrix() failed, return NULL to signify this */
155 	if (NULL == item->matrix)
156 	{
157 		free(item);
158 		return NULL;
159 	}
160 
161 	item->position = newSWFPosition(item->matrix);
162 
163 	/* If newSWFPosition() failed, return NULL to signify this */
164 	if (NULL == item->position)
165 	{
166 		destroySWFMatrix(item->matrix);
167 		free(item);
168 		return NULL;
169 	}
170 
171 	item->block = newSWFPlaceObject2Block(item->depth);
172 
173 	/* If newSWFPlaceObject2Block() failed, return NULL to signify this */
174 	if (NULL == item->block)
175 	{
176 		destroySWFPosition(item->position);
177 		destroySWFMatrix(item->matrix);
178 		free(item);
179 		return NULL;
180 	}
181 
182 	item->character = character;
183 	item->isPlaced = 0;
184 	item->blocklist = blocklist;
185 
186 	SWFPlaceObject2Block_setCharacter(item->block, character);
187 	SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
188 
189 	if ( list->tail )
190 		list->tail->next = item;
191 	else
192 		list->head = item;
193 
194 	item->prev = list->tail;
195 	list->tail = item;
196 	// back pointer for endmask
197 	item->list = list;
198 	return item;
199 }
200 
201 
202 void
SWFDisplayItem_remove(SWFDisplayItem item)203 SWFDisplayItem_remove(SWFDisplayItem item)
204 {
205 	item->flags |= ITEM_REMOVED;
206 }
207 
208 void
SWFDisplayItem_removeFromList(SWFDisplayItem item,SWFBlockList blocklist)209 SWFDisplayItem_removeFromList(SWFDisplayItem item, SWFBlockList blocklist)
210 {
211 		SWFDisplayList list;
212 
213 		if(item == NULL || item->list == NULL || blocklist == NULL)
214 			return;
215 
216 		list = item->list;
217 		if(item->next)
218 			item->next->prev = item->prev;
219 
220 		if(item->prev)
221 			item->prev->next = item->next;
222 
223 		if(item == list->head)
224 			list->head = item->next;
225 		if(item == list->tail)
226 			list->tail = item->prev;
227 
228 		if(item->isPlaced)
229 			SWFBlockList_addBlock(blocklist,
230 				(SWFBlock)newSWFRemoveObject2Block(item->depth));
231 
232 		destroySWFDisplayItem(item);
233 }
234 
235 static void
checkBlock(SWFDisplayItem item)236 checkBlock(SWFDisplayItem item)
237 {
238 	if ( item->block == NULL )
239 		item->block = newSWFPlaceObject2Block(item->depth);
240 
241 	if ( (item->flags & ITEM_NEW) == 0 )
242 		SWFPlaceObject2Block_setMove(item->block);
243 }
244 
245 
246 SWFCharacter
SWFDisplayItem_getCharacter(SWFDisplayItem item)247 SWFDisplayItem_getCharacter(SWFDisplayItem item)
248 {
249 	return item->character;
250 }
251 
252 
253 int
SWFDisplayItem_getDepth(SWFDisplayItem item)254 SWFDisplayItem_getDepth(SWFDisplayItem item)
255 {
256 	return item->depth;
257 }
258 
259 
260 void
SWFDisplayItem_setDepth(SWFDisplayItem item,int depth)261 SWFDisplayItem_setDepth(SWFDisplayItem item, int depth)
262 {
263 	item->depth = depth;
264 
265 	checkBlock(item);
266 
267 	if ( (item->flags & ITEM_NEW) == 0 )
268 	{
269 		/* warn.. */
270 		return;
271 	}
272 
273 	SWFPlaceObject2Block_setDepth(item->block, depth);
274 }
275 
276 
277 SWFMatrix
SWFDisplayItem_getMatrix(SWFDisplayItem item)278 SWFDisplayItem_getMatrix(SWFDisplayItem item)
279 {
280 	checkBlock(item);
281 	return item->matrix;
282 }
283 
284 
285 void
SWFDisplayItem_move(SWFDisplayItem item,double x,double y)286 SWFDisplayItem_move(SWFDisplayItem item, double x, double y)
287 {
288 	checkBlock(item);
289 	SWFPosition_move(item->position, x, y);
290 	SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
291 }
292 
293 
294 void
SWFDisplayItem_moveTo(SWFDisplayItem item,double x,double y)295 SWFDisplayItem_moveTo(SWFDisplayItem item,  double x, double y)
296 {
297 	checkBlock(item);
298 	SWFPosition_moveTo(item->position, x, y);
299 	SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
300 }
301 
302 
303 void
SWFDisplayItem_getPosition(SWFDisplayItem item,double * x,double * y)304 SWFDisplayItem_getPosition(SWFDisplayItem item, double *x, double *y)
305 {
306 	// returns the current position of this display item into the provided
307 	// pointers, respects NULL values
308 
309 	checkBlock(item);
310 	SWFPosition_getXY(item->position, x, y);
311 }
312 
313 
314 void
SWFDisplayItem_rotate(SWFDisplayItem item,double degrees)315 SWFDisplayItem_rotate(SWFDisplayItem item, double degrees)
316 {
317 	checkBlock(item);
318 	SWFPosition_rotate(item->position, degrees);
319 	SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
320 }
321 
322 
323 void
SWFDisplayItem_rotateTo(SWFDisplayItem item,double degrees)324 SWFDisplayItem_rotateTo(SWFDisplayItem item, double degrees)
325 {
326 	checkBlock(item);
327 	SWFPosition_rotateTo(item->position, degrees);
328 	SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
329 }
330 
331 
332 void
SWFDisplayItem_getRotation(SWFDisplayItem item,double * degrees)333 SWFDisplayItem_getRotation(SWFDisplayItem item, double *degrees)
334 {
335 	// returns the current rotation of this display item into the given
336 	// pointer, respects NULL value
337 
338 	checkBlock(item);
339 
340 	if ( degrees != NULL )
341 		*degrees = SWFPosition_getRotation(item->position);
342 }
343 
344 
345 void
SWFDisplayItem_scale(SWFDisplayItem item,double xScale,double yScale)346 SWFDisplayItem_scale(SWFDisplayItem item, double xScale, double yScale)
347 {
348 	checkBlock(item);
349 	SWFPosition_scaleXY(item->position, xScale, yScale);
350 	SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
351 }
352 
353 
354 void
SWFDisplayItem_scaleTo(SWFDisplayItem item,double xScale,double yScale)355 SWFDisplayItem_scaleTo(SWFDisplayItem item, double xScale, double yScale)
356 {
357 	checkBlock(item);
358 	SWFPosition_scaleXYTo(item->position, xScale, yScale);
359 	SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
360 }
361 
362 
363 void
SWFDisplayItem_getScale(SWFDisplayItem item,double * xScale,double * yScale)364 SWFDisplayItem_getScale(SWFDisplayItem item, double *xScale, double *yScale)
365 {
366 	// returns the current x- and y-scale of this display item into the given
367 	// pointers, respects NULL values
368 
369 	checkBlock(item);
370 	SWFPosition_getXYScale(item->position, xScale, yScale);
371 }
372 
373 
374 void
SWFDisplayItem_skewX(SWFDisplayItem item,double x)375 SWFDisplayItem_skewX(SWFDisplayItem item, double x)
376 {
377 	checkBlock(item);
378 	SWFPosition_skewX(item->position, x);
379 	SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
380 }
381 
382 
383 void
SWFDisplayItem_skewXTo(SWFDisplayItem item,double x)384 SWFDisplayItem_skewXTo(SWFDisplayItem item, double x)
385 {
386 	checkBlock(item);
387 	SWFPosition_skewXTo(item->position, x);
388 	SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
389 }
390 
391 
392 void
SWFDisplayItem_skewY(SWFDisplayItem item,double y)393 SWFDisplayItem_skewY(SWFDisplayItem item, double y)
394 {
395 	checkBlock(item);
396 	SWFPosition_skewY(item->position, y);
397 	SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
398 }
399 
400 
401 void
SWFDisplayItem_skewYTo(SWFDisplayItem item,double y)402 SWFDisplayItem_skewYTo(SWFDisplayItem item, double y)
403 {
404 	checkBlock(item);
405 	SWFPosition_skewYTo(item->position, y);
406 	SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
407 }
408 
409 
410 void
SWFDisplayItem_getSkew(SWFDisplayItem item,double * xSkew,double * ySkew)411 SWFDisplayItem_getSkew(SWFDisplayItem item, double *xSkew, double *ySkew)
412 {
413 	// returns the current x- and y-skew of this display item into the given
414 	// pointers, respects NULL values
415 
416 	checkBlock(item);
417 	SWFPosition_getXYSkew(item->position, xSkew, ySkew);
418 }
419 
420 
421 void
SWFDisplayItem_setMatrix(SWFDisplayItem item,double a,double b,double c,double d,double x,double y)422 SWFDisplayItem_setMatrix(SWFDisplayItem item,
423                          double a, double b, double c, double d, double x, double y)
424 {
425 	checkBlock(item);
426 	SWFPosition_setMatrix(item->position, a, b, c, d, x, y);
427 	SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
428 }
429 
430 /*
431  * This function assigns a name to a display item.
432  * The assigend name can be used in AS as a reference to this item
433  */
434 void
SWFDisplayItem_setName(SWFDisplayItem item,const char * name)435 SWFDisplayItem_setName(SWFDisplayItem item, const char *name)
436 {
437 	checkBlock(item);
438 
439 	if ( (item->flags & ITEM_NEW) == 0 )
440 	{
441 		/* warn.. */
442 		return;
443 	}
444 	/* item->block is never null when ITEM_NEW set */
445 	SWFPlaceObject2Block_setName(item->block, name);
446 }
447 
448 /*
449  * This function sets masklevel for the current display item
450  * This item masks other display items above it. If this items
451  * depth is 1 and its masklevel is set to 4, all items with depth
452  * >= 5 are masked.
453  */
454 void
SWFDisplayItem_setMaskLevel(SWFDisplayItem item,int masklevel)455 SWFDisplayItem_setMaskLevel(SWFDisplayItem item, int masklevel)
456 {
457 	checkBlock(item);
458 
459 	if ( (item->flags & ITEM_NEW) == 0 )
460 	{
461 		/* warn.. */
462 		return;
463 	}
464 
465 	/* item->block is never null when ITEM_NEW set */
466 	SWFPlaceObject2Block_setMaskLevel(item->block, masklevel);
467 }
468 
469 
470 void
SWFDisplayItem_endMask(SWFDisplayItem item)471 SWFDisplayItem_endMask(SWFDisplayItem item)
472 {
473 	checkBlock(item);
474 	SWFPlaceObject2Block_setMaskLevel(item->block, item->list->depth);
475 }
476 
477 
478 void
SWFDisplayItem_setRatio(SWFDisplayItem item,float ratio)479 SWFDisplayItem_setRatio(SWFDisplayItem item, float ratio)
480 {
481 	int res;
482 	checkBlock(item);
483 	if(ratio < 0)
484 	{
485 		SWF_warn("SWFDisplayItem_setRatio: ratio must be inside [0...1]\n");
486 	 	ratio = 0;
487 	}
488 	else if (ratio > 1.0)
489 	{
490 		SWF_warn("SWFDisplayItem_setRatio: ratio must be inside [0...1]\n");
491 	 	ratio = 1.0;
492 	}
493 	res = (int)floor(ratio * 65535);
494 	SWFPlaceObject2Block_setRatio(item->block, res);
495 }
496 
497 
498 void
SWFDisplayItem_setCXform(SWFDisplayItem item,SWFCXform cXform)499 SWFDisplayItem_setCXform(SWFDisplayItem item, SWFCXform cXform)
500 {
501 	checkBlock(item);
502 	SWFPlaceObject2Block_setCXform(item->block, cXform);
503 }
504 
505 
506 void
SWFDisplayItem_setColorAdd(SWFDisplayItem item,int r,int g,int b,int a)507 SWFDisplayItem_setColorAdd(SWFDisplayItem item,	int r, int g, int b, int a)
508 {
509 	checkBlock(item);
510 	SWFPlaceObject2Block_setColorAdd(item->block, r, g, b, a);
511 }
512 
513 
514 void
SWFDisplayItem_setColorMult(SWFDisplayItem item,float r,float g,float b,float a)515 SWFDisplayItem_setColorMult(SWFDisplayItem item,
516 														float r, float g, float b, float a)
517 {
518 	checkBlock(item);
519 	SWFPlaceObject2Block_setColorMult(item->block, r, g, b, a);
520 }
521 
522 
523 void
SWFDisplayItem_addAction(SWFDisplayItem item,SWFAction action,int flags)524 SWFDisplayItem_addAction(SWFDisplayItem item, SWFAction action, int flags)
525 {
526 	checkBlock(item);
527 
528 	if ( (item->flags & ITEM_NEW) == 0 )
529 	{
530 		/* warn.. */
531 		return;
532 	}
533 
534 	/* item->block is never null when ITEM_NEW set */
535 	SWFPlaceObject2Block_addAction(item->block, action, flags);
536 }
537 
538 /*
539  * adds a surface filter
540  * Adds a bitmap filter to the display object.
541  * Also sets cache-as-bitmap flag.
542  * See SWFFilter for possible filter objects. Filter can
543  * only be applied to buttons, sprite/movieclips and text
544  */
SWFDisplayItem_addFilter(SWFDisplayItem item,SWFFilter filter)545 void SWFDisplayItem_addFilter(SWFDisplayItem item,
546                               SWFFilter filter /* filter */)
547 {
548 	SWFBlock block;
549 	block = (SWFBlock)item->character;
550 	if(!SWFFilter_testBlockType(block->type))
551 	{
552 		SWF_warn("Filter can only be applied to buttons, sprite/movieclips and text\n");
553 		return;
554 	}
555 	checkBlock(item);
556 	SWFPlaceObject2Block_setCacheFlag(item->block, 1);
557 	SWFPlaceObject2Block_addFilter(item->block, filter);
558 
559 }
560 
561 
562 /*
563  * set blend mdoe
564  * Sets an alternative blend mode instead of default alpha blend.
565  * possible modes are:
566  * SWFBLEND_MODE_NORMAL
567  * SWFBLEND_MODE_LAYER
568  * SWFBLEND_MODE_MULT
569  * SWFBLEND_MODE_SCREEN
570  * SWFBLEND_MODE_DARKEN
571  * SWFBLEND_MODE_ADD
572  * SWFBLEND_MODE_SUB
573  * SWFBLEND_MODE_DIFF
574  * SWFBLEND_MODE_DIFF
575  * SWFBLEND_MODE_INV
576  * SWFBLDEN_MODE_ALPHA
577  * SWFBLEND_MDOE_ERASE
578  * SWFBLEND_MDOE_OVERLAY
579  * SWFBLEND_MODE_HARDLIGHT
580  */
SWFDisplayItem_setBlendMode(SWFDisplayItem item,int mode)581 void SWFDisplayItem_setBlendMode(SWFDisplayItem item,
582 			int mode /* blend mode */)
583 {
584 	checkBlock(item);
585 	SWFPlaceObject2Block_setBlendMode(item->block, mode);
586 }
587 
588 
589 /*
590  * set cashing flag
591  * If this flag ist set, the character can be cached as a bitmap. This might
592  * improve rednering speed, if the object dos no change often.
593  * This feature is for SWF version >= 8 only.
594  */
SWFDisplayItem_cacheAsBitmap(SWFDisplayItem item,int flag)595 void SWFDisplayItem_cacheAsBitmap(SWFDisplayItem item,
596 	int flag /* flag 0 or 1 */)
597 {
598 	checkBlock(item);
599 	SWFPlaceObject2Block_setCacheFlag(item->block, flag);
600 }
601 
602 void
SWFDisplayList_setSoundStream(SWFDisplayList list,SWFSoundStream stream)603 SWFDisplayList_setSoundStream(SWFDisplayList list, SWFSoundStream stream)
604 {
605 	list->soundStream = stream;
606 }
607 
608 
609 void
SWFDisplayList_rewindSoundStream(SWFDisplayList list)610 SWFDisplayList_rewindSoundStream(SWFDisplayList list)
611 {
612 	// XXX - this is a hack, should be replaced..
613 
614 	if ( list->soundStream )
615 		SWFSoundStream_rewind(list->soundStream);
616 }
617 
618 void
SWFDisplayList_writeBlocks(SWFDisplayList list,SWFBlockList blocklist)619 SWFDisplayList_writeBlocks(SWFDisplayList list, SWFBlockList blocklist)
620 {
621 	SWFDisplayItem item = list->head, next;
622 	SWFCharacter character;
623 
624 	if ( list->soundStream )
625 	{
626 		SWFBlock stream = SWFSoundStream_getStreamBlock(list->soundStream);
627 
628 		if ( stream )
629 			SWFBlockList_addBlock(blocklist, stream);
630 	}
631 
632 	while ( item != NULL )
633 	{
634 		character = item->character;
635 
636 		//		if ( character != NULL )
637 		//			SWFBlockList_resolveCharacterDependencies(blocklist, character);
638 
639 		if ( item->flags & ITEM_REMOVED )
640 		{
641 			next = item->next;
642 			SWFDisplayItem_removeFromList(item, blocklist);
643 			item = next;
644 			continue;
645 		}
646 
647 		if ( character != NULL &&
648 				 !SWFBlock_isDefined((SWFBlock)character) &&
649 				 !list->isSprite )
650 		{
651 			SWFBlockList_addBlock(blocklist, (SWFBlock)character);
652 		}
653 
654 		if ( item->block != NULL )
655 		{
656 			if(!item->isPlaced && character->onPlace)
657 				character->onPlace(item, blocklist);
658 			SWFBlockList_addBlock(blocklist, (SWFBlock)item->block);
659 			item->isPlaced = 1;
660 		}
661 
662 		if (character && character->onFrame)
663 			character->onFrame(item, blocklist);
664 
665 		item->flags = 0;
666 		item->block = NULL;
667 
668 		item = item->next;
669 	}
670 }
671 
672 /*
673  * This function writes the item object immediately to the blocklist.
674  * Usually MING waits with writing a display item until a frame is closed
675  * through a nextFrame() call, because a display items state could be altered
676  * for the current frame. By using SWFDisplayItem_flush() MING does not wait
677  * and writes the frame immediately. Therefore a user can influence the
678  * swf tag oder. Changing a display items state after calling flush() takes
679  * effect in the next frame.
680  */
681 void
SWFDisplayItem_flush(SWFDisplayItem item)682 SWFDisplayItem_flush(SWFDisplayItem item /* item to write */)
683 {
684 	SWFCharacter character;
685 	if(item == NULL)
686 		return;
687 
688 	character = item->character;
689 	if (item->flags & ITEM_REMOVED)
690 	{
691 		SWFDisplayItem_removeFromList(item, item->blocklist);
692 		return;
693 	}
694 
695 	if (character != NULL && !SWFBlock_isDefined((SWFBlock)character))
696 	{
697 		SWFBlockList_addBlock(item->blocklist, (SWFBlock)character);
698 	}
699 
700 	if ( item->block != NULL )
701 	{
702 		if(!item->isPlaced && character->onPlace)
703 			character->onPlace(item, item->blocklist);
704 		SWFBlockList_addBlock(item->blocklist, (SWFBlock)item->block);
705 		item->isPlaced = 1;
706 	}
707 
708 	item->flags = 0;
709 	item->block = NULL;
710 }
711 
712 /*
713  * Local variables:
714  * tab-width: 2
715  * c-basic-offset: 2
716  * End:
717  */
718