fixed staircase issue with poly2bitmap
[swftools.git] / lib / pdf / BitmapOutputDev.cc
1 /* InfoOutputDev.h
2
3    Output Device which creates a bitmap.
4
5    Swftools is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    Swftools is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with swftools; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <memory.h>
22 #include <assert.h>
23 #include "config.h"
24 #include "BitmapOutputDev.h"
25 #include "GFXOutputDev.h"
26 #include "SplashBitmap.h"
27 #include "SplashPattern.h"
28 #include "Splash.h"
29 #include "../log.h"
30 #include "../png.h"
31 #include "../devices/record.h"
32 #include "../types.h"
33 #include "bbox.h"
34
35 #define UNKNOWN_BOUNDING_BOX 0,0,0,0
36
37 static SplashColor splash_white = {255,255,255};
38 static SplashColor splash_black = {0,0,0};
39     
40 ClipState::ClipState()
41 {
42     this->next = 0;
43     this->clipbitmap = 0;
44     this->written = 0;
45 }
46
47 BitmapOutputDev::BitmapOutputDev(InfoOutputDev*info, PDFDoc*doc)
48 {
49     this->info = info;
50     this->doc = doc;
51     this->xref = doc->getXRef();
52     
53     /* color graphic output device, for creating bitmaps */
54     this->rgbdev = new SplashOutputDev(splashModeRGB8, 1, gFalse, splash_white, gTrue, gTrue);
55   
56     /* color mode for binary bitmaps */
57     SplashColorMode colorMode = splashModeMono1;
58
59     /* two devices for testing things against clipping: one clips, the other doesn't */
60     this->clip0dev = new SplashOutputDev(colorMode, 1, gFalse, splash_black, gTrue, gFalse);
61     this->clip1dev = new SplashOutputDev(colorMode, 1, gFalse, splash_black, gTrue, gFalse);
62     
63     /* device indicating where polygonal pixels were drawn */
64     this->boolpolydev = new SplashOutputDev(colorMode, 1, gFalse, splash_black, gTrue, gFalse);
65     /* device indicating where text pixels were drawn */
66     this->booltextdev = new SplashOutputDev(colorMode, 1, gFalse, splash_black, gTrue, gFalse);
67
68     /* device for handling texts and links */
69     this->gfxdev = new GFXOutputDev(info, this->doc);
70
71     this->rgbdev->startDoc(this->xref);
72     this->boolpolydev->startDoc(this->xref);
73     this->booltextdev->startDoc(this->xref);
74     this->clip0dev->startDoc(this->xref);
75     this->clip1dev->startDoc(this->xref);
76
77     this->gfxoutput = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
78     gfxdevice_record_init(this->gfxoutput);
79
80     this->gfxdev->setDevice(this->gfxoutput);
81     
82     this->config_extrafontdata = 0;
83     this->bboxpath = 0;
84     //this->clipdev = 0;
85     //this->clipstates = 0;
86 }
87 BitmapOutputDev::~BitmapOutputDev()
88 {
89     if(this->gfxoutput) {
90         gfxresult_t*r = this->gfxoutput->finish(this->gfxoutput);
91         r->destroy(r);
92         free(this->gfxoutput);this->gfxoutput = 0;
93     }
94     if(this->bboxpath) {
95         delete this->bboxpath;this->bboxpath = 0;
96     }
97     if(this->rgbdev) {
98         delete this->rgbdev;this->rgbdev = 0;
99     }
100     if(this->gfxdev) {
101         delete this->gfxdev;this->gfxdev= 0;
102     }
103     if(this->boolpolydev) {
104         delete this->boolpolydev;this->boolpolydev = 0;
105     }
106     if(this->booltextdev) {
107         delete this->booltextdev;this->booltextdev = 0;
108     }
109     if(this->clip0dev) {
110         delete this->clip0dev;this->clip0dev = 0;
111     }
112     if(this->clip1dev) {
113         delete this->clip1dev;this->clip1dev = 0;
114     }
115     //if(this->clipbitmap) {
116     //    delete this->clipbitmap;this->clipbitmap = 0;
117     //}
118     //if(this->clipdev) {
119     //    delete this->clipdev;this->clipdev = 0;
120     //}
121
122 }
123
124 GBool BitmapOutputDev::getVectorAntialias()
125 {
126     return this->rgbdev->getVectorAntialias();
127 }
128 void BitmapOutputDev::setVectorAntialias(GBool vaa)
129 {
130     this->rgbdev->setVectorAntialias(vaa);
131 }
132 void BitmapOutputDev::setDevice(gfxdevice_t*dev)
133 {
134     this->dev = dev;
135 }
136 void BitmapOutputDev::setMove(int x,int y)
137 {
138     this->gfxdev->setMove(x,y);
139     this->user_movex = x;
140     this->user_movey = y;
141 }
142 void BitmapOutputDev::setClip(int x1,int y1,int x2,int y2)
143 {
144     this->gfxdev->setClip(x1,y1,x2,y2);
145     this->user_clipx1 = x1;
146     this->user_clipy1 = y1;
147     this->user_clipx2 = x2;
148     this->user_clipy2 = y2;
149 }
150 void BitmapOutputDev::setParameter(const char*key, const char*value)
151 {
152     if(!strcmp(key, "extrafontdata")) {
153         this->config_extrafontdata = atoi(value);
154     }
155     this->gfxdev->setParameter(key, value);
156 }
157 void BitmapOutputDev::setPageMap(int*page2page, int num_pages)
158 {
159     this->gfxdev->setPageMap(page2page, num_pages);
160 }
161
162 void writeBitmap(SplashBitmap*bitmap, char*filename);
163
164 void BitmapOutputDev::flushBitmap()
165 {
166     int width = rgbdev->getBitmapWidth();
167     int height = rgbdev->getBitmapHeight();
168
169     if(sizeof(SplashColor)!=3) {
170         msg("<error> sizeof(SplashColor)!=3");
171         return;
172     }
173
174     /*static int counter=0;
175     if(!counter) {
176         writeBitmap(rgbdev->getBitmap(), "test.png");
177     } counter++;*/
178     
179     SplashColorPtr rgb = rgbbitmap->getDataPtr();
180     Guchar*alpha = rgbbitmap->getAlphaPtr();
181     
182     Guchar*alpha2 = boolpolybitmap->getDataPtr();
183     int width8 = (boolpolybitmap->getWidth()+7)/8;
184
185     ibbox_t* boxes = get_bitmap_bboxes((unsigned char*)alpha, width, height);
186     ibbox_t*b;
187
188
189     for(b=boxes;b;b=b->next) {
190         int xmin = b->xmin;
191         int ymin = b->ymin;
192         int xmax = b->xmax;
193         int ymax = b->ymax;
194
195         /* clip against (-movex, -movey, -movex+width, -movey+height) */
196         if(xmin < -this->movex) xmin = -this->movex;
197         if(ymin < -this->movey) ymin = -this->movey;
198         if(xmax > -this->movex + width) xmax = -this->movex+this->width;
199         if(ymax > -this->movey + height) ymax = -this->movey+this->height;
200
201         msg("<verbose> Flushing bitmap (bbox: %d,%d,%d,%d)", xmin,ymin,xmax,ymax);
202         
203         if((xmax-xmin)<=0 || (ymax-ymin)<=0) // no bitmap, nothing to do
204             continue;
205
206         int rangex = xmax-xmin;
207         int rangey = ymax-ymin;
208         gfximage_t*img = (gfximage_t*)malloc(sizeof(gfximage_t)); 
209         img->data = (gfxcolor_t*)malloc(rangex * rangey * 4);
210         img->width = rangex;
211         img->height = rangey;
212         int x,y;
213         for(y=0;y<rangey;y++) {
214             SplashColorPtr in=&rgb[((y+ymin)*width+xmin)*sizeof(SplashColor)];
215             gfxcolor_t*out = &img->data[y*rangex];
216             Guchar*ain = &alpha[(y+ymin)*width+xmin];
217             Guchar*ain2 = &alpha2[(y+ymin)*width8];
218             if(this->emptypage) {
219                 for(x=0;x<rangex;x++) {
220                     /* the first bitmap on the page doesn't need to have an alpha channel-
221                        blend against a white background*/
222                     out[x].r = (in[x*3+0]*ain[x])/255 + 255-ain[x];
223                     out[x].g = (in[x*3+1]*ain[x])/255 + 255-ain[x];
224                     out[x].b = (in[x*3+2]*ain[x])/255 + 255-ain[x];
225                     out[x].a = 255;
226                 }
227             } else {
228                 for(x=0;x<rangex;x++) {
229                     if(!(ain2[(x+xmin)/8]&(0x80>>((x+xmin)&7)))) {
230                         /* cut away pixels that we don't remember drawing (i.e., that are
231                            not in the monochrome bitmap). Prevents some "hairlines" showing
232                            up to the left and right of bitmaps. */
233                         out[x].r = 0;out[x].g = 0;out[x].b = 0;out[x].a = 0;
234                     } else {
235                         /* according to endPage()/compositeBackground() in xpdf/SplashOutputDev.cc, we
236                            have to premultiply alpha (mix background and pixel according to the alpha channel).
237                         */
238                         out[x].r = (in[x*3+0]*ain[x])/255;
239                         out[x].g = (in[x*3+1]*ain[x])/255;
240                         out[x].b = (in[x*3+2]*ain[x])/255;
241                         out[x].a = ain[x];
242                     }
243                 }
244             }
245         }
246
247         /* transform bitmap rectangle to "device space" */
248         xmin += movex;
249         ymin += movey;
250         xmax += movex;
251         ymax += movey;
252
253         gfxmatrix_t m;
254         m.tx = xmin;
255         m.ty = ymin;
256         m.m00 = m.m11 = 1;
257         m.m10 = m.m01 = 0;
258         m.tx -= 0.5;
259         m.ty -= 0.5;
260
261         gfxline_t* line = gfxline_makerectangle(xmin, ymin, xmax, ymax);
262         dev->fillbitmap(dev, line, img, &m, 0);
263         gfxline_free(line);
264     
265         free(img->data);img->data=0;free(img);img=0;
266     }
267     ibbox_destroy(boxes);
268
269     memset(rgbbitmap->getAlphaPtr(), 0, rgbbitmap->getWidth()*rgbbitmap->getHeight());
270     memset(rgbbitmap->getDataPtr(), 0, rgbbitmap->getRowSize()*rgbbitmap->getHeight());
271
272     this->emptypage = 0;
273 }
274
275 void BitmapOutputDev::flushText()
276 {
277     msg("<verbose> Flushing text/polygons");
278     gfxdevice_record_flush(this->gfxoutput, this->dev);
279     
280     this->emptypage = 0;
281 }
282
283 void writeMonoBitmap(SplashBitmap*btm, char*filename)
284 {
285     int width8 = (btm->getWidth()+7)/8;
286     int width = btm->getWidth();
287     int height = btm->getHeight();
288     gfxcolor_t*b = (gfxcolor_t*)malloc(sizeof(gfxcolor_t)*width*height);
289     unsigned char*data = btm->getDataPtr();
290     int x,y;
291     for(y=0;y<height;y++) {
292         unsigned char*l = &data[width8*y];
293         gfxcolor_t*d = &b[width*y];
294         for(x=0;x<width;x++) {
295             if(l[x>>3]&(128>>(x&7))) {
296                 d[x].r = d[x].g = d[x].b = 255;
297             } else {
298                 d[x].r = d[x].g = d[x].b = 0;
299             }
300             d[x].a = 255;
301         }
302     }
303     writePNG(filename, (unsigned char*)b, width, height);
304     free(b);
305 }
306
307 void writeBitmap(SplashBitmap*bitmap, char*filename)
308 {
309     int y,x;
310     
311     int width = bitmap->getWidth();
312     int height = bitmap->getHeight();
313
314     gfxcolor_t*data = (gfxcolor_t*)malloc(sizeof(gfxcolor_t)*width*height);
315
316     if(bitmap->getMode()==splashModeMono1) {
317         writeMonoBitmap(bitmap, filename);
318         return;
319     }
320
321     for(y=0;y<height;y++) {
322         gfxcolor_t*line = &data[y*width];
323         for(x=0;x<width;x++) {
324             Guchar c[4] = {0,0,0,0};
325             bitmap->getPixel(x,y,c);
326             line[x].r = c[0];
327             line[x].g = c[1];
328             line[x].b = c[2];
329             line[x].a =  bitmap->getAlpha(x,y);
330         }
331     }
332     writePNG(filename, (unsigned char*)data, width, height);
333     free(data);
334 }
335
336 void writeAlpha(SplashBitmap*bitmap, char*filename)
337 {
338     int y,x;
339     
340     int width = bitmap->getWidth();
341     int height = bitmap->getHeight();
342     
343     if(bitmap->getMode()==splashModeMono1) {
344         writeMonoBitmap(bitmap, filename);
345         return;
346     }
347
348     gfxcolor_t*data = (gfxcolor_t*)malloc(sizeof(gfxcolor_t)*width*height);
349
350     for(y=0;y<height;y++) {
351         gfxcolor_t*line = &data[y*width];
352         for(x=0;x<width;x++) {
353             int a = bitmap->getAlpha(x,y);
354             line[x].r = a;
355             line[x].g = a;
356             line[x].b = a;
357             line[x].a = 255;
358         }
359     }
360     writePNG(filename, (unsigned char*)data, width, height);
361     free(data);
362 }
363 static int dbg_btm_counter=1;
364
365 static const char*STATE_NAME[] = {"parallel", "textabovebitmap", "bitmapabovetext"};
366
367 int checkAlphaSanity(SplashBitmap*boolbtm, SplashBitmap*alphabtm)
368 {
369     assert(boolbtm->getWidth() == alphabtm->getWidth());
370     assert(boolbtm->getHeight() == alphabtm->getHeight());
371     if(boolbtm->getMode()==splashModeMono1) {
372         return 1;
373     }
374
375     int width = boolbtm->getWidth();
376     int height = boolbtm->getHeight();
377
378     int bad=0;
379     int x,y;
380     for(y=0;y<height;y++) {
381         for(x=0;x<width;x++) {
382             int a1 = alphabtm->getAlpha(x,y);
383             int a2 = boolbtm->getAlpha(x,y);
384             if(a1!=a2) {
385                 bad++;
386             }
387         }
388     }
389     double badness = bad/(double)(width*height);
390     if(badness>0.2) {
391         msg("<error> Bitmaps don't correspond: %d out of %d pixels wrong (%.2f%%)", bad, width*height, 
392                 badness*100.0);
393         return 0;
394     }
395     msg("<notice> %f", badness);
396     return 1;
397 }
398
399 GBool BitmapOutputDev::checkNewText(int x1, int y1, int x2, int y2)
400 {
401     /* called once some new text was drawn on booltextdev, and
402        before the same thing is drawn on gfxdev */
403    
404     msg("<trace> Testing new text data against current bitmap data, state=%s, counter=%d\n", STATE_NAME[layerstate], dbg_btm_counter);
405     
406     if(0) {
407         char filename1[80];
408         char filename2[80];
409         char filename3[80];
410         sprintf(filename1, "state%dboolbitmap_afternewtext.png", dbg_btm_counter);
411         sprintf(filename2, "state%dbooltext_afternewtext.png", dbg_btm_counter);
412         sprintf(filename3, "state%dbitmap_afternewtext.png", dbg_btm_counter);
413         msg("<verbose> %s %s %s", filename1, filename2, filename3);
414         writeAlpha(boolpolybitmap, filename1);
415         writeAlpha(booltextbitmap, filename2);
416         writeBitmap(rgbdev->getBitmap(), filename3);
417     }
418     dbg_btm_counter++;
419
420     GBool ret = false;
421     if(intersection(x1,y1,x2,y2)) {
422         if(layerstate==STATE_PARALLEL) {
423             /* the new text is above the bitmap. So record that fact,
424                and also clear the bitmap buffer, so we can check for
425                new intersections */
426             msg("<verbose> Text is above current bitmap/polygon data");
427             layerstate=STATE_TEXT_IS_ABOVE;
428             clearBoolPolyDev(x1,y1,x2,y2);
429         } else if(layerstate==STATE_BITMAP_IS_ABOVE) {
430             /* there's a bitmap above the (old) text. So we need
431                to flush out that text, and record that the *new*
432                text is now *above* the bitmap
433              */
434             msg("<verbose> Text is above current bitmap/polygon data (which is above some other text)");
435             flushText();
436             layerstate=STATE_TEXT_IS_ABOVE;
437             /* clear both bool devices- the text device because
438                we just dumped out all the (old) text, and the
439                poly dev so we can check for new intersections */
440             clearBoolPolyDev(x1,y1,x2,y2);
441             /* FIXME this destroys the text pixels we just
442                drew to test for the intersection- however we need
443                those to check for the *new* intersections */
444             clearBoolTextDev(x1,y1,x2,y2);
445             ret = true;
446         } else {
447             /* we already know that the current text section is
448                above the current bitmap section- now just new
449                bitmap data *and* new text data was drawn, and
450                *again* it's above the current bitmap- so clear
451                the polygon bitmap again, so we can check for
452                new intersections */
453             msg("<verbose> Text is still above current bitmap/polygon data");
454             clearBoolPolyDev(x1,y1,x2,y2);
455         }
456     } 
457     return ret;
458 }
459
460 GBool BitmapOutputDev::checkNewBitmap(int x1, int y1, int x2, int y2)
461 {
462     /* similar to checkNewText() above, only in reverse */
463     msg("<trace> Testing new graphics data against current text data, state=%s, counter=%d\n", STATE_NAME[layerstate], dbg_btm_counter);
464
465     if(0) {
466         char filename1[80];
467         char filename2[80];
468         char filename3[80];
469         sprintf(filename1, "state%dboolbitmap_afternewgfx.png", dbg_btm_counter);
470         sprintf(filename2, "state%dbooltext_afternewgfx.png", dbg_btm_counter);
471         sprintf(filename3, "state%dbitmap_afternewgfx.png", dbg_btm_counter);
472         msg("<verbose> %s %s %s", filename1, filename2, filename3);
473         writeAlpha(boolpolybitmap, filename1);
474         writeAlpha(booltextbitmap, filename2);
475         writeBitmap(rgbdev->getBitmap(), filename3);
476     }
477     dbg_btm_counter++;
478
479     GBool ret = false;
480     if(intersection(x1,y1,x2,y2)) {
481         if(layerstate==STATE_PARALLEL) {
482             msg("<verbose> Bitmap is above current text data");
483             layerstate=STATE_BITMAP_IS_ABOVE;
484             clearBoolTextDev(x1,y1,x2,y2);
485         } else if(layerstate==STATE_TEXT_IS_ABOVE) {
486             msg("<verbose> Bitmap is above current text data (which is above some bitmap)");
487             flushBitmap();
488             layerstate=STATE_BITMAP_IS_ABOVE;
489             clearBoolTextDev(x1,y1,x2,y2);
490             /* FIXME this destroys the polygon pixels we just
491                drew to test for the intersection- however we need
492                those to check for the *new* intersections */
493             clearBoolPolyDev(x1,y1,x2,y2);
494             ret = true;
495         } else {
496             msg("<verbose> Bitmap is still above current text data");
497             clearBoolTextDev(x1,y1,x2,y2);
498         }
499     } 
500     return ret;
501 }
502
503 //void checkNewText() {
504 //    Guchar*alpha = rgbbitmap->getAlphaPtr();
505 //    Guchar*charpixels = clip1bitmap->getDataPtr();
506 //    int xx,yy;
507 //    for(yy=0;yy<height;yy++) {
508 //        Guchar*aline = &alpha[yy*width];
509 //        Guchar*cline = &charpixels[yy*width8];
510 //        for(xx=0;xx<width;xx++) {
511 //            int bit = xx&7;
512 //            int bytepos = xx>>3;
513 //            /* TODO: is the bit order correct? */
514 //            if(aline[xx] && (cline[bytepos]&(1<<bit))) 
515 //              break;
516 //        }
517 //        if(xx!=width)
518 //            break;
519 //}
520
521 static inline GBool fixBBox(int*x1, int*y1, int*x2, int*y2, int width, int height)
522 {
523     if(!(*x1|*y1|*x2|*y2)) {
524         // undefined bbox
525         *x1 = *y1 = 0;
526         *x2 = width;
527         *y2 = height;
528         return gTrue;
529     }
530     if(*x2<=*x1) return gFalse;
531     if(*x2<0) return gFalse;
532     if(*x1<0) *x1 = 0;
533     if(*x1>=width) return gFalse;
534     if(*x2>width) *x2=width;
535
536     if(*y2<=*y1) return gFalse;
537     if(*y2<0) return gFalse;
538     if(*y1<0) *y1 = 0;
539     if(*y1>=height) return gFalse;
540     if(*y2>height) *y2=height;
541     return gTrue;
542 }
543
544 GBool BitmapOutputDev::clip0and1differ(int x1,int y1,int x2,int y2)
545 {
546     if(clip0bitmap->getMode()==splashModeMono1) {
547         int width = clip0bitmap->getWidth();
548         int width8 = (width+7)/8;
549         int height = clip0bitmap->getHeight();
550
551         if(!fixBBox(&x1,&y1,&x2,&y2,width,height)) {
552             /* area is outside or null */
553             return gFalse;
554         }
555         
556         SplashBitmap*clip0 = clip0bitmap;
557         SplashBitmap*clip1 = clip1bitmap;
558         int x18 = x1/8;
559         int x28 = (x2+7)/8;
560         int y;
561
562         for(y=y1;y<y2;y++) {
563             unsigned char*row1 = &clip0bitmap->getDataPtr()[width8*y+x18];
564             unsigned char*row2 = &clip1bitmap->getDataPtr()[width8*y+x18];
565             if(memcmp(row1, row2, x28-x18)) {
566                 return gTrue;
567             }
568         }
569         return gFalse;
570     } else {
571         SplashBitmap*clip0 = clip0bitmap;
572         SplashBitmap*clip1 = clip1bitmap;
573         int width = clip0->getAlphaRowSize();
574         int height = clip0->getHeight();
575
576         if(!fixBBox(&x1, &y1, &x2, &y2, width, height)) {
577             x1=y1=0;x2=y2=1;
578         }
579
580         Guchar*a0 = clip0->getAlphaPtr();
581         Guchar*a1 = clip1->getAlphaPtr();
582         int x,y;
583         char differs=0;
584         for(y=y1;y<y2;y++) {
585             for(x=x1;x<x2;x++) {
586                 if(a0[y*width+x]!=a1[y*width+x]) {
587                     differs=1;
588                     break;
589                 }
590             }
591             if(differs)
592                 break;
593         }
594         char differs2 = memcmp(a0, a1, width*height);
595         if(differs && !differs2) 
596             msg("<warning> Strange internal error (2)");
597         else if(!differs && differs2) {
598             msg("<warning> Bad Bounding Box: Difference in clip0 and clip1 outside bbox");
599             msg("<warning> %d %d %d %d", x1, y1, x2, y2);
600         }
601         return differs2;
602     }
603 }
604
605 static void clearBooleanBitmap(SplashBitmap*btm, int x1, int y1, int x2, int y2)
606 {
607     if(!(x1|y1|x2|y2)) {
608         x1 = y1 = 0;
609         x2 = btm->getWidth();
610         y2 = btm->getHeight();
611     }
612     if(btm->getMode()==splashModeMono1) {
613         int width8 = (btm->getWidth()+7)/8;
614         int width = btm->getWidth();
615         int height = btm->getHeight();
616         memset(btm->getDataPtr(), 0, width8*height);
617     } else {
618         int width = btm->getAlphaRowSize();
619         int height = btm->getHeight();
620         memset(btm->getAlphaPtr(), 0, width*height);
621     }
622 }
623
624 GBool compare8(unsigned char*data1, unsigned char*data2, int len)
625 {
626     if(!len)
627         return 0;
628     if(((ptroff_t)data1&7)==((ptroff_t)data2&7)) {
629         // oh good, we can do aligning
630         while((ptroff_t)data1&7) {
631             if(*data1&*data2)
632                 return 1;
633             data1++;
634             data2++;
635             if(!--len)
636                 return 0;
637         }
638     }
639     /* use 64 bit for the (hopefully aligned) middle section */
640     int l8 = len/8;
641     long long unsigned int*d1 = (long long unsigned int*)data1;
642     long long unsigned int*d2 = (long long unsigned int*)data2;
643     long long unsigned int x = 0;
644     int t;
645     for(t=0;t<l8;t++) {
646         x |= d1[t]&d2[t];
647     }
648     if(x)
649         return 1;
650
651     data1+=l8*8;
652     data2+=l8*8;
653     len -= l8*8;
654     for(t=0;t<len;t++) {
655         if(data1[t]&data2[t]) {
656             return 1;
657         }
658     }
659     return 0;
660 }
661
662 GBool BitmapOutputDev::intersection(int x1, int y1, int x2, int y2)
663 {
664     SplashBitmap*boolpoly = boolpolybitmap;
665     SplashBitmap*booltext = booltextbitmap;
666             
667     if(boolpoly->getMode()==splashModeMono1) {
668         /* alternative implementation, using one bit per pixel-
669            needs the no-dither patch in xpdf */
670         
671         int width = boolpoly->getWidth();
672         int height = boolpoly->getHeight();
673
674         if(!fixBBox(&x1,&y1,&x2,&y2, width, height)) {
675             return gFalse;
676         }
677
678         Guchar*polypixels = boolpoly->getDataPtr();
679         Guchar*textpixels = booltext->getDataPtr();
680
681         int width8 = (width+7)/8;
682         int runx = width8;
683         int runy = height;
684         
685         if(x1|y1|x2|y2) {
686             polypixels+=y1*width8+x1/8;
687             textpixels+=y1*width8+x1/8;
688             runx=(x2+7)/8 - x1/8;
689             runy=y2-y1;
690         }
691         
692         int t;
693         unsigned char c=0;
694         
695         /*assert(sizeof(unsigned long long int)==8);
696         if(((ptroff_t)polypixels&7) || ((ptroff_t)textpixels&7)) {
697             //msg("<warning> Non-optimal alignment");
698         }*/
699
700         int x,y;
701         unsigned char*data1 = (unsigned char*)polypixels;
702         unsigned char*data2 = (unsigned char*)textpixels;
703         msg("<verbose> Testing area (%d,%d,%d,%d), runx=%d,runy=%d", x1,y1,x2,y2, runx, runy);
704         for(y=0;y<runy;y++) {
705             if(compare8(data1,data2,runx))
706                 return gTrue;
707             data1+=width8;
708             data2+=width8;
709         }
710         return gFalse;
711     } else {
712         int width = boolpoly->getAlphaRowSize();
713         int height = boolpoly->getHeight();
714
715         if(!fixBBox(&x1, &y1, &x2, &y2, width, height)) {
716             x1=y1=0;x2=y2=1;
717         }
718         Guchar*polypixels = boolpoly->getAlphaPtr();
719         Guchar*textpixels = booltext->getAlphaPtr();
720
721         int x,y;
722         char overlap1 = 0;
723         char overlap2 = 0;
724         for(x=x1;x<x2;x++) {
725             for(y=y1;y<y2;y++) {
726                 if(polypixels[width*y+x]&&textpixels[width*y+x])
727                     overlap1 = 1;
728             }
729         }
730         int ax1=0,ay1=0,ax2=0,ay2=0;
731         for(y=0;y<height;y++) {
732             for(x=0;x<width;x++) {
733                 if(polypixels[width*y+x]&&textpixels[width*y+x]) {
734                     overlap2 = 1;
735                     if(!(ax1|ay1|ax2|ay2)) {
736                         ax1 = ax2 = x;
737                         ay1 = ay2 = y;
738                     } else {
739                         ax1 = ax1<x?ax1:x;
740                         ay1 = ay1<y?ay1:y;
741                         ax2 = ax2>x?ax2:x;
742                         ay2 = ay2>y?ay2:y;
743                     }
744                 }
745             }
746         }
747         if(overlap1 && !overlap2)
748             msg("<warning> strange internal error");
749         if(!overlap1 && overlap2) {
750             msg("<warning> Bad bounding box: intersection outside bbox");
751             msg("<warning> given bbox: %d %d %d %d", x1, y1, x2, y2);
752             msg("<warning> changed area: %d %d %d %d", ax1, ay1, ax2, ay2);
753             //writeAlpha(booltextbitmap, "alpha.png");
754         }
755         return overlap2;
756     }
757 }
758
759
760 void BitmapOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
761 {
762     double x1,y1,x2,y2;
763     state->transform(crop_x1,crop_y1,&x1,&y1);
764     state->transform(crop_x2,crop_y2,&x2,&y2);
765     if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
766     if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
767     
768     this->movex = -(int)x1 - user_movex;
769     this->movey = -(int)y1 - user_movey;
770     
771     if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
772         x1 = user_clipx1;
773         x2 = user_clipx2;
774         y1 = user_clipy1;
775         y2 = user_clipy2;
776     }
777     this->width = (int)(x2-x1);
778     this->height = (int)(y2-y1);
779
780     msg("<debug> startPage");
781     rgbdev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
782     boolpolydev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
783     booltextdev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
784     clip0dev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
785     clip1dev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
786     gfxdev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
787
788     boolpolybitmap = boolpolydev->getBitmap();
789     booltextbitmap = booltextdev->getBitmap();
790     clip0bitmap = clip0dev->getBitmap();
791     clip1bitmap = clip1dev->getBitmap();
792     rgbbitmap = rgbdev->getBitmap();
793     
794     flushText(); // write out the initial clipping rectangle
795
796     /* just in case any device did draw a white background rectangle 
797        into the device */
798     clearBoolTextDev(UNKNOWN_BOUNDING_BOX);
799     clearBoolPolyDev(UNKNOWN_BOUNDING_BOX);
800
801     this->layerstate = STATE_PARALLEL;
802     this->emptypage = 1;
803     msg("<debug> startPage done");
804 }
805
806 void BitmapOutputDev::endPage()
807 {
808     msg("<verbose> endPage (BitmapOutputDev)");
809
810     /* notice: we're not fully done yet with this page- there might still be 
811        a few calls to drawLink() yet to come */
812 }
813 void BitmapOutputDev::finishPage()
814 {
815     msg("<verbose> finishPage (BitmapOutputDev)");
816     gfxdev->endPage();
817    
818     if(layerstate == STATE_BITMAP_IS_ABOVE) {
819         this->flushText();
820         this->flushBitmap();
821     } else {
822         this->flushBitmap();
823         this->flushText();
824     }
825
826     /* splash will now destroy alpha, and paint the 
827        background color into the "holes" in the bitmap */
828     boolpolydev->endPage();
829     booltextdev->endPage();
830     rgbdev->endPage();
831     clip0dev->endPage();
832     clip1dev->endPage();
833 }
834
835 GBool BitmapOutputDev::upsideDown()
836 {
837     boolpolydev->upsideDown();
838     booltextdev->upsideDown();
839     clip0dev->upsideDown();
840     clip1dev->upsideDown();
841     return rgbdev->upsideDown();
842 }
843
844 GBool BitmapOutputDev::useDrawChar()
845 {
846     boolpolydev->useDrawChar();
847     booltextdev->useDrawChar();
848     clip0dev->useDrawChar();
849     clip1dev->useDrawChar();
850     return rgbdev->useDrawChar();
851 }
852
853 GBool BitmapOutputDev::useTilingPatternFill()
854 {
855     boolpolydev->useTilingPatternFill();
856     booltextdev->useTilingPatternFill();
857     clip0dev->useTilingPatternFill();
858     clip1dev->useTilingPatternFill();
859     return rgbdev->useTilingPatternFill();
860 }
861
862 GBool BitmapOutputDev::useShadedFills()
863 {
864     boolpolydev->useShadedFills();
865     booltextdev->useShadedFills();
866     clip0dev->useShadedFills();
867     clip1dev->useShadedFills();
868     return rgbdev->useShadedFills();
869 }
870
871 GBool BitmapOutputDev::useDrawForm()
872 {
873     boolpolydev->useDrawForm();
874     booltextdev->useDrawForm();
875     clip0dev->useDrawForm();
876     clip1dev->useDrawForm();
877     return rgbdev->useDrawForm();
878 }
879
880 GBool BitmapOutputDev::interpretType3Chars()
881 {
882     boolpolydev->interpretType3Chars();
883     booltextdev->interpretType3Chars();
884     clip0dev->interpretType3Chars();
885     clip1dev->interpretType3Chars();
886     return rgbdev->interpretType3Chars();
887 }
888
889 GBool BitmapOutputDev::needNonText() 
890 {
891     boolpolydev->needNonText();
892     booltextdev->needNonText();
893     clip0dev->needNonText();
894     clip1dev->needNonText();
895     return rgbdev->needNonText();
896 }
897 /*GBool BitmapOutputDev::checkPageSlice(Page *page, double hDPI, double vDPI,
898                            int rotate, GBool useMediaBox, GBool crop,
899                            int sliceX, int sliceY, int sliceW, int sliceH,
900                            GBool printing, Catalog *catalog,
901                            GBool (*abortCheckCbk)(void *data),
902                            void *abortCheckCbkData)
903 {
904     return gTrue;
905 }*/
906 void BitmapOutputDev::setDefaultCTM(double *ctm) 
907 {
908     boolpolydev->setDefaultCTM(ctm);
909     booltextdev->setDefaultCTM(ctm);
910     rgbdev->setDefaultCTM(ctm);
911     clip0dev->setDefaultCTM(ctm);
912     clip1dev->setDefaultCTM(ctm);
913     gfxdev->setDefaultCTM(ctm);
914 }
915 void BitmapOutputDev::saveState(GfxState *state) 
916 {
917     boolpolydev->saveState(state);
918     booltextdev->saveState(state);
919     rgbdev->saveState(state);
920     clip0dev->saveState(state);
921     clip1dev->saveState(state);
922
923     /*ClipState*cstate = new ClipState();
924     cstate->next = this->clipstates;
925     this->clipstates = cstate;*/
926 }
927 void BitmapOutputDev::restoreState(GfxState *state) 
928 {
929     boolpolydev->restoreState(state);
930     booltextdev->restoreState(state);
931     rgbdev->restoreState(state);
932     clip0dev->restoreState(state);
933     clip1dev->restoreState(state);
934
935     /*if(this->clipstates) {
936         ClipState*old = this->clipstates;
937         if(old->written) {
938             gfxdev->restoreState(state);
939         }
940         this->clipstates = this->clipstates->next;
941         delete(old);
942     } else {
943         msg("<error> invalid restoreState()");
944     }*/
945 }
946 void BitmapOutputDev::updateAll(GfxState *state)
947 {
948     boolpolydev->updateAll(state);
949     booltextdev->updateAll(state);
950     rgbdev->updateAll(state);
951     clip0dev->updateAll(state);
952     clip1dev->updateAll(state);
953     gfxdev->updateAll(state);
954 }
955 void BitmapOutputDev::updateCTM(GfxState *state, double m11, double m12, double m21, double m22, double m31, double m32)
956 {
957     boolpolydev->updateCTM(state,m11,m12,m21,m22,m31,m32);
958     booltextdev->updateCTM(state,m11,m12,m21,m22,m31,m32);
959     rgbdev->updateCTM(state,m11,m12,m21,m22,m31,m32);
960     clip0dev->updateCTM(state,m11,m12,m21,m22,m31,m32);
961     clip1dev->updateCTM(state,m11,m12,m21,m22,m31,m32);
962     gfxdev->updateCTM(state,m11,m12,m21,m22,m31,m32);
963 }
964 void BitmapOutputDev::updateLineDash(GfxState *state)
965 {
966     boolpolydev->updateLineDash(state);
967     booltextdev->updateLineDash(state);
968     rgbdev->updateLineDash(state);
969     clip0dev->updateLineDash(state);
970     clip1dev->updateLineDash(state);
971     gfxdev->updateLineDash(state);
972 }
973 void BitmapOutputDev::updateFlatness(GfxState *state)
974 {
975     boolpolydev->updateFlatness(state);
976     booltextdev->updateFlatness(state);
977     rgbdev->updateFlatness(state);
978     clip0dev->updateFlatness(state);
979     clip1dev->updateFlatness(state);
980     gfxdev->updateFlatness(state);
981 }
982 void BitmapOutputDev::updateLineJoin(GfxState *state)
983 {
984     boolpolydev->updateLineJoin(state);
985     booltextdev->updateLineJoin(state);
986     rgbdev->updateLineJoin(state);
987     clip0dev->updateLineJoin(state);
988     clip1dev->updateLineJoin(state);
989     gfxdev->updateLineJoin(state);
990 }
991 void BitmapOutputDev::updateLineCap(GfxState *state)
992 {
993     boolpolydev->updateLineCap(state);
994     booltextdev->updateLineCap(state);
995     rgbdev->updateLineCap(state);
996     clip0dev->updateLineCap(state);
997     clip1dev->updateLineCap(state);
998     gfxdev->updateLineCap(state);
999 }
1000 void BitmapOutputDev::updateMiterLimit(GfxState *state)
1001 {
1002     boolpolydev->updateMiterLimit(state);
1003     booltextdev->updateMiterLimit(state);
1004     rgbdev->updateMiterLimit(state);
1005     clip0dev->updateMiterLimit(state);
1006     clip1dev->updateMiterLimit(state);
1007     gfxdev->updateMiterLimit(state);
1008 }
1009 void BitmapOutputDev::updateLineWidth(GfxState *state)
1010 {
1011     boolpolydev->updateLineWidth(state);
1012     booltextdev->updateLineWidth(state);
1013     rgbdev->updateLineWidth(state);
1014     clip0dev->updateLineWidth(state);
1015     clip1dev->updateLineWidth(state);
1016     gfxdev->updateLineWidth(state);
1017 }
1018 void BitmapOutputDev::updateStrokeAdjust(GfxState *state)
1019 {
1020     boolpolydev->updateStrokeAdjust(state);
1021     booltextdev->updateStrokeAdjust(state);
1022     rgbdev->updateStrokeAdjust(state);
1023     clip0dev->updateStrokeAdjust(state);
1024     clip1dev->updateStrokeAdjust(state);
1025     gfxdev->updateStrokeAdjust(state);
1026 }
1027 void BitmapOutputDev::updateFillColorSpace(GfxState *state)
1028 {
1029     boolpolydev->updateFillColorSpace(state);
1030     booltextdev->updateFillColorSpace(state);
1031     rgbdev->updateFillColorSpace(state);
1032     clip0dev->updateFillColorSpace(state);
1033     clip1dev->updateFillColorSpace(state);
1034     gfxdev->updateFillColorSpace(state);
1035 }
1036 void BitmapOutputDev::updateStrokeColorSpace(GfxState *state)
1037 {
1038     boolpolydev->updateStrokeColorSpace(state);
1039     booltextdev->updateStrokeColorSpace(state);
1040     rgbdev->updateStrokeColorSpace(state);
1041     clip0dev->updateStrokeColorSpace(state);
1042     clip1dev->updateStrokeColorSpace(state);
1043     gfxdev->updateStrokeColorSpace(state);
1044 }
1045 void BitmapOutputDev::updateFillColor(GfxState *state)
1046 {
1047     boolpolydev->updateFillColor(state);
1048     booltextdev->updateFillColor(state);
1049     rgbdev->updateFillColor(state);
1050     clip0dev->updateFillColor(state);
1051     clip1dev->updateFillColor(state);
1052     gfxdev->updateFillColor(state);
1053 }
1054 void BitmapOutputDev::updateStrokeColor(GfxState *state)
1055 {
1056     boolpolydev->updateStrokeColor(state);
1057     booltextdev->updateStrokeColor(state);
1058     rgbdev->updateStrokeColor(state);
1059     clip0dev->updateStrokeColor(state);
1060     clip1dev->updateStrokeColor(state);
1061     gfxdev->updateStrokeColor(state);
1062 }
1063 void BitmapOutputDev::updateBlendMode(GfxState *state)
1064 {
1065     boolpolydev->updateBlendMode(state);
1066     booltextdev->updateBlendMode(state);
1067     rgbdev->updateBlendMode(state);
1068     clip0dev->updateBlendMode(state);
1069     clip1dev->updateBlendMode(state);
1070     gfxdev->updateBlendMode(state);
1071 }
1072 void BitmapOutputDev::updateFillOpacity(GfxState *state)
1073 {
1074     boolpolydev->updateFillOpacity(state);
1075     booltextdev->updateFillOpacity(state);
1076     rgbdev->updateFillOpacity(state);
1077     clip0dev->updateFillOpacity(state);
1078     clip1dev->updateFillOpacity(state);
1079     gfxdev->updateFillOpacity(state);
1080 }
1081 void BitmapOutputDev::updateStrokeOpacity(GfxState *state)
1082 {
1083     boolpolydev->updateStrokeOpacity(state);
1084     booltextdev->updateStrokeOpacity(state);
1085     rgbdev->updateStrokeOpacity(state);
1086     clip0dev->updateStrokeOpacity(state);
1087     clip1dev->updateStrokeOpacity(state);
1088     gfxdev->updateStrokeOpacity(state);
1089 }
1090 void BitmapOutputDev::updateFillOverprint(GfxState *state)
1091 {
1092     boolpolydev->updateFillOverprint(state);
1093     booltextdev->updateFillOverprint(state);
1094     rgbdev->updateFillOverprint(state);
1095     clip0dev->updateFillOverprint(state);
1096     clip1dev->updateFillOverprint(state);
1097     gfxdev->updateFillOverprint(state);
1098 }
1099 void BitmapOutputDev::updateStrokeOverprint(GfxState *state)
1100 {
1101     boolpolydev->updateStrokeOverprint(state);
1102     booltextdev->updateStrokeOverprint(state);
1103     rgbdev->updateStrokeOverprint(state);
1104     clip0dev->updateStrokeOverprint(state);
1105     clip1dev->updateStrokeOverprint(state);
1106     gfxdev->updateStrokeOverprint(state);
1107 }
1108 void BitmapOutputDev::updateTransfer(GfxState *state)
1109 {
1110     boolpolydev->updateTransfer(state);
1111     booltextdev->updateTransfer(state);
1112     rgbdev->updateTransfer(state);
1113     clip0dev->updateTransfer(state);
1114     clip1dev->updateTransfer(state);
1115     gfxdev->updateTransfer(state);
1116 }
1117
1118 void BitmapOutputDev::updateFont(GfxState *state)
1119 {
1120     boolpolydev->updateFont(state);
1121     booltextdev->updateFont(state);
1122     rgbdev->updateFont(state);
1123     clip0dev->updateFont(state);
1124     clip1dev->updateFont(state);
1125     gfxdev->updateFont(state);
1126 }
1127 void BitmapOutputDev::updateTextMat(GfxState *state)
1128 {
1129     boolpolydev->updateTextMat(state);
1130     booltextdev->updateTextMat(state);
1131     rgbdev->updateTextMat(state);
1132     clip0dev->updateTextMat(state);
1133     clip1dev->updateTextMat(state);
1134     gfxdev->updateTextMat(state);
1135 }
1136 void BitmapOutputDev::updateCharSpace(GfxState *state)
1137 {
1138     boolpolydev->updateCharSpace(state);
1139     booltextdev->updateCharSpace(state);
1140     rgbdev->updateCharSpace(state);
1141     clip0dev->updateCharSpace(state);
1142     clip1dev->updateCharSpace(state);
1143     gfxdev->updateCharSpace(state);
1144 }
1145 void BitmapOutputDev::updateRender(GfxState *state)
1146 {
1147     boolpolydev->updateRender(state);
1148     booltextdev->updateRender(state);
1149     rgbdev->updateRender(state);
1150     clip0dev->updateRender(state);
1151     clip1dev->updateRender(state);
1152     gfxdev->updateRender(state);
1153 }
1154 void BitmapOutputDev::updateRise(GfxState *state)
1155 {
1156     boolpolydev->updateRise(state);
1157     booltextdev->updateRise(state);
1158     rgbdev->updateRise(state);
1159     clip0dev->updateRise(state);
1160     clip1dev->updateRise(state);
1161     gfxdev->updateRise(state);
1162 }
1163 void BitmapOutputDev::updateWordSpace(GfxState *state)
1164 {
1165     boolpolydev->updateWordSpace(state);
1166     booltextdev->updateWordSpace(state);
1167     rgbdev->updateWordSpace(state);
1168     clip0dev->updateWordSpace(state);
1169     clip1dev->updateWordSpace(state);
1170     gfxdev->updateWordSpace(state);
1171 }
1172 void BitmapOutputDev::updateHorizScaling(GfxState *state)
1173 {
1174     boolpolydev->updateHorizScaling(state);
1175     booltextdev->updateHorizScaling(state);
1176     rgbdev->updateHorizScaling(state);
1177     clip0dev->updateHorizScaling(state);
1178     clip1dev->updateHorizScaling(state);
1179     gfxdev->updateHorizScaling(state);
1180 }
1181 void BitmapOutputDev::updateTextPos(GfxState *state)
1182 {
1183     boolpolydev->updateTextPos(state);
1184     booltextdev->updateTextPos(state);
1185     rgbdev->updateTextPos(state);
1186     clip0dev->updateTextPos(state);
1187     clip1dev->updateTextPos(state);
1188     gfxdev->updateTextPos(state);
1189 }
1190 void BitmapOutputDev::updateTextShift(GfxState *state, double shift)
1191 {
1192     boolpolydev->updateTextShift(state, shift);
1193     booltextdev->updateTextShift(state, shift);
1194     rgbdev->updateTextShift(state, shift);
1195     clip0dev->updateTextShift(state, shift);
1196     clip1dev->updateTextShift(state, shift);
1197     gfxdev->updateTextShift(state, shift);
1198 }
1199
1200 double max(double x, double y) 
1201 {
1202     return x>y?x:y;
1203 }
1204 double min(double x, double y) 
1205 {
1206     return x<y?x:y;
1207 }
1208
1209 gfxbbox_t BitmapOutputDev::getBBox(GfxState*state)
1210 {
1211     GfxPath * path = state->getPath();
1212     int num = path->getNumSubpaths();
1213     gfxbbox_t bbox = {0,0,1,1};
1214     char valid=0;
1215     int t;
1216     for(t = 0; t < num; t++) {
1217         GfxSubpath *subpath = path->getSubpath(t);
1218         int subnum = subpath->getNumPoints();
1219         int s;
1220         for(s=0;s<subnum;s++) {
1221            double x,y;
1222            state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
1223            if(!valid) {
1224                bbox.xmin = x; bbox.ymin = y;
1225                bbox.xmax = x; bbox.ymax = y;
1226                valid = 1;
1227            } else {
1228                bbox.xmin = min(bbox.xmin, x);
1229                bbox.ymin = min(bbox.ymin, y);
1230                bbox.xmax = max(bbox.xmax, x);
1231                bbox.ymax = max(bbox.ymax, y);
1232            }
1233         }
1234     }
1235     return bbox;
1236 }
1237
1238 void BitmapOutputDev::stroke(GfxState *state)
1239 {
1240     msg("<debug> stroke");
1241     boolpolydev->stroke(state);
1242     gfxbbox_t bbox = getBBox(state);
1243     double width = state->getTransformedLineWidth();
1244     bbox.xmin -= width; bbox.ymin -= width;
1245     bbox.xmax += width; bbox.ymax += width;
1246     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1247     rgbdev->stroke(state);
1248 }
1249 void BitmapOutputDev::fill(GfxState *state)
1250 {
1251     msg("<debug> fill");
1252     boolpolydev->fill(state);
1253     gfxbbox_t bbox = getBBox(state);
1254     if(checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax))) {
1255         boolpolydev->fill(state);
1256     }
1257     rgbdev->fill(state);
1258 }
1259 void BitmapOutputDev::eoFill(GfxState *state)
1260 {
1261     msg("<debug> eoFill");
1262     boolpolydev->eoFill(state);
1263     gfxbbox_t bbox = getBBox(state);
1264     if(checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax))) {
1265         boolpolydev->eoFill(state);
1266     }
1267     rgbdev->eoFill(state);
1268 }
1269 #if (xpdfMajorVersion*10000 + xpdfMinorVersion*100 + xpdfUpdateVersion) < 30207
1270 void BitmapOutputDev::tilingPatternFill(GfxState *state, Object *str,
1271                                int paintType, Dict *resDict,
1272                                double *mat, double *bbox,
1273                                int x0, int y0, int x1, int y1,
1274                                double xStep, double yStep)
1275 {
1276     msg("<debug> tilingPatternFill");
1277     boolpolydev->tilingPatternFill(state, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep);
1278     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1279     rgbdev->tilingPatternFill(state, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep);
1280 }
1281 #else
1282 void BitmapOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Object *str,
1283                                int paintType, Dict *resDict,
1284                                double *mat, double *bbox,
1285                                int x0, int y0, int x1, int y1,
1286                                double xStep, double yStep) 
1287 {
1288     msg("<debug> tilingPatternFill");
1289     boolpolydev->tilingPatternFill(state, gfx, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep);
1290     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1291     rgbdev->tilingPatternFill(state, gfx, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep);
1292 }
1293 #endif
1294
1295 GBool BitmapOutputDev::functionShadedFill(GfxState *state, GfxFunctionShading *shading) 
1296 {
1297     msg("<debug> functionShadedFill");
1298     boolpolydev->functionShadedFill(state, shading);
1299     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1300     return rgbdev->functionShadedFill(state, shading);
1301 }
1302 GBool BitmapOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading)
1303 {
1304     msg("<debug> axialShadedFill");
1305     boolpolydev->axialShadedFill(state, shading);
1306     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1307     return rgbdev->axialShadedFill(state, shading);
1308 }
1309 GBool BitmapOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading)
1310 {
1311     msg("<debug> radialShadedFill");
1312     boolpolydev->radialShadedFill(state, shading);
1313     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1314     return rgbdev->radialShadedFill(state, shading);
1315 }
1316
1317 SplashColor black = {0,0,0};
1318 SplashColor white = {255,255,255};
1319
1320 void BitmapOutputDev::clip(GfxState *state)
1321 {
1322     msg("<debug> clip");
1323     boolpolydev->clip(state);
1324     booltextdev->clip(state);
1325     rgbdev->clip(state);
1326     clip1dev->clip(state);
1327 }
1328 void BitmapOutputDev::eoClip(GfxState *state)
1329 {
1330     msg("<debug> eoClip");
1331     boolpolydev->eoClip(state);
1332     booltextdev->eoClip(state);
1333     rgbdev->eoClip(state);
1334     clip1dev->eoClip(state);
1335 }
1336 void BitmapOutputDev::clipToStrokePath(GfxState *state)
1337 {
1338     msg("<debug> clipToStrokePath");
1339     boolpolydev->clipToStrokePath(state);
1340     booltextdev->clipToStrokePath(state);
1341     rgbdev->clipToStrokePath(state);
1342     clip1dev->clipToStrokePath(state);
1343 }
1344
1345 void BitmapOutputDev::beginStringOp(GfxState *state)
1346 {
1347     msg("<debug> beginStringOp");
1348     clip0dev->beginStringOp(state);
1349     clip1dev->beginStringOp(state);
1350     booltextdev->beginStringOp(state);
1351     gfxdev->beginStringOp(state);
1352 }
1353 void BitmapOutputDev::beginString(GfxState *state, GString *s)
1354 {
1355     msg("<debug> beginString");
1356     clip0dev->beginString(state, s);
1357     clip1dev->beginString(state, s);
1358     booltextdev->beginString(state, s);
1359     gfxdev->beginString(state, s);
1360 }
1361
1362 void BitmapOutputDev::clearClips()
1363 {
1364     clearBooleanBitmap(clip0bitmap, 0, 0, 0, 0);
1365     clearBooleanBitmap(clip1bitmap, 0, 0, 0, 0);
1366 }
1367 void BitmapOutputDev::clearBoolPolyDev(int x1, int y1, int x2, int y2)
1368 {
1369     clearBooleanBitmap(boolpolybitmap, x1, y1, x2, y2);
1370 }
1371 void BitmapOutputDev::clearBoolTextDev(int x1, int y1, int x2, int y2)
1372 {
1373     clearBooleanBitmap(booltextbitmap, x1, y1, x2, y2);
1374 }
1375 void BitmapOutputDev::drawChar(GfxState *state, double x, double y,
1376                       double dx, double dy,
1377                       double originX, double originY,
1378                       CharCode code, int nBytes, Unicode *u, int uLen)
1379 {
1380     msg("<debug> drawChar render=%d", state->getRender());
1381
1382     if(state->getRender()&RENDER_CLIP) {
1383         //char is just a clipping boundary
1384         rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1385         boolpolydev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1386         booltextdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1387         clip1dev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1388     } else if(rgbbitmap != rgbdev->getBitmap()) {
1389         // we're doing softmasking or transparency grouping
1390         boolpolydev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1391         //checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1392         rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1393     } else {
1394         // we're drawing a regular char
1395         clearClips();
1396         clip0dev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1397         clip1dev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1398    
1399         /* calculate the bbox of this character */
1400         int x1 = (int)x, x2 = (int)x+1, y1 = (int)y, y2 = (int)y+1;
1401         SplashFont*font = clip0dev->getCurrentFont();
1402         SplashPath*path = font?font->getGlyphPath(code):NULL;
1403
1404         if(!path) {
1405             if(code)
1406                 msg("<error> couldn't create outline for char %d", code);
1407             return;
1408         }
1409         x-=originX;
1410         y-=originY;
1411         path->offset((SplashCoord)x, (SplashCoord)y);
1412         int t;
1413         for(t=0;t<path->getLength();t++) {
1414             double xx,yy;
1415             Guchar f;
1416             path->getPoint(t,&xx,&yy,&f);
1417             state->transform(xx,yy,&xx,&yy);
1418             if(xx<x1) x1=(int)xx;
1419             if(yy<y1) y1=(int)yy;
1420             if(xx>=x2) x2=(int)xx+1;
1421             if(yy>=y2) y2=(int)yy+1;
1422         }
1423
1424         /* if this character is affected somehow by the various clippings (i.e., it looks
1425            different on a device without clipping), then draw it on the bitmap, not as
1426            text */
1427         if(clip0and1differ(x1,y1,x2,y2)) {
1428             msg("<verbose> Char %d is affected by clipping", code);
1429             boolpolydev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1430             checkNewBitmap(x1,y1,x2,y2);
1431             rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1432             if(config_extrafontdata) {
1433                 int oldrender = state->getRender();
1434                 state->setRender(3); //invisible
1435                 gfxdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1436                 state->setRender(oldrender);
1437             }
1438         } else {
1439
1440             /* this char is not at all affected by clipping. 
1441                Now just dump out the bitmap we're currently working on, if necessary. */
1442             booltextdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1443             checkNewText(x1,y1,x2,y2);
1444             /* use polygonal output device to do the actual text handling */
1445             gfxdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1446         }
1447     }
1448 }
1449 void BitmapOutputDev::drawString(GfxState *state, GString *s)
1450 {
1451     msg("<error> internal error: drawString not implemented");
1452     return;
1453     clip0dev->drawString(state, s);
1454     clip1dev->drawString(state, s);
1455     booltextdev->drawString(state, s);
1456     gfxdev->drawString(state, s);
1457 }
1458 void BitmapOutputDev::endTextObject(GfxState *state)
1459 {
1460     msg("<debug> endTextObject");
1461     rgbdev->endTextObject(state);
1462     clip0dev->endTextObject(state);
1463     clip1dev->endTextObject(state);
1464     booltextdev->endTextObject(state);
1465     /* the only thing "drawn" here is clipping */
1466     //checkNewText(UNKNOWN_BOUNDING_BOX);
1467     gfxdev->endTextObject(state);
1468 }
1469 void BitmapOutputDev::endString(GfxState *state)
1470 {
1471     msg("<debug> endString");
1472     clip0dev->endString(state);
1473     clip1dev->endString(state);
1474     booltextdev->endString(state);
1475     int render = state->getRender();
1476     if(render != RENDER_INVISIBLE && render != RENDER_FILL) {
1477         checkNewText(UNKNOWN_BOUNDING_BOX);
1478     }
1479     gfxdev->endString(state);
1480 }
1481 void BitmapOutputDev::endStringOp(GfxState *state)
1482 {
1483     msg("<debug> endStringOp");
1484     clip0dev->endStringOp(state);
1485     clip1dev->endStringOp(state);
1486     booltextdev->endStringOp(state);
1487     gfxdev->endStringOp(state);
1488 }
1489
1490 /* TODO: these four operations below *should* do nothing, as type3
1491          chars are drawn using operations like fill() */
1492 GBool BitmapOutputDev::beginType3Char(GfxState *state, double x, double y,
1493                              double dx, double dy,
1494                              CharCode code, Unicode *u, int uLen)
1495 {
1496     msg("<debug> beginType3Char");
1497     /* call gfxdev so that it can generate "invisible" characters
1498        on top of the actual graphic content, for text extraction */
1499     return gfxdev->beginType3Char(state, x, y, dx, dy, code, u, uLen);
1500 }
1501 void BitmapOutputDev::type3D0(GfxState *state, double wx, double wy)
1502 {
1503     msg("<debug> type3D0");
1504     return gfxdev->type3D0(state, wx, wy);
1505 }
1506 void BitmapOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury)
1507 {
1508     msg("<debug> type3D1");
1509     return gfxdev->type3D1(state, wx, wy, llx, lly, urx, ury);
1510 }
1511 void BitmapOutputDev::endType3Char(GfxState *state)
1512 {
1513     msg("<debug> endType3Char");
1514     gfxdev->endType3Char(state);
1515 }
1516
1517 class CopyStream: public Object
1518 {
1519     Dict*dict;
1520     char*buf;
1521     MemStream*memstream;
1522     public:
1523     CopyStream(Stream*str, int len)
1524     {
1525         buf = 0;
1526         str->reset();
1527         if(len) {
1528             buf = (char*)malloc(len);
1529             int t;
1530             for (t=0; t<len; t++)
1531               buf[t] = str->getChar();
1532         }
1533         str->close();
1534         this->dict = str->getDict();
1535         this->memstream = new MemStream(buf, 0, len, this);
1536     }
1537     ~CopyStream() 
1538     {
1539         ::free(this->buf);this->buf = 0;
1540         delete this->memstream;
1541     }
1542     Dict* getDict() {return dict;}
1543     Stream* getStream() {return this->memstream;};
1544 };
1545
1546 gfxbbox_t BitmapOutputDev::getImageBBox(GfxState*state)
1547 {
1548     gfxbbox_t bbox;
1549     double x,y;
1550     state->transform(0, 1, &x, &y);
1551     bbox.xmin=bbox.xmax = x;
1552     bbox.ymin=bbox.ymax = x;
1553     state->transform(0, 0, &x, &y);
1554     bbox.xmin=min(bbox.xmin,x);
1555     bbox.ymin=min(bbox.ymin,y);
1556     bbox.xmax=max(bbox.xmin,x);
1557     bbox.ymax=max(bbox.ymin,y);
1558     state->transform(1, 0, &x, &y);
1559     bbox.xmin=min(bbox.xmin,x);
1560     bbox.ymin=min(bbox.ymin,y);
1561     bbox.xmax=max(bbox.xmin,x);
1562     bbox.ymax=max(bbox.ymin,y);
1563     state->transform(1, 1, &x, &y);
1564     bbox.xmin=min(bbox.xmin,x);
1565     bbox.ymin=min(bbox.ymin,y);
1566     bbox.xmax=max(bbox.xmin,x);
1567     bbox.ymax=max(bbox.ymin,y);
1568     return bbox;
1569 }
1570 void BitmapOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
1571                            int width, int height, GBool invert,
1572                            GBool inlineImg)
1573 {
1574     msg("<debug> drawImageMask streamkind=%d", str->getKind());
1575     CopyStream*cpystr = 0;
1576     if(inlineImg) {
1577         cpystr = new CopyStream(str, height * ((width + 7) / 8));
1578         str = cpystr->getStream();
1579     }
1580     boolpolydev->drawImageMask(state, ref, str, width, height, invert, inlineImg);
1581     gfxbbox_t bbox = getImageBBox(state);
1582     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1583     rgbdev->drawImageMask(state, ref, str, width, height, invert, inlineImg);
1584     if(cpystr)
1585         delete cpystr;
1586 }
1587 void BitmapOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
1588                        int width, int height, GfxImageColorMap *colorMap,
1589                        int *maskColors, GBool inlineImg)
1590 {
1591     msg("<debug> drawImage streamkind=%d", str->getKind());
1592     CopyStream*cpystr = 0;
1593     if(inlineImg) {
1594         cpystr = new CopyStream(str, height * ((width * colorMap->getNumPixelComps() * colorMap->getBits() + 7) / 8));
1595         str = cpystr->getStream();
1596     }
1597     boolpolydev->drawImage(state, ref, str, width, height, colorMap, maskColors, inlineImg);
1598     gfxbbox_t bbox=getImageBBox(state);
1599     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1600     rgbdev->drawImage(state, ref, str, width, height, colorMap, maskColors, inlineImg);
1601     if(cpystr)
1602         delete cpystr;
1603 }
1604 void BitmapOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
1605                              int width, int height,
1606                              GfxImageColorMap *colorMap,
1607                              Stream *maskStr, int maskWidth, int maskHeight,
1608                              GBool maskInvert)
1609 {
1610     msg("<debug> drawMaskedImage streamkind=%d", str->getKind());
1611     boolpolydev->drawMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert);
1612     gfxbbox_t bbox=getImageBBox(state);
1613     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1614     rgbdev->drawMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert);
1615 }
1616 void BitmapOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
1617                                  int width, int height,
1618                                  GfxImageColorMap *colorMap,
1619                                  Stream *maskStr,
1620                                  int maskWidth, int maskHeight,
1621                                  GfxImageColorMap *maskColorMap)
1622 {
1623     msg("<debug> drawSoftMaskedImage %dx%d (%dx%d) streamkind=%d", width, height, maskWidth, maskHeight, str->getKind());
1624     boolpolydev->drawSoftMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap);
1625     gfxbbox_t bbox=getImageBBox(state);
1626     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1627     rgbdev->drawSoftMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap);
1628 }
1629 void BitmapOutputDev::drawForm(Ref id)
1630 {
1631     msg("<debug> drawForm");
1632     boolpolydev->drawForm(id);
1633     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1634     rgbdev->drawForm(id);
1635 }
1636
1637 void BitmapOutputDev::processLink(Link *link, Catalog *catalog)
1638 {
1639     msg("<debug> processLink");
1640     gfxdev->processLink(link, catalog);
1641 }
1642
1643 void BitmapOutputDev::beginTransparencyGroup(GfxState *state, double *bbox,
1644                                     GfxColorSpace *blendingColorSpace,
1645                                     GBool isolated, GBool knockout,
1646                                     GBool forSoftMask)
1647 {
1648     msg("<debug> beginTransparencyGroup");
1649 #if (xpdfMajorVersion*10000 + xpdfMinorVersion*100 + xpdfUpdateVersion) < 30207
1650     GfxState*state1 = state->copy();
1651     GfxState*state2 = state->copy();
1652     state1->setPath(0);
1653     state1->setPath(state->getPath()->copy());
1654     state2->setPath(0);
1655     state2->setPath(state->getPath()->copy());
1656 #else
1657     GfxState*state1 = state->copy(gTrue);
1658     GfxState*state2 = state->copy(gTrue);
1659 #endif
1660     boolpolydev->beginTransparencyGroup(state1, bbox, blendingColorSpace, isolated, knockout, forSoftMask);
1661     rgbdev->beginTransparencyGroup(state2, bbox, blendingColorSpace, isolated, knockout, forSoftMask);
1662     clip1dev->beginTransparencyGroup(state, bbox, blendingColorSpace, isolated, knockout, forSoftMask);
1663     delete state1;
1664     delete state2;
1665 }
1666 void BitmapOutputDev::endTransparencyGroup(GfxState *state)
1667 {
1668     msg("<debug> endTransparencyGroup");
1669 #if (xpdfMajorVersion*10000 + xpdfMinorVersion*100 + xpdfUpdateVersion) < 30207
1670     GfxState*state1 = state->copy();
1671     GfxState*state2 = state->copy();
1672     state1->setPath(0);
1673     state1->setPath(state->getPath()->copy());
1674     state2->setPath(0);
1675     state2->setPath(state->getPath()->copy());
1676 #else
1677     GfxState*state1 = state->copy(gTrue);
1678     GfxState*state2 = state->copy(gTrue);
1679 #endif
1680     boolpolydev->endTransparencyGroup(state1);
1681     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1682     rgbdev->endTransparencyGroup(state2);
1683     delete state1;
1684     delete state2;
1685     clip1dev->endTransparencyGroup(state);
1686 }
1687 void BitmapOutputDev::paintTransparencyGroup(GfxState *state, double *bbox)
1688 {
1689     msg("<debug> paintTransparencyGroup");
1690     boolpolydev->paintTransparencyGroup(state,bbox);
1691     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1692     rgbdev->paintTransparencyGroup(state,bbox);
1693     clip1dev->paintTransparencyGroup(state,bbox);
1694 }
1695 void BitmapOutputDev::setSoftMask(GfxState *state, double *bbox, GBool alpha, Function *transferFunc, GfxColor *backdropColor)
1696 {
1697     msg("<debug> setSoftMask");
1698     boolpolydev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
1699     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1700     rgbdev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
1701     clip1dev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
1702 }
1703 void BitmapOutputDev::clearSoftMask(GfxState *state)
1704 {
1705     msg("<debug> clearSoftMask");
1706     boolpolydev->clearSoftMask(state);
1707     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1708     rgbdev->clearSoftMask(state);
1709     clip1dev->clearSoftMask(state);
1710 }