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