added libpdf
[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     /* configure device */
189     while(p) {
190         if(!strcmp(p->name,"forceType0Fonts")) {
191             this->forceType0Fonts = atoi(p->value);
192         } else if(!strcmp(p->name,"fontconfig")) {
193             this->config_use_fontconfig = atoi(p->value);
194         } else {
195             msg("<warning> Ignored Paramter %s=%s", p->name, p->value);
196         }
197         p = p->next;
198     }
199 };
200   
201 void GFXOutputDev::setDevice(gfxdevice_t*dev)
202 {
203     this->device = dev;
204 }
205   
206 void GFXOutputDev::setMove(int x,int y)
207 {
208     this->user_movex = x;
209     this->user_movey = y;
210 }
211
212 void GFXOutputDev::setClip(int x1,int y1,int x2,int y2)
213 {
214     if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
215     if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
216
217     this->user_clipx1 = x1;
218     this->user_clipy1 = y1;
219     this->user_clipx2 = x2;
220     this->user_clipy2 = y2;
221 }
222
223 static char*getFontID(GfxFont*font)
224 {
225     Ref*ref = font->getID();
226     GString*gstr = font->getName();
227     char* fname = gstr==0?0:gstr->getCString();
228     char buf[128];
229     if(fname==0) {
230         sprintf(buf, "font-%d-%d", ref->num, ref->gen);
231     } else {
232         sprintf(buf, "%s-%d-%d", fname, ref->num, ref->gen);
233     }
234     return strdup(buf);
235 }
236
237 static char*getFontName(GfxFont*font)
238 {
239     char*fontid;
240     GString*gstr = font->getName();
241     char* fname = gstr==0?0:gstr->getCString();
242     if(fname==0) {
243         char buf[32];
244         Ref*r=font->getID();
245         sprintf(buf, "UFONT%d", r->num);
246         fontid = strdup(buf);
247     }
248     fontid = strdup(fname);
249
250     char*fontname= 0;
251     char* plus = strchr(fontid, '+');
252     if(plus && plus < &fontid[strlen(fontid)-1]) {
253         fontname = strdup(plus+1);
254     } else {
255         fontname = strdup(fontid);
256     }
257     free(fontid);
258     return fontname;
259 }
260
261 static char mybuf[1024];
262 static char* gfxstate2str(GfxState *state)
263 {
264   char*bufpos = mybuf;
265   GfxRGB rgb;
266   bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
267                                     state->getCTM()[0],
268                                     state->getCTM()[1],
269                                     state->getCTM()[2],
270                                     state->getCTM()[3],
271                                     state->getCTM()[4],
272                                     state->getCTM()[5]);
273   if(state->getX1()!=0.0)
274   bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
275   if(state->getY1()!=0.0)
276   bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
277   bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
278   bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
279   bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
280   bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
281   /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
282           state->getFillColor()->c[0], state->getFillColor()->c[1]);
283   bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
284           state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
285 /*  bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
286           state->getFillColor()->c[0], state->getFillColor()->c[1],
287           state->getFillColor()->c[2], state->getFillColor()->c[3],
288           state->getFillColor()->c[4], state->getFillColor()->c[5],
289           state->getFillColor()->c[6], state->getFillColor()->c[7]);
290   bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
291           state->getStrokeColor()->c[0], state->getFillColor()->c[1],
292           state->getStrokeColor()->c[2], state->getFillColor()->c[3],
293           state->getStrokeColor()->c[4], state->getFillColor()->c[5],
294           state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
295   state->getFillRGB(&rgb);
296   if(rgb.r || rgb.g || rgb.b)
297   bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
298   state->getStrokeRGB(&rgb);
299   if(rgb.r || rgb.g || rgb.b)
300   bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
301   if(state->getFillColorSpace()->getNComps()>1)
302   bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
303   if(state->getStrokeColorSpace()->getNComps()>1)
304   bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
305   if(state->getFillPattern())
306   bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
307   if(state->getStrokePattern())
308   bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
309  
310   if(state->getFillOpacity()!=1.0)
311   bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
312   if(state->getStrokeOpacity()!=1.0)
313   bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
314
315   bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
316  
317   double * dash;
318   int length;
319   double start;
320   state->getLineDash(&dash, &length, &start);
321   int t;
322   if(length)
323   {
324       bufpos+=sprintf(bufpos,"DASH%.1f[",start);
325       for(t=0;t<length;t++) {
326           bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
327       }
328       bufpos+=sprintf(bufpos,"]");
329   }
330
331   if(state->getFlatness()!=1)
332   bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
333   if(state->getLineJoin()!=0)
334   bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
335   if(state->getLineJoin()!=0)
336   bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
337   if(state->getLineJoin()!=0)
338   bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
339
340   if(state->getFont() && getFontID(state->getFont()))
341   bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
342   bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
343   bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
344                                    state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
345   if(state->getCharSpace())
346   bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
347   if(state->getWordSpace())
348   bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
349   if(state->getHorizScaling()!=1.0)
350   bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
351   if(state->getLeading())
352   bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
353   if(state->getRise())
354   bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
355   if(state->getRender())
356   bufpos+=sprintf(bufpos,"R%d ", state->getRender());
357   bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
358   bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
359   bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
360   if(state->getLineX())
361   bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
362   if(state->getLineY())
363   bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
364   bufpos+=sprintf(bufpos," ");
365   return mybuf;
366 }
367
368 static void dumpFontInfo(char*loglevel, GfxFont*font);
369 static int lastdumps[1024];
370 static int lastdumppos = 0;
371 /* nr = 0  unknown
372    nr = 1  substituting
373    nr = 2  type 3
374  */
375 static void showFontError(GfxFont*font, int nr) 
376 {  
377     Ref*r=font->getID();
378     int t;
379     for(t=0;t<lastdumppos;t++)
380         if(lastdumps[t] == r->num)
381             break;
382     if(t < lastdumppos)
383       return;
384     if(lastdumppos<sizeof(lastdumps)/sizeof(int))
385     lastdumps[lastdumppos++] = r->num;
386     if(nr == 0)
387       msg("<warning> The following font caused problems:");
388     else if(nr == 1)
389       msg("<warning> The following font caused problems (substituting):");
390     else if(nr == 2)
391       msg("<warning> The following Type 3 Font will be rendered as bitmap:");
392     dumpFontInfo("<warning>", font);
393 }
394
395 static void dumpFontInfo(char*loglevel, GfxFont*font)
396 {
397   char* id = getFontID(font);
398   char* name = getFontName(font);
399   Ref* r=font->getID();
400   msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
401
402   GString*gstr  = font->getTag();
403    
404   msg("%s| Tag: %s\n", loglevel, id);
405   
406   if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
407
408   GfxFontType type=font->getType();
409   switch(type) {
410     case fontUnknownType:
411      msg("%s| Type: unknown\n",loglevel);
412     break;
413     case fontType1:
414      msg("%s| Type: 1\n",loglevel);
415     break;
416     case fontType1C:
417      msg("%s| Type: 1C\n",loglevel);
418     break;
419     case fontType3:
420      msg("%s| Type: 3\n",loglevel);
421     break;
422     case fontTrueType:
423      msg("%s| Type: TrueType\n",loglevel);
424     break;
425     case fontCIDType0:
426      msg("%s| Type: CIDType0\n",loglevel);
427     break;
428     case fontCIDType0C:
429      msg("%s| Type: CIDType0C\n",loglevel);
430     break;
431     case fontCIDType2:
432      msg("%s| Type: CIDType2\n",loglevel);
433     break;
434   }
435   
436   Ref embRef;
437   GBool embedded = font->getEmbeddedFontID(&embRef);
438   char*embeddedName=0;
439   if(font->getEmbeddedFontName()) {
440     embeddedName = font->getEmbeddedFontName()->getCString();
441   }
442   if(embedded)
443    msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
444
445   gstr = font->getExtFontFile();
446   if(gstr)
447    msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
448
449   // Get font descriptor flags.
450   if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
451   if(font->isSerif()) msg("%s| is serif\n", loglevel);
452   if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
453   if(font->isItalic()) msg("%s| is italic\n", loglevel);
454   if(font->isBold()) msg("%s| is bold\n", loglevel);
455
456   free(id);
457   free(name);
458 }
459
460 //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");}
461 //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");}
462
463
464 void dump_outline(gfxline_t*line)
465 {
466     while(line) {
467         if(line->type == gfx_moveTo) {
468             msg("<debug> |     moveTo %.2f %.2f", line->x,line->y);
469         } else if(line->type == gfx_lineTo) {
470             msg("<debug> |     lineTo %.2f %.2f", line->x,line->y);
471         } else if(line->type == gfx_splineTo) {
472             msg("<debug> |     splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
473         }
474         line = line->next;
475     }
476 }
477
478 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey)
479 {
480     int num = path->getNumSubpaths();
481     int s,t;
482     int cpos = 0;
483     double lastx=0,lasty=0,posx=0,posy=0;
484     int needsfix=0;
485     if(!num) {
486         msg("<warning> empty path");
487         return 0;
488     }
489     gfxdrawer_t draw;
490     gfxdrawer_target_gfxline(&draw);
491
492     for(t = 0; t < num; t++) {
493         GfxSubpath *subpath = path->getSubpath(t);
494         int subnum = subpath->getNumPoints();
495         double bx=0,by=0,cx=0,cy=0;
496
497         for(s=0;s<subnum;s++) {
498            double x,y;
499            
500            state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
501            x += user_movex;
502            y += user_movey;
503
504            if(s==0) {
505                 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
506                     draw.lineTo(&draw, lastx, lasty);
507                 }
508                 draw.moveTo(&draw, x,y);
509                 posx = lastx = x; 
510                 posy = lasty = y;
511                 cpos = 0;
512                 needsfix = 0;
513            } else if(subpath->getCurve(s) && cpos==0) {
514                 bx = x;
515                 by = y;
516                 cpos = 1;
517            } else if(subpath->getCurve(s) && cpos==1) {
518                 cx = x;
519                 cy = y;
520                 cpos = 2;
521            } else {
522                 posx = x;
523                 posy = y;
524                 if(cpos==0) {
525                     draw.lineTo(&draw, x,y);
526                 } else {
527                     gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y, 0.05);
528                 }
529                 needsfix = 1;
530                 cpos = 0;
531            }
532         }
533     }
534     /* fix non-closed lines */
535     if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
536         draw.lineTo(&draw, lastx, lasty);
537     }
538     gfxline_t*result = (gfxline_t*)draw.result(&draw);
539     return result;
540 }
541
542 /*----------------------------------------------------------------------------
543  * Primitive Graphic routines
544  *----------------------------------------------------------------------------*/
545
546 void GFXOutputDev::stroke(GfxState *state) 
547 {
548     GfxPath * path = state->getPath();
549     gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex, user_movey);
550     strokeGfxline(state, line);
551     gfxline_free(line);
552 }
553
554 void GFXOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
555 {
556     int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
557     int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
558     double miterLimit = state->getMiterLimit();
559     double width = state->getTransformedLineWidth();
560
561     GfxRGB rgb;
562     double opaq = state->getStrokeOpacity();
563     if(type3active)
564         state->getFillRGB(&rgb);
565     else
566         state->getStrokeRGB(&rgb);
567     gfxcolor_t col;
568     col.r = colToByte(rgb.r);
569     col.g = colToByte(rgb.g);
570     col.b = colToByte(rgb.b);
571     col.a = (unsigned char)(opaq*255);
572    
573     gfx_capType capType = gfx_capRound;
574     if(lineCap == 0) capType = gfx_capButt;
575     else if(lineCap == 1) capType = gfx_capRound;
576     else if(lineCap == 2) capType = gfx_capSquare;
577
578     gfx_joinType joinType = gfx_joinRound;
579     if(lineJoin == 0) joinType = gfx_joinMiter;
580     else if(lineJoin == 1) joinType = gfx_joinRound;
581     else if(lineJoin == 2) joinType = gfx_joinBevel;
582
583     int dashnum = 0;
584     double dashphase = 0;
585     double * ldash = 0;
586     state->getLineDash(&ldash, &dashnum, &dashphase);
587
588     gfxline_t*line2 = 0;
589
590     if(dashnum && ldash) {
591         float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
592         int t;
593         double cut = 0;
594         int fixzero = 0;
595         msg("<trace> %d dashes", dashnum);
596         msg("<trace> |  phase: %f", dashphase);
597         for(t=0;t<dashnum;t++) {
598             dash[t] = ldash[t];
599             msg("<trace> |  d%-3d: %f", t, ldash[t]);
600         }
601         dash[dashnum] = -1;
602         if(getLogLevel() >= LOGLEVEL_TRACE) {
603             dump_outline(line);
604         }
605
606         line2 = gfxtool_dash_line(line, dash, dashphase);
607         line = line2;
608         free(dash);
609         msg("<trace> After dashing:");
610     }
611     
612     if(getLogLevel() >= LOGLEVEL_TRACE)  {
613         msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x\n",
614                 width,
615                 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
616                 lineCap==0?"butt": (lineJoin==1?"round":"square"),
617                 dashnum,
618                 col.r,col.g,col.b,col.a
619                 );
620         dump_outline(line);
621     }
622    
623     //swfoutput_drawgfxline(output, line, width, &col, capType, joinType, miterLimit);
624     device->stroke(device, line, width, &col, capType, joinType, miterLimit);
625     
626     if(line2)
627         gfxline_free(line2);
628 }
629
630 void convertRGB()
631 {
632 }
633
634 gfxcolor_t getFillColor(GfxState * state)
635 {
636     GfxRGB rgb;
637     double opaq = state->getFillOpacity();
638     state->getFillRGB(&rgb);
639     gfxcolor_t col;
640     col.r = colToByte(rgb.r);
641     col.g = colToByte(rgb.g);
642     col.b = colToByte(rgb.b);
643     col.a = (unsigned char)(opaq*255);
644     return col;
645 }
646
647 void GFXOutputDev::fillGfxLine(GfxState *state, gfxline_t*line) 
648 {
649     gfxcolor_t col = getFillColor(state);
650
651     if(getLogLevel() >= LOGLEVEL_TRACE)  {
652         msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
653         dump_outline(line);
654     }
655     device->fill(device, line, &col);
656 }
657 void GFXOutputDev::fill(GfxState *state) 
658 {
659     GfxPath * path = state->getPath();
660     gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
661     fillGfxLine(state, line);
662     gfxline_free(line);
663 }
664 void GFXOutputDev::eoFill(GfxState *state) 
665 {
666     GfxPath * path = state->getPath();
667     gfxcolor_t col = getFillColor(state);
668
669     gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
670
671     if(getLogLevel() >= LOGLEVEL_TRACE)  {
672         msg("<trace> eofill\n");
673         dump_outline(line);
674     }
675
676     device->fill(device, line, &col);
677     gfxline_free(line);
678 }
679
680 void GFXOutputDev::clip(GfxState *state) 
681 {
682     GfxPath * path = state->getPath();
683     gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
684     clipToGfxLine(state, line);
685     gfxline_free(line);
686 }
687
688 void GFXOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line) 
689 {
690     if(getLogLevel() >= LOGLEVEL_TRACE)  {
691         msg("<trace> clip\n");
692         dump_outline(line);
693     }
694
695     device->startclip(device, line);
696     states[statepos].clipping++;
697 }
698 void GFXOutputDev::eoClip(GfxState *state) 
699 {
700     GfxPath * path = state->getPath();
701     gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
702
703     if(getLogLevel() >= LOGLEVEL_TRACE)  {
704         msg("<trace> eoclip\n");
705         dump_outline(line);
706     }
707
708     device->startclip(device, line);
709     states[statepos].clipping++;
710     gfxline_free(line);
711 }
712
713 void GFXOutputDev::endframe()
714 {
715     if(outer_clip_box) {
716         device->endclip(device);
717         outer_clip_box = 0;
718     }
719
720     device->endpage(device);
721 }
722
723 void GFXOutputDev::finish()
724 {
725     if(outer_clip_box) {
726         if(device) {
727             device->endclip(device);
728         }
729         outer_clip_box = 0;
730     }
731 }
732
733 GFXOutputDev::~GFXOutputDev() 
734 {
735     finish();
736
737     if(this->pages) {
738         free(this->pages); this->pages = 0;
739     }
740
741     fontlist_t*l = this->fontlist;
742     while(l) {
743         fontlist_t*next = l->next;
744         l->next = 0;
745         gfxfont_free(l->font);
746         free(l->id);l->id=0;
747         free(l->filename);l->filename=0;
748         free(l);
749         l = next;
750     }
751     this->fontlist = 0;
752 };
753 GBool GFXOutputDev::upsideDown() 
754 {
755     return gTrue;
756 };
757 GBool GFXOutputDev::useDrawChar() 
758 {
759     return gTrue;
760 }
761
762 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
763                       "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
764
765 #define RENDER_FILL 0
766 #define RENDER_STROKE 1
767 #define RENDER_FILLSTROKE 2
768 #define RENDER_INVISIBLE 3
769 #define RENDER_CLIP 4
770
771 static char tmp_printstr[4096];
772 char* makeStringPrintable(char*str)
773 {
774     int len = strlen(str);
775     int dots = 0;
776     if(len>=80) {
777         len = 80;
778         dots = 1;
779     }
780     int t;
781     for(t=0;t<len;t++) {
782         char c = str[t];
783         if(c<32 || c>124) {
784             c = '.';
785         }
786         tmp_printstr[t] = c;
787     }
788     if(dots) {
789         tmp_printstr[len++] = '.';
790         tmp_printstr[len++] = '.';
791         tmp_printstr[len++] = '.';
792     }
793     tmp_printstr[len] = 0;
794     return tmp_printstr;
795 }
796
797
798 int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
799 {
800     char*uniname = 0;
801     if(u>0) {
802         int t;
803         /* find out char name from unicode index 
804            TODO: should be precomputed
805          */
806         for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
807             if(nameToUnicodeTab[t].u == u) {
808                 uniname = nameToUnicodeTab[t].name;
809                 break;
810             }
811         }
812     }
813
814     if(charname) {
815         int t;
816         for(t=0;t<font->num_glyphs;t++) {
817             if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) {
818                 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
819                 return t;
820             }
821         }
822         /* if we didn't find the character, maybe
823            we can find the capitalized version */
824         for(t=0;t<font->num_glyphs;t++) {
825             if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) {
826                 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
827                 return t;
828             }
829         }
830     }
831
832     if(uniname) {
833         int t;
834         for(t=0;t<font->num_glyphs;t++) {
835             if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,uniname)) {
836                 msg("<debug> Char [%d,%s,>%d(%s)<] maps to %d\n", charnr, charname, u, uniname, t);
837                 return t;
838             }
839         }
840         /* if we didn't find the character, maybe
841            we can find the capitalized version */
842         for(t=0;t<font->num_glyphs;t++) {
843             if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,uniname)) {
844                 msg("<debug> Char [%d,%s,>>%d(%s)<<] maps to %d\n", charnr, charname, u, uniname, t);
845                 return t;
846             }
847         }
848     }
849
850     /* try to use the unicode id */
851     if(u>=0 && u<font->max_unicode && font->unicode2glyph[u]>=0) {
852         msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]);
853         return font->unicode2glyph[u];
854     }
855
856     if(charnr>=0 && charnr<font->num_glyphs) {
857         msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
858         return charnr;
859     }
860     
861     return -1;
862 }
863
864
865 void GFXOutputDev::beginString(GfxState *state, GString *s) 
866
867     int render = state->getRender();
868     if(current_text_stroke) {
869         msg("<error> Error: Incompatible change of text rendering to %d while inside cliptext", render);
870     }
871
872     msg("<trace> beginString(%s) render=%d", makeStringPrintable(s->getCString()), render);
873     double m11,m21,m12,m22;
874 //    msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
875     state->getFontTransMat(&m11, &m12, &m21, &m22);
876     m11 *= state->getHorizScaling();
877     m21 *= state->getHorizScaling();
878
879     this->current_font_matrix.m00 = m11 / 1024.0;
880     this->current_font_matrix.m01 = m12 / 1024.0;
881     this->current_font_matrix.m10 = -m21 / 1024.0;
882     this->current_font_matrix.m11 = -m22 / 1024.0;
883     this->current_font_matrix.tx = 0;
884     this->current_font_matrix.ty = 0;
885
886     gfxmatrix_t m = this->current_font_matrix;
887
888     /*if(render != 3 && render != 0)
889         msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/
890     states[statepos].textRender = render;
891 }
892
893 void GFXOutputDev::drawChar(GfxState *state, double x, double y,
894                         double dx, double dy,
895                         double originX, double originY,
896                         CharCode c, int nBytes, Unicode *_u, int uLen)
897 {
898     int render = state->getRender();
899     // check for invisible text -- this is used by Acrobat Capture
900     if (render == 3) {
901         msg("<debug> Ignoring invisible text: char %d at %f,%f", c, x, y);
902         return;
903     }
904
905     if(states[statepos].textRender != render)
906         msg("<error> Internal error: drawChar.render!=beginString.render");
907
908     gfxcolor_t col = getFillColor(state);
909
910     Gushort *CIDToGIDMap = 0;
911     GfxFont*font = state->getFont();
912
913     if(font->getType() == fontType3) {
914         /* type 3 chars are passed as graphics */
915         msg("<debug> type3 char at %f/%f", x, y);
916         return;
917     }
918     
919     Unicode u=0;
920     char*name=0;
921
922     if(uLen)
923         u = _u[0];
924
925     if(font->isCIDFont()) {
926         GfxCIDFont*cfont = (GfxCIDFont*)font;
927
928         if(font->getType() == fontCIDType2)
929             CIDToGIDMap = cfont->getCIDToGID();
930     } else {
931         Gfx8BitFont*font8;
932         font8 = (Gfx8BitFont*)font;
933         char**enc=font8->getEncoding();
934         name = enc[c];
935     }
936     if (CIDToGIDMap) {
937         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);
938         c = CIDToGIDMap[c];
939     } else {
940         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);
941     }
942
943     int charid = -1;
944    
945     if(uLen<=1) {
946         charid = getGfxCharID(current_gfxfont, c, name, u);
947     } else {
948         charid = getGfxCharID(current_gfxfont, c, name, -1);
949
950         if(charid < 0) {
951             /* multiple unicodes- should usually map to a ligature.
952                if the ligature doesn't exist, we need to draw
953                the characters one-by-one. */
954             int t;
955             msg("<warning> ligature %d missing in font %s\n", c, current_font_id);
956             for(t=0;t<uLen;t++) {
957                 drawChar(state, x, y, dx, dy, originX, originY, c, nBytes, _u+t, 1);
958             }
959             return;
960         }
961     }
962     if(charid<0) {
963         msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)", 
964                 FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
965         return;
966     }
967
968     gfxmatrix_t m = this->current_font_matrix;
969     state->transform(x, y, &m.tx, &m.ty);
970     m.tx += user_movex;
971     m.ty += user_movey;
972
973     if(render == RENDER_FILL) {
974         device->drawchar(device, current_font_id, charid, &col, &m);
975     } else {
976         msg("<debug> Drawing glyph %d as shape", charid);
977         if(!textmodeinfo) {
978             msg("<notice> Some texts will be rendered as shape");
979             textmodeinfo = 1;
980         }
981         gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
982         gfxline_t*tglyph = gfxline_clone(glyph);
983         gfxline_transform(tglyph, &m);
984         if((render&3) != RENDER_INVISIBLE) {
985             gfxline_t*add = gfxline_clone(tglyph);
986             current_text_stroke = gfxline_append(current_text_stroke, add);
987         }
988         if(render&RENDER_CLIP) {
989             gfxline_t*add = gfxline_clone(tglyph);
990             current_text_clip = gfxline_append(current_text_clip, add);
991         }
992         gfxline_free(tglyph);
993     }
994 }
995
996 void GFXOutputDev::endString(GfxState *state) 
997
998     int render = state->getRender();
999     msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
1000     if(states[statepos].textRender != render)
1001         msg("<error> Internal error: drawChar.render!=beginString.render");
1002     
1003     if(current_text_stroke) {
1004         /* fillstroke and stroke text rendering objects we can process right
1005            now (as there may be texts of other rendering modes in this
1006            text object)- clipping objects have to wait until endTextObject,
1007            however */
1008         device->setparameter(device, "mark","TXT");
1009         if((render&3) == RENDER_FILL) {
1010             fillGfxLine(state, current_text_stroke);
1011             gfxline_free(current_text_stroke);
1012             current_text_stroke = 0;
1013         } else if((render&3) == RENDER_FILLSTROKE) {
1014             fillGfxLine(state, current_text_stroke);
1015             strokeGfxline(state, current_text_stroke);
1016             gfxline_free(current_text_stroke);
1017             current_text_stroke = 0;
1018         } else if((render&3) == RENDER_STROKE) {
1019             strokeGfxline(state, current_text_stroke);
1020             gfxline_free(current_text_stroke);
1021             current_text_stroke = 0;
1022         }
1023         device->setparameter(device, "mark","");
1024     }
1025 }    
1026
1027 void GFXOutputDev::endTextObject(GfxState *state)
1028 {
1029     int render = state->getRender();
1030     msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
1031     if(states[statepos].textRender != render)
1032         msg("<error> Internal error: drawChar.render!=beginString.render");
1033     
1034     if(current_text_clip) {
1035         device->setparameter(device, "mark","TXT");
1036         clipToGfxLine(state, current_text_clip);
1037         device->setparameter(device, "mark","");
1038         gfxline_free(current_text_clip);
1039         current_text_clip = 0;
1040     }
1041 }
1042
1043 /* the logic seems to be as following:
1044    first, beginType3Char is called, with the charcode and the coordinates.
1045    if this function returns true, it already knew about the char and has now drawn it.
1046    if the function returns false, it's a new char, and type3D1 is called with some parameters-
1047    the all draw operations until endType3Char are part of the char (which in this moment is
1048    at the position first passed to beginType3Char). the char ends with endType3Char.
1049
1050    The drawing operations between beginType3Char and endType3Char are somewhat different to
1051    the normal ones. For example, the fillcolor equals the stroke color.
1052 */
1053
1054 GBool GFXOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1055 {
1056     msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1057     type3active = 1;
1058     /* the character itself is going to be passed using the draw functions */
1059     return gFalse; /* gTrue= is_in_cache? */
1060 }
1061
1062 void GFXOutputDev::type3D0(GfxState *state, double wx, double wy) {
1063     msg("<debug> type3D0 width=%f height=%f", wx, wy);
1064 }
1065 void GFXOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1066     msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1067             llx,lly,urx,ury);
1068 }
1069
1070 void GFXOutputDev::endType3Char(GfxState *state)
1071 {
1072     type3active = 0;
1073     msg("<debug> endType3Char");
1074 }
1075
1076 void GFXOutputDev::startFrame(int width, int height) 
1077 {
1078     device->startpage(device, width, height);
1079 }
1080
1081 void GFXOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2) 
1082 {
1083     this->currentpage = pageNum;
1084     double x1,y1,x2,y2;
1085     int rot = doc->getPageRotate(1);
1086     gfxcolor_t white;
1087     laststate = state;
1088     gfxline_t clippath[5];
1089
1090     white.r = white.g = white.b = white.a = 255;
1091
1092     /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1093     state->transform(state->getX2(),state->getY2(),&x2,&y2);
1094     Use CropBox, not MediaBox, as page size
1095     */
1096     
1097     /*x1 = crop_x1;
1098     y1 = crop_y1;
1099     x2 = crop_x2;
1100     y2 = crop_y2;*/
1101     state->transform(crop_x1,crop_y1,&x1,&y1); //x1 += user_movex; y1 += user_movey;
1102     state->transform(crop_x2,crop_y2,&x2,&y2); //x2 += user_movex; y2 += user_movey;
1103
1104     if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1105     if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1106
1107
1108     /* apply user clip box */
1109     if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1110         /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1111         /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1112         /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1113         /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1114     }
1115
1116     //msg("<verbose> Bounding box is (%f,%f)-(%f,%f) [shifted by %d/%d]", x1,y1,x2,y2, user_movex, user_movey);
1117     
1118     if(outer_clip_box) {
1119         device->endclip(device);
1120         outer_clip_box = 0;
1121     }
1122
1123     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);
1124     if(rot!=0)
1125         msg("<verbose> page is rotated %d degrees\n", rot);
1126
1127     clippath[0].type = gfx_moveTo;clippath[0].x = x1; clippath[0].y = y1; clippath[0].next = &clippath[1];
1128     clippath[1].type = gfx_lineTo;clippath[1].x = x2; clippath[1].y = y1; clippath[1].next = &clippath[2];
1129     clippath[2].type = gfx_lineTo;clippath[2].x = x2; clippath[2].y = y2; clippath[2].next = &clippath[3];
1130     clippath[3].type = gfx_lineTo;clippath[3].x = x1; clippath[3].y = y2; clippath[3].next = &clippath[4];
1131     clippath[4].type = gfx_lineTo;clippath[4].x = x1; clippath[4].y = y1; clippath[4].next = 0;
1132     device->startclip(device, clippath); outer_clip_box = 1;
1133     device->fill(device, clippath, &white);
1134 }
1135
1136 void GFXOutputDev::drawLink(Link *link, Catalog *catalog) 
1137 {
1138     double x1, y1, x2, y2, w;
1139     gfxline_t points[5];
1140     int x, y;
1141     
1142     msg("<debug> drawlink\n");
1143
1144     link->getRect(&x1, &y1, &x2, &y2);
1145     cvtUserToDev(x1, y1, &x, &y);
1146     points[0].type = gfx_moveTo;
1147     points[0].x = points[4].x = x + user_movex;
1148     points[0].y = points[4].y = y + user_movey;
1149     points[0].next = &points[1];
1150     cvtUserToDev(x2, y1, &x, &y);
1151     points[1].type = gfx_lineTo;
1152     points[1].x = x + user_movex;
1153     points[1].y = y + user_movey;
1154     points[1].next = &points[2];
1155     cvtUserToDev(x2, y2, &x, &y);
1156     points[2].type = gfx_lineTo;
1157     points[2].x = x + user_movex;
1158     points[2].y = y + user_movey;
1159     points[2].next = &points[3];
1160     cvtUserToDev(x1, y2, &x, &y);
1161     points[3].type = gfx_lineTo;
1162     points[3].x = x + user_movex;
1163     points[3].y = y + user_movey;
1164     points[3].next = &points[4];
1165     cvtUserToDev(x1, y1, &x, &y);
1166     points[4].type = gfx_lineTo;
1167     points[4].x = x + user_movex;
1168     points[4].y = y + user_movey;
1169     points[4].next = 0;
1170     
1171     msg("<trace> drawlink %.2f/%.2f %.2f/%.2f %.2f/%.2f %.2f/%.2f\n",
1172             points[0].x, points[0].y,
1173             points[1].x, points[1].y,
1174             points[2].x, points[2].y,
1175             points[3].x, points[3].y); 
1176
1177     LinkAction*action=link->getAction();
1178     char buf[128];
1179     char*s = 0;
1180     char*type = "-?-";
1181     char*named = 0;
1182     int page = -1;
1183     msg("<trace> drawlink action=%d\n", action->getKind());
1184     switch(action->getKind())
1185     {
1186         case actionGoTo: {
1187             type = "GoTo";
1188             LinkGoTo *ha=(LinkGoTo *)link->getAction();
1189             LinkDest *dest=NULL;
1190             if (ha->getDest()==NULL) 
1191                 dest=catalog->findDest(ha->getNamedDest());
1192             else dest=ha->getDest();
1193             if (dest){ 
1194               if (dest->isPageRef()){
1195                 Ref pageref=dest->getPageRef();
1196                 page=catalog->findPage(pageref.num,pageref.gen);
1197               }
1198               else  page=dest->getPageNum();
1199               sprintf(buf, "%d", page);
1200               s = strdup(buf);
1201             }
1202         }
1203         break;
1204         case actionGoToR: {
1205             type = "GoToR";
1206             LinkGoToR*l = (LinkGoToR*)action;
1207             GString*g = l->getNamedDest();
1208             if(g)
1209              s = strdup(g->getCString());
1210         }
1211         break;
1212         case actionNamed: {
1213             type = "Named";
1214             LinkNamed*l = (LinkNamed*)action;
1215             GString*name = l->getName();
1216             if(name) {
1217                 s = strdup(name->lowerCase()->getCString());
1218                 named = name->getCString();
1219                 if(!strchr(s,':')) 
1220                 {
1221                     if(strstr(s, "next") || strstr(s, "forward"))
1222                     {
1223                         page = currentpage + 1;
1224                     }
1225                     else if(strstr(s, "prev") || strstr(s, "back"))
1226                     {
1227                         page = currentpage - 1;
1228                     }
1229                     else if(strstr(s, "last") || strstr(s, "end"))
1230                     {
1231                         if(pages && pagepos>0)
1232                             page = pages[pagepos-1];
1233                     }
1234                     else if(strstr(s, "first") || strstr(s, "top"))
1235                     {
1236                         page = 1;
1237                     }
1238                 }
1239             }
1240         }
1241         break;
1242         case actionLaunch: {
1243             type = "Launch";
1244             LinkLaunch*l = (LinkLaunch*)action;
1245             GString * str = new GString(l->getFileName());
1246             GString * params = l->getParams();
1247             if(params)
1248                 str->append(params);
1249             s = strdup(str->getCString());
1250             delete str;
1251         }
1252         break;
1253         case actionURI: {
1254             char*url = 0;
1255             type = "URI";
1256             LinkURI*l = (LinkURI*)action;
1257             GString*g = l->getURI();
1258             if(g) {
1259              url = g->getCString();
1260              s = strdup(url);
1261             }
1262         }
1263         break;
1264         case actionUnknown: {
1265             type = "Unknown";
1266             LinkUnknown*l = (LinkUnknown*)action;
1267             s = strdup("");
1268         }
1269         break;
1270         default: {
1271             msg("<error> Unknown link type!\n");
1272             break;
1273         }
1274     }
1275
1276     if(!s) s = strdup("-?-");
1277     
1278     msg("<trace> drawlink s=%s\n", s);
1279
1280     if(!linkinfo && (page || s))
1281     {
1282         msg("<notice> File contains links");
1283         linkinfo = 1;
1284     }
1285     
1286     if(page>0)
1287     {
1288         int t;
1289         int lpage = -1;
1290         for(t=1;t<=pagepos;t++) {
1291             if(pages[t]==page) {
1292                 lpage = t;
1293                 break;
1294             }
1295         }
1296         if(lpage<0) {
1297             lpage = page;
1298         }
1299         char buf[80];
1300         sprintf(buf, "page%d", lpage);
1301         device->drawlink(device, points, buf);
1302     }
1303     else if(s)
1304     {
1305         device->drawlink(device, points, s);
1306     }
1307
1308     msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1309     free(s);s=0;
1310 }
1311
1312 void GFXOutputDev::saveState(GfxState *state) {
1313   msg("<trace> saveState\n");
1314   updateAll(state);
1315   if(statepos>=64) {
1316     msg("<error> Too many nested states in pdf.");
1317     return;
1318   }
1319   statepos ++;
1320   states[statepos].clipping = 0; //? shouldn't this be the current value?
1321   states[statepos].textRender = states[statepos-1].textRender;
1322 };
1323
1324 void GFXOutputDev::restoreState(GfxState *state) {
1325   msg("<trace> restoreState\n");
1326   updateAll(state);
1327   while(states[statepos].clipping) {
1328       device->endclip(device);
1329       states[statepos].clipping--;
1330   }
1331   statepos--;
1332 }
1333
1334 char* GFXOutputDev::searchFont(char*name) 
1335 {       
1336     int i;
1337     char*filename=0;
1338     int is_standard_font = 0;
1339         
1340     msg("<verbose> SearchFont(%s)", name);
1341
1342     /* see if it is a pdf standard font */
1343     for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++) 
1344     {
1345         if(!strcmp(name, pdf2t1map[i].pdffont))
1346         {
1347             name = pdf2t1map[i].filename;
1348             is_standard_font = 1;
1349             break;
1350         }
1351     }
1352     /* look in all font files */
1353     for(i=0;i<fontnum;i++) 
1354     {
1355         if(strstr(fonts[i].filename, name))
1356         {
1357             if(!fonts[i].used) {
1358
1359                 fonts[i].used = 1;
1360                 if(!is_standard_font)
1361                     msg("<notice> Using %s for %s", fonts[i].filename, name);
1362             }
1363             return strdup(fonts[i].filename);
1364         }
1365     }
1366     return 0;
1367 }
1368
1369 void GFXOutputDev::updateLineWidth(GfxState *state)
1370 {
1371     double width = state->getTransformedLineWidth();
1372     //swfoutput_setlinewidth(&device, width);
1373 }
1374
1375 void GFXOutputDev::updateLineCap(GfxState *state)
1376 {
1377     int c = state->getLineCap();
1378 }
1379
1380 void GFXOutputDev::updateLineJoin(GfxState *state)
1381 {
1382     int j = state->getLineJoin();
1383 }
1384
1385 void GFXOutputDev::updateFillColor(GfxState *state) 
1386 {
1387     GfxRGB rgb;
1388     double opaq = state->getFillOpacity();
1389     state->getFillRGB(&rgb);
1390
1391     //swfoutput_setfillcolor(&device, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1392 }
1393
1394 void GFXOutputDev::updateStrokeColor(GfxState *state) 
1395 {
1396     GfxRGB rgb;
1397     double opaq = state->getStrokeOpacity();
1398     state->getStrokeRGB(&rgb);
1399     //swfoutput_setstrokecolor(&device, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1400 }
1401
1402 void FoFiWrite(void *stream, char *data, int len)
1403 {
1404    fwrite(data, len, 1, (FILE*)stream);
1405 }
1406
1407 char*GFXOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1408 {
1409     char*tmpFileName = NULL;
1410     FILE *f;
1411     int c;
1412     char *fontBuf;
1413     int fontLen;
1414     Ref embRef;
1415     Object refObj, strObj;
1416     char namebuf[512];
1417     tmpFileName = mktmpname(namebuf);
1418     int ret;
1419
1420     ret = font->getEmbeddedFontID(&embRef);
1421     if(!ret) {
1422         msg("<verbose> Didn't get embedded font id");
1423         /* not embedded- the caller should now search the font
1424            directories for this font */
1425         return 0;
1426     }
1427
1428     f = fopen(tmpFileName, "wb");
1429     if (!f) {
1430       msg("<error> Couldn't create temporary Type 1 font file");
1431         return 0;
1432     }
1433
1434     /*if(font->isCIDFont()) {
1435         GfxCIDFont* cidFont = (GfxCIDFont *)font;
1436         GString c = cidFont->getCollection();
1437         msg("<notice> Collection: %s", c.getCString());
1438     }*/
1439
1440     //if (font->getType() == fontType1C) {
1441     if (0) { //font->getType() == fontType1C) {
1442       if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1443         fclose(f);
1444         msg("<error> Couldn't read embedded font file");
1445         return 0;
1446       }
1447       FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1448       if(!cvt) return 0;
1449       cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1450       //cvt->convertToCIDType0("test", f);
1451       //cvt->convertToType0("test", f);
1452       delete cvt;
1453       gfree(fontBuf);
1454     } else if(font->getType() == fontTrueType) {
1455       msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1456       if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1457         fclose(f);
1458         msg("<error> Couldn't read embedded font file");
1459         return 0;
1460       }
1461       FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1462       cvt->writeTTF(FoFiWrite, f);
1463       delete cvt;
1464       gfree(fontBuf);
1465     } else {
1466       font->getEmbeddedFontID(&embRef);
1467       refObj.initRef(embRef.num, embRef.gen);
1468       refObj.fetch(ref, &strObj);
1469       refObj.free();
1470       strObj.streamReset();
1471       int f4[4];
1472       char f4c[4];
1473       int t;
1474       for(t=0;t<4;t++) {
1475           f4[t] = strObj.streamGetChar();
1476           f4c[t] = (char)f4[t];
1477           if(f4[t] == EOF)
1478               break;
1479       }
1480       if(t==4) {
1481           if(!strncmp(f4c, "true", 4)) {
1482               /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1483                  Change this on the fly */
1484               f4[0] = f4[2] = f4[3] = 0;
1485               f4[1] = 1;
1486           }
1487           fputc(f4[0], f);
1488           fputc(f4[1], f);
1489           fputc(f4[2], f);
1490           fputc(f4[3], f);
1491
1492           while ((c = strObj.streamGetChar()) != EOF) {
1493             fputc(c, f);
1494           }
1495       }
1496       strObj.streamClose();
1497       strObj.free();
1498     }
1499     fclose(f);
1500
1501     return strdup(tmpFileName);
1502 }
1503     
1504 char* GFXOutputDev::searchForSuitableFont(GfxFont*gfxFont)
1505 {
1506     char*name = getFontName(gfxFont);
1507     char*fontname = 0;
1508     char*filename = 0;
1509
1510     if(!this->config_use_fontconfig)
1511         return 0;
1512     
1513 #ifdef HAVE_FONTCONFIG
1514     FcPattern *pattern, *match;
1515     FcResult result;
1516     FcChar8 *v;
1517
1518     static int fcinitcalled = false; 
1519         
1520     msg("<debug> searchForSuitableFont(%s)", name);
1521     
1522     // call init ony once
1523     if (!fcinitcalled) {
1524         msg("<debug> Initializing FontConfig...");
1525         fcinitcalled = true;
1526         if(!FcInit()) {
1527             msg("<debug> FontConfig Initialization failed. Disabling.");
1528             config_use_fontconfig = 0;
1529             return 0;
1530         }
1531         msg("<debug> ...initialized FontConfig");
1532     }
1533    
1534     msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1535     pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1536     if (gfxFont->isItalic()) // check for italic
1537         msg("<debug> FontConfig: Adding Italic Slant");
1538         FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1539     if (gfxFont->isBold()) // check for bold
1540         msg("<debug> FontConfig: Adding Bold Weight");
1541         FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1542
1543     msg("<debug> FontConfig: Try to match...");
1544     // configure and match using the original font name 
1545     FcConfigSubstitute(0, pattern, FcMatchPattern); 
1546     FcDefaultSubstitute(pattern);
1547     match = FcFontMatch(0, pattern, &result);
1548     
1549     if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1550         msg("<debug> FontConfig: family=%s", (char*)v);
1551         // if we get an exact match
1552         if (strcmp((char *)v, name) == 0) {
1553             if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1554                 filename = strdup((char*)v); // mem leak
1555                 char *nfn = strrchr(filename, '/');
1556                 if(nfn) fontname = strdup(nfn+1);
1557                 else    fontname = filename;
1558             }
1559             msg("<debug> FontConfig: Returning \"%s\"", fontname);
1560         } else {
1561             // initialize patterns
1562             FcPatternDestroy(pattern);
1563             FcPatternDestroy(match);
1564
1565             // now match against serif etc.
1566             if (gfxFont->isSerif()) {
1567                 msg("<debug> FontConfig: Create Serif Family Pattern");
1568                 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1569             } else if (gfxFont->isFixedWidth()) {
1570                 msg("<debug> FontConfig: Create Monospace Family Pattern");
1571                 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1572             } else {
1573                 msg("<debug> FontConfig: Create Sans Family Pattern");
1574                 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1575             }
1576
1577             // check for italic
1578             if (gfxFont->isItalic()) {
1579                 msg("<debug> FontConfig: Adding Italic Slant");
1580                 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1581             }
1582             // check for bold
1583             if (gfxFont->isBold()) {
1584                 msg("<debug> FontConfig: Adding Bold Weight");
1585                 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1586             }
1587
1588             msg("<debug> FontConfig: Try to match... (2)");
1589             // configure and match using serif etc
1590             FcConfigSubstitute (0, pattern, FcMatchPattern);
1591             FcDefaultSubstitute (pattern);
1592             match = FcFontMatch (0, pattern, &result);
1593             
1594             if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1595                 filename = strdup((char*)v); // mem leak
1596                 char *nfn = strrchr(filename, '/');
1597                 if(nfn) fontname = strdup(nfn+1);
1598                 else    fontname = filename;
1599             }
1600             msg("<debug> FontConfig: Returning \"%s\"", fontname);
1601         }        
1602     }
1603
1604     //printf("FONTCONFIG: pattern");
1605     //FcPatternPrint(pattern);
1606     //printf("FONTCONFIG: match");
1607     //FcPatternPrint(match);
1608  
1609     FcPatternDestroy(pattern);
1610     FcPatternDestroy(match);
1611
1612     pdfswf_addfont(filename);
1613     return fontname;
1614 #else
1615     return 0;
1616 #endif
1617 }
1618
1619 char* GFXOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1620 {
1621     char*fontname = 0, *filename = 0;
1622     msg("<notice> substituteFont(%s)", oldname);
1623
1624     if(!(fontname = searchForSuitableFont(gfxFont))) {
1625         fontname = "Times-Roman";
1626     }
1627     filename = searchFont(fontname);
1628     if(!filename) {
1629         msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1630         return 0;
1631     }
1632
1633     if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1634         msg("<fatal> Too many fonts in file.");
1635         exit(1);
1636     }
1637     if(oldname) {
1638         substitutesource[substitutepos] = strdup(oldname); //mem leak
1639         substitutetarget[substitutepos] = fontname;
1640         msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1641         substitutepos ++;
1642     }
1643     return strdup(filename); //mem leak
1644 }
1645
1646 void unlinkfont(char* filename)
1647 {
1648     int l;
1649     if(!filename)
1650         return;
1651     l=strlen(filename);
1652     unlink(filename);
1653     if(!strncmp(&filename[l-4],".afm",4)) {
1654         memcpy(&filename[l-4],".pfb",4);
1655         unlink(filename);
1656         memcpy(&filename[l-4],".pfa",4);
1657         unlink(filename);
1658         memcpy(&filename[l-4],".afm",4);
1659         return;
1660     } else 
1661     if(!strncmp(&filename[l-4],".pfa",4)) {
1662         memcpy(&filename[l-4],".afm",4);
1663         unlink(filename);
1664         memcpy(&filename[l-4],".pfa",4);
1665         return;
1666     } else 
1667     if(!strncmp(&filename[l-4],".pfb",4)) {
1668         memcpy(&filename[l-4],".afm",4);
1669         unlink(filename);
1670         memcpy(&filename[l-4],".pfb",4);
1671         return;
1672     }
1673 }
1674
1675 void GFXOutputDev::setXRef(PDFDoc*doc, XRef *xref) 
1676 {
1677     this->doc = doc;
1678     this->xref = xref;
1679 }
1680
1681 int GFXOutputDev::setGfxFont(char*id, char*name, char*filename, double maxSize)
1682 {
1683     gfxfont_t*font = 0;
1684     fontlist_t*last=0,*l = this->fontlist;
1685
1686     /* TODO: should this be part of the state? */
1687     while(l) {
1688         last = l;
1689         if(!strcmp(l->id, id)) {
1690             current_font_id = l->id;
1691             current_gfxfont = l->font;
1692             font = l->font;
1693             device->addfont(device, id, current_gfxfont);
1694             return 1;
1695         }
1696         l = l->next;
1697     }
1698     if(!filename) return 0;
1699
1700     /* A font size of e.g. 9 means the font will be scaled down by
1701        1024 and scaled up by 9. So to have a maximum error of 1/20px,
1702        we have to divide 0.05 by (fontsize/1024)
1703      */
1704     double quality = (1024 * 0.05) / maxSize;
1705    
1706     msg("<verbose> Loading %s...", filename);
1707     font = gfxfont_load(filename, quality);
1708     msg("<verbose> Font %s loaded successfully", filename);
1709
1710     l = new fontlist_t;
1711     l->font = font;
1712     l->filename = strdup(filename);
1713     l->id = strdup(id);
1714     l->next = 0;
1715     current_font_id = l->id;
1716     current_gfxfont = l->font;
1717     if(last) {
1718         last->next = l;
1719     } else {
1720         this->fontlist = l;
1721     }
1722     device->addfont(device, id, 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; y1 += user_movey;
2037   state->transform(0, 0, &x2, &y2); x2 += user_movex; y2 += user_movey;
2038   state->transform(1, 0, &x3, &y3); x3 += user_movex; y3 += user_movey;
2039   state->transform(1, 1, &x4, &y4); x4 += user_movex; y4 += user_movey;
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(states[statepos].textRender & 4) //clipped
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(states[statepos].textRender & 4) //clipped
2223       return;
2224
2225   msg("<verbose> drawImage %dx%d, %s, %s, inline=%d", width, height, 
2226           colorMap?"colorMap":"no colorMap", 
2227           maskColors?"maskColors":"no maskColors",
2228           inlineImg);
2229   if(colorMap)
2230       msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2231               colorMap->getBits(),colorMap->getColorSpace()->getMode());
2232   drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors, 0,0,0,0, 0);
2233 }
2234   
2235 void GFXOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
2236                                int width, int height,
2237                                GfxImageColorMap *colorMap,
2238                                Stream *maskStr, int maskWidth, int maskHeight,
2239                                GBool maskInvert)
2240 {
2241   if(states[statepos].textRender & 4) //clipped
2242       return;
2243
2244   msg("<verbose> drawMaskedImage %dx%d, %s, %dx%d mask", width, height, 
2245           colorMap?"colorMap":"no colorMap", 
2246           maskWidth, maskHeight);
2247   if(colorMap)
2248       msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2249               colorMap->getBits(),colorMap->getColorSpace()->getMode());
2250   drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, maskInvert, 0);
2251 }
2252
2253 void GFXOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
2254                                    int width, int height,
2255                                    GfxImageColorMap *colorMap,
2256                                    Stream *maskStr,
2257                                    int maskWidth, int maskHeight,
2258                                    GfxImageColorMap *maskColorMap)
2259 {
2260   if(states[statepos].textRender & 4) //clipped
2261       return;
2262
2263   msg("<verbose> drawSoftMaskedImage %dx%d, %s, %dx%d mask", width, height, 
2264           colorMap?"colorMap":"no colorMap", 
2265           maskWidth, maskHeight);
2266   if(colorMap)
2267       msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2268               colorMap->getBits(),colorMap->getColorSpace()->getMode());
2269   drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, 0, maskColorMap);
2270 }
2271
2272 static char* dirseparator()
2273 {
2274 #ifdef WIN32
2275     return "\\";
2276 #else
2277     return "/";
2278 #endif
2279 }
2280
2281 void addGlobalFont(char*filename)
2282 {
2283     fontfile_t f;
2284     memset(&f, 0, sizeof(fontfile_t));
2285     f.filename = filename;
2286     if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2287         msg("<verbose> Adding font \"%s\".", filename);
2288         fonts[fontnum++] = f;
2289     } else {
2290         msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2291     }
2292 }
2293
2294 void addGlobalLanguageDir(char*dir)
2295 {
2296     if(!globalParams)
2297         globalParams = new GlobalParams("");
2298     
2299     msg("<notice> Adding %s to language pack directories", dir);
2300
2301     int l;
2302     FILE*fi = 0;
2303     char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc") + 1);
2304     strcpy(config_file, dir);
2305     strcat(config_file, dirseparator());
2306     strcat(config_file, "add-to-xpdfrc");
2307
2308     fi = fopen(config_file, "rb");
2309     if(!fi) {
2310         msg("<error> Could not open %s", config_file);
2311         return;
2312     }
2313     globalParams->parseFile(new GString(config_file), fi);
2314     fclose(fi);
2315 }
2316
2317 void addGlobalFontDir(char*dirname)
2318 {
2319 #ifdef HAVE_DIRENT_H
2320     msg("<notice> Adding %s to font directories", dirname);
2321     lastfontdir = strdup(dirname);
2322     DIR*dir = opendir(dirname);
2323     if(!dir) {
2324         msg("<warning> Couldn't open directory %s\n", dirname);
2325         return;
2326     }
2327     struct dirent*ent;
2328     while(1) {
2329         ent = readdir (dir);
2330         if (!ent) 
2331             break;
2332         int l;
2333         char*name = ent->d_name;
2334         char type = 0;
2335         if(!name) continue;
2336         l=strlen(name);
2337         if(l<4)
2338             continue;
2339         if(!strncasecmp(&name[l-4], ".pfa", 4)) 
2340             type=1;
2341         if(!strncasecmp(&name[l-4], ".pfb", 4)) 
2342             type=3;
2343         if(!strncasecmp(&name[l-4], ".ttf", 4)) 
2344             type=2;
2345         if(type)
2346         {
2347             char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2348             strcpy(fontname, dirname);
2349             strcat(fontname, dirseparator());
2350             strcat(fontname, name);
2351             addGlobalFont(fontname);
2352         }
2353     }
2354     closedir(dir);
2355 #else
2356     msg("<warning> No dirent.h- unable to add font dir %s", dir);
2357 #endif
2358 }
2359
2360 void GFXOutputDev::preparePage(int pdfpage, int outputpage)
2361 {
2362     if(pdfpage < 0)
2363         return;
2364
2365     if(!this->pages) {
2366         this->pagebuflen = 1024;
2367         this->pages = (int*)malloc(this->pagebuflen*sizeof(int));
2368         memset(this->pages, -1, this->pagebuflen*sizeof(int));
2369     } else {
2370         while(pdfpage >= this->pagebuflen)
2371         {
2372             int oldlen = this->pagebuflen;
2373             this->pagebuflen+=1024;
2374             this->pages = (int*)realloc(this->pages, this->pagebuflen*sizeof(int));
2375             memset(&this->pages[oldlen], -1, (this->pagebuflen-oldlen)*sizeof(int));
2376         }
2377     }
2378     this->pages[pdfpage] = outputpage;
2379     if(pdfpage>this->pagepos)
2380         this->pagepos = pdfpage;
2381 }
2382
2383 /*class MemCheck
2384 {
2385     public: ~MemCheck()
2386     {
2387         delete globalParams;globalParams=0;
2388         Object::memCheck(stderr);
2389         gMemReport(stderr);
2390     }
2391 } myMemCheck;*/
2392