Diffstat (limited to 'core/multimedia/opieplayer/libflash/shape.cc') (more/less context) (show whitespace changes)
-rw-r--r-- | core/multimedia/opieplayer/libflash/shape.cc | 1205 |
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 @@ | |||
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 | ||
26 | static char *rcsid = "$Id$"; | ||
27 | #endif | ||
28 | |||
29 | #define PRINT 0 | ||
30 | |||
31 | #define ABS(v) ((v) < 0 ? -(v) : (v)) | ||
32 | |||
33 | static void prepareStyles(GraphicDevice *gd, Matrix *matrix, Cxform *cxform, FillStyleDef *f, long n); | ||
34 | |||
35 | static void clearStyles(GraphicDevice *gd, FillStyleDef *f, long n); | ||
36 | |||
37 | static void drawShape(GraphicDevice *gd, Matrix *matrix1, Cxform *cxform, Shape *shape, | ||
38 | ShapeAction shapeAction, void *id,ScanLineFunc scan_line_func); | ||
39 | |||
40 | // Constructor | ||
41 | |||
42 | Shape::Shape(long id, int level) : Character(ShapeType, id) | ||
43 | { | ||
44 | defLevel = level; | ||
45 | |||
46 | defaultFillStyle.type = f_Solid; | ||
47 | defaultFillStyle.color.red = 0; | ||
48 | defaultFillStyle.color.green = 0; | ||
49 | defaultFillStyle.color.blue = 0; | ||
50 | defaultFillStyle.color.alpha = ALPHA_OPAQUE; | ||
51 | |||
52 | defaultLineStyle.width = 0; | ||
53 | |||
54 | // This is to force a first update | ||
55 | lastMat.a = 0; | ||
56 | lastMat.d = 0; | ||
57 | shape_size += sizeof(Shape); | ||
58 | shape_nb ++; | ||
59 | |||
60 | file_ptr = NULL; | ||
61 | getStyles = 0; | ||
62 | getAlpha = 0; | ||
63 | } | ||
64 | |||
65 | Shape::~Shape() | ||
66 | { | ||
67 | if (file_ptr) { | ||
68 | free(file_ptr); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | void | ||
73 | Shape::setBoundingBox(Rect rect) | ||
74 | { | ||
75 | boundary = rect; | ||
76 | } | ||
77 | |||
78 | void | ||
79 | Shape::getBoundingBox(Rect *bb, DisplayListEntry *e) | ||
80 | { | ||
81 | *bb = boundary; | ||
82 | } | ||
83 | |||
84 | int | ||
85 | Shape::execute(GraphicDevice *gd, Matrix *matrix, Cxform *cxform) | ||
86 | { | ||
87 | //printf("TagId = %d\n", getTagId()); | ||
88 | //if (getTagId() != 220) return 0; | ||
89 | |||
90 | if (cxform) { | ||
91 | defaultFillStyle.color = cxform->getColor(gd->getForegroundColor()); | ||
92 | } else { | ||
93 | defaultFillStyle.color = gd->getForegroundColor(); | ||
94 | } | ||
95 | defaultFillStyle.color.pixel = gd->allocColor(defaultFillStyle.color); | ||
96 | |||
97 | drawShape(gd, matrix, cxform, this, ShapeDraw, NULL, 0); | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | void | ||
102 | Shape::getRegion(GraphicDevice *gd, Matrix *matrix, void *id, ScanLineFunc scan_line_func) | ||
103 | { | ||
104 | gd->setClipping(0); | ||
105 | drawShape(gd,matrix,0,this,ShapeGetRegion,id,scan_line_func); | ||
106 | gd->setClipping(1); | ||
107 | } | ||
108 | |||
109 | /************************************************************************/ | ||
110 | |||
111 | /* create a new path */ | ||
112 | |||
113 | static void newPath(ShapeParser *shape, | ||
114 | long x, long y) | ||
115 | { | ||
116 | Path *p; | ||
117 | long x1,y1; | ||
118 | |||
119 | p=&shape->curPath; | ||
120 | |||
121 | x1 = shape->matrix->getX(x, y); | ||
122 | y1 = shape->matrix->getY(x, y); | ||
123 | |||
124 | p->lastX = x1; | ||
125 | p->lastY = y1; | ||
126 | |||
127 | p->nb_edges = 0; | ||
128 | p->nb_segments = 0; | ||
129 | } | ||
130 | |||
131 | |||
132 | static void addSegment1(ShapeParser *shape, | ||
133 | long x, long y, | ||
134 | FillStyleDef *f0, | ||
135 | FillStyleDef *f1, | ||
136 | LineStyleDef *l) | ||
137 | { | ||
138 | Path *p; | ||
139 | p=&shape->curPath; | ||
140 | |||
141 | if (l) { | ||
142 | /* a line is defined ... it will be drawn later */ | ||
143 | LineSegment *ls; | ||
144 | |||
145 | ls = new LineSegment; | ||
146 | if (ls != NULL) { | ||
147 | ls->l = l; | ||
148 | ls->x1 = p->lastX; | ||
149 | ls->y1 = p->lastY; | ||
150 | ls->x2 = x; | ||
151 | ls->y2 = y; | ||
152 | ls->first = (p->nb_segments == 0); | ||
153 | ls->next = NULL; | ||
154 | if (shape->last_line == NULL) { | ||
155 | shape->first_line = ls; | ||
156 | } else { | ||
157 | shape->last_line->next = ls; | ||
158 | } | ||
159 | shape->last_line = ls; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | /* anti antialiasing not needed if line */ | ||
164 | if (!shape->reverse) { | ||
165 | shape->gd->addSegment(p->lastX,p->lastY,x,y,f0,f1,l ? 0 : 1); | ||
166 | } else { | ||
167 | shape->gd->addSegment(p->lastX,p->lastY,x,y,f1,f0,l ? 0 : 1); | ||
168 | } | ||
169 | |||
170 | p->lastX = x; | ||
171 | p->lastY = y; | ||
172 | |||
173 | p->nb_segments++; | ||
174 | } | ||
175 | |||
176 | |||
177 | static void addLine(ShapeParser *shape, long x, long y, | ||
178 | FillStyleDef *f0, | ||
179 | FillStyleDef *f1, | ||
180 | LineStyleDef *l) | ||
181 | { | ||
182 | long x1,y1; | ||
183 | Path *p; | ||
184 | |||
185 | p=&shape->curPath; | ||
186 | |||
187 | x1 = shape->matrix->getX(x, y); | ||
188 | y1 = shape->matrix->getY(x, y); | ||
189 | |||
190 | addSegment1(shape,x1,y1,f0,f1,l); | ||
191 | |||
192 | p->nb_edges++; | ||
193 | } | ||
194 | |||
195 | |||
196 | // This is based on Divide and Conquer algorithm. | ||
197 | |||
198 | #define BFRAC_BITS 0 | ||
199 | #define BFRAC (1 << BFRAC_BITS) | ||
200 | |||
201 | static void | ||
202 | bezierBuildPoints (ShapeParser *s, | ||
203 | int subdivisions, | ||
204 | long a1X, long a1Y, | ||
205 | long cX, long cY, | ||
206 | long a2X, long a2Y) | ||
207 | { | ||
208 | long c1X,c1Y; | ||
209 | long c2X,c2Y; | ||
210 | long X,Y; | ||
211 | long xmin,ymin,xmax,ymax; | ||
212 | |||
213 | if (subdivisions != 0) { | ||
214 | |||
215 | /* find the bounding box */ | ||
216 | |||
217 | if (a1X < cX) { | ||
218 | xmin = a1X; | ||
219 | xmax = cX; | ||
220 | } else { | ||
221 | xmin = cX; | ||
222 | xmax = a1X; | ||
223 | } | ||
224 | if (a2X < xmin) xmin = a2X; | ||
225 | if (a2X > xmax) xmax = a2X; | ||
226 | |||
227 | if (a1Y < cY) { | ||
228 | ymin = a1Y; | ||
229 | ymax = cY; | ||
230 | } else { | ||
231 | ymin = cY; | ||
232 | ymax = a1Y; | ||
233 | } | ||
234 | if (a2Y < ymin) ymin = a2Y; | ||
235 | if (a2Y > ymax) ymax = a2Y; | ||
236 | |||
237 | if (((xmax - xmin) + (ymax - ymin)) >= (BFRAC*FRAC*2)) { | ||
238 | // Control point 1 | ||
239 | c1X = (a1X+cX) >> 1; | ||
240 | c1Y = (a1Y+cY) >> 1; | ||
241 | |||
242 | // Control point 2 | ||
243 | c2X = (a2X+cX) >> 1; | ||
244 | c2Y = (a2Y+cY) >> 1; | ||
245 | |||
246 | // New point | ||
247 | X = (c1X+c2X) >> 1; | ||
248 | Y = (c1Y+c2Y) >> 1; | ||
249 | |||
250 | subdivisions--; | ||
251 | |||
252 | bezierBuildPoints(s, subdivisions, | ||
253 | a1X, a1Y, c1X, c1Y, X, Y); | ||
254 | bezierBuildPoints(s, subdivisions, | ||
255 | X, Y, c2X, c2Y, a2X, a2Y); | ||
256 | |||
257 | return; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | addSegment1(s, (a2X+(BFRAC/2)) >> BFRAC_BITS, | ||
262 | (a2Y+(BFRAC/2)) >> BFRAC_BITS, s->f0, s->f1, s->l); | ||
263 | } | ||
264 | |||
265 | /* this code is broken, but useful to get something */ | ||
266 | static void flushPaths(ShapeParser *s) | ||
267 | { | ||
268 | LineSegment *ls; | ||
269 | LineStyleDef *l; | ||
270 | long nx,ny,nn,w; | ||
271 | GraphicDevice *gd = s->gd; | ||
272 | |||
273 | /* draw the filled polygon */ | ||
274 | gd->drawPolygon(); | ||
275 | |||
276 | /* draw the lines */ | ||
277 | ls = s->first_line; | ||
278 | if (ls != NULL) { | ||
279 | do { | ||
280 | l = ls->l; | ||
281 | |||
282 | #if 0 | ||
283 | printf("line %d %d %d %d width=%d\n", | ||
284 | ls->x1, ls->y1, ls->x2, ls->y2, l->width); | ||
285 | #endif | ||
286 | |||
287 | /* XXX: this width is false, but it is difficult (and expensive) | ||
288 | to have the correct one */ | ||
289 | w = ABS((long)(s->matrix->a * l->width)); | ||
290 | |||
291 | if (w <= ((3*FRAC)/2)) { | ||
292 | w = FRAC; | ||
293 | } | ||
294 | #ifdef THIN_LINES | ||
295 | if (w <= ((3*FRAC)/2)) { | ||
296 | // draw the thin lines only in shapeAction == shapeDraw | ||
297 | if (gd->scan_line_func == NULL) { | ||
298 | gd->setForegroundColor(l->fillstyle.color); | ||
299 | gd->drawLine(ls->x1, ls->y1, ls->x2, ls->y2, w); | ||
300 | } | ||
301 | } else { | ||
302 | #else | ||
303 | { | ||
304 | #endif | ||
305 | /* compute the normal vector */ | ||
306 | |||
307 | nx = -(ls->y2 - ls->y1); | ||
308 | ny = (ls->x2 - ls->x1); | ||
309 | |||
310 | /* normalize & width */ | ||
311 | nn = 2 * (long) sqrt(nx * nx + ny * ny); | ||
312 | |||
313 | #define UL ls->x1 + nx -ny, ls->y1 + ny +nx | ||
314 | #define UR ls->x2 + nx +ny, ls->y2 + ny -nx | ||
315 | #define LL ls->x1 - nx -ny, ls->y1 - ny +nx | ||
316 | #define LR ls->x2 - nx +ny, ls->y2 - ny -nx | ||
317 | |||
318 | if (nn > 0) { | ||
319 | nx = (nx * w) / nn; | ||
320 | ny = (ny * w) / nn; | ||
321 | |||
322 | /* top segment */ | ||
323 | gd->addSegment(UL, UR, NULL, &l->fillstyle, 1); | ||
324 | |||
325 | /* bottom segment */ | ||
326 | gd->addSegment(LL, LR, &l->fillstyle, NULL, 1); | ||
327 | |||
328 | /* right segment */ | ||
329 | gd->addSegment(UR, LR, &l->fillstyle, NULL, 1); | ||
330 | |||
331 | /* left segment */ | ||
332 | gd->addSegment(UL, LL, NULL, &l->fillstyle, 1); | ||
333 | |||
334 | /* draw the line polygon */ | ||
335 | gd->drawPolygon(); | ||
336 | } | ||
337 | } | ||
338 | |||
339 | ls = ls->next; | ||
340 | } while (ls != NULL); | ||
341 | |||
342 | /* delete the line structures */ | ||
343 | |||
344 | ls = s->first_line; | ||
345 | while (ls != NULL) { | ||
346 | LineSegment *ls1; | ||
347 | ls1 = ls->next; | ||
348 | delete ls; | ||
349 | ls = ls1; | ||
350 | } | ||
351 | |||
352 | /* reset the line pointers */ | ||
353 | s->first_line = NULL; | ||
354 | s->last_line = NULL; | ||
355 | } | ||
356 | } | ||
357 | |||
358 | |||
359 | static void addBezier(ShapeParser *shape, | ||
360 | long ctrlX1, long ctrlY1, | ||
361 | long newX1, long newY1, | ||
362 | FillStyleDef *f0, | ||
363 | FillStyleDef *f1, | ||
364 | LineStyleDef *l) | ||
365 | { | ||
366 | long newX,newY,ctrlX,ctrlY; | ||
367 | Path *p; | ||
368 | |||
369 | p=&shape->curPath; | ||
370 | |||
371 | /* note: we do the matrix multiplication before calculating the | ||
372 | bezier points (faster !) */ | ||
373 | |||
374 | ctrlX = shape->matrix->getX(ctrlX1, ctrlY1); | ||
375 | ctrlY = shape->matrix->getY(ctrlX1, ctrlY1); | ||
376 | newX = shape->matrix->getX(newX1, newY1); | ||
377 | newY = shape->matrix->getY(newX1, newY1); | ||
378 | |||
379 | shape->f0 = f0; | ||
380 | shape->f1 = f1; | ||
381 | shape->l = l; | ||
382 | |||
383 | bezierBuildPoints(shape, 3, | ||
384 | p->lastX<<BFRAC_BITS,p->lastY<<BFRAC_BITS, | ||
385 | ctrlX<<BFRAC_BITS,ctrlY<<BFRAC_BITS, | ||
386 | newX<<BFRAC_BITS,newY<<BFRAC_BITS); | ||
387 | |||
388 | p->nb_edges++; | ||
389 | } | ||
390 | |||
391 | /***********************************************************************/ | ||
392 | |||
393 | |||
394 | /* bit parser */ | ||
395 | |||
396 | static void InitBitParser(struct BitParser *b,U8 *buf) | ||
397 | { | ||
398 | b->ptr = buf; | ||
399 | } | ||
400 | |||
401 | static void InitBits(struct BitParser *b) | ||
402 | { | ||
403 | // Reset the bit position and buffer. | ||
404 | b->m_bitPos = 0; | ||
405 | b->m_bitBuf = 0; | ||
406 | } | ||
407 | |||
408 | |||
409 | |||
410 | static inline U8 GetByte(struct BitParser *b) | ||
411 | { | ||
412 | U8 v; | ||
413 | v = *b->ptr++; | ||
414 | return v; | ||
415 | } | ||
416 | |||
417 | static inline U16 GetWord(struct BitParser *b) | ||
418 | { | ||
419 | U8 *s; | ||
420 | U16 v; | ||
421 | s = b->ptr; | ||
422 | v = s[0] | ((U16) s[1] << 8); | ||
423 | b->ptr = s + 2; | ||
424 | return v; | ||
425 | } | ||
426 | |||
427 | static inline U32 GetDWord(struct BitParser *b) | ||
428 | { | ||
429 | U32 v; | ||
430 | U8 * s = b->ptr; | ||
431 | v = (U32) s[0] | ((U32) s[1] << 8) | | ||
432 | ((U32) s[2] << 16) | ((U32) s [3] << 24); | ||
433 | b->ptr = s + 4; | ||
434 | return v; | ||
435 | } | ||
436 | |||
437 | static inline U32 GetBit (struct BitParser *b) | ||
438 | { | ||
439 | U32 v; | ||
440 | S32 m_bitPos = b->m_bitPos; | ||
441 | U32 m_bitBuf = b->m_bitBuf; | ||
442 | |||
443 | if (m_bitPos == 0) { | ||
444 | m_bitBuf = (U32)(*b->ptr++) << 24; | ||
445 | m_bitPos = 8; | ||
446 | } | ||
447 | |||
448 | v = (m_bitBuf >> 31); | ||
449 | |||
450 | m_bitPos--; | ||
451 | m_bitBuf <<= 1; | ||
452 | |||
453 | b->m_bitPos = m_bitPos; | ||
454 | b->m_bitBuf = m_bitBuf; | ||
455 | |||
456 | return v; | ||
457 | } | ||
458 | |||
459 | static inline U32 GetBits (struct BitParser *b, int n) | ||
460 | { | ||
461 | U32 v; | ||
462 | S32 m_bitPos = b->m_bitPos; | ||
463 | U32 m_bitBuf = b->m_bitBuf; | ||
464 | |||
465 | if (n == 0) | ||
466 | return 0; | ||
467 | |||
468 | while (m_bitPos < n) { | ||
469 | m_bitBuf |= (U32)(*b->ptr++) << (24 - m_bitPos); | ||
470 | m_bitPos += 8; | ||
471 | } | ||
472 | |||
473 | v = m_bitBuf >> (32 - n); | ||
474 | m_bitBuf <<= n; | ||
475 | m_bitPos -= n; | ||
476 | |||
477 | b->m_bitPos = m_bitPos; | ||
478 | b->m_bitBuf = m_bitBuf; | ||
479 | return v; | ||
480 | } | ||
481 | |||
482 | // Get n bits from the string with sign extension. | ||
483 | static inline S32 GetSBits (struct BitParser *b,S32 n) | ||
484 | { | ||
485 | // Get the number as an unsigned value. | ||
486 | S32 v = (S32) GetBits(b,n); | ||
487 | |||
488 | // Is the number negative? | ||
489 | if (v & (1L << (n - 1))) | ||
490 | { | ||
491 | // Yes. Extend the sign. | ||
492 | v |= -1L << n; | ||
493 | } | ||
494 | |||
495 | return v; | ||
496 | } | ||
497 | |||
498 | |||
499 | |||
500 | /************************************************************************/ | ||
501 | |||
502 | static void GetMatrix(BitParser *b, Matrix* mat) | ||
503 | { | ||
504 | InitBits(b); | ||
505 | |||
506 | // Scale terms | ||
507 | if (GetBit(b)) | ||
508 | { | ||
509 | int nBits = (int) GetBits(b,5); | ||
510 | mat->a = (float)(GetSBits(b,nBits))/(float)0x10000; | ||
511 | mat->d = (float)(GetSBits(b,nBits))/(float)0x10000; | ||
512 | } | ||
513 | else | ||
514 | { | ||
515 | mat->a = mat->d = 1.0; | ||
516 | } | ||
517 | |||
518 | // Rotate/skew terms | ||
519 | if (GetBit(b)) | ||
520 | { | ||
521 | int nBits = (int)GetBits(b,5); | ||
522 | mat->c = (float)(GetSBits(b,nBits))/(float)0x10000; | ||
523 | mat->b = (float)(GetSBits(b,nBits))/(float)0x10000; | ||
524 | } | ||
525 | else | ||
526 | { | ||
527 | mat->b = mat->c = 0.0; | ||
528 | } | ||
529 | |||
530 | // Translate terms | ||
531 | int nBits = (int) GetBits(b,5); | ||
532 | mat->tx = GetSBits(b,nBits); | ||
533 | mat->ty = GetSBits(b,nBits); | ||
534 | } | ||
535 | |||
536 | static FillStyleDef * ParseFillStyle(ShapeParser *shape, long *n, long getAlpha) | ||
537 | { | ||
538 | BitParser *b = &shape->bit_parser; | ||
539 | FillStyleDef *defs; | ||
540 | U16 i = 0; | ||
541 | |||
542 | // Get the number of fills. | ||
543 | U16 nFills = GetByte(b); | ||
544 | |||
545 | // Do we have a larger number? | ||
546 | if (nFills == 255) | ||
547 | { | ||
548 | // Get the larger number. | ||
549 | nFills = GetWord(b); | ||
550 | } | ||
551 | |||
552 | *n = nFills; | ||
553 | defs = new FillStyleDef[ nFills ]; | ||
554 | if (defs == NULL) return NULL; | ||
555 | |||
556 | // Get each of the fill style. | ||
557 | for (i = 0; i < nFills; i++) | ||
558 | { | ||
559 | U16 fillStyle = GetByte(b); | ||
560 | |||
561 | defs[i].type = (FillType) fillStyle; | ||
562 | |||
563 | if (fillStyle & 0x10) | ||
564 | { | ||
565 | defs[i].type = (FillType) (fillStyle & 0x12); | ||
566 | |||
567 | // Get the gradient matrix. | ||
568 | GetMatrix(b,&(defs[i].matrix)); | ||
569 | |||
570 | // Get the number of colors. | ||
571 | defs[i].gradient.nbGradients = GetByte(b); | ||
572 | |||
573 | // Get each of the colors. | ||
574 | for (U16 j = 0; j < defs[i].gradient.nbGradients; j++) | ||
575 | { | ||
576 | defs[i].gradient.ratio[j] = GetByte(b); | ||
577 | defs[i].gradient.color[j].red = GetByte(b); | ||
578 | defs[i].gradient.color[j].green = GetByte(b); | ||
579 | defs[i].gradient.color[j].blue = GetByte(b); | ||
580 | if (getAlpha) { | ||
581 | defs[i].gradient.color[j].alpha = GetByte(b); | ||
582 | } else { | ||
583 | defs[i].gradient.color[j].alpha = ALPHA_OPAQUE; | ||
584 | } | ||
585 | } | ||
586 | } | ||
587 | else if (fillStyle & 0x40) | ||
588 | { | ||
589 | defs[i].type = (FillType) (fillStyle & 0x41); | ||
590 | |||
591 | // Get the bitmapId | ||
592 | defs[i].bitmap = (Bitmap *)shape->dict->getCharacter(GetWord(b)); | ||
593 | // Get the bitmap matrix. | ||
594 | GetMatrix(b,&(defs[i].matrix)); | ||
595 | } | ||
596 | else | ||
597 | { | ||
598 | defs[i].type = (FillType) 0; | ||
599 | |||
600 | // A solid color | ||
601 | defs[i].color.red = GetByte(b); | ||
602 | defs[i].color.green = GetByte(b); | ||
603 | defs[i].color.blue = GetByte(b); | ||
604 | if (getAlpha) { | ||
605 | defs[i].color.alpha = GetByte(b); | ||
606 | } else { | ||
607 | defs[i].color.alpha = ALPHA_OPAQUE; | ||
608 | } | ||
609 | } | ||
610 | } | ||
611 | |||
612 | return defs; | ||
613 | } | ||
614 | |||
615 | static LineStyleDef * ParseLineStyle(ShapeParser *shape, long *n, long getAlpha) | ||
616 | { | ||
617 | BitParser *b = &shape->bit_parser; | ||
618 | LineStyleDef *defs,*def; | ||
619 | FillStyleDef *f; | ||
620 | long i; | ||
621 | |||
622 | // Get the number of lines. | ||
623 | U16 nLines = GetByte(b); | ||
624 | |||
625 | // Do we have a larger number? | ||
626 | if (nLines == 255) | ||
627 | { | ||
628 | // Get the larger number. | ||
629 | nLines = GetWord(b); | ||
630 | } | ||
631 | |||
632 | *n = nLines; | ||
633 | defs = new LineStyleDef[ nLines ]; | ||
634 | if (defs == NULL) return NULL; | ||
635 | |||
636 | // Get each of the line styles. | ||
637 | for (i = 0; i < nLines; i++) | ||
638 | { | ||
639 | def=&defs[i]; | ||
640 | def->width = GetWord(b); | ||
641 | def->color.red = GetByte(b); | ||
642 | def->color.green = GetByte(b); | ||
643 | def->color.blue = GetByte(b); | ||
644 | if (getAlpha) { | ||
645 | def->color.alpha = GetByte(b); | ||
646 | } else { | ||
647 | def->color.alpha = ALPHA_OPAQUE; | ||
648 | } | ||
649 | |||
650 | f=&def->fillstyle; | ||
651 | f->type = f_Solid; | ||
652 | f->color = def->color; | ||
653 | if (shape->cxform) { | ||
654 | f->color = shape->cxform->getColor(f->color); | ||
655 | } | ||
656 | f->color.pixel = shape->gd->allocColor(f->color); | ||
657 | } | ||
658 | |||
659 | return defs; | ||
660 | } | ||
661 | |||
662 | /* 0 = end of shape */ | ||
663 | static int ParseShapeRecord(ShapeParser *shape, ShapeRecord *sr, long getAlpha) | ||
664 | { | ||
665 | BitParser *b = &shape->bit_parser; | ||
666 | |||
667 | // Determine if this is an edge. | ||
668 | BOOL isEdge = (BOOL) GetBit(b); | ||
669 | |||
670 | if (!isEdge) | ||
671 | { | ||
672 | // Handle a state change | ||
673 | U16 flags = (U16) GetBits(b,5); | ||
674 | |||
675 | // Are we at the end? | ||
676 | if (flags == 0) | ||
677 | { | ||
678 | // End of shape | ||
679 | return 0; | ||
680 | } | ||
681 | |||
682 | sr->type = shapeNonEdge; | ||
683 | sr->flags = (ShapeFlags)flags; | ||
684 | |||
685 | // Process a move to. | ||
686 | if (flags & flagsMoveTo) | ||
687 | { | ||
688 | U16 nBits = (U16) GetBits(b,5); | ||
689 | sr->x = GetSBits(b,nBits); | ||
690 | sr->y = GetSBits(b,nBits); | ||
691 | } | ||
692 | |||
693 | // Get new fill info. | ||
694 | if (flags & flagsFill0) | ||
695 | { | ||
696 | sr->fillStyle0 = GetBits(b,shape->m_nFillBits); | ||
697 | } | ||
698 | if (flags & flagsFill1) | ||
699 | { | ||
700 | sr->fillStyle1 = GetBits(b,shape->m_nFillBits); | ||
701 | } | ||
702 | |||
703 | // Get new line info | ||
704 | if (flags & flagsLine) | ||
705 | { | ||
706 | sr->lineStyle = GetBits(b,shape->m_nLineBits); | ||
707 | } | ||
708 | |||
709 | // Check to get a new set of styles for a new shape layer. | ||
710 | if (flags & flagsNewStyles) | ||
711 | { | ||
712 | FillStyleDef *fillDefs; | ||
713 | LineStyleDef *lineDefs; | ||
714 | long n; | ||
715 | |||
716 | // Parse the style. | ||
717 | fillDefs = ParseFillStyle(shape, &n, getAlpha); | ||
718 | if (fillDefs == NULL) return 0; | ||
719 | |||
720 | sr->newFillStyles = fillDefs; | ||
721 | sr->nbNewFillStyles = n; | ||
722 | |||
723 | lineDefs = ParseLineStyle(shape, &n, getAlpha); | ||
724 | if (lineDefs == NULL) return 0; | ||
725 | |||
726 | sr->newLineStyles = lineDefs; | ||
727 | sr->nbNewLineStyles = n; | ||
728 | |||
729 | InitBits(b);// Bug ! | ||
730 | |||
731 | // Reset. | ||
732 | shape->m_nFillBits = (U16) GetBits(b,4); | ||
733 | shape->m_nLineBits = (U16) GetBits(b,4); | ||
734 | } | ||
735 | |||
736 | //if (flags & flagsEndShape) | ||
737 | //printf("\tEnd of shape.\n\n"); | ||
738 | |||
739 | return flags & flagsEndShape ? 0 : 1; | ||
740 | } | ||
741 | else | ||
742 | { | ||
743 | if (GetBit(b)) | ||
744 | { | ||
745 | sr->type = shapeLine; | ||
746 | |||
747 | // Handle a line | ||
748 | U16 nBits = (U16) GetBits(b,4) + 2;// nBits is biased by 2 | ||
749 | |||
750 | // Save the deltas | ||
751 | if (GetBit(b)) | ||
752 | { | ||
753 | // Handle a general line. | ||
754 | sr->dX = GetSBits(b,nBits); | ||
755 | sr->dY = GetSBits(b,nBits); | ||
756 | } | ||
757 | else | ||
758 | { | ||
759 | // Handle a vert or horiz line. | ||
760 | if (GetBit(b)) | ||
761 | { | ||
762 | // Vertical line | ||
763 | sr->dY = GetSBits(b,nBits); | ||
764 | sr->dX = 0; | ||
765 | } | ||
766 | else | ||
767 | { | ||
768 | // Horizontal line | ||
769 | sr->dX = GetSBits(b,nBits); | ||
770 | sr->dY = 0; | ||
771 | } | ||
772 | } | ||
773 | } | ||
774 | else | ||
775 | { | ||
776 | sr->type = shapeCurve; | ||
777 | |||
778 | // Handle a curve | ||
779 | U16 nBits = (U16) GetBits(b,4) + 2;// nBits is biased by 2 | ||
780 | |||
781 | // Get the control | ||
782 | sr->ctrlX = GetSBits(b,nBits); | ||
783 | sr->ctrlY = GetSBits(b,nBits); | ||
784 | |||
785 | // Get the anchor | ||
786 | sr->anchorX = GetSBits(b,nBits); | ||
787 | sr->anchorY = GetSBits(b,nBits); | ||
788 | } | ||
789 | |||
790 | return 1; | ||
791 | } | ||
792 | } | ||
793 | |||
794 | static void drawShape(GraphicDevice *gd, Matrix *matrix1, Cxform *cxform, Shape *shape, | ||
795 | ShapeAction shapeAction, void *id,ScanLineFunc scan_line_func) | ||
796 | { | ||
797 | LineStyleDef *l; | ||
798 | FillStyleDef *f0; | ||
799 | FillStyleDef *f1; | ||
800 | ShapeRecord sr1,*sr = &sr1; | ||
801 | int firstPoint; | ||
802 | long lastX,lastY; | ||
803 | LineStyleDef *curLineStyle; | ||
804 | long curNbLineStyles; | ||
805 | FillStyleDef *curFillStyle; | ||
806 | long curNbFillStyles; | ||
807 | StyleList *sl; | ||
808 | ShapeParser sp1,*sp=&sp1; | ||
809 | BitParser *b; | ||
810 | Matrix mat,*matrix; | ||
811 | |||
812 | mat = (*gd->adjust) * (*matrix1); | ||
813 | matrix = &mat; | ||
814 | |||
815 | sp->reverse = (mat.a * mat.d) < 0; | ||
816 | |||
817 | curLineStyle = NULL; | ||
818 | curNbLineStyles = 0; | ||
819 | curFillStyle = NULL; | ||
820 | curNbFillStyles = 0; | ||
821 | sp->style_list = NULL; | ||
822 | |||
823 | sp->shape = shape; | ||
824 | sp->gd = gd; | ||
825 | sp->matrix = matrix; | ||
826 | sp->cxform = cxform; | ||
827 | sp->dict = shape->dict; | ||
828 | |||
829 | if (shapeAction == ShapeGetRegion) { | ||
830 | gd->scan_line_func = scan_line_func; | ||
831 | gd->scan_line_func_id = id; | ||
832 | } else { | ||
833 | gd->scan_line_func = NULL; | ||
834 | } | ||
835 | |||
836 | b = &sp->bit_parser; | ||
837 | InitBitParser(b,shape->file_ptr); | ||
838 | |||
839 | if (shape->getStyles) { | ||
840 | // ShapeWithStyle | ||
841 | curFillStyle = ParseFillStyle(sp, &curNbFillStyles, shape->getAlpha); | ||
842 | if (curFillStyle == NULL) return; | ||
843 | |||
844 | curLineStyle = ParseLineStyle(sp, &curNbLineStyles, shape->getAlpha); | ||
845 | if (curLineStyle == NULL) return; | ||
846 | |||
847 | sl = new StyleList; | ||
848 | if (sl == NULL) return; | ||
849 | |||
850 | sl->next = NULL; | ||
851 | sl->newFillStyles = curFillStyle; | ||
852 | sl->nbNewFillStyles = curNbFillStyles; | ||
853 | sl->newLineStyles = curLineStyle; | ||
854 | sl->nbNewLineStyles = curNbLineStyles; | ||
855 | |||
856 | sp->style_list = sl; | ||
857 | |||
858 | if (shapeAction == ShapeDraw) { | ||
859 | prepareStyles(gd, matrix, cxform, curFillStyle, curNbFillStyles); | ||
860 | } | ||
861 | } | ||
862 | |||
863 | InitBits(b); | ||
864 | sp->m_nFillBits = (U16) GetBits(b,4); | ||
865 | sp->m_nLineBits = (U16) GetBits(b,4); | ||
866 | |||
867 | l = 0; | ||
868 | f0 = 0; | ||
869 | f1 = 0; | ||
870 | firstPoint = 1; | ||
871 | lastX = 0; | ||
872 | lastY = 0; | ||
873 | sp->curPath.nb_edges = 0; | ||
874 | sp->first_line = NULL; | ||
875 | sp->last_line = NULL; | ||
876 | |||
877 | for(;;) { | ||
878 | if (ParseShapeRecord(sp, sr, shape->getAlpha) == 0) break; | ||
879 | |||
880 | switch (sr->type) | ||
881 | { | ||
882 | case shapeNonEdge: | ||
883 | if (sr->flags & flagsNewStyles) { | ||
884 | |||
885 | curFillStyle = sr->newFillStyles; | ||
886 | curNbFillStyles = sr->nbNewFillStyles; | ||
887 | curLineStyle = sr->newLineStyles; | ||
888 | curNbLineStyles = sr->nbNewLineStyles; | ||
889 | |||
890 | sl = new StyleList; | ||
891 | sl->next = sp->style_list; | ||
892 | sl->newFillStyles = sr->newFillStyles; | ||
893 | sl->nbNewFillStyles = sr->nbNewFillStyles; | ||
894 | sl->newLineStyles = sr->newLineStyles; | ||
895 | sl->nbNewLineStyles = sr->nbNewLineStyles; | ||
896 | |||
897 | sp->style_list = sl; | ||
898 | |||
899 | if (shapeAction == ShapeDraw) { | ||
900 | prepareStyles(gd, matrix, cxform, curFillStyle, curNbFillStyles); | ||
901 | } | ||
902 | } | ||
903 | if (sr->flags & flagsFill0) { | ||
904 | if (sr->fillStyle0) { | ||
905 | if (curFillStyle) { | ||
906 | f0 = &curFillStyle[sr->fillStyle0-1]; | ||
907 | } else { | ||
908 | f0 = &shape->defaultFillStyle; | ||
909 | } | ||
910 | } else { | ||
911 | f0 = 0; | ||
912 | } | ||
913 | } | ||
914 | if (sr->flags & flagsFill1) { | ||
915 | if (sr->fillStyle1) { | ||
916 | if (curFillStyle) { | ||
917 | f1 = &curFillStyle[sr->fillStyle1-1]; | ||
918 | } else { | ||
919 | f1 = &shape->defaultFillStyle; | ||
920 | } | ||
921 | } else { | ||
922 | f1 = 0; | ||
923 | } | ||
924 | } | ||
925 | if (sr->flags & flagsLine) { | ||
926 | if (sr->lineStyle) { | ||
927 | l = &curLineStyle[sr->lineStyle-1]; | ||
928 | } else { | ||
929 | l = 0; | ||
930 | } | ||
931 | } | ||
932 | if (sr->flags & flagsMoveTo) { | ||
933 | if (sp->curPath.nb_edges == 0) { | ||
934 | /* if no edges, draw the polygon, then the lines */ | ||
935 | flushPaths(sp); | ||
936 | } | ||
937 | |||
938 | newPath(sp, sr->x, sr->y); | ||
939 | firstPoint = 0; | ||
940 | |||
941 | lastX = sr->x; | ||
942 | lastY = sr->y; | ||
943 | |||
944 | #if PRINT | ||
945 | printf("---------\nX,Y = %4d,%4d\n", sr->x/20, sr->y/20); | ||
946 | #endif | ||
947 | } | ||
948 | break; | ||
949 | case shapeCurve: | ||
950 | // Handle Bezier Curves !!! | ||
951 | if (firstPoint) { | ||
952 | newPath(sp, 0, 0); | ||
953 | firstPoint = 0; | ||
954 | } | ||
955 | { | ||
956 | long newX,newY,ctrlX,ctrlY; | ||
957 | |||
958 | ctrlX = lastX+sr->ctrlX; | ||
959 | ctrlY = lastY+sr->ctrlY; | ||
960 | newX = ctrlX+sr->anchorX; | ||
961 | newY = ctrlY+sr->anchorY; | ||
962 | |||
963 | #if 1 | ||
964 | addBezier(sp, ctrlX, ctrlY, newX, newY, f0 , f1, l); | ||
965 | #else | ||
966 | addLine(sp, newX, newY, f0, f1, l); | ||
967 | #endif | ||
968 | |||
969 | lastX = newX; | ||
970 | lastY = newY; | ||
971 | } | ||
972 | break; | ||
973 | case shapeLine: | ||
974 | if (firstPoint) { | ||
975 | newPath(sp, 0, 0); | ||
976 | firstPoint = 0; | ||
977 | } | ||
978 | |||
979 | lastX += sr->dX; | ||
980 | lastY += sr->dY; | ||
981 | |||
982 | addLine(sp, lastX, lastY, f0, f1, l); | ||
983 | #if PRINT | ||
984 | printf(" X, Y = %4d,%4d\n", lastX/20, lastY/20); | ||
985 | #endif | ||
986 | break; | ||
987 | } | ||
988 | } | ||
989 | |||
990 | /* XXX: should test if there is something to draw */ | ||
991 | flushPaths(sp); | ||
992 | |||
993 | /* free the styles */ | ||
994 | while (sp->style_list) { | ||
995 | StyleList *sl; | ||
996 | |||
997 | sl=sp->style_list; | ||
998 | sp->style_list = sl->next; | ||
999 | |||
1000 | if (shapeAction == ShapeDraw) { | ||
1001 | clearStyles(gd, sl->newFillStyles, sl->nbNewFillStyles); | ||
1002 | } | ||
1003 | |||
1004 | delete[] sl->newFillStyles; | ||
1005 | delete[] sl->newLineStyles; | ||
1006 | |||
1007 | delete sl; | ||
1008 | } | ||
1009 | } | ||
1010 | |||
1011 | static void | ||
1012 | prepareStyles(GraphicDevice *gd, Matrix *matrix, Cxform *cxform, | ||
1013 | FillStyleDef *ftab, long n) | ||
1014 | { | ||
1015 | long fs; | ||
1016 | FillStyleDef *f; | ||
1017 | |||
1018 | for(fs = 0; fs < n; fs++) | ||
1019 | { | ||
1020 | f = ftab + fs; | ||
1021 | switch (f->type) | ||
1022 | { | ||
1023 | case f_None: | ||
1024 | break; | ||
1025 | case f_Solid: | ||
1026 | if (cxform) { | ||
1027 | f->color = cxform->getColor(f->color); | ||
1028 | } | ||
1029 | f->color.pixel = gd->allocColor(f->color); | ||
1030 | break; | ||
1031 | case f_LinearGradient: | ||
1032 | case f_RadialGradient: | ||
1033 | { | ||
1034 | Matrix mat; | ||
1035 | int n,r,l; | ||
1036 | long red, green, blue, alpha; | ||
1037 | long dRed, dGreen, dBlue, dAlpha; | ||
1038 | long min,max; | ||
1039 | Matrix *m; | ||
1040 | |||
1041 | mat = *(matrix) * f->matrix; | ||
1042 | // Compute inverted matrix | ||
1043 | f->gradient.imat = mat.invert(); | ||
1044 | |||
1045 | /* renormalize the matrix */ | ||
1046 | m=&f->gradient.imat; | ||
1047 | if (f->type == f_LinearGradient) { | ||
1048 | m->a = m->a * FRAC * (1/128.0) * 65536.0; | ||
1049 | m->b = m->b * FRAC * (1/128.0) * 65536.0; | ||
1050 | m->tx = (long) ((m->tx + 16384) * (1/128.0) * 65536.0); | ||
1051 | } else { | ||
1052 | m->a = m->a * FRAC * (1/64.0) * 65536.0; | ||
1053 | m->b = m->b * FRAC * (1/64.0) * 65536.0; | ||
1054 | m->c = m->c * FRAC * (1/64.0) * 65536.0; | ||
1055 | m->d = m->d * FRAC * (1/64.0) * 65536.0; | ||
1056 | m->tx = (long) (m->tx * (1/64.0) * 65536.0); | ||
1057 | m->ty = (long) (m->ty * (1/64.0) * 65536.0); | ||
1058 | } | ||
1059 | |||
1060 | // Reset translation in inverted matrix | ||
1061 | f->gradient.has_alpha = 0; | ||
1062 | |||
1063 | // Build a 256 color ramp | ||
1064 | f->gradient.ramp = new Color[256]; | ||
1065 | if (f->gradient.ramp == NULL) { | ||
1066 | // Invalidate fill style | ||
1067 | f->type = f_None; | ||
1068 | continue; | ||
1069 | } | ||
1070 | |||
1071 | // Store min and max | ||
1072 | min = f->gradient.ratio[0]; | ||
1073 | max = f->gradient.ratio[f->gradient.nbGradients-1]; | ||
1074 | for(r=0; r < f->gradient.nbGradients-1; r++) | ||
1075 | { | ||
1076 | Color start,end; | ||
1077 | |||
1078 | l = f->gradient.ratio[r+1]-f->gradient.ratio[r]; | ||
1079 | if (l == 0) continue; | ||
1080 | |||
1081 | if (cxform) { | ||
1082 | start = cxform->getColor(f->gradient.color[r]); | ||
1083 | end = cxform->getColor(f->gradient.color[r+1]); | ||
1084 | } else { | ||
1085 | start = f->gradient.color[r]; | ||
1086 | end = f->gradient.color[r+1]; | ||
1087 | } | ||
1088 | |||
1089 | if (start.alpha != ALPHA_OPAQUE || | ||
1090 | end.alpha != ALPHA_OPAQUE) { | ||
1091 | f->gradient.has_alpha = 1; | ||
1092 | } | ||
1093 | |||
1094 | dRed = end.red - start.red; | ||
1095 | dGreen = end.green - start.green; | ||
1096 | dBlue = end.blue - start.blue; | ||
1097 | dAlpha = end.alpha - start.alpha; | ||
1098 | |||
1099 | dRed = (dRed<<16)/l; | ||
1100 | dGreen = (dGreen<<16)/l; | ||
1101 | dBlue = (dBlue<<16)/l; | ||
1102 | dAlpha = (dAlpha<<16)/l; | ||
1103 | |||
1104 | red = start.red <<16; | ||
1105 | green = start.green <<16; | ||
1106 | blue = start.blue <<16; | ||
1107 | alpha = start.alpha <<16; | ||
1108 | |||
1109 | for (n=f->gradient.ratio[r]; n<=f->gradient.ratio[r+1]; n++) { | ||
1110 | f->gradient.ramp[n].red = red>>16; | ||
1111 | f->gradient.ramp[n].green = green>>16; | ||
1112 | f->gradient.ramp[n].blue = blue>>16; | ||
1113 | f->gradient.ramp[n].alpha = alpha>>16; | ||
1114 | |||
1115 | f->gradient.ramp[n].pixel = gd->allocColor(f->gradient.ramp[n]); | ||
1116 | red += dRed; | ||
1117 | green += dGreen; | ||
1118 | blue += dBlue; | ||
1119 | alpha += dAlpha; | ||
1120 | } | ||
1121 | } | ||
1122 | for(n=0; n<min; n++) { | ||
1123 | f->gradient.ramp[n] = f->gradient.ramp[min]; | ||
1124 | } | ||
1125 | for(n=max; n<256; n++) { | ||
1126 | f->gradient.ramp[n] = f->gradient.ramp[max]; | ||
1127 | } | ||
1128 | } | ||
1129 | break; | ||
1130 | case f_TiledBitmap: | ||
1131 | case f_clippedBitmap: | ||
1132 | if (f->bitmap) { | ||
1133 | Matrix *m; | ||
1134 | |||
1135 | f->cmap = gd->getColormap(f->bitmap->colormap, | ||
1136 | f->bitmap->nbColors, cxform); | ||
1137 | if (f->cmap == NULL) { | ||
1138 | /* Get the normal cmap anyway */ | ||
1139 | f->cmap = f->bitmap->colormap; | ||
1140 | } | ||
1141 | |||
1142 | f->bitmap_matrix = *(matrix) * f->matrix; | ||
1143 | |||
1144 | f->bitmap_matrix = f->bitmap_matrix.invert(); | ||
1145 | |||
1146 | m=&f->bitmap_matrix; | ||
1147 | m->a = m->a * FRAC * 65536.0; | ||
1148 | m->b = m->b * FRAC * 65536.0; | ||
1149 | m->c = m->c * FRAC * 65536.0; | ||
1150 | m->d = m->d * FRAC * 65536.0; | ||
1151 | m->tx = (long) (m->tx * 65536.0); | ||
1152 | m->ty = (long) (m->ty * 65536.0); | ||
1153 | |||
1154 | f->alpha_table = NULL; | ||
1155 | |||
1156 | if (f->bitmap->alpha_buf && cxform) { | ||
1157 | unsigned char *alpha_table; | ||
1158 | int i; | ||
1159 | |||
1160 | alpha_table = (unsigned char *)malloc (256); | ||
1161 | if (alpha_table != NULL) { | ||
1162 | for(i=0;i<256;i++) { | ||
1163 | alpha_table[i] = cxform->getAlpha(i); | ||
1164 | } | ||
1165 | } | ||
1166 | f->alpha_table = alpha_table; | ||
1167 | } | ||
1168 | } | ||
1169 | break; | ||
1170 | } | ||
1171 | } | ||
1172 | } | ||
1173 | |||
1174 | static void | ||
1175 | clearStyles(GraphicDevice *gd, FillStyleDef *ftab, long n) | ||
1176 | { | ||
1177 | long fs; | ||
1178 | FillStyleDef *f; | ||
1179 | |||
1180 | for(fs = 0; fs < n; fs++) | ||
1181 | { | ||
1182 | f = ftab + fs; | ||
1183 | switch (f->type) | ||
1184 | { | ||
1185 | case f_Solid: | ||
1186 | break; | ||
1187 | case f_LinearGradient: | ||
1188 | case f_RadialGradient: | ||
1189 | if (f->gradient.ramp) { | ||
1190 | delete f->gradient.ramp; | ||
1191 | } | ||
1192 | break; | ||
1193 | case f_TiledBitmap: | ||
1194 | case f_clippedBitmap: | ||
1195 | if (f->bitmap) { | ||
1196 | if (f->cmap && f->cmap != f->bitmap->colormap) delete f->cmap; | ||
1197 | if (f->alpha_table) free(f->alpha_table); | ||
1198 | } | ||
1199 | break; | ||
1200 | case f_None: | ||
1201 | break; | ||
1202 | } | ||
1203 | } | ||
1204 | } | ||
1205 | |||