ded2f6553538b998a8655d1e99bc5d46c221e704
[swftools.git] / lib / modules / swfshape.c
1 /* swfshape.c
2
3    shape functions
4       
5    Extension module for the rfxswf library.
6    Part of the swftools package.
7
8    Copyright (c) 2001 Rainer Böhme <rfxswf@reflex-studio.de>
9  
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
23
24 #define SF_MOVETO       0x01
25 #define SF_FILL0        0x02
26 #define SF_FILL1        0x04
27 #define SF_LINE         0x08
28 #define SF_NEWSTYLE     0x10
29
30 #define FILL_SOLID      0x00
31 #define FILL_LINEAR     0x10  // Gradient
32 #define FILL_RADIAL     0x12
33 #define FILL_TILED      0x40  // Bitmap
34 #define FILL_CLIPPED    0x41
35
36 void swf_ShapeFree(SHAPE * s)
37 { if (s)
38   { if (s->linestyle.data) free(s->linestyle.data);
39     s->linestyle.data = NULL;
40     s->linestyle.n    = 0;
41     if (s->fillstyle.data) free(s->fillstyle.data);
42     s->fillstyle.data = NULL;
43     s->fillstyle.n    = 0;
44     if (s->data) free(s->data);
45     s->data = NULL;
46   }
47   free(s);
48 }
49
50 int swf_ShapeNew(SHAPE * * s)
51 { SHAPE * sh;
52   if (!s) return -1;
53   sh = (SHAPE *)malloc(sizeof(SHAPE)); s[0] = sh;
54   if (sh) memset(sh,0x00,sizeof(SHAPE));
55   return sh?0:-1;
56 }
57
58 int swf_GetSimpleShape(TAG * t,SHAPE * * s) // without Linestyle/Fillstyle Record
59 { SHAPE * sh;
60   int bitl, len;
61   int end;
62   U32 pos;
63   
64   if (FAILED(swf_ShapeNew(s))) return -1;
65   sh = s[0];
66
67   swf_ResetReadBits(t); 
68   sh->bits.fill = (U16)swf_GetBits(t,4);
69   sh->bits.line = (U16)swf_GetBits(t,4);
70   bitl = 0; end = 0; pos = swf_GetTagPos(t);
71
72   while (!end)
73   { int edge = swf_GetBits(t,1); bitl+=1;
74     if (edge)
75     { bitl+=1;
76       if (swf_GetBits(t,1))                 // Line
77       { U16 nbits = swf_GetBits(t,4)+2;
78         bitl+=5;
79
80         if (swf_GetBits(t,1))               // x/y Line
81         { swf_GetBits(t,nbits);
82           swf_GetBits(t,nbits);
83           bitl+=nbits*2;
84         }
85         else                            // hline/vline
86         { swf_GetBits(t,nbits+1);
87           bitl+=nbits+1;
88         }
89       }
90       else                              // Curve
91       { U16 nbits = swf_GetBits(t,4)+2;
92         bitl+=4;
93
94         swf_GetBits(t,nbits);
95         swf_GetBits(t,nbits);
96         swf_GetBits(t,nbits);
97         swf_GetBits(t,nbits);
98
99         bitl+=4*nbits;
100       }
101     }
102     else
103     { U16 flags = swf_GetBits(t,5); bitl+=5;
104       if (flags)
105       {
106         if (flags&SF_MOVETO)
107         { U16 nbits = swf_GetBits(t,5); bitl+=5;
108           swf_GetBits(t,nbits);
109           swf_GetBits(t,nbits);
110           bitl+=2*nbits;
111         }
112         
113         if (flags&SF_FILL0)
114         { swf_GetBits(t,sh->bits.fill);
115           bitl+=sh->bits.fill;
116         }
117         
118         if (flags&SF_FILL1)
119         { swf_GetBits(t,sh->bits.fill);
120           bitl+=sh->bits.fill;
121         }
122
123         if (flags&SF_LINE)
124         { swf_GetBits(t,sh->bits.line);
125           bitl+=sh->bits.line;
126         }
127
128         if (flags&SF_NEWSTYLE)
129         { fprintf(stderr,"RFXSWF: Can't process extended styles in shape.\n");
130         }
131       }
132       else end = 1;
133     }
134   }
135   swf_SetTagPos(t,pos);
136   len = (bitl+7)/8;
137   
138   if (sh->data) free(sh->data);
139   sh->data = (U8*)malloc(len);
140   
141   if (sh->data)
142   { sh->bitlen = bitl;
143     swf_GetBlock(t,sh->data,len);
144   }
145   else return -1;
146   
147   return len;
148 }
149
150 int swf_SetSimpleShape(TAG * t,SHAPE * s) // without Linestyle/Fillstyle Record
151 { int l;
152
153   if (!s) return -1;
154   l = (s->bitlen+7)/8;
155
156   if (t)
157   { swf_ResetWriteBits(t);
158
159     swf_SetBits(t,s->bits.fill,4);
160     swf_SetBits(t,s->bits.line,4);
161     swf_SetBlock(t,s->data,l);
162
163     swf_ResetWriteBits(t);
164   }
165   return l+1;
166 }
167
168 int swf_SetFillStyle(TAG * t,FILLSTYLE * f)
169 { if ((!t)||(!f)) return -1;
170   swf_SetU8(t,f->type);
171   
172   // no gradients yet!
173   
174   switch (f->type)
175   { case FILL_SOLID:
176       if (swf_GetTagID(t)!=ST_DEFINESHAPE3) swf_SetRGB(t,&f->color);
177       else swf_SetRGBA(t,&f->color);
178       break;
179
180     case FILL_TILED:
181     case FILL_CLIPPED:
182       swf_SetU16(t,f->id_bitmap);
183       swf_SetMatrix(t,&f->m);
184       break;
185   }
186   
187   return 0;
188 }
189
190 int swf_SetLineStyle(TAG * t,LINESTYLE * l)
191 { if ((!l)||(!t)) return -1;
192   swf_SetU16(t,l->width);
193
194   if (swf_GetTagID(t)!=ST_DEFINESHAPE3) swf_SetRGB(t,&l->color);
195   else swf_SetRGBA(t,&l->color);
196   
197   return 0;
198 }
199
200 int swf_SetShapeStyleCount(TAG * t,U16 n)
201 { if (n>254)
202   { swf_SetU8(t,0xff);
203     swf_SetU16(t,n);
204     return 3;
205   }
206   else
207   { swf_SetU8(t,n);
208     return 1;
209   }
210 }
211
212 int swf_SetShapeStyles(TAG * t,SHAPE * s)
213 { int i,l;
214   if (!s) return -1;
215
216   l = 0;
217   l += swf_SetShapeStyleCount(t,s->fillstyle.n);
218
219   for (i=0;i<s->fillstyle.n;i++)
220     l+=swf_SetFillStyle(t,&s->fillstyle.data[i]);
221
222   l += swf_SetShapeStyleCount(t,s->linestyle.n);
223
224   for (i=0;i<s->linestyle.n;i++)
225     l+=swf_SetLineStyle(t,&s->linestyle.data[i]);
226
227   return l;
228 }
229
230 int swf_ShapeCountBits(SHAPE * s,U8 * fbits,U8 * lbits)
231 { if (!s) return -1;
232   s->bits.fill = swf_CountUBits(s->fillstyle.n, 0);
233   s->bits.line = swf_CountUBits(s->linestyle.n, 0);
234   if (fbits) fbits[0] = s->bits.fill;
235   if (lbits) lbits[0] = s->bits.line;
236   return 0;    
237 }
238
239 int swf_SetShapeBits(TAG * t,SHAPE * s)
240 { if ((!t)||(!s)) return -1;
241   swf_ResetWriteBits(t);
242   swf_SetBits(t,s->bits.fill,4);
243   swf_SetBits(t,s->bits.line,4);
244   return 0;
245 }
246
247 int swf_SetShapeHeader(TAG * t,SHAPE * s)
248 { int res;
249   res = swf_SetShapeStyles(t,s);
250   if (res>=0) res = swf_ShapeCountBits(s,NULL,NULL);
251   if (res>=0) res = swf_SetShapeBits(t,s);
252   return res;
253 }
254
255 int swf_ShapeExport(int handle,SHAPE * s)  // without Linestyle/Fillstyle Record
256 { int l;
257   if (!s) return 0;
258
259   l = sizeof(SHAPE);
260
261   if (handle>=0)
262     if (write(handle,s,sizeof(SHAPE))!=sizeof(SHAPE)) return -1;
263
264   // Fillstyle, Linestyle ...
265
266   if (s->data)
267   { int ll = (s->bitlen+7)/8;
268     l+=ll;
269     if (handle>=0)
270       if (write(handle,s->data,ll)!=ll) return -1;
271   }
272
273   return l;
274 }
275
276 int swf_ShapeImport(int handle,SHAPE * * shape)
277 { SHAPE * s;
278
279   if (handle<0) return -1;
280
281   s = (SHAPE *)malloc(sizeof(SHAPE)); shape[0] = s;
282   if (!s) return -1;
283
284   if (read(handle,s,sizeof(SHAPE))!=sizeof(SHAPE))
285   { shape[0] = NULL;
286     free(s);
287     return -1;
288   }
289
290   if (s->data)
291   { int ll = (s->bitlen+7)/8;
292     s->data = (U8*)malloc(ll);
293     if (!s->data)
294     { shape[0] = NULL;
295       free(s);
296       return -1;
297     }
298     if (read(handle,s->data,ll)!=ll)
299     { free(s->data);
300       free(s);
301       shape[0] = NULL;
302       return -1;
303     }
304   }
305
306   return 0;
307 }
308
309 int swf_ShapeAddFillStyle(SHAPE * s,U8 type,MATRIX * m,RGBA * color,U16 id_bitmap)
310 { RGBA def_c;
311   MATRIX def_m;    
312
313   // handle defaults
314   
315   if (!s) return -1;
316   if (!color)
317   { color = &def_c;
318     def_c.a = 0xff;
319     def_c.r = def_c.g = def_c.b = 0;
320   }
321   if (!m)
322   { m = &def_m;
323     swf_GetMatrix(NULL,m);
324   }
325
326   // handle memory
327   
328   if (s->fillstyle.data)
329   { FILLSTYLE * new = (FILLSTYLE *)realloc(s->fillstyle.data,(s->fillstyle.n+1)*sizeof(FILLSTYLE));
330     if (!new) return -1;
331     s->fillstyle.data = new;
332   }
333   else
334   { s->fillstyle.data = (FILLSTYLE *)malloc(sizeof(FILLSTYLE));
335     s->fillstyle.n = 0;
336     if (!s->fillstyle.data) return -1;
337   }
338
339   // set fillstyle  (no gradients yet!)
340   
341   s->fillstyle.data[s->fillstyle.n].type = type; 
342   s->fillstyle.data[s->fillstyle.n].id_bitmap = id_bitmap;
343   memcpy(&s->fillstyle.data[s->fillstyle.n].m,m,sizeof(MATRIX));
344   memcpy(&s->fillstyle.data[s->fillstyle.n].color,color,sizeof(RGBA));
345           
346   return (++s->fillstyle.n);
347 }
348
349 int swf_ShapeAddSolidFillStyle(SHAPE * s,RGBA * color)
350 { return swf_ShapeAddFillStyle(s,FILL_SOLID,NULL,color,0);
351 }
352
353 int swf_ShapeAddBitmapFillStyle(SHAPE * s,MATRIX * m,U16 id_bitmap,int clip)
354 { return swf_ShapeAddFillStyle(s,clip?FILL_CLIPPED:FILL_TILED,m,NULL,id_bitmap);
355 }
356
357 int swf_ShapeAddLineStyle(SHAPE * s,U16 width,RGBA * color)
358 { RGBA def;
359   if (!s) return -1;
360   if (!color)
361   { color = &def;
362     def.a = 0xff;
363     def.r = def.g = def.b = 0; 
364   }
365   if (s->linestyle.data)
366   { LINESTYLE * new = (LINESTYLE *)realloc(s->linestyle.data,(s->linestyle.n+1)*sizeof(LINESTYLE));
367     if (!new) return -1;
368     s->linestyle.data = new;
369   }
370   else
371   { s->linestyle.data = (LINESTYLE *)malloc(sizeof(LINESTYLE));
372     s->linestyle.n = 0;
373     if (!s->linestyle.data) return -1;
374   }
375   
376   s->linestyle.data[s->linestyle.n].width = width;
377   memcpy(&s->linestyle.data[s->linestyle.n].color,color,sizeof(RGBA));
378
379   return (++s->linestyle.n);
380 }
381
382 int swf_ShapeSetMove(TAG * t,SHAPE * s,S32 x,S32 y)
383 { U8 b;
384   if (!t) return -1;
385   swf_SetBits(t,0,1);
386   swf_SetBits(t,SF_MOVETO,5);
387   
388   b = swf_CountBits(x,0);
389   b = swf_CountBits(y,b);
390   
391   swf_SetBits(t,b,5);
392   swf_SetBits(t,x,b);
393   swf_SetBits(t,y,b);
394
395   return 0;
396 }
397
398 int swf_ShapeSetStyle(TAG * t,SHAPE * s,U16 line,U16 fill0,U16 fill1)
399 { if ((!t)||(!s)) return -1;
400     
401   swf_SetBits(t,0,1);
402   swf_SetBits(t,(line?SF_LINE:0)|(fill0?SF_FILL0:0)|(fill1?SF_FILL1:0),5);
403
404   if (fill0) swf_SetBits(t,fill0,s->bits.fill);
405   if (fill1) swf_SetBits(t,fill1,s->bits.fill);
406   if (line)  swf_SetBits(t,line ,s->bits.line);
407   
408   return 0;
409 }
410
411 /* TODO: sometimes we want to set fillstyle 0, as that's the empty fill
412    used for line drawings. At the moment, we can't, as 0 fill be considered
413    nonexistent and therefore not set.
414    these defines are a workaround (they also reduce the maximal number of
415    fill styles to 32768)
416  */
417 #define FILL_RESET 0x8000
418 #define LINE_RESET 0x8000
419 #define UNDEFINED_COORD 0x7fffffff
420
421 int swf_ShapeSetAll(TAG * t,SHAPE * s,S32 x,S32 y,U16 line,U16 fill0,U16 fill1)
422 { U8 b;
423   U8 hasmove = 0;
424   if ((!t)||(!s)) return -1;
425
426   if(x!=UNDEFINED_COORD || y!=UNDEFINED_COORD)
427       hasmove=1;
428
429   swf_SetBits(t,0,1);
430   swf_SetBits(t,(hasmove?SF_MOVETO:0)|(line?SF_LINE:0)|(fill0?SF_FILL0:0)|(fill1?SF_FILL1:0),5);
431
432   if(hasmove) {
433     b = swf_CountBits(x,0);
434     b = swf_CountBits(y,b);
435     swf_SetBits(t,b,5);
436     swf_SetBits(t,x,b);
437     swf_SetBits(t,y,b);
438   }
439
440   if (fill0) swf_SetBits(t,fill0,s->bits.fill);
441   if (fill1) swf_SetBits(t,fill1,s->bits.fill);
442   if (line)  swf_SetBits(t,line ,s->bits.line);
443   
444   return 0;
445 }
446
447 int swf_ShapeSetEnd(TAG * t)
448 { if (!t) return -1;
449   swf_SetBits(t,0,6);
450   swf_ResetWriteBits(t);
451   return 0;
452 }
453
454 int swf_ShapeSetLine(TAG * t,SHAPE * s,S32 x,S32 y)
455 { U8 b;
456   if (!t) return -1;
457   swf_SetBits(t,3,2); // Straight Edge
458
459   if ((!s)||((x!=0)&&(y!=0)))
460   { b = swf_CountBits(x,2);
461     b = swf_CountBits(y,b);
462     if (b<2) b=2;
463     if(b-2 >= 16) {
464         fprintf(stderr, "Bit overflow in swf_ShapeSetLine(1)- %d\n", b);
465         fflush(stdout);
466         *(int*)0 = 0xdead;
467         b = 17;
468     }
469     swf_SetBits(t, b-2, 4);
470     swf_SetBits(t,1,1);
471     swf_SetBits(t,x,b);
472     swf_SetBits(t,y,b);
473     return 0;
474   }
475
476   if (x==0)
477   { b = swf_CountBits(y,2);
478     if(b<2) 
479         b=2;
480     if(b-2 >= 16) {
481         fprintf(stderr, "Bit overflow in swf_ShapeSetLine(2)- %d\n", b);
482         b = 17;
483     }
484     swf_SetBits(t, b-2, 4);
485     swf_SetBits(t,1,2);
486     swf_SetBits(t,y,b);
487   } 
488   else
489   { b = swf_CountBits(x,2);
490     if(b<2) 
491         b=2;
492     if(b-2 >= 16) {
493         fprintf(stderr, "Bit overflow in swf_ShapeSetLine(3)- %d\n", b);
494         b = 17;
495     }
496     swf_SetBits(t, b-2, 4);
497     swf_SetBits(t,0,2);
498     swf_SetBits(t,x,b);
499   }
500   return 0;
501 }
502
503 int swf_ShapeSetCurve(TAG * t,SHAPE * s,S32 x,S32 y,S32 ax,S32 ay)
504 { U8 b;
505   if (!t) return -1;
506
507   swf_SetBits(t,2,2);
508
509   b = swf_CountBits(ax,2);
510   b = swf_CountBits(ay,b);
511   b = swf_CountBits(x,b);
512   b = swf_CountBits(y,b);
513
514   swf_SetBits(t,b-2,4);
515   swf_SetBits(t,x,b);
516   swf_SetBits(t,y,b);
517   swf_SetBits(t,ax,b);
518   swf_SetBits(t,ay,b);
519
520   return 0;
521 }
522
523 int swf_ShapeSetCircle(TAG * t,SHAPE * s,S32 x,S32 y,S32 rx,S32 ry)
524 { double C1 = 0.2930;    
525   double C2 = 0.4140;   
526   double begin = 0.7070; 
527
528   if (!t) return -1;
529   
530   swf_ShapeSetMove(t,s,x+begin*rx,y+begin*ry);
531   swf_ShapeSetCurve(t,s, -C1*rx,  C1*ry, -C2*rx,      0);
532   swf_ShapeSetCurve(t,s, -C2*rx,      0, -C1*rx, -C1*ry);
533   swf_ShapeSetCurve(t,s, -C1*rx, -C1*ry,      0, -C2*ry);
534   swf_ShapeSetCurve(t,s,      0, -C2*ry,  C1*rx, -C1*ry);
535   swf_ShapeSetCurve(t,s,  C1*rx, -C1*ry,  C2*rx,      0);
536   swf_ShapeSetCurve(t,s,  C2*rx,      0,  C1*rx,  C1*ry);
537   swf_ShapeSetCurve(t,s,  C1*rx,  C1*ry,      0,  C2*ry);
538   swf_ShapeSetCurve(t,s,      0,  C2*ry, -C1*rx,  C1*ry);
539   
540   return 0;
541 }
542
543 /* todo: merge this with swf_GetSimpleShape */
544 SHAPELINE* swf_ParseShapeData(U8*data, int bits, int fillbits, int linebits)
545 {
546     SHAPELINE _lines;
547     SHAPELINE*lines = &_lines;
548
549     TAG _tag;
550     TAG* tag = &_tag;
551     int fill0 = 0;
552     int fill1 = 0;
553     int line = 0;
554     int x=0,y=0;
555     
556     memset(tag, 0, sizeof(TAG));
557     tag->data = data;
558     tag->len = tag->memsize = (bits+7)/8;
559     tag->pos = 0;
560
561     lines->next = 0;
562     while(1) {
563         int flags;
564         flags = swf_GetBits(tag, 1);
565         if(!flags) { //style change
566             flags = swf_GetBits(tag, 5);
567             if(!flags)
568                 break;
569             if(flags&1) { //move
570                 int n = swf_GetBits(tag, 5); 
571                 x = swf_GetSBits(tag, n); //x
572                 y = swf_GetSBits(tag, n); //y
573             }
574             if(flags&2)
575                 fill0 = swf_GetBits(tag, fillbits); 
576             if(flags&4)
577                 fill1 = swf_GetBits(tag, fillbits); 
578             if(flags&8)
579                 line = swf_GetBits(tag, linebits); 
580             if(flags&16) {
581                 fprintf(stderr, "Additional file styles style change not yet supported\n");
582                 exit(1);
583                 //enumerateUsedIDs_styles(tag, callback, callback_data, num);
584                 fillbits = swf_GetBits(tag, 4);
585                 linebits = swf_GetBits(tag, 4);
586             }
587             if(flags&1) { //move
588                 lines->next = (SHAPELINE*)malloc(sizeof(SHAPELINE));
589                 lines = lines->next;
590                 lines->type = moveTo;
591                 lines->x = x; 
592                 lines->y = y; 
593                 lines->sx = lines->sy = 0;
594                 lines->fillstyle0 = fill0;
595                 lines->fillstyle1 = fill1;
596                 lines->linestyle = line;
597                 lines->next = 0;
598             }
599         } else {
600             flags = swf_GetBits(tag, 1);
601             if(flags) { //straight edge
602                 int n = swf_GetBits(tag, 4) + 2;
603                 if(swf_GetBits(tag, 1)) { //line flag
604                     x += swf_GetSBits(tag, n); //delta x
605                     y += swf_GetSBits(tag, n); //delta y
606                 } else {
607                     int v=swf_GetBits(tag, 1);
608                     int d;
609                     d = swf_GetSBits(tag, n); //vert/horz
610                     if(v) y += d;
611                     else  x += d;
612                 }
613                 lines->next = (SHAPELINE*)malloc(sizeof(SHAPELINE));
614                 lines = lines->next;
615                 lines->type = lineTo;
616                 lines->x = x; 
617                 lines->y = y; 
618                 lines->sx = lines->sy = 0;
619                 lines->fillstyle0 = fill0;
620                 lines->fillstyle1 = fill1;
621                 lines->linestyle = line;
622                 lines->next = 0;
623             } else { //curved edge
624                 int n = swf_GetBits(tag, 4) + 2;
625                 int x1,y1;
626                 x += swf_GetSBits(tag, n);
627                 y += swf_GetSBits(tag, n);
628                 x1 = x;
629                 y1 = y;
630                 x += swf_GetSBits(tag, n);
631                 y += swf_GetSBits(tag, n);
632
633                 lines->next = (SHAPELINE*)malloc(sizeof(SHAPELINE));
634                 lines = lines->next;
635                 lines->type = splineTo;
636                 lines->sx = x1; 
637                 lines->sy = y1; 
638                 lines->x = x; 
639                 lines->y = y; 
640                 lines->fillstyle0 = fill0;
641                 lines->fillstyle1 = fill1;
642                 lines->linestyle = line;
643                 lines->next = 0;
644             }
645         }
646     }
647     return _lines.next;
648 }
649
650 SRECT swf_GetShapeBoundingBox(SHAPE2*shape2)
651 {
652     SRECT r;
653     SHAPELINE*l = shape2->lines;
654     int SCOORD_MAX = 0x7fffffff;
655     int SCOORD_MIN = -0x80000000;
656     int lastx=0,lasty=0;
657     int valid = 0;
658     r.xmin = r.ymin = SCOORD_MAX;
659     r.xmax = r.ymax = SCOORD_MIN;
660
661     while(l) {
662         int t1;
663         if(l->linestyle>0) {
664             t1 = shape2->linestyles[l->linestyle - 1].width*3/2;
665         } else {
666             t1 = 0;
667         }
668
669         if(l->type == lineTo || l->type == splineTo)
670         {
671             valid = 1;
672             if(lastx - t1 < r.xmin) r.xmin = lastx - t1;
673             if(lasty - t1 < r.ymin) r.ymin = lasty - t1;
674             if(lastx + t1 > r.xmax) r.xmax = lastx + t1;
675             if(lasty + t1 > r.ymax) r.ymax = lasty + t1;
676             if(l->x - t1 < r.xmin) r.xmin = l->x - t1;
677             if(l->y - t1 < r.ymin) r.ymin = l->y - t1;
678             if(l->x + t1 > r.xmax) r.xmax = l->x + t1;
679             if(l->y + t1 > r.ymax) r.ymax = l->y + t1;
680             if(l->type == splineTo) {
681                 if(l->sx - t1 < r.xmin) r.xmin = l->sx - t1;
682                 if(l->sy - t1 < r.ymin) r.ymin = l->sy - t1;
683                 if(l->sx + t1 > r.xmax) r.xmax = l->sx + t1;
684                 if(l->sy + t1 > r.ymax) r.ymax = l->sy + t1;
685             }
686         }
687         lastx = l->x;
688         lasty = l->y;
689         l = l->next;
690     }
691     if(!valid) memset(&r, 0, sizeof(SRECT));
692     return r;
693 }
694
695 void swf_Shape2Free(SHAPE2 * s)
696 {
697     SHAPELINE*line = s->lines;
698     while(line) {
699         SHAPELINE*next = line->next;
700         free(line);
701         line = next;
702     }
703     if(s->linestyles)
704         free(s->linestyles);
705     if(s->fillstyles)
706         free(s->fillstyles);
707     if(s->bbox)
708         free(s->bbox);
709 }
710
711 SHAPE2* swf_ShapeToShape2(SHAPE*shape) {
712
713     SHAPE2*shape2 = (SHAPE2*)malloc(sizeof(SHAPE2));
714     
715     shape2->numlinestyles = shape->linestyle.n;
716     shape2->linestyles = (LINESTYLE*)malloc(sizeof(LINESTYLE)*shape->linestyle.n);
717     memcpy(shape2->linestyles, shape->linestyle.data, sizeof(LINESTYLE)*shape->linestyle.n);
718     
719     shape2->numfillstyles = shape->fillstyle.n;
720     shape2->fillstyles = (FILLSTYLE*)malloc(sizeof(FILLSTYLE)*shape->fillstyle.n);
721     memcpy(shape2->fillstyles, shape->fillstyle.data, sizeof(FILLSTYLE)*shape->fillstyle.n);
722
723     shape2->lines = swf_ParseShapeData(shape->data, shape->bitlen, shape->bits.fill, shape->bits.line);
724     shape2->bbox = 0;
725     return shape2;
726 };
727
728 void swf_ShapeSetBitmapRect(TAG*tag, U16 gfxid, int width, int height)
729 {
730     SHAPE*shape;
731     MATRIX m;
732     RGBA rgb;
733     SRECT r;
734     int lines = 0;
735     int ls,fs;
736     swf_ShapeNew(&shape);
737     rgb.b = rgb.g = rgb.r = 0xff;
738     if(lines)
739         ls = swf_ShapeAddLineStyle(shape,20,&rgb);  
740     swf_GetMatrix(NULL,&m);
741     m.sx = 20*65536;
742     m.sy = 20*65536;
743
744     fs = swf_ShapeAddBitmapFillStyle(shape,&m,gfxid,0);
745     r.xmin = 0;
746     r.ymin = 0;
747     r.xmax = width*20;
748     r.ymax = height*20;
749     swf_SetRect(tag,&r);
750
751     swf_SetShapeStyles(tag,shape);
752     swf_ShapeCountBits(shape,NULL,NULL);
753     swf_SetShapeBits(tag,shape);
754
755     swf_ShapeSetAll(tag,shape,0,0,lines?ls:0,fs,0);
756
757     swf_ShapeSetLine(tag,shape,width*20,0);
758     swf_ShapeSetLine(tag,shape,0,height*20);
759     swf_ShapeSetLine(tag,shape,-width*20,0);
760     swf_ShapeSetLine(tag,shape,0,-height*20);
761     swf_ShapeSetEnd(tag);
762     swf_ShapeFree(shape);
763 }
764