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