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