* draw images behind clipped text again
[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     if(!font) {
1721         msg("<verbose> Couldn't load Font %s (%s)", filename, id);
1722         return 0;
1723     }
1724     msg("<verbose> Font %s (%s) loaded successfully", filename, id);
1725
1726     l = new fontlist_t;
1727     l->font = font;
1728     l->filename = strdup(filename);
1729     l->next = 0;
1730     current_gfxfont = l->font;
1731     if(last) {
1732         last->next = l;
1733     } else {
1734         this->fontlist = l;
1735     }
1736     device->addfont(device, current_gfxfont);
1737     return 1;
1738 }
1739
1740 void GFXOutputDev::updateFont(GfxState *state) 
1741 {
1742     GfxFont*gfxFont = state->getFont();
1743       
1744     if (!gfxFont) {
1745         return;
1746     }  
1747     
1748     char * fontid = getFontID(gfxFont);
1749     char * fontname = getFontName(gfxFont);
1750
1751     double maxSize = 1.0;
1752
1753     if(this->info) {
1754         maxSize = this->info->getMaximumFontSize(fontid);
1755     }
1756     
1757     int t;
1758     /* first, look if we substituted this font before-
1759        this way, we don't initialize the T1 Fonts
1760        too often */
1761     for(t=0;t<substitutepos;t++) {
1762         if(!strcmp(fontid, substitutesource[t])) {
1763             free(fontid);fontid=0;
1764             fontid = strdup(substitutetarget[t]);
1765             break;
1766         }
1767     }
1768
1769     /* second, see if this is a font which was used before-
1770        if so, we are done */
1771     if(setGfxFont(fontid, fontname, 0, 0)) {
1772         free(fontid);
1773         free(fontname);
1774         return;
1775     }
1776 /*    if(swfoutput_queryfont(&device, fontid))
1777         swfoutput_setfont(&device, fontid, 0);
1778         
1779         msg("<debug> updateFont(%s) [cached]", fontid);
1780         return;
1781     }*/
1782
1783     // look for Type 3 font
1784     if (gfxFont->getType() == fontType3) {
1785         if(!type3Warning) {
1786             type3Warning = gTrue;
1787             showFontError(gfxFont, 2);
1788         }
1789         free(fontid);
1790         free(fontname);
1791         return;
1792     }
1793
1794     /* now either load the font, or find a substitution */
1795
1796     Ref embRef;
1797     GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
1798
1799     char*fileName = 0;
1800     int del = 0;
1801     if(embedded &&
1802        (gfxFont->getType() == fontType1 ||
1803         gfxFont->getType() == fontType1C ||
1804        (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
1805         gfxFont->getType() == fontTrueType ||
1806         gfxFont->getType() == fontCIDType2
1807        ))
1808     {
1809       fileName = writeEmbeddedFontToFile(xref, gfxFont);
1810       if(!fileName) showFontError(gfxFont,0);
1811       else del = 1;
1812     } else {
1813       fileName = searchFont(fontname);
1814       if(!fileName) showFontError(gfxFont,0);
1815     }
1816     if(!fileName) {
1817         char * fontname = getFontName(gfxFont);
1818         msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
1819         
1820         if(lastfontdir)
1821             msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into %s", fontname, lastfontdir);
1822         else
1823             msg("<warning> Try specifying one or more font directories");
1824
1825         fileName = substituteFont(gfxFont, fontid);
1826         if(!fileName)
1827             exit(1);
1828         if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
1829         msg("<notice> Font is now %s (%s)", fontid, fileName);
1830     }
1831
1832     if(!fileName) {
1833         msg("<error> Couldn't set font %s\n", fontid);
1834         free(fontid);
1835         free(fontname);
1836         return;
1837     }
1838         
1839     msg("<verbose> updateFont(%s) -> %s (max size: %f)", fontid, fileName, maxSize);
1840     dumpFontInfo("<verbose>", gfxFont);
1841
1842     //swfoutput_setfont(&device, fontid, fileName);
1843     
1844     if(!setGfxFont(fontid, fontname, 0, 0)) {
1845         setGfxFont(fontid, fontname, fileName, maxSize);
1846     }
1847    
1848     if(fileName && del)
1849         unlinkfont(fileName);
1850
1851     if(fileName)
1852         free(fileName);
1853     free(fontid);
1854     free(fontname);
1855
1856     msg("<verbose> |");
1857 }
1858
1859 #define SQR(x) ((x)*(x))
1860
1861 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
1862 {
1863     if((newwidth<2 || newheight<2) ||
1864        (width<=newwidth || height<=newheight))
1865         return 0;
1866     unsigned char*newdata;
1867     int x,y;
1868     newdata= (unsigned char*)malloc(newwidth*newheight);
1869     int t;
1870     double fx = (double)(width)/newwidth;
1871     double fy = (double)(height)/newheight;
1872     double px = 0;
1873     int blocksize = (int)(8192/(fx*fy));
1874     int r = 8192*256/palettesize;
1875     for(x=0;x<newwidth;x++) {
1876         double ex = px + fx;
1877         int fromx = (int)px;
1878         int tox = (int)ex;
1879         int xweight1 = (int)(((fromx+1)-px)*256);
1880         int xweight2 = (int)((ex-tox)*256);
1881         double py =0;
1882         for(y=0;y<newheight;y++) {
1883             double ey = py + fy;
1884             int fromy = (int)py;
1885             int toy = (int)ey;
1886             int yweight1 = (int)(((fromy+1)-py)*256);
1887             int yweight2 = (int)((ey-toy)*256);
1888             int a = 0;
1889             int xx,yy;
1890             for(xx=fromx;xx<=tox;xx++)
1891             for(yy=fromy;yy<=toy;yy++) {
1892                 int b = 1-data[width*yy+xx];
1893                 int weight=256;
1894                 if(xx==fromx) weight = (weight*xweight1)/256;
1895                 if(xx==tox) weight = (weight*xweight2)/256;
1896                 if(yy==fromy) weight = (weight*yweight1)/256;
1897                 if(yy==toy) weight = (weight*yweight2)/256;
1898                 a+=b*weight;
1899             }
1900             //if(a) a=(palettesize-1)*r/blocksize;
1901             newdata[y*newwidth+x] = (a*blocksize)/r;
1902             py = ey;
1903         }
1904         px = ex;
1905     }
1906     return newdata;
1907 }
1908
1909 #define IMAGE_TYPE_JPEG 0
1910 #define IMAGE_TYPE_LOSSLESS 1
1911
1912 static void drawimage(gfxdevice_t*dev, gfxcolor_t* data, int sizex,int sizey, 
1913         double x1,double y1,
1914         double x2,double y2,
1915         double x3,double y3,
1916         double x4,double y4, int type)
1917 {
1918     gfxcolor_t*newpic=0;
1919     
1920     double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
1921     double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
1922    
1923     gfxline_t p1,p2,p3,p4,p5;
1924     p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
1925     p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
1926     p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
1927     p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
1928     p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
1929
1930     {p1.x = (int)(p1.x*20)/20.0;
1931      p1.y = (int)(p1.y*20)/20.0;
1932      p2.x = (int)(p2.x*20)/20.0;
1933      p2.y = (int)(p2.y*20)/20.0;
1934      p3.x = (int)(p3.x*20)/20.0;
1935      p3.y = (int)(p3.y*20)/20.0;
1936      p4.x = (int)(p4.x*20)/20.0;
1937      p4.y = (int)(p4.y*20)/20.0;
1938      p5.x = (int)(p5.x*20)/20.0;
1939      p5.y = (int)(p5.y*20)/20.0;
1940     }
1941     
1942     float m00,m10,tx;
1943     float m01,m11,ty;
1944     
1945     gfxmatrix_t m;
1946     m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
1947     m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
1948     m.tx = p1.x - 0.5;
1949     m.ty = p1.y - 0.5;
1950
1951     gfximage_t img;
1952     img.data = (gfxcolor_t*)data;
1953     img.width = sizex;
1954     img.height = sizey;
1955   
1956     if(type == IMAGE_TYPE_JPEG)
1957         /* TODO: pass image_dpi to device instead */
1958         dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
1959
1960     dev->fillbitmap(dev, &p1, &img, &m, 0);
1961 }
1962
1963 void drawimagejpeg(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey, 
1964         double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
1965 {
1966     drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
1967 }
1968
1969 void drawimagelossless(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey, 
1970         double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
1971 {
1972     drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
1973 }
1974
1975
1976 void GFXOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
1977                                    int width, int height, GfxImageColorMap*colorMap, GBool invert,
1978                                    GBool inlineImg, int mask, int*maskColors,
1979                                    Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert, GfxImageColorMap*maskColorMap)
1980 {
1981   double x1,y1,x2,y2,x3,y3,x4,y4;
1982   ImageStream *imgStr;
1983   Guchar pixBuf[4];
1984   GfxRGB rgb;
1985   int ncomps = 1;
1986   int bits = 1;
1987   unsigned char* maskbitmap = 0;
1988                                  
1989   if(colorMap) {
1990     ncomps = colorMap->getNumPixelComps();
1991     bits = colorMap->getBits();
1992   }
1993       
1994   if(maskStr) {
1995       int x,y;
1996       unsigned char buf[8];
1997       maskbitmap = (unsigned char*)malloc(maskHeight*maskWidth);
1998       if(maskColorMap) {
1999           ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, maskColorMap->getNumPixelComps(), maskColorMap->getBits());
2000           imgMaskStr->reset();
2001           unsigned char pal[256];
2002           int n = 1 << colorMap->getBits();
2003           int t;
2004           for(t=0;t<n;t++) {
2005               GfxGray gray;
2006               pixBuf[0] = t;
2007               maskColorMap->getGray(pixBuf, &gray);
2008               pal[t] = colToByte(gray);
2009           }
2010           for (y = 0; y < maskHeight; y++) {
2011               for (x = 0; x < maskWidth; x++) {
2012                   imgMaskStr->getPixel(buf);
2013                   maskbitmap[y*maskWidth+x] = pal[buf[0]];
2014               }
2015           }
2016           delete imgMaskStr;
2017       } else {
2018           ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, 1, 1);
2019           imgMaskStr->reset();
2020           for (y = 0; y < maskHeight; y++) {
2021               for (x = 0; x < maskWidth; x++) {
2022                   imgMaskStr->getPixel(buf);
2023                   buf[0]^=maskInvert;
2024                   maskbitmap[y*maskWidth+x] = (buf[0]^1)*255;
2025               }
2026           }
2027           delete imgMaskStr;
2028       }
2029       maskStr->close();
2030   }
2031   
2032   imgStr = new ImageStream(str, width, ncomps,bits);
2033   imgStr->reset();
2034
2035   if(!width || !height || (height<=1 && width<=1))
2036   {
2037       msg("<verbose> Ignoring %d by %d image", width, height);
2038       unsigned char buf[8];
2039       int x,y;
2040       for (y = 0; y < height; ++y)
2041       for (x = 0; x < width; ++x) {
2042           imgStr->getPixel(buf);
2043       }
2044       delete imgStr;
2045       if(maskbitmap)
2046           free(maskbitmap);
2047       return;
2048   }
2049
2050   state->transform(0, 1, &x1, &y1); x1 += user_movex; y1 += user_movey;
2051   state->transform(0, 0, &x2, &y2); x2 += user_movex; y2 += user_movey;
2052   state->transform(1, 0, &x3, &y3); x3 += user_movex; y3 += user_movey;
2053   state->transform(1, 1, &x4, &y4); x4 += user_movex; y4 += user_movey;
2054
2055
2056   if(!pbminfo && !(str->getKind()==strDCT)) {
2057       if(!type3active) {
2058           msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2059           pbminfo = 1;
2060       }
2061       if(mask)
2062       msg("<verbose> drawing %d by %d masked picture\n", width, height);
2063   }
2064   if(!jpeginfo && (str->getKind()==strDCT)) {
2065       msg("<notice> file contains jpeg pictures");
2066       jpeginfo = 1;
2067   }
2068
2069   if(mask) {
2070       int i,j;
2071       unsigned char buf[8];
2072       int x,y;
2073       unsigned char*pic = new unsigned char[width*height];
2074       gfxcolor_t pal[256];
2075       GfxRGB rgb;
2076       state->getFillRGB(&rgb);
2077
2078       memset(pal,255,sizeof(pal));
2079       pal[0].r = (int)(colToByte(rgb.r)); pal[1].r = 0;
2080       pal[0].g = (int)(colToByte(rgb.g)); pal[1].g = 0;
2081       pal[0].b = (int)(colToByte(rgb.b)); pal[1].b = 0;
2082       pal[0].a = 255;              pal[1].a = 0;
2083     
2084       int numpalette = 2;
2085       int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2086       int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2087       for (y = 0; y < height; ++y)
2088       for (x = 0; x < width; ++x)
2089       {
2090             imgStr->getPixel(buf);
2091             if(invert) 
2092                 buf[0]=1-buf[0];
2093             pic[width*y+x] = buf[0];
2094       }
2095       
2096       /* the size of the drawn image is added to the identifier
2097          as the same image may require different bitmaps if displayed
2098          at different sizes (due to antialiasing): */
2099       int t,found = -1;
2100       if(type3active) {
2101           unsigned char*pic2 = 0;
2102           numpalette = 16;
2103           
2104           pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2105
2106           if(!pic2) {
2107             delete pic;
2108             delete imgStr;
2109             return;
2110           }
2111
2112           width = realwidth;
2113           height = realheight;
2114           free(pic);
2115           pic = pic2;
2116           
2117           /* make a black/white palette */
2118
2119           float r = 255/(numpalette-1);
2120           int t;
2121           for(t=0;t<numpalette;t++) {
2122               pal[t].r = colToByte(rgb.r);
2123               pal[t].g = colToByte(rgb.g);
2124               pal[t].b = colToByte(rgb.b);
2125               pal[t].a = (unsigned char)(t*r);
2126           }
2127       }
2128
2129       gfxcolor_t*pic2 = new gfxcolor_t[width*height];
2130       for (y = 0; y < height; ++y) {
2131         for (x = 0; x < width; ++x) {
2132           pic2[width*y+x] = pal[pic[y*width+x]];
2133         }
2134       }
2135       drawimagelossless(device, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2136       free(pic2);
2137       free(pic);
2138       delete imgStr;
2139       if(maskbitmap) free(maskbitmap);
2140       return;
2141   }
2142
2143   int x,y;
2144
2145   if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2146       gfxcolor_t*pic=new gfxcolor_t[width*height];
2147       for (y = 0; y < height; ++y) {
2148         for (x = 0; x < width; ++x) {
2149           imgStr->getPixel(pixBuf);
2150           colorMap->getRGB(pixBuf, &rgb);
2151           pic[width*y+x].r = (unsigned char)(colToByte(rgb.r));
2152           pic[width*y+x].g = (unsigned char)(colToByte(rgb.g));
2153           pic[width*y+x].b = (unsigned char)(colToByte(rgb.b));
2154           pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2155           if(maskbitmap) {
2156               pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2157           }
2158         }
2159       }
2160       if(str->getKind()==strDCT)
2161           drawimagejpeg(device, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2162       else
2163           drawimagelossless(device, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2164       delete pic;
2165       delete imgStr;
2166       if(maskbitmap) free(maskbitmap);
2167       return;
2168   } else {
2169       gfxcolor_t*pic=new gfxcolor_t[width*height];
2170       gfxcolor_t pal[256];
2171       int n = 1 << colorMap->getBits();
2172       int t;
2173       for(t=0;t<256;t++) {
2174           pixBuf[0] = t;
2175           colorMap->getRGB(pixBuf, &rgb);
2176
2177           {/*if(maskColors && *maskColors==t) {
2178               msg("<notice> Color %d is transparent", t);
2179               if (imgData->maskColors) {
2180                 *alpha = 0;
2181                 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2182                   if (pix[i] < imgData->maskColors[2*i] ||
2183                       pix[i] > imgData->maskColors[2*i+1]) {
2184                     *alpha = 1;
2185                     break;
2186                   }
2187                 }
2188               } else {
2189                 *alpha = 1;
2190               }
2191               if(!*alpha) {
2192                     pal[t].r = 0;
2193                     pal[t].g = 0;
2194                     pal[t].b = 0;
2195                     pal[t].a = 0;
2196               }
2197           } else {*/
2198               pal[t].r = (unsigned char)(colToByte(rgb.r));
2199               pal[t].g = (unsigned char)(colToByte(rgb.g));
2200               pal[t].b = (unsigned char)(colToByte(rgb.b));
2201               pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2202           }
2203       }
2204       for (y = 0; y < height; ++y) {
2205         for (x = 0; x < width; ++x) {
2206           imgStr->getPixel(pixBuf);
2207           pic[width*y+x] = pal[pixBuf[0]];
2208           if(maskbitmap) {
2209               pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2210           }
2211         }
2212       }
2213       drawimagelossless(device, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2214
2215       delete pic;
2216       delete imgStr;
2217       if(maskbitmap) free(maskbitmap);
2218       return;
2219   }
2220 }
2221
2222 void GFXOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2223                                    int width, int height, GBool invert,
2224                                    GBool inlineImg) 
2225 {
2226   msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2227   drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0, 0,0,0,0, 0);
2228 }
2229
2230 void GFXOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2231                          int width, int height, GfxImageColorMap *colorMap,
2232                          int *maskColors, GBool inlineImg)
2233 {
2234   msg("<verbose> drawImage %dx%d, %s, %s, inline=%d", width, height, 
2235           colorMap?"colorMap":"no colorMap", 
2236           maskColors?"maskColors":"no maskColors",
2237           inlineImg);
2238   if(colorMap)
2239       msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2240               colorMap->getBits(),colorMap->getColorSpace()->getMode());
2241   drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors, 0,0,0,0, 0);
2242 }
2243   
2244 void GFXOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
2245                                int width, int height,
2246                                GfxImageColorMap *colorMap,
2247                                Stream *maskStr, int maskWidth, int maskHeight,
2248                                GBool maskInvert)
2249 {
2250   msg("<verbose> drawMaskedImage %dx%d, %s, %dx%d mask", width, height, 
2251           colorMap?"colorMap":"no colorMap", 
2252           maskWidth, maskHeight);
2253   if(colorMap)
2254       msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2255               colorMap->getBits(),colorMap->getColorSpace()->getMode());
2256   drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, maskInvert, 0);
2257 }
2258
2259 void GFXOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
2260                                    int width, int height,
2261                                    GfxImageColorMap *colorMap,
2262                                    Stream *maskStr,
2263                                    int maskWidth, int maskHeight,
2264                                    GfxImageColorMap *maskColorMap)
2265 {
2266   msg("<verbose> drawSoftMaskedImage %dx%d, %s, %dx%d mask", width, height, 
2267           colorMap?"colorMap":"no colorMap", 
2268           maskWidth, maskHeight);
2269   if(colorMap)
2270       msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2271               colorMap->getBits(),colorMap->getColorSpace()->getMode());
2272   drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, 0, maskColorMap);
2273 }
2274
2275 static char* dirseparator()
2276 {
2277 #ifdef WIN32
2278     return "\\";
2279 #else
2280     return "/";
2281 #endif
2282 }
2283
2284 void addGlobalFont(char*filename)
2285 {
2286     fontfile_t f;
2287     memset(&f, 0, sizeof(fontfile_t));
2288     f.filename = filename;
2289     if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2290         msg("<verbose> Adding font \"%s\".", filename);
2291         fonts[fontnum++] = f;
2292     } else {
2293         msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2294     }
2295 }
2296
2297 void addGlobalLanguageDir(char*dir)
2298 {
2299     if(!globalParams)
2300         globalParams = new GlobalParams("");
2301     
2302     msg("<notice> Adding %s to language pack directories", dir);
2303
2304     int l;
2305     FILE*fi = 0;
2306     char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc") + 1);
2307     strcpy(config_file, dir);
2308     strcat(config_file, dirseparator());
2309     strcat(config_file, "add-to-xpdfrc");
2310
2311     fi = fopen(config_file, "rb");
2312     if(!fi) {
2313         msg("<error> Could not open %s", config_file);
2314         return;
2315     }
2316     globalParams->parseFile(new GString(config_file), fi);
2317     fclose(fi);
2318 }
2319
2320 void addGlobalFontDir(char*dirname)
2321 {
2322 #ifdef HAVE_DIRENT_H
2323     msg("<notice> Adding %s to font directories", dirname);
2324     lastfontdir = strdup(dirname);
2325     DIR*dir = opendir(dirname);
2326     if(!dir) {
2327         msg("<warning> Couldn't open directory %s\n", dirname);
2328         return;
2329     }
2330     struct dirent*ent;
2331     while(1) {
2332         ent = readdir (dir);
2333         if (!ent) 
2334             break;
2335         int l;
2336         char*name = ent->d_name;
2337         char type = 0;
2338         if(!name) continue;
2339         l=strlen(name);
2340         if(l<4)
2341             continue;
2342         if(!strncasecmp(&name[l-4], ".pfa", 4)) 
2343             type=1;
2344         if(!strncasecmp(&name[l-4], ".pfb", 4)) 
2345             type=3;
2346         if(!strncasecmp(&name[l-4], ".ttf", 4)) 
2347             type=2;
2348         if(type)
2349         {
2350             char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2351             strcpy(fontname, dirname);
2352             strcat(fontname, dirseparator());
2353             strcat(fontname, name);
2354             addGlobalFont(fontname);
2355         }
2356     }
2357     closedir(dir);
2358 #else
2359     msg("<warning> No dirent.h- unable to add font dir %s", dir);
2360 #endif
2361 }
2362
2363 void GFXOutputDev::preparePage(int pdfpage, int outputpage)
2364 {
2365     if(pdfpage < 0)
2366         return;
2367
2368     if(!this->pages) {
2369         this->pagebuflen = 1024;
2370         this->pages = (int*)malloc(this->pagebuflen*sizeof(int));
2371         memset(this->pages, -1, this->pagebuflen*sizeof(int));
2372     } else {
2373         while(pdfpage >= this->pagebuflen)
2374         {
2375             int oldlen = this->pagebuflen;
2376             this->pagebuflen+=1024;
2377             this->pages = (int*)realloc(this->pages, this->pagebuflen*sizeof(int));
2378             memset(&this->pages[oldlen], -1, (this->pagebuflen-oldlen)*sizeof(int));
2379         }
2380     }
2381     this->pages[pdfpage] = outputpage;
2382     if(pdfpage>this->pagepos)
2383         this->pagepos = pdfpage;
2384 }
2385
2386 /*class MemCheck
2387 {
2388     public: ~MemCheck()
2389     {
2390         delete globalParams;globalParams=0;
2391         Object::memCheck(stderr);
2392         gMemReport(stderr);
2393     }
2394 } myMemCheck;*/
2395