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