use 64 bit operations to update boolean bitmaps
[swftools.git] / lib / pdf / BitmapOutputDev.cc
1 /* InfoOutputDev.h
2
3    Output Device which creates a bitmap.
4
5    Swftools is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    Swftools is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with swftools; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <memory.h>
22 #include <assert.h>
23 #include "config.h"
24 #include "BitmapOutputDev.h"
25 #include "GFXOutputDev.h"
26 #include "SplashBitmap.h"
27 #include "SplashPattern.h"
28 #include "Splash.h"
29 #include "../log.h"
30 #include "../png.h"
31 #include "../devices/record.h"
32 #include "../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 + width) xmax = -this->movex+this->width;
220         if(ymax > -this->movey + 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     msg("<debug> startPage");
848     rgbdev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
849     boolpolydev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
850     booltextdev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
851     clip0dev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
852     clip1dev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
853     gfxdev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
854
855     boolpolybitmap = boolpolydev->getBitmap();
856     stalepolybitmap = new SplashBitmap(boolpolybitmap->getWidth(), boolpolybitmap->getHeight(), 1, boolpolybitmap->getMode(), 0);
857     assert(stalepolybitmap->getRowSize() == boolpolybitmap->getRowSize());
858
859     booltextbitmap = booltextdev->getBitmap();
860     staletextbitmap = new SplashBitmap(booltextbitmap->getWidth(), booltextbitmap->getHeight(), 1, booltextbitmap->getMode(), 0);
861     assert(staletextbitmap->getRowSize() == booltextbitmap->getRowSize());
862
863     clip0bitmap = clip0dev->getBitmap();
864     clip1bitmap = clip1dev->getBitmap();
865     rgbbitmap = rgbdev->getBitmap();
866     
867     flushText(); // write out the initial clipping rectangle
868
869     /* just in case any device did draw a white background rectangle 
870        into the device */
871     clearBoolTextDev();
872     clearBoolPolyDev();
873
874     this->layerstate = STATE_PARALLEL;
875     this->emptypage = 1;
876     msg("<debug> startPage done");
877 }
878
879 void BitmapOutputDev::endPage()
880 {
881     msg("<verbose> endPage (BitmapOutputDev)");
882
883     /* notice: we're not fully done yet with this page- there might still be 
884        a few calls to drawLink() yet to come */
885 }
886 void BitmapOutputDev::finishPage()
887 {
888     msg("<verbose> finishPage (BitmapOutputDev)");
889     gfxdev->endPage();
890    
891     if(layerstate == STATE_BITMAP_IS_ABOVE) {
892         this->flushText();
893         this->flushBitmap();
894     } else {
895         this->flushBitmap();
896         this->flushText();
897     }
898
899     /* splash will now destroy alpha, and paint the 
900        background color into the "holes" in the bitmap */
901     boolpolydev->endPage();
902     booltextdev->endPage();
903     rgbdev->endPage();
904     clip0dev->endPage();
905     clip1dev->endPage();
906 }
907
908 GBool BitmapOutputDev::upsideDown()
909 {
910     boolpolydev->upsideDown();
911     booltextdev->upsideDown();
912     clip0dev->upsideDown();
913     clip1dev->upsideDown();
914     return rgbdev->upsideDown();
915 }
916
917 GBool BitmapOutputDev::useDrawChar()
918 {
919     boolpolydev->useDrawChar();
920     booltextdev->useDrawChar();
921     clip0dev->useDrawChar();
922     clip1dev->useDrawChar();
923     return rgbdev->useDrawChar();
924 }
925
926 GBool BitmapOutputDev::useTilingPatternFill()
927 {
928     boolpolydev->useTilingPatternFill();
929     booltextdev->useTilingPatternFill();
930     clip0dev->useTilingPatternFill();
931     clip1dev->useTilingPatternFill();
932     return rgbdev->useTilingPatternFill();
933 }
934
935 GBool BitmapOutputDev::useShadedFills()
936 {
937     boolpolydev->useShadedFills();
938     booltextdev->useShadedFills();
939     clip0dev->useShadedFills();
940     clip1dev->useShadedFills();
941     return rgbdev->useShadedFills();
942 }
943
944 GBool BitmapOutputDev::useDrawForm()
945 {
946     boolpolydev->useDrawForm();
947     booltextdev->useDrawForm();
948     clip0dev->useDrawForm();
949     clip1dev->useDrawForm();
950     return rgbdev->useDrawForm();
951 }
952
953 GBool BitmapOutputDev::interpretType3Chars()
954 {
955     boolpolydev->interpretType3Chars();
956     booltextdev->interpretType3Chars();
957     clip0dev->interpretType3Chars();
958     clip1dev->interpretType3Chars();
959     return rgbdev->interpretType3Chars();
960 }
961
962 GBool BitmapOutputDev::needNonText() 
963 {
964     boolpolydev->needNonText();
965     booltextdev->needNonText();
966     clip0dev->needNonText();
967     clip1dev->needNonText();
968     return rgbdev->needNonText();
969 }
970 /*GBool BitmapOutputDev::checkPageSlice(Page *page, double hDPI, double vDPI,
971                            int rotate, GBool useMediaBox, GBool crop,
972                            int sliceX, int sliceY, int sliceW, int sliceH,
973                            GBool printing, Catalog *catalog,
974                            GBool (*abortCheckCbk)(void *data),
975                            void *abortCheckCbkData)
976 {
977     return gTrue;
978 }*/
979 void BitmapOutputDev::setDefaultCTM(double *ctm) 
980 {
981     boolpolydev->setDefaultCTM(ctm);
982     booltextdev->setDefaultCTM(ctm);
983     rgbdev->setDefaultCTM(ctm);
984     clip0dev->setDefaultCTM(ctm);
985     clip1dev->setDefaultCTM(ctm);
986     gfxdev->setDefaultCTM(ctm);
987 }
988 void BitmapOutputDev::saveState(GfxState *state) 
989 {
990     boolpolydev->saveState(state);
991     booltextdev->saveState(state);
992     rgbdev->saveState(state);
993     clip0dev->saveState(state);
994     clip1dev->saveState(state);
995
996     /*ClipState*cstate = new ClipState();
997     cstate->next = this->clipstates;
998     this->clipstates = cstate;*/
999 }
1000 void BitmapOutputDev::restoreState(GfxState *state) 
1001 {
1002     boolpolydev->restoreState(state);
1003     booltextdev->restoreState(state);
1004     rgbdev->restoreState(state);
1005     clip0dev->restoreState(state);
1006     clip1dev->restoreState(state);
1007
1008     /*if(this->clipstates) {
1009         ClipState*old = this->clipstates;
1010         if(old->written) {
1011             gfxdev->restoreState(state);
1012         }
1013         this->clipstates = this->clipstates->next;
1014         delete(old);
1015     } else {
1016         msg("<error> invalid restoreState()");
1017     }*/
1018 }
1019 void BitmapOutputDev::updateAll(GfxState *state)
1020 {
1021     boolpolydev->updateAll(state);
1022     booltextdev->updateAll(state);
1023     rgbdev->updateAll(state);
1024     clip0dev->updateAll(state);
1025     clip1dev->updateAll(state);
1026     gfxdev->updateAll(state);
1027 }
1028 void BitmapOutputDev::updateCTM(GfxState *state, double m11, double m12, double m21, double m22, double m31, double m32)
1029 {
1030     boolpolydev->updateCTM(state,m11,m12,m21,m22,m31,m32);
1031     booltextdev->updateCTM(state,m11,m12,m21,m22,m31,m32);
1032     rgbdev->updateCTM(state,m11,m12,m21,m22,m31,m32);
1033     clip0dev->updateCTM(state,m11,m12,m21,m22,m31,m32);
1034     clip1dev->updateCTM(state,m11,m12,m21,m22,m31,m32);
1035     gfxdev->updateCTM(state,m11,m12,m21,m22,m31,m32);
1036 }
1037 void BitmapOutputDev::updateLineDash(GfxState *state)
1038 {
1039     boolpolydev->updateLineDash(state);
1040     booltextdev->updateLineDash(state);
1041     rgbdev->updateLineDash(state);
1042     clip0dev->updateLineDash(state);
1043     clip1dev->updateLineDash(state);
1044     gfxdev->updateLineDash(state);
1045 }
1046 void BitmapOutputDev::updateFlatness(GfxState *state)
1047 {
1048     boolpolydev->updateFlatness(state);
1049     booltextdev->updateFlatness(state);
1050     rgbdev->updateFlatness(state);
1051     clip0dev->updateFlatness(state);
1052     clip1dev->updateFlatness(state);
1053     gfxdev->updateFlatness(state);
1054 }
1055 void BitmapOutputDev::updateLineJoin(GfxState *state)
1056 {
1057     boolpolydev->updateLineJoin(state);
1058     booltextdev->updateLineJoin(state);
1059     rgbdev->updateLineJoin(state);
1060     clip0dev->updateLineJoin(state);
1061     clip1dev->updateLineJoin(state);
1062     gfxdev->updateLineJoin(state);
1063 }
1064 void BitmapOutputDev::updateLineCap(GfxState *state)
1065 {
1066     boolpolydev->updateLineCap(state);
1067     booltextdev->updateLineCap(state);
1068     rgbdev->updateLineCap(state);
1069     clip0dev->updateLineCap(state);
1070     clip1dev->updateLineCap(state);
1071     gfxdev->updateLineCap(state);
1072 }
1073 void BitmapOutputDev::updateMiterLimit(GfxState *state)
1074 {
1075     boolpolydev->updateMiterLimit(state);
1076     booltextdev->updateMiterLimit(state);
1077     rgbdev->updateMiterLimit(state);
1078     clip0dev->updateMiterLimit(state);
1079     clip1dev->updateMiterLimit(state);
1080     gfxdev->updateMiterLimit(state);
1081 }
1082 void BitmapOutputDev::updateLineWidth(GfxState *state)
1083 {
1084     boolpolydev->updateLineWidth(state);
1085     booltextdev->updateLineWidth(state);
1086     rgbdev->updateLineWidth(state);
1087     clip0dev->updateLineWidth(state);
1088     clip1dev->updateLineWidth(state);
1089     gfxdev->updateLineWidth(state);
1090 }
1091 void BitmapOutputDev::updateStrokeAdjust(GfxState *state)
1092 {
1093     boolpolydev->updateStrokeAdjust(state);
1094     booltextdev->updateStrokeAdjust(state);
1095     rgbdev->updateStrokeAdjust(state);
1096     clip0dev->updateStrokeAdjust(state);
1097     clip1dev->updateStrokeAdjust(state);
1098     gfxdev->updateStrokeAdjust(state);
1099 }
1100 void BitmapOutputDev::updateFillColorSpace(GfxState *state)
1101 {
1102     boolpolydev->updateFillColorSpace(state);
1103     booltextdev->updateFillColorSpace(state);
1104     rgbdev->updateFillColorSpace(state);
1105     clip0dev->updateFillColorSpace(state);
1106     clip1dev->updateFillColorSpace(state);
1107     gfxdev->updateFillColorSpace(state);
1108 }
1109 void BitmapOutputDev::updateStrokeColorSpace(GfxState *state)
1110 {
1111     boolpolydev->updateStrokeColorSpace(state);
1112     booltextdev->updateStrokeColorSpace(state);
1113     rgbdev->updateStrokeColorSpace(state);
1114     clip0dev->updateStrokeColorSpace(state);
1115     clip1dev->updateStrokeColorSpace(state);
1116     gfxdev->updateStrokeColorSpace(state);
1117 }
1118 void BitmapOutputDev::updateFillColor(GfxState *state)
1119 {
1120     boolpolydev->updateFillColor(state);
1121     booltextdev->updateFillColor(state);
1122     rgbdev->updateFillColor(state);
1123     clip0dev->updateFillColor(state);
1124     clip1dev->updateFillColor(state);
1125     gfxdev->updateFillColor(state);
1126 }
1127 void BitmapOutputDev::updateStrokeColor(GfxState *state)
1128 {
1129     boolpolydev->updateStrokeColor(state);
1130     booltextdev->updateStrokeColor(state);
1131     rgbdev->updateStrokeColor(state);
1132     clip0dev->updateStrokeColor(state);
1133     clip1dev->updateStrokeColor(state);
1134     gfxdev->updateStrokeColor(state);
1135 }
1136 void BitmapOutputDev::updateBlendMode(GfxState *state)
1137 {
1138     boolpolydev->updateBlendMode(state);
1139     booltextdev->updateBlendMode(state);
1140     rgbdev->updateBlendMode(state);
1141     clip0dev->updateBlendMode(state);
1142     clip1dev->updateBlendMode(state);
1143     gfxdev->updateBlendMode(state);
1144 }
1145 void BitmapOutputDev::updateFillOpacity(GfxState *state)
1146 {
1147     boolpolydev->updateFillOpacity(state);
1148     booltextdev->updateFillOpacity(state);
1149     rgbdev->updateFillOpacity(state);
1150     clip0dev->updateFillOpacity(state);
1151     clip1dev->updateFillOpacity(state);
1152     gfxdev->updateFillOpacity(state);
1153 }
1154 void BitmapOutputDev::updateStrokeOpacity(GfxState *state)
1155 {
1156     boolpolydev->updateStrokeOpacity(state);
1157     booltextdev->updateStrokeOpacity(state);
1158     rgbdev->updateStrokeOpacity(state);
1159     clip0dev->updateStrokeOpacity(state);
1160     clip1dev->updateStrokeOpacity(state);
1161     gfxdev->updateStrokeOpacity(state);
1162 }
1163 void BitmapOutputDev::updateFillOverprint(GfxState *state)
1164 {
1165     boolpolydev->updateFillOverprint(state);
1166     booltextdev->updateFillOverprint(state);
1167     rgbdev->updateFillOverprint(state);
1168     clip0dev->updateFillOverprint(state);
1169     clip1dev->updateFillOverprint(state);
1170     gfxdev->updateFillOverprint(state);
1171 }
1172 void BitmapOutputDev::updateStrokeOverprint(GfxState *state)
1173 {
1174     boolpolydev->updateStrokeOverprint(state);
1175     booltextdev->updateStrokeOverprint(state);
1176     rgbdev->updateStrokeOverprint(state);
1177     clip0dev->updateStrokeOverprint(state);
1178     clip1dev->updateStrokeOverprint(state);
1179     gfxdev->updateStrokeOverprint(state);
1180 }
1181 void BitmapOutputDev::updateTransfer(GfxState *state)
1182 {
1183     boolpolydev->updateTransfer(state);
1184     booltextdev->updateTransfer(state);
1185     rgbdev->updateTransfer(state);
1186     clip0dev->updateTransfer(state);
1187     clip1dev->updateTransfer(state);
1188     gfxdev->updateTransfer(state);
1189 }
1190
1191 void BitmapOutputDev::updateFont(GfxState *state)
1192 {
1193     boolpolydev->updateFont(state);
1194     booltextdev->updateFont(state);
1195     rgbdev->updateFont(state);
1196     clip0dev->updateFont(state);
1197     clip1dev->updateFont(state);
1198     gfxdev->updateFont(state);
1199 }
1200 void BitmapOutputDev::updateTextMat(GfxState *state)
1201 {
1202     boolpolydev->updateTextMat(state);
1203     booltextdev->updateTextMat(state);
1204     rgbdev->updateTextMat(state);
1205     clip0dev->updateTextMat(state);
1206     clip1dev->updateTextMat(state);
1207     gfxdev->updateTextMat(state);
1208 }
1209 void BitmapOutputDev::updateCharSpace(GfxState *state)
1210 {
1211     boolpolydev->updateCharSpace(state);
1212     booltextdev->updateCharSpace(state);
1213     rgbdev->updateCharSpace(state);
1214     clip0dev->updateCharSpace(state);
1215     clip1dev->updateCharSpace(state);
1216     gfxdev->updateCharSpace(state);
1217 }
1218 void BitmapOutputDev::updateRender(GfxState *state)
1219 {
1220     boolpolydev->updateRender(state);
1221     booltextdev->updateRender(state);
1222     rgbdev->updateRender(state);
1223     clip0dev->updateRender(state);
1224     clip1dev->updateRender(state);
1225     gfxdev->updateRender(state);
1226 }
1227 void BitmapOutputDev::updateRise(GfxState *state)
1228 {
1229     boolpolydev->updateRise(state);
1230     booltextdev->updateRise(state);
1231     rgbdev->updateRise(state);
1232     clip0dev->updateRise(state);
1233     clip1dev->updateRise(state);
1234     gfxdev->updateRise(state);
1235 }
1236 void BitmapOutputDev::updateWordSpace(GfxState *state)
1237 {
1238     boolpolydev->updateWordSpace(state);
1239     booltextdev->updateWordSpace(state);
1240     rgbdev->updateWordSpace(state);
1241     clip0dev->updateWordSpace(state);
1242     clip1dev->updateWordSpace(state);
1243     gfxdev->updateWordSpace(state);
1244 }
1245 void BitmapOutputDev::updateHorizScaling(GfxState *state)
1246 {
1247     boolpolydev->updateHorizScaling(state);
1248     booltextdev->updateHorizScaling(state);
1249     rgbdev->updateHorizScaling(state);
1250     clip0dev->updateHorizScaling(state);
1251     clip1dev->updateHorizScaling(state);
1252     gfxdev->updateHorizScaling(state);
1253 }
1254 void BitmapOutputDev::updateTextPos(GfxState *state)
1255 {
1256     boolpolydev->updateTextPos(state);
1257     booltextdev->updateTextPos(state);
1258     rgbdev->updateTextPos(state);
1259     clip0dev->updateTextPos(state);
1260     clip1dev->updateTextPos(state);
1261     gfxdev->updateTextPos(state);
1262 }
1263 void BitmapOutputDev::updateTextShift(GfxState *state, double shift)
1264 {
1265     boolpolydev->updateTextShift(state, shift);
1266     booltextdev->updateTextShift(state, shift);
1267     rgbdev->updateTextShift(state, shift);
1268     clip0dev->updateTextShift(state, shift);
1269     clip1dev->updateTextShift(state, shift);
1270     gfxdev->updateTextShift(state, shift);
1271 }
1272
1273 double max(double x, double y) 
1274 {
1275     return x>y?x:y;
1276 }
1277 double min(double x, double y) 
1278 {
1279     return x<y?x:y;
1280 }
1281
1282 gfxbbox_t BitmapOutputDev::getBBox(GfxState*state)
1283 {
1284     GfxPath * path = state->getPath();
1285     int num = path->getNumSubpaths();
1286     gfxbbox_t bbox = {0,0,1,1};
1287     char valid=0;
1288     int t;
1289     for(t = 0; t < num; t++) {
1290         GfxSubpath *subpath = path->getSubpath(t);
1291         int subnum = subpath->getNumPoints();
1292         int s;
1293         for(s=0;s<subnum;s++) {
1294            double x,y;
1295            state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
1296            if(!valid) {
1297                bbox.xmin = x; bbox.ymin = y;
1298                bbox.xmax = x; bbox.ymax = y;
1299                valid = 1;
1300            } else {
1301                bbox.xmin = min(bbox.xmin, x);
1302                bbox.ymin = min(bbox.ymin, y);
1303                bbox.xmax = max(bbox.xmax, x);
1304                bbox.ymax = max(bbox.ymax, y);
1305            }
1306         }
1307     }
1308     return bbox;
1309 }
1310
1311 void BitmapOutputDev::stroke(GfxState *state)
1312 {
1313     msg("<debug> stroke");
1314     boolpolydev->stroke(state);
1315     gfxbbox_t bbox = getBBox(state);
1316     double width = state->getTransformedLineWidth();
1317     bbox.xmin -= width; bbox.ymin -= width;
1318     bbox.xmax += width; bbox.ymax += width;
1319     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1320     rgbdev->stroke(state);
1321     dbg_newdata("stroke");
1322 }
1323 void BitmapOutputDev::fill(GfxState *state)
1324 {
1325     msg("<debug> fill");
1326     boolpolydev->fill(state);
1327     gfxbbox_t bbox = getBBox(state);
1328     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1329     rgbdev->fill(state);
1330     dbg_newdata("fill");
1331 }
1332 void BitmapOutputDev::eoFill(GfxState *state)
1333 {
1334     msg("<debug> eoFill");
1335     boolpolydev->eoFill(state);
1336     gfxbbox_t bbox = getBBox(state);
1337     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1338     rgbdev->eoFill(state);
1339     dbg_newdata("eofill");
1340 }
1341 #if (xpdfMajorVersion*10000 + xpdfMinorVersion*100 + xpdfUpdateVersion) < 30207
1342 void BitmapOutputDev::tilingPatternFill(GfxState *state, Object *str,
1343                                int paintType, Dict *resDict,
1344                                double *mat, double *bbox,
1345                                int x0, int y0, int x1, int y1,
1346                                double xStep, double yStep)
1347 {
1348     msg("<debug> tilingPatternFill");
1349     boolpolydev->tilingPatternFill(state, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep);
1350     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1351     rgbdev->tilingPatternFill(state, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep);
1352     dbg_newdata("tilingpatternfill");
1353 }
1354 #else
1355 void BitmapOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Object *str,
1356                                int paintType, Dict *resDict,
1357                                double *mat, double *bbox,
1358                                int x0, int y0, int x1, int y1,
1359                                double xStep, double yStep) 
1360 {
1361     msg("<debug> tilingPatternFill");
1362     boolpolydev->tilingPatternFill(state, gfx, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep);
1363     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1364     rgbdev->tilingPatternFill(state, gfx, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep);
1365     dbg_newdata("tilingpatternfill");
1366 }
1367 #endif
1368
1369 GBool BitmapOutputDev::functionShadedFill(GfxState *state, GfxFunctionShading *shading) 
1370 {
1371     msg("<debug> functionShadedFill");
1372     boolpolydev->functionShadedFill(state, shading);
1373     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1374     return rgbdev->functionShadedFill(state, shading);
1375 }
1376 GBool BitmapOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading)
1377 {
1378     msg("<debug> axialShadedFill");
1379     boolpolydev->axialShadedFill(state, shading);
1380     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1381     return rgbdev->axialShadedFill(state, shading);
1382 }
1383 GBool BitmapOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading)
1384 {
1385     msg("<debug> radialShadedFill");
1386     boolpolydev->radialShadedFill(state, shading);
1387     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1388     return rgbdev->radialShadedFill(state, shading);
1389 }
1390
1391 SplashColor black = {0,0,0};
1392 SplashColor white = {255,255,255};
1393
1394 void BitmapOutputDev::clip(GfxState *state)
1395 {
1396     msg("<debug> clip");
1397     boolpolydev->clip(state);
1398     booltextdev->clip(state);
1399     rgbdev->clip(state);
1400     clip1dev->clip(state);
1401 }
1402 void BitmapOutputDev::eoClip(GfxState *state)
1403 {
1404     msg("<debug> eoClip");
1405     boolpolydev->eoClip(state);
1406     booltextdev->eoClip(state);
1407     rgbdev->eoClip(state);
1408     clip1dev->eoClip(state);
1409 }
1410 void BitmapOutputDev::clipToStrokePath(GfxState *state)
1411 {
1412     msg("<debug> clipToStrokePath");
1413     boolpolydev->clipToStrokePath(state);
1414     booltextdev->clipToStrokePath(state);
1415     rgbdev->clipToStrokePath(state);
1416     clip1dev->clipToStrokePath(state);
1417 }
1418
1419 void BitmapOutputDev::beginStringOp(GfxState *state)
1420 {
1421     msg("<debug> beginStringOp");
1422     clip0dev->beginStringOp(state);
1423     clip1dev->beginStringOp(state);
1424     booltextdev->beginStringOp(state);
1425     gfxdev->beginStringOp(state);
1426 }
1427 void BitmapOutputDev::beginString(GfxState *state, GString *s)
1428 {
1429     msg("<debug> beginString");
1430     clip0dev->beginString(state, s);
1431     clip1dev->beginString(state, s);
1432     booltextdev->beginString(state, s);
1433     gfxdev->beginString(state, s);
1434 }
1435
1436 void BitmapOutputDev::clearClips()
1437 {
1438     clearBooleanBitmap(clip0bitmap, 0, 0, 0, 0);
1439     clearBooleanBitmap(clip1bitmap, 0, 0, 0, 0);
1440 }
1441 void BitmapOutputDev::clearBoolPolyDev()
1442 {
1443     clearBooleanBitmap(stalepolybitmap, 0, 0, stalepolybitmap->getWidth(), stalepolybitmap->getHeight());
1444 }
1445 void BitmapOutputDev::clearBoolTextDev()
1446 {
1447     clearBooleanBitmap(staletextbitmap, 0, 0, staletextbitmap->getWidth(), staletextbitmap->getHeight());
1448 }
1449 void BitmapOutputDev::drawChar(GfxState *state, double x, double y,
1450                       double dx, double dy,
1451                       double originX, double originY,
1452                       CharCode code, int nBytes, Unicode *u, int uLen)
1453 {
1454     msg("<debug> drawChar render=%d", state->getRender());
1455
1456     if(state->getRender()&RENDER_CLIP) {
1457         //char is just a clipping boundary
1458         rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1459         boolpolydev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1460         booltextdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1461         clip1dev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1462     } else if(rgbbitmap != rgbdev->getBitmap()) {
1463         // we're doing softmasking or transparency grouping
1464         boolpolydev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1465         rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1466     } else {
1467         // we're drawing a regular char
1468         clearClips();
1469         clip0dev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1470         clip1dev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1471    
1472         /* calculate the bbox of this character */
1473         int x1 = (int)x, x2 = (int)x+1, y1 = (int)y, y2 = (int)y+1;
1474         SplashFont*font = clip0dev->getCurrentFont();
1475         SplashPath*path = font?font->getGlyphPath(code):NULL;
1476         x-=originX;
1477         y-=originY;
1478         if(path) {
1479             path->offset((SplashCoord)x, (SplashCoord)y);
1480             int t;
1481             for(t=0;t<path->getLength();t++) {
1482                 double xx,yy;
1483                 Guchar f;
1484                 path->getPoint(t,&xx,&yy,&f);
1485                 state->transform(xx,yy,&xx,&yy);
1486                 if(xx<x1) x1=(int)xx;
1487                 if(yy<y1) y1=(int)yy;
1488                 if(xx>=x2) x2=(int)xx+1;
1489                 if(yy>=y2) y2=(int)yy+1;
1490             }
1491             delete(path);path=0;
1492         }
1493
1494         /* if this character is affected somehow by the various clippings (i.e., it looks
1495            different on a device without clipping), then draw it on the bitmap, not as
1496            text */
1497         if(clip0and1differ(x1,y1,x2,y2)) {
1498             msg("<verbose> Char %d is affected by clipping", code);
1499             boolpolydev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1500             checkNewBitmap(x1,y1,x2,y2);
1501             rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1502             if(config_extrafontdata) {
1503                 int oldrender = state->getRender();
1504                 state->setRender(3); //invisible
1505                 gfxdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1506                 state->setRender(oldrender);
1507             }
1508         } else {
1509
1510             /* this char is not at all affected by clipping. 
1511                Now just dump out the bitmap we're currently working on, if necessary. */
1512             booltextdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1513             checkNewText(x1,y1,x2,y2);
1514             /* use polygonal output device to do the actual text handling */
1515             gfxdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1516         }
1517     }
1518     dbg_newdata("text");
1519 }
1520 void BitmapOutputDev::drawString(GfxState *state, GString *s)
1521 {
1522     msg("<error> internal error: drawString not implemented");
1523     return;
1524 }
1525 void BitmapOutputDev::endTextObject(GfxState *state)
1526 {
1527     msg("<debug> endTextObject");
1528     rgbdev->endTextObject(state);
1529     clip0dev->endTextObject(state);
1530     clip1dev->endTextObject(state);
1531     booltextdev->endTextObject(state);
1532     /* the only thing "drawn" here is clipping */
1533     //checkNewText(UNKNOWN_BOUNDING_BOX);
1534     gfxdev->endTextObject(state);
1535     dbg_newdata("endtextobject");
1536 }
1537 void BitmapOutputDev::endString(GfxState *state)
1538 {
1539     msg("<debug> endString");
1540     clip0dev->endString(state);
1541     clip1dev->endString(state);
1542     booltextdev->endString(state);
1543     int render = state->getRender();
1544     if(render != RENDER_INVISIBLE && render != RENDER_FILL) {
1545         /* xpdf draws things like stroke text or fill+stroke text in the
1546            endString() method */
1547         checkNewText(UNKNOWN_BOUNDING_BOX);
1548     }
1549     gfxdev->endString(state);
1550     dbg_newdata("endstring");
1551 }
1552 void BitmapOutputDev::endStringOp(GfxState *state)
1553 {
1554     msg("<debug> endStringOp");
1555     clip0dev->endStringOp(state);
1556     clip1dev->endStringOp(state);
1557     booltextdev->endStringOp(state);
1558     gfxdev->endStringOp(state);
1559     dbg_newdata("endstringop");
1560 }
1561
1562 /* TODO: these four operations below *should* do nothing, as type3
1563          chars are drawn using operations like fill() */
1564 GBool BitmapOutputDev::beginType3Char(GfxState *state, double x, double y,
1565                              double dx, double dy,
1566                              CharCode code, Unicode *u, int uLen)
1567 {
1568     msg("<debug> beginType3Char");
1569     /* call gfxdev so that it can generate "invisible" characters
1570        on top of the actual graphic content, for text extraction */
1571     return gfxdev->beginType3Char(state, x, y, dx, dy, code, u, uLen);
1572 }
1573 void BitmapOutputDev::type3D0(GfxState *state, double wx, double wy)
1574 {
1575     msg("<debug> type3D0");
1576     return gfxdev->type3D0(state, wx, wy);
1577 }
1578 void BitmapOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury)
1579 {
1580     msg("<debug> type3D1");
1581     return gfxdev->type3D1(state, wx, wy, llx, lly, urx, ury);
1582 }
1583 void BitmapOutputDev::endType3Char(GfxState *state)
1584 {
1585     msg("<debug> endType3Char");
1586     gfxdev->endType3Char(state);
1587 }
1588
1589 class CopyStream: public Object
1590 {
1591     Dict*dict;
1592     char*buf;
1593     MemStream*memstream;
1594     public:
1595     CopyStream(Stream*str, int len)
1596     {
1597         buf = 0;
1598         str->reset();
1599         if(len) {
1600             buf = (char*)malloc(len);
1601             int t;
1602             for (t=0; t<len; t++)
1603               buf[t] = str->getChar();
1604         }
1605         str->close();
1606         this->dict = str->getDict();
1607         this->memstream = new MemStream(buf, 0, len, this);
1608     }
1609     ~CopyStream() 
1610     {
1611         ::free(this->buf);this->buf = 0;
1612         delete this->memstream;
1613     }
1614     Dict* getDict() {return dict;}
1615     Stream* getStream() {return this->memstream;};
1616 };
1617
1618 gfxbbox_t BitmapOutputDev::getImageBBox(GfxState*state)
1619 {
1620     gfxbbox_t bbox;
1621     double x,y;
1622     state->transform(0, 1, &x, &y);
1623     bbox.xmin=bbox.xmax = x;
1624     bbox.ymin=bbox.ymax = y;
1625     state->transform(0, 0, &x, &y);
1626     bbox.xmin=min(bbox.xmin,x);
1627     bbox.ymin=min(bbox.ymin,y);
1628     bbox.xmax=max(bbox.xmax,x);
1629     bbox.ymax=max(bbox.ymax,y);
1630     state->transform(1, 0, &x, &y);
1631     bbox.xmin=min(bbox.xmin,x);
1632     bbox.ymin=min(bbox.ymin,y);
1633     bbox.xmax=max(bbox.xmax,x);
1634     bbox.ymax=max(bbox.ymax,y);
1635     state->transform(1, 1, &x, &y);
1636     bbox.xmin=min(bbox.xmin,x);
1637     bbox.ymin=min(bbox.ymin,y);
1638     bbox.xmax=max(bbox.xmax,x);
1639     bbox.ymax=max(bbox.ymax,y);
1640     return bbox;
1641 }
1642 void BitmapOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
1643                            int width, int height, GBool invert,
1644                            GBool inlineImg)
1645 {
1646     msg("<debug> drawImageMask streamkind=%d", str->getKind());
1647
1648     CopyStream*cpystr = new CopyStream(str, height * ((width + 7) / 8));
1649     str = cpystr->getStream();
1650     
1651     boolpolydev->drawImageMask(state, ref, str, width, height, invert, inlineImg);
1652     gfxbbox_t bbox = getImageBBox(state);
1653     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1654     rgbdev->drawImageMask(state, ref, str, width, height, invert, inlineImg);
1655     delete cpystr;
1656     dbg_newdata("imagemask");
1657 }
1658 void BitmapOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
1659                        int width, int height, GfxImageColorMap *colorMap,
1660                        int *maskColors, GBool inlineImg)
1661 {
1662     msg("<debug> drawImage streamkind=%d", str->getKind());
1663         
1664     CopyStream*cpystr = new CopyStream(str, height * ((width * colorMap->getNumPixelComps() * colorMap->getBits() + 7) / 8));
1665     str = cpystr->getStream();
1666
1667     boolpolydev->drawImage(state, ref, str, width, height, colorMap, maskColors, inlineImg);
1668     gfxbbox_t bbox=getImageBBox(state);
1669     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1670     rgbdev->drawImage(state, ref, str, width, height, colorMap, maskColors, inlineImg);
1671     delete cpystr;
1672     dbg_newdata("image");
1673 }
1674 void BitmapOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
1675                              int width, int height,
1676                              GfxImageColorMap *colorMap,
1677                              Stream *maskStr, int maskWidth, int maskHeight,
1678                              GBool maskInvert)
1679 {
1680     msg("<debug> drawMaskedImage streamkind=%d", str->getKind());
1681     
1682     CopyStream*cpystr = new CopyStream(str, height * ((width * colorMap->getNumPixelComps() * colorMap->getBits() + 7) / 8));
1683     str = cpystr->getStream();
1684
1685     boolpolydev->drawMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert);
1686     gfxbbox_t bbox=getImageBBox(state);
1687     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1688     rgbdev->drawMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert);
1689     delete cpystr;
1690     dbg_newdata("maskedimage");
1691 }
1692 void BitmapOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
1693                                  int width, int height,
1694                                  GfxImageColorMap *colorMap,
1695                                  Stream *maskStr,
1696                                  int maskWidth, int maskHeight,
1697                                  GfxImageColorMap *maskColorMap)
1698 {
1699     msg("<debug> drawSoftMaskedImage %dx%d (%dx%d) streamkind=%d", width, height, maskWidth, maskHeight, str->getKind());
1700
1701     CopyStream*cpystr = new CopyStream(str, height * ((width * colorMap->getNumPixelComps() * colorMap->getBits() + 7) / 8));
1702     str = cpystr->getStream();
1703
1704     boolpolydev->drawSoftMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap);
1705     gfxbbox_t bbox=getImageBBox(state);
1706     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1707     rgbdev->drawSoftMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap);
1708     delete cpystr;
1709     dbg_newdata("softmaskimage");
1710 }
1711 void BitmapOutputDev::drawForm(Ref id)
1712 {
1713     msg("<debug> drawForm");
1714     boolpolydev->drawForm(id);
1715     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1716     rgbdev->drawForm(id);
1717 }
1718
1719 void BitmapOutputDev::processLink(Link *link, Catalog *catalog)
1720 {
1721     msg("<debug> processLink");
1722     gfxdev->processLink(link, catalog);
1723 }
1724
1725 void BitmapOutputDev::beginTransparencyGroup(GfxState *state, double *bbox,
1726                                     GfxColorSpace *blendingColorSpace,
1727                                     GBool isolated, GBool knockout,
1728                                     GBool forSoftMask)
1729 {
1730     msg("<debug> beginTransparencyGroup");
1731 #if (xpdfMajorVersion*10000 + xpdfMinorVersion*100 + xpdfUpdateVersion) < 30207
1732     GfxState*state1 = state->copy();
1733     GfxState*state2 = state->copy();
1734     state1->setPath(0);
1735     state1->setPath(state->getPath()->copy());
1736     state2->setPath(0);
1737     state2->setPath(state->getPath()->copy());
1738 #else
1739     GfxState*state1 = state->copy(gTrue);
1740     GfxState*state2 = state->copy(gTrue);
1741 #endif
1742     boolpolydev->beginTransparencyGroup(state1, bbox, blendingColorSpace, isolated, knockout, forSoftMask);
1743     rgbdev->beginTransparencyGroup(state2, bbox, blendingColorSpace, isolated, knockout, forSoftMask);
1744     clip1dev->beginTransparencyGroup(state, bbox, blendingColorSpace, isolated, knockout, forSoftMask);
1745     delete state1;
1746     delete state2;
1747     dbg_newdata("endtransparencygroup");
1748 }
1749 void BitmapOutputDev::endTransparencyGroup(GfxState *state)
1750 {
1751     msg("<debug> endTransparencyGroup");
1752 #if (xpdfMajorVersion*10000 + xpdfMinorVersion*100 + xpdfUpdateVersion) < 30207
1753     GfxState*state1 = state->copy();
1754     GfxState*state2 = state->copy();
1755     state1->setPath(0);
1756     state1->setPath(state->getPath()->copy());
1757     state2->setPath(0);
1758     state2->setPath(state->getPath()->copy());
1759 #else
1760     GfxState*state1 = state->copy(gTrue);
1761     GfxState*state2 = state->copy(gTrue);
1762 #endif
1763     boolpolydev->endTransparencyGroup(state1);
1764     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1765     rgbdev->endTransparencyGroup(state2);
1766     delete state1;
1767     delete state2;
1768     clip1dev->endTransparencyGroup(state);
1769     dbg_newdata("endtransparencygroup");
1770 }
1771 void BitmapOutputDev::paintTransparencyGroup(GfxState *state, double *bbox)
1772 {
1773     msg("<debug> paintTransparencyGroup");
1774     boolpolydev->paintTransparencyGroup(state,bbox);
1775     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1776     rgbdev->paintTransparencyGroup(state,bbox);
1777     clip1dev->paintTransparencyGroup(state,bbox);
1778     dbg_newdata("painttransparencygroup");
1779 }
1780 void BitmapOutputDev::setSoftMask(GfxState *state, double *bbox, GBool alpha, Function *transferFunc, GfxColor *backdropColor)
1781 {
1782     msg("<debug> setSoftMask");
1783     boolpolydev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
1784     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1785     rgbdev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
1786     clip1dev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
1787     dbg_newdata("setsoftmask");
1788 }
1789 void BitmapOutputDev::clearSoftMask(GfxState *state)
1790 {
1791     msg("<debug> clearSoftMask");
1792     boolpolydev->clearSoftMask(state);
1793     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1794     rgbdev->clearSoftMask(state);
1795     clip1dev->clearSoftMask(state);
1796     dbg_newdata("clearsoftmask");
1797 }