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