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