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