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