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