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