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