link pages tables are now a part of SWFOutputDev
[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             printf("%d) %d (%d?)\n", t, pages[t], page);
1517             if(pages[t]==page) {
1518                 lpage = t;
1519                 break;
1520             }
1521         }
1522         if(lpage>=0) {
1523             char buf[80];
1524             sprintf(buf, "page%d", t);
1525             output->drawlink(output, points, buf);
1526         } else {
1527             msg("<warning> Invalid link to page %d", page);
1528         }
1529     }
1530     else if(url)
1531     {
1532         output->drawlink(output, points, url);
1533     }
1534
1535     msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1536     free(s);s=0;
1537 }
1538
1539 void SWFOutputDev::saveState(GfxState *state) {
1540   msg("<trace> saveState\n");
1541   updateAll(state);
1542   if(statepos>=64) {
1543     msg("<error> Too many nested states in pdf.");
1544     return;
1545   }
1546   statepos ++;
1547   states[statepos].clipping = 0; //? shouldn't this be the current value?
1548   states[statepos].textRender = states[statepos-1].textRender;
1549 };
1550
1551 void SWFOutputDev::restoreState(GfxState *state) {
1552   msg("<trace> restoreState\n");
1553   updateAll(state);
1554   while(states[statepos].clipping) {
1555       output->endclip(output);
1556       states[statepos].clipping--;
1557   }
1558   statepos--;
1559 }
1560
1561 char* SWFOutputDev::searchFont(char*name) 
1562 {       
1563     int i;
1564     char*filename=0;
1565     int is_standard_font = 0;
1566         
1567     msg("<verbose> SearchFont(%s)", name);
1568
1569     /* see if it is a pdf standard font */
1570     for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++) 
1571     {
1572         if(!strcmp(name, pdf2t1map[i].pdffont))
1573         {
1574             name = pdf2t1map[i].filename;
1575             is_standard_font = 1;
1576             break;
1577         }
1578     }
1579     /* look in all font files */
1580     for(i=0;i<fontnum;i++) 
1581     {
1582         if(strstr(fonts[i].filename, name))
1583         {
1584             if(!fonts[i].used) {
1585
1586                 fonts[i].used = 1;
1587                 if(!is_standard_font)
1588                     msg("<notice> Using %s for %s", fonts[i].filename, name);
1589             }
1590             return strdup(fonts[i].filename);
1591         }
1592     }
1593     return 0;
1594 }
1595
1596 void SWFOutputDev::updateLineWidth(GfxState *state)
1597 {
1598     double width = state->getTransformedLineWidth();
1599     //swfoutput_setlinewidth(&output, width);
1600 }
1601
1602 void SWFOutputDev::updateLineCap(GfxState *state)
1603 {
1604     int c = state->getLineCap();
1605 }
1606
1607 void SWFOutputDev::updateLineJoin(GfxState *state)
1608 {
1609     int j = state->getLineJoin();
1610 }
1611
1612 void SWFOutputDev::updateFillColor(GfxState *state) 
1613 {
1614     GfxRGB rgb;
1615     double opaq = state->getFillOpacity();
1616     state->getFillRGB(&rgb);
1617
1618     //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1619 }
1620
1621 void SWFOutputDev::updateStrokeColor(GfxState *state) 
1622 {
1623     GfxRGB rgb;
1624     double opaq = state->getStrokeOpacity();
1625     state->getStrokeRGB(&rgb);
1626     //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1627 }
1628
1629 void FoFiWrite(void *stream, char *data, int len)
1630 {
1631    fwrite(data, len, 1, (FILE*)stream);
1632 }
1633
1634 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1635 {
1636     char*tmpFileName = NULL;
1637     FILE *f;
1638     int c;
1639     char *fontBuf;
1640     int fontLen;
1641     Ref embRef;
1642     Object refObj, strObj;
1643     char namebuf[512];
1644     tmpFileName = mktmpname(namebuf);
1645     int ret;
1646
1647     ret = font->getEmbeddedFontID(&embRef);
1648     if(!ret) {
1649         msg("<verbose> Didn't get embedded font id");
1650         /* not embedded- the caller should now search the font
1651            directories for this font */
1652         return 0;
1653     }
1654
1655     f = fopen(tmpFileName, "wb");
1656     if (!f) {
1657       msg("<error> Couldn't create temporary Type 1 font file");
1658         return 0;
1659     }
1660
1661     /*if(font->isCIDFont()) {
1662         GfxCIDFont* cidFont = (GfxCIDFont *)font;
1663         GString c = cidFont->getCollection();
1664         msg("<notice> Collection: %s", c.getCString());
1665     }*/
1666
1667     //if (font->getType() == fontType1C) {
1668     if (0) { //font->getType() == fontType1C) {
1669       if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1670         fclose(f);
1671         msg("<error> Couldn't read embedded font file");
1672         return 0;
1673       }
1674 #ifdef XPDF_101
1675       Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1676       if(!cvt) return 0;
1677       cvt->convertToType1(f);
1678 #else
1679       FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1680       if(!cvt) return 0;
1681       cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1682 #endif
1683       //cvt->convertToCIDType0("test", f);
1684       //cvt->convertToType0("test", f);
1685       delete cvt;
1686       gfree(fontBuf);
1687     } else if(font->getType() == fontTrueType) {
1688       msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1689       if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1690         fclose(f);
1691         msg("<error> Couldn't read embedded font file");
1692         return 0;
1693       }
1694 #ifdef XPDF_101
1695       TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1696       cvt->writeTTF(f);
1697 #else
1698       FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1699       cvt->writeTTF(FoFiWrite, f);
1700 #endif
1701       delete cvt;
1702       gfree(fontBuf);
1703     } else {
1704       font->getEmbeddedFontID(&embRef);
1705       refObj.initRef(embRef.num, embRef.gen);
1706       refObj.fetch(ref, &strObj);
1707       refObj.free();
1708       strObj.streamReset();
1709       int f4[4];
1710       char f4c[4];
1711       int t;
1712       for(t=0;t<4;t++) {
1713           f4[t] = strObj.streamGetChar();
1714           f4c[t] = (char)f4[t];
1715           if(f4[t] == EOF)
1716               break;
1717       }
1718       if(t==4) {
1719           if(!strncmp(f4c, "true", 4)) {
1720               /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1721                  Change this on the fly */
1722               f4[0] = f4[2] = f4[3] = 0;
1723               f4[1] = 1;
1724           }
1725           fputc(f4[0], f);
1726           fputc(f4[1], f);
1727           fputc(f4[2], f);
1728           fputc(f4[3], f);
1729
1730           while ((c = strObj.streamGetChar()) != EOF) {
1731             fputc(c, f);
1732           }
1733       }
1734       strObj.streamClose();
1735       strObj.free();
1736     }
1737     fclose(f);
1738
1739     return strdup(tmpFileName);
1740 }
1741     
1742 char* searchForSuitableFont(GfxFont*gfxFont)
1743 {
1744     char*name = getFontName(gfxFont);
1745     char*fontname = 0;
1746     char*filename = 0;
1747
1748     if(!config_use_fontconfig)
1749         return 0;
1750     
1751 #ifdef HAVE_FONTCONFIG
1752     FcPattern *pattern, *match;
1753     FcResult result;
1754     FcChar8 *v;
1755
1756     static int fcinitcalled = false; 
1757         
1758     msg("<debug> searchForSuitableFont(%s)", name);
1759     
1760     // call init ony once
1761     if (!fcinitcalled) {
1762         msg("<debug> Initializing FontConfig...");
1763         fcinitcalled = true;
1764         if(!FcInit()) {
1765             msg("<debug> FontConfig Initialization failed. Disabling.");
1766             config_use_fontconfig = 0;
1767             return 0;
1768         }
1769         msg("<debug> ...initialized FontConfig");
1770     }
1771    
1772     msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1773     pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1774     if (gfxFont->isItalic()) // check for italic
1775         msg("<debug> FontConfig: Adding Italic Slant");
1776         FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1777     if (gfxFont->isBold()) // check for bold
1778         msg("<debug> FontConfig: Adding Bold Weight");
1779         FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1780
1781     msg("<debug> FontConfig: Try to match...");
1782     // configure and match using the original font name 
1783     FcConfigSubstitute(0, pattern, FcMatchPattern); 
1784     FcDefaultSubstitute(pattern);
1785     match = FcFontMatch(0, pattern, &result);
1786     
1787     if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1788         msg("<debug> FontConfig: family=%s", (char*)v);
1789         // if we get an exact match
1790         if (strcmp((char *)v, name) == 0) {
1791             if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1792                 filename = strdup((char*)v); // mem leak
1793                 char *nfn = strrchr(filename, '/');
1794                 if(nfn) fontname = strdup(nfn+1);
1795                 else    fontname = filename;
1796             }
1797             msg("<debug> FontConfig: Returning \"%s\"", fontname);
1798         } else {
1799             // initialize patterns
1800             FcPatternDestroy(pattern);
1801             FcPatternDestroy(match);
1802
1803             // now match against serif etc.
1804             if (gfxFont->isSerif()) {
1805                 msg("<debug> FontConfig: Create Serif Family Pattern");
1806                 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1807             } else if (gfxFont->isFixedWidth()) {
1808                 msg("<debug> FontConfig: Create Monospace Family Pattern");
1809                 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1810             } else {
1811                 msg("<debug> FontConfig: Create Sans Family Pattern");
1812                 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1813             }
1814
1815             // check for italic
1816             if (gfxFont->isItalic()) {
1817                 msg("<debug> FontConfig: Adding Italic Slant");
1818                 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1819             }
1820             // check for bold
1821             if (gfxFont->isBold()) {
1822                 msg("<debug> FontConfig: Adding Bold Weight");
1823                 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1824             }
1825
1826             msg("<debug> FontConfig: Try to match... (2)");
1827             // configure and match using serif etc
1828             FcConfigSubstitute (0, pattern, FcMatchPattern);
1829             FcDefaultSubstitute (pattern);
1830             match = FcFontMatch (0, pattern, &result);
1831             
1832             if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1833                 filename = strdup((char*)v); // mem leak
1834                 char *nfn = strrchr(filename, '/');
1835                 if(nfn) fontname = strdup(nfn+1);
1836                 else    fontname = filename;
1837             }
1838             msg("<debug> FontConfig: Returning \"%s\"", fontname);
1839         }        
1840     }
1841
1842     //printf("FONTCONFIG: pattern");
1843     //FcPatternPrint(pattern);
1844     //printf("FONTCONFIG: match");
1845     //FcPatternPrint(match);
1846  
1847     FcPatternDestroy(pattern);
1848     FcPatternDestroy(match);
1849
1850     pdfswf_addfont(filename);
1851     return fontname;
1852 #else
1853     return 0;
1854 #endif
1855 }
1856
1857 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1858 {
1859     char*fontname = 0, *filename = 0;
1860     msg("<notice> subsituteFont(%s)", oldname);
1861
1862     if(!(fontname = searchForSuitableFont(gfxFont))) {
1863         fontname = "Times-Roman";
1864     }
1865     filename = searchFont(fontname);
1866     if(!filename) {
1867         msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1868         return 0;
1869     }
1870
1871     if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1872         msg("<fatal> Too many fonts in file.");
1873         exit(1);
1874     }
1875     if(oldname) {
1876         substitutesource[substitutepos] = strdup(oldname); //mem leak
1877         substitutetarget[substitutepos] = fontname;
1878         msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1879         substitutepos ++;
1880     }
1881     return strdup(filename); //mem leak
1882 }
1883
1884 void unlinkfont(char* filename)
1885 {
1886     int l;
1887     if(!filename)
1888         return;
1889     l=strlen(filename);
1890     unlink(filename);
1891     if(!strncmp(&filename[l-4],".afm",4)) {
1892         memcpy(&filename[l-4],".pfb",4);
1893         unlink(filename);
1894         memcpy(&filename[l-4],".pfa",4);
1895         unlink(filename);
1896         memcpy(&filename[l-4],".afm",4);
1897         return;
1898     } else 
1899     if(!strncmp(&filename[l-4],".pfa",4)) {
1900         memcpy(&filename[l-4],".afm",4);
1901         unlink(filename);
1902         memcpy(&filename[l-4],".pfa",4);
1903         return;
1904     } else 
1905     if(!strncmp(&filename[l-4],".pfb",4)) {
1906         memcpy(&filename[l-4],".afm",4);
1907         unlink(filename);
1908         memcpy(&filename[l-4],".pfb",4);
1909         return;
1910     }
1911 }
1912
1913 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref) 
1914 {
1915     this->doc = doc;
1916     this->xref = xref;
1917 }
1918
1919 int SWFOutputDev::setGfxFont(char*id, char*filename, double maxSize)
1920 {
1921     gfxfont_t*font = 0;
1922     fontlist_t*last=0,*l = this->fontlist;
1923
1924     /* TODO: should this be part of the state? */
1925     while(l) {
1926         last = l;
1927         if(!strcmp(l->id, id)) {
1928             current_font_id = l->id;
1929             current_gfxfont = l->font;
1930             font = l->font;
1931             output->addfont(output, id, current_gfxfont);
1932             return 1;
1933         }
1934         l = l->next;
1935     }
1936     if(!filename) return 0;
1937
1938     /* A font size of e.g. 9 means the font will be scaled down by
1939        1024 and scaled up by 9. So to have a maximum error of 1/20px,
1940        we have to divide 0.05 by (fontsize/1024)
1941      */
1942     double quality = (1024 * 0.05) / maxSize;
1943     
1944     font = gfxfont_load(filename, quality);
1945     l = new fontlist_t;
1946     l->font = font;
1947     l->filename = strdup(filename);
1948     l->id = strdup(id);
1949     l->next = 0;
1950     current_font_id = l->id;
1951     current_gfxfont = l->font;
1952     if(last) {
1953         last->next = l;
1954     } else {
1955         this->fontlist = l;
1956     }
1957     output->addfont(output, id, current_gfxfont);
1958     return 1;
1959 }
1960
1961 void SWFOutputDev::updateFont(GfxState *state) 
1962 {
1963     GfxFont*gfxFont = state->getFont();
1964       
1965     if (!gfxFont) {
1966         return;
1967     }  
1968     char * fontid = getFontID(gfxFont);
1969     double maxSize = 1.0;
1970
1971     if(this->info) {
1972         maxSize = this->info->getMaximumFontSize(fontid);
1973     }
1974     
1975     int t;
1976     /* first, look if we substituted this font before-
1977        this way, we don't initialize the T1 Fonts
1978        too often */
1979     for(t=0;t<substitutepos;t++) {
1980         if(!strcmp(fontid, substitutesource[t])) {
1981             free(fontid);fontid=0;
1982             fontid = strdup(substitutetarget[t]);
1983             break;
1984         }
1985     }
1986
1987     /* second, see if this is a font which was used before-
1988        if so, we are done */
1989     if(setGfxFont(fontid, 0, 0)) {
1990         free(fontid);
1991         return;
1992     }
1993 /*    if(swfoutput_queryfont(&output, fontid))
1994         swfoutput_setfont(&output, fontid, 0);
1995         
1996         msg("<debug> updateFont(%s) [cached]", fontid);
1997         return;
1998     }*/
1999
2000     // look for Type 3 font
2001     if (gfxFont->getType() == fontType3) {
2002         if(!type3Warning) {
2003             type3Warning = gTrue;
2004             showFontError(gfxFont, 2);
2005         }
2006         free(fontid);
2007         return;
2008     }
2009
2010     /* now either load the font, or find a substitution */
2011
2012     Ref embRef;
2013     GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
2014
2015     char*fileName = 0;
2016     int del = 0;
2017     if(embedded &&
2018        (gfxFont->getType() == fontType1 ||
2019         gfxFont->getType() == fontType1C ||
2020        (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
2021         gfxFont->getType() == fontTrueType ||
2022         gfxFont->getType() == fontCIDType2
2023        ))
2024     {
2025       fileName = writeEmbeddedFontToFile(xref, gfxFont);
2026       if(!fileName) showFontError(gfxFont,0);
2027       else del = 1;
2028     } else {
2029       char * fontname = getFontName(gfxFont);
2030       fileName = searchFont(fontname);
2031       if(!fileName) showFontError(gfxFont,0);
2032       free(fontname);
2033     }
2034     if(!fileName) {
2035         char * fontname = getFontName(gfxFont);
2036         msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
2037         msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
2038         fileName = substituteFont(gfxFont, fontid);
2039         if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
2040         msg("<notice> Font is now %s (%s)", fontid, fileName);
2041     }
2042
2043     if(!fileName) {
2044         msg("<error> Couldn't set font %s\n", fontid);
2045         free(fontid);
2046         return;
2047     }
2048         
2049     msg("<verbose> updateFont(%s) -> %s (max size: %f)", fontid, fileName, maxSize);
2050     dumpFontInfo("<verbose>", gfxFont);
2051
2052     //swfoutput_setfont(&output, fontid, fileName);
2053     
2054     if(!setGfxFont(fontid, 0, 0)) {
2055         setGfxFont(fontid, fileName, maxSize);
2056     }
2057    
2058     if(fileName && del)
2059         unlinkfont(fileName);
2060     if(fileName)
2061         free(fileName);
2062     free(fontid);
2063 }
2064
2065 #define SQR(x) ((x)*(x))
2066
2067 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
2068 {
2069     if((newwidth<2 || newheight<2) ||
2070        (width<=newwidth || height<=newheight))
2071         return 0;
2072     unsigned char*newdata;
2073     int x,y;
2074     newdata= (unsigned char*)malloc(newwidth*newheight);
2075     int t;
2076     double fx = (double)(width)/newwidth;
2077     double fy = (double)(height)/newheight;
2078     double px = 0;
2079     int blocksize = (int)(8192/(fx*fy));
2080     int r = 8192*256/palettesize;
2081     for(x=0;x<newwidth;x++) {
2082         double ex = px + fx;
2083         int fromx = (int)px;
2084         int tox = (int)ex;
2085         int xweight1 = (int)(((fromx+1)-px)*256);
2086         int xweight2 = (int)((ex-tox)*256);
2087         double py =0;
2088         for(y=0;y<newheight;y++) {
2089             double ey = py + fy;
2090             int fromy = (int)py;
2091             int toy = (int)ey;
2092             int yweight1 = (int)(((fromy+1)-py)*256);
2093             int yweight2 = (int)((ey-toy)*256);
2094             int a = 0;
2095             int xx,yy;
2096             for(xx=fromx;xx<=tox;xx++)
2097             for(yy=fromy;yy<=toy;yy++) {
2098                 int b = 1-data[width*yy+xx];
2099                 int weight=256;
2100                 if(xx==fromx) weight = (weight*xweight1)/256;
2101                 if(xx==tox) weight = (weight*xweight2)/256;
2102                 if(yy==fromy) weight = (weight*yweight1)/256;
2103                 if(yy==toy) weight = (weight*yweight2)/256;
2104                 a+=b*weight;
2105             }
2106             //if(a) a=(palettesize-1)*r/blocksize;
2107             newdata[y*newwidth+x] = (a*blocksize)/r;
2108             py = ey;
2109         }
2110         px = ex;
2111     }
2112     return newdata;
2113 }
2114
2115 #define IMAGE_TYPE_JPEG 0
2116 #define IMAGE_TYPE_LOSSLESS 1
2117
2118 static void drawimage(gfxdevice_t*dev, RGBA* data, int sizex,int sizey, 
2119         double x1,double y1,
2120         double x2,double y2,
2121         double x3,double y3,
2122         double x4,double y4, int type)
2123 {
2124     RGBA*newpic=0;
2125     
2126     double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2127     double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2128    
2129     gfxline_t p1,p2,p3,p4,p5;
2130     p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2131     p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2132     p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2133     p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2134     p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2135
2136     {p1.x = (int)(p1.x*20)/20.0;
2137      p1.y = (int)(p1.y*20)/20.0;
2138      p2.x = (int)(p2.x*20)/20.0;
2139      p2.y = (int)(p2.y*20)/20.0;
2140      p3.x = (int)(p3.x*20)/20.0;
2141      p3.y = (int)(p3.y*20)/20.0;
2142      p4.x = (int)(p4.x*20)/20.0;
2143      p4.y = (int)(p4.y*20)/20.0;
2144      p5.x = (int)(p5.x*20)/20.0;
2145      p5.y = (int)(p5.y*20)/20.0;
2146     }
2147     
2148     float m00,m10,tx;
2149     float m01,m11,ty;
2150     
2151     gfxmatrix_t m;
2152     m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
2153     m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
2154     m.tx = p1.x - 0.5;
2155     m.ty = p1.y - 0.5;
2156
2157     gfximage_t img;
2158     img.data = (gfxcolor_t*)data;
2159     img.width = sizex;
2160     img.height = sizey;
2161   
2162     if(type == IMAGE_TYPE_JPEG)
2163         /* TODO: pass image_dpi to device instead */
2164         dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
2165
2166     dev->fillbitmap(dev, &p1, &img, &m, 0);
2167 }
2168
2169 void drawimagejpeg(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey, 
2170         double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2171 {
2172     drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
2173 }
2174
2175 void drawimagelossless(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey, 
2176         double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2177 {
2178     drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2179 }
2180
2181
2182 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
2183                                    int width, int height, GfxImageColorMap*colorMap, GBool invert,
2184                                    GBool inlineImg, int mask, int*maskColors)
2185 {
2186   FILE *fi;
2187   int c;
2188   char fileName[128];
2189   double x1,y1,x2,y2,x3,y3,x4,y4;
2190   ImageStream *imgStr;
2191   Guchar pixBuf[4];
2192   GfxRGB rgb;
2193   int ncomps = 1;
2194   int bits = 1;
2195                                  
2196   if(colorMap) {
2197     ncomps = colorMap->getNumPixelComps();
2198     bits = colorMap->getBits();
2199   }
2200   imgStr = new ImageStream(str, width, ncomps,bits);
2201   imgStr->reset();
2202
2203   if(!width || !height || (height<=1 && width<=1))
2204   {
2205       msg("<verbose> Ignoring %d by %d image", width, height);
2206       unsigned char buf[8];
2207       int x,y;
2208       for (y = 0; y < height; ++y)
2209       for (x = 0; x < width; ++x) {
2210           imgStr->getPixel(buf);
2211       }
2212       delete imgStr;
2213       return;
2214   }
2215   
2216   state->transform(0, 1, &x1, &y1); x1 += user_movex; y1+= user_movey;
2217   state->transform(0, 0, &x2, &y2); x2 += user_movex; y2+= user_movey;
2218   state->transform(1, 0, &x3, &y3); x3 += user_movex; y3+= user_movey;
2219   state->transform(1, 1, &x4, &y4); x4 += user_movex; y4+= user_movey;
2220
2221   if(!pbminfo && !(str->getKind()==strDCT)) {
2222       if(!type3active) {
2223           msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2224           pbminfo = 1;
2225       }
2226       if(mask)
2227       msg("<verbose> drawing %d by %d masked picture\n", width, height);
2228   }
2229   if(!jpeginfo && (str->getKind()==strDCT)) {
2230       msg("<notice> file contains jpeg pictures");
2231       jpeginfo = 1;
2232   }
2233
2234   if(mask) {
2235       int i,j;
2236       unsigned char buf[8];
2237       int x,y;
2238       unsigned char*pic = new unsigned char[width*height];
2239       RGBA pal[256];
2240       GfxRGB rgb;
2241       state->getFillRGB(&rgb);
2242
2243       memset(pal,255,sizeof(pal));
2244       pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
2245       pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
2246       pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
2247       pal[0].a = 255;              pal[1].a = 0;
2248
2249       int numpalette = 2;
2250       int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2251       int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2252       for (y = 0; y < height; ++y)
2253       for (x = 0; x < width; ++x)
2254       {
2255             imgStr->getPixel(buf);
2256             if(invert) 
2257                 buf[0]=1-buf[0];
2258             pic[width*y+x] = buf[0];
2259       }
2260       
2261       /* the size of the drawn image is added to the identifier
2262          as the same image may require different bitmaps if displayed
2263          at different sizes (due to antialiasing): */
2264       int t,found = -1;
2265       if(type3active) {
2266           unsigned char*pic2 = 0;
2267           numpalette = 16;
2268           
2269           pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2270
2271           if(!pic2) {
2272             delete pic;
2273             delete imgStr;
2274             return;
2275           }
2276
2277           width = realwidth;
2278           height = realheight;
2279           free(pic);
2280           pic = pic2;
2281           
2282           /* make a black/white palette */
2283           GfxRGB rgb2;
2284           rgb2.r = 1 - rgb.r;
2285           rgb2.g = 1 - rgb.g;
2286           rgb2.b = 1 - rgb.b;
2287           float r = 255/(numpalette-1);
2288           int t;
2289           for(t=0;t<numpalette;t++) {
2290               pal[t].r = (U8)(255*rgb.r);
2291               pal[t].g = (U8)(255*rgb.g);
2292               pal[t].b = (U8)(255*rgb.b);
2293               pal[t].a = (U8)(t*r);
2294           }
2295       }
2296
2297       RGBA*pic2 = new RGBA[width*height];
2298       for (y = 0; y < height; ++y) {
2299         for (x = 0; x < width; ++x) {
2300           pic2[width*y+x] = pal[pic[y*width+x]];
2301         }
2302       }
2303       drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2304       free(pic2);
2305       free(pic);
2306       delete imgStr;
2307       return;
2308   } 
2309
2310   int x,y;
2311
2312   if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2313       RGBA*pic=new RGBA[width*height];
2314       for (y = 0; y < height; ++y) {
2315         for (x = 0; x < width; ++x) {
2316           imgStr->getPixel(pixBuf);
2317           colorMap->getRGB(pixBuf, &rgb);
2318           pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5);
2319           pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5);
2320           pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5);
2321           pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2322         }
2323       }
2324       if(str->getKind()==strDCT)
2325           drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2326       else
2327           drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2328       delete pic;
2329       delete imgStr;
2330       return;
2331   } else {
2332       RGBA*pic=new RGBA[width*height];
2333       RGBA pal[256];
2334       int t;
2335       for(t=0;t<256;t++) {
2336           pixBuf[0] = t;
2337           colorMap->getRGB(pixBuf, &rgb);
2338           /*if(maskColors && *maskColors==t) {
2339               msg("<notice> Color %d is transparent", t);
2340               if (imgData->maskColors) {
2341                 *alpha = 0;
2342                 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2343                   if (pix[i] < imgData->maskColors[2*i] ||
2344                       pix[i] > imgData->maskColors[2*i+1]) {
2345                     *alpha = 1;
2346                     break;
2347                   }
2348                 }
2349               } else {
2350                 *alpha = 1;
2351               }
2352               if(!*alpha) {
2353                     pal[t].r = 0;
2354                     pal[t].g = 0;
2355                     pal[t].b = 0;
2356                     pal[t].a = 0;
2357               }
2358           } else*/ {
2359               pal[t].r = (U8)(rgb.r * 255 + 0.5);
2360               pal[t].g = (U8)(rgb.g * 255 + 0.5);
2361               pal[t].b = (U8)(rgb.b * 255 + 0.5);
2362               pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2363           }
2364       }
2365       for (y = 0; y < height; ++y) {
2366         for (x = 0; x < width; ++x) {
2367           imgStr->getPixel(pixBuf);
2368           pic[width*y+x] = pal[pixBuf[0]];
2369         }
2370       }
2371       drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2372
2373       delete pic;
2374       delete imgStr;
2375       return;
2376   }
2377 }
2378
2379 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2380                                    int width, int height, GBool invert,
2381                                    GBool inlineImg) 
2382 {
2383   if(states[statepos].textRender & 4) //clipped
2384       return;
2385   msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2386   drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
2387 }
2388
2389 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2390                          int width, int height, GfxImageColorMap *colorMap,
2391                          int *maskColors, GBool inlineImg)
2392 {
2393   if(states[statepos].textRender & 4) //clipped
2394       return;
2395
2396   msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height, 
2397           colorMap?"colorMap":"no colorMap", 
2398           maskColors?"maskColors":"no maskColors",
2399           inlineImg);
2400   if(colorMap)
2401       msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2402               colorMap->getBits(),colorMap->getColorSpace()->getMode());
2403   drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
2404 }
2405
2406 //SWFOutputDev*output = 0; 
2407
2408 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2409   Object obj;
2410   GString *s1, *s2;
2411   int i;
2412
2413   if (infoDict->lookup(key, &obj)->isString()) {
2414     s1 = obj.getString();
2415     if ((s1->getChar(0) & 0xff) == 0xfe &&
2416         (s1->getChar(1) & 0xff) == 0xff) {
2417       s2 = new GString();
2418       for (i = 2; i < obj.getString()->getLength(); i += 2) {
2419         if (s1->getChar(i) == '\0') {
2420           s2->append(s1->getChar(i+1));
2421         } else {
2422           delete s2;
2423           s2 = new GString("<unicode>");
2424           break;
2425         }
2426       }
2427       printf(fmt, s2->getCString());
2428       delete s2;
2429     } else {
2430       printf(fmt, s1->getCString());
2431     }
2432   }
2433   obj.free();
2434 }
2435
2436 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2437   Object obj;
2438   char *s;
2439
2440   if (infoDict->lookup(key, &obj)->isString()) {
2441     s = obj.getString()->getCString();
2442     if (s[0] == 'D' && s[1] == ':') {
2443       s += 2;
2444     }
2445     printf(fmt, s);
2446   }
2447   obj.free();
2448 }
2449
2450 int jpeg_dpi = 0;
2451 int ppm_dpi = 0;
2452
2453 void storeDeviceParameter(char*name, char*value)
2454 {
2455     parameter_t*p = new parameter_t();
2456     p->name = strdup(name);
2457     p->value = strdup(value);
2458     p->next = 0;
2459     if(device_config_next) {
2460         device_config_next->next = p;
2461         device_config_next = p;
2462     } else {
2463         device_config = p;
2464         device_config_next = p;
2465     }
2466 }
2467
2468 void pdfswf_setparameter(char*name, char*value)
2469 {
2470     msg("<verbose> setting parameter %s to \"%s\"", name, value);
2471     if(!strcmp(name, "caplinewidth")) {
2472         caplinewidth = atof(value);
2473     } else if(!strcmp(name, "zoom")) {
2474         char buf[80];
2475         zoom = atof(value);
2476         sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2477         storeDeviceParameter("jpegsubpixels", buf);
2478         sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2479         storeDeviceParameter("ppmsubpixels", buf);
2480     } else if(!strcmp(name, "jpegdpi")) {
2481         char buf[80];
2482         jpeg_dpi = atoi(value);
2483         sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2484         storeDeviceParameter("jpegsubpixels", buf);
2485     } else if(!strcmp(name, "ppmdpi")) {
2486         char buf[80];
2487         ppm_dpi = atoi(value);
2488         sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2489         storeDeviceParameter("ppmsubpixels", buf);
2490     } else if(!strcmp(name, "forceType0Fonts")) {
2491         forceType0Fonts = atoi(value);
2492     } else if(!strcmp(name, "fontdir")) {
2493         pdfswf_addfontdir(value);
2494     } else if(!strcmp(name, "languagedir")) {
2495         pdfswf_addlanguagedir(value);
2496     } else if(!strcmp(name, "fontconfig")) {
2497         config_use_fontconfig = atoi(value);
2498     } else {
2499         storeDeviceParameter(name,value);
2500     }
2501 }
2502 void pdfswf_addfont(char*filename)
2503 {
2504     fontfile_t f;
2505     memset(&f, 0, sizeof(fontfile_t));
2506     f.filename = filename;
2507     if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2508         fonts[fontnum++] = f;
2509     } else {
2510         msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2511     }
2512 }
2513
2514 static char* dirseparator()
2515 {
2516 #ifdef WIN32
2517     return "\\";
2518 #else
2519     return "/";
2520 #endif
2521 }
2522
2523 void pdfswf_addlanguagedir(char*dir)
2524 {
2525     if(!globalParams)
2526         globalParams = new GlobalParams("");
2527     
2528     msg("<notice> Adding %s to language pack directories", dir);
2529
2530     int l;
2531     FILE*fi = 0;
2532     char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2533     strcpy(config_file, dir);
2534     strcat(config_file, dirseparator());
2535     strcat(config_file, "add-to-xpdfrc");
2536
2537     fi = fopen(config_file, "rb");
2538     if(!fi) {
2539         msg("<error> Could not open %s", config_file);
2540         return;
2541     }
2542     globalParams->parseFile(new GString(config_file), fi);
2543     fclose(fi);
2544 }
2545
2546 void pdfswf_addfontdir(char*dirname)
2547 {
2548 #ifdef HAVE_DIRENT_H
2549     msg("<notice> Adding %s to font directories", dirname);
2550     DIR*dir = opendir(dirname);
2551     if(!dir) {
2552         msg("<warning> Couldn't open directory %s\n", dirname);
2553         return;
2554     }
2555     struct dirent*ent;
2556     while(1) {
2557         ent = readdir (dir);
2558         if (!ent) 
2559             break;
2560         int l;
2561         char*name = ent->d_name;
2562         char type = 0;
2563         if(!name) continue;
2564         l=strlen(name);
2565         if(l<4)
2566             continue;
2567         if(!strncasecmp(&name[l-4], ".pfa", 4)) 
2568             type=1;
2569         if(!strncasecmp(&name[l-4], ".pfb", 4)) 
2570             type=3;
2571         if(!strncasecmp(&name[l-4], ".ttf", 4)) 
2572             type=2;
2573         if(type)
2574         {
2575             char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2576             strcpy(fontname, dirname);
2577             strcat(fontname, dirseparator());
2578             strcat(fontname, name);
2579             msg("<verbose> Adding %s to fonts", fontname);
2580             pdfswf_addfont(fontname);
2581         }
2582     }
2583     closedir(dir);
2584 #else
2585     msg("<warning> No dirent.h- unable to add font dir %s", dir);
2586 #endif
2587 }
2588
2589
2590 typedef struct _pdf_doc_internal
2591 {
2592     int protect;
2593     PDFDoc*doc;
2594     InfoOutputDev*info;
2595 } pdf_doc_internal_t;
2596 typedef struct _pdf_page_internal
2597 {
2598 } pdf_page_internal_t;
2599 typedef struct _swf_output_internal
2600 {
2601     SWFOutputDev*outputDev;
2602 } swf_output_internal_t;
2603
2604 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2605 {
2606     pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2607     memset(pdf_doc, 0, sizeof(pdf_doc_t));
2608     pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2609     memset(i, 0, sizeof(pdf_doc_internal_t));
2610     pdf_doc->internal = i;
2611     
2612     GString *fileName = new GString(filename);
2613     GString *userPW;
2614     Object info;
2615
2616     // read config file
2617     if(!globalParams)
2618         globalParams = new GlobalParams("");
2619
2620     // open PDF file
2621     if (userPassword && userPassword[0]) {
2622       userPW = new GString(userPassword);
2623     } else {
2624       userPW = NULL;
2625     }
2626     i->doc = new PDFDoc(fileName, userPW);
2627     if (userPW) {
2628       delete userPW;
2629     }
2630     if (!i->doc->isOk()) {
2631         return 0;
2632     }
2633
2634     // print doc info
2635     i->doc->getDocInfo(&info);
2636     if (info.isDict() &&
2637       (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2638       printInfoString(info.getDict(), "Title",        "Title:        %s\n");
2639       printInfoString(info.getDict(), "Subject",      "Subject:      %s\n");
2640       printInfoString(info.getDict(), "Keywords",     "Keywords:     %s\n");
2641       printInfoString(info.getDict(), "Author",       "Author:       %s\n");
2642       printInfoString(info.getDict(), "Creator",      "Creator:      %s\n");
2643       printInfoString(info.getDict(), "Producer",     "Producer:     %s\n");
2644       printInfoDate(info.getDict(),   "CreationDate", "CreationDate: %s\n");
2645       printInfoDate(info.getDict(),   "ModDate",      "ModDate:      %s\n");
2646       printf("Pages:        %d\n", i->doc->getNumPages());
2647       printf("Linearized:   %s\n", i->doc->isLinearized() ? "yes" : "no");
2648       printf("Encrypted:    ");
2649       if (i->doc->isEncrypted()) {
2650         printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2651                i->doc->okToPrint() ? "yes" : "no",
2652                i->doc->okToCopy() ? "yes" : "no",
2653                i->doc->okToChange() ? "yes" : "no",
2654                i->doc->okToAddNotes() ? "yes" : "no");
2655       } else {
2656         printf("no\n");
2657       }
2658     }
2659     info.free();
2660                    
2661     pdf_doc->num_pages = i->doc->getNumPages();
2662     i->protect = 0;
2663     if (i->doc->isEncrypted()) {
2664           if(!i->doc->okToCopy()) {
2665               printf("PDF disallows copying.\n");
2666               return 0;
2667           }
2668           if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2669               i->protect = 1;
2670     }
2671
2672     InfoOutputDev*io = new InfoOutputDev();
2673     int t;
2674     for(t=1;t<=pdf_doc->num_pages;t++) {
2675 #ifdef XPDF_101
2676         i->doc->displayPage((OutputDev*)io, t, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2677 #else
2678         i->doc->displayPage((OutputDev*)io, t, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2679 #endif
2680     }
2681     i->info = io;
2682
2683     return pdf_doc;
2684 }
2685
2686 class MemCheck
2687 {
2688     public: ~MemCheck()
2689     {
2690         delete globalParams;globalParams=0;
2691         Object::memCheck(stderr);
2692         gMemReport(stderr);
2693     }
2694 } myMemCheck;
2695
2696 void pdf_destroy(pdf_doc_t*pdf_doc)
2697 {
2698     pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2699
2700     delete i->doc; i->doc=0;
2701     
2702     if(i->info) {
2703         delete i->info;i->info=0;
2704     }
2705
2706     free(pdf_doc->internal);pdf_doc->internal=0;
2707     free(pdf_doc);pdf_doc=0;
2708 }
2709
2710 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2711 {
2712     pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2713
2714     if(page < 1 || page > pdf_doc->num_pages)
2715         return 0;
2716     
2717     pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2718     pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2719     memset(pi, 0, sizeof(pdf_page_internal_t));
2720     pdf_page->internal = pi;
2721
2722     pdf_page->parent = pdf_doc;
2723     pdf_page->nr = page;
2724     return pdf_page;
2725 }
2726
2727 void pdf_page_destroy(pdf_page_t*pdf_page)
2728 {
2729     pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2730     free(pdf_page->internal);pdf_page->internal = 0;
2731     free(pdf_page);pdf_page=0;
2732 }
2733
2734 swf_output_t* swf_output_init() 
2735 {
2736     swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2737     memset(swf_output, 0, sizeof(swf_output_t));
2738     swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2739     memset(i, 0, sizeof(swf_output_internal_t));
2740     swf_output->internal = i;
2741
2742     i->outputDev = new SWFOutputDev();
2743     return swf_output;
2744 }
2745
2746 void swf_output_setparameter(swf_output_t*swf, char*name, char*value)
2747 {
2748     pdfswf_setparameter(name, value);
2749 }
2750
2751 void swf_output_startframe(swf_output_t*swf, int width, int height)
2752 {
2753     swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2754     i->outputDev->startFrame(width, height);
2755 }
2756
2757 void swf_output_endframe(swf_output_t*swf)
2758 {
2759     swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2760     i->outputDev->endframe();
2761 }
2762
2763 void swf_output_preparepage(swf_output_t*swf, int pdfpage, int outputpage)
2764 {
2765     swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2766     SWFOutputDev*o = i->outputDev;
2767
2768     if(pdfpage < 0)
2769         return;
2770
2771     if(!o->pages) {
2772         o->pagebuflen = 1024;
2773         o->pages = (int*)malloc(o->pagebuflen*sizeof(int));
2774         memset(o->pages, -1, o->pagebuflen*sizeof(int));
2775     } else {
2776         while(pdfpage >= o->pagebuflen)
2777         {
2778             int oldlen = o->pagebuflen;
2779             o->pagebuflen+=1024;
2780             o->pages = (int*)realloc(o->pages, o->pagebuflen*sizeof(int));
2781             memset(&o->pages[oldlen], -1, (o->pagebuflen-oldlen)*sizeof(int));
2782         }
2783     }
2784     o->pages[pdfpage] = outputpage;
2785     if(pdfpage>o->pagepos)
2786         o->pagepos = pdfpage;
2787 }
2788
2789 int swf_output_save(swf_output_t*swf, char*filename)
2790 {
2791     swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2792     int ret = i->outputDev->save(filename);
2793     return ret;
2794 }
2795
2796 void* swf_output_get(swf_output_t*swf)
2797 {
2798     swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2799     void* ret = i->outputDev->getSWF();
2800     return ret;
2801 }
2802
2803 void swf_output_destroy(swf_output_t*output)
2804 {
2805     swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2806     delete i->outputDev; i->outputDev=0;
2807     free(output->internal);output->internal=0;
2808     free(output);
2809 }
2810
2811 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2812 {
2813     pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2814     swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2815
2816     if(!pi) {
2817         msg("<fatal> pdf_page_render: Parent PDF this page belongs to doesn't exist yet/anymore");
2818         return;
2819     }
2820
2821     if(pi->protect) {
2822         gfxdevice_t*dev = si->outputDev->output;
2823         dev->setparameter(dev, "protect", "1");
2824     }
2825     si->outputDev->setInfo(pi->info);
2826     si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2827 #ifdef XPDF_101
2828     pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2829 #else
2830     pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2831 #endif
2832 }
2833
2834 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2835 {
2836     pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2837     swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2838
2839     si->outputDev->setMove(x,y);
2840     if((x1|y1|x2|y2)==0) x2++;
2841     si->outputDev->setClip(x1,y1,x2,y2);
2842
2843     pdf_page_render2(page, output);
2844 }
2845 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2846 {
2847     pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2848     swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2849     
2850     si->outputDev->setMove(0,0);
2851     si->outputDev->setClip(0,0,0,0);
2852     
2853     pdf_page_render2(page, output);
2854 }
2855
2856
2857 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2858 {
2859     pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2860     pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2861     pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2862     memset(info, 0, sizeof(pdf_page_info_t));
2863
2864     InfoOutputDev*output = new InfoOutputDev;
2865     
2866 #ifdef XPDF_101
2867     pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2868 #else
2869     pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2870 #endif
2871
2872     info->xMin = output->x1;
2873     info->yMin = output->y1;
2874     info->xMax = output->x2;
2875     info->yMax = output->y2;
2876     info->number_of_images = output->num_images;
2877     info->number_of_links = output->num_links;
2878     info->number_of_fonts = output->num_fonts;
2879
2880     delete output;
2881
2882     return info;
2883 }
2884
2885 void pdf_page_info_destroy(pdf_page_info_t*info)
2886 {
2887     free(info);
2888
2889 }