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