a949fe006cc00b01cf197f90742685d13403a6c3
[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
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 #include "GHash.h"
62 #endif
63 #include "SWFOutputDev.h"
64
65 //swftools header files
66 #include "swfoutput.h"
67 #include "../lib/log.h"
68 #include "../lib/gfxdevice.h"
69 #include "../lib/gfxtools.h"
70 #include "../lib/gfxfont.h"
71
72 #include <math.h>
73
74 typedef struct _fontfile
75 {
76     char*filename;
77     int used;
78 } fontfile_t;
79
80 typedef struct _parameter
81 {
82     char*name;
83     char*value;
84     struct _parameter*next;
85 } parameter_t;
86
87 static parameter_t* device_config = 0;
88 static parameter_t* device_config_next = 0;
89
90 // for pdfswf_addfont
91 static fontfile_t fonts[2048];
92 static int fontnum = 0;
93
94 static int config_use_fontconfig = 1;
95
96 /* config */
97 static double caplinewidth = 3.0;
98 static double zoom = 72; /* xpdf: 86 */
99 static int forceType0Fonts = 1;
100
101 static void printInfoString(Dict *infoDict, char *key, char *fmt);
102 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
103
104 struct mapping {
105     char*pdffont;
106     char*filename;
107 } pdf2t1map[] ={
108 {"Times-Roman",           "n021003l"},
109 {"Times-Italic",          "n021023l"},
110 {"Times-Bold",            "n021004l"},
111 {"Times-BoldItalic",      "n021024l"},
112 {"Helvetica",             "n019003l"},
113 {"Helvetica-Oblique",     "n019023l"},
114 {"Helvetica-Bold",        "n019004l"},
115 {"Helvetica-BoldOblique", "n019024l"},
116 {"Courier",               "n022003l"},
117 {"Courier-Oblique",       "n022023l"},
118 {"Courier-Bold",          "n022004l"},
119 {"Courier-BoldOblique",   "n022024l"},
120 {"Symbol",                "s050000l"},
121 {"ZapfDingbats",          "d050000l"}};
122
123 class SWFOutputState {
124     public:
125     int clipping;
126     int textRender;
127     SWFOutputState() {
128         this->clipping = 0;
129         this->textRender = 0;
130     }
131 };
132
133 typedef struct _fontlist
134 {
135     char*id;
136     char*filename;
137     gfxfont_t*font;
138     _fontlist*next;
139 } fontlist_t;
140
141 class InfoOutputDev;
142
143 class SWFOutputDev:  public OutputDev {
144 public:
145   gfxdevice_t* output;
146
147   // Constructor.
148   SWFOutputDev();
149
150   // Destructor.
151   virtual ~SWFOutputDev() ;
152
153   void setMove(int x,int y);
154   void setClip(int x1,int y1,int x2,int y2);
155
156   void setInfo(InfoOutputDev*info) {this->info = info;}
157   
158   int save(char*filename);
159     
160   // Start a page.
161   void startFrame(int width, int height);
162
163   virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
164
165   void endframe();
166   void* get(char*name);
167
168   //----- get info about output device
169
170   // Does this device use upside-down coordinates?
171   // (Upside-down means (0,0) is the top left corner of the page.)
172   virtual GBool upsideDown();
173
174   // Does this device use drawChar() or drawString()?
175   virtual GBool useDrawChar();
176   
177   // Can this device draw gradients?
178   virtual GBool useGradients();
179   
180   virtual GBool interpretType3Chars() {return gTrue;}
181
182   //----- initialization and control
183
184   void setXRef(PDFDoc*doc, XRef *xref);
185
186   //----- link borders
187   virtual void drawLink(Link *link, Catalog *catalog) ;
188
189   //----- save/restore graphics state
190   virtual void saveState(GfxState *state) ;
191   virtual void restoreState(GfxState *state) ;
192
193   //----- update graphics state
194
195   virtual void updateFont(GfxState *state);
196   virtual void updateFillColor(GfxState *state);
197   virtual void updateStrokeColor(GfxState *state);
198   virtual void updateLineWidth(GfxState *state);
199   virtual void updateLineJoin(GfxState *state);
200   virtual void updateLineCap(GfxState *state);
201   
202   virtual void updateAll(GfxState *state) 
203   {
204       updateFont(state);
205       updateFillColor(state);
206       updateStrokeColor(state);
207       updateLineWidth(state);
208       updateLineJoin(state);
209       updateLineCap(state);
210   };
211
212   //----- path painting
213   virtual void stroke(GfxState *state) ;
214   virtual void fill(GfxState *state) ;
215   virtual void eoFill(GfxState *state) ;
216
217   //----- path clipping
218   virtual void clip(GfxState *state) ;
219   virtual void eoClip(GfxState *state) ;
220
221   //----- text drawing
222   virtual void beginString(GfxState *state, GString *s) ;
223   virtual void endString(GfxState *state) ;
224   virtual void endTextObject(GfxState *state);
225   virtual void drawChar(GfxState *state, double x, double y,
226                         double dx, double dy,
227                         double originX, double originY,
228                         CharCode code, Unicode *u, int uLen);
229
230   //----- image drawing
231   virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
232                              int width, int height, GBool invert,
233                              GBool inlineImg);
234   virtual void drawImage(GfxState *state, Object *ref, Stream *str,
235                          int width, int height, GfxImageColorMap *colorMap,
236                          int *maskColors, GBool inlineImg);
237   
238   virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
239   virtual void endType3Char(GfxState *state);
240
241   virtual void type3D0(GfxState *state, double wx, double wy);
242   virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury);
243
244   private:
245   void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
246                                    int width, int height, GfxImageColorMap*colorMap, GBool invert,
247                                    GBool inlineImg, int mask, int *maskColors);
248   int SWFOutputDev::setGfxFont(char*id, char*filename, double quality);
249   void strokeGfxline(GfxState *state, gfxline_t*line);
250   void clipToGfxLine(GfxState *state, gfxline_t*line);
251   void fillGfxLine(GfxState *state, gfxline_t*line);
252
253   void finish();
254
255   gfxresult_t*result; //filled when complete
256
257   char outer_clip_box; //whether the page clip box is still on
258
259   InfoOutputDev*info;
260   SWFOutputState states[64];
261   int statepos;
262
263   int currentpage;
264
265   PDFDoc*doc;
266   XRef*xref;
267
268   char* searchFont(char*name);
269   char* substituteFont(GfxFont*gfxFont, char*oldname);
270   char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
271   int t1id;
272   int textmodeinfo; // did we write "Text will be rendered as polygon" yet?
273   int jpeginfo; // did we write "File contains jpegs" yet?
274   int pbminfo; // did we write "File contains jpegs" yet?
275   int linkinfo; // did we write "File contains links" yet?
276   int ttfinfo; // did we write "File contains TrueType Fonts" yet?
277   int gradientinfo; // did we write "File contains Gradients yet?
278
279   int type3active; // are we between beginType3()/endType3()?
280
281   GfxState *laststate;
282
283   char type3Warning;
284
285   char* substitutetarget[256];
286   char* substitutesource[256];
287   int substitutepos;
288
289   int user_movex,user_movey;
290   int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
291
292   gfxline_t* current_text_stroke;
293   gfxline_t* current_text_clip;
294   char* current_font_id;
295   gfxfont_t* current_gfxfont;
296   gfxmatrix_t current_font_matrix;
297
298   fontlist_t* fontlist;
299
300   int*pages;
301   int pagebuflen;
302   int pagepos;
303
304   friend void swf_output_preparepage(swf_output_t*swf, int pdfpage, int outputpage);
305 };
306
307 typedef struct _drawnchar
308 {
309     gfxcoord_t x,y;
310     int charid;
311     gfxcolor_t color;
312 } drawnchar_t;
313
314 class CharBuffer
315 {
316     drawnchar_t * chars;
317     int buf_size;
318     int num_chars;
319
320 public:
321
322     CharBuffer()
323     {
324         buf_size = 32;
325         chars = (drawnchar_t*)malloc(sizeof(drawnchar_t)*buf_size);
326         memset(chars, 0, sizeof(drawnchar_t)*buf_size);
327         num_chars = 0;
328     }
329     ~CharBuffer()
330     {
331         free(chars);chars = 0;
332     }
333
334     void grow(int size)
335     {
336         if(size>=buf_size) {
337             buf_size += 32;
338             chars = (drawnchar_t*)realloc(chars, sizeof(drawnchar_t)*buf_size);
339         }
340     }
341
342     void addChar(int charid, gfxcoord_t x, gfxcoord_t y, gfxcolor_t color)
343     {
344         grow(num_chars);
345         chars[num_chars].x = x;
346         chars[num_chars].y = y;
347         chars[num_chars].color = color;
348         chars[num_chars].charid = charid;
349     }
350 };
351
352 static char*getFontID(GfxFont*font);
353
354 struct FontInfo
355 {
356     GfxFont*font;
357     double max_size;
358 };
359
360 class InfoOutputDev:  public OutputDev 
361 {
362   GHash* id2font;
363   FontInfo* currentfont;
364   public:
365   int x1,y1,x2,y2;
366   int num_links;
367   int num_images;
368   int num_fonts;
369
370   InfoOutputDev() 
371   {
372       num_links = 0;
373       num_images = 0;
374       num_fonts = 0;
375       id2font = new GHash();
376   }
377   virtual ~InfoOutputDev() 
378   {
379       delete id2font;
380   }
381   virtual GBool upsideDown() {return gTrue;}
382   virtual GBool useDrawChar() {return gTrue;}
383   virtual GBool useGradients() {return gTrue;}
384   virtual GBool interpretType3Chars() {return gTrue;}
385   virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
386   {
387       double x1,y1,x2,y2;
388       state->transform(crop_x1,crop_y1,&x1,&y1);
389       state->transform(crop_x2,crop_y2,&x2,&y2);
390       if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
391       if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
392       this->x1 = (int)x1;
393       this->y1 = (int)y1;
394       this->x2 = (int)x2;
395       this->y2 = (int)y2;
396   }
397   virtual void drawLink(Link *link, Catalog *catalog) 
398   {
399       num_links++;
400   }
401   virtual double getMaximumFontSize(char*id)
402   {
403       FontInfo*info = (FontInfo*)id2font->lookup(id);
404       if(!info) {
405           msg("<error> Unknown font id: %s", id);
406           return 0.0;
407       }
408       return info->max_size;
409   }
410
411   virtual void updateFont(GfxState *state) 
412   {
413       GfxFont*font = state->getFont();
414       if(!font)
415           return;
416       char*id = getFontID(font);
417       
418       FontInfo*info = (FontInfo*)id2font->lookup(id);
419       if(!info) {
420         GString* idStr = new GString(id);
421         info = new FontInfo;
422         info->font = font;
423         info->max_size = 0;
424         id2font->add(idStr, (void*)info);
425         free(id);
426         num_fonts++;
427       }
428       currentfont = info;
429   }
430   virtual void drawChar(GfxState *state, double x, double y,
431                         double dx, double dy,
432                         double originX, double originY,
433                         CharCode code, Unicode *u, int uLen)
434   {
435       int render = state->getRender();
436       if (render == 3)
437           return;
438       double m11,m21,m12,m22;
439       state->getFontTransMat(&m11, &m12, &m21, &m22);
440       m11 *= state->getHorizScaling();
441       m21 *= state->getHorizScaling();
442       double lenx = sqrt(m11*m11 + m12*m12);
443       double leny = sqrt(m21*m21 + m22*m22);
444       double len = lenx>leny?lenx:leny;
445       if(currentfont && currentfont->max_size < len) {
446           currentfont->max_size = len;
447       }
448   }
449   virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
450                              int width, int height, GBool invert,
451                              GBool inlineImg) 
452   {
453       num_images++;
454   }
455   virtual void drawImage(GfxState *state, Object *ref, Stream *str,
456                          int width, int height, GfxImageColorMap *colorMap,
457                          int *maskColors, GBool inlineImg)
458   {
459       num_images++;
460   }
461 };
462
463 SWFOutputDev::SWFOutputDev()
464 {
465     jpeginfo = 0;
466     textmodeinfo = 0;
467     ttfinfo = 0;
468     linkinfo = 0;
469     pbminfo = 0;
470     type3active = 0;
471     statepos = 0;
472     xref = 0;
473     substitutepos = 0;
474     type3Warning = 0;
475     user_movex = 0;
476     user_movey = 0;
477     user_clipx1 = 0;
478     user_clipy1 = 0;
479     user_clipx2 = 0;
480     user_clipy2 = 0;
481     current_text_stroke = 0;
482     current_text_clip = 0;
483     fontlist = 0;
484     result = 0;
485     outer_clip_box = 0;
486     pages = 0;
487     pagebuflen = 0;
488     pagepos = 0;
489     output = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
490     gfxdevice_swf_init(output);
491     /* configure device */
492     parameter_t*p = device_config;
493     while(p) {
494         output->setparameter(output, p->name, p->value);
495         p = p->next;
496     }
497 };
498   
499 void SWFOutputDev::setMove(int x,int y)
500 {
501     this->user_movex = x;
502     this->user_movey = y;
503 }
504
505 void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
506 {
507     if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
508     if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
509
510     this->user_clipx1 = x1;
511     this->user_clipy1 = y1;
512     this->user_clipx2 = x2;
513     this->user_clipy2 = y2;
514 }
515
516 static char*getFontID(GfxFont*font)
517 {
518     GString*gstr = font->getName();
519     char* fontname = gstr==0?0:gstr->getCString();
520     if(fontname==0) {
521         char buf[32];
522         Ref*r=font->getID();
523         sprintf(buf, "UFONT%d", r->num);
524         return strdup(buf);
525     }
526     return strdup(fontname);
527 }
528
529 static char*getFontName(GfxFont*font)
530 {
531     char*fontid = getFontID(font);
532     char*fontname= 0;
533     char* plus = strchr(fontid, '+');
534     if(plus && plus < &fontid[strlen(fontid)-1]) {
535         fontname = strdup(plus+1);
536     } else {
537         fontname = strdup(fontid);
538     }
539     free(fontid);
540     return fontname;
541 }
542
543 static char mybuf[1024];
544 static char* gfxstate2str(GfxState *state)
545 {
546   char*bufpos = mybuf;
547   GfxRGB rgb;
548   bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
549                                     state->getCTM()[0],
550                                     state->getCTM()[1],
551                                     state->getCTM()[2],
552                                     state->getCTM()[3],
553                                     state->getCTM()[4],
554                                     state->getCTM()[5]);
555   if(state->getX1()!=0.0)
556   bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
557   if(state->getY1()!=0.0)
558   bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
559   bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
560   bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
561   bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
562   bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
563   /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
564           state->getFillColor()->c[0], state->getFillColor()->c[1]);
565   bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
566           state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
567 /*  bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
568           state->getFillColor()->c[0], state->getFillColor()->c[1],
569           state->getFillColor()->c[2], state->getFillColor()->c[3],
570           state->getFillColor()->c[4], state->getFillColor()->c[5],
571           state->getFillColor()->c[6], state->getFillColor()->c[7]);
572   bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
573           state->getStrokeColor()->c[0], state->getFillColor()->c[1],
574           state->getStrokeColor()->c[2], state->getFillColor()->c[3],
575           state->getStrokeColor()->c[4], state->getFillColor()->c[5],
576           state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
577   state->getFillRGB(&rgb);
578   if(rgb.r || rgb.g || rgb.b)
579   bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
580   state->getStrokeRGB(&rgb);
581   if(rgb.r || rgb.g || rgb.b)
582   bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
583   if(state->getFillColorSpace()->getNComps()>1)
584   bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
585   if(state->getStrokeColorSpace()->getNComps()>1)
586   bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
587   if(state->getFillPattern())
588   bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
589   if(state->getStrokePattern())
590   bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
591  
592   if(state->getFillOpacity()!=1.0)
593   bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
594   if(state->getStrokeOpacity()!=1.0)
595   bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
596
597   bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
598  
599   double * dash;
600   int length;
601   double start;
602   state->getLineDash(&dash, &length, &start);
603   int t;
604   if(length)
605   {
606       bufpos+=sprintf(bufpos,"DASH%.1f[",start);
607       for(t=0;t<length;t++) {
608           bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
609       }
610       bufpos+=sprintf(bufpos,"]");
611   }
612
613   if(state->getFlatness()!=1)
614   bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
615   if(state->getLineJoin()!=0)
616   bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
617   if(state->getLineJoin()!=0)
618   bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
619   if(state->getLineJoin()!=0)
620   bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
621
622   if(state->getFont() && getFontID(state->getFont()))
623   bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
624   bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
625   bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
626                                    state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
627   if(state->getCharSpace())
628   bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
629   if(state->getWordSpace())
630   bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
631   if(state->getHorizScaling()!=1.0)
632   bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
633   if(state->getLeading())
634   bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
635   if(state->getRise())
636   bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
637   if(state->getRender())
638   bufpos+=sprintf(bufpos,"R%d ", state->getRender());
639   bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
640   bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
641   bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
642   if(state->getLineX())
643   bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
644   if(state->getLineY())
645   bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
646   bufpos+=sprintf(bufpos," ");
647   return mybuf;
648 }
649
650 static void dumpFontInfo(char*loglevel, GfxFont*font);
651 static int lastdumps[1024];
652 static int lastdumppos = 0;
653 /* nr = 0  unknown
654    nr = 1  substituting
655    nr = 2  type 3
656  */
657 static void showFontError(GfxFont*font, int nr) 
658 {  
659     Ref*r=font->getID();
660     int t;
661     for(t=0;t<lastdumppos;t++)
662         if(lastdumps[t] == r->num)
663             break;
664     if(t < lastdumppos)
665       return;
666     if(lastdumppos<sizeof(lastdumps)/sizeof(int))
667     lastdumps[lastdumppos++] = r->num;
668     if(nr == 0)
669       msg("<warning> The following font caused problems:");
670     else if(nr == 1)
671       msg("<warning> The following font caused problems (substituting):");
672     else if(nr == 2)
673       msg("<warning> The following Type 3 Font will be rendered as bitmap:");
674     dumpFontInfo("<warning>", font);
675 }
676
677 static void dumpFontInfo(char*loglevel, GfxFont*font)
678 {
679   char* id = getFontID(font);
680   char* name = getFontName(font);
681   Ref* r=font->getID();
682   msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
683
684   GString*gstr  = font->getTag();
685    
686   msg("%s| Tag: %s\n", loglevel, id);
687   
688   if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
689
690   GfxFontType type=font->getType();
691   switch(type) {
692     case fontUnknownType:
693      msg("%s| Type: unknown\n",loglevel);
694     break;
695     case fontType1:
696      msg("%s| Type: 1\n",loglevel);
697     break;
698     case fontType1C:
699      msg("%s| Type: 1C\n",loglevel);
700     break;
701     case fontType3:
702      msg("%s| Type: 3\n",loglevel);
703     break;
704     case fontTrueType:
705      msg("%s| Type: TrueType\n",loglevel);
706     break;
707     case fontCIDType0:
708      msg("%s| Type: CIDType0\n",loglevel);
709     break;
710     case fontCIDType0C:
711      msg("%s| Type: CIDType0C\n",loglevel);
712     break;
713     case fontCIDType2:
714      msg("%s| Type: CIDType2\n",loglevel);
715     break;
716   }
717   
718   Ref embRef;
719   GBool embedded = font->getEmbeddedFontID(&embRef);
720   char*embeddedName=0;
721   if(font->getEmbeddedFontName()) {
722     embeddedName = font->getEmbeddedFontName()->getCString();
723   }
724   if(embedded)
725    msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
726
727   gstr = font->getExtFontFile();
728   if(gstr)
729    msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
730
731   // Get font descriptor flags.
732   if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
733   if(font->isSerif()) msg("%s| is serif\n", loglevel);
734   if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
735   if(font->isItalic()) msg("%s| is italic\n", loglevel);
736   if(font->isBold()) msg("%s| is bold\n", loglevel);
737
738   free(id);
739   free(name);
740 }
741
742 //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");}
743 //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");}
744
745
746 void dump_outline(gfxline_t*line)
747 {
748     while(line) {
749         if(line->type == gfx_moveTo) {
750             msg("<debug> |     moveTo %.2f %.2f", line->x,line->y);
751         } else if(line->type == gfx_lineTo) {
752             msg("<debug> |     lineTo %.2f %.2f", line->x,line->y);
753         } else if(line->type == gfx_splineTo) {
754             msg("<debug> |     splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
755         }
756         line = line->next;
757     }
758 }
759
760 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey)
761 {
762     int num = path->getNumSubpaths();
763     int s,t;
764     int cpos = 0;
765     double lastx=0,lasty=0,posx=0,posy=0;
766     int needsfix=0;
767     if(!num) {
768         msg("<warning> empty path");
769         return 0;
770     }
771     gfxdrawer_t draw;
772     gfxdrawer_target_gfxline(&draw);
773
774     for(t = 0; t < num; t++) {
775         GfxSubpath *subpath = path->getSubpath(t);
776         int subnum = subpath->getNumPoints();
777         double bx=0,by=0,cx=0,cy=0;
778
779         for(s=0;s<subnum;s++) {
780            double x,y;
781            
782            state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
783            x += user_movex;
784            y += user_movey;
785
786            if(s==0) {
787                 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
788                     draw.lineTo(&draw, lastx, lasty);
789                 }
790                 draw.moveTo(&draw, x,y);
791                 posx = lastx = x; 
792                 posy = lasty = y;
793                 cpos = 0;
794                 needsfix = 0;
795            } else if(subpath->getCurve(s) && cpos==0) {
796                 bx = x;
797                 by = y;
798                 cpos = 1;
799            } else if(subpath->getCurve(s) && cpos==1) {
800                 cx = x;
801                 cy = y;
802                 cpos = 2;
803            } else {
804                 posx = x;
805                 posy = y;
806                 if(cpos==0) {
807                     draw.lineTo(&draw, x,y);
808                 } else {
809                     gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y, 0.05);
810                 }
811                 needsfix = 1;
812                 cpos = 0;
813            }
814         }
815     }
816     /* fix non-closed lines */
817     if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
818         draw.lineTo(&draw, lastx, lasty);
819     }
820     gfxline_t*result = (gfxline_t*)draw.result(&draw);
821     return result;
822 }
823
824 /*----------------------------------------------------------------------------
825  * Primitive Graphic routines
826  *----------------------------------------------------------------------------*/
827
828 void SWFOutputDev::stroke(GfxState *state) 
829 {
830     GfxPath * path = state->getPath();
831     gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex, user_movey);
832     strokeGfxline(state, line);
833     gfxline_free(line);
834 }
835
836 void SWFOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
837 {
838     int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
839     int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
840     double miterLimit = state->getMiterLimit();
841     double width = state->getTransformedLineWidth();
842
843     GfxRGB rgb;
844     double opaq = state->getStrokeOpacity();
845     if(type3active)
846         state->getFillRGB(&rgb);
847     else
848         state->getStrokeRGB(&rgb);
849     gfxcolor_t col;
850     col.r = (unsigned char)(rgb.r*255);
851     col.g = (unsigned char)(rgb.g*255);
852     col.b = (unsigned char)(rgb.b*255);
853     col.a = (unsigned char)(opaq*255);
854    
855     gfx_capType capType = gfx_capRound;
856     if(lineCap == 0) capType = gfx_capButt;
857     else if(lineCap == 1) capType = gfx_capRound;
858     else if(lineCap == 2) capType = gfx_capSquare;
859
860     gfx_joinType joinType = gfx_joinRound;
861     if(lineJoin == 0) joinType = gfx_joinMiter;
862     else if(lineJoin == 1) joinType = gfx_joinRound;
863     else if(lineJoin == 2) joinType = gfx_joinBevel;
864
865     int dashnum = 0;
866     double dashphase = 0;
867     double * ldash = 0;
868     state->getLineDash(&ldash, &dashnum, &dashphase);
869
870     gfxline_t*line2 = 0;
871
872     if(dashnum && ldash) {
873         float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
874         int t;
875         double cut = 0;
876         int fixzero = 0;
877         msg("<trace> %d dashes", dashnum);
878         msg("<trace> |  phase: %f", dashphase);
879         for(t=0;t<dashnum;t++) {
880             dash[t] = ldash[t];
881             msg("<trace> |  d%-3d: %f", t, ldash[t]);
882         }
883         dash[dashnum] = -1;
884         if(getLogLevel() >= LOGLEVEL_TRACE) {
885             dump_outline(line);
886         }
887
888         line2 = gfxtool_dash_line(line, dash, dashphase);
889         line = line2;
890         free(dash);
891         msg("<trace> After dashing:");
892     }
893     
894     if(getLogLevel() >= LOGLEVEL_TRACE)  {
895         double gray;
896         state->getStrokeGray(&gray);
897         msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x gray=%f\n",
898                 width,
899                 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
900                 lineCap==0?"butt": (lineJoin==1?"round":"square"),
901                 dashnum,
902                 col.r,col.g,col.b,col.a,
903                 gray
904                 );
905         dump_outline(line);
906     }
907    
908     //swfoutput_drawgfxline(output, line, width, &col, capType, joinType, miterLimit);
909     output->stroke(output, line, width, &col, capType, joinType, miterLimit);
910     
911     if(line2)
912         gfxline_free(line2);
913 }
914
915 gfxcolor_t getFillColor(GfxState * state)
916 {
917     GfxRGB rgb;
918     double opaq = state->getFillOpacity();
919     state->getFillRGB(&rgb);
920     gfxcolor_t col;
921     col.r = (unsigned char)(rgb.r*255);
922     col.g = (unsigned char)(rgb.g*255);
923     col.b = (unsigned char)(rgb.b*255);
924     col.a = (unsigned char)(opaq*255);
925     return col;
926 }
927
928 void SWFOutputDev::fillGfxLine(GfxState *state, gfxline_t*line) 
929 {
930     gfxcolor_t col = getFillColor(state);
931
932     if(getLogLevel() >= LOGLEVEL_TRACE)  {
933         msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
934         dump_outline(line);
935     }
936     output->fill(output, line, &col);
937 }
938 void SWFOutputDev::fill(GfxState *state) 
939 {
940     GfxPath * path = state->getPath();
941     gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
942     fillGfxLine(state, line);
943     gfxline_free(line);
944 }
945 void SWFOutputDev::eoFill(GfxState *state) 
946 {
947     GfxPath * path = state->getPath();
948     gfxcolor_t col = getFillColor(state);
949
950     gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
951
952     if(getLogLevel() >= LOGLEVEL_TRACE)  {
953         msg("<trace> eofill\n");
954         dump_outline(line);
955     }
956
957     output->fill(output, line, &col);
958     gfxline_free(line);
959 }
960
961 void SWFOutputDev::clip(GfxState *state) 
962 {
963     GfxPath * path = state->getPath();
964     gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
965     clipToGfxLine(state, line);
966     gfxline_free(line);
967 }
968
969 void SWFOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line) 
970 {
971     if(getLogLevel() >= LOGLEVEL_TRACE)  {
972         msg("<trace> clip\n");
973         dump_outline(line);
974     }
975
976     output->startclip(output, line);
977     states[statepos].clipping++;
978 }
979 void SWFOutputDev::eoClip(GfxState *state) 
980 {
981     GfxPath * path = state->getPath();
982     gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
983
984     if(getLogLevel() >= LOGLEVEL_TRACE)  {
985         msg("<trace> eoclip\n");
986         dump_outline(line);
987     }
988
989     output->startclip(output, line);
990     states[statepos].clipping++;
991     gfxline_free(line);
992 }
993
994 void SWFOutputDev::endframe()
995 {
996     if(outer_clip_box) {
997         output->endclip(output);
998         outer_clip_box = 0;
999     }
1000
1001     output->endpage(output);
1002 }
1003
1004 void SWFOutputDev::finish()
1005 {
1006     if(outer_clip_box) {
1007         if(output) {
1008             output->endclip(output);
1009         }
1010         outer_clip_box = 0;
1011     }
1012     if(output) {
1013         this->result = output->finish(output);
1014         free(output);output=0;
1015     }
1016 }
1017
1018 int SWFOutputDev::save(char*filename)
1019 {
1020     finish();
1021     return result->save(result, filename);
1022 }
1023 void* SWFOutputDev::get(char*name)
1024 {
1025     finish();
1026     return result->get(result, name);
1027 }
1028
1029 SWFOutputDev::~SWFOutputDev() 
1030 {
1031     finish();
1032
1033     if(this->result) {
1034         this->result->destroy(this->result);
1035         this->result = 0;
1036     }
1037     
1038     if(this->pages) {
1039         free(this->pages); this->pages = 0;
1040     }
1041
1042     fontlist_t*l = this->fontlist;
1043     while(l) {
1044         fontlist_t*next = l->next;
1045         l->next = 0;
1046         gfxfont_free(l->font);
1047         free(l->id);
1048         free(l->filename);
1049         free(l);
1050         l = next;
1051     }
1052     this->fontlist = 0;
1053 };
1054 GBool SWFOutputDev::upsideDown() 
1055 {
1056     return gTrue;
1057 };
1058 GBool SWFOutputDev::useDrawChar() 
1059 {
1060     return gTrue;
1061 }
1062 GBool SWFOutputDev::useGradients()
1063 {
1064     if(!gradientinfo)
1065     {
1066         msg("<notice> File contains gradients");
1067         gradientinfo = 1;
1068     }
1069     return gTrue;
1070 }
1071
1072 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
1073                       "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
1074
1075 #define RENDER_FILL 0
1076 #define RENDER_STROKE 1
1077 #define RENDER_FILLSTROKE 2
1078 #define RENDER_INVISIBLE 3
1079 #define RENDER_CLIP 4
1080
1081 static char tmp_printstr[4096];
1082 char* makeStringPrintable(char*str)
1083 {
1084     int len = strlen(str);
1085     int dots = 0;
1086     if(len>=80) {
1087         len = 80;
1088         dots = 1;
1089     }
1090     int t;
1091     for(t=0;t<len;t++) {
1092         char c = str[t];
1093         if(c<32 || c>124) {
1094             c = '.';
1095         }
1096         tmp_printstr[t] = c;
1097     }
1098     if(dots) {
1099         tmp_printstr[len++] = '.';
1100         tmp_printstr[len++] = '.';
1101         tmp_printstr[len++] = '.';
1102     }
1103     tmp_printstr[len] = 0;
1104     return tmp_printstr;
1105 }
1106
1107
1108 int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
1109 {
1110     int t;
1111     if(charname) {
1112         for(t=0;t<font->num_glyphs;t++) {
1113             if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) {
1114                 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1115                 return t;
1116             }
1117         }
1118         /* if we didn't find the character, maybe
1119            we can find the capitalized version */
1120         for(t=0;t<font->num_glyphs;t++) {
1121             if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) {
1122                 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1123                 return t;
1124             }
1125         }
1126     }
1127
1128     /* try to use the unicode id */
1129     if(u>=0 && u<font->max_unicode && font->unicode2glyph[u]>=0) {
1130         msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]);
1131         return font->unicode2glyph[u];
1132     }
1133
1134     /* we don't need to "draw" space characters, so don't overdo the search
1135        for a matching glyph */
1136     if(charname && !strcasecmp(charname, "space"))
1137         return -1;
1138
1139     if(charnr>=0 && charnr<font->num_glyphs) {
1140         msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1141         return charnr;
1142     }
1143     
1144     return -1;
1145 }
1146
1147
1148 void SWFOutputDev::beginString(GfxState *state, GString *s) 
1149
1150     int render = state->getRender();
1151     if(current_text_stroke) {
1152         msg("<error> Error: Incompatible change of text rendering to %d while inside cliptext", render);
1153     }
1154
1155     msg("<trace> beginString(%s) render=%d", makeStringPrintable(s->getCString()), render);
1156     double m11,m21,m12,m22;
1157 //    msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
1158     state->getFontTransMat(&m11, &m12, &m21, &m22);
1159     m11 *= state->getHorizScaling();
1160     m21 *= state->getHorizScaling();
1161
1162     this->current_font_matrix.m00 = m11 / 1024.0;
1163     this->current_font_matrix.m01 = m12 / 1024.0;
1164     this->current_font_matrix.m10 = -m21 / 1024.0;
1165     this->current_font_matrix.m11 = -m22 / 1024.0;
1166     this->current_font_matrix.tx = 0;
1167     this->current_font_matrix.ty = 0;
1168
1169     gfxmatrix_t m = this->current_font_matrix;
1170
1171     /*if(render != 3 && render != 0)
1172         msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/
1173     states[statepos].textRender = render;
1174 }
1175
1176 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
1177                         double dx, double dy,
1178                         double originX, double originY,
1179                         CharCode c, Unicode *_u, int uLen)
1180 {
1181     int render = state->getRender();
1182     // check for invisible text -- this is used by Acrobat Capture
1183     if (render == 3) {
1184         msg("<debug> Ignoring invisible text: char %d at %f,%f", c, x, y);
1185         return;
1186     }
1187
1188     if(states[statepos].textRender != render)
1189         msg("<error> Internal error: drawChar.render!=beginString.render");
1190
1191     gfxcolor_t col = getFillColor(state);
1192
1193     Gushort *CIDToGIDMap = 0;
1194     GfxFont*font = state->getFont();
1195
1196     if(font->getType() == fontType3) {
1197         /* type 3 chars are passed as graphics */
1198         msg("<debug> type3 char at %f/%f", x, y);
1199         return;
1200     }
1201     
1202     Unicode u=0;
1203     char*name=0;
1204
1205     if(_u && uLen) {
1206         u = *_u;
1207         if (u) {
1208             int t;
1209             /* find out char name from unicode index 
1210                TODO: should be precomputed
1211              */
1212             for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
1213                 if(nameToUnicodeTab[t].u == u) {
1214                     name = nameToUnicodeTab[t].name;
1215                     break;
1216                 }
1217             }
1218         }
1219     }
1220
1221     if(font->isCIDFont()) {
1222         GfxCIDFont*cfont = (GfxCIDFont*)font;
1223
1224         if(font->getType() == fontCIDType2)
1225             CIDToGIDMap = cfont->getCIDToGID();
1226     } else {
1227         Gfx8BitFont*font8;
1228         font8 = (Gfx8BitFont*)font;
1229         char**enc=font8->getEncoding();
1230         if(enc && enc[c] && strcasecmp(enc[c], "space")) {
1231            name = enc[c];
1232         }
1233     }
1234     if (CIDToGIDMap) {
1235         msg("<debug> drawChar(%f, %f, c='%c' (%d), GID=%d, u=%d <%d>) CID=%d name=\"%s\" render=%d\n", x, y, (c&127)>=32?c:'?', c, CIDToGIDMap[c], u, uLen, font->isCIDFont(), FIXNULL(name), render);
1236         c = CIDToGIDMap[c];
1237     } else {
1238         msg("<debug> drawChar(%f,%f,c='%c' (%d), u=%d <%d>) CID=%d name=\"%s\" render=%d\n",x,y,(c&127)>=32?c:'?',c,u, uLen, font->isCIDFont(), FIXNULL(name), render);
1239     }
1240
1241     int charid = -1;
1242    
1243     if(uLen<=1) {
1244         charid = getGfxCharID(current_gfxfont, c, name, u);
1245     } else {
1246         charid = getGfxCharID(current_gfxfont, c, 0, -1);
1247         if(charid < 0) {
1248             /* multiple unicodes- should usually map to a ligature.
1249                if the ligature doesn't exist, we need to draw
1250                the characters one-by-one. */
1251             int t;
1252             msg("<warning> ligature %d missing in font %s\n", c, current_font_id);
1253             for(t=0;t<uLen;t++) {
1254                 drawChar(state, x, y, dx, dy, originX, originY, c, _u+t, 1);
1255             }
1256             return;
1257         }
1258     }
1259
1260     if(charid<0 && name) {
1261         if(strcasecmp(name, "space")) {
1262             msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)", 
1263                     FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
1264         }
1265         return;
1266     }
1267
1268     gfxmatrix_t m = this->current_font_matrix;
1269     state->transform(x, y, &m.tx, &m.ty);
1270     m.tx += user_movex;
1271     m.ty += user_movey;
1272
1273     if(render == RENDER_FILL) {
1274         output->drawchar(output, current_font_id, charid, &col, &m);
1275     } else {
1276         msg("<debug> Drawing glyph %d as shape", charid);
1277         if(!textmodeinfo) {
1278             msg("<notice> Some texts will be rendered as shape");
1279             textmodeinfo = 1;
1280         }
1281         gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
1282         gfxline_t*tglyph = gfxline_clone(glyph);
1283         gfxline_transform(tglyph, &m);
1284         if((render&3) != RENDER_INVISIBLE) {
1285             gfxline_t*add = gfxline_clone(tglyph);
1286             current_text_stroke = gfxline_append(current_text_stroke, add);
1287         }
1288         if(render&RENDER_CLIP) {
1289             gfxline_t*add = gfxline_clone(tglyph);
1290             current_text_clip = gfxline_append(current_text_clip, add);
1291         }
1292         gfxline_free(tglyph);
1293     }
1294 }
1295
1296 void SWFOutputDev::endString(GfxState *state) 
1297
1298     int render = state->getRender();
1299     msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
1300     if(states[statepos].textRender != render)
1301         msg("<error> Internal error: drawChar.render!=beginString.render");
1302     
1303     if(current_text_stroke) {
1304         /* fillstroke and stroke text rendering objects we can process right
1305            now (as there may be texts of other rendering modes in this
1306            text object)- clipping objects have to wait until endTextObject,
1307            however */
1308         if((render&3) == RENDER_FILL) {
1309             fillGfxLine(state, current_text_stroke);
1310             gfxline_free(current_text_stroke);
1311             current_text_stroke = 0;
1312         } else if((render&3) == RENDER_FILLSTROKE) {
1313             fillGfxLine(state, current_text_stroke);
1314             strokeGfxline(state, current_text_stroke);
1315             gfxline_free(current_text_stroke);
1316             current_text_stroke = 0;
1317         } else if((render&3) == RENDER_STROKE) {
1318             strokeGfxline(state, current_text_stroke);
1319             gfxline_free(current_text_stroke);
1320             current_text_stroke = 0;
1321         }
1322     }
1323 }    
1324
1325 void SWFOutputDev::endTextObject(GfxState *state)
1326 {
1327     int render = state->getRender();
1328     msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
1329     if(states[statepos].textRender != render)
1330         msg("<error> Internal error: drawChar.render!=beginString.render");
1331     
1332     if(current_text_clip) {
1333         clipToGfxLine(state, current_text_clip);
1334         gfxline_free(current_text_clip);
1335         current_text_clip = 0;
1336     }
1337 }
1338
1339 /* the logic seems to be as following:
1340    first, beginType3Char is called, with the charcode and the coordinates.
1341    if this function returns true, it already knew about the char and has now drawn it.
1342    if the function returns false, it's a new char, and type3D1 is called with some parameters-
1343    the all draw operations until endType3Char are part of the char (which in this moment is
1344    at the position first passed to beginType3Char). the char ends with endType3Char.
1345
1346    The drawing operations between beginType3Char and endType3Char are somewhat different to
1347    the normal ones. For example, the fillcolor equals the stroke color.
1348 */
1349
1350 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1351 {
1352     msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1353     type3active = 1;
1354     /* the character itself is going to be passed using the draw functions */
1355     return gFalse; /* gTrue= is_in_cache? */
1356 }
1357
1358 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
1359     msg("<debug> type3D0 width=%f height=%f", wx, wy);
1360 }
1361 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1362     msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1363             llx,lly,urx,ury);
1364 }
1365
1366 void SWFOutputDev::endType3Char(GfxState *state)
1367 {
1368     type3active = 0;
1369     msg("<debug> endType3Char");
1370 }
1371
1372 void SWFOutputDev::startFrame(int width, int height) 
1373 {
1374     output->startpage(output, width, height);
1375 }
1376
1377 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2) 
1378 {
1379     this->currentpage = pageNum;
1380     double x1,y1,x2,y2;
1381     int rot = doc->getPageRotate(1);
1382     gfxcolor_t white;
1383     laststate = state;
1384     gfxline_t clippath[5];
1385
1386     white.r = white.g = white.b = white.a = 255;
1387
1388     /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1389     state->transform(state->getX2(),state->getY2(),&x2,&y2);
1390     Use CropBox, not MediaBox, as page size
1391     */
1392     
1393     /*x1 = crop_x1;
1394     y1 = crop_y1;
1395     x2 = crop_x2;
1396     y2 = crop_y2;*/
1397     state->transform(crop_x1,crop_y1,&x1,&y1); //x1 += user_movex; y1 += user_movey;
1398     state->transform(crop_x2,crop_y2,&x2,&y2); //x2 += user_movex; y2 += user_movey;
1399
1400     if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1401     if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1402
1403
1404     /* apply user clip box */
1405     if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1406         /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1407         /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1408         /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1409         /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1410     }
1411
1412     //msg("<verbose> Bounding box is (%f,%f)-(%f,%f) [shifted by %d/%d]", x1,y1,x2,y2, user_movex, user_movey);
1413     
1414     if(outer_clip_box) {
1415         output->endclip(output);
1416         outer_clip_box = 0;
1417     }
1418
1419     msg("<notice> processing PDF page %d (%dx%d:%d:%d) (move:%d:%d)", pageNum, (int)x2-(int)x1,(int)y2-(int)y1, (int)x1, (int)y1, user_movex, user_movey);
1420     if(rot!=0)
1421         msg("<verbose> page is rotated %d degrees\n", rot);
1422
1423     clippath[0].type = gfx_moveTo;clippath[0].x = x1; clippath[0].y = y1; clippath[0].next = &clippath[1];
1424     clippath[1].type = gfx_lineTo;clippath[1].x = x2; clippath[1].y = y1; clippath[1].next = &clippath[2];
1425     clippath[2].type = gfx_lineTo;clippath[2].x = x2; clippath[2].y = y2; clippath[2].next = &clippath[3];
1426     clippath[3].type = gfx_lineTo;clippath[3].x = x1; clippath[3].y = y2; clippath[3].next = &clippath[4];
1427     clippath[4].type = gfx_lineTo;clippath[4].x = x1; clippath[4].y = y1; clippath[4].next = 0;
1428     output->startclip(output, clippath); outer_clip_box = 1;
1429     output->fill(output, clippath, &white);
1430 }
1431
1432 void SWFOutputDev::drawLink(Link *link, Catalog *catalog) 
1433 {
1434     msg("<debug> drawlink\n");
1435     double x1, y1, x2, y2, w;
1436     GfxRGB rgb;
1437     gfxline_t points[5];
1438     int x, y;
1439
1440 #ifdef XPDF_101
1441     link->getBorder(&x1, &y1, &x2, &y2, &w);
1442 #else
1443     link->getRect(&x1, &y1, &x2, &y2);
1444 #endif
1445     rgb.r = 0;
1446     rgb.g = 0;
1447     rgb.b = 1;
1448     cvtUserToDev(x1, y1, &x, &y);
1449     points[0].type = gfx_moveTo;
1450     points[0].x = points[4].x = x + user_movex;
1451     points[0].y = points[4].y = y + user_movey;
1452     points[0].next = &points[1];
1453     cvtUserToDev(x2, y1, &x, &y);
1454     points[1].type = gfx_lineTo;
1455     points[1].x = x + user_movex;
1456     points[1].y = y + user_movey;
1457     points[1].next = &points[2];
1458     cvtUserToDev(x2, y2, &x, &y);
1459     points[2].type = gfx_lineTo;
1460     points[2].x = x + user_movex;
1461     points[2].y = y + user_movey;
1462     points[2].next = &points[3];
1463     cvtUserToDev(x1, y2, &x, &y);
1464     points[3].type = gfx_lineTo;
1465     points[3].x = x + user_movex;
1466     points[3].y = y + user_movey;
1467     points[3].next = &points[4];
1468     cvtUserToDev(x1, y1, &x, &y);
1469     points[4].type = gfx_lineTo;
1470     points[4].x = x + user_movex;
1471     points[4].y = y + user_movey;
1472     points[4].next = 0;
1473
1474     LinkAction*action=link->getAction();
1475     char buf[128];
1476     char*s = 0;
1477     char*type = "-?-";
1478     char*url = 0;
1479     char*named = 0;
1480     int page = -1;
1481     switch(action->getKind())
1482     {
1483         case actionGoTo: {
1484             type = "GoTo";
1485             LinkGoTo *ha=(LinkGoTo *)link->getAction();
1486             LinkDest *dest=NULL;
1487             if (ha->getDest()==NULL) 
1488                 dest=catalog->findDest(ha->getNamedDest());
1489             else dest=ha->getDest();
1490             if (dest){ 
1491               if (dest->isPageRef()){
1492                 Ref pageref=dest->getPageRef();
1493                 page=catalog->findPage(pageref.num,pageref.gen);
1494               }
1495               else  page=dest->getPageNum();
1496               sprintf(buf, "%d", page);
1497               s = strdup(buf);
1498             }
1499         }
1500         break;
1501         case actionGoToR: {
1502             type = "GoToR";
1503             LinkGoToR*l = (LinkGoToR*)action;
1504             GString*g = l->getNamedDest();
1505             if(g)
1506              s = strdup(g->getCString());
1507         }
1508         break;
1509         case actionNamed: {
1510             type = "Named";
1511             LinkNamed*l = (LinkNamed*)action;
1512             GString*name = l->getName();
1513             if(name) {
1514                 s = strdup(name->lowerCase()->getCString());
1515                 named = name->getCString();
1516                 if(!strchr(s,':')) 
1517                 {
1518                     if(strstr(s, "next") || strstr(s, "forward"))
1519                     {
1520                         page = currentpage + 1;
1521                     }
1522                     else if(strstr(s, "prev") || strstr(s, "back"))
1523                     {
1524                         page = currentpage - 1;
1525                     }
1526                     else if(strstr(s, "last") || strstr(s, "end"))
1527                     {
1528                         if(pages && pagepos>0)
1529                             page = pages[pagepos-1];
1530                     }
1531                     else if(strstr(s, "first") || strstr(s, "top"))
1532                     {
1533                         page = 1;
1534                     }
1535                 }
1536             }
1537         }
1538         break;
1539         case actionLaunch: {
1540             type = "Launch";
1541             LinkLaunch*l = (LinkLaunch*)action;
1542             GString * str = new GString(l->getFileName());
1543             str->append(l->getParams());
1544             s = strdup(str->getCString());
1545             delete str;
1546         }
1547         break;
1548         case actionURI: {
1549             type = "URI";
1550             LinkURI*l = (LinkURI*)action;
1551             GString*g = l->getURI();
1552             if(g) {
1553              url = g->getCString();
1554              s = strdup(url);
1555             }
1556         }
1557         break;
1558         case actionUnknown: {
1559             type = "Unknown";
1560             LinkUnknown*l = (LinkUnknown*)action;
1561             s = strdup("");
1562         }
1563         break;
1564         default: {
1565             msg("<error> Unknown link type!\n");
1566             break;
1567         }
1568     }
1569     if(!s) s = strdup("-?-");
1570
1571     if(!linkinfo && (page || url))
1572     {
1573         msg("<notice> File contains links");
1574         linkinfo = 1;
1575     }
1576     
1577     if(page>0)
1578     {
1579         int t;
1580         int lpage = -1;
1581         for(t=1;t<=pagepos;t++) {
1582             if(pages[t]==page) {
1583                 lpage = t;
1584                 break;
1585             }
1586         }
1587         if(lpage>=0) {
1588             char buf[80];
1589             sprintf(buf, "page%d", t);
1590             output->drawlink(output, points, buf);
1591         } else {
1592             msg("<warning> Invalid link to page %d", page);
1593         }
1594     }
1595     else if(url)
1596     {
1597         output->drawlink(output, points, url);
1598     }
1599
1600     msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1601     free(s);s=0;
1602 }
1603
1604 void SWFOutputDev::saveState(GfxState *state) {
1605   msg("<trace> saveState\n");
1606   updateAll(state);
1607   if(statepos>=64) {
1608     msg("<error> Too many nested states in pdf.");
1609     return;
1610   }
1611   statepos ++;
1612   states[statepos].clipping = 0; //? shouldn't this be the current value?
1613   states[statepos].textRender = states[statepos-1].textRender;
1614 };
1615
1616 void SWFOutputDev::restoreState(GfxState *state) {
1617   msg("<trace> restoreState\n");
1618   updateAll(state);
1619   while(states[statepos].clipping) {
1620       output->endclip(output);
1621       states[statepos].clipping--;
1622   }
1623   statepos--;
1624 }
1625
1626 char* SWFOutputDev::searchFont(char*name) 
1627 {       
1628     int i;
1629     char*filename=0;
1630     int is_standard_font = 0;
1631         
1632     msg("<verbose> SearchFont(%s)", name);
1633
1634     /* see if it is a pdf standard font */
1635     for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++) 
1636     {
1637         if(!strcmp(name, pdf2t1map[i].pdffont))
1638         {
1639             name = pdf2t1map[i].filename;
1640             is_standard_font = 1;
1641             break;
1642         }
1643     }
1644     /* look in all font files */
1645     for(i=0;i<fontnum;i++) 
1646     {
1647         if(strstr(fonts[i].filename, name))
1648         {
1649             if(!fonts[i].used) {
1650
1651                 fonts[i].used = 1;
1652                 if(!is_standard_font)
1653                     msg("<notice> Using %s for %s", fonts[i].filename, name);
1654             }
1655             return strdup(fonts[i].filename);
1656         }
1657     }
1658     return 0;
1659 }
1660
1661 void SWFOutputDev::updateLineWidth(GfxState *state)
1662 {
1663     double width = state->getTransformedLineWidth();
1664     //swfoutput_setlinewidth(&output, width);
1665 }
1666
1667 void SWFOutputDev::updateLineCap(GfxState *state)
1668 {
1669     int c = state->getLineCap();
1670 }
1671
1672 void SWFOutputDev::updateLineJoin(GfxState *state)
1673 {
1674     int j = state->getLineJoin();
1675 }
1676
1677 void SWFOutputDev::updateFillColor(GfxState *state) 
1678 {
1679     GfxRGB rgb;
1680     double opaq = state->getFillOpacity();
1681     state->getFillRGB(&rgb);
1682
1683     //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1684 }
1685
1686 void SWFOutputDev::updateStrokeColor(GfxState *state) 
1687 {
1688     GfxRGB rgb;
1689     double opaq = state->getStrokeOpacity();
1690     state->getStrokeRGB(&rgb);
1691     //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1692 }
1693
1694 void FoFiWrite(void *stream, char *data, int len)
1695 {
1696    fwrite(data, len, 1, (FILE*)stream);
1697 }
1698
1699 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1700 {
1701     char*tmpFileName = NULL;
1702     FILE *f;
1703     int c;
1704     char *fontBuf;
1705     int fontLen;
1706     Ref embRef;
1707     Object refObj, strObj;
1708     char namebuf[512];
1709     tmpFileName = mktmpname(namebuf);
1710     int ret;
1711
1712     ret = font->getEmbeddedFontID(&embRef);
1713     if(!ret) {
1714         msg("<verbose> Didn't get embedded font id");
1715         /* not embedded- the caller should now search the font
1716            directories for this font */
1717         return 0;
1718     }
1719
1720     f = fopen(tmpFileName, "wb");
1721     if (!f) {
1722       msg("<error> Couldn't create temporary Type 1 font file");
1723         return 0;
1724     }
1725
1726     /*if(font->isCIDFont()) {
1727         GfxCIDFont* cidFont = (GfxCIDFont *)font;
1728         GString c = cidFont->getCollection();
1729         msg("<notice> Collection: %s", c.getCString());
1730     }*/
1731
1732     //if (font->getType() == fontType1C) {
1733     if (0) { //font->getType() == fontType1C) {
1734       if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1735         fclose(f);
1736         msg("<error> Couldn't read embedded font file");
1737         return 0;
1738       }
1739 #ifdef XPDF_101
1740       Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1741       if(!cvt) return 0;
1742       cvt->convertToType1(f);
1743 #else
1744       FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1745       if(!cvt) return 0;
1746       cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1747 #endif
1748       //cvt->convertToCIDType0("test", f);
1749       //cvt->convertToType0("test", f);
1750       delete cvt;
1751       gfree(fontBuf);
1752     } else if(font->getType() == fontTrueType) {
1753       msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1754       if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1755         fclose(f);
1756         msg("<error> Couldn't read embedded font file");
1757         return 0;
1758       }
1759 #ifdef XPDF_101
1760       TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1761       cvt->writeTTF(f);
1762 #else
1763       FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1764       cvt->writeTTF(FoFiWrite, f);
1765 #endif
1766       delete cvt;
1767       gfree(fontBuf);
1768     } else {
1769       font->getEmbeddedFontID(&embRef);
1770       refObj.initRef(embRef.num, embRef.gen);
1771       refObj.fetch(ref, &strObj);
1772       refObj.free();
1773       strObj.streamReset();
1774       int f4[4];
1775       char f4c[4];
1776       int t;
1777       for(t=0;t<4;t++) {
1778           f4[t] = strObj.streamGetChar();
1779           f4c[t] = (char)f4[t];
1780           if(f4[t] == EOF)
1781               break;
1782       }
1783       if(t==4) {
1784           if(!strncmp(f4c, "true", 4)) {
1785               /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1786                  Change this on the fly */
1787               f4[0] = f4[2] = f4[3] = 0;
1788               f4[1] = 1;
1789           }
1790           fputc(f4[0], f);
1791           fputc(f4[1], f);
1792           fputc(f4[2], f);
1793           fputc(f4[3], f);
1794
1795           while ((c = strObj.streamGetChar()) != EOF) {
1796             fputc(c, f);
1797           }
1798       }
1799       strObj.streamClose();
1800       strObj.free();
1801     }
1802     fclose(f);
1803
1804     return strdup(tmpFileName);
1805 }
1806     
1807 char* searchForSuitableFont(GfxFont*gfxFont)
1808 {
1809     char*name = getFontName(gfxFont);
1810     char*fontname = 0;
1811     char*filename = 0;
1812
1813     if(!config_use_fontconfig)
1814         return 0;
1815     
1816 #ifdef HAVE_FONTCONFIG
1817     FcPattern *pattern, *match;
1818     FcResult result;
1819     FcChar8 *v;
1820
1821     static int fcinitcalled = false; 
1822         
1823     msg("<debug> searchForSuitableFont(%s)", name);
1824     
1825     // call init ony once
1826     if (!fcinitcalled) {
1827         msg("<debug> Initializing FontConfig...");
1828         fcinitcalled = true;
1829         if(!FcInit()) {
1830             msg("<debug> FontConfig Initialization failed. Disabling.");
1831             config_use_fontconfig = 0;
1832             return 0;
1833         }
1834         msg("<debug> ...initialized FontConfig");
1835     }
1836    
1837     msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1838     pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1839     if (gfxFont->isItalic()) // check for italic
1840         msg("<debug> FontConfig: Adding Italic Slant");
1841         FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1842     if (gfxFont->isBold()) // check for bold
1843         msg("<debug> FontConfig: Adding Bold Weight");
1844         FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1845
1846     msg("<debug> FontConfig: Try to match...");
1847     // configure and match using the original font name 
1848     FcConfigSubstitute(0, pattern, FcMatchPattern); 
1849     FcDefaultSubstitute(pattern);
1850     match = FcFontMatch(0, pattern, &result);
1851     
1852     if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1853         msg("<debug> FontConfig: family=%s", (char*)v);
1854         // if we get an exact match
1855         if (strcmp((char *)v, name) == 0) {
1856             if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1857                 filename = strdup((char*)v); // mem leak
1858                 char *nfn = strrchr(filename, '/');
1859                 if(nfn) fontname = strdup(nfn+1);
1860                 else    fontname = filename;
1861             }
1862             msg("<debug> FontConfig: Returning \"%s\"", fontname);
1863         } else {
1864             // initialize patterns
1865             FcPatternDestroy(pattern);
1866             FcPatternDestroy(match);
1867
1868             // now match against serif etc.
1869             if (gfxFont->isSerif()) {
1870                 msg("<debug> FontConfig: Create Serif Family Pattern");
1871                 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1872             } else if (gfxFont->isFixedWidth()) {
1873                 msg("<debug> FontConfig: Create Monospace Family Pattern");
1874                 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1875             } else {
1876                 msg("<debug> FontConfig: Create Sans Family Pattern");
1877                 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1878             }
1879
1880             // check for italic
1881             if (gfxFont->isItalic()) {
1882                 msg("<debug> FontConfig: Adding Italic Slant");
1883                 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1884             }
1885             // check for bold
1886             if (gfxFont->isBold()) {
1887                 msg("<debug> FontConfig: Adding Bold Weight");
1888                 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1889             }
1890
1891             msg("<debug> FontConfig: Try to match... (2)");
1892             // configure and match using serif etc
1893             FcConfigSubstitute (0, pattern, FcMatchPattern);
1894             FcDefaultSubstitute (pattern);
1895             match = FcFontMatch (0, pattern, &result);
1896             
1897             if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1898                 filename = strdup((char*)v); // mem leak
1899                 char *nfn = strrchr(filename, '/');
1900                 if(nfn) fontname = strdup(nfn+1);
1901                 else    fontname = filename;
1902             }
1903             msg("<debug> FontConfig: Returning \"%s\"", fontname);
1904         }        
1905     }
1906
1907     //printf("FONTCONFIG: pattern");
1908     //FcPatternPrint(pattern);
1909     //printf("FONTCONFIG: match");
1910     //FcPatternPrint(match);
1911  
1912     FcPatternDestroy(pattern);
1913     FcPatternDestroy(match);
1914
1915     pdfswf_addfont(filename);
1916     return fontname;
1917 #else
1918     return 0;
1919 #endif
1920 }
1921
1922 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1923 {
1924     char*fontname = 0, *filename = 0;
1925     msg("<notice> subsituteFont(%s)", oldname);
1926
1927     if(!(fontname = searchForSuitableFont(gfxFont))) {
1928         fontname = "Times-Roman";
1929     }
1930     filename = searchFont(fontname);
1931     if(!filename) {
1932         msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1933         return 0;
1934     }
1935
1936     if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1937         msg("<fatal> Too many fonts in file.");
1938         exit(1);
1939     }
1940     if(oldname) {
1941         substitutesource[substitutepos] = strdup(oldname); //mem leak
1942         substitutetarget[substitutepos] = fontname;
1943         msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1944         substitutepos ++;
1945     }
1946     return strdup(filename); //mem leak
1947 }
1948
1949 void unlinkfont(char* filename)
1950 {
1951     int l;
1952     if(!filename)
1953         return;
1954     l=strlen(filename);
1955     unlink(filename);
1956     if(!strncmp(&filename[l-4],".afm",4)) {
1957         memcpy(&filename[l-4],".pfb",4);
1958         unlink(filename);
1959         memcpy(&filename[l-4],".pfa",4);
1960         unlink(filename);
1961         memcpy(&filename[l-4],".afm",4);
1962         return;
1963     } else 
1964     if(!strncmp(&filename[l-4],".pfa",4)) {
1965         memcpy(&filename[l-4],".afm",4);
1966         unlink(filename);
1967         memcpy(&filename[l-4],".pfa",4);
1968         return;
1969     } else 
1970     if(!strncmp(&filename[l-4],".pfb",4)) {
1971         memcpy(&filename[l-4],".afm",4);
1972         unlink(filename);
1973         memcpy(&filename[l-4],".pfb",4);
1974         return;
1975     }
1976 }
1977
1978 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref) 
1979 {
1980     this->doc = doc;
1981     this->xref = xref;
1982 }
1983
1984 int SWFOutputDev::setGfxFont(char*id, char*filename, double maxSize)
1985 {
1986     gfxfont_t*font = 0;
1987     fontlist_t*last=0,*l = this->fontlist;
1988
1989     /* TODO: should this be part of the state? */
1990     while(l) {
1991         last = l;
1992         if(!strcmp(l->id, id)) {
1993             current_font_id = l->id;
1994             current_gfxfont = l->font;
1995             font = l->font;
1996             output->addfont(output, id, current_gfxfont);
1997             return 1;
1998         }
1999         l = l->next;
2000     }
2001     if(!filename) return 0;
2002
2003     /* A font size of e.g. 9 means the font will be scaled down by
2004        1024 and scaled up by 9. So to have a maximum error of 1/20px,
2005        we have to divide 0.05 by (fontsize/1024)
2006      */
2007     double quality = (1024 * 0.05) / maxSize;
2008     
2009     font = gfxfont_load(filename, quality);
2010     l = new fontlist_t;
2011     l->font = font;
2012     l->filename = strdup(filename);
2013     l->id = strdup(id);
2014     l->next = 0;
2015     current_font_id = l->id;
2016     current_gfxfont = l->font;
2017     if(last) {
2018         last->next = l;
2019     } else {
2020         this->fontlist = l;
2021     }
2022     output->addfont(output, id, current_gfxfont);
2023     return 1;
2024 }
2025
2026 void SWFOutputDev::updateFont(GfxState *state) 
2027 {
2028     GfxFont*gfxFont = state->getFont();
2029       
2030     if (!gfxFont) {
2031         return;
2032     }  
2033     char * fontid = getFontID(gfxFont);
2034     double maxSize = 1.0;
2035
2036     if(this->info) {
2037         maxSize = this->info->getMaximumFontSize(fontid);
2038     }
2039     
2040     int t;
2041     /* first, look if we substituted this font before-
2042        this way, we don't initialize the T1 Fonts
2043        too often */
2044     for(t=0;t<substitutepos;t++) {
2045         if(!strcmp(fontid, substitutesource[t])) {
2046             free(fontid);fontid=0;
2047             fontid = strdup(substitutetarget[t]);
2048             break;
2049         }
2050     }
2051
2052     /* second, see if this is a font which was used before-
2053        if so, we are done */
2054     if(setGfxFont(fontid, 0, 0)) {
2055         free(fontid);
2056         return;
2057     }
2058 /*    if(swfoutput_queryfont(&output, fontid))
2059         swfoutput_setfont(&output, fontid, 0);
2060         
2061         msg("<debug> updateFont(%s) [cached]", fontid);
2062         return;
2063     }*/
2064
2065     // look for Type 3 font
2066     if (gfxFont->getType() == fontType3) {
2067         if(!type3Warning) {
2068             type3Warning = gTrue;
2069             showFontError(gfxFont, 2);
2070         }
2071         free(fontid);
2072         return;
2073     }
2074
2075     /* now either load the font, or find a substitution */
2076
2077     Ref embRef;
2078     GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
2079
2080     char*fileName = 0;
2081     int del = 0;
2082     if(embedded &&
2083        (gfxFont->getType() == fontType1 ||
2084         gfxFont->getType() == fontType1C ||
2085        (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
2086         gfxFont->getType() == fontTrueType ||
2087         gfxFont->getType() == fontCIDType2
2088        ))
2089     {
2090       fileName = writeEmbeddedFontToFile(xref, gfxFont);
2091       if(!fileName) showFontError(gfxFont,0);
2092       else del = 1;
2093     } else {
2094       char * fontname = getFontName(gfxFont);
2095       fileName = searchFont(fontname);
2096       if(!fileName) showFontError(gfxFont,0);
2097       free(fontname);
2098     }
2099     if(!fileName) {
2100         char * fontname = getFontName(gfxFont);
2101         msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
2102         msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
2103         fileName = substituteFont(gfxFont, fontid);
2104         if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
2105         msg("<notice> Font is now %s (%s)", fontid, fileName);
2106     }
2107
2108     if(!fileName) {
2109         msg("<error> Couldn't set font %s\n", fontid);
2110         free(fontid);
2111         return;
2112     }
2113         
2114     msg("<verbose> updateFont(%s) -> %s (max size: %f)", fontid, fileName, maxSize);
2115     dumpFontInfo("<verbose>", gfxFont);
2116
2117     //swfoutput_setfont(&output, fontid, fileName);
2118     
2119     if(!setGfxFont(fontid, 0, 0)) {
2120         setGfxFont(fontid, fileName, maxSize);
2121     }
2122    
2123     if(fileName && del)
2124         unlinkfont(fileName);
2125     if(fileName)
2126         free(fileName);
2127     free(fontid);
2128 }
2129
2130 #define SQR(x) ((x)*(x))
2131
2132 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
2133 {
2134     if((newwidth<2 || newheight<2) ||
2135        (width<=newwidth || height<=newheight))
2136         return 0;
2137     unsigned char*newdata;
2138     int x,y;
2139     newdata= (unsigned char*)malloc(newwidth*newheight);
2140     int t;
2141     double fx = (double)(width)/newwidth;
2142     double fy = (double)(height)/newheight;
2143     double px = 0;
2144     int blocksize = (int)(8192/(fx*fy));
2145     int r = 8192*256/palettesize;
2146     for(x=0;x<newwidth;x++) {
2147         double ex = px + fx;
2148         int fromx = (int)px;
2149         int tox = (int)ex;
2150         int xweight1 = (int)(((fromx+1)-px)*256);
2151         int xweight2 = (int)((ex-tox)*256);
2152         double py =0;
2153         for(y=0;y<newheight;y++) {
2154             double ey = py + fy;
2155             int fromy = (int)py;
2156             int toy = (int)ey;
2157             int yweight1 = (int)(((fromy+1)-py)*256);
2158             int yweight2 = (int)((ey-toy)*256);
2159             int a = 0;
2160             int xx,yy;
2161             for(xx=fromx;xx<=tox;xx++)
2162             for(yy=fromy;yy<=toy;yy++) {
2163                 int b = 1-data[width*yy+xx];
2164                 int weight=256;
2165                 if(xx==fromx) weight = (weight*xweight1)/256;
2166                 if(xx==tox) weight = (weight*xweight2)/256;
2167                 if(yy==fromy) weight = (weight*yweight1)/256;
2168                 if(yy==toy) weight = (weight*yweight2)/256;
2169                 a+=b*weight;
2170             }
2171             //if(a) a=(palettesize-1)*r/blocksize;
2172             newdata[y*newwidth+x] = (a*blocksize)/r;
2173             py = ey;
2174         }
2175         px = ex;
2176     }
2177     return newdata;
2178 }
2179
2180 #define IMAGE_TYPE_JPEG 0
2181 #define IMAGE_TYPE_LOSSLESS 1
2182
2183 static void drawimage(gfxdevice_t*dev, RGBA* data, int sizex,int sizey, 
2184         double x1,double y1,
2185         double x2,double y2,
2186         double x3,double y3,
2187         double x4,double y4, int type)
2188 {
2189     RGBA*newpic=0;
2190     
2191     double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2192     double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2193    
2194     gfxline_t p1,p2,p3,p4,p5;
2195     p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2196     p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2197     p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2198     p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2199     p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2200
2201     {p1.x = (int)(p1.x*20)/20.0;
2202      p1.y = (int)(p1.y*20)/20.0;
2203      p2.x = (int)(p2.x*20)/20.0;
2204      p2.y = (int)(p2.y*20)/20.0;
2205      p3.x = (int)(p3.x*20)/20.0;
2206      p3.y = (int)(p3.y*20)/20.0;
2207      p4.x = (int)(p4.x*20)/20.0;
2208      p4.y = (int)(p4.y*20)/20.0;
2209      p5.x = (int)(p5.x*20)/20.0;
2210      p5.y = (int)(p5.y*20)/20.0;
2211     }
2212     
2213     float m00,m10,tx;
2214     float m01,m11,ty;
2215     
2216     gfxmatrix_t m;
2217     m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
2218     m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
2219     m.tx = p1.x - 0.5;
2220     m.ty = p1.y - 0.5;
2221
2222     gfximage_t img;
2223     img.data = (gfxcolor_t*)data;
2224     img.width = sizex;
2225     img.height = sizey;
2226   
2227     if(type == IMAGE_TYPE_JPEG)
2228         /* TODO: pass image_dpi to device instead */
2229         dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
2230
2231     dev->fillbitmap(dev, &p1, &img, &m, 0);
2232 }
2233
2234 void drawimagejpeg(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey, 
2235         double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2236 {
2237     drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
2238 }
2239
2240 void drawimagelossless(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey, 
2241         double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2242 {
2243     drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2244 }
2245
2246
2247 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
2248                                    int width, int height, GfxImageColorMap*colorMap, GBool invert,
2249                                    GBool inlineImg, int mask, int*maskColors)
2250 {
2251   FILE *fi;
2252   int c;
2253   char fileName[128];
2254   double x1,y1,x2,y2,x3,y3,x4,y4;
2255   ImageStream *imgStr;
2256   Guchar pixBuf[4];
2257   GfxRGB rgb;
2258   int ncomps = 1;
2259   int bits = 1;
2260                                  
2261   if(colorMap) {
2262     ncomps = colorMap->getNumPixelComps();
2263     bits = colorMap->getBits();
2264   }
2265   imgStr = new ImageStream(str, width, ncomps,bits);
2266   imgStr->reset();
2267
2268   if(!width || !height || (height<=1 && width<=1))
2269   {
2270       msg("<verbose> Ignoring %d by %d image", width, height);
2271       unsigned char buf[8];
2272       int x,y;
2273       for (y = 0; y < height; ++y)
2274       for (x = 0; x < width; ++x) {
2275           imgStr->getPixel(buf);
2276       }
2277       delete imgStr;
2278       return;
2279   }
2280   
2281   state->transform(0, 1, &x1, &y1); x1 += user_movex; y1+= user_movey;
2282   state->transform(0, 0, &x2, &y2); x2 += user_movex; y2+= user_movey;
2283   state->transform(1, 0, &x3, &y3); x3 += user_movex; y3+= user_movey;
2284   state->transform(1, 1, &x4, &y4); x4 += user_movex; y4+= user_movey;
2285
2286   if(!pbminfo && !(str->getKind()==strDCT)) {
2287       if(!type3active) {
2288           msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2289           pbminfo = 1;
2290       }
2291       if(mask)
2292       msg("<verbose> drawing %d by %d masked picture\n", width, height);
2293   }
2294   if(!jpeginfo && (str->getKind()==strDCT)) {
2295       msg("<notice> file contains jpeg pictures");
2296       jpeginfo = 1;
2297   }
2298
2299   if(mask) {
2300       int i,j;
2301       unsigned char buf[8];
2302       int x,y;
2303       unsigned char*pic = new unsigned char[width*height];
2304       RGBA pal[256];
2305       GfxRGB rgb;
2306       state->getFillRGB(&rgb);
2307
2308       memset(pal,255,sizeof(pal));
2309       pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
2310       pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
2311       pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
2312       pal[0].a = 255;              pal[1].a = 0;
2313
2314       int numpalette = 2;
2315       int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2316       int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2317       for (y = 0; y < height; ++y)
2318       for (x = 0; x < width; ++x)
2319       {
2320             imgStr->getPixel(buf);
2321             if(invert) 
2322                 buf[0]=1-buf[0];
2323             pic[width*y+x] = buf[0];
2324       }
2325       
2326       /* the size of the drawn image is added to the identifier
2327          as the same image may require different bitmaps if displayed
2328          at different sizes (due to antialiasing): */
2329       int t,found = -1;
2330       if(type3active) {
2331           unsigned char*pic2 = 0;
2332           numpalette = 16;
2333           
2334           pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2335
2336           if(!pic2) {
2337             delete pic;
2338             delete imgStr;
2339             return;
2340           }
2341
2342           width = realwidth;
2343           height = realheight;
2344           free(pic);
2345           pic = pic2;
2346           
2347           /* make a black/white palette */
2348           GfxRGB rgb2;
2349           rgb2.r = 1 - rgb.r;
2350           rgb2.g = 1 - rgb.g;
2351           rgb2.b = 1 - rgb.b;
2352           float r = 255/(numpalette-1);
2353           int t;
2354           for(t=0;t<numpalette;t++) {
2355               pal[t].r = (U8)(255*rgb.r);
2356               pal[t].g = (U8)(255*rgb.g);
2357               pal[t].b = (U8)(255*rgb.b);
2358               pal[t].a = (U8)(t*r);
2359           }
2360       }
2361
2362       RGBA*pic2 = new RGBA[width*height];
2363       for (y = 0; y < height; ++y) {
2364         for (x = 0; x < width; ++x) {
2365           pic2[width*y+x] = pal[pic[y*width+x]];
2366         }
2367       }
2368       drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2369       free(pic2);
2370       free(pic);
2371       delete imgStr;
2372       return;
2373   } 
2374
2375   int x,y;
2376
2377   if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2378       RGBA*pic=new RGBA[width*height];
2379       for (y = 0; y < height; ++y) {
2380         for (x = 0; x < width; ++x) {
2381           imgStr->getPixel(pixBuf);
2382           colorMap->getRGB(pixBuf, &rgb);
2383           pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5);
2384           pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5);
2385           pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5);
2386           pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2387         }
2388       }
2389       if(str->getKind()==strDCT)
2390           drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2391       else
2392           drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2393       delete pic;
2394       delete imgStr;
2395       return;
2396   } else {
2397       RGBA*pic=new RGBA[width*height];
2398       RGBA pal[256];
2399       int t;
2400       for(t=0;t<256;t++) {
2401           pixBuf[0] = t;
2402           colorMap->getRGB(pixBuf, &rgb);
2403           /*if(maskColors && *maskColors==t) {
2404               msg("<notice> Color %d is transparent", t);
2405               if (imgData->maskColors) {
2406                 *alpha = 0;
2407                 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2408                   if (pix[i] < imgData->maskColors[2*i] ||
2409                       pix[i] > imgData->maskColors[2*i+1]) {
2410                     *alpha = 1;
2411                     break;
2412                   }
2413                 }
2414               } else {
2415                 *alpha = 1;
2416               }
2417               if(!*alpha) {
2418                     pal[t].r = 0;
2419                     pal[t].g = 0;
2420                     pal[t].b = 0;
2421                     pal[t].a = 0;
2422               }
2423           } else*/ {
2424               pal[t].r = (U8)(rgb.r * 255 + 0.5);
2425               pal[t].g = (U8)(rgb.g * 255 + 0.5);
2426               pal[t].b = (U8)(rgb.b * 255 + 0.5);
2427               pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2428           }
2429       }
2430       for (y = 0; y < height; ++y) {
2431         for (x = 0; x < width; ++x) {
2432           imgStr->getPixel(pixBuf);
2433           pic[width*y+x] = pal[pixBuf[0]];
2434         }
2435       }
2436       drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2437
2438       delete pic;
2439       delete imgStr;
2440       return;
2441   }
2442 }
2443
2444 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2445                                    int width, int height, GBool invert,
2446                                    GBool inlineImg) 
2447 {
2448   if(states[statepos].textRender & 4) //clipped
2449       return;
2450   msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2451   drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
2452 }
2453
2454 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2455                          int width, int height, GfxImageColorMap *colorMap,
2456                          int *maskColors, GBool inlineImg)
2457 {
2458   if(states[statepos].textRender & 4) //clipped
2459       return;
2460
2461   msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height, 
2462           colorMap?"colorMap":"no colorMap", 
2463           maskColors?"maskColors":"no maskColors",
2464           inlineImg);
2465   if(colorMap)
2466       msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2467               colorMap->getBits(),colorMap->getColorSpace()->getMode());
2468   drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
2469 }
2470
2471 //SWFOutputDev*output = 0; 
2472
2473 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2474   Object obj;
2475   GString *s1, *s2;
2476   int i;
2477
2478   if (infoDict->lookup(key, &obj)->isString()) {
2479     s1 = obj.getString();
2480     if ((s1->getChar(0) & 0xff) == 0xfe &&
2481         (s1->getChar(1) & 0xff) == 0xff) {
2482       s2 = new GString();
2483       for (i = 2; i < obj.getString()->getLength(); i += 2) {
2484         if (s1->getChar(i) == '\0') {
2485           s2->append(s1->getChar(i+1));
2486         } else {
2487           delete s2;
2488           s2 = new GString("<unicode>");
2489           break;
2490         }
2491       }
2492       printf(fmt, s2->getCString());
2493       delete s2;
2494     } else {
2495       printf(fmt, s1->getCString());
2496     }
2497   }
2498   obj.free();
2499 }
2500
2501 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2502   Object obj;
2503   char *s;
2504
2505   if (infoDict->lookup(key, &obj)->isString()) {
2506     s = obj.getString()->getCString();
2507     if (s[0] == 'D' && s[1] == ':') {
2508       s += 2;
2509     }
2510     printf(fmt, s);
2511   }
2512   obj.free();
2513 }
2514
2515 int jpeg_dpi = 0;
2516 int ppm_dpi = 0;
2517
2518 void storeDeviceParameter(char*name, char*value)
2519 {
2520     parameter_t*p = new parameter_t();
2521     p->name = strdup(name);
2522     p->value = strdup(value);
2523     p->next = 0;
2524     if(device_config_next) {
2525         device_config_next->next = p;
2526         device_config_next = p;
2527     } else {
2528         device_config = p;
2529         device_config_next = p;
2530     }
2531 }
2532
2533 void pdfswf_setparameter(char*name, char*value)
2534 {
2535     msg("<verbose> setting parameter %s to \"%s\"", name, value);
2536     if(!strcmp(name, "caplinewidth")) {
2537         caplinewidth = atof(value);
2538     } else if(!strcmp(name, "zoom")) {
2539         char buf[80];
2540         zoom = atof(value);
2541         sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2542         storeDeviceParameter("jpegsubpixels", buf);
2543         sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2544         storeDeviceParameter("ppmsubpixels", buf);
2545     } else if(!strcmp(name, "jpegdpi")) {
2546         char buf[80];
2547         jpeg_dpi = atoi(value);
2548         sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2549         storeDeviceParameter("jpegsubpixels", buf);
2550     } else if(!strcmp(name, "ppmdpi")) {
2551         char buf[80];
2552         ppm_dpi = atoi(value);
2553         sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2554         storeDeviceParameter("ppmsubpixels", buf);
2555     } else if(!strcmp(name, "forceType0Fonts")) {
2556         forceType0Fonts = atoi(value);
2557     } else if(!strcmp(name, "fontdir")) {
2558         pdfswf_addfontdir(value);
2559     } else if(!strcmp(name, "languagedir")) {
2560         pdfswf_addlanguagedir(value);
2561     } else if(!strcmp(name, "fontconfig")) {
2562         config_use_fontconfig = atoi(value);
2563     } else {
2564         storeDeviceParameter(name,value);
2565     }
2566 }
2567 void pdfswf_addfont(char*filename)
2568 {
2569     fontfile_t f;
2570     memset(&f, 0, sizeof(fontfile_t));
2571     f.filename = filename;
2572     if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2573         fonts[fontnum++] = f;
2574     } else {
2575         msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2576     }
2577 }
2578
2579 static char* dirseparator()
2580 {
2581 #ifdef WIN32
2582     return "\\";
2583 #else
2584     return "/";
2585 #endif
2586 }
2587
2588 void pdfswf_addlanguagedir(char*dir)
2589 {
2590     if(!globalParams)
2591         globalParams = new GlobalParams("");
2592     
2593     msg("<notice> Adding %s to language pack directories", dir);
2594
2595     int l;
2596     FILE*fi = 0;
2597     char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2598     strcpy(config_file, dir);
2599     strcat(config_file, dirseparator());
2600     strcat(config_file, "add-to-xpdfrc");
2601
2602     fi = fopen(config_file, "rb");
2603     if(!fi) {
2604         msg("<error> Could not open %s", config_file);
2605         return;
2606     }
2607     globalParams->parseFile(new GString(config_file), fi);
2608     fclose(fi);
2609 }
2610
2611 void pdfswf_addfontdir(char*dirname)
2612 {
2613 #ifdef HAVE_DIRENT_H
2614     msg("<notice> Adding %s to font directories", dirname);
2615     DIR*dir = opendir(dirname);
2616     if(!dir) {
2617         msg("<warning> Couldn't open directory %s\n", dirname);
2618         return;
2619     }
2620     struct dirent*ent;
2621     while(1) {
2622         ent = readdir (dir);
2623         if (!ent) 
2624             break;
2625         int l;
2626         char*name = ent->d_name;
2627         char type = 0;
2628         if(!name) continue;
2629         l=strlen(name);
2630         if(l<4)
2631             continue;
2632         if(!strncasecmp(&name[l-4], ".pfa", 4)) 
2633             type=1;
2634         if(!strncasecmp(&name[l-4], ".pfb", 4)) 
2635             type=3;
2636         if(!strncasecmp(&name[l-4], ".ttf", 4)) 
2637             type=2;
2638         if(type)
2639         {
2640             char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2641             strcpy(fontname, dirname);
2642             strcat(fontname, dirseparator());
2643             strcat(fontname, name);
2644             msg("<verbose> Adding %s to fonts", fontname);
2645             pdfswf_addfont(fontname);
2646         }
2647     }
2648     closedir(dir);
2649 #else
2650     msg("<warning> No dirent.h- unable to add font dir %s", dir);
2651 #endif
2652 }
2653
2654
2655 typedef struct _pdf_doc_internal
2656 {
2657     int protect;
2658     PDFDoc*doc;
2659     InfoOutputDev*info;
2660 } pdf_doc_internal_t;
2661 typedef struct _pdf_page_internal
2662 {
2663 } pdf_page_internal_t;
2664 typedef struct _swf_output_internal
2665 {
2666     SWFOutputDev*outputDev;
2667 } swf_output_internal_t;
2668
2669 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2670 {
2671     pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2672     memset(pdf_doc, 0, sizeof(pdf_doc_t));
2673     pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2674     memset(i, 0, sizeof(pdf_doc_internal_t));
2675     pdf_doc->internal = i;
2676     
2677     GString *fileName = new GString(filename);
2678     GString *userPW;
2679     Object info;
2680
2681     // read config file
2682     if(!globalParams)
2683         globalParams = new GlobalParams("");
2684
2685     // open PDF file
2686     if (userPassword && userPassword[0]) {
2687       userPW = new GString(userPassword);
2688     } else {
2689       userPW = NULL;
2690     }
2691     i->doc = new PDFDoc(fileName, userPW);
2692     if (userPW) {
2693       delete userPW;
2694     }
2695     if (!i->doc->isOk()) {
2696         return 0;
2697     }
2698
2699     // print doc info
2700     i->doc->getDocInfo(&info);
2701     if (info.isDict() &&
2702       (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2703       printInfoString(info.getDict(), "Title",        "Title:        %s\n");
2704       printInfoString(info.getDict(), "Subject",      "Subject:      %s\n");
2705       printInfoString(info.getDict(), "Keywords",     "Keywords:     %s\n");
2706       printInfoString(info.getDict(), "Author",       "Author:       %s\n");
2707       printInfoString(info.getDict(), "Creator",      "Creator:      %s\n");
2708       printInfoString(info.getDict(), "Producer",     "Producer:     %s\n");
2709       printInfoDate(info.getDict(),   "CreationDate", "CreationDate: %s\n");
2710       printInfoDate(info.getDict(),   "ModDate",      "ModDate:      %s\n");
2711       printf("Pages:        %d\n", i->doc->getNumPages());
2712       printf("Linearized:   %s\n", i->doc->isLinearized() ? "yes" : "no");
2713       printf("Encrypted:    ");
2714       if (i->doc->isEncrypted()) {
2715         printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2716                i->doc->okToPrint() ? "yes" : "no",
2717                i->doc->okToCopy() ? "yes" : "no",
2718                i->doc->okToChange() ? "yes" : "no",
2719                i->doc->okToAddNotes() ? "yes" : "no");
2720       } else {
2721         printf("no\n");
2722       }
2723     }
2724     info.free();
2725                    
2726     pdf_doc->num_pages = i->doc->getNumPages();
2727     i->protect = 0;
2728     if (i->doc->isEncrypted()) {
2729           if(!i->doc->okToCopy()) {
2730               printf("PDF disallows copying.\n");
2731               return 0;
2732           }
2733           if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2734               i->protect = 1;
2735     }
2736
2737     InfoOutputDev*io = new InfoOutputDev();
2738     int t;
2739     for(t=1;t<=pdf_doc->num_pages;t++) {
2740 #ifdef XPDF_101
2741         i->doc->displayPage((OutputDev*)io, t, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2742 #else
2743         i->doc->displayPage((OutputDev*)io, t, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2744 #endif
2745     }
2746     i->info = io;
2747
2748     return pdf_doc;
2749 }
2750
2751 class MemCheck
2752 {
2753     public: ~MemCheck()
2754     {
2755         delete globalParams;globalParams=0;
2756         Object::memCheck(stderr);
2757         gMemReport(stderr);
2758     }
2759 } myMemCheck;
2760
2761 void pdf_destroy(pdf_doc_t*pdf_doc)
2762 {
2763     pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2764
2765     delete i->doc; i->doc=0;
2766     
2767     if(i->info) {
2768         delete i->info;i->info=0;
2769     }
2770
2771     free(pdf_doc->internal);pdf_doc->internal=0;
2772     free(pdf_doc);pdf_doc=0;
2773 }
2774
2775 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2776 {
2777     pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2778
2779     if(page < 1 || page > pdf_doc->num_pages)
2780         return 0;
2781     
2782     pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2783     pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2784     memset(pi, 0, sizeof(pdf_page_internal_t));
2785     pdf_page->internal = pi;
2786
2787     pdf_page->parent = pdf_doc;
2788     pdf_page->nr = page;
2789     return pdf_page;
2790 }
2791
2792 void pdf_page_destroy(pdf_page_t*pdf_page)
2793 {
2794     pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2795     free(pdf_page->internal);pdf_page->internal = 0;
2796     free(pdf_page);pdf_page=0;
2797 }
2798
2799 swf_output_t* swf_output_init() 
2800 {
2801     swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2802     memset(swf_output, 0, sizeof(swf_output_t));
2803     swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2804     memset(i, 0, sizeof(swf_output_internal_t));
2805     swf_output->internal = i;
2806
2807     i->outputDev = new SWFOutputDev();
2808     return swf_output;
2809 }
2810
2811 void swf_output_setparameter(swf_output_t*swf, char*name, char*value)
2812 {
2813     pdfswf_setparameter(name, value);
2814 }
2815
2816 void swf_output_startframe(swf_output_t*swf, int width, int height)
2817 {
2818     swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2819     i->outputDev->startFrame(width, height);
2820 }
2821
2822 void swf_output_endframe(swf_output_t*swf)
2823 {
2824     swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2825     i->outputDev->endframe();
2826 }
2827
2828 void swf_output_preparepage(swf_output_t*swf, int pdfpage, int outputpage)
2829 {
2830     swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2831     SWFOutputDev*o = i->outputDev;
2832
2833     if(pdfpage < 0)
2834         return;
2835
2836     if(!o->pages) {
2837         o->pagebuflen = 1024;
2838         o->pages = (int*)malloc(o->pagebuflen*sizeof(int));
2839         memset(o->pages, -1, o->pagebuflen*sizeof(int));
2840     } else {
2841         while(pdfpage >= o->pagebuflen)
2842         {
2843             int oldlen = o->pagebuflen;
2844             o->pagebuflen+=1024;
2845             o->pages = (int*)realloc(o->pages, o->pagebuflen*sizeof(int));
2846             memset(&o->pages[oldlen], -1, (o->pagebuflen-oldlen)*sizeof(int));
2847         }
2848     }
2849     o->pages[pdfpage] = outputpage;
2850     if(pdfpage>o->pagepos)
2851         o->pagepos = pdfpage;
2852 }
2853
2854 int swf_output_save(swf_output_t*swf, char*filename)
2855 {
2856     swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2857     int ret = i->outputDev->save(filename);
2858     return ret;
2859 }
2860
2861 void* swf_output_get(swf_output_t*swf,char*name)
2862 {
2863     swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2864     void* ret = i->outputDev->get(name);
2865     return ret;
2866 }
2867
2868 void swf_output_destroy(swf_output_t*output)
2869 {
2870     swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2871     delete i->outputDev; i->outputDev=0;
2872     free(output->internal);output->internal=0;
2873     free(output);
2874 }
2875
2876 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2877 {
2878     pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2879     swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2880
2881     if(!pi) {
2882         msg("<fatal> pdf_page_render: Parent PDF this page belongs to doesn't exist yet/anymore");
2883         return;
2884     }
2885
2886     if(pi->protect) {
2887         gfxdevice_t*dev = si->outputDev->output;
2888         dev->setparameter(dev, "protect", "1");
2889     }
2890     si->outputDev->setInfo(pi->info);
2891     si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2892 #ifdef XPDF_101
2893     pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2894 #else
2895     pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2896 #endif
2897 }
2898
2899 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2900 {
2901     pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2902     swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2903
2904     si->outputDev->setMove(x,y);
2905     if((x1|y1|x2|y2)==0) x2++;
2906     si->outputDev->setClip(x1,y1,x2,y2);
2907
2908     pdf_page_render2(page, output);
2909 }
2910 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2911 {
2912     pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2913     swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2914     
2915     si->outputDev->setMove(0,0);
2916     si->outputDev->setClip(0,0,0,0);
2917     
2918     pdf_page_render2(page, output);
2919 }
2920
2921
2922 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2923 {
2924     pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2925     pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2926     pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2927     memset(info, 0, sizeof(pdf_page_info_t));
2928
2929     InfoOutputDev*output = new InfoOutputDev;
2930     
2931 #ifdef XPDF_101
2932     pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2933 #else
2934     pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2935 #endif
2936
2937     info->xMin = output->x1;
2938     info->yMin = output->y1;
2939     info->xMax = output->x2;
2940     info->yMax = output->y2;
2941     info->number_of_images = output->num_images;
2942     info->number_of_links = output->num_links;
2943     info->number_of_fonts = output->num_fonts;
2944
2945     delete output;
2946
2947     return info;
2948 }
2949
2950 void pdf_page_info_destroy(pdf_page_info_t*info)
2951 {
2952     free(info);
2953
2954 }