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