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