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