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