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