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