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