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