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