summaryrefslogtreecommitdiff
path: root/core/multimedia/opieplayer/libflash/displaylist.cc
Unidiff
Diffstat (limited to 'core/multimedia/opieplayer/libflash/displaylist.cc') (more/less context) (ignore whitespace changes)
-rw-r--r--core/multimedia/opieplayer/libflash/displaylist.cc708
1 files changed, 708 insertions, 0 deletions
diff --git a/core/multimedia/opieplayer/libflash/displaylist.cc b/core/multimedia/opieplayer/libflash/displaylist.cc
new file mode 100644
index 0000000..d71cfb7
--- a/dev/null
+++ b/core/multimedia/opieplayer/libflash/displaylist.cc
@@ -0,0 +1,708 @@
1////////////////////////////////////////////////////////////
2// Flash Plugin and Player
3// Copyright (C) 1998,1999 Olivier Debon
4//
5// This program is free software; you can redistribute it and/or
6// modify it under the terms of the GNU General Public License
7// as published by the Free Software Foundation; either version 2
8// of the License, or (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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18//
19///////////////////////////////////////////////////////////////
20// Author : Olivier Debon <odebon@club-internet.fr>
21//
22
23#include "swf.h"
24
25#ifdef RCSID
26static char *rcsid = "$Id$";
27#endif
28
29#define PRINT 0
30
31void deleteButton(FlashMovie *movie, DisplayListEntry *e)
32{
33 /* save the focus */
34 if (movie->mouse_active == 0 && e->renderState == stateOver) {
35 movie->lost_over = (Button *)e->character;
36 movie->cur_focus = NULL;
37 }
38
39 if (e == movie->cur_focus) {
40 movie->cur_focus = NULL;
41 }
42}
43
44void addButton(FlashMovie *movie, DisplayListEntry *e)
45{
46 if (movie->mouse_active == 0 &&
47 movie->cur_focus == NULL &&
48 movie->lost_over == (Button *)e->character) {
49 /* restore the lost focus */
50 e->renderState = stateOver;
51 e->oldState = stateOver;
52 ((Button *)e->character)->updateButtonState(e);
53 movie->lost_over = NULL;
54 movie->cur_focus = e;
55 }
56}
57
58DisplayList::DisplayList(FlashMovie *movie)
59{
60 list = NULL;
61 this->movie = movie;
62 bbox.reset();
63 isSprite = 0;
64}
65
66DisplayList::~DisplayList()
67{
68 clearList();
69}
70
71void
72DisplayList::clearList()
73{
74 DisplayListEntry *del, *e;
75
76 for(e = list; e;)
77 {
78 updateBoundingBox(e);
79 if (e->character->isButton()) {
80 deleteButton(movie,e);
81 }
82 del = e;
83 e = e->next;
84 delete del;
85 }
86 list = 0;
87}
88
89DisplayListEntry *
90DisplayList::getList()
91{
92 return list;
93}
94
95static void bbox(Rect *rect, Matrix *m, long x1, long y1)
96{
97 long x,y;
98
99 x = m->getX(x1,y1);
100 y = m->getY(x1,y1);
101 if (x < rect->xmin) rect->xmin = x;
102 if (x > rect->xmax) rect->xmax = x;
103 if (y < rect->ymin) rect->ymin = y;
104 if (y > rect->ymax) rect->ymax = y;
105}
106
107// Update bb to include boundary, optional reset of bb
108void transformBoundingBox(Rect *bb, Matrix *matrix, Rect *boundary, int reset)
109{
110 if (reset) {
111 bb->reset();
112 }
113
114 if (boundary->xmin != LONG_MAX) {
115 bbox(bb, matrix, boundary->xmin, boundary->ymin);
116 bbox(bb, matrix, boundary->xmax, boundary->ymin);
117 bbox(bb, matrix, boundary->xmin, boundary->ymax);
118 bbox(bb, matrix, boundary->xmax, boundary->ymax);
119 }
120}
121
122void
123DisplayList::placeObject(GraphicDevice *gd,Character *character, long depth, Matrix *matrix, Cxform *cxform, char *name)
124{
125 DisplayListEntry *n,*e,*prev;
126
127 n = new DisplayListEntry;
128 if (n == NULL) return;
129
130 n->depth = depth;
131 n->matrix = matrix;
132 n->cxform = cxform;
133 n->character = character;
134 n->instanceName = name;
135 n->owner = this;
136
137#if 0
138 printf("Dl %lx: placeObject: depth=%d character=%d cxform=%p\n",
139 this, n->depth,n->character ? n->character->getTagId() : 0, cxform);
140#endif
141
142 if (character == 0 || matrix == 0 || cxform == 0) {
143 for (e = list; e; prev = e, e = e->next) {
144 if (e->depth == n->depth) {
145 if (character == 0) {
146 n->character = e->character;
147 }
148 if (matrix == 0) {
149 n->matrix = e->matrix;
150 }
151 if (cxform == 0) {
152 n->cxform = e->cxform;
153 }
154 break;
155 }
156 }
157 }
158
159 if (n->character == 0) {
160 // Not found !!! Should not happen
161 // printf("PlaceObject cannot find character at depth %ld\n", n->depth);
162 delete n;
163 return;
164 }
165
166 prev = 0;
167 for (e = list; e; prev = e, e = e->next)
168 {
169 if (e->depth == n->depth) {
170 if (e->character->isButton()) {
171 deleteButton(movie, e);
172 }
173
174 // Do update, object has moved or been resized
175 updateBoundingBox(e);
176
177 // Replace object
178 e->depth = n->depth;
179 e->matrix = n->matrix;
180 e->cxform = n->cxform;
181 e->character = n->character;
182 /* if it is a button, we must update its state */
183 if (e->character->isButton()) {
184 movie->buttons_updated = 1;
185 addButton(movie, e);
186 }
187
188 updateBoundingBox(e);
189
190 delete n;
191 return;
192 }
193 if (e->depth > n->depth) break;
194 }
195 /* new object */
196
197 /* button instantiation */
198 if (n->character->isButton()) {
199 n->renderState = stateUp;
200 n->oldState = stateUp;
201 ((Button *)n->character)->updateButtonState(n);
202 addButton(movie,n);
203 }
204
205 updateBoundingBox(n);
206
207 if (prev == 0) {
208 // Object comes at first place
209 n->next = list;
210 list = n;
211 } else {
212 // Insert object
213 n->next = prev->next;
214 prev->next = n;
215 }
216}
217
218
219Character *
220DisplayList::removeObject(GraphicDevice *gd,Character *character, long depth)
221{
222 DisplayListEntry *e,*prev;
223
224 // List should not be empty
225 if (list == 0) return 0;
226
227#if 0
228 printf("removeObject: depth=%d character=%d\n",
229 depth,character ? character->getTagId() : 0);
230#endif
231
232 prev = 0;
233 for (e = list; e; prev = e, e = e->next) {
234 if (e->depth == depth) {
235 if (prev) {
236 prev->next = e->next;
237 } else {
238 list = e->next;
239 }
240 if (character == 0) {
241 character = e->character;
242 }
243 if (e->character->isButton()) {
244 deleteButton(movie, e);
245 }
246 if (e->character->isSprite()) {
247 ((Sprite*)e->character)->reset();
248 }
249
250 updateBoundingBox(e);
251
252 delete e;
253 return character;
254 }
255 }
256 return 0;// Should not happen
257}
258
259void
260DisplayList::updateBoundingBox(DisplayListEntry *e)
261{
262 Rect rect;
263
264 //rect.reset();
265 e->character->getBoundingBox(&rect,e);
266 transformBoundingBox(&this->bbox, e->matrix, &rect, 0);
267}
268
269int
270DisplayList::updateSprites()
271{
272 Sprite *sprite;
273 DisplayListEntry *e;
274 int refresh = 0;
275
276 for (e = this->list; e != NULL; e = e->next) {
277 if (e->character->isButton() && e->buttonCharacter) {
278 if (e->buttonCharacter->isSprite()) {
279 Matrix mat;
280
281 sprite = (Sprite *)e->buttonCharacter;
282 refresh |= sprite->program->dl->updateSprites();
283 refresh |= sprite->program->nestedMovie(this->movie->gd,this->movie->sm, e->matrix, e->cxform);
284 mat = (*e->matrix) * e->buttonMatrix;
285 transformBoundingBox(&this->bbox, &mat,
286 &(sprite->program->dl->bbox),
287 0);
288 }
289 }
290 if (e->character->isSprite()) {
291 sprite = (Sprite *)e->character;
292 refresh |= sprite->program->dl->updateSprites();
293 refresh |= sprite->program->nestedMovie(this->movie->gd,this->movie->sm, e->matrix, e->cxform);
294 transformBoundingBox(&this->bbox, e->matrix,
295 &(sprite->program->dl->bbox),
296 0);
297 }
298 }
299 return refresh;
300}
301
302/* Function can return either 0,1 or 2
303 0: Nothing match, continue
304 1: Something matches, but continue searching
305 2: Something matches, but stop searching
306*/
307
308static int exploreButtons1(Program *prg, void *opaque,
309 ExploreButtonFunc func)
310{
311 DisplayListEntry *e;
312 int ret, ret2 = 0;
313
314 for(e=prg->dl->list; e != NULL; e = e->next) {
315 if (e->character == NULL) continue;
316 if (e->character->isButton()) {
317 ret = func(opaque,prg,e);
318 if (ret == 2) return ret;// Func asks to return at once !!!
319 if (ret) ret2 = 1;
320 }
321 if (e->character->isSprite()) {
322 ret = exploreButtons1(((Sprite *)e->character)->program,
323 opaque,func);
324 if (ret == 2) return ret;// Func asks to return at once !!!
325 if (ret) ret2 = 1;
326 }
327 }
328 return ret2;
329}
330
331int exploreButtons(FlashMovie *movie, void *opaque, ExploreButtonFunc func)
332{
333 CInputScript *script;
334 int ret;
335
336 script = movie->main;
337 while (script != NULL) {
338 if (script->program) {
339 ret = exploreButtons1(script->program, opaque, func);
340 if (ret) return ret;
341 }
342 script = script->next;
343 }
344 return 0;
345}
346
347typedef struct {
348 long x,y;
349 int hit;
350 DisplayListEntry *bhit;
351} HitTable;
352
353static void button_hit_func(void *id, long y, long start, long end)
354{
355 HitTable *h = (HitTable *) id;
356 if ( y == h->y && (h->x >= start && h->x < end) )
357 h->hit = 1;
358}
359
360typedef struct {
361 FlashMovie *movie;
362 DisplayListEntry *bhit;
363} ButtonHit;
364
365static int button_hit(void *opaque, Program *prg, DisplayListEntry *e)
366{
367 ButtonHit *h = (ButtonHit *) opaque;
368 HitTable hit_table;
369 FlashMovie *movie = h->movie;
370 Rect bb,boundary;
371 Matrix mat;
372 ButtonState save;
373
374 hit_table.x = movie->mouse_x;
375 hit_table.y = movie->mouse_y / FRAC;
376 hit_table.hit = 0;
377
378 // Compute the bounding box in screen coordinates
379 save = e->renderState;
380 e->renderState = stateHitTest;
381 e->character->getBoundingBox(&boundary,e);
382 e->renderState = save;
383 mat = (*movie->gd->adjust) * e->renderMatrix;
384 transformBoundingBox(&bb, &mat, &boundary, 1);
385 // Check if mouse is within bb
386 if (movie->mouse_x < bb.xmin) return 0;
387 if (movie->mouse_x > bb.xmax) return 0;
388 if (movie->mouse_y < bb.ymin) return 0;
389 if (movie->mouse_y > bb.ymax) return 0;
390
391 e->character->getRegion(movie->gd, &e->renderMatrix,
392 &hit_table, button_hit_func);
393
394 if (hit_table.hit) {
395 h->bhit = e;
396 return 1;
397 } else {
398 return 0;
399 }
400}
401
402static int button_reset(void *opaque, Program *prg, DisplayListEntry *e)
403{
404 if (e->renderState != stateUp) {
405 e->owner->updateBoundingBox(e);
406 e->oldState = e->renderState;
407 e->renderState = stateUp;
408 ((Button *)e->character)->updateButtonState(e);
409 e->owner->updateBoundingBox(e);
410 }
411 return 0;
412}
413
414/* update the button states according to the current mouse state & return the list of actions */
415void
416DisplayList::updateButtons(FlashMovie *movie)
417{
418 DisplayListEntry *bhit;
419 ButtonHit h;
420
421 if (movie->mouse_active) {
422
423 h.bhit = NULL;
424 h.movie = movie;
425
426 exploreButtons(movie, &h, button_hit);
427
428 bhit = h.bhit;
429
430 /* set every button to not hit */
431 exploreButtons(movie, NULL, button_reset);
432
433 if (bhit) {
434 ButtonState state;
435
436 if (movie->button_pressed) {
437 state = stateDown;
438 } else {
439 state = stateOver;
440 }
441 if (state != bhit->renderState) {
442 bhit->owner->updateBoundingBox(bhit);
443 bhit->renderState = state;
444 ((Button *)bhit->character)->updateButtonState(bhit);
445 bhit->owner->updateBoundingBox(bhit);
446 movie->cur_focus = bhit;
447 if (movie->cursorOnOff)
448 movie->cursorOnOff(1,movie->cursorOnOffClientData);
449 }
450 } else {
451 if (movie->cursorOnOff)
452 movie->cursorOnOff(0,movie->cursorOnOffClientData);
453 }
454 }
455}
456
457typedef struct {
458 ActionRecord *action;// Action to do
459 Program *prg; // Context program
460} ButtonAction;
461
462static int button_action(void *opaque, Program *prg, DisplayListEntry *e)
463{
464 ButtonAction *h = (ButtonAction *)opaque;
465 static ActionRecord actionRefresh;
466 static ActionRecord soundFx;
467 Button *b;
468 ActionRecord **paction;
469 int n;
470
471 actionRefresh.action = ActionRefresh;
472 actionRefresh.next = 0;
473
474 soundFx.action = ActionPlaySound;
475 soundFx.next = &actionRefresh;
476
477 b = (Button *)e->character;
478
479 if (e->oldState != e->renderState) {
480
481 paction = &actionRefresh.next;
482
483 if (b->conditionList) {
484 *paction = b->getActionFromTransition(e->renderState, e->oldState);
485 } else if (e->renderState == stateDown) {
486 /* if the button is pressed and
487 no condition list is defined*/
488 *paction = b->actionRecords;
489 }
490
491 switch(e->renderState) {
492 case stateUp:
493 n = 0;
494 break;
495 case stateOver:
496 n = 1;
497 break;
498 default:
499 /* case stateDown: */
500 n = 2;
501 break;
502 }
503
504 if (b->sound[n]) {
505 soundFx.sound = b->sound[n];
506 h->action = &soundFx;
507 } else {
508 h->action = &actionRefresh;
509 }
510
511 e->oldState = e->renderState;
512
513 h->prg = prg;
514 return 2;
515 }
516 h->action = 0;// Nothing to do about this
517 return 0;
518}
519
520int computeActions(FlashMovie *movie, Program **prg, ActionRecord **ar)
521{
522 ButtonAction h;
523
524 h.action = NULL;
525 exploreButtons(movie, &h, button_action);
526 if (h.action) {
527 *prg = h.prg;
528 *ar = h.action;
529 return 1;
530 }
531 return 0;
532}
533
534#define FOCUS_ZOOM 1.5
535/* in pixels */
536#define FOCUS_SIZE_MIN 50
537#define FOCUS_TRANSLATE 15
538
539int
540DisplayList::render(GraphicDevice *gd, Matrix *render_matrix, Cxform *cxform)
541{
542 DisplayListEntry *e,*cur_focus;
543 int sprite = 0;
544 long n = 0;
545 Cxform cxf,*cxf1;
546 Rect bb,boundary;
547
548 cur_focus = NULL;
549
550 /*
551 if (isSprite == 0) {
552 if (this->bbox.xmin == LONG_MAX) return 0;
553 gd->updateClippingRegion(&this->bbox, render_matrix);
554 gd->clearCanvas();
555 }
556 */
557
558 for (e = list; e; e = e->next)
559 {
560#if PRINT
561 printf("Character %3d @ %3d\n", e->character ? e->character->getTagId() : 0, e->depth);
562#endif
563 if (e->character) {
564 Matrix mat;
565
566 if (render_matrix) {
567 mat = *render_matrix;
568 }
569
570 if (e->matrix) {
571 mat = mat * (*e->matrix);
572 }
573
574 /* fast clipping */
575 // If object boundaries are outside current clip region give up with rendering
576 e->character->getBoundingBox(&boundary,e);
577 if (boundary.xmin != LONG_MAX) {
578 Matrix tmat;
579
580 tmat = (*gd->adjust) * mat;
581 transformBoundingBox(&bb, &tmat, &boundary, 1);
582
583 bb.xmin = bb.xmin >> FRAC_BITS;
584 bb.ymin = bb.ymin >> FRAC_BITS;
585 bb.xmax = (bb.xmax + FRAC - 1) >> FRAC_BITS;
586 bb.ymax = (bb.ymax + FRAC - 1) >> FRAC_BITS;
587
588 if (bb.xmin >= gd->clip_rect.xmax ||
589 bb.xmax <= gd->clip_rect.xmin ||
590 bb.ymin >= gd->clip_rect.ymax ||
591 bb.ymax <= gd->clip_rect.ymin) {
592 continue;
593 }
594 }
595
596 if (cxform == NULL) {
597 cxf1 = e->cxform;
598 }
599 else if (e->cxform == NULL) {
600 cxf1 = cxform;
601 }
602 else {
603 cxf1 = &cxf;
604 cxf.ra = cxform->ra * e->cxform->ra;
605 cxf.ga = cxform->ga * e->cxform->ga;
606 cxf.ba = cxform->ba * e->cxform->ba;
607 cxf.aa = cxform->aa * e->cxform->aa;
608
609 cxf.rb = (long)(cxform->ra * e->cxform->rb + cxform->rb);
610 cxf.gb = (long)(cxform->ga * e->cxform->gb + cxform->gb);
611 cxf.bb = (long)(cxform->ba * e->cxform->bb + cxform->bb);
612 cxf.ab = (long)(cxform->aa * e->cxform->ab + cxform->ab);
613 }
614
615 if (e->character->isButton()) {
616 Button *b = (Button *) e->character;
617
618 e->renderMatrix = mat;
619
620 if (e->renderState != stateUp && movie->mouse_active == 0) {
621 cur_focus = e;
622 ((Button *)e->character)->updateButtonState(e);
623 }
624
625 if (b->execute(gd, &mat, cxf1, e->renderState)) {
626 sprite = 1;
627 }
628 } else {
629 if (e->character->execute(gd, &mat, cxf1)) {
630 sprite = 1;
631 }
632 }
633
634 n++;
635 }
636 }
637
638#if 0
639 {
640 /* display the bounding box (debug) */
641 Matrix tmat;
642 long x1,x2,y1,y2;
643 Color white;
644
645 white.red = 255;
646 white.green = white.blue = 0;
647 gd->setForegroundColor(white);
648
649 if (render_matrix) {
650 tmat = (*gd->adjust) * (*render_matrix);
651 } else {
652 tmat = *gd->adjust;
653 }
654 x1 = bbox.xmin;
655 y1 = bbox.ymin;
656 x2 = bbox.xmax;
657 y2 = bbox.ymax;
658 gd->drawLine(tmat.getX(x1,y1),tmat.getY(x1,y1),tmat.getX(x2,y1),tmat.getY(x2,y1),10*FRAC);
659 gd->drawLine(tmat.getX(x2,y1),tmat.getY(x2,y1),tmat.getX(x2,y2),tmat.getY(x2,y2),10*FRAC);
660 gd->drawLine(tmat.getX(x2,y2),tmat.getY(x2,y2),tmat.getX(x1,y2),tmat.getY(x1,y2),10*FRAC);
661 gd->drawLine(tmat.getX(x1,y2),tmat.getY(x1,y2),tmat.getX(x1,y1),tmat.getY(x1,y1),10*FRAC);
662 bbox.print();
663 }
664#endif
665
666 // Reset clipping zone
667 bbox.reset();
668
669 return sprite;
670}
671
672void
673DisplayList::getBoundary(Rect *bb)
674{
675 DisplayListEntry *e;
676 Rect boundary;
677
678 bb->reset();
679 for (e = list; e; e = e->next)
680 {
681 if (e->character) {
682 e->character->getBoundingBox(&boundary,e);
683 transformBoundingBox(bb, e->matrix, &boundary, 0);
684 }
685 }
686}
687
688extern "C" {
689
690void dump_buttons(FlashHandle flashHandle)
691{
692#if 0
693 Rect rect;
694 DisplayListEntry *e;
695 FlashMovie *movie;
696
697 movie = (FlashMovie *)flashHandle;
698
699 for (e = movie->first_button; e; e = e->next_button) {
700 computeBBox(movie,&rect,e);
701 printf("button: id=%d pos=%d %d %d %d\n",
702 e->character->getTagId(),
703 rect.xmin, rect.ymin, rect.xmax, rect.ymax);
704 }
705#endif
706}
707
708}