summaryrefslogtreecommitdiff
path: root/core/multimedia/opieplayer/libflash/shape.cc
Side-by-side diff
Diffstat (limited to 'core/multimedia/opieplayer/libflash/shape.cc') (more/less context) (ignore whitespace changes)
-rw-r--r--core/multimedia/opieplayer/libflash/shape.cc1205
1 files changed, 1205 insertions, 0 deletions
diff --git a/core/multimedia/opieplayer/libflash/shape.cc b/core/multimedia/opieplayer/libflash/shape.cc
new file mode 100644
index 0000000..0d8df93
--- a/dev/null
+++ b/core/multimedia/opieplayer/libflash/shape.cc
@@ -0,0 +1,1205 @@
+/////////////////////////////////////////////////////////////
+// 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
+
+#define ABS(v) ((v) < 0 ? -(v) : (v))
+
+static void prepareStyles(GraphicDevice *gd, Matrix *matrix, Cxform *cxform, FillStyleDef *f, long n);
+
+static void clearStyles(GraphicDevice *gd, FillStyleDef *f, long n);
+
+static void drawShape(GraphicDevice *gd, Matrix *matrix1, Cxform *cxform, Shape *shape,
+ ShapeAction shapeAction, void *id,ScanLineFunc scan_line_func);
+
+// Constructor
+
+Shape::Shape(long id, int level) : Character(ShapeType, id)
+{
+ defLevel = level;
+
+ defaultFillStyle.type = f_Solid;
+ defaultFillStyle.color.red = 0;
+ defaultFillStyle.color.green = 0;
+ defaultFillStyle.color.blue = 0;
+ defaultFillStyle.color.alpha = ALPHA_OPAQUE;
+
+ defaultLineStyle.width = 0;
+
+ // This is to force a first update
+ lastMat.a = 0;
+ lastMat.d = 0;
+ shape_size += sizeof(Shape);
+ shape_nb ++;
+
+ file_ptr = NULL;
+ getStyles = 0;
+ getAlpha = 0;
+}
+
+Shape::~Shape()
+{
+ if (file_ptr) {
+ free(file_ptr);
+ }
+}
+
+void
+Shape::setBoundingBox(Rect rect)
+{
+ boundary = rect;
+}
+
+void
+Shape::getBoundingBox(Rect *bb, DisplayListEntry *e)
+{
+ *bb = boundary;
+}
+
+int
+Shape::execute(GraphicDevice *gd, Matrix *matrix, Cxform *cxform)
+{
+ //printf("TagId = %d\n", getTagId());
+ //if (getTagId() != 220) return 0;
+
+ if (cxform) {
+ defaultFillStyle.color = cxform->getColor(gd->getForegroundColor());
+ } else {
+ defaultFillStyle.color = gd->getForegroundColor();
+ }
+ defaultFillStyle.color.pixel = gd->allocColor(defaultFillStyle.color);
+
+ drawShape(gd, matrix, cxform, this, ShapeDraw, NULL, 0);
+ return 0;
+}
+
+void
+Shape::getRegion(GraphicDevice *gd, Matrix *matrix, void *id, ScanLineFunc scan_line_func)
+{
+ gd->setClipping(0);
+ drawShape(gd,matrix,0,this,ShapeGetRegion,id,scan_line_func);
+ gd->setClipping(1);
+}
+
+/************************************************************************/
+
+/* create a new path */
+
+static void newPath(ShapeParser *shape,
+ long x, long y)
+{
+ Path *p;
+ long x1,y1;
+
+ p=&shape->curPath;
+
+ x1 = shape->matrix->getX(x, y);
+ y1 = shape->matrix->getY(x, y);
+
+ p->lastX = x1;
+ p->lastY = y1;
+
+ p->nb_edges = 0;
+ p->nb_segments = 0;
+}
+
+
+static void addSegment1(ShapeParser *shape,
+ long x, long y,
+ FillStyleDef *f0,
+ FillStyleDef *f1,
+ LineStyleDef *l)
+{
+ Path *p;
+ p=&shape->curPath;
+
+ if (l) {
+ /* a line is defined ... it will be drawn later */
+ LineSegment *ls;
+
+ ls = new LineSegment;
+ if (ls != NULL) {
+ ls->l = l;
+ ls->x1 = p->lastX;
+ ls->y1 = p->lastY;
+ ls->x2 = x;
+ ls->y2 = y;
+ ls->first = (p->nb_segments == 0);
+ ls->next = NULL;
+ if (shape->last_line == NULL) {
+ shape->first_line = ls;
+ } else {
+ shape->last_line->next = ls;
+ }
+ shape->last_line = ls;
+ }
+ }
+
+ /* anti antialiasing not needed if line */
+ if (!shape->reverse) {
+ shape->gd->addSegment(p->lastX,p->lastY,x,y,f0,f1,l ? 0 : 1);
+ } else {
+ shape->gd->addSegment(p->lastX,p->lastY,x,y,f1,f0,l ? 0 : 1);
+ }
+
+ p->lastX = x;
+ p->lastY = y;
+
+ p->nb_segments++;
+}
+
+
+static void addLine(ShapeParser *shape, long x, long y,
+ FillStyleDef *f0,
+ FillStyleDef *f1,
+ LineStyleDef *l)
+{
+ long x1,y1;
+ Path *p;
+
+ p=&shape->curPath;
+
+ x1 = shape->matrix->getX(x, y);
+ y1 = shape->matrix->getY(x, y);
+
+ addSegment1(shape,x1,y1,f0,f1,l);
+
+ p->nb_edges++;
+}
+
+
+// This is based on Divide and Conquer algorithm.
+
+#define BFRAC_BITS 0
+#define BFRAC (1 << BFRAC_BITS)
+
+static void
+bezierBuildPoints (ShapeParser *s,
+ int subdivisions,
+ long a1X, long a1Y,
+ long cX, long cY,
+ long a2X, long a2Y)
+{
+ long c1X,c1Y;
+ long c2X,c2Y;
+ long X,Y;
+ long xmin,ymin,xmax,ymax;
+
+ if (subdivisions != 0) {
+
+ /* find the bounding box */
+
+ if (a1X < cX) {
+ xmin = a1X;
+ xmax = cX;
+ } else {
+ xmin = cX;
+ xmax = a1X;
+ }
+ if (a2X < xmin) xmin = a2X;
+ if (a2X > xmax) xmax = a2X;
+
+ if (a1Y < cY) {
+ ymin = a1Y;
+ ymax = cY;
+ } else {
+ ymin = cY;
+ ymax = a1Y;
+ }
+ if (a2Y < ymin) ymin = a2Y;
+ if (a2Y > ymax) ymax = a2Y;
+
+ if (((xmax - xmin) + (ymax - ymin)) >= (BFRAC*FRAC*2)) {
+ // Control point 1
+ c1X = (a1X+cX) >> 1;
+ c1Y = (a1Y+cY) >> 1;
+
+ // Control point 2
+ c2X = (a2X+cX) >> 1;
+ c2Y = (a2Y+cY) >> 1;
+
+ // New point
+ X = (c1X+c2X) >> 1;
+ Y = (c1Y+c2Y) >> 1;
+
+ subdivisions--;
+
+ bezierBuildPoints(s, subdivisions,
+ a1X, a1Y, c1X, c1Y, X, Y);
+ bezierBuildPoints(s, subdivisions,
+ X, Y, c2X, c2Y, a2X, a2Y);
+
+ return;
+ }
+ }
+
+ addSegment1(s, (a2X+(BFRAC/2)) >> BFRAC_BITS,
+ (a2Y+(BFRAC/2)) >> BFRAC_BITS, s->f0, s->f1, s->l);
+}
+
+/* this code is broken, but useful to get something */
+static void flushPaths(ShapeParser *s)
+{
+ LineSegment *ls;
+ LineStyleDef *l;
+ long nx,ny,nn,w;
+ GraphicDevice *gd = s->gd;
+
+ /* draw the filled polygon */
+ gd->drawPolygon();
+
+ /* draw the lines */
+ ls = s->first_line;
+ if (ls != NULL) {
+ do {
+ l = ls->l;
+
+#if 0
+ printf("line %d %d %d %d width=%d\n",
+ ls->x1, ls->y1, ls->x2, ls->y2, l->width);
+#endif
+
+ /* XXX: this width is false, but it is difficult (and expensive)
+ to have the correct one */
+ w = ABS((long)(s->matrix->a * l->width));
+
+ if (w <= ((3*FRAC)/2)) {
+ w = FRAC;
+ }
+#ifdef THIN_LINES
+ if (w <= ((3*FRAC)/2)) {
+ // draw the thin lines only in shapeAction == shapeDraw
+ if (gd->scan_line_func == NULL) {
+ gd->setForegroundColor(l->fillstyle.color);
+ gd->drawLine(ls->x1, ls->y1, ls->x2, ls->y2, w);
+ }
+ } else {
+#else
+ {
+#endif
+ /* compute the normal vector */
+
+ nx = -(ls->y2 - ls->y1);
+ ny = (ls->x2 - ls->x1);
+
+ /* normalize & width */
+ nn = 2 * (long) sqrt(nx * nx + ny * ny);
+
+#define UL ls->x1 + nx -ny, ls->y1 + ny +nx
+#define UR ls->x2 + nx +ny, ls->y2 + ny -nx
+#define LL ls->x1 - nx -ny, ls->y1 - ny +nx
+#define LR ls->x2 - nx +ny, ls->y2 - ny -nx
+
+ if (nn > 0) {
+ nx = (nx * w) / nn;
+ ny = (ny * w) / nn;
+
+ /* top segment */
+ gd->addSegment(UL, UR, NULL, &l->fillstyle, 1);
+
+ /* bottom segment */
+ gd->addSegment(LL, LR, &l->fillstyle, NULL, 1);
+
+ /* right segment */
+ gd->addSegment(UR, LR, &l->fillstyle, NULL, 1);
+
+ /* left segment */
+ gd->addSegment(UL, LL, NULL, &l->fillstyle, 1);
+
+ /* draw the line polygon */
+ gd->drawPolygon();
+ }
+ }
+
+ ls = ls->next;
+ } while (ls != NULL);
+
+ /* delete the line structures */
+
+ ls = s->first_line;
+ while (ls != NULL) {
+ LineSegment *ls1;
+ ls1 = ls->next;
+ delete ls;
+ ls = ls1;
+ }
+
+ /* reset the line pointers */
+ s->first_line = NULL;
+ s->last_line = NULL;
+ }
+}
+
+
+static void addBezier(ShapeParser *shape,
+ long ctrlX1, long ctrlY1,
+ long newX1, long newY1,
+ FillStyleDef *f0,
+ FillStyleDef *f1,
+ LineStyleDef *l)
+{
+ long newX,newY,ctrlX,ctrlY;
+ Path *p;
+
+ p=&shape->curPath;
+
+ /* note: we do the matrix multiplication before calculating the
+ bezier points (faster !) */
+
+ ctrlX = shape->matrix->getX(ctrlX1, ctrlY1);
+ ctrlY = shape->matrix->getY(ctrlX1, ctrlY1);
+ newX = shape->matrix->getX(newX1, newY1);
+ newY = shape->matrix->getY(newX1, newY1);
+
+ shape->f0 = f0;
+ shape->f1 = f1;
+ shape->l = l;
+
+ bezierBuildPoints(shape, 3,
+ p->lastX<<BFRAC_BITS,p->lastY<<BFRAC_BITS,
+ ctrlX<<BFRAC_BITS,ctrlY<<BFRAC_BITS,
+ newX<<BFRAC_BITS,newY<<BFRAC_BITS);
+
+ p->nb_edges++;
+}
+
+/***********************************************************************/
+
+
+/* bit parser */
+
+static void InitBitParser(struct BitParser *b,U8 *buf)
+{
+ b->ptr = buf;
+}
+
+static void InitBits(struct BitParser *b)
+{
+ // Reset the bit position and buffer.
+ b->m_bitPos = 0;
+ b->m_bitBuf = 0;
+}
+
+
+
+static inline U8 GetByte(struct BitParser *b)
+{
+ U8 v;
+ v = *b->ptr++;
+ return v;
+}
+
+static inline U16 GetWord(struct BitParser *b)
+{
+ U8 *s;
+ U16 v;
+ s = b->ptr;
+ v = s[0] | ((U16) s[1] << 8);
+ b->ptr = s + 2;
+ return v;
+}
+
+static inline U32 GetDWord(struct BitParser *b)
+{
+ U32 v;
+ U8 * s = b->ptr;
+ v = (U32) s[0] | ((U32) s[1] << 8) |
+ ((U32) s[2] << 16) | ((U32) s [3] << 24);
+ b->ptr = s + 4;
+ return v;
+}
+
+static inline U32 GetBit (struct BitParser *b)
+{
+ U32 v;
+ S32 m_bitPos = b->m_bitPos;
+ U32 m_bitBuf = b->m_bitBuf;
+
+ if (m_bitPos == 0) {
+ m_bitBuf = (U32)(*b->ptr++) << 24;
+ m_bitPos = 8;
+ }
+
+ v = (m_bitBuf >> 31);
+
+ m_bitPos--;
+ m_bitBuf <<= 1;
+
+ b->m_bitPos = m_bitPos;
+ b->m_bitBuf = m_bitBuf;
+
+ return v;
+}
+
+static inline U32 GetBits (struct BitParser *b, int n)
+{
+ U32 v;
+ S32 m_bitPos = b->m_bitPos;
+ U32 m_bitBuf = b->m_bitBuf;
+
+ if (n == 0)
+ return 0;
+
+ while (m_bitPos < n) {
+ m_bitBuf |= (U32)(*b->ptr++) << (24 - m_bitPos);
+ m_bitPos += 8;
+ }
+
+ v = m_bitBuf >> (32 - n);
+ m_bitBuf <<= n;
+ m_bitPos -= n;
+
+ b->m_bitPos = m_bitPos;
+ b->m_bitBuf = m_bitBuf;
+ return v;
+}
+
+// Get n bits from the string with sign extension.
+static inline S32 GetSBits (struct BitParser *b,S32 n)
+{
+ // Get the number as an unsigned value.
+ S32 v = (S32) GetBits(b,n);
+
+ // Is the number negative?
+ if (v & (1L << (n - 1)))
+ {
+ // Yes. Extend the sign.
+ v |= -1L << n;
+ }
+
+ return v;
+}
+
+
+
+/************************************************************************/
+
+static void GetMatrix(BitParser *b, Matrix* mat)
+{
+ InitBits(b);
+
+ // Scale terms
+ if (GetBit(b))
+ {
+ int nBits = (int) GetBits(b,5);
+ mat->a = (float)(GetSBits(b,nBits))/(float)0x10000;
+ mat->d = (float)(GetSBits(b,nBits))/(float)0x10000;
+ }
+ else
+ {
+ mat->a = mat->d = 1.0;
+ }
+
+ // Rotate/skew terms
+ if (GetBit(b))
+ {
+ int nBits = (int)GetBits(b,5);
+ mat->c = (float)(GetSBits(b,nBits))/(float)0x10000;
+ mat->b = (float)(GetSBits(b,nBits))/(float)0x10000;
+ }
+ else
+ {
+ mat->b = mat->c = 0.0;
+ }
+
+ // Translate terms
+ int nBits = (int) GetBits(b,5);
+ mat->tx = GetSBits(b,nBits);
+ mat->ty = GetSBits(b,nBits);
+}
+
+static FillStyleDef * ParseFillStyle(ShapeParser *shape, long *n, long getAlpha)
+{
+ BitParser *b = &shape->bit_parser;
+ FillStyleDef *defs;
+ U16 i = 0;
+
+ // Get the number of fills.
+ U16 nFills = GetByte(b);
+
+ // Do we have a larger number?
+ if (nFills == 255)
+ {
+ // Get the larger number.
+ nFills = GetWord(b);
+ }
+
+ *n = nFills;
+ defs = new FillStyleDef[ nFills ];
+ if (defs == NULL) return NULL;
+
+ // Get each of the fill style.
+ for (i = 0; i < nFills; i++)
+ {
+ U16 fillStyle = GetByte(b);
+
+ defs[i].type = (FillType) fillStyle;
+
+ if (fillStyle & 0x10)
+ {
+ defs[i].type = (FillType) (fillStyle & 0x12);
+
+ // Get the gradient matrix.
+ GetMatrix(b,&(defs[i].matrix));
+
+ // Get the number of colors.
+ defs[i].gradient.nbGradients = GetByte(b);
+
+ // Get each of the colors.
+ for (U16 j = 0; j < defs[i].gradient.nbGradients; j++)
+ {
+ defs[i].gradient.ratio[j] = GetByte(b);
+ defs[i].gradient.color[j].red = GetByte(b);
+ defs[i].gradient.color[j].green = GetByte(b);
+ defs[i].gradient.color[j].blue = GetByte(b);
+ if (getAlpha) {
+ defs[i].gradient.color[j].alpha = GetByte(b);
+ } else {
+ defs[i].gradient.color[j].alpha = ALPHA_OPAQUE;
+ }
+ }
+ }
+ else if (fillStyle & 0x40)
+ {
+ defs[i].type = (FillType) (fillStyle & 0x41);
+
+ // Get the bitmapId
+ defs[i].bitmap = (Bitmap *)shape->dict->getCharacter(GetWord(b));
+ // Get the bitmap matrix.
+ GetMatrix(b,&(defs[i].matrix));
+ }
+ else
+ {
+ defs[i].type = (FillType) 0;
+
+ // A solid color
+ defs[i].color.red = GetByte(b);
+ defs[i].color.green = GetByte(b);
+ defs[i].color.blue = GetByte(b);
+ if (getAlpha) {
+ defs[i].color.alpha = GetByte(b);
+ } else {
+ defs[i].color.alpha = ALPHA_OPAQUE;
+ }
+ }
+ }
+
+ return defs;
+}
+
+static LineStyleDef * ParseLineStyle(ShapeParser *shape, long *n, long getAlpha)
+{
+ BitParser *b = &shape->bit_parser;
+ LineStyleDef *defs,*def;
+ FillStyleDef *f;
+ long i;
+
+ // Get the number of lines.
+ U16 nLines = GetByte(b);
+
+ // Do we have a larger number?
+ if (nLines == 255)
+ {
+ // Get the larger number.
+ nLines = GetWord(b);
+ }
+
+ *n = nLines;
+ defs = new LineStyleDef[ nLines ];
+ if (defs == NULL) return NULL;
+
+ // Get each of the line styles.
+ for (i = 0; i < nLines; i++)
+ {
+ def=&defs[i];
+ def->width = GetWord(b);
+ def->color.red = GetByte(b);
+ def->color.green = GetByte(b);
+ def->color.blue = GetByte(b);
+ if (getAlpha) {
+ def->color.alpha = GetByte(b);
+ } else {
+ def->color.alpha = ALPHA_OPAQUE;
+ }
+
+ f=&def->fillstyle;
+ f->type = f_Solid;
+ f->color = def->color;
+ if (shape->cxform) {
+ f->color = shape->cxform->getColor(f->color);
+ }
+ f->color.pixel = shape->gd->allocColor(f->color);
+ }
+
+ return defs;
+}
+
+/* 0 = end of shape */
+static int ParseShapeRecord(ShapeParser *shape, ShapeRecord *sr, long getAlpha)
+{
+ BitParser *b = &shape->bit_parser;
+
+ // Determine if this is an edge.
+ BOOL isEdge = (BOOL) GetBit(b);
+
+ if (!isEdge)
+ {
+ // Handle a state change
+ U16 flags = (U16) GetBits(b,5);
+
+ // Are we at the end?
+ if (flags == 0)
+ {
+ // End of shape
+ return 0;
+ }
+
+ sr->type = shapeNonEdge;
+ sr->flags = (ShapeFlags)flags;
+
+ // Process a move to.
+ if (flags & flagsMoveTo)
+ {
+ U16 nBits = (U16) GetBits(b,5);
+ sr->x = GetSBits(b,nBits);
+ sr->y = GetSBits(b,nBits);
+ }
+
+ // Get new fill info.
+ if (flags & flagsFill0)
+ {
+ sr->fillStyle0 = GetBits(b,shape->m_nFillBits);
+ }
+ if (flags & flagsFill1)
+ {
+ sr->fillStyle1 = GetBits(b,shape->m_nFillBits);
+ }
+
+ // Get new line info
+ if (flags & flagsLine)
+ {
+ sr->lineStyle = GetBits(b,shape->m_nLineBits);
+ }
+
+ // Check to get a new set of styles for a new shape layer.
+ if (flags & flagsNewStyles)
+ {
+ FillStyleDef *fillDefs;
+ LineStyleDef *lineDefs;
+ long n;
+
+ // Parse the style.
+ fillDefs = ParseFillStyle(shape, &n, getAlpha);
+ if (fillDefs == NULL) return 0;
+
+ sr->newFillStyles = fillDefs;
+ sr->nbNewFillStyles = n;
+
+ lineDefs = ParseLineStyle(shape, &n, getAlpha);
+ if (lineDefs == NULL) return 0;
+
+ sr->newLineStyles = lineDefs;
+ sr->nbNewLineStyles = n;
+
+ InitBits(b); // Bug !
+
+ // Reset.
+ shape->m_nFillBits = (U16) GetBits(b,4);
+ shape->m_nLineBits = (U16) GetBits(b,4);
+ }
+
+ //if (flags & flagsEndShape)
+ //printf("\tEnd of shape.\n\n");
+
+ return flags & flagsEndShape ? 0 : 1;
+ }
+ else
+ {
+ if (GetBit(b))
+ {
+ sr->type = shapeLine;
+
+ // Handle a line
+ U16 nBits = (U16) GetBits(b,4) + 2; // nBits is biased by 2
+
+ // Save the deltas
+ if (GetBit(b))
+ {
+ // Handle a general line.
+ sr->dX = GetSBits(b,nBits);
+ sr->dY = GetSBits(b,nBits);
+ }
+ else
+ {
+ // Handle a vert or horiz line.
+ if (GetBit(b))
+ {
+ // Vertical line
+ sr->dY = GetSBits(b,nBits);
+ sr->dX = 0;
+ }
+ else
+ {
+ // Horizontal line
+ sr->dX = GetSBits(b,nBits);
+ sr->dY = 0;
+ }
+ }
+ }
+ else
+ {
+ sr->type = shapeCurve;
+
+ // Handle a curve
+ U16 nBits = (U16) GetBits(b,4) + 2; // nBits is biased by 2
+
+ // Get the control
+ sr->ctrlX = GetSBits(b,nBits);
+ sr->ctrlY = GetSBits(b,nBits);
+
+ // Get the anchor
+ sr->anchorX = GetSBits(b,nBits);
+ sr->anchorY = GetSBits(b,nBits);
+ }
+
+ return 1;
+ }
+}
+
+static void drawShape(GraphicDevice *gd, Matrix *matrix1, Cxform *cxform, Shape *shape,
+ ShapeAction shapeAction, void *id,ScanLineFunc scan_line_func)
+{
+ LineStyleDef *l;
+ FillStyleDef *f0;
+ FillStyleDef *f1;
+ ShapeRecord sr1,*sr = &sr1;
+ int firstPoint;
+ long lastX,lastY;
+ LineStyleDef *curLineStyle;
+ long curNbLineStyles;
+ FillStyleDef *curFillStyle;
+ long curNbFillStyles;
+ StyleList *sl;
+ ShapeParser sp1,*sp=&sp1;
+ BitParser *b;
+ Matrix mat,*matrix;
+
+ mat = (*gd->adjust) * (*matrix1);
+ matrix = &mat;
+
+ sp->reverse = (mat.a * mat.d) < 0;
+
+ curLineStyle = NULL;
+ curNbLineStyles = 0;
+ curFillStyle = NULL;
+ curNbFillStyles = 0;
+ sp->style_list = NULL;
+
+ sp->shape = shape;
+ sp->gd = gd;
+ sp->matrix = matrix;
+ sp->cxform = cxform;
+ sp->dict = shape->dict;
+
+ if (shapeAction == ShapeGetRegion) {
+ gd->scan_line_func = scan_line_func;
+ gd->scan_line_func_id = id;
+ } else {
+ gd->scan_line_func = NULL;
+ }
+
+ b = &sp->bit_parser;
+ InitBitParser(b,shape->file_ptr);
+
+ if (shape->getStyles) {
+ // ShapeWithStyle
+ curFillStyle = ParseFillStyle(sp, &curNbFillStyles, shape->getAlpha);
+ if (curFillStyle == NULL) return;
+
+ curLineStyle = ParseLineStyle(sp, &curNbLineStyles, shape->getAlpha);
+ if (curLineStyle == NULL) return;
+
+ sl = new StyleList;
+ if (sl == NULL) return;
+
+ sl->next = NULL;
+ sl->newFillStyles = curFillStyle;
+ sl->nbNewFillStyles = curNbFillStyles;
+ sl->newLineStyles = curLineStyle;
+ sl->nbNewLineStyles = curNbLineStyles;
+
+ sp->style_list = sl;
+
+ if (shapeAction == ShapeDraw) {
+ prepareStyles(gd, matrix, cxform, curFillStyle, curNbFillStyles);
+ }
+ }
+
+ InitBits(b);
+ sp->m_nFillBits = (U16) GetBits(b,4);
+ sp->m_nLineBits = (U16) GetBits(b,4);
+
+ l = 0;
+ f0 = 0;
+ f1 = 0;
+ firstPoint = 1;
+ lastX = 0;
+ lastY = 0;
+ sp->curPath.nb_edges = 0;
+ sp->first_line = NULL;
+ sp->last_line = NULL;
+
+ for(;;) {
+ if (ParseShapeRecord(sp, sr, shape->getAlpha) == 0) break;
+
+ switch (sr->type)
+ {
+ case shapeNonEdge:
+ if (sr->flags & flagsNewStyles) {
+
+ curFillStyle = sr->newFillStyles;
+ curNbFillStyles = sr->nbNewFillStyles;
+ curLineStyle = sr->newLineStyles;
+ curNbLineStyles = sr->nbNewLineStyles;
+
+ sl = new StyleList;
+ sl->next = sp->style_list;
+ sl->newFillStyles = sr->newFillStyles;
+ sl->nbNewFillStyles = sr->nbNewFillStyles;
+ sl->newLineStyles = sr->newLineStyles;
+ sl->nbNewLineStyles = sr->nbNewLineStyles;
+
+ sp->style_list = sl;
+
+ if (shapeAction == ShapeDraw) {
+ prepareStyles(gd, matrix, cxform, curFillStyle, curNbFillStyles);
+ }
+ }
+ if (sr->flags & flagsFill0) {
+ if (sr->fillStyle0) {
+ if (curFillStyle) {
+ f0 = &curFillStyle[sr->fillStyle0-1];
+ } else {
+ f0 = &shape->defaultFillStyle;
+ }
+ } else {
+ f0 = 0;
+ }
+ }
+ if (sr->flags & flagsFill1) {
+ if (sr->fillStyle1) {
+ if (curFillStyle) {
+ f1 = &curFillStyle[sr->fillStyle1-1];
+ } else {
+ f1 = &shape->defaultFillStyle;
+ }
+ } else {
+ f1 = 0;
+ }
+ }
+ if (sr->flags & flagsLine) {
+ if (sr->lineStyle) {
+ l = &curLineStyle[sr->lineStyle-1];
+ } else {
+ l = 0;
+ }
+ }
+ if (sr->flags & flagsMoveTo) {
+ if (sp->curPath.nb_edges == 0) {
+ /* if no edges, draw the polygon, then the lines */
+ flushPaths(sp);
+ }
+
+ newPath(sp, sr->x, sr->y);
+ firstPoint = 0;
+
+ lastX = sr->x;
+ lastY = sr->y;
+
+#if PRINT
+ printf("---------\nX,Y = %4d,%4d\n", sr->x/20, sr->y/20);
+#endif
+ }
+ break;
+ case shapeCurve:
+ // Handle Bezier Curves !!!
+ if (firstPoint) {
+ newPath(sp, 0, 0);
+ firstPoint = 0;
+ }
+ {
+ long newX,newY,ctrlX,ctrlY;
+
+ ctrlX = lastX+sr->ctrlX;
+ ctrlY = lastY+sr->ctrlY;
+ newX = ctrlX+sr->anchorX;
+ newY = ctrlY+sr->anchorY;
+
+#if 1
+ addBezier(sp, ctrlX, ctrlY, newX, newY, f0 , f1, l);
+#else
+ addLine(sp, newX, newY, f0, f1, l);
+#endif
+
+ lastX = newX;
+ lastY = newY;
+ }
+ break;
+ case shapeLine:
+ if (firstPoint) {
+ newPath(sp, 0, 0);
+ firstPoint = 0;
+ }
+
+ lastX += sr->dX;
+ lastY += sr->dY;
+
+ addLine(sp, lastX, lastY, f0, f1, l);
+#if PRINT
+ printf(" X, Y = %4d,%4d\n", lastX/20, lastY/20);
+#endif
+ break;
+ }
+ }
+
+ /* XXX: should test if there is something to draw */
+ flushPaths(sp);
+
+ /* free the styles */
+ while (sp->style_list) {
+ StyleList *sl;
+
+ sl=sp->style_list;
+ sp->style_list = sl->next;
+
+ if (shapeAction == ShapeDraw) {
+ clearStyles(gd, sl->newFillStyles, sl->nbNewFillStyles);
+ }
+
+ delete[] sl->newFillStyles;
+ delete[] sl->newLineStyles;
+
+ delete sl;
+ }
+}
+
+static void
+prepareStyles(GraphicDevice *gd, Matrix *matrix, Cxform *cxform,
+ FillStyleDef *ftab, long n)
+{
+ long fs;
+ FillStyleDef *f;
+
+ for(fs = 0; fs < n; fs++)
+ {
+ f = ftab + fs;
+ switch (f->type)
+ {
+ case f_None:
+ break;
+ case f_Solid:
+ if (cxform) {
+ f->color = cxform->getColor(f->color);
+ }
+ f->color.pixel = gd->allocColor(f->color);
+ break;
+ case f_LinearGradient:
+ case f_RadialGradient:
+ {
+ Matrix mat;
+ int n,r,l;
+ long red, green, blue, alpha;
+ long dRed, dGreen, dBlue, dAlpha;
+ long min,max;
+ Matrix *m;
+
+ mat = *(matrix) * f->matrix;
+ // Compute inverted matrix
+ f->gradient.imat = mat.invert();
+
+ /* renormalize the matrix */
+ m=&f->gradient.imat;
+ if (f->type == f_LinearGradient) {
+ m->a = m->a * FRAC * (1/128.0) * 65536.0;
+ m->b = m->b * FRAC * (1/128.0) * 65536.0;
+ m->tx = (long) ((m->tx + 16384) * (1/128.0) * 65536.0);
+ } else {
+ m->a = m->a * FRAC * (1/64.0) * 65536.0;
+ m->b = m->b * FRAC * (1/64.0) * 65536.0;
+ m->c = m->c * FRAC * (1/64.0) * 65536.0;
+ m->d = m->d * FRAC * (1/64.0) * 65536.0;
+ m->tx = (long) (m->tx * (1/64.0) * 65536.0);
+ m->ty = (long) (m->ty * (1/64.0) * 65536.0);
+ }
+
+ // Reset translation in inverted matrix
+ f->gradient.has_alpha = 0;
+
+ // Build a 256 color ramp
+ f->gradient.ramp = new Color[256];
+ if (f->gradient.ramp == NULL) {
+ // Invalidate fill style
+ f->type = f_None;
+ continue;
+ }
+
+ // Store min and max
+ min = f->gradient.ratio[0];
+ max = f->gradient.ratio[f->gradient.nbGradients-1];
+ for(r=0; r < f->gradient.nbGradients-1; r++)
+ {
+ Color start,end;
+
+ l = f->gradient.ratio[r+1]-f->gradient.ratio[r];
+ if (l == 0) continue;
+
+ if (cxform) {
+ start = cxform->getColor(f->gradient.color[r]);
+ end = cxform->getColor(f->gradient.color[r+1]);
+ } else {
+ start = f->gradient.color[r];
+ end = f->gradient.color[r+1];
+ }
+
+ if (start.alpha != ALPHA_OPAQUE ||
+ end.alpha != ALPHA_OPAQUE) {
+ f->gradient.has_alpha = 1;
+ }
+
+ dRed = end.red - start.red;
+ dGreen = end.green - start.green;
+ dBlue = end.blue - start.blue;
+ dAlpha = end.alpha - start.alpha;
+
+ dRed = (dRed<<16)/l;
+ dGreen = (dGreen<<16)/l;
+ dBlue = (dBlue<<16)/l;
+ dAlpha = (dAlpha<<16)/l;
+
+ red = start.red <<16;
+ green = start.green <<16;
+ blue = start.blue <<16;
+ alpha = start.alpha <<16;
+
+ for (n=f->gradient.ratio[r]; n<=f->gradient.ratio[r+1]; n++) {
+ f->gradient.ramp[n].red = red>>16;
+ f->gradient.ramp[n].green = green>>16;
+ f->gradient.ramp[n].blue = blue>>16;
+ f->gradient.ramp[n].alpha = alpha>>16;
+
+ f->gradient.ramp[n].pixel = gd->allocColor(f->gradient.ramp[n]);
+ red += dRed;
+ green += dGreen;
+ blue += dBlue;
+ alpha += dAlpha;
+ }
+ }
+ for(n=0; n<min; n++) {
+ f->gradient.ramp[n] = f->gradient.ramp[min];
+ }
+ for(n=max; n<256; n++) {
+ f->gradient.ramp[n] = f->gradient.ramp[max];
+ }
+ }
+ break;
+ case f_TiledBitmap:
+ case f_clippedBitmap:
+ if (f->bitmap) {
+ Matrix *m;
+
+ f->cmap = gd->getColormap(f->bitmap->colormap,
+ f->bitmap->nbColors, cxform);
+ if (f->cmap == NULL) {
+ /* Get the normal cmap anyway */
+ f->cmap = f->bitmap->colormap;
+ }
+
+ f->bitmap_matrix = *(matrix) * f->matrix;
+
+ f->bitmap_matrix = f->bitmap_matrix.invert();
+
+ m=&f->bitmap_matrix;
+ m->a = m->a * FRAC * 65536.0;
+ m->b = m->b * FRAC * 65536.0;
+ m->c = m->c * FRAC * 65536.0;
+ m->d = m->d * FRAC * 65536.0;
+ m->tx = (long) (m->tx * 65536.0);
+ m->ty = (long) (m->ty * 65536.0);
+
+ f->alpha_table = NULL;
+
+ if (f->bitmap->alpha_buf && cxform) {
+ unsigned char *alpha_table;
+ int i;
+
+ alpha_table = (unsigned char *)malloc (256);
+ if (alpha_table != NULL) {
+ for(i=0;i<256;i++) {
+ alpha_table[i] = cxform->getAlpha(i);
+ }
+ }
+ f->alpha_table = alpha_table;
+ }
+ }
+ break;
+ }
+ }
+}
+
+static void
+clearStyles(GraphicDevice *gd, FillStyleDef *ftab, long n)
+{
+ long fs;
+ FillStyleDef *f;
+
+ for(fs = 0; fs < n; fs++)
+ {
+ f = ftab + fs;
+ switch (f->type)
+ {
+ case f_Solid:
+ break;
+ case f_LinearGradient:
+ case f_RadialGradient:
+ if (f->gradient.ramp) {
+ delete f->gradient.ramp;
+ }
+ break;
+ case f_TiledBitmap:
+ case f_clippedBitmap:
+ if (f->bitmap) {
+ if (f->cmap && f->cmap != f->bitmap->colormap) delete f->cmap;
+ if (f->alpha_table) free(f->alpha_table);
+ }
+ break;
+ case f_None:
+ break;
+ }
+ }
+}
+