summaryrefslogtreecommitdiff
path: root/core/multimedia/opieplayer/libflash/displaylist.cc
Side-by-side diff
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 @@
+////////////////////////////////////////////////////////////
+// Flash Plugin and Player
+// Copyright (C) 1998,1999 Olivier Debon
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+///////////////////////////////////////////////////////////////
+// Author : Olivier Debon <odebon@club-internet.fr>
+//
+
+#include "swf.h"
+
+#ifdef RCSID
+static char *rcsid = "$Id$";
+#endif
+
+#define PRINT 0
+
+void deleteButton(FlashMovie *movie, DisplayListEntry *e)
+{
+ /* save the focus */
+ if (movie->mouse_active == 0 && e->renderState == stateOver) {
+ movie->lost_over = (Button *)e->character;
+ movie->cur_focus = NULL;
+ }
+
+ if (e == movie->cur_focus) {
+ movie->cur_focus = NULL;
+ }
+}
+
+void addButton(FlashMovie *movie, DisplayListEntry *e)
+{
+ if (movie->mouse_active == 0 &&
+ movie->cur_focus == NULL &&
+ movie->lost_over == (Button *)e->character) {
+ /* restore the lost focus */
+ e->renderState = stateOver;
+ e->oldState = stateOver;
+ ((Button *)e->character)->updateButtonState(e);
+ movie->lost_over = NULL;
+ movie->cur_focus = e;
+ }
+}
+
+DisplayList::DisplayList(FlashMovie *movie)
+{
+ list = NULL;
+ this->movie = movie;
+ bbox.reset();
+ isSprite = 0;
+}
+
+DisplayList::~DisplayList()
+{
+ clearList();
+}
+
+void
+DisplayList::clearList()
+{
+ DisplayListEntry *del, *e;
+
+ for(e = list; e;)
+ {
+ updateBoundingBox(e);
+ if (e->character->isButton()) {
+ deleteButton(movie,e);
+ }
+ del = e;
+ e = e->next;
+ delete del;
+ }
+ list = 0;
+}
+
+DisplayListEntry *
+DisplayList::getList()
+{
+ return list;
+}
+
+static void bbox(Rect *rect, Matrix *m, long x1, long y1)
+{
+ long x,y;
+
+ x = m->getX(x1,y1);
+ y = m->getY(x1,y1);
+ if (x < rect->xmin) rect->xmin = x;
+ if (x > rect->xmax) rect->xmax = x;
+ if (y < rect->ymin) rect->ymin = y;
+ if (y > rect->ymax) rect->ymax = y;
+}
+
+// Update bb to include boundary, optional reset of bb
+void transformBoundingBox(Rect *bb, Matrix *matrix, Rect *boundary, int reset)
+{
+ if (reset) {
+ bb->reset();
+ }
+
+ if (boundary->xmin != LONG_MAX) {
+ bbox(bb, matrix, boundary->xmin, boundary->ymin);
+ bbox(bb, matrix, boundary->xmax, boundary->ymin);
+ bbox(bb, matrix, boundary->xmin, boundary->ymax);
+ bbox(bb, matrix, boundary->xmax, boundary->ymax);
+ }
+}
+
+void
+DisplayList::placeObject(GraphicDevice *gd,Character *character, long depth, Matrix *matrix, Cxform *cxform, char *name)
+{
+ DisplayListEntry *n,*e,*prev;
+
+ n = new DisplayListEntry;
+ if (n == NULL) return;
+
+ n->depth = depth;
+ n->matrix = matrix;
+ n->cxform = cxform;
+ n->character = character;
+ n->instanceName = name;
+ n->owner = this;
+
+#if 0
+ printf("Dl %lx: placeObject: depth=%d character=%d cxform=%p\n",
+ this, n->depth,n->character ? n->character->getTagId() : 0, cxform);
+#endif
+
+ if (character == 0 || matrix == 0 || cxform == 0) {
+ for (e = list; e; prev = e, e = e->next) {
+ if (e->depth == n->depth) {
+ if (character == 0) {
+ n->character = e->character;
+ }
+ if (matrix == 0) {
+ n->matrix = e->matrix;
+ }
+ if (cxform == 0) {
+ n->cxform = e->cxform;
+ }
+ break;
+ }
+ }
+ }
+
+ if (n->character == 0) {
+ // Not found !!! Should not happen
+ // printf("PlaceObject cannot find character at depth %ld\n", n->depth);
+ delete n;
+ return;
+ }
+
+ prev = 0;
+ for (e = list; e; prev = e, e = e->next)
+ {
+ if (e->depth == n->depth) {
+ if (e->character->isButton()) {
+ deleteButton(movie, e);
+ }
+
+ // Do update, object has moved or been resized
+ updateBoundingBox(e);
+
+ // Replace object
+ e->depth = n->depth;
+ e->matrix = n->matrix;
+ e->cxform = n->cxform;
+ e->character = n->character;
+ /* if it is a button, we must update its state */
+ if (e->character->isButton()) {
+ movie->buttons_updated = 1;
+ addButton(movie, e);
+ }
+
+ updateBoundingBox(e);
+
+ delete n;
+ return;
+ }
+ if (e->depth > n->depth) break;
+ }
+ /* new object */
+
+ /* button instantiation */
+ if (n->character->isButton()) {
+ n->renderState = stateUp;
+ n->oldState = stateUp;
+ ((Button *)n->character)->updateButtonState(n);
+ addButton(movie,n);
+ }
+
+ updateBoundingBox(n);
+
+ if (prev == 0) {
+ // Object comes at first place
+ n->next = list;
+ list = n;
+ } else {
+ // Insert object
+ n->next = prev->next;
+ prev->next = n;
+ }
+}
+
+
+Character *
+DisplayList::removeObject(GraphicDevice *gd,Character *character, long depth)
+{
+ DisplayListEntry *e,*prev;
+
+ // List should not be empty
+ if (list == 0) return 0;
+
+#if 0
+ printf("removeObject: depth=%d character=%d\n",
+ depth,character ? character->getTagId() : 0);
+#endif
+
+ prev = 0;
+ for (e = list; e; prev = e, e = e->next) {
+ if (e->depth == depth) {
+ if (prev) {
+ prev->next = e->next;
+ } else {
+ list = e->next;
+ }
+ if (character == 0) {
+ character = e->character;
+ }
+ if (e->character->isButton()) {
+ deleteButton(movie, e);
+ }
+ if (e->character->isSprite()) {
+ ((Sprite*)e->character)->reset();
+ }
+
+ updateBoundingBox(e);
+
+ delete e;
+ return character;
+ }
+ }
+ return 0; // Should not happen
+}
+
+void
+DisplayList::updateBoundingBox(DisplayListEntry *e)
+{
+ Rect rect;
+
+ //rect.reset();
+ e->character->getBoundingBox(&rect,e);
+ transformBoundingBox(&this->bbox, e->matrix, &rect, 0);
+}
+
+int
+DisplayList::updateSprites()
+{
+ Sprite *sprite;
+ DisplayListEntry *e;
+ int refresh = 0;
+
+ for (e = this->list; e != NULL; e = e->next) {
+ if (e->character->isButton() && e->buttonCharacter) {
+ if (e->buttonCharacter->isSprite()) {
+ Matrix mat;
+
+ sprite = (Sprite *)e->buttonCharacter;
+ refresh |= sprite->program->dl->updateSprites();
+ refresh |= sprite->program->nestedMovie(this->movie->gd,this->movie->sm, e->matrix, e->cxform);
+ mat = (*e->matrix) * e->buttonMatrix;
+ transformBoundingBox(&this->bbox, &mat,
+ &(sprite->program->dl->bbox),
+ 0);
+ }
+ }
+ if (e->character->isSprite()) {
+ sprite = (Sprite *)e->character;
+ refresh |= sprite->program->dl->updateSprites();
+ refresh |= sprite->program->nestedMovie(this->movie->gd,this->movie->sm, e->matrix, e->cxform);
+ transformBoundingBox(&this->bbox, e->matrix,
+ &(sprite->program->dl->bbox),
+ 0);
+ }
+ }
+ return refresh;
+}
+
+/* Function can return either 0,1 or 2
+ 0: Nothing match, continue
+ 1: Something matches, but continue searching
+ 2: Something matches, but stop searching
+*/
+
+static int exploreButtons1(Program *prg, void *opaque,
+ ExploreButtonFunc func)
+{
+ DisplayListEntry *e;
+ int ret, ret2 = 0;
+
+ for(e=prg->dl->list; e != NULL; e = e->next) {
+ if (e->character == NULL) continue;
+ if (e->character->isButton()) {
+ ret = func(opaque,prg,e);
+ if (ret == 2) return ret; // Func asks to return at once !!!
+ if (ret) ret2 = 1;
+ }
+ if (e->character->isSprite()) {
+ ret = exploreButtons1(((Sprite *)e->character)->program,
+ opaque,func);
+ if (ret == 2) return ret; // Func asks to return at once !!!
+ if (ret) ret2 = 1;
+ }
+ }
+ return ret2;
+}
+
+int exploreButtons(FlashMovie *movie, void *opaque, ExploreButtonFunc func)
+{
+ CInputScript *script;
+ int ret;
+
+ script = movie->main;
+ while (script != NULL) {
+ if (script->program) {
+ ret = exploreButtons1(script->program, opaque, func);
+ if (ret) return ret;
+ }
+ script = script->next;
+ }
+ return 0;
+}
+
+typedef struct {
+ long x,y;
+ int hit;
+ DisplayListEntry *bhit;
+} HitTable;
+
+static void button_hit_func(void *id, long y, long start, long end)
+{
+ HitTable *h = (HitTable *) id;
+ if ( y == h->y && (h->x >= start && h->x < end) )
+ h->hit = 1;
+}
+
+typedef struct {
+ FlashMovie *movie;
+ DisplayListEntry *bhit;
+} ButtonHit;
+
+static int button_hit(void *opaque, Program *prg, DisplayListEntry *e)
+{
+ ButtonHit *h = (ButtonHit *) opaque;
+ HitTable hit_table;
+ FlashMovie *movie = h->movie;
+ Rect bb,boundary;
+ Matrix mat;
+ ButtonState save;
+
+ hit_table.x = movie->mouse_x;
+ hit_table.y = movie->mouse_y / FRAC;
+ hit_table.hit = 0;
+
+ // Compute the bounding box in screen coordinates
+ save = e->renderState;
+ e->renderState = stateHitTest;
+ e->character->getBoundingBox(&boundary,e);
+ e->renderState = save;
+ mat = (*movie->gd->adjust) * e->renderMatrix;
+ transformBoundingBox(&bb, &mat, &boundary, 1);
+ // Check if mouse is within bb
+ if (movie->mouse_x < bb.xmin) return 0;
+ if (movie->mouse_x > bb.xmax) return 0;
+ if (movie->mouse_y < bb.ymin) return 0;
+ if (movie->mouse_y > bb.ymax) return 0;
+
+ e->character->getRegion(movie->gd, &e->renderMatrix,
+ &hit_table, button_hit_func);
+
+ if (hit_table.hit) {
+ h->bhit = e;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int button_reset(void *opaque, Program *prg, DisplayListEntry *e)
+{
+ if (e->renderState != stateUp) {
+ e->owner->updateBoundingBox(e);
+ e->oldState = e->renderState;
+ e->renderState = stateUp;
+ ((Button *)e->character)->updateButtonState(e);
+ e->owner->updateBoundingBox(e);
+ }
+ return 0;
+}
+
+/* update the button states according to the current mouse state & return the list of actions */
+void
+DisplayList::updateButtons(FlashMovie *movie)
+{
+ DisplayListEntry *bhit;
+ ButtonHit h;
+
+ if (movie->mouse_active) {
+
+ h.bhit = NULL;
+ h.movie = movie;
+
+ exploreButtons(movie, &h, button_hit);
+
+ bhit = h.bhit;
+
+ /* set every button to not hit */
+ exploreButtons(movie, NULL, button_reset);
+
+ if (bhit) {
+ ButtonState state;
+
+ if (movie->button_pressed) {
+ state = stateDown;
+ } else {
+ state = stateOver;
+ }
+ if (state != bhit->renderState) {
+ bhit->owner->updateBoundingBox(bhit);
+ bhit->renderState = state;
+ ((Button *)bhit->character)->updateButtonState(bhit);
+ bhit->owner->updateBoundingBox(bhit);
+ movie->cur_focus = bhit;
+ if (movie->cursorOnOff)
+ movie->cursorOnOff(1,movie->cursorOnOffClientData);
+ }
+ } else {
+ if (movie->cursorOnOff)
+ movie->cursorOnOff(0,movie->cursorOnOffClientData);
+ }
+ }
+}
+
+typedef struct {
+ ActionRecord *action; // Action to do
+ Program *prg; // Context program
+} ButtonAction;
+
+static int button_action(void *opaque, Program *prg, DisplayListEntry *e)
+{
+ ButtonAction *h = (ButtonAction *)opaque;
+ static ActionRecord actionRefresh;
+ static ActionRecord soundFx;
+ Button *b;
+ ActionRecord **paction;
+ int n;
+
+ actionRefresh.action = ActionRefresh;
+ actionRefresh.next = 0;
+
+ soundFx.action = ActionPlaySound;
+ soundFx.next = &actionRefresh;
+
+ b = (Button *)e->character;
+
+ if (e->oldState != e->renderState) {
+
+ paction = &actionRefresh.next;
+
+ if (b->conditionList) {
+ *paction = b->getActionFromTransition(e->renderState, e->oldState);
+ } else if (e->renderState == stateDown) {
+ /* if the button is pressed and
+ no condition list is defined*/
+ *paction = b->actionRecords;
+ }
+
+ switch(e->renderState) {
+ case stateUp:
+ n = 0;
+ break;
+ case stateOver:
+ n = 1;
+ break;
+ default:
+ /* case stateDown: */
+ n = 2;
+ break;
+ }
+
+ if (b->sound[n]) {
+ soundFx.sound = b->sound[n];
+ h->action = &soundFx;
+ } else {
+ h->action = &actionRefresh;
+ }
+
+ e->oldState = e->renderState;
+
+ h->prg = prg;
+ return 2;
+ }
+ h->action = 0; // Nothing to do about this
+ return 0;
+}
+
+int computeActions(FlashMovie *movie, Program **prg, ActionRecord **ar)
+{
+ ButtonAction h;
+
+ h.action = NULL;
+ exploreButtons(movie, &h, button_action);
+ if (h.action) {
+ *prg = h.prg;
+ *ar = h.action;
+ return 1;
+ }
+ return 0;
+}
+
+#define FOCUS_ZOOM 1.5
+/* in pixels */
+#define FOCUS_SIZE_MIN 50
+#define FOCUS_TRANSLATE 15
+
+int
+DisplayList::render(GraphicDevice *gd, Matrix *render_matrix, Cxform *cxform)
+{
+ DisplayListEntry *e,*cur_focus;
+ int sprite = 0;
+ long n = 0;
+ Cxform cxf,*cxf1;
+ Rect bb,boundary;
+
+ cur_focus = NULL;
+
+ /*
+ if (isSprite == 0) {
+ if (this->bbox.xmin == LONG_MAX) return 0;
+ gd->updateClippingRegion(&this->bbox, render_matrix);
+ gd->clearCanvas();
+ }
+ */
+
+ for (e = list; e; e = e->next)
+ {
+#if PRINT
+ printf("Character %3d @ %3d\n", e->character ? e->character->getTagId() : 0, e->depth);
+#endif
+ if (e->character) {
+ Matrix mat;
+
+ if (render_matrix) {
+ mat = *render_matrix;
+ }
+
+ if (e->matrix) {
+ mat = mat * (*e->matrix);
+ }
+
+ /* fast clipping */
+ // If object boundaries are outside current clip region give up with rendering
+ e->character->getBoundingBox(&boundary,e);
+ if (boundary.xmin != LONG_MAX) {
+ Matrix tmat;
+
+ tmat = (*gd->adjust) * mat;
+ transformBoundingBox(&bb, &tmat, &boundary, 1);
+
+ bb.xmin = bb.xmin >> FRAC_BITS;
+ bb.ymin = bb.ymin >> FRAC_BITS;
+ bb.xmax = (bb.xmax + FRAC - 1) >> FRAC_BITS;
+ bb.ymax = (bb.ymax + FRAC - 1) >> FRAC_BITS;
+
+ if (bb.xmin >= gd->clip_rect.xmax ||
+ bb.xmax <= gd->clip_rect.xmin ||
+ bb.ymin >= gd->clip_rect.ymax ||
+ bb.ymax <= gd->clip_rect.ymin) {
+ continue;
+ }
+ }
+
+ if (cxform == NULL) {
+ cxf1 = e->cxform;
+ }
+ else if (e->cxform == NULL) {
+ cxf1 = cxform;
+ }
+ else {
+ cxf1 = &cxf;
+ cxf.ra = cxform->ra * e->cxform->ra;
+ cxf.ga = cxform->ga * e->cxform->ga;
+ cxf.ba = cxform->ba * e->cxform->ba;
+ cxf.aa = cxform->aa * e->cxform->aa;
+
+ cxf.rb = (long)(cxform->ra * e->cxform->rb + cxform->rb);
+ cxf.gb = (long)(cxform->ga * e->cxform->gb + cxform->gb);
+ cxf.bb = (long)(cxform->ba * e->cxform->bb + cxform->bb);
+ cxf.ab = (long)(cxform->aa * e->cxform->ab + cxform->ab);
+ }
+
+ if (e->character->isButton()) {
+ Button *b = (Button *) e->character;
+
+ e->renderMatrix = mat;
+
+ if (e->renderState != stateUp && movie->mouse_active == 0) {
+ cur_focus = e;
+ ((Button *)e->character)->updateButtonState(e);
+ }
+
+ if (b->execute(gd, &mat, cxf1, e->renderState)) {
+ sprite = 1;
+ }
+ } else {
+ if (e->character->execute(gd, &mat, cxf1)) {
+ sprite = 1;
+ }
+ }
+
+ n++;
+ }
+ }
+
+#if 0
+ {
+ /* display the bounding box (debug) */
+ Matrix tmat;
+ long x1,x2,y1,y2;
+ Color white;
+
+ white.red = 255;
+ white.green = white.blue = 0;
+ gd->setForegroundColor(white);
+
+ if (render_matrix) {
+ tmat = (*gd->adjust) * (*render_matrix);
+ } else {
+ tmat = *gd->adjust;
+ }
+ x1 = bbox.xmin;
+ y1 = bbox.ymin;
+ x2 = bbox.xmax;
+ y2 = bbox.ymax;
+ gd->drawLine(tmat.getX(x1,y1),tmat.getY(x1,y1),tmat.getX(x2,y1),tmat.getY(x2,y1),10*FRAC);
+ gd->drawLine(tmat.getX(x2,y1),tmat.getY(x2,y1),tmat.getX(x2,y2),tmat.getY(x2,y2),10*FRAC);
+ gd->drawLine(tmat.getX(x2,y2),tmat.getY(x2,y2),tmat.getX(x1,y2),tmat.getY(x1,y2),10*FRAC);
+ gd->drawLine(tmat.getX(x1,y2),tmat.getY(x1,y2),tmat.getX(x1,y1),tmat.getY(x1,y1),10*FRAC);
+ bbox.print();
+ }
+#endif
+
+ // Reset clipping zone
+ bbox.reset();
+
+ return sprite;
+}
+
+void
+DisplayList::getBoundary(Rect *bb)
+{
+ DisplayListEntry *e;
+ Rect boundary;
+
+ bb->reset();
+ for (e = list; e; e = e->next)
+ {
+ if (e->character) {
+ e->character->getBoundingBox(&boundary,e);
+ transformBoundingBox(bb, e->matrix, &boundary, 0);
+ }
+ }
+}
+
+extern "C" {
+
+void dump_buttons(FlashHandle flashHandle)
+{
+#if 0
+ Rect rect;
+ DisplayListEntry *e;
+ FlashMovie *movie;
+
+ movie = (FlashMovie *)flashHandle;
+
+ for (e = movie->first_button; e; e = e->next_button) {
+ computeBBox(movie,&rect,e);
+ printf("button: id=%d pos=%d %d %d %d\n",
+ e->character->getTagId(),
+ rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+ }
+#endif
+}
+
+}