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