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