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