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