* changed interface to pdf2swf.cc
[swftools.git] / pdf2swf / SWFOutputDev.cc
1 /* pdfswf.cc
2    implements a pdf output device (OutputDev).
3
4    This file is part of swftools.
5
6    Swftools is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    Swftools is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with swftools; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stddef.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include "../config.h"
26 #ifdef HAVE_FONTCONFIG_H
27 #include <fontconfig.h>
28 #endif
29 //xpdf header files
30 #include "config.h"
31 #include "gfile.h"
32 #include "GString.h"
33 #include "gmem.h"
34 #include "Object.h"
35 #include "Stream.h"
36 #include "Array.h"
37 #include "Dict.h"
38 #include "XRef.h"
39 #include "Catalog.h"
40 #include "Page.h"
41 #include "PDFDoc.h"
42 #include "Error.h"
43 #include "OutputDev.h"
44 #include "GfxState.h"
45 #include "GfxFont.h"
46 #include "CharCodeToUnicode.h"
47 #include "NameToUnicodeTable.h"
48 #include "GlobalParams.h"
49 //#define XPDF_101
50 #ifdef XPDF_101
51 #include "FontFile.h"
52 #else
53 #include "FoFiType1C.h"
54 #include "FoFiTrueType.h"
55 #endif
56 #include "SWFOutputDev.h"
57
58 //swftools header files
59 #include "swfoutput.h"
60 #include "../lib/log.h"
61
62 #include <math.h>
63
64 typedef struct _fontfile
65 {
66     char*filename;
67     int used;
68 } fontfile_t;
69
70 // for pdfswf_addfont
71 static fontfile_t fonts[2048];
72 static int fontnum = 0;
73
74 // swf <-> pdf pages
75 // TODO: move into pdf_doc_t
76 static int*pages = 0;
77 static int pagebuflen = 0;
78 static int pagepos = 0;
79
80 /* config */
81 static double caplinewidth = 3.0;
82 static int zoom = 72; /* xpdf: 86 */
83
84 static void printInfoString(Dict *infoDict, char *key, char *fmt);
85 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
86
87 struct mapping {
88     char*pdffont;
89     char*filename;
90 } pdf2t1map[] ={
91 {"Times-Roman",           "n021003l"},
92 {"Times-Italic",          "n021023l"},
93 {"Times-Bold",            "n021004l"},
94 {"Times-BoldItalic",      "n021024l"},
95 {"Helvetica",             "n019003l"},
96 {"Helvetica-Oblique",     "n019023l"},
97 {"Helvetica-Bold",        "n019004l"},
98 {"Helvetica-BoldOblique", "n019024l"},
99 {"Courier",               "n022003l"},
100 {"Courier-Oblique",       "n022023l"},
101 {"Courier-Bold",          "n022004l"},
102 {"Courier-BoldOblique",   "n022024l"},
103 {"Symbol",                "s050000l"},
104 {"ZapfDingbats",          "d050000l"}};
105
106 class SWFOutputDev:  public OutputDev {
107   struct swfoutput output;
108   int outputstarted;
109 public:
110
111   // Constructor.
112   SWFOutputDev();
113
114   // Destructor.
115   virtual ~SWFOutputDev() ;
116   
117   void save(char*filename);
118
119   //----- get info about output device
120
121   // Does this device use upside-down coordinates?
122   // (Upside-down means (0,0) is the top left corner of the page.)
123   virtual GBool upsideDown();
124
125   // Does this device use drawChar() or drawString()?
126   virtual GBool useDrawChar();
127   
128   // Can this device draw gradients?
129   virtual GBool useGradients();
130   
131   virtual GBool interpretType3Chars() {return gTrue;}
132
133   //----- initialization and control
134
135   void setXRef(PDFDoc*doc, XRef *xref);
136
137   // Start a page.
138   virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
139
140   //----- link borders
141   virtual void drawLink(Link *link, Catalog *catalog) ;
142
143   //----- save/restore graphics state
144   virtual void saveState(GfxState *state) ;
145   virtual void restoreState(GfxState *state) ;
146
147   //----- update graphics state
148
149   virtual void updateFont(GfxState *state);
150   virtual void updateFillColor(GfxState *state);
151   virtual void updateStrokeColor(GfxState *state);
152   virtual void updateLineWidth(GfxState *state);
153   virtual void updateLineJoin(GfxState *state);
154   virtual void updateLineCap(GfxState *state);
155   
156   virtual void updateAll(GfxState *state) 
157   {
158       updateFont(state);
159       updateFillColor(state);
160       updateStrokeColor(state);
161       updateLineWidth(state);
162       updateLineJoin(state);
163       updateLineCap(state);
164   };
165
166   //----- path painting
167   virtual void stroke(GfxState *state) ;
168   virtual void fill(GfxState *state) ;
169   virtual void eoFill(GfxState *state) ;
170
171   //----- path clipping
172   virtual void clip(GfxState *state) ;
173   virtual void eoClip(GfxState *state) ;
174
175   //----- text drawing
176   virtual void beginString(GfxState *state, GString *s) ;
177   virtual void endString(GfxState *state) ;
178   virtual void drawChar(GfxState *state, double x, double y,
179                         double dx, double dy,
180                         double originX, double originY,
181                         CharCode code, Unicode *u, int uLen);
182
183   //----- image drawing
184   virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
185                              int width, int height, GBool invert,
186                              GBool inlineImg);
187   virtual void drawImage(GfxState *state, Object *ref, Stream *str,
188                          int width, int height, GfxImageColorMap *colorMap,
189                          int *maskColors, GBool inlineImg);
190   
191   virtual GBool beginType3Char(GfxState *state,
192                                CharCode code, Unicode *u, int uLen);
193   virtual void endType3Char(GfxState *state);
194
195   private:
196   void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
197                                    int width, int height, GfxImageColorMap*colorMap, GBool invert,
198                                    GBool inlineImg, int mask);
199   int clipping[64];
200   int clippos;
201
202   int currentpage;
203
204   PDFDoc*doc;
205   XRef*xref;
206
207   char* searchFont(char*name);
208   char* substituteFont(GfxFont*gfxFont, char*oldname);
209   char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
210   int t1id;
211   int jpeginfo; // did we write "File contains jpegs" yet?
212   int pbminfo; // did we write "File contains jpegs" yet?
213   int linkinfo; // did we write "File contains links" yet?
214   int ttfinfo; // did we write "File contains TrueType Fonts" yet?
215   int gradientinfo; // did we write "File contains Gradients yet?
216
217   int type3active; // are we between beginType3()/endType3()?
218
219   GfxState *laststate;
220
221   int pic_xids[1024];
222   int pic_yids[1024];
223   int pic_ids[1024];
224   int pic_width[1024];
225   int pic_height[1024];
226   int picpos;
227   int pic_id;
228   char type3Warning;
229
230   char* substitutetarget[256];
231   char* substitutesource[256];
232   int substitutepos;
233 };
234
235 static char*getFontID(GfxFont*font);
236
237 class InfoOutputDev:  public OutputDev 
238 {
239   public:
240   int x1,y1,x2,y2;
241   int has_links;
242   int has_images;
243
244   InfoOutputDev() 
245   {
246       has_links = 0;
247       has_images = 0;
248   }
249   virtual ~InfoOutputDev() {}
250   virtual GBool upsideDown() {return gTrue;}
251   virtual GBool useDrawChar() {return gTrue;}
252   virtual GBool useGradients() {return gTrue;}
253   virtual GBool interpretType3Chars() {return gTrue;}
254   virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
255   {
256       double x1,y1,x2,y2;
257       state->transform(crop_x1,crop_y1,&x1,&y1);
258       state->transform(crop_x2,crop_y2,&x2,&y2);
259       if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
260       if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
261       this->x1 = (int)x1;
262       this->y1 = (int)y1;
263       this->x2 = (int)x2;
264       this->y2 = (int)y2;
265   }
266   virtual void drawLink(Link *link, Catalog *catalog) 
267   {
268       has_links = 1;
269   }
270   virtual void updateFont(GfxState *state) 
271   {
272       char*id = getFontID(state->getFont());
273   }
274   virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
275                              int width, int height, GBool invert,
276                              GBool inlineImg) 
277   {
278       has_images = 1;
279   }
280   virtual void drawImage(GfxState *state, Object *ref, Stream *str,
281                          int width, int height, GfxImageColorMap *colorMap,
282                          int *maskColors, GBool inlineImg)
283   {
284       has_images = 1;
285   }
286 };
287
288 SWFOutputDev::SWFOutputDev()
289 {
290     jpeginfo = 0;
291     ttfinfo = 0;
292     linkinfo = 0;
293     pbminfo = 0;
294     type3active = 0;
295     clippos = 0;
296     clipping[clippos] = 0;
297     outputstarted = 0;
298     xref = 0;
299     picpos = 0;
300     pic_id = 0;
301     substitutepos = 0;
302     type3Warning = 0;
303 //    printf("SWFOutputDev::SWFOutputDev() \n");
304 };
305
306 static char*getFontID(GfxFont*font)
307 {
308     GString*gstr = font->getName();
309     char* fontname = gstr==0?0:gstr->getCString();
310     if(fontname==0) {
311         char buf[32];
312         Ref*r=font->getID();
313         sprintf(buf, "UFONT%d", r->num);
314         return strdup(buf);
315     }
316     return strdup(fontname);
317 }
318
319 static char*getFontName(GfxFont*font)
320 {
321     char*fontid = getFontID(font);
322     char*fontname= 0;
323     char* plus = strchr(fontid, '+');
324     if(plus && plus < &fontid[strlen(fontid)-1]) {
325         fontname = strdup(plus+1);
326     } else {
327         fontname = strdup(fontid);
328     }
329     free(fontid);
330     return fontname;
331 }
332
333 static char mybuf[1024];
334 static char* gfxstate2str(GfxState *state)
335 {
336   char*bufpos = mybuf;
337   GfxRGB rgb;
338   bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
339                                     state->getCTM()[0],
340                                     state->getCTM()[1],
341                                     state->getCTM()[2],
342                                     state->getCTM()[3],
343                                     state->getCTM()[4],
344                                     state->getCTM()[5]);
345   if(state->getX1()!=0.0)
346   bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
347   if(state->getY1()!=0.0)
348   bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
349   bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
350   bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
351   bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
352   bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
353   /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
354           state->getFillColor()->c[0], state->getFillColor()->c[1]);
355   bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
356           state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
357 /*  bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
358           state->getFillColor()->c[0], state->getFillColor()->c[1],
359           state->getFillColor()->c[2], state->getFillColor()->c[3],
360           state->getFillColor()->c[4], state->getFillColor()->c[5],
361           state->getFillColor()->c[6], state->getFillColor()->c[7]);
362   bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
363           state->getStrokeColor()->c[0], state->getFillColor()->c[1],
364           state->getStrokeColor()->c[2], state->getFillColor()->c[3],
365           state->getStrokeColor()->c[4], state->getFillColor()->c[5],
366           state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
367   state->getFillRGB(&rgb);
368   if(rgb.r || rgb.g || rgb.b)
369   bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
370   state->getStrokeRGB(&rgb);
371   if(rgb.r || rgb.g || rgb.b)
372   bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
373   if(state->getFillColorSpace()->getNComps()>1)
374   bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
375   if(state->getStrokeColorSpace()->getNComps()>1)
376   bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
377   if(state->getFillPattern())
378   bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
379   if(state->getStrokePattern())
380   bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
381  
382   if(state->getFillOpacity()!=1.0)
383   bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
384   if(state->getStrokeOpacity()!=1.0)
385   bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
386
387   bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
388  
389   double * dash;
390   int length;
391   double start;
392   state->getLineDash(&dash, &length, &start);
393   int t;
394   if(length)
395   {
396       bufpos+=sprintf(bufpos,"DASH%.1f[",start);
397       for(t=0;t<length;t++) {
398           bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
399       }
400       bufpos+=sprintf(bufpos,"]");
401   }
402
403   if(state->getFlatness()!=1)
404   bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
405   if(state->getLineJoin()!=0)
406   bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
407   if(state->getLineJoin()!=0)
408   bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
409   if(state->getLineJoin()!=0)
410   bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
411
412   if(state->getFont() && getFontID(state->getFont()))
413   bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
414   bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
415   bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
416                                    state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
417   if(state->getCharSpace())
418   bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
419   if(state->getWordSpace())
420   bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
421   if(state->getHorizScaling()!=1.0)
422   bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
423   if(state->getLeading())
424   bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
425   if(state->getRise())
426   bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
427   if(state->getRender())
428   bufpos+=sprintf(bufpos,"R%d ", state->getRender());
429   bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
430   bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
431   bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
432   if(state->getLineX())
433   bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
434   if(state->getLineY())
435   bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
436   bufpos+=sprintf(bufpos," ");
437   return mybuf;
438 }
439
440 static void dumpFontInfo(char*loglevel, GfxFont*font);
441 static int lastdumps[1024];
442 static int lastdumppos = 0;
443 /* nr = 0  unknown
444    nr = 1  substituting
445    nr = 2  type 3
446  */
447 static void showFontError(GfxFont*font, int nr) 
448 {  
449     Ref*r=font->getID();
450     int t;
451     for(t=0;t<lastdumppos;t++)
452         if(lastdumps[t] == r->num)
453             break;
454     if(t < lastdumppos)
455       return;
456     if(lastdumppos<sizeof(lastdumps)/sizeof(int))
457     lastdumps[lastdumppos++] = r->num;
458     if(nr == 0)
459       msg("<warning> The following font caused problems:");
460     else if(nr == 1)
461       msg("<warning> The following font caused problems (substituting):");
462     else if(nr == 2)
463       msg("<warning> The following Type 3 Font will be rendered as bitmap:");
464     dumpFontInfo("<warning>", font);
465 }
466
467 static void dumpFontInfo(char*loglevel, GfxFont*font)
468 {
469   char* name = getFontID(font);
470   Ref* r=font->getID();
471   msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, getFontName(font), r->num,r->gen);
472
473   GString*gstr  = font->getTag();
474    
475   msg("%s| Tag: %s\n", loglevel, name);
476   
477   if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
478
479   GfxFontType type=font->getType();
480   switch(type) {
481     case fontUnknownType:
482      msg("%s| Type: unknown\n",loglevel);
483     break;
484     case fontType1:
485      msg("%s| Type: 1\n",loglevel);
486     break;
487     case fontType1C:
488      msg("%s| Type: 1C\n",loglevel);
489     break;
490     case fontType3:
491      msg("%s| Type: 3\n",loglevel);
492     break;
493     case fontTrueType:
494      msg("%s| Type: TrueType\n",loglevel);
495     break;
496     case fontCIDType0:
497      msg("%s| Type: CIDType0\n",loglevel);
498     break;
499     case fontCIDType0C:
500      msg("%s| Type: CIDType0C\n",loglevel);
501     break;
502     case fontCIDType2:
503      msg("%s| Type: CIDType2\n",loglevel);
504     break;
505   }
506   
507   Ref embRef;
508   GBool embedded = font->getEmbeddedFontID(&embRef);
509   if(font->getEmbeddedFontName())
510     name = font->getEmbeddedFontName()->getCString();
511   if(embedded)
512    msg("%s| Embedded name: %s id: %d\n",loglevel, FIXNULL(name), embRef.num);
513
514   gstr = font->getExtFontFile();
515   if(gstr)
516    msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
517
518   // Get font descriptor flags.
519   if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
520   if(font->isSerif()) msg("%s| is serif\n", loglevel);
521   if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
522   if(font->isItalic()) msg("%s| is italic\n", loglevel);
523   if(font->isBold()) msg("%s| is bold\n", loglevel);
524 }
525
526 //void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) {printf("void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) \n");}
527 //void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool inlineImg) {printf("void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool inlineImg) \n");}
528
529 static void free_outline(SWF_OUTLINE*outline)
530 {
531     while(outline) {
532         SWF_OUTLINE*next = outline->link;
533         free(outline);
534         outline = next;
535     }
536 }
537
538 static void dump_outline(SWF_OUTLINE*outline)
539 {
540     double x=0,y=0;
541     while(outline) {
542         double lastx=x,lasty=y;
543         x += (outline->dest.x/(float)0xffff);
544         y += (outline->dest.y/(float)0xffff);
545         if(outline->type == SWF_PATHTYPE_MOVE) {
546             msg("<trace> | moveto %f,%f", x,y);
547         } else if(outline->type == SWF_PATHTYPE_LINE) {
548             msg("<trace> | lineto: %f,%f\n",x,y);
549         } else if(outline->type == SWF_PATHTYPE_BEZIER) {
550             SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
551             float x1 = o2->C.x/(float)0xffff+lastx;
552             float y1 = o2->C.y/(float)0xffff+lasty;
553             float x2 = o2->B.x/(float)0xffff+lastx;
554             float y2 = o2->B.y/(float)0xffff+lasty;
555             msg("<trace> | spline: %f,%f -> %f,%f -> %f,%f\n",x1,y1,x2,y2,x,y);
556         } 
557         outline = outline->link;
558     }
559 }
560
561 SWF_OUTLINE* gfxPath_to_SWF_OUTLINE(GfxState*state, GfxPath*path)
562 {
563     int num = path->getNumSubpaths();
564     int s,t;
565     bezierpathsegment*start,*last=0;
566     bezierpathsegment*outline = start = (bezierpathsegment*)malloc(sizeof(bezierpathsegment));
567     int cpos = 0;
568     double lastx=0,lasty=0;
569     if(!num) {
570         msg("<warning> empty path");
571         outline->type = SWF_PATHTYPE_MOVE;
572         outline->dest.x = 0;
573         outline->dest.y = 0;
574         outline->link = 0;
575         return (SWF_OUTLINE*)outline;
576     }
577     for(t = 0; t < num; t++) {
578         GfxSubpath *subpath = path->getSubpath(t);
579         int subnum = subpath->getNumPoints();
580
581         for(s=0;s<subnum;s++) {
582            double nx,ny;
583            state->transform(subpath->getX(s),subpath->getY(s),&nx,&ny);
584            int x = (int)((nx-lastx)*0xffff);
585            int y = (int)((ny-lasty)*0xffff);
586            if(s==0) 
587            {
588                 last = outline;
589                 outline->type = SWF_PATHTYPE_MOVE;
590                 outline->dest.x = x;
591                 outline->dest.y = y;
592                 outline->link = (SWF_OUTLINE*)malloc(sizeof(bezierpathsegment));
593                 outline = (bezierpathsegment*)outline->link;
594                 cpos = 0;
595                 lastx = nx;
596                 lasty = ny;
597            }
598            else if(subpath->getCurve(s) && !cpos)
599            {
600                 outline->B.x = x;
601                 outline->B.y = y;
602                 cpos = 1;
603            } 
604            else if(subpath->getCurve(s) && cpos)
605            {
606                 outline->C.x = x;
607                 outline->C.y = y;
608                 cpos = 2;
609            }
610            else
611            {
612                 last = outline;
613                 outline->dest.x = x;
614                 outline->dest.y = y;
615                 outline->type = cpos?SWF_PATHTYPE_BEZIER:SWF_PATHTYPE_LINE;
616                 outline->link = (SWF_OUTLINE*)malloc(sizeof(bezierpathsegment));
617                 outline = (bezierpathsegment*)outline->link;
618                 cpos = 0;
619                 lastx = nx;
620                 lasty = ny;
621            }
622         }
623     }
624     if(last->link) {free(last->link);}
625     last->link = 0;
626
627     return (SWF_OUTLINE*)start;
628 }
629 /*----------------------------------------------------------------------------
630  * Primitive Graphic routines
631  *----------------------------------------------------------------------------*/
632
633 void SWFOutputDev::stroke(GfxState *state) 
634 {
635     GfxPath * path = state->getPath();
636     int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
637     int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
638     double miterLimit = state->getMiterLimit();
639     double width = state->getTransformedLineWidth();
640     struct swfmatrix m;
641     GfxRGB rgb;
642     double opaq = state->getStrokeOpacity();
643     state->getStrokeRGB(&rgb);
644
645     m.m11 = 1; m.m21 = 0; m.m22 = 1;
646     m.m12 = 0; m.m13 = 0; m.m23 = 0;
647     SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
648     
649     if(screenloglevel >= LOGLEVEL_TRACE)  {
650         msg("<trace> stroke\n");
651         dump_outline(outline);
652     }
653
654     lineJoin = 1; // other line joins are not yet supported by the swf encoder
655                   // TODO: support bevel joints
656
657     if(((lineCap==1) && (lineJoin==1)) || width<=caplinewidth) {
658         /* FIXME- if the path is smaller than 2 segments, we could ignore
659            lineJoin */
660         swfoutput_setdrawmode(&output, DRAWMODE_STROKE);
661         swfoutput_drawpath(&output, outline, &m);
662     } else {
663         swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), 
664                                         (char)(rgb.b*255), (char)(opaq*255));
665
666         //swfoutput_setlinewidth(&output, 1.0); //only for debugging
667         //swfoutput_setstrokecolor(&output, 0, 255, 0, 255); //likewise, see below
668         //swfoutput_setfillcolor(&output, 255, 0, 0, 255); //likewise, see below
669
670         swfoutput_drawpath2poly(&output, outline, &m, lineJoin, lineCap, width, miterLimit);
671         updateLineWidth(state);  //reset
672         updateStrokeColor(state); //reset
673         updateFillColor(state);  //reset
674     }
675     free_outline(outline);
676 }
677 void SWFOutputDev::fill(GfxState *state) 
678 {
679     GfxPath * path = state->getPath();
680     struct swfmatrix m;
681     m.m11 = 1; m.m21 = 0; m.m22 = 1;
682     m.m12 = 0; m.m13 = 0; m.m23 = 0;
683     SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
684
685     if(screenloglevel >= LOGLEVEL_TRACE)  {
686         msg("<trace> fill\n");
687         dump_outline(outline);
688     }
689
690     swfoutput_setdrawmode(&output, DRAWMODE_FILL);
691     swfoutput_drawpath(&output, outline, &m);
692     free_outline(outline);
693 }
694 void SWFOutputDev::eoFill(GfxState *state) 
695 {
696     GfxPath * path = state->getPath();
697     struct swfmatrix m;
698     m.m11 = 1; m.m21 = 0; m.m22 = 1;
699     m.m12 = 0; m.m13 = 0; m.m23 = 0;
700     SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
701
702     if(screenloglevel >= LOGLEVEL_TRACE)  {
703         msg("<trace> eofill\n");
704         dump_outline(outline);
705     }
706
707     swfoutput_setdrawmode(&output, DRAWMODE_EOFILL);
708     swfoutput_drawpath(&output, outline, &m);
709     free_outline(outline);
710 }
711 void SWFOutputDev::clip(GfxState *state) 
712 {
713     GfxPath * path = state->getPath();
714     struct swfmatrix m;
715     m.m11 = 1; m.m22 = 1;
716     m.m12 = 0; m.m21 = 0; 
717     m.m13 = 0; m.m23 = 0;
718     SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
719
720     if(screenloglevel >= LOGLEVEL_TRACE)  {
721         msg("<trace> clip\n");
722         dump_outline(outline);
723     }
724
725     swfoutput_startclip(&output, outline, &m);
726     clipping[clippos] ++;
727     free_outline(outline);
728 }
729 void SWFOutputDev::eoClip(GfxState *state) 
730 {
731     GfxPath * path = state->getPath();
732     struct swfmatrix m;
733     m.m11 = 1; m.m21 = 0; m.m22 = 1;
734     m.m12 = 0; m.m13 = 0; m.m23 = 0;
735     SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
736
737     if(screenloglevel >= LOGLEVEL_TRACE)  {
738         msg("<trace> eoclip\n");
739         dump_outline(outline);
740     }
741
742     swfoutput_startclip(&output, outline, &m);
743     clipping[clippos] ++;
744     free_outline(outline);
745 }
746 void SWFOutputDev::save(char*filename)
747 {
748     swfoutput_save(&output, filename);
749 }
750
751 SWFOutputDev::~SWFOutputDev() 
752 {
753     swfoutput_destroy(&output);
754     outputstarted = 0;
755 };
756 GBool SWFOutputDev::upsideDown() 
757 {
758     msg("<debug> upsidedown? yes");
759     return gTrue;
760 };
761 GBool SWFOutputDev::useDrawChar() 
762 {
763     return gTrue;
764 }
765 GBool SWFOutputDev::useGradients()
766 {
767     if(!gradientinfo)
768     {
769         msg("<notice> File contains gradients");
770         gradientinfo = 1;
771     }
772     return gTrue;
773 }
774
775 void SWFOutputDev::beginString(GfxState *state, GString *s) 
776
777     double m11,m21,m12,m22;
778 //    msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
779     state->getFontTransMat(&m11, &m12, &m21, &m22);
780     m11 *= state->getHorizScaling();
781     m21 *= state->getHorizScaling();
782     swfoutput_setfontmatrix(&output, m11, -m21, m12, -m22);
783 }
784
785 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
786                         double dx, double dy,
787                         double originX, double originY,
788                         CharCode c, Unicode *_u, int uLen)
789 {
790     // check for invisible text -- this is used by Acrobat Capture
791     if ((state->getRender() & 3) == 3)
792         return;
793
794     GfxFont*font = state->getFont();
795
796     if(font->getType() == fontType3) {
797         /* type 3 chars are passed as graphics */
798         return;
799     }
800     double x1,y1;
801     x1 = x;
802     y1 = y;
803     state->transform(x, y, &x1, &y1);
804     
805     Unicode u=0;
806     if(_u && uLen) 
807         u = *_u;
808
809     /* find out the character name */
810     char*name=0;
811     if(font->isCIDFont() && u) {
812         GfxCIDFont*cfont = (GfxCIDFont*)font;
813         int t;
814         for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
815             /* todo: should be precomputed */
816             if(nameToUnicodeTab[t].u == u) {
817                 name = nameToUnicodeTab[t].name;
818                 break;
819             }
820         }
821     } else {
822         Gfx8BitFont*font8;
823         font8 = (Gfx8BitFont*)font;
824         char**enc=font8->getEncoding();
825         if(enc && enc[c])
826            name = enc[c];
827     }
828     
829     msg("<debug> drawChar(%f,%f,c='%c' (%d),u=%d <%d>) CID=%d name=\"%s\"\n",x,y,(c&127)>=32?c:'?',c,u, uLen, font->isCIDFont(), FIXNULL(name));
830
831     /*x1 = (int)(x1+0.5);
832     y1 = (int)(y1+0.5);*/
833     
834     int ret = swfoutput_drawchar(&output, x1, y1, name, c, u);
835 }
836
837 void SWFOutputDev::endString(GfxState *state) { 
838 }    
839
840  
841 GBool SWFOutputDev::beginType3Char(GfxState *state,
842                                CharCode code, Unicode *u, int uLen)
843 {
844     msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
845     type3active = 1;
846     /* the character itself is going to be passed using
847        drawImageMask() */
848     return gFalse; /* gTrue= is_in_cache? */
849 }
850
851 void SWFOutputDev::endType3Char(GfxState *state)
852 {
853     type3active = 0;
854     msg("<debug> endType3Char");
855 }
856
857 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2) 
858 {
859     this->currentpage = pageNum;
860     double x1,y1,x2,y2;
861     int rot = doc->getPageRotate(1);
862     laststate = state;
863     msg("<verbose> startPage %d (%f,%f,%f,%f)\n", pageNum, crop_x1, crop_y1, crop_x2, crop_y2);
864     if(rot!=0)
865         msg("<verbose> page is rotated %d degrees\n", rot);
866
867     /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
868     state->transform(state->getX2(),state->getY2(),&x2,&y2);
869     Use CropBox, not MediaBox, as page size
870     */
871     
872     /*x1 = crop_x1;
873     y1 = crop_y1;
874     x2 = crop_x2;
875     y2 = crop_y2;*/
876     state->transform(crop_x1,crop_y1,&x1,&y1);
877     state->transform(crop_x2,crop_y2,&x2,&y2);
878
879     if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
880     if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
881
882     if(!outputstarted) {
883         msg("<verbose> Bounding box is (%f,%f)-(%f,%f)", x1,y1,x2,y2);
884         swfoutput_init(&output);
885         outputstarted = 1;
886     }
887       
888     swfoutput_newpage(&output, pageNum, (int)x1, (int)y1, (int)x2, (int)y2);
889 }
890
891 void SWFOutputDev::drawLink(Link *link, Catalog *catalog) 
892 {
893     msg("<debug> drawlink\n");
894     double x1, y1, x2, y2, w;
895     GfxRGB rgb;
896     swfcoord points[5];
897     int x, y;
898
899 #ifdef XPDF_101
900     link->getBorder(&x1, &y1, &x2, &y2, &w);
901 #else
902     link->getRect(&x1, &y1, &x2, &y2);
903 #endif
904     rgb.r = 0;
905     rgb.g = 0;
906     rgb.b = 1;
907     cvtUserToDev(x1, y1, &x, &y);
908     points[0].x = points[4].x = (int)x;
909     points[0].y = points[4].y = (int)y;
910     cvtUserToDev(x2, y1, &x, &y);
911     points[1].x = (int)x;
912     points[1].y = (int)y;
913     cvtUserToDev(x2, y2, &x, &y);
914     points[2].x = (int)x;
915     points[2].y = (int)y;
916     cvtUserToDev(x1, y2, &x, &y);
917     points[3].x = (int)x;
918     points[3].y = (int)y;
919
920     LinkAction*action=link->getAction();
921     char buf[128];
922     char*s = 0;
923     char*type = "-?-";
924     char*url = 0;
925     char*named = 0;
926     int page = -1;
927     switch(action->getKind())
928     {
929         case actionGoTo: {
930             type = "GoTo";
931             LinkGoTo *ha=(LinkGoTo *)link->getAction();
932             LinkDest *dest=NULL;
933             if (ha->getDest()==NULL) 
934                 dest=catalog->findDest(ha->getNamedDest());
935             else dest=ha->getDest();
936             if (dest){ 
937               if (dest->isPageRef()){
938                 Ref pageref=dest->getPageRef();
939                 page=catalog->findPage(pageref.num,pageref.gen);
940               }
941               else  page=dest->getPageNum();
942               sprintf(buf, "%d", page);
943               s = strdup(buf);
944             }
945         }
946         break;
947         case actionGoToR: {
948             type = "GoToR";
949             LinkGoToR*l = (LinkGoToR*)action;
950             GString*g = l->getNamedDest();
951             if(g)
952              s = strdup(g->getCString());
953         }
954         break;
955         case actionNamed: {
956             type = "Named";
957             LinkNamed*l = (LinkNamed*)action;
958             GString*name = l->getName();
959             if(name) {
960                 s = strdup(name->lowerCase()->getCString());
961                 named = name->getCString();
962                 if(!strchr(s,':')) 
963                 {
964                     if(strstr(s, "next") || strstr(s, "forward"))
965                     {
966                         page = currentpage + 1;
967                     }
968                     else if(strstr(s, "prev") || strstr(s, "back"))
969                     {
970                         page = currentpage - 1;
971                     }
972                     else if(strstr(s, "last") || strstr(s, "end"))
973                     {
974                         page = pagepos>0?pages[pagepos-1]:0;
975                     }
976                     else if(strstr(s, "first") || strstr(s, "top"))
977                     {
978                         page = 1;
979                     }
980                 }
981             }
982         }
983         break;
984         case actionLaunch: {
985             type = "Launch";
986             LinkLaunch*l = (LinkLaunch*)action;
987             GString * str = new GString(l->getFileName());
988             str->append(l->getParams());
989             s = strdup(str->getCString());
990             delete str;
991         }
992         break;
993         case actionURI: {
994             type = "URI";
995             LinkURI*l = (LinkURI*)action;
996             GString*g = l->getURI();
997             if(g) {
998              url = g->getCString();
999              s = strdup(url);
1000             }
1001         }
1002         break;
1003         case actionUnknown: {
1004             type = "Unknown";
1005             LinkUnknown*l = (LinkUnknown*)action;
1006             s = strdup("");
1007         }
1008         break;
1009         default: {
1010             msg("<error> Unknown link type!\n");
1011             break;
1012         }
1013     }
1014     if(!s) s = strdup("-?-");
1015
1016     if(!linkinfo && (page || url))
1017     {
1018         msg("<notice> File contains links");
1019         linkinfo = 1;
1020     }
1021     if(page>0)
1022     {
1023         int t;
1024         for(t=0;t<pagepos;t++)
1025             if(pages[t]==page)
1026                 break;
1027         if(t!=pagepos)
1028             swfoutput_linktopage(&output, t, points);
1029     }
1030     else if(url)
1031     {
1032         swfoutput_linktourl(&output, url, points);
1033     }
1034     else if(named)
1035     {
1036         swfoutput_namedlink(&output, named, points);
1037     }
1038     msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1039     free(s);s=0;
1040 }
1041
1042 void SWFOutputDev::saveState(GfxState *state) {
1043   msg("<debug> saveState\n");
1044   updateAll(state);
1045   if(clippos<64)
1046     clippos ++;
1047   else
1048     msg("<error> Too many nested states in pdf.");
1049   clipping[clippos] = 0;
1050 };
1051
1052 void SWFOutputDev::restoreState(GfxState *state) {
1053   msg("<debug> restoreState\n");
1054   updateAll(state);
1055   while(clipping[clippos]) {
1056       swfoutput_endclip(&output);
1057       clipping[clippos]--;
1058   }
1059   clippos--;
1060 }
1061
1062 char* SWFOutputDev::searchFont(char*name) 
1063 {       
1064     int i;
1065     char*filename=0;
1066     int is_standard_font = 0;
1067         
1068     msg("<verbose> SearchFont(%s)", name);
1069
1070     /* see if it is a pdf standard font */
1071     for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++) 
1072     {
1073         if(!strcmp(name, pdf2t1map[i].pdffont))
1074         {
1075             name = pdf2t1map[i].filename;
1076             is_standard_font = 1;
1077             break;
1078         }
1079     }
1080     /* look in all font files */
1081     for(i=0;i<fontnum;i++) 
1082     {
1083         if(strstr(fonts[i].filename, name))
1084         {
1085             if(!fonts[i].used) {
1086
1087                 fonts[i].used = 1;
1088                 if(!is_standard_font)
1089                     msg("<notice> Using %s for %s", fonts[i].filename, name);
1090             }
1091             return strdup(fonts[i].filename);
1092         }
1093     }
1094     return 0;
1095 }
1096
1097 void SWFOutputDev::updateLineWidth(GfxState *state)
1098 {
1099     double width = state->getTransformedLineWidth();
1100     swfoutput_setlinewidth(&output, width);
1101 }
1102
1103 void SWFOutputDev::updateLineCap(GfxState *state)
1104 {
1105     int c = state->getLineCap();
1106 }
1107
1108 void SWFOutputDev::updateLineJoin(GfxState *state)
1109 {
1110     int j = state->getLineJoin();
1111 }
1112
1113 void SWFOutputDev::updateFillColor(GfxState *state) 
1114 {
1115     GfxRGB rgb;
1116     double opaq = state->getFillOpacity();
1117     state->getFillRGB(&rgb);
1118
1119     swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), 
1120                                     (char)(rgb.b*255), (char)(opaq*255));
1121 }
1122
1123 void SWFOutputDev::updateStrokeColor(GfxState *state) 
1124 {
1125     GfxRGB rgb;
1126     double opaq = state->getStrokeOpacity();
1127     state->getStrokeRGB(&rgb);
1128
1129     swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), 
1130                                       (char)(rgb.b*255), (char)(opaq*255));
1131 }
1132
1133 void FoFiWrite(void *stream, char *data, int len)
1134 {
1135    fwrite(data, len, 1, (FILE*)stream);
1136 }
1137
1138 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1139 {
1140     char*tmpFileName = NULL;
1141     FILE *f;
1142     int c;
1143     char *fontBuf;
1144     int fontLen;
1145     Ref embRef;
1146     Object refObj, strObj;
1147     char namebuf[512];
1148     tmpFileName = mktmpname(namebuf);
1149     int ret;
1150
1151     ret = font->getEmbeddedFontID(&embRef);
1152     if(!ret) {
1153         msg("<verbose> Didn't get embedded font id");
1154         /* not embedded- the caller should now search the font
1155            directories for this font */
1156         return 0;
1157     }
1158
1159     f = fopen(tmpFileName, "wb");
1160     if (!f) {
1161       msg("<error> Couldn't create temporary Type 1 font file");
1162         return 0;
1163     }
1164
1165     /*if(font->isCIDFont()) {
1166         GfxCIDFont* cidFont = (GfxCIDFont *)font;
1167         GString c = cidFont->getCollection();
1168         msg("<notice> Collection: %s", c.getCString());
1169     }*/
1170
1171     if (font->getType() == fontType1C ||
1172         font->getType() == fontCIDType0C) {
1173       if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1174         fclose(f);
1175         msg("<error> Couldn't read embedded font file");
1176         return 0;
1177       }
1178 #ifdef XPDF_101
1179       Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1180       cvt->convertToType1(f);
1181 #else
1182       FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1183       cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1184 #endif
1185       //cvt->convertToCIDType0("test", f);
1186       //cvt->convertToType0("test", f);
1187       delete cvt;
1188       gfree(fontBuf);
1189     } else if(font->getType() == fontTrueType) {
1190       msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1191       if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1192         fclose(f);
1193         msg("<error> Couldn't read embedded font file");
1194         return 0;
1195       }
1196 #ifdef XPDF_101
1197       TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1198       cvt->writeTTF(f);
1199 #else
1200       FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1201       cvt->writeTTF(FoFiWrite, f);
1202 #endif
1203       delete cvt;
1204       gfree(fontBuf);
1205     } else {
1206       font->getEmbeddedFontID(&embRef);
1207       refObj.initRef(embRef.num, embRef.gen);
1208       refObj.fetch(ref, &strObj);
1209       refObj.free();
1210       strObj.streamReset();
1211       int f4[4];
1212       char f4c[4];
1213       int t;
1214       for(t=0;t<4;t++) {
1215           f4[t] = strObj.streamGetChar();
1216           f4c[t] = (char)f4[t];
1217           if(f4[t] == EOF)
1218               break;
1219       }
1220       if(t==4) {
1221           if(!strncmp(f4c, "true", 4)) {
1222               /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1223                  Change this on the fly */
1224               f4[0] = f4[2] = f4[3] = 0;
1225               f4[1] = 1;
1226           }
1227           fputc(f4[0], f);
1228           fputc(f4[1], f);
1229           fputc(f4[2], f);
1230           fputc(f4[3], f);
1231
1232           while ((c = strObj.streamGetChar()) != EOF) {
1233             fputc(c, f);
1234           }
1235       }
1236       strObj.streamClose();
1237       strObj.free();
1238     }
1239     fclose(f);
1240
1241     return strdup(tmpFileName);
1242 }
1243     
1244 char* searchForSuitableFont(GfxFont*gfxFont)
1245 {
1246     char*name = getFontName(gfxFont);
1247     char*fontname = 0;
1248     char*filename = 0;
1249     
1250 #ifdef HAVE_FONTCONFIG
1251     FcPattern *pattern, *match;
1252     FcResult result;
1253     FcChar8 *v;
1254
1255     static int fcinitcalled = false; 
1256     
1257     // call init ony once
1258     if (!fcinitcalled) {
1259         fcinitcalled = true;
1260         FcInit(); //leaks
1261     }
1262    
1263     pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1264     if (gfxFont->isItalic()) // check for italic
1265         FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1266     if (gfxFont->isBold()) // check for bold
1267         FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1268
1269     // configure and match using the original font name 
1270     FcConfigSubstitute(0, pattern, FcMatchPattern); 
1271     FcDefaultSubstitute(pattern);
1272     match = FcFontMatch(0, pattern, &result);
1273     
1274     if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1275         // if we get an exact match
1276         if (strcmp((char *)v, name) == 0) {
1277             if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1278                 filename = strdup((char*)v);
1279                 char *nfn = strrchr(filename, '/');
1280                 if(nfn) fontname = strdup(nfn+1);
1281                 else    fontname = filename;
1282             }
1283         } else {
1284             // initialize patterns
1285             FcPatternDestroy(pattern);
1286             FcPatternDestroy(match);
1287
1288             // now match against serif etc.
1289             if (gfxFont->isSerif()) {
1290                 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1291             } else if (gfxFont->isFixedWidth()) {
1292                 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1293             } else {
1294                 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1295             }
1296
1297             // check for italic
1298             if (gfxFont->isItalic()) {
1299                 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1300             }
1301             // check for bold
1302             if (gfxFont->isBold()) {
1303                 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1304             }
1305
1306             // configure and match using serif etc
1307             FcConfigSubstitute (0, pattern, FcMatchPattern);
1308             FcDefaultSubstitute (pattern);
1309             match = FcFontMatch (0, pattern, &result);
1310             
1311             if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1312                 filename = strdup((char*)v);
1313                 char *nfn = strrchr(filename, '/');
1314                 if(nfn) fontname = strdup(nfn+1);
1315                 else    fontname = filename;
1316             }
1317         }        
1318     }
1319
1320     //printf("FONTCONFIG: pattern");
1321     //FcPatternPrint(pattern);
1322     //printf("FONTCONFIG: match");
1323     //FcPatternPrint(match);
1324  
1325     FcPatternDestroy(pattern);
1326     FcPatternDestroy(match);
1327
1328     pdfswf_addfont(filename);
1329     return fontname;
1330 #else
1331     return 0;
1332 #endif
1333 }
1334
1335 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1336 {
1337     char*fontname = 0, *filename = 0;
1338     msg("<notice> subsituteFont(%s)", oldname);
1339
1340     if(!(fontname = searchForSuitableFont(gfxFont))) {
1341         fontname = "Times-Roman";
1342     }
1343     filename = searchFont(fontname);
1344
1345     if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1346         msg("<fatal> Too many fonts in file.");
1347         exit(1);
1348     }
1349     if(oldname) {
1350         substitutesource[substitutepos] = oldname;
1351         substitutetarget[substitutepos] = fontname;
1352         msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1353         substitutepos ++;
1354     }
1355     return strdup(filename);
1356 }
1357
1358 void unlinkfont(char* filename)
1359 {
1360     int l;
1361     if(!filename)
1362         return;
1363     l=strlen(filename);
1364     unlink(filename);
1365     if(!strncmp(&filename[l-4],".afm",4)) {
1366         memcpy(&filename[l-4],".pfb",4);
1367         unlink(filename);
1368         memcpy(&filename[l-4],".pfa",4);
1369         unlink(filename);
1370         memcpy(&filename[l-4],".afm",4);
1371         return;
1372     } else 
1373     if(!strncmp(&filename[l-4],".pfa",4)) {
1374         memcpy(&filename[l-4],".afm",4);
1375         unlink(filename);
1376         memcpy(&filename[l-4],".pfa",4);
1377         return;
1378     } else 
1379     if(!strncmp(&filename[l-4],".pfb",4)) {
1380         memcpy(&filename[l-4],".afm",4);
1381         unlink(filename);
1382         memcpy(&filename[l-4],".pfb",4);
1383         return;
1384     }
1385 }
1386
1387 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref) 
1388 {
1389     this->doc = doc;
1390     this->xref = xref;
1391 }
1392
1393
1394 void SWFOutputDev::updateFont(GfxState *state) 
1395 {
1396     GfxFont*gfxFont = state->getFont();
1397       
1398     if (!gfxFont) {
1399         return;
1400     }  
1401     char * fontid = getFontID(gfxFont);
1402     
1403     int t;
1404     /* first, look if we substituted this font before-
1405        this way, we don't initialize the T1 Fonts
1406        too often */
1407     for(t=0;t<substitutepos;t++) {
1408         if(!strcmp(fontid, substitutesource[t])) {
1409             fontid = substitutetarget[t];
1410             break;
1411         }
1412     }
1413
1414     /* second, see if swfoutput already has this font
1415        cached- if so, we are done */
1416     if(swfoutput_queryfont(&output, fontid))
1417     {
1418         swfoutput_setfont(&output, fontid, 0);
1419         
1420         msg("<debug> updateFont(%s) [cached]", fontid);
1421         return;
1422     }
1423
1424     // look for Type 3 font
1425     if (gfxFont->getType() == fontType3) {
1426         if(!type3Warning) {
1427             type3Warning = gTrue;
1428             showFontError(gfxFont, 2);
1429         }
1430         return;
1431     }
1432
1433     /* now either load the font, or find a substitution */
1434
1435     Ref embRef;
1436     GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
1437
1438     char*fileName = 0;
1439     int del = 0;
1440     if(embedded &&
1441        (gfxFont->getType() == fontType1 ||
1442         gfxFont->getType() == fontType1C ||
1443         //gfxFont->getType() == fontCIDType0C ||
1444         gfxFont->getType() == fontTrueType ||
1445         gfxFont->getType() == fontCIDType2
1446        ))
1447     {
1448       fileName = writeEmbeddedFontToFile(xref, gfxFont);
1449       if(!fileName) showFontError(gfxFont,0);
1450       else del = 1;
1451     } else {
1452       char * fontname = getFontName(gfxFont);
1453       fileName = searchFont(fontname);
1454       if(!fileName) showFontError(gfxFont,0);
1455     }
1456     if(!fileName) {
1457         char * fontname = getFontName(gfxFont);
1458         msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
1459         msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
1460         fileName = substituteFont(gfxFont, fontid);
1461         if(fontid) { fontid = substitutetarget[substitutepos-1]; /*ugly hack*/};
1462         msg("<notice> Font is now %s (%s)", fontid, fileName);
1463     }
1464
1465     if(!fileName) {
1466         msg("<error> Couldn't set font %s\n", fontid);
1467         return;
1468     }
1469         
1470     msg("<verbose> updateFont(%s) -> %s", fontid, fileName);
1471     dumpFontInfo("<verbose>", gfxFont);
1472
1473     swfoutput_setfont(&output, fontid, fileName);
1474    
1475     if(fileName && del)
1476         unlinkfont(fileName);
1477     if(fileName)
1478         free(fileName);
1479 }
1480
1481 #define SQR(x) ((x)*(x))
1482
1483 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
1484 {
1485     if((newwidth<2 || newheight<2) ||
1486        (width<=newwidth || height<=newheight))
1487         return 0;
1488     unsigned char*newdata;
1489     int x,y;
1490     newdata= (unsigned char*)malloc(newwidth*newheight);
1491     int t;
1492     double fx = (double)(width)/newwidth;
1493     double fy = (double)(height)/newheight;
1494     double px = 0;
1495     int blocksize = (int)(8192/(fx*fy));
1496     int r = 8192*256/palettesize;
1497     for(x=0;x<newwidth;x++) {
1498         double ex = px + fx;
1499         int fromx = (int)px;
1500         int tox = (int)ex;
1501         int xweight1 = (int)(((fromx+1)-px)*256);
1502         int xweight2 = (int)((ex-tox)*256);
1503         double py =0;
1504         for(y=0;y<newheight;y++) {
1505             double ey = py + fy;
1506             int fromy = (int)py;
1507             int toy = (int)ey;
1508             int yweight1 = (int)(((fromy+1)-py)*256);
1509             int yweight2 = (int)((ey-toy)*256);
1510             int a = 0;
1511             int xx,yy;
1512             for(xx=fromx;xx<=tox;xx++)
1513             for(yy=fromy;yy<=toy;yy++) {
1514                 int b = 1-data[width*yy+xx];
1515                 int weight=256;
1516                 if(xx==fromx) weight = (weight*xweight1)/256;
1517                 if(xx==tox) weight = (weight*xweight2)/256;
1518                 if(yy==fromy) weight = (weight*yweight1)/256;
1519                 if(yy==toy) weight = (weight*yweight2)/256;
1520                 a+=b*weight;
1521             }
1522             //if(a) a=(palettesize-1)*r/blocksize;
1523             newdata[y*newwidth+x] = (a*blocksize)/r;
1524             py = ey;
1525         }
1526         px = ex;
1527     }
1528     return newdata;
1529 }
1530
1531 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
1532                                    int width, int height, GfxImageColorMap*colorMap, GBool invert,
1533                                    GBool inlineImg, int mask)
1534 {
1535   FILE *fi;
1536   int c;
1537   char fileName[128];
1538   double x1,y1,x2,y2,x3,y3,x4,y4;
1539   ImageStream *imgStr;
1540   Guchar pixBuf[4];
1541   GfxRGB rgb;
1542   int ncomps = 1;
1543   int bits = 1;
1544                                  
1545   if(colorMap) {
1546     ncomps = colorMap->getNumPixelComps();
1547     bits = colorMap->getBits();
1548   }
1549   imgStr = new ImageStream(str, width, ncomps,bits);
1550   imgStr->reset();
1551
1552   if(!width || !height || (height<=1 && width<=1))
1553   {
1554       msg("<verbose> Ignoring %d by %d image", width, height);
1555       unsigned char buf[8];
1556       int x,y;
1557       for (y = 0; y < height; ++y)
1558       for (x = 0; x < width; ++x) {
1559           imgStr->getPixel(buf);
1560       }
1561       delete imgStr;
1562       return;
1563   }
1564   
1565   state->transform(0, 1, &x1, &y1);
1566   state->transform(0, 0, &x2, &y2);
1567   state->transform(1, 0, &x3, &y3);
1568   state->transform(1, 1, &x4, &y4);
1569
1570   if(!pbminfo && !(str->getKind()==strDCT)) {
1571       if(!type3active) {
1572           msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
1573           pbminfo = 1;
1574       }
1575       if(mask)
1576       msg("<verbose> drawing %d by %d masked picture\n", width, height);
1577   }
1578   if(!jpeginfo && (str->getKind()==strDCT)) {
1579       msg("<notice> file contains jpeg pictures");
1580       jpeginfo = 1;
1581   }
1582
1583   if(mask) {
1584       int yes=0,i,j;
1585       unsigned char buf[8];
1586       int xid = 0;
1587       int yid = 0;
1588       int x,y;
1589       unsigned char*pic = new unsigned char[width*height];
1590       RGBA pal[256];
1591       GfxRGB rgb;
1592       state->getFillRGB(&rgb);
1593       memset(pal,255,sizeof(pal));
1594       pal[0].r = (int)(rgb.r*255); pal[0].g = (int)(rgb.g*255); 
1595       pal[0].b = (int)(rgb.b*255); pal[0].a = 255;
1596       pal[1].r = 0; pal[1].g = 0; pal[1].b = 0; pal[1].a = 0;
1597       int numpalette = 2;
1598       xid += pal[1].r*3 + pal[1].g*11 + pal[1].b*17;
1599       yid += pal[1].r*7 + pal[1].g*5 + pal[1].b*23;
1600       int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
1601       int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
1602       for (y = 0; y < height; ++y)
1603       for (x = 0; x < width; ++x)
1604       {
1605             imgStr->getPixel(buf);
1606             if(invert) 
1607                 buf[0]=1-buf[0];
1608             pic[width*y+x] = buf[0];
1609             xid+=x*buf[0]+1;
1610             yid+=y*buf[0]*3+1;
1611       }
1612       
1613       /* the size of the drawn image is added to the identifier
1614          as the same image may require different bitmaps if displayed
1615          at different sizes (due to antialiasing): */
1616       if(type3active) {
1617           xid += realwidth;
1618           yid += realheight;
1619       }
1620       int t,found = -1;
1621       for(t=0;t<picpos;t++)
1622       {
1623           if(pic_xids[t] == xid &&
1624              pic_yids[t] == yid) {
1625               /* if the image was antialiased, the size has changed: */
1626               width = pic_width[t];
1627               height = pic_height[t];
1628               found = t;break;
1629           }
1630       }
1631       if(found<0) {
1632           if(type3active) {
1633               numpalette = 16;
1634               unsigned char*pic2 = 0;
1635               
1636               pic2 = antialize(pic,width,height,realwidth,realheight, numpalette);
1637
1638               if(pic2) {
1639                   width = realwidth;
1640                   height = realheight;
1641                   free(pic);
1642                   pic = pic2;
1643                   /* make a black/white palette */
1644                   int t;
1645                   GfxRGB rgb2;
1646                   rgb2.r = 1 - rgb.r;
1647                   rgb2.g = 1 - rgb.g;
1648                   rgb2.b = 1 - rgb.b;
1649
1650                   float r = 255/(numpalette-1);
1651                   for(t=0;t<numpalette;t++) {
1652                       /*pal[t].r = (U8)(t*r*rgb.r+(numpalette-1-t)*r*rgb2.r);
1653                       pal[t].g = (U8)(t*r*rgb.g+(numpalette-1-t)*r*rgb2.g);
1654                       pal[t].b = (U8)(t*r*rgb.b+(numpalette-1-t)*r*rgb2.b);
1655                       pal[t].a = 255; */
1656                       pal[t].r = (U8)(255*rgb.r);
1657                       pal[t].g = (U8)(255*rgb.g);
1658                       pal[t].b = (U8)(255*rgb.b);
1659                       pal[t].a = (U8)(t*r);
1660                   }
1661               }
1662           }
1663           pic_ids[picpos] = swfoutput_drawimagelosslessN(&output, pic, pal, width, height, 
1664                   x1,y1,x2,y2,x3,y3,x4,y4, numpalette);
1665           pic_xids[picpos] = xid;
1666           pic_yids[picpos] = yid;
1667           pic_width[picpos] = width;
1668           pic_height[picpos] = height;
1669           if(picpos<1024)
1670               picpos++;
1671       } else {
1672           swfoutput_drawimageagain(&output, pic_ids[found], width, height,
1673                   x1,y1,x2,y2,x3,y3,x4,y4);
1674       }
1675       free(pic);
1676       delete imgStr;
1677       return;
1678   } 
1679
1680   int x,y;
1681   
1682   if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT)
1683   {
1684       RGBA*pic=new RGBA[width*height];
1685       int xid = 0;
1686       int yid = 0;
1687       for (y = 0; y < height; ++y) {
1688         for (x = 0; x < width; ++x) {
1689           int r,g,b,a;
1690           imgStr->getPixel(pixBuf);
1691           colorMap->getRGB(pixBuf, &rgb);
1692           pic[width*y+x].r = r = (U8)(rgb.r * 255 + 0.5);
1693           pic[width*y+x].g = g = (U8)(rgb.g * 255 + 0.5);
1694           pic[width*y+x].b = b = (U8)(rgb.b * 255 + 0.5);
1695           pic[width*y+x].a = a = 255;//(U8)(rgb.a * 255 + 0.5);
1696           xid += x*r+x*b*3+x*g*7+x*a*11;
1697           yid += y*r*3+y*b*17+y*g*19+y*a*11;
1698         }
1699       }
1700       int t,found = -1;
1701       for(t=0;t<picpos;t++)
1702       {
1703           if(pic_xids[t] == xid &&
1704              pic_yids[t] == yid) {
1705               found = t;break;
1706           }
1707       }
1708       if(found<0) {
1709           if(str->getKind()==strDCT)
1710               pic_ids[picpos] = swfoutput_drawimagejpeg(&output, pic, width, height, 
1711                       x1,y1,x2,y2,x3,y3,x4,y4);
1712           else
1713               pic_ids[picpos] = swfoutput_drawimagelossless(&output, pic, width, height, 
1714                       x1,y1,x2,y2,x3,y3,x4,y4);
1715           pic_xids[picpos] = xid;
1716           pic_yids[picpos] = yid;
1717           pic_width[picpos] = width;
1718           pic_height[picpos] = height;
1719           if(picpos<1024)
1720               picpos++;
1721       } else {
1722           swfoutput_drawimageagain(&output, pic_ids[found], width, height,
1723                   x1,y1,x2,y2,x3,y3,x4,y4);
1724       }
1725       delete pic;
1726       delete imgStr;
1727       return;
1728   }
1729   else
1730   {
1731       U8*pic = new U8[width*height];
1732       RGBA pal[256];
1733       int t;
1734       int xid=0,yid=0;
1735       for(t=0;t<256;t++)
1736       {
1737           int r,g,b,a;
1738           pixBuf[0] = t;
1739           colorMap->getRGB(pixBuf, &rgb);
1740           pal[t].r = r = (U8)(rgb.r * 255 + 0.5);
1741           pal[t].g = g = (U8)(rgb.g * 255 + 0.5);
1742           pal[t].b = b = (U8)(rgb.b * 255 + 0.5);
1743           pal[t].a = a = 255;//(U8)(rgb.b * 255 + 0.5);
1744           xid += t*r+t*b*3+t*g*7+t*a*11;
1745           xid += (~t)*r+t*b*3+t*g*7+t*a*11;
1746       }
1747       for (y = 0; y < height; ++y) {
1748         for (x = 0; x < width; ++x) {
1749           imgStr->getPixel(pixBuf);
1750           pic[width*y+x] = pixBuf[0];
1751           xid += x*pixBuf[0]*7;
1752           yid += y*pixBuf[0]*3;
1753         }
1754       }
1755       int found = -1;
1756       for(t=0;t<picpos;t++)
1757       {
1758           if(pic_xids[t] == xid &&
1759              pic_yids[t] == yid) {
1760               found = t;break;
1761           }
1762       }
1763       if(found<0) {
1764           pic_ids[picpos] = swfoutput_drawimagelosslessN(&output, pic, pal, width, height, 
1765                   x1,y1,x2,y2,x3,y3,x4,y4,256);
1766           pic_xids[picpos] = xid;
1767           pic_yids[picpos] = yid;
1768           pic_width[picpos] = width;
1769           pic_height[picpos] = height;
1770           if(picpos<1024)
1771               picpos++;
1772       } else {
1773           swfoutput_drawimageagain(&output, pic_ids[found], width, height,
1774                   x1,y1,x2,y2,x3,y3,x4,y4);
1775       }
1776       delete pic;
1777       delete imgStr;
1778       return;
1779   }
1780 }
1781
1782 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
1783                                    int width, int height, GBool invert,
1784                                    GBool inlineImg) 
1785 {
1786   msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
1787   drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1);
1788 }
1789
1790 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
1791                          int width, int height, GfxImageColorMap *colorMap,
1792                          int *maskColors, GBool inlineImg)
1793 {
1794   msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height, 
1795           colorMap?"colorMap":"no colorMap", 
1796           maskColors?"maskColors":"no maskColors",
1797           inlineImg);
1798   if(colorMap)
1799       msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
1800               colorMap->getBits(),colorMap->getColorSpace()->getMode());
1801   drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0);
1802 }
1803
1804 SWFOutputDev*output = 0; 
1805
1806 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
1807   Object obj;
1808   GString *s1, *s2;
1809   int i;
1810
1811   if (infoDict->lookup(key, &obj)->isString()) {
1812     s1 = obj.getString();
1813     if ((s1->getChar(0) & 0xff) == 0xfe &&
1814         (s1->getChar(1) & 0xff) == 0xff) {
1815       s2 = new GString();
1816       for (i = 2; i < obj.getString()->getLength(); i += 2) {
1817         if (s1->getChar(i) == '\0') {
1818           s2->append(s1->getChar(i+1));
1819         } else {
1820           delete s2;
1821           s2 = new GString("<unicode>");
1822           break;
1823         }
1824       }
1825       printf(fmt, s2->getCString());
1826       delete s2;
1827     } else {
1828       printf(fmt, s1->getCString());
1829     }
1830   }
1831   obj.free();
1832 }
1833
1834 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
1835   Object obj;
1836   char *s;
1837
1838   if (infoDict->lookup(key, &obj)->isString()) {
1839     s = obj.getString()->getCString();
1840     if (s[0] == 'D' && s[1] == ':') {
1841       s += 2;
1842     }
1843     printf(fmt, s);
1844   }
1845   obj.free();
1846 }
1847
1848 void pdfswf_setparameter(char*name, char*value)
1849 {
1850     if(!strcmp(name, "caplinewidth")) {
1851         caplinewidth = atof(value);
1852     } else if(!strcmp(name, "zoom")) {
1853         zoom = atoi(value);
1854     } else {
1855         swfoutput_setparameter(name, value);
1856     }
1857 }
1858 void pdfswf_addfont(char*filename)
1859 {
1860     fontfile_t f;
1861     memset(&f, 0, sizeof(fontfile_t));
1862     f.filename = filename;
1863     if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
1864         fonts[fontnum++] = f;
1865     } else {
1866         msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
1867     }
1868 }
1869
1870 typedef struct _pdf_doc_internal
1871 {
1872     int protect;
1873     PDFDoc*doc;
1874 } pdf_doc_internal_t;
1875 typedef struct _pdf_page_internal
1876 {
1877 } pdf_page_internal_t;
1878 typedef struct _swf_output_internal
1879 {
1880     SWFOutputDev*outputDev;
1881 } swf_output_internal_t;
1882
1883 pdf_doc_t* pdf_init(char*filename, char*userPassword)
1884 {
1885     pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
1886     memset(pdf_doc, 0, sizeof(pdf_doc_t));
1887     pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
1888     memset(i, 0, sizeof(pdf_doc_internal_t));
1889     pdf_doc->internal = i;
1890     
1891     GString *fileName = new GString(filename);
1892     GString *userPW;
1893     Object info;
1894
1895     // read config file
1896     globalParams = new GlobalParams("");
1897
1898     // open PDF file
1899     if (userPassword && userPassword[0]) {
1900       userPW = new GString(userPassword);
1901     } else {
1902       userPW = NULL;
1903     }
1904     i->doc = new PDFDoc(fileName, userPW);
1905     if (userPW) {
1906       delete userPW;
1907     }
1908     if (!i->doc->isOk()) {
1909         return 0;
1910     }
1911
1912     // print doc info
1913     i->doc->getDocInfo(&info);
1914     if (info.isDict() &&
1915       (screenloglevel>=LOGLEVEL_NOTICE)) {
1916       printInfoString(info.getDict(), "Title",        "Title:        %s\n");
1917       printInfoString(info.getDict(), "Subject",      "Subject:      %s\n");
1918       printInfoString(info.getDict(), "Keywords",     "Keywords:     %s\n");
1919       printInfoString(info.getDict(), "Author",       "Author:       %s\n");
1920       printInfoString(info.getDict(), "Creator",      "Creator:      %s\n");
1921       printInfoString(info.getDict(), "Producer",     "Producer:     %s\n");
1922       printInfoDate(info.getDict(),   "CreationDate", "CreationDate: %s\n");
1923       printInfoDate(info.getDict(),   "ModDate",      "ModDate:      %s\n");
1924       printf("Pages:        %d\n", i->doc->getNumPages());
1925       printf("Linearized:   %s\n", i->doc->isLinearized() ? "yes" : "no");
1926       printf("Encrypted:    ");
1927       if (i->doc->isEncrypted()) {
1928         printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
1929                i->doc->okToPrint() ? "yes" : "no",
1930                i->doc->okToCopy() ? "yes" : "no",
1931                i->doc->okToChange() ? "yes" : "no",
1932                i->doc->okToAddNotes() ? "yes" : "no");
1933       } else {
1934         printf("no\n");
1935       }
1936     }
1937     info.free();
1938                    
1939     pdf_doc->num_pages = i->doc->getNumPages();
1940     i->protect = 0;
1941     if (i->doc->isEncrypted()) {
1942           if(!i->doc->okToCopy()) {
1943               printf("PDF disallows copying. Terminating.\n");
1944               exit(1); //bail out
1945           }
1946           if(!i->doc->okToChange() || !i->doc->okToAddNotes())
1947               i->protect = 1;
1948     }
1949    
1950     return pdf_doc;
1951 }
1952
1953 void pdfswf_preparepage(int page)
1954 {
1955     /*FIXME*/
1956     if(!pages) {
1957         pages = (int*)malloc(1024*sizeof(int));
1958         pagebuflen = 1024;
1959     } else {
1960         if(pagepos == pagebuflen)
1961         {
1962             pagebuflen+=1024;
1963             pages = (int*)realloc(pages, pagebuflen);
1964         }
1965     }
1966     pages[pagepos++] = page;
1967 }
1968
1969 class MemCheck
1970 {
1971     public: ~MemCheck()
1972     {
1973         delete globalParams;
1974         Object::memCheck(stderr);
1975         gMemReport(stderr);
1976     }
1977 } myMemCheck;
1978
1979 void pdf_destroy(pdf_doc_t*pdf_doc)
1980 {
1981     pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
1982
1983     msg("<debug> pdfswf.cc: pdfswf_close()");
1984     delete i->doc; i->doc=0;
1985     
1986     free(pages); pages = 0; //FIXME
1987
1988     free(pdf_doc->internal);pdf_doc->internal=0;
1989     free(pdf_doc);pdf_doc=0;
1990 }
1991
1992 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
1993 {
1994     pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
1995     
1996     pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
1997     pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
1998     memset(pi, 0, sizeof(pdf_page_internal_t));
1999     pdf_page->internal = pi;
2000
2001     pdf_page->parent = pdf_doc;
2002     pdf_page->nr = page;
2003     return pdf_page;
2004 }
2005
2006 void pdf_page_destroy(pdf_page_t*pdf_page)
2007 {
2008     pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2009     free(pdf_page->internal);pdf_page->internal = 0;
2010     free(pdf_page);pdf_page=0;
2011 }
2012
2013 swf_output_t* swf_output_init() 
2014 {
2015     swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2016     memset(swf_output, 0, sizeof(swf_output_t));
2017     swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2018     memset(i, 0, sizeof(swf_output_internal_t));
2019     swf_output->internal = i;
2020
2021     i->outputDev = new SWFOutputDev();
2022     return swf_output;
2023 }
2024
2025 void swf_output_setparameter(swf_output_t*swf_output, char*name, char*value)
2026 {
2027     /* FIXME */
2028     pdfswf_setparameter(name, value);
2029 }
2030
2031 void swf_output_save(swf_output_t*swf, char*filename)
2032 {
2033     swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2034     i->outputDev->save(filename);
2035 }
2036
2037 void swf_output_destroy(swf_output_t*output)
2038 {
2039     swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2040     delete i->outputDev; i->outputDev=0;
2041     free(output->internal);output->internal=0;
2042     free(output);
2043 }
2044
2045
2046 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2047 {
2048     pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2049     swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2050
2051     if(pi->protect) {
2052         swfoutput_setparameter("protect", "1");
2053     }
2054     si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2055 #ifdef XPDF_101
2056     pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2057 #else
2058     pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2059 #endif
2060 }
2061
2062 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2063 {
2064     pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2065     pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2066     memset(info, 0, sizeof(pdf_page_info_t));
2067     return info;
2068 }
2069