fixed type 3 stroke/fill color problem.
[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         font->getType() == fontCIDType0C) {
1284       if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1285         fclose(f);
1286         msg("<error> Couldn't read embedded font file");
1287         return 0;
1288       }
1289 #ifdef XPDF_101
1290       Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1291       if(!cvt) return 0;
1292       cvt->convertToType1(f);
1293 #else
1294       FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1295       if(!cvt) return 0;
1296       cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1297 #endif
1298       //cvt->convertToCIDType0("test", f);
1299       //cvt->convertToType0("test", f);
1300       delete cvt;
1301       gfree(fontBuf);
1302     } else if(font->getType() == fontTrueType) {
1303       msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1304       if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1305         fclose(f);
1306         msg("<error> Couldn't read embedded font file");
1307         return 0;
1308       }
1309 #ifdef XPDF_101
1310       TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1311       cvt->writeTTF(f);
1312 #else
1313       FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1314       cvt->writeTTF(FoFiWrite, f);
1315 #endif
1316       delete cvt;
1317       gfree(fontBuf);
1318     } else {
1319       font->getEmbeddedFontID(&embRef);
1320       refObj.initRef(embRef.num, embRef.gen);
1321       refObj.fetch(ref, &strObj);
1322       refObj.free();
1323       strObj.streamReset();
1324       int f4[4];
1325       char f4c[4];
1326       int t;
1327       for(t=0;t<4;t++) {
1328           f4[t] = strObj.streamGetChar();
1329           f4c[t] = (char)f4[t];
1330           if(f4[t] == EOF)
1331               break;
1332       }
1333       if(t==4) {
1334           if(!strncmp(f4c, "true", 4)) {
1335               /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1336                  Change this on the fly */
1337               f4[0] = f4[2] = f4[3] = 0;
1338               f4[1] = 1;
1339           }
1340           fputc(f4[0], f);
1341           fputc(f4[1], f);
1342           fputc(f4[2], f);
1343           fputc(f4[3], f);
1344
1345           while ((c = strObj.streamGetChar()) != EOF) {
1346             fputc(c, f);
1347           }
1348       }
1349       strObj.streamClose();
1350       strObj.free();
1351     }
1352     fclose(f);
1353
1354     return strdup(tmpFileName);
1355 }
1356     
1357 char* searchForSuitableFont(GfxFont*gfxFont)
1358 {
1359     char*name = getFontName(gfxFont);
1360     char*fontname = 0;
1361     char*filename = 0;
1362
1363     if(!config_use_fontconfig)
1364         return 0;
1365     
1366 #ifdef HAVE_FONTCONFIG
1367     FcPattern *pattern, *match;
1368     FcResult result;
1369     FcChar8 *v;
1370
1371     static int fcinitcalled = false; 
1372         
1373     msg("<debug> searchForSuitableFont(%s)", name);
1374     
1375     // call init ony once
1376     if (!fcinitcalled) {
1377         msg("<debug> Initializing FontConfig...");
1378         fcinitcalled = true;
1379         if(FcInit()) {
1380             msg("<debug> FontConfig Initialization failed. Disabling.");
1381             config_use_fontconfig = 0;
1382             return 0;
1383         }
1384         msg("<debug> ...initialized FontConfig");
1385     }
1386    
1387     msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1388     pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1389     if (gfxFont->isItalic()) // check for italic
1390         msg("<debug> FontConfig: Adding Italic Slant");
1391         FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1392     if (gfxFont->isBold()) // check for bold
1393         msg("<debug> FontConfig: Adding Bold Weight");
1394         FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1395
1396     msg("<debug> FontConfig: Try to match...");
1397     // configure and match using the original font name 
1398     FcConfigSubstitute(0, pattern, FcMatchPattern); 
1399     FcDefaultSubstitute(pattern);
1400     match = FcFontMatch(0, pattern, &result);
1401     
1402     if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1403         msg("<debug> FontConfig: family=%s", (char*)v);
1404         // if we get an exact match
1405         if (strcmp((char *)v, name) == 0) {
1406             if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1407                 filename = strdup((char*)v);
1408                 char *nfn = strrchr(filename, '/');
1409                 if(nfn) fontname = strdup(nfn+1);
1410                 else    fontname = filename;
1411             }
1412             msg("<debug> FontConfig: Returning \"%s\"", fontname);
1413         } else {
1414             // initialize patterns
1415             FcPatternDestroy(pattern);
1416             FcPatternDestroy(match);
1417
1418             // now match against serif etc.
1419             if (gfxFont->isSerif()) {
1420                 msg("<debug> FontConfig: Create Serif Family Pattern");
1421                 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1422             } else if (gfxFont->isFixedWidth()) {
1423                 msg("<debug> FontConfig: Create Monospace Family Pattern");
1424                 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1425             } else {
1426                 msg("<debug> FontConfig: Create Sans Family Pattern");
1427                 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1428             }
1429
1430             // check for italic
1431             if (gfxFont->isItalic()) {
1432                 msg("<debug> FontConfig: Adding Italic Slant");
1433                 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1434             }
1435             // check for bold
1436             if (gfxFont->isBold()) {
1437                 msg("<debug> FontConfig: Adding Bold Weight");
1438                 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1439             }
1440
1441             msg("<debug> FontConfig: Try to match... (2)");
1442             // configure and match using serif etc
1443             FcConfigSubstitute (0, pattern, FcMatchPattern);
1444             FcDefaultSubstitute (pattern);
1445             match = FcFontMatch (0, pattern, &result);
1446             
1447             if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1448                 filename = strdup((char*)v);
1449                 char *nfn = strrchr(filename, '/');
1450                 if(nfn) fontname = strdup(nfn+1);
1451                 else    fontname = filename;
1452             }
1453             msg("<debug> FontConfig: Returning \"%s\"", fontname);
1454         }        
1455     }
1456
1457     //printf("FONTCONFIG: pattern");
1458     //FcPatternPrint(pattern);
1459     //printf("FONTCONFIG: match");
1460     //FcPatternPrint(match);
1461  
1462     FcPatternDestroy(pattern);
1463     FcPatternDestroy(match);
1464
1465     pdfswf_addfont(filename);
1466     return fontname;
1467 #else
1468     return 0;
1469 #endif
1470 }
1471
1472 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1473 {
1474     char*fontname = 0, *filename = 0;
1475     msg("<notice> subsituteFont(%s)", oldname);
1476
1477     if(!(fontname = searchForSuitableFont(gfxFont))) {
1478         fontname = "Times-Roman";
1479     }
1480     filename = searchFont(fontname);
1481     if(!filename) {
1482         msg("<error> Couldn't find font %s- did you install the default fonts?");
1483         return 0;
1484     }
1485
1486     if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1487         msg("<fatal> Too many fonts in file.");
1488         exit(1);
1489     }
1490     if(oldname) {
1491         substitutesource[substitutepos] = oldname;
1492         substitutetarget[substitutepos] = fontname;
1493         msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1494         substitutepos ++;
1495     }
1496     return strdup(filename);
1497 }
1498
1499 void unlinkfont(char* filename)
1500 {
1501     int l;
1502     if(!filename)
1503         return;
1504     l=strlen(filename);
1505     unlink(filename);
1506     if(!strncmp(&filename[l-4],".afm",4)) {
1507         memcpy(&filename[l-4],".pfb",4);
1508         unlink(filename);
1509         memcpy(&filename[l-4],".pfa",4);
1510         unlink(filename);
1511         memcpy(&filename[l-4],".afm",4);
1512         return;
1513     } else 
1514     if(!strncmp(&filename[l-4],".pfa",4)) {
1515         memcpy(&filename[l-4],".afm",4);
1516         unlink(filename);
1517         memcpy(&filename[l-4],".pfa",4);
1518         return;
1519     } else 
1520     if(!strncmp(&filename[l-4],".pfb",4)) {
1521         memcpy(&filename[l-4],".afm",4);
1522         unlink(filename);
1523         memcpy(&filename[l-4],".pfb",4);
1524         return;
1525     }
1526 }
1527
1528 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref) 
1529 {
1530     this->doc = doc;
1531     this->xref = xref;
1532 }
1533
1534
1535 void SWFOutputDev::updateFont(GfxState *state) 
1536 {
1537     GfxFont*gfxFont = state->getFont();
1538       
1539     if (!gfxFont) {
1540         return;
1541     }  
1542     char * fontid = getFontID(gfxFont);
1543     
1544     int t;
1545     /* first, look if we substituted this font before-
1546        this way, we don't initialize the T1 Fonts
1547        too often */
1548     for(t=0;t<substitutepos;t++) {
1549         if(!strcmp(fontid, substitutesource[t])) {
1550             fontid = substitutetarget[t];
1551             break;
1552         }
1553     }
1554
1555     /* second, see if swfoutput already has this font
1556        cached- if so, we are done */
1557     if(swfoutput_queryfont(&output, fontid))
1558     {
1559         swfoutput_setfont(&output, fontid, 0);
1560         
1561         msg("<debug> updateFont(%s) [cached]", fontid);
1562         return;
1563     }
1564
1565     // look for Type 3 font
1566     if (gfxFont->getType() == fontType3) {
1567         if(!type3Warning) {
1568             type3Warning = gTrue;
1569             showFontError(gfxFont, 2);
1570         }
1571         return;
1572     }
1573
1574     /* now either load the font, or find a substitution */
1575
1576     Ref embRef;
1577     GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
1578
1579     char*fileName = 0;
1580     int del = 0;
1581     if(embedded &&
1582        (gfxFont->getType() == fontType1 ||
1583         gfxFont->getType() == fontType1C ||
1584        (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
1585         gfxFont->getType() == fontTrueType ||
1586         gfxFont->getType() == fontCIDType2
1587        ))
1588     {
1589       fileName = writeEmbeddedFontToFile(xref, gfxFont);
1590       if(!fileName) showFontError(gfxFont,0);
1591       else del = 1;
1592     } else {
1593       char * fontname = getFontName(gfxFont);
1594       fileName = searchFont(fontname);
1595       if(!fileName) showFontError(gfxFont,0);
1596     }
1597     if(!fileName) {
1598         char * fontname = getFontName(gfxFont);
1599         msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
1600         msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
1601         fileName = substituteFont(gfxFont, fontid);
1602         if(fontid) { fontid = substitutetarget[substitutepos-1]; /*ugly hack*/};
1603         msg("<notice> Font is now %s (%s)", fontid, fileName);
1604     }
1605
1606     if(!fileName) {
1607         msg("<error> Couldn't set font %s\n", fontid);
1608         return;
1609     }
1610         
1611     msg("<verbose> updateFont(%s) -> %s", fontid, fileName);
1612     dumpFontInfo("<verbose>", gfxFont);
1613
1614     swfoutput_setfont(&output, fontid, fileName);
1615    
1616     if(fileName && del)
1617         unlinkfont(fileName);
1618     if(fileName)
1619         free(fileName);
1620 }
1621
1622 #define SQR(x) ((x)*(x))
1623
1624 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
1625 {
1626     if((newwidth<2 || newheight<2) ||
1627        (width<=newwidth || height<=newheight))
1628         return 0;
1629     unsigned char*newdata;
1630     int x,y;
1631     newdata= (unsigned char*)malloc(newwidth*newheight);
1632     int t;
1633     double fx = (double)(width)/newwidth;
1634     double fy = (double)(height)/newheight;
1635     double px = 0;
1636     int blocksize = (int)(8192/(fx*fy));
1637     int r = 8192*256/palettesize;
1638     for(x=0;x<newwidth;x++) {
1639         double ex = px + fx;
1640         int fromx = (int)px;
1641         int tox = (int)ex;
1642         int xweight1 = (int)(((fromx+1)-px)*256);
1643         int xweight2 = (int)((ex-tox)*256);
1644         double py =0;
1645         for(y=0;y<newheight;y++) {
1646             double ey = py + fy;
1647             int fromy = (int)py;
1648             int toy = (int)ey;
1649             int yweight1 = (int)(((fromy+1)-py)*256);
1650             int yweight2 = (int)((ey-toy)*256);
1651             int a = 0;
1652             int xx,yy;
1653             for(xx=fromx;xx<=tox;xx++)
1654             for(yy=fromy;yy<=toy;yy++) {
1655                 int b = 1-data[width*yy+xx];
1656                 int weight=256;
1657                 if(xx==fromx) weight = (weight*xweight1)/256;
1658                 if(xx==tox) weight = (weight*xweight2)/256;
1659                 if(yy==fromy) weight = (weight*yweight1)/256;
1660                 if(yy==toy) weight = (weight*yweight2)/256;
1661                 a+=b*weight;
1662             }
1663             //if(a) a=(palettesize-1)*r/blocksize;
1664             newdata[y*newwidth+x] = (a*blocksize)/r;
1665             py = ey;
1666         }
1667         px = ex;
1668     }
1669     return newdata;
1670 }
1671
1672 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
1673                                    int width, int height, GfxImageColorMap*colorMap, GBool invert,
1674                                    GBool inlineImg, int mask, int*maskColors)
1675 {
1676   FILE *fi;
1677   int c;
1678   char fileName[128];
1679   double x1,y1,x2,y2,x3,y3,x4,y4;
1680   ImageStream *imgStr;
1681   Guchar pixBuf[4];
1682   GfxRGB rgb;
1683   int ncomps = 1;
1684   int bits = 1;
1685                                  
1686   if(colorMap) {
1687     ncomps = colorMap->getNumPixelComps();
1688     bits = colorMap->getBits();
1689   }
1690   imgStr = new ImageStream(str, width, ncomps,bits);
1691   imgStr->reset();
1692
1693   if(!width || !height || (height<=1 && width<=1))
1694   {
1695       msg("<verbose> Ignoring %d by %d image", width, height);
1696       unsigned char buf[8];
1697       int x,y;
1698       for (y = 0; y < height; ++y)
1699       for (x = 0; x < width; ++x) {
1700           imgStr->getPixel(buf);
1701       }
1702       delete imgStr;
1703       return;
1704   }
1705   
1706   state->transform(0, 1, &x1, &y1);
1707   state->transform(0, 0, &x2, &y2);
1708   state->transform(1, 0, &x3, &y3);
1709   state->transform(1, 1, &x4, &y4);
1710
1711   if(!pbminfo && !(str->getKind()==strDCT)) {
1712       if(!type3active) {
1713           msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
1714           pbminfo = 1;
1715       }
1716       if(mask)
1717       msg("<verbose> drawing %d by %d masked picture\n", width, height);
1718   }
1719   if(!jpeginfo && (str->getKind()==strDCT)) {
1720       msg("<notice> file contains jpeg pictures");
1721       jpeginfo = 1;
1722   }
1723
1724   if(mask) {
1725       int i,j;
1726       unsigned char buf[8];
1727       int x,y;
1728       unsigned char*pic = new unsigned char[width*height];
1729       RGBA pal[256];
1730       GfxRGB rgb;
1731       state->getFillRGB(&rgb);
1732
1733       memset(pal,255,sizeof(pal));
1734       pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
1735       pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
1736       pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
1737       pal[0].a = 255;              pal[1].a = 0;
1738
1739       int numpalette = 2;
1740       int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
1741       int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
1742       for (y = 0; y < height; ++y)
1743       for (x = 0; x < width; ++x)
1744       {
1745             imgStr->getPixel(buf);
1746             if(invert) 
1747                 buf[0]=1-buf[0];
1748             pic[width*y+x] = buf[0];
1749       }
1750       
1751       /* the size of the drawn image is added to the identifier
1752          as the same image may require different bitmaps if displayed
1753          at different sizes (due to antialiasing): */
1754       int t,found = -1;
1755       if(type3active) {
1756           unsigned char*pic2 = 0;
1757           numpalette = 16;
1758           
1759           pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
1760
1761           if(!pic2) {
1762             delete pic;
1763             delete imgStr;
1764             return;
1765           }
1766
1767           width = realwidth;
1768           height = realheight;
1769           free(pic);
1770           pic = pic2;
1771           
1772           /* make a black/white palette */
1773           GfxRGB rgb2;
1774           rgb2.r = 1 - rgb.r;
1775           rgb2.g = 1 - rgb.g;
1776           rgb2.b = 1 - rgb.b;
1777           float r = 255/(numpalette-1);
1778           int t;
1779           for(t=0;t<numpalette;t++) {
1780               pal[t].r = (U8)(255*rgb.r);
1781               pal[t].g = (U8)(255*rgb.g);
1782               pal[t].b = (U8)(255*rgb.b);
1783               pal[t].a = (U8)(t*r);
1784           }
1785       }
1786
1787       RGBA*pic2 = new RGBA[width*height];
1788       for (y = 0; y < height; ++y) {
1789         for (x = 0; x < width; ++x) {
1790           pic2[width*y+x] = pal[pic[y*width+x]];
1791         }
1792       }
1793       swfoutput_drawimagelossless(&output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1794       free(pic2);
1795       free(pic);
1796       delete imgStr;
1797       return;
1798   } 
1799
1800   int x,y;
1801
1802   if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
1803       RGBA*pic=new RGBA[width*height];
1804       for (y = 0; y < height; ++y) {
1805         for (x = 0; x < width; ++x) {
1806           imgStr->getPixel(pixBuf);
1807           colorMap->getRGB(pixBuf, &rgb);
1808           pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5);
1809           pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5);
1810           pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5);
1811           pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
1812         }
1813       }
1814       if(str->getKind()==strDCT)
1815           swfoutput_drawimagejpeg(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1816       else
1817           swfoutput_drawimagelossless(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1818       delete pic;
1819       delete imgStr;
1820       return;
1821   } else {
1822       RGBA*pic=new RGBA[width*height];
1823       RGBA pal[256];
1824       int t;
1825       for(t=0;t<256;t++) {
1826           pixBuf[0] = t;
1827           colorMap->getRGB(pixBuf, &rgb);
1828           /*if(maskColors && *maskColors==t) {
1829               msg("<notice> Color %d is transparent", t);
1830               if (imgData->maskColors) {
1831                 *alpha = 0;
1832                 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
1833                   if (pix[i] < imgData->maskColors[2*i] ||
1834                       pix[i] > imgData->maskColors[2*i+1]) {
1835                     *alpha = 1;
1836                     break;
1837                   }
1838                 }
1839               } else {
1840                 *alpha = 1;
1841               }
1842               if(!*alpha) {
1843                     pal[t].r = 0;
1844                     pal[t].g = 0;
1845                     pal[t].b = 0;
1846                     pal[t].a = 0;
1847               }
1848           } else*/ {
1849               pal[t].r = (U8)(rgb.r * 255 + 0.5);
1850               pal[t].g = (U8)(rgb.g * 255 + 0.5);
1851               pal[t].b = (U8)(rgb.b * 255 + 0.5);
1852               pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
1853           }
1854       }
1855       for (y = 0; y < height; ++y) {
1856         for (x = 0; x < width; ++x) {
1857           imgStr->getPixel(pixBuf);
1858           pic[width*y+x] = pal[pixBuf[0]];
1859         }
1860       }
1861       swfoutput_drawimagelossless(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1862
1863       delete pic;
1864       delete imgStr;
1865       return;
1866   }
1867 }
1868
1869 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
1870                                    int width, int height, GBool invert,
1871                                    GBool inlineImg) 
1872 {
1873   msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
1874   drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
1875 }
1876
1877 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
1878                          int width, int height, GfxImageColorMap *colorMap,
1879                          int *maskColors, GBool inlineImg)
1880 {
1881   msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height, 
1882           colorMap?"colorMap":"no colorMap", 
1883           maskColors?"maskColors":"no maskColors",
1884           inlineImg);
1885   if(colorMap)
1886       msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
1887               colorMap->getBits(),colorMap->getColorSpace()->getMode());
1888   drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
1889 }
1890
1891 SWFOutputDev*output = 0; 
1892
1893 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
1894   Object obj;
1895   GString *s1, *s2;
1896   int i;
1897
1898   if (infoDict->lookup(key, &obj)->isString()) {
1899     s1 = obj.getString();
1900     if ((s1->getChar(0) & 0xff) == 0xfe &&
1901         (s1->getChar(1) & 0xff) == 0xff) {
1902       s2 = new GString();
1903       for (i = 2; i < obj.getString()->getLength(); i += 2) {
1904         if (s1->getChar(i) == '\0') {
1905           s2->append(s1->getChar(i+1));
1906         } else {
1907           delete s2;
1908           s2 = new GString("<unicode>");
1909           break;
1910         }
1911       }
1912       printf(fmt, s2->getCString());
1913       delete s2;
1914     } else {
1915       printf(fmt, s1->getCString());
1916     }
1917   }
1918   obj.free();
1919 }
1920
1921 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
1922   Object obj;
1923   char *s;
1924
1925   if (infoDict->lookup(key, &obj)->isString()) {
1926     s = obj.getString()->getCString();
1927     if (s[0] == 'D' && s[1] == ':') {
1928       s += 2;
1929     }
1930     printf(fmt, s);
1931   }
1932   obj.free();
1933 }
1934
1935 int jpeg_dpi = 0;
1936 int ppm_dpi = 0;
1937
1938 void pdfswf_setparameter(char*name, char*value)
1939 {
1940     msg("<verbose> setting parameter %s to \"%s\"", name, value);
1941     if(!strcmp(name, "caplinewidth")) {
1942         caplinewidth = atof(value);
1943     } else if(!strcmp(name, "zoom")) {
1944         char buf[80];
1945         zoom = atoi(value);
1946         sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
1947         swfoutput_setparameter("jpegsubpixels", buf);
1948         sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
1949         swfoutput_setparameter("ppmsubpixels", buf);
1950     } else if(!strcmp(name, "jpegdpi")) {
1951         char buf[80];
1952         jpeg_dpi = atoi(value);
1953         sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
1954         swfoutput_setparameter("jpegsubpixels", buf);
1955     } else if(!strcmp(name, "ppmdpi")) {
1956         char buf[80];
1957         ppm_dpi = atoi(value);
1958         sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
1959         swfoutput_setparameter("ppmsubpixels", buf);
1960     } else if(!strcmp(name, "forceType0Fonts")) {
1961         forceType0Fonts = atoi(value);
1962     } else if(!strcmp(name, "fontdir")) {
1963         pdfswf_addfontdir(value);
1964     } else if(!strcmp(name, "languagedir")) {
1965         pdfswf_addlanguagedir(value);
1966     } else if(!strcmp(name, "fontconfig")) {
1967         config_use_fontconfig = atoi(value);
1968     } else {
1969         swfoutput_setparameter(name, value);
1970     }
1971 }
1972 void pdfswf_addfont(char*filename)
1973 {
1974     fontfile_t f;
1975     memset(&f, 0, sizeof(fontfile_t));
1976     f.filename = filename;
1977     if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
1978         fonts[fontnum++] = f;
1979     } else {
1980         msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
1981     }
1982 }
1983
1984 static char* dirseparator()
1985 {
1986 #ifdef WIN32
1987     return "\\";
1988 #else
1989     return "/";
1990 #endif
1991 }
1992
1993 void pdfswf_addlanguagedir(char*dir)
1994 {
1995     if(!globalParams)
1996         globalParams = new GlobalParams("");
1997     
1998     msg("<notice> Adding %s to language pack directories", dir);
1999
2000     int l;
2001     FILE*fi = 0;
2002     char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2003     strcpy(config_file, dir);
2004     strcat(config_file, dirseparator());
2005     strcat(config_file, "add-to-xpdfrc");
2006
2007     fi = fopen(config_file, "rb");
2008     if(!fi) {
2009         msg("<error> Could not open %s", config_file);
2010         return;
2011     }
2012     globalParams->parseFile(new GString(config_file), fi);
2013     fclose(fi);
2014 }
2015
2016 void pdfswf_addfontdir(char*dirname)
2017 {
2018 #ifdef HAVE_DIRENT_H
2019     msg("<notice> Adding %s to font directories", dirname);
2020     DIR*dir = opendir(dirname);
2021     if(!dir) {
2022         msg("<warning> Couldn't open directory %s\n", dirname);
2023         return;
2024     }
2025     struct dirent*ent;
2026     while(1) {
2027         ent = readdir (dir);
2028         if (!ent) 
2029             break;
2030         int l;
2031         char*name = ent->d_name;
2032         char type = 0;
2033         if(!name) continue;
2034         l=strlen(name);
2035         if(l<4)
2036             continue;
2037         if(!strncasecmp(&name[l-4], ".pfa", 4)) 
2038             type=1;
2039         if(!strncasecmp(&name[l-4], ".pfb", 4)) 
2040             type=3;
2041         if(!strncasecmp(&name[l-4], ".ttf", 4)) 
2042             type=2;
2043         if(type)
2044         {
2045             char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2046             strcpy(fontname, dirname);
2047             strcat(fontname, dirseparator());
2048             strcat(fontname, name);
2049             msg("<verbose> Adding %s to fonts", fontname);
2050             pdfswf_addfont(fontname);
2051         }
2052     }
2053     closedir(dir);
2054 #else
2055     msg("<warning> No dirent.h- unable to add font dir %s", dir);
2056 #endif
2057 }
2058
2059
2060 typedef struct _pdf_doc_internal
2061 {
2062     int protect;
2063     PDFDoc*doc;
2064 } pdf_doc_internal_t;
2065 typedef struct _pdf_page_internal
2066 {
2067 } pdf_page_internal_t;
2068 typedef struct _swf_output_internal
2069 {
2070     SWFOutputDev*outputDev;
2071 } swf_output_internal_t;
2072
2073 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2074 {
2075     pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2076     memset(pdf_doc, 0, sizeof(pdf_doc_t));
2077     pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2078     memset(i, 0, sizeof(pdf_doc_internal_t));
2079     pdf_doc->internal = i;
2080     
2081     GString *fileName = new GString(filename);
2082     GString *userPW;
2083     Object info;
2084
2085     // read config file
2086     if(!globalParams)
2087         globalParams = new GlobalParams("");
2088
2089     // open PDF file
2090     if (userPassword && userPassword[0]) {
2091       userPW = new GString(userPassword);
2092     } else {
2093       userPW = NULL;
2094     }
2095     i->doc = new PDFDoc(fileName, userPW);
2096     if (userPW) {
2097       delete userPW;
2098     }
2099     if (!i->doc->isOk()) {
2100         return 0;
2101     }
2102
2103     // print doc info
2104     i->doc->getDocInfo(&info);
2105     if (info.isDict() &&
2106       (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2107       printInfoString(info.getDict(), "Title",        "Title:        %s\n");
2108       printInfoString(info.getDict(), "Subject",      "Subject:      %s\n");
2109       printInfoString(info.getDict(), "Keywords",     "Keywords:     %s\n");
2110       printInfoString(info.getDict(), "Author",       "Author:       %s\n");
2111       printInfoString(info.getDict(), "Creator",      "Creator:      %s\n");
2112       printInfoString(info.getDict(), "Producer",     "Producer:     %s\n");
2113       printInfoDate(info.getDict(),   "CreationDate", "CreationDate: %s\n");
2114       printInfoDate(info.getDict(),   "ModDate",      "ModDate:      %s\n");
2115       printf("Pages:        %d\n", i->doc->getNumPages());
2116       printf("Linearized:   %s\n", i->doc->isLinearized() ? "yes" : "no");
2117       printf("Encrypted:    ");
2118       if (i->doc->isEncrypted()) {
2119         printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2120                i->doc->okToPrint() ? "yes" : "no",
2121                i->doc->okToCopy() ? "yes" : "no",
2122                i->doc->okToChange() ? "yes" : "no",
2123                i->doc->okToAddNotes() ? "yes" : "no");
2124       } else {
2125         printf("no\n");
2126       }
2127     }
2128     info.free();
2129                    
2130     pdf_doc->num_pages = i->doc->getNumPages();
2131     i->protect = 0;
2132     if (i->doc->isEncrypted()) {
2133           if(!i->doc->okToCopy()) {
2134               printf("PDF disallows copying.\n");
2135               return 0;
2136           }
2137           if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2138               i->protect = 1;
2139     }
2140    
2141     return pdf_doc;
2142 }
2143
2144 void pdfswf_preparepage(int page)
2145 {
2146     /*FIXME*/
2147     if(!pages) {
2148         pages = (int*)malloc(1024*sizeof(int));
2149         pagebuflen = 1024;
2150     } else {
2151         if(pagepos == pagebuflen)
2152         {
2153             pagebuflen+=1024;
2154             pages = (int*)realloc(pages, pagebuflen);
2155         }
2156     }
2157     pages[pagepos++] = page;
2158 }
2159
2160 class MemCheck
2161 {
2162     public: ~MemCheck()
2163     {
2164         delete globalParams;globalParams=0;
2165         Object::memCheck(stderr);
2166         gMemReport(stderr);
2167     }
2168 } myMemCheck;
2169
2170 void pdf_destroy(pdf_doc_t*pdf_doc)
2171 {
2172     pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2173
2174     msg("<debug> pdfswf.cc: pdfswf_close()");
2175     delete i->doc; i->doc=0;
2176     
2177     free(pages); pages = 0; //FIXME
2178
2179     free(pdf_doc->internal);pdf_doc->internal=0;
2180     free(pdf_doc);pdf_doc=0;
2181 }
2182
2183 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2184 {
2185     pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2186
2187     if(page < 1 || page > pdf_doc->num_pages)
2188         return 0;
2189     
2190     pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2191     pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2192     memset(pi, 0, sizeof(pdf_page_internal_t));
2193     pdf_page->internal = pi;
2194
2195     pdf_page->parent = pdf_doc;
2196     pdf_page->nr = page;
2197     return pdf_page;
2198 }
2199
2200 void pdf_page_destroy(pdf_page_t*pdf_page)
2201 {
2202     pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2203     free(pdf_page->internal);pdf_page->internal = 0;
2204     free(pdf_page);pdf_page=0;
2205 }
2206
2207 swf_output_t* swf_output_init() 
2208 {
2209     swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2210     memset(swf_output, 0, sizeof(swf_output_t));
2211     swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2212     memset(i, 0, sizeof(swf_output_internal_t));
2213     swf_output->internal = i;
2214
2215     i->outputDev = new SWFOutputDev();
2216     return swf_output;
2217 }
2218
2219 void swf_output_setparameter(swf_output_t*swf_output, char*name, char*value)
2220 {
2221     /* FIXME */
2222     pdfswf_setparameter(name, value);
2223 }
2224
2225 void swf_output_pagefeed(swf_output_t*swf)
2226 {
2227     swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2228     i->outputDev->pagefeed();
2229     i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2230 }
2231
2232 int swf_output_save(swf_output_t*swf, char*filename)
2233 {
2234     swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2235     int ret = i->outputDev->save(filename);
2236     i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2237     return ret;
2238 }
2239
2240 void* swf_output_get(swf_output_t*swf)
2241 {
2242     swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2243     void* ret = i->outputDev->getSWF();
2244     i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2245     return ret;
2246 }
2247
2248 void swf_output_destroy(swf_output_t*output)
2249 {
2250     swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2251     delete i->outputDev; i->outputDev=0;
2252     free(output->internal);output->internal=0;
2253     free(output);
2254 }
2255
2256 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2257 {
2258     pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2259     swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2260
2261     if(pi->protect) {
2262         swfoutput_setparameter("protect", "1");
2263     }
2264     si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2265 #ifdef XPDF_101
2266     pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2267 #else
2268     pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2269 #endif
2270     si->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2271 }
2272
2273 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2274 {
2275     pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2276     swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2277
2278     si->outputDev->setMove(x,y);
2279     if((x1|y1|x2|y2)==0) x2++;
2280     si->outputDev->setClip(x1,y1,x2,y2);
2281
2282     pdf_page_render2(page, output);
2283 }
2284 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2285 {
2286     pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2287     swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2288     
2289     si->outputDev->setMove(0,0);
2290     si->outputDev->setClip(0,0,0,0);
2291     
2292     pdf_page_render2(page, output);
2293 }
2294
2295
2296 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2297 {
2298     pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2299     pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2300     pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2301     memset(info, 0, sizeof(pdf_page_info_t));
2302
2303     InfoOutputDev*output = new InfoOutputDev;
2304     
2305 #ifdef XPDF_101
2306     pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2307 #else
2308     pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2309 #endif
2310
2311     info->xMin = output->x1;
2312     info->yMin = output->y1;
2313     info->xMax = output->x2;
2314     info->yMax = output->y2;
2315     info->number_of_images = output->num_images;
2316     info->number_of_links = output->num_links;
2317     info->number_of_fonts = output->num_fonts;
2318
2319     delete output;
2320
2321     return info;
2322 }
2323
2324 void pdf_page_info_destroy(pdf_page_info_t*info)
2325 {
2326     free(info);
2327 }