fixed crash and offset error in transparency groups
[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 "config.h"
23 #include "BitmapOutputDev.h"
24 #include "GFXOutputDev.h"
25 #include "SplashBitmap.h"
26 #include "SplashPattern.h"
27 #include "Splash.h"
28 #include "../log.h"
29 #include "../png.h"
30 #include "../devices/record.h"
31
32 static SplashColor splash_white = {255,255,255};
33 static SplashColor splash_black = {0,0,0};
34     
35 ClipState::ClipState()
36 {
37     this->next = 0;
38     this->clipbitmap = 0;
39     this->written = 0;
40 }
41
42 BitmapOutputDev::BitmapOutputDev(InfoOutputDev*info, PDFDoc*doc)
43 {
44     this->info = info;
45     this->doc = doc;
46     this->xref = doc->getXRef();
47     
48     /* color graphic output device, for creating bitmaps */
49     this->rgbdev = new SplashOutputDev(splashModeRGB8, 1, gFalse, splash_white, gTrue, gTrue);
50   
51     /* color mode for binary bitmaps */
52     SplashColorMode colorMode = splashModeMono8;
53
54     /* two devices for testing things against clipping: one clips, the other doesn't */
55     this->clip0dev = new SplashOutputDev(colorMode, 1, gFalse, splash_black, gTrue, gFalse);
56     this->clip1dev = new SplashOutputDev(colorMode, 1, gFalse, splash_black, gTrue, gFalse);
57     
58     /* device indicating where polygonal pixels were drawn */
59     this->boolpolydev = new SplashOutputDev(colorMode, 1, gFalse, splash_black, gTrue, gFalse);
60     /* device indicating where text pixels were drawn */
61     this->booltextdev = new SplashOutputDev(colorMode, 1, gFalse, splash_black, gTrue, gFalse);
62
63     /* device for handling texts and links */
64     this->gfxdev = new GFXOutputDev(info, this->doc);
65
66     this->rgbdev->startDoc(this->xref);
67     this->boolpolydev->startDoc(this->xref);
68     this->booltextdev->startDoc(this->xref);
69     this->clip0dev->startDoc(this->xref);
70     this->clip1dev->startDoc(this->xref);
71
72     this->gfxoutput = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
73     gfxdevice_record_init(this->gfxoutput);
74
75     this->gfxdev->setDevice(this->gfxoutput);
76     
77     this->config_extrafontdata = 0;
78     this->bboxpath = 0;
79     //this->clipdev = 0;
80     //this->clipstates = 0;
81 }
82 BitmapOutputDev::~BitmapOutputDev()
83 {
84     if(this->gfxoutput) {
85         gfxresult_t*r = this->gfxoutput->finish(this->gfxoutput);
86         r->destroy(r);
87         free(this->gfxoutput);this->gfxoutput = 0;
88     }
89     if(this->bboxpath) {
90         delete this->bboxpath;this->bboxpath = 0;
91     }
92     if(this->rgbdev) {
93         delete this->rgbdev;this->rgbdev = 0;
94     }
95     if(this->gfxdev) {
96         delete this->gfxdev;this->gfxdev= 0;
97     }
98     if(this->boolpolydev) {
99         delete this->boolpolydev;this->boolpolydev = 0;
100     }
101     if(this->booltextdev) {
102         delete this->booltextdev;this->booltextdev = 0;
103     }
104     if(this->clip0dev) {
105         delete this->clip0dev;this->clip0dev = 0;
106     }
107     if(this->clip1dev) {
108         delete this->clip1dev;this->clip1dev = 0;
109     }
110     //if(this->clipbitmap) {
111     //    delete this->clipbitmap;this->clipbitmap = 0;
112     //}
113     //if(this->clipdev) {
114     //    delete this->clipdev;this->clipdev = 0;
115     //}
116
117 }
118
119 GBool BitmapOutputDev::getVectorAntialias()
120 {
121     return this->rgbdev->getVectorAntialias();
122 }
123 void BitmapOutputDev::setVectorAntialias(GBool vaa)
124 {
125     this->rgbdev->setVectorAntialias(vaa);
126 }
127 void BitmapOutputDev::setDevice(gfxdevice_t*dev)
128 {
129     this->dev = dev;
130 }
131 void BitmapOutputDev::setMove(int x,int y)
132 {
133     this->gfxdev->setMove(x,y);
134     this->user_movex = x;
135     this->user_movey = y;
136 }
137 void BitmapOutputDev::setClip(int x1,int y1,int x2,int y2)
138 {
139     this->gfxdev->setClip(x1,y1,x2,y2);
140     this->user_clipx1 = x1;
141     this->user_clipy1 = y1;
142     this->user_clipx2 = x2;
143     this->user_clipy2 = y2;
144 }
145 void BitmapOutputDev::setParameter(const char*key, const char*value)
146 {
147     if(!strcmp(key, "extrafontdata")) {
148         this->config_extrafontdata = atoi(value);
149     }
150     this->gfxdev->setParameter(key, value);
151 }
152 void BitmapOutputDev::preparePage(int pdfpage, int outputpage)
153 {
154 }
155
156 static void getBitmapBBox(Guchar*alpha, int width, int height, int*xmin, int*ymin, int*xmax, int*ymax)
157 {
158     *ymin = -1;
159     *xmin = width;
160     *xmax = 0;
161     int x,y;
162     for(y=0;y<height;y++) {
163         Guchar*a = &alpha[y*width];
164         for(x=0;x<width;x++) {
165             if(a[x]) break;
166         }
167         int left = x; //first occupied pixel from left
168         int right = x+1; //last non-occupied pixel from right
169         for(;x<width;x++) {
170             if(a[x]) right=x+1;
171         }
172
173         if(left!=width) {
174             if(*ymin<0) 
175                 *ymin=y;
176             *ymax=y+1;
177             if(left<*xmin) *xmin = left;
178             if(right>*xmax) *xmax = right;
179         }
180     }
181     if(*xmin>=*xmax || *ymin>=*ymax) {
182         *xmin = 0;
183         *ymin = 0;
184         *xmax = 0;
185         *ymax = 0;
186     }
187 }
188
189 void BitmapOutputDev::flushBitmap()
190 {
191     int width = rgbdev->getBitmapWidth();
192     int height = rgbdev->getBitmapHeight();
193     
194     SplashColorPtr rgb = rgbdev->getBitmap()->getDataPtr();
195     Guchar*alpha = rgbdev->getBitmap()->getAlphaPtr();
196
197     int xmin,ymin,xmax,ymax;
198     getBitmapBBox(alpha, width, height, &xmin,&ymin,&xmax,&ymax);
199
200     /* clip against (-movex, -movey, -movex+width, -movey+height) */
201     if(xmin < -this->movex) xmin = -this->movex;
202     if(ymin < -this->movey) ymin = -this->movey;
203     if(xmax > -this->movex + width) xmax = -this->movex+this->width;
204     if(ymax > -this->movey + height) ymax = -this->movey+this->height;
205
206     msg("<verbose> Flushing bitmap (bbox: %d,%d,%d,%d)", xmin,ymin,xmax,ymax);
207     
208     if((xmax-xmin)<=0 || (ymax-ymin)<=0) // no bitmap, nothing to do
209         return;
210
211     if(sizeof(SplashColor)!=3) {
212         msg("<error> sizeof(SplashColor)!=3");
213         return;
214     }
215     //xmin = ymin = 0;
216     //xmax = width;
217     //ymax = height;
218
219     int rangex = xmax-xmin;
220     int rangey = ymax-ymin;
221     gfximage_t*img = (gfximage_t*)malloc(sizeof(gfximage_t)); 
222     img->data = (gfxcolor_t*)malloc(rangex * rangey * 4);
223     img->width = rangex;
224     img->height = rangey;
225     int x,y;
226     for(y=0;y<rangey;y++) {
227         SplashColorPtr in=&rgb[((y+ymin)*width+xmin)*sizeof(SplashColor)];
228         gfxcolor_t*out = &img->data[y*rangex];
229         Guchar*ain = &alpha[(y+ymin)*width+xmin];
230         for(x=0;x<rangex;x++) {
231             /* according to endPage()/compositeBackground() in xpdf/SplashOutputDev.cc, we
232                have to premultiply alpha (mix background and pixel according to the alpha channel).
233             */
234             out[x].r = (in[x*3+0]*ain[x])/255;
235             out[x].g = (in[x*3+1]*ain[x])/255;
236             out[x].b = (in[x*3+2]*ain[x])/255;
237             out[x].a = ain[x];
238         }
239     }
240     /* transform bitmap rectangle to "device space" */
241     xmin += movex;
242     ymin += movey;
243     xmax += movex;
244     ymax += movey;
245
246     gfxmatrix_t m;
247     m.tx = xmin;
248     m.ty = ymin;
249     m.m00 = m.m11 = 1;
250     m.m10 = m.m01 = 0;
251
252     gfxline_t* line = gfxline_makerectangle(xmin, ymin, xmax, ymax);
253     dev->fillbitmap(dev, line, img, &m, 0);
254     gfxline_free(line);
255
256     memset(rgbdev->getBitmap()->getAlphaPtr(), 0, rgbdev->getBitmap()->getWidth()*rgbdev->getBitmap()->getHeight());
257     memset(rgbdev->getBitmap()->getDataPtr(), 0, rgbdev->getBitmap()->getRowSize()*rgbdev->getBitmap()->getHeight());
258
259     free(img->data);img->data=0;free(img);img=0;
260 }
261
262 void BitmapOutputDev::flushText()
263 {
264     msg("<verbose> Flushing text/polygons");
265     gfxdevice_record_flush(this->gfxoutput, this->dev);
266 }
267
268 void writeAlpha(SplashBitmap*bitmap, char*filename)
269 {
270     return;
271     int y,x;
272     
273     int width = bitmap->getWidth();
274     int height = bitmap->getHeight();
275
276     gfxcolor_t*data = (gfxcolor_t*)malloc(sizeof(gfxcolor_t)*width*height);
277
278     for(y=0;y<height;y++) {
279         gfxcolor_t*line = &data[y*width];
280         for(x=0;x<width;x++) {
281             int a = bitmap->getAlpha(x,y);
282             line[x].r = a;
283             line[x].g = a;
284             line[x].b = a;
285             line[x].a = 255;
286         }
287     }
288     writePNG(filename, (unsigned char*)data, width, height);
289     free(data);
290 }
291 static int dbg_btm_counter=1;
292
293 void BitmapOutputDev::checkNewText()
294 {
295     /* called once some new text was drawn on booltextdev, and
296        before the same thing is drawn on gfxdev */
297    
298     msg("<trace> Testing new text data against current bitmap data, state=%d, counter=%d\n", layerstate, dbg_btm_counter);
299     
300     char filename1[80];
301     char filename2[80];
302     sprintf(filename1, "state%dbitmap_newtext.png", dbg_btm_counter);
303     sprintf(filename2, "state%dtext_newtext.png", dbg_btm_counter);
304     writeAlpha(boolpolydev->getBitmap(), filename1);
305     writeAlpha(booltextdev->getBitmap(), filename2);
306     dbg_btm_counter++;
307
308     if(intersection()) {
309         msg("<verbose> Text is above current bitmap/polygon data");
310         if(layerstate==STATE_PARALLEL) {
311             /* the new text is above the bitmap. So record that fact,
312                and also clear the bitmap buffer, so we can check for
313                new intersections */
314             layerstate=STATE_TEXT_IS_ABOVE;
315             clearBoolPolyDev();
316         } else if(layerstate==STATE_BITMAP_IS_ABOVE) {
317             /* there's a bitmap above the (old) text. So we need
318                to flush out that text, and record that the *new*
319                text is now *above* the bitmap
320              */
321             flushText();
322             layerstate=STATE_TEXT_IS_ABOVE;
323             /* clear both bool devices- the text device because
324                we just dumped out all the (old) text, and the
325                poly dev so we can check for new intersections */
326             clearBoolPolyDev();
327             clearBoolTextDev();
328         } else {
329             /* we already know that the current text section is
330                above the current bitmap section- now just new
331                bitmap data *and* new text data was drawn, and
332                *again* it's above the current bitmap- so clear
333                the polygon bitmap again, so we can check for
334                new intersections */
335             clearBoolPolyDev();
336         }
337     } 
338 }
339
340 void BitmapOutputDev::checkNewBitmap()
341 {
342     /* similar to checkNewText() above, only in reverse */
343     msg("<trace> Testing new graphics data against current text data, state=%d, counter=%d\n", layerstate, dbg_btm_counter);
344
345     char filename1[80];
346     char filename2[80];
347     sprintf(filename1, "state%dbitmap_newbitmap.png", dbg_btm_counter);
348     sprintf(filename2, "state%dtext_newbitmap.png", dbg_btm_counter);
349     writeAlpha(boolpolydev->getBitmap(), filename1);
350     writeAlpha(booltextdev->getBitmap(), filename2);
351     dbg_btm_counter++;
352
353     if(intersection()) {
354         msg("<verbose> Bitmap is above current text data");
355         if(layerstate==STATE_PARALLEL) {
356             layerstate=STATE_BITMAP_IS_ABOVE;
357             clearBoolTextDev();
358         } else if(layerstate==STATE_TEXT_IS_ABOVE) {
359             flushBitmap();
360             layerstate=STATE_BITMAP_IS_ABOVE;
361             clearBoolTextDev();
362             clearBoolPolyDev();
363         } else {
364             clearBoolTextDev();
365         }
366     } 
367 }
368
369 //void checkNewText() {
370 //    Guchar*alpha = rgbdev->getBitmap()->getAlphaPtr();
371 //    Guchar*charpixels = clip1dev->getBitmap()->getDataPtr();
372 //    int xx,yy;
373 //    for(yy=0;yy<height;yy++) {
374 //        Guchar*aline = &alpha[yy*width];
375 //        Guchar*cline = &charpixels[yy*width8];
376 //        for(xx=0;xx<width;xx++) {
377 //            int bit = xx&7;
378 //            int bytepos = xx>>3;
379 //            /* TODO: is the bit order correct? */
380 //            if(aline[xx] && (cline[bytepos]&(1<<bit))) 
381 //              break;
382 //        }
383 //        if(xx!=width)
384 //            break;
385 //}
386
387 GBool BitmapOutputDev::clip0and1differ()
388 {
389     if(clip0dev->getBitmap()->getMode()==splashModeMono1) {
390         SplashBitmap*clip0 = clip0dev->getBitmap();
391         SplashBitmap*clip1 = clip1dev->getBitmap();
392         int width8 = (clip0->getWidth()+7)/8;
393         int height = clip0->getHeight();
394         return memcmp(clip0->getDataPtr(), clip1->getDataPtr(), width8*height);
395     } else {
396         SplashBitmap*clip0 = clip0dev->getBitmap();
397         SplashBitmap*clip1 = clip1dev->getBitmap();
398         int width = clip0->getAlphaRowSize();
399         int height = clip0->getHeight();
400         return memcmp(clip0->getAlphaPtr(), clip1->getAlphaPtr(), width*height);
401     }
402 }
403
404 static void clearBooleanDev(SplashOutputDev*dev)
405 {
406     SplashBitmap*btm = dev->getBitmap();
407     if(btm->getMode()==splashModeMono1) {
408         int width8 = (btm->getWidth()+7)/8;
409         int width = btm->getWidth();
410         int height = btm->getHeight();
411         memset(btm->getDataPtr(), 0, width8*height);
412     } else {
413         int width = btm->getAlphaRowSize();
414         int height = btm->getHeight();
415         memset(btm->getAlphaPtr(), 0, width*height);
416     }
417 }
418
419 GBool BitmapOutputDev::intersection()
420 {
421     SplashBitmap*boolpoly = boolpolydev->getBitmap();
422     SplashBitmap*booltext = booltextdev->getBitmap();
423         
424     if(boolpoly->getMode()==splashModeMono1) {
425         /* alternative implementation, using one bit per pixel-
426            would work if xpdf wouldn't try to dither everything */
427
428         Guchar*polypixels = boolpoly->getDataPtr();
429         Guchar*textpixels = booltext->getDataPtr();
430     
431         int width8 = (width+7)/8;
432         int height = boolpoly->getHeight();
433         
434         int t;
435         int len = height*width8;
436         unsigned int c=0;
437         if(len & (sizeof(unsigned int)-1)) {
438             Guchar c2=0;
439             for(t=0;t<len;t++) {
440                 c2 |= polypixels[t]&textpixels[t];
441             }
442             c = c2;
443         } else {
444             len /= sizeof(unsigned int);
445             for(t=0;t<len;t++) {
446                 c |= (((unsigned int*)polypixels)[t]) & (((unsigned int*)textpixels)[t]);
447             }
448         }
449         if(c)
450             /* if graphic data and the characters overlap, they have common bits */
451             return gTrue;
452         else
453             return gFalse;
454     } else {
455         Guchar*polypixels = boolpoly->getAlphaPtr();
456         Guchar*textpixels = booltext->getAlphaPtr();
457         
458         int width = boolpoly->getAlphaRowSize();
459         int height = boolpoly->getHeight();
460         
461         int t;
462         int len = height*width;
463         unsigned int c=0;
464         if(len & (sizeof(unsigned int)-1)) {
465             Guchar c2=0;
466             for(t=0;t<len;t++) {
467                 if(polypixels[t]&&textpixels[t])
468                     return gTrue;
469             }
470         } else {
471             len /= sizeof(unsigned int);
472             for(t=0;t<len;t++) {
473                 if((((unsigned int*)polypixels)[t]) & (((unsigned int*)textpixels)[t]))
474                     return gTrue;
475             }
476         }
477         return gFalse;
478     }
479 }
480
481
482 void BitmapOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
483 {
484     double x1,y1,x2,y2;
485     state->transform(crop_x1,crop_y1,&x1,&y1);
486     state->transform(crop_x2,crop_y2,&x2,&y2);
487     if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
488     if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
489     
490     this->movex = -(int)x1 - user_movex;
491     this->movey = -(int)y1 - user_movey;
492     
493     if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
494         x1 = user_clipx1;
495         x2 = user_clipx2;
496         y1 = user_clipy1;
497         y2 = user_clipy2;
498     }
499     this->width = (int)(x2-x1);
500     this->height = (int)(y2-y1);
501
502     msg("<debug> startPage");
503     rgbdev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
504     boolpolydev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
505     booltextdev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
506     clip0dev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
507     clip1dev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
508     gfxdev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
509
510     flushText(); // write out the initial clipping rectangle
511
512     /* just in case any device did draw a white background rectangle 
513        into the device */
514     clearBoolTextDev();
515     clearBoolPolyDev();
516
517     this->layerstate = STATE_PARALLEL;
518 }
519
520 void BitmapOutputDev::endPage()
521 {
522     msg("<verbose> endPage (BitmapOutputDev)");
523    
524     if(layerstate == STATE_BITMAP_IS_ABOVE) {
525         this->flushText();
526         this->flushBitmap();
527     } else {
528         this->flushBitmap();
529         this->flushText();
530     }
531
532     /* splash will now destroy alpha, and paint the 
533        background color into the "holes" in the bitmap */
534     boolpolydev->endPage();
535     booltextdev->endPage();
536     rgbdev->endPage();
537     clip0dev->endPage();
538     clip1dev->endPage();
539     gfxdev->endPage();
540 }
541
542 GBool BitmapOutputDev::upsideDown()
543 {
544     boolpolydev->upsideDown();
545     booltextdev->upsideDown();
546     clip0dev->upsideDown();
547     clip1dev->upsideDown();
548     return rgbdev->upsideDown();
549 }
550
551 GBool BitmapOutputDev::useDrawChar()
552 {
553     boolpolydev->useDrawChar();
554     booltextdev->useDrawChar();
555     clip0dev->useDrawChar();
556     clip1dev->useDrawChar();
557     return rgbdev->useDrawChar();
558 }
559
560 GBool BitmapOutputDev::useTilingPatternFill()
561 {
562     boolpolydev->useTilingPatternFill();
563     booltextdev->useTilingPatternFill();
564     clip0dev->useTilingPatternFill();
565     clip1dev->useTilingPatternFill();
566     return rgbdev->useTilingPatternFill();
567 }
568
569 GBool BitmapOutputDev::useShadedFills()
570 {
571     boolpolydev->useShadedFills();
572     booltextdev->useShadedFills();
573     clip0dev->useShadedFills();
574     clip1dev->useShadedFills();
575     return rgbdev->useShadedFills();
576 }
577
578 GBool BitmapOutputDev::useDrawForm()
579 {
580     boolpolydev->useDrawForm();
581     booltextdev->useDrawForm();
582     clip0dev->useDrawForm();
583     clip1dev->useDrawForm();
584     return rgbdev->useDrawForm();
585 }
586
587 GBool BitmapOutputDev::interpretType3Chars()
588 {
589     boolpolydev->interpretType3Chars();
590     booltextdev->interpretType3Chars();
591     clip0dev->interpretType3Chars();
592     clip1dev->interpretType3Chars();
593     return rgbdev->interpretType3Chars();
594 }
595
596 GBool BitmapOutputDev::needNonText() 
597 {
598     boolpolydev->needNonText();
599     booltextdev->needNonText();
600     clip0dev->needNonText();
601     clip1dev->needNonText();
602     return rgbdev->needNonText();
603 }
604 /*GBool BitmapOutputDev::checkPageSlice(Page *page, double hDPI, double vDPI,
605                            int rotate, GBool useMediaBox, GBool crop,
606                            int sliceX, int sliceY, int sliceW, int sliceH,
607                            GBool printing, Catalog *catalog,
608                            GBool (*abortCheckCbk)(void *data),
609                            void *abortCheckCbkData)
610 {
611     return gTrue;
612 }*/
613 void BitmapOutputDev::setDefaultCTM(double *ctm) 
614 {
615     boolpolydev->setDefaultCTM(ctm);
616     booltextdev->setDefaultCTM(ctm);
617     rgbdev->setDefaultCTM(ctm);
618     clip0dev->setDefaultCTM(ctm);
619     clip1dev->setDefaultCTM(ctm);
620     gfxdev->setDefaultCTM(ctm);
621 }
622 void BitmapOutputDev::saveState(GfxState *state) 
623 {
624     boolpolydev->saveState(state);
625     booltextdev->saveState(state);
626     rgbdev->saveState(state);
627     clip0dev->saveState(state);
628     clip1dev->saveState(state);
629
630     /*ClipState*cstate = new ClipState();
631     cstate->next = this->clipstates;
632     this->clipstates = cstate;*/
633 }
634 void BitmapOutputDev::restoreState(GfxState *state) 
635 {
636     boolpolydev->restoreState(state);
637     booltextdev->restoreState(state);
638     rgbdev->restoreState(state);
639     clip0dev->restoreState(state);
640     clip1dev->restoreState(state);
641
642     /*if(this->clipstates) {
643         ClipState*old = this->clipstates;
644         if(old->written) {
645             gfxdev->restoreState(state);
646         }
647         this->clipstates = this->clipstates->next;
648         delete(old);
649     } else {
650         msg("<error> invalid restoreState()");
651     }*/
652 }
653 void BitmapOutputDev::updateAll(GfxState *state)
654 {
655     boolpolydev->updateAll(state);
656     booltextdev->updateAll(state);
657     rgbdev->updateAll(state);
658     clip0dev->updateAll(state);
659     clip1dev->updateAll(state);
660     gfxdev->updateAll(state);
661 }
662 void BitmapOutputDev::updateCTM(GfxState *state, double m11, double m12, double m21, double m22, double m31, double m32)
663 {
664     boolpolydev->updateCTM(state,m11,m12,m21,m22,m31,m32);
665     booltextdev->updateCTM(state,m11,m12,m21,m22,m31,m32);
666     rgbdev->updateCTM(state,m11,m12,m21,m22,m31,m32);
667     clip0dev->updateCTM(state,m11,m12,m21,m22,m31,m32);
668     clip1dev->updateCTM(state,m11,m12,m21,m22,m31,m32);
669     gfxdev->updateCTM(state,m11,m12,m21,m22,m31,m32);
670 }
671 void BitmapOutputDev::updateLineDash(GfxState *state)
672 {
673     boolpolydev->updateLineDash(state);
674     booltextdev->updateLineDash(state);
675     rgbdev->updateLineDash(state);
676     clip0dev->updateLineDash(state);
677     clip1dev->updateLineDash(state);
678     gfxdev->updateLineDash(state);
679 }
680 void BitmapOutputDev::updateFlatness(GfxState *state)
681 {
682     boolpolydev->updateFlatness(state);
683     booltextdev->updateFlatness(state);
684     rgbdev->updateFlatness(state);
685     clip0dev->updateFlatness(state);
686     clip1dev->updateFlatness(state);
687     gfxdev->updateFlatness(state);
688 }
689 void BitmapOutputDev::updateLineJoin(GfxState *state)
690 {
691     boolpolydev->updateLineJoin(state);
692     booltextdev->updateLineJoin(state);
693     rgbdev->updateLineJoin(state);
694     clip0dev->updateLineJoin(state);
695     clip1dev->updateLineJoin(state);
696     gfxdev->updateLineJoin(state);
697 }
698 void BitmapOutputDev::updateLineCap(GfxState *state)
699 {
700     boolpolydev->updateLineCap(state);
701     booltextdev->updateLineCap(state);
702     rgbdev->updateLineCap(state);
703     clip0dev->updateLineCap(state);
704     clip1dev->updateLineCap(state);
705     gfxdev->updateLineCap(state);
706 }
707 void BitmapOutputDev::updateMiterLimit(GfxState *state)
708 {
709     boolpolydev->updateMiterLimit(state);
710     booltextdev->updateMiterLimit(state);
711     rgbdev->updateMiterLimit(state);
712     clip0dev->updateMiterLimit(state);
713     clip1dev->updateMiterLimit(state);
714     gfxdev->updateMiterLimit(state);
715 }
716 void BitmapOutputDev::updateLineWidth(GfxState *state)
717 {
718     boolpolydev->updateLineWidth(state);
719     booltextdev->updateLineWidth(state);
720     rgbdev->updateLineWidth(state);
721     clip0dev->updateLineWidth(state);
722     clip1dev->updateLineWidth(state);
723     gfxdev->updateLineWidth(state);
724 }
725 void BitmapOutputDev::updateStrokeAdjust(GfxState *state)
726 {
727     boolpolydev->updateStrokeAdjust(state);
728     booltextdev->updateStrokeAdjust(state);
729     rgbdev->updateStrokeAdjust(state);
730     clip0dev->updateStrokeAdjust(state);
731     clip1dev->updateStrokeAdjust(state);
732     gfxdev->updateStrokeAdjust(state);
733 }
734 void BitmapOutputDev::updateFillColorSpace(GfxState *state)
735 {
736     boolpolydev->updateFillColorSpace(state);
737     booltextdev->updateFillColorSpace(state);
738     rgbdev->updateFillColorSpace(state);
739     clip0dev->updateFillColorSpace(state);
740     clip1dev->updateFillColorSpace(state);
741     gfxdev->updateFillColorSpace(state);
742 }
743 void BitmapOutputDev::updateStrokeColorSpace(GfxState *state)
744 {
745     boolpolydev->updateStrokeColorSpace(state);
746     booltextdev->updateStrokeColorSpace(state);
747     rgbdev->updateStrokeColorSpace(state);
748     clip0dev->updateStrokeColorSpace(state);
749     clip1dev->updateStrokeColorSpace(state);
750     gfxdev->updateStrokeColorSpace(state);
751 }
752 void BitmapOutputDev::updateFillColor(GfxState *state)
753 {
754     boolpolydev->updateFillColor(state);
755     booltextdev->updateFillColor(state);
756     rgbdev->updateFillColor(state);
757     clip0dev->updateFillColor(state);
758     clip1dev->updateFillColor(state);
759     gfxdev->updateFillColor(state);
760 }
761 void BitmapOutputDev::updateStrokeColor(GfxState *state)
762 {
763     boolpolydev->updateStrokeColor(state);
764     booltextdev->updateStrokeColor(state);
765     rgbdev->updateStrokeColor(state);
766     clip0dev->updateStrokeColor(state);
767     clip1dev->updateStrokeColor(state);
768     gfxdev->updateStrokeColor(state);
769 }
770 void BitmapOutputDev::updateBlendMode(GfxState *state)
771 {
772     boolpolydev->updateBlendMode(state);
773     booltextdev->updateBlendMode(state);
774     rgbdev->updateBlendMode(state);
775     clip0dev->updateBlendMode(state);
776     clip1dev->updateBlendMode(state);
777     gfxdev->updateBlendMode(state);
778 }
779 void BitmapOutputDev::updateFillOpacity(GfxState *state)
780 {
781     boolpolydev->updateFillOpacity(state);
782     booltextdev->updateFillOpacity(state);
783     rgbdev->updateFillOpacity(state);
784     clip0dev->updateFillOpacity(state);
785     clip1dev->updateFillOpacity(state);
786     gfxdev->updateFillOpacity(state);
787 }
788 void BitmapOutputDev::updateStrokeOpacity(GfxState *state)
789 {
790     boolpolydev->updateStrokeOpacity(state);
791     booltextdev->updateStrokeOpacity(state);
792     rgbdev->updateStrokeOpacity(state);
793     clip0dev->updateStrokeOpacity(state);
794     clip1dev->updateStrokeOpacity(state);
795     gfxdev->updateStrokeOpacity(state);
796 }
797 void BitmapOutputDev::updateFillOverprint(GfxState *state)
798 {
799     boolpolydev->updateFillOverprint(state);
800     booltextdev->updateFillOverprint(state);
801     rgbdev->updateFillOverprint(state);
802     clip0dev->updateFillOverprint(state);
803     clip1dev->updateFillOverprint(state);
804     gfxdev->updateFillOverprint(state);
805 }
806 void BitmapOutputDev::updateStrokeOverprint(GfxState *state)
807 {
808     boolpolydev->updateStrokeOverprint(state);
809     booltextdev->updateStrokeOverprint(state);
810     rgbdev->updateStrokeOverprint(state);
811     clip0dev->updateStrokeOverprint(state);
812     clip1dev->updateStrokeOverprint(state);
813     gfxdev->updateStrokeOverprint(state);
814 }
815 void BitmapOutputDev::updateTransfer(GfxState *state)
816 {
817     boolpolydev->updateTransfer(state);
818     booltextdev->updateTransfer(state);
819     rgbdev->updateTransfer(state);
820     clip0dev->updateTransfer(state);
821     clip1dev->updateTransfer(state);
822     gfxdev->updateTransfer(state);
823 }
824 void BitmapOutputDev::updateFont(GfxState *state)
825 {
826     boolpolydev->updateFont(state);
827     booltextdev->updateFont(state);
828     rgbdev->updateFont(state);
829     clip0dev->updateFont(state);
830     clip1dev->updateFont(state);
831     gfxdev->updateFont(state);
832 }
833 void BitmapOutputDev::updateTextMat(GfxState *state)
834 {
835     boolpolydev->updateTextMat(state);
836     booltextdev->updateTextMat(state);
837     rgbdev->updateTextMat(state);
838     clip0dev->updateTextMat(state);
839     clip1dev->updateTextMat(state);
840     gfxdev->updateTextMat(state);
841 }
842 void BitmapOutputDev::updateCharSpace(GfxState *state)
843 {
844     boolpolydev->updateCharSpace(state);
845     booltextdev->updateCharSpace(state);
846     rgbdev->updateCharSpace(state);
847     clip0dev->updateCharSpace(state);
848     clip1dev->updateCharSpace(state);
849     gfxdev->updateCharSpace(state);
850 }
851 void BitmapOutputDev::updateRender(GfxState *state)
852 {
853     boolpolydev->updateRender(state);
854     booltextdev->updateRender(state);
855     rgbdev->updateRender(state);
856     clip0dev->updateRender(state);
857     clip1dev->updateRender(state);
858     gfxdev->updateRender(state);
859 }
860 void BitmapOutputDev::updateRise(GfxState *state)
861 {
862     boolpolydev->updateRise(state);
863     booltextdev->updateRise(state);
864     rgbdev->updateRise(state);
865     clip0dev->updateRise(state);
866     clip1dev->updateRise(state);
867     gfxdev->updateRise(state);
868 }
869 void BitmapOutputDev::updateWordSpace(GfxState *state)
870 {
871     boolpolydev->updateWordSpace(state);
872     booltextdev->updateWordSpace(state);
873     rgbdev->updateWordSpace(state);
874     clip0dev->updateWordSpace(state);
875     clip1dev->updateWordSpace(state);
876     gfxdev->updateWordSpace(state);
877 }
878 void BitmapOutputDev::updateHorizScaling(GfxState *state)
879 {
880     boolpolydev->updateHorizScaling(state);
881     booltextdev->updateHorizScaling(state);
882     rgbdev->updateHorizScaling(state);
883     clip0dev->updateHorizScaling(state);
884     clip1dev->updateHorizScaling(state);
885     gfxdev->updateHorizScaling(state);
886 }
887 void BitmapOutputDev::updateTextPos(GfxState *state)
888 {
889     boolpolydev->updateTextPos(state);
890     booltextdev->updateTextPos(state);
891     rgbdev->updateTextPos(state);
892     clip0dev->updateTextPos(state);
893     clip1dev->updateTextPos(state);
894     gfxdev->updateTextPos(state);
895 }
896 void BitmapOutputDev::updateTextShift(GfxState *state, double shift)
897 {
898     boolpolydev->updateTextShift(state, shift);
899     booltextdev->updateTextShift(state, shift);
900     rgbdev->updateTextShift(state, shift);
901     clip0dev->updateTextShift(state, shift);
902     clip1dev->updateTextShift(state, shift);
903     gfxdev->updateTextShift(state, shift);
904 }
905
906 void BitmapOutputDev::stroke(GfxState *state)
907 {
908     msg("<debug> stroke");
909     boolpolydev->stroke(state);
910     checkNewBitmap();
911     rgbdev->stroke(state);
912 }
913 void BitmapOutputDev::fill(GfxState *state)
914 {
915     msg("<debug> fill");
916     boolpolydev->fill(state);
917     checkNewBitmap();
918     rgbdev->fill(state);
919 }
920 void BitmapOutputDev::eoFill(GfxState *state)
921 {
922     msg("<debug> eoFill");
923     boolpolydev->eoFill(state);
924     checkNewBitmap();
925     rgbdev->eoFill(state);
926 }
927 #if (xpdfMajorVersion*10000 + xpdfMinorVersion*100 + xpdfUpdateVersion) < 30207
928 void BitmapOutputDev::tilingPatternFill(GfxState *state, Object *str,
929                                int paintType, Dict *resDict,
930                                double *mat, double *bbox,
931                                int x0, int y0, int x1, int y1,
932                                double xStep, double yStep)
933 {
934     msg("<debug> tilingPatternFill");
935     boolpolydev->tilingPatternFill(state, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep);
936     checkNewBitmap();
937     rgbdev->tilingPatternFill(state, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep);
938 }
939 #else
940 void BitmapOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Object *str,
941                                int paintType, Dict *resDict,
942                                double *mat, double *bbox,
943                                int x0, int y0, int x1, int y1,
944                                double xStep, double yStep) 
945 {
946     msg("<debug> tilingPatternFill");
947     boolpolydev->tilingPatternFill(state, gfx, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep);
948     checkNewBitmap();
949     rgbdev->tilingPatternFill(state, gfx, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep);
950 }
951 #endif
952
953 GBool BitmapOutputDev::functionShadedFill(GfxState *state, GfxFunctionShading *shading) 
954 {
955     msg("<debug> functionShadedFill");
956     boolpolydev->functionShadedFill(state, shading);
957     checkNewBitmap();
958     return rgbdev->functionShadedFill(state, shading);
959 }
960 GBool BitmapOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading)
961 {
962     msg("<debug> axialShadedFill");
963     boolpolydev->axialShadedFill(state, shading);
964     checkNewBitmap();
965     return rgbdev->axialShadedFill(state, shading);
966 }
967 GBool BitmapOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading)
968 {
969     msg("<debug> radialShadedFill");
970     boolpolydev->radialShadedFill(state, shading);
971     checkNewBitmap();
972     return rgbdev->radialShadedFill(state, shading);
973 }
974
975 SplashColor black = {0,0,0};
976 SplashColor white = {255,255,255};
977
978 void BitmapOutputDev::clip(GfxState *state)
979 {
980     msg("<debug> clip");
981     boolpolydev->clip(state);
982     booltextdev->clip(state);
983     rgbdev->clip(state);
984     clip1dev->clip(state);
985 }
986 void BitmapOutputDev::eoClip(GfxState *state)
987 {
988     msg("<debug> eoClip");
989     boolpolydev->eoClip(state);
990     booltextdev->eoClip(state);
991     rgbdev->eoClip(state);
992     clip1dev->eoClip(state);
993 }
994 void BitmapOutputDev::clipToStrokePath(GfxState *state)
995 {
996     msg("<debug> clipToStrokePath");
997     boolpolydev->clipToStrokePath(state);
998     booltextdev->clipToStrokePath(state);
999     rgbdev->clipToStrokePath(state);
1000     clip1dev->clipToStrokePath(state);
1001 }
1002
1003 void BitmapOutputDev::beginStringOp(GfxState *state)
1004 {
1005     msg("<debug> beginStringOp");
1006     clip0dev->beginStringOp(state);
1007     clip1dev->beginStringOp(state);
1008     booltextdev->beginStringOp(state);
1009     gfxdev->beginStringOp(state);
1010 }
1011 void BitmapOutputDev::endStringOp(GfxState *state)
1012 {
1013     msg("<debug> endStringOp");
1014     clip0dev->endStringOp(state);
1015     clip1dev->endStringOp(state);
1016     booltextdev->endStringOp(state);
1017     checkNewText();
1018     gfxdev->endStringOp(state);
1019 }
1020 void BitmapOutputDev::beginString(GfxState *state, GString *s)
1021 {
1022     msg("<debug> beginString");
1023     clip0dev->beginString(state, s);
1024     clip1dev->beginString(state, s);
1025     booltextdev->beginString(state, s);
1026     gfxdev->beginString(state, s);
1027 }
1028 void BitmapOutputDev::endString(GfxState *state)
1029 {
1030     msg("<debug> endString");
1031     clip0dev->endString(state);
1032     clip1dev->endString(state);
1033     booltextdev->endString(state);
1034     checkNewText();
1035     gfxdev->endString(state);
1036 }
1037
1038 void BitmapOutputDev::clearClips()
1039 {
1040     clearBooleanDev(clip0dev);
1041     clearBooleanDev(clip1dev);
1042 }
1043 void BitmapOutputDev::clearBoolPolyDev()
1044 {
1045     clearBooleanDev(boolpolydev);
1046 }
1047 void BitmapOutputDev::clearBoolTextDev()
1048 {
1049     clearBooleanDev(booltextdev);
1050 }
1051 void BitmapOutputDev::drawChar(GfxState *state, double x, double y,
1052                       double dx, double dy,
1053                       double originX, double originY,
1054                       CharCode code, int nBytes, Unicode *u, int uLen)
1055 {
1056     msg("<debug> drawChar");
1057     if(state->getRender()&4 /*clip*/ ) {
1058         rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1059     } else {
1060         clearClips();
1061         clip0dev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1062         clip1dev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1063
1064         /* if this character is affected somehow by the various clippings (i.e., it looks
1065            different on a device without clipping), then draw it on the bitmap, not as
1066            text */
1067         if(clip0and1differ()) {
1068             msg("<verbose> Char %d is affected by clipping", code);
1069             boolpolydev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1070             checkNewBitmap();
1071             rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1072             if(config_extrafontdata) {
1073                 int oldrender = state->getRender();
1074                 state->setRender(3); //invisible
1075                 gfxdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1076                 state->setRender(oldrender);
1077             }
1078         } else {
1079             /* this char is not at all affected by clipping. 
1080                Now just dump out the bitmap we're currently working on, if necessary. */
1081             booltextdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1082             checkNewText();
1083             /* use polygonal output device to do the actual text handling */
1084             gfxdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1085         }
1086     }
1087 }
1088 void BitmapOutputDev::drawString(GfxState *state, GString *s)
1089 {
1090     msg("<error> internal error: drawString not implemented");
1091     return;
1092     clip0dev->drawString(state, s);
1093     clip1dev->drawString(state, s);
1094     booltextdev->drawString(state, s);
1095     gfxdev->drawString(state, s);
1096 }
1097 void BitmapOutputDev::endTextObject(GfxState *state)
1098 {
1099     msg("<debug> endTextObject");
1100     clip0dev->endTextObject(state);
1101     clip1dev->endTextObject(state);
1102     booltextdev->endTextObject(state);
1103     checkNewText();
1104     gfxdev->endTextObject(state);
1105 }
1106
1107 /* TODO: these four operations below *should* do nothing, as type3
1108          chars are drawn using operations like fill() */
1109 GBool BitmapOutputDev::beginType3Char(GfxState *state, double x, double y,
1110                              double dx, double dy,
1111                              CharCode code, Unicode *u, int uLen)
1112 {
1113     msg("<debug> beginType3Char");
1114     /* call gfxdev so that it can generate "invisible" characters
1115        on top of the actual graphic content, for text extraction */
1116     return gfxdev->beginType3Char(state, x, y, dx, dy, code, u, uLen);
1117 }
1118 void BitmapOutputDev::type3D0(GfxState *state, double wx, double wy)
1119 {
1120     msg("<debug> type3D0");
1121     return gfxdev->type3D0(state, wx, wy);
1122 }
1123 void BitmapOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury)
1124 {
1125     msg("<debug> type3D1");
1126     return gfxdev->type3D1(state, wx, wy, llx, lly, urx, ury);
1127 }
1128 void BitmapOutputDev::endType3Char(GfxState *state)
1129 {
1130     msg("<debug> endType3Char");
1131     gfxdev->endType3Char(state);
1132 }
1133 void BitmapOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
1134                            int width, int height, GBool invert,
1135                            GBool inlineImg)
1136 {
1137     msg("<debug> drawImageMask");
1138     boolpolydev->drawImageMask(state, ref, str, width, height, invert, inlineImg);
1139     checkNewBitmap();
1140     rgbdev->drawImageMask(state, ref, str, width, height, invert, inlineImg);
1141 }
1142 void BitmapOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
1143                        int width, int height, GfxImageColorMap *colorMap,
1144                        int *maskColors, GBool inlineImg)
1145 {
1146     msg("<debug> drawImage");
1147     boolpolydev->drawImage(state, ref, str, width, height, colorMap, maskColors, inlineImg);
1148     checkNewBitmap();
1149     rgbdev->drawImage(state, ref, str, width, height, colorMap, maskColors, inlineImg);
1150 }
1151 void BitmapOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
1152                              int width, int height,
1153                              GfxImageColorMap *colorMap,
1154                              Stream *maskStr, int maskWidth, int maskHeight,
1155                              GBool maskInvert)
1156 {
1157     msg("<debug> drawMaskedImage");
1158     boolpolydev->drawMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert);
1159     checkNewBitmap();
1160     rgbdev->drawMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert);
1161 }
1162 void BitmapOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
1163                                  int width, int height,
1164                                  GfxImageColorMap *colorMap,
1165                                  Stream *maskStr,
1166                                  int maskWidth, int maskHeight,
1167                                  GfxImageColorMap *maskColorMap)
1168 {
1169     msg("<debug> drawSoftMaskedImage");
1170     boolpolydev->drawSoftMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap);
1171     checkNewBitmap();
1172     rgbdev->drawSoftMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap);
1173 }
1174 void BitmapOutputDev::drawForm(Ref id)
1175 {
1176     msg("<debug> drawForm");
1177     boolpolydev->drawForm(id);
1178     checkNewBitmap();
1179     rgbdev->drawForm(id);
1180 }
1181
1182 void BitmapOutputDev::processLink(Link *link, Catalog *catalog)
1183 {
1184     msg("<debug> processLink");
1185     gfxdev->processLink(link, catalog);
1186 }
1187
1188 void BitmapOutputDev::beginTransparencyGroup(GfxState *state, double *bbox,
1189                                     GfxColorSpace *blendingColorSpace,
1190                                     GBool isolated, GBool knockout,
1191                                     GBool forSoftMask)
1192 {
1193     msg("<debug> beginTransparencyGroup");
1194     GfxState*state1 = state->copy(gTrue);
1195     GfxState*state2 = state->copy(gTrue);
1196     boolpolydev->beginTransparencyGroup(state1, bbox, blendingColorSpace, isolated, knockout, forSoftMask);
1197     rgbdev->beginTransparencyGroup(state2, bbox, blendingColorSpace, isolated, knockout, forSoftMask);
1198     clip1dev->beginTransparencyGroup(state, bbox, blendingColorSpace, isolated, knockout, forSoftMask);
1199     delete state1;
1200     delete state2;
1201 }
1202 void BitmapOutputDev::endTransparencyGroup(GfxState *state)
1203 {
1204     msg("<debug> endTransparencyGroup");
1205     GfxState*state1 = state->copy(gTrue);
1206     GfxState*state2 = state->copy(gTrue);
1207     boolpolydev->endTransparencyGroup(state1);
1208     checkNewBitmap();
1209     rgbdev->endTransparencyGroup(state2);
1210     delete state1;
1211     delete state2;
1212     clip1dev->endTransparencyGroup(state);
1213 }
1214 void BitmapOutputDev::paintTransparencyGroup(GfxState *state, double *bbox)
1215 {
1216     msg("<debug> paintTransparencyGroup");
1217     boolpolydev->paintTransparencyGroup(state,bbox);
1218     checkNewBitmap();
1219     rgbdev->paintTransparencyGroup(state,bbox);
1220     clip1dev->paintTransparencyGroup(state,bbox);
1221 }
1222 void BitmapOutputDev::setSoftMask(GfxState *state, double *bbox, GBool alpha, Function *transferFunc, GfxColor *backdropColor)
1223 {
1224     msg("<debug> setSoftMask");
1225     boolpolydev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
1226     checkNewBitmap();
1227     rgbdev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
1228     clip1dev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
1229 }
1230 void BitmapOutputDev::clearSoftMask(GfxState *state)
1231 {
1232     msg("<debug> clearSoftMask");
1233     boolpolydev->clearSoftMask(state);
1234     checkNewBitmap();
1235     rgbdev->clearSoftMask(state);
1236     clip1dev->clearSoftMask(state);
1237 }