poppler: fix drawImage*() parameters
[swftools.git] / lib / pdf / BitmapOutputDev.cc
1 /* InfoOutputDev.h
2
3    Output Device which creates a bitmap.
4
5    Swftools is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    Swftools is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with swftools; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <memory.h>
22 #include <assert.h>
23 #include "BitmapOutputDev.h"
24 #include "GFXOutputDev.h"
25
26 #ifdef HAVE_POPPLER
27   #include "splash/SplashBitmap.h"
28   #include "splash/SplashPattern.h"
29   #include "splash/Splash.h"
30 #else
31   #include "xpdf/config.h"
32   #include "SplashBitmap.h"
33   #include "SplashPattern.h"
34   #include "Splash.h"
35 #endif
36
37 #include "../log.h"
38 #include "../png.h"
39 #include "../devices/record.h"
40 #include "../gfxtools.h"
41 #include "../types.h"
42 #include "bbox.h"
43
44 #define UNKNOWN_BOUNDING_BOX 0,0,0,0
45
46 static SplashColor splash_white = {255,255,255};
47 static SplashColor splash_black = {0,0,0};
48     
49 ClipState::ClipState()
50 {
51     this->next = 0;
52     this->clipbitmap = 0;
53     this->written = 0;
54 }
55
56 BitmapOutputDev::BitmapOutputDev(InfoOutputDev*info, PDFDoc*doc)
57 {
58     this->info = info;
59     this->doc = doc;
60     this->xref = doc->getXRef();
61     
62     /* color graphic output device, for creating bitmaps */
63     this->rgbdev = new SplashOutputDev(splashModeRGB8, 1, gFalse, splash_white, gTrue, gTrue);
64   
65     /* color mode for binary bitmaps */
66     SplashColorMode colorMode = splashModeMono1;
67
68     /* two devices for testing things against clipping: one clips, the other doesn't */
69     this->clip0dev = new SplashOutputDev(colorMode, 1, gFalse, splash_black, gTrue, gFalse);
70     this->clip1dev = new SplashOutputDev(colorMode, 1, gFalse, splash_black, gTrue, gFalse);
71     
72     /* device indicating where polygonal pixels were drawn */
73     this->boolpolydev = new SplashOutputDev(colorMode, 1, gFalse, splash_black, gTrue, gFalse);
74     /* device indicating where text pixels were drawn */
75     this->booltextdev = new SplashOutputDev(colorMode, 1, gFalse, splash_black, gTrue, gFalse);
76
77     /* device for handling texts and links */
78     this->gfxdev = new GFXOutputDev(info, this->doc);
79
80     this->rgbdev->startDoc(this->xref);
81     this->boolpolydev->startDoc(this->xref);
82     this->booltextdev->startDoc(this->xref);
83     this->clip0dev->startDoc(this->xref);
84     this->clip1dev->startDoc(this->xref);
85
86     this->gfxoutput = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
87     gfxdevice_record_init(this->gfxoutput, 0);
88
89     this->gfxdev->setDevice(this->gfxoutput);
90     
91     this->config_extrafontdata = 0;
92     this->config_optimizeplaincolorfills = 0;
93     this->bboxpath = 0;
94     //this->clipdev = 0;
95     //this->clipstates = 0;
96 }
97 BitmapOutputDev::~BitmapOutputDev()
98 {
99     if(this->gfxoutput) {
100         gfxresult_t*r = this->gfxoutput->finish(this->gfxoutput);
101         r->destroy(r);
102         free(this->gfxoutput);this->gfxoutput = 0;
103     }
104     if(this->bboxpath) {
105         delete this->bboxpath;this->bboxpath = 0;
106     }
107     if(this->rgbdev) {
108         delete this->rgbdev;this->rgbdev = 0;
109     }
110     if(this->gfxdev) {
111         delete this->gfxdev;this->gfxdev= 0;
112     }
113     if(this->boolpolydev) {
114         delete this->boolpolydev;this->boolpolydev = 0;
115     }
116     if(this->stalepolybitmap) {
117         delete this->stalepolybitmap;this->stalepolybitmap = 0;
118     }
119     if(this->staletextbitmap) {
120         delete this->staletextbitmap;this->staletextbitmap = 0;
121     }
122     if(this->booltextdev) {
123         delete this->booltextdev;this->booltextdev = 0;
124     }
125     if(this->clip0dev) {
126         delete this->clip0dev;this->clip0dev = 0;
127     }
128     if(this->clip1dev) {
129         delete this->clip1dev;this->clip1dev = 0;
130     }
131     //if(this->clipbitmap) {
132     //    delete this->clipbitmap;this->clipbitmap = 0;
133     //}
134     //if(this->clipdev) {
135     //    delete this->clipdev;this->clipdev = 0;
136     //}
137
138 }
139
140 GBool BitmapOutputDev::getVectorAntialias()
141 {
142     return this->rgbdev->getVectorAntialias();
143 }
144 void BitmapOutputDev::setVectorAntialias(GBool vaa)
145 {
146     this->rgbdev->setVectorAntialias(vaa);
147 }
148 void BitmapOutputDev::setDevice(gfxdevice_t*dev)
149 {
150     this->dev = dev;
151 }
152 void BitmapOutputDev::setMove(int x,int y)
153 {
154     this->gfxdev->setMove(x,y);
155     this->user_movex = x;
156     this->user_movey = y;
157 }
158 void BitmapOutputDev::setClip(int x1,int y1,int x2,int y2)
159 {
160     this->gfxdev->setClip(x1,y1,x2,y2);
161     this->user_clipx1 = x1;
162     this->user_clipy1 = y1;
163     this->user_clipx2 = x2;
164     this->user_clipy2 = y2;
165 }
166 void BitmapOutputDev::setParameter(const char*key, const char*value)
167 {
168     if(!strcmp(key, "extrafontdata")) {
169         this->config_extrafontdata = atoi(value);
170     }
171     this->gfxdev->setParameter(key, value);
172 }
173 void BitmapOutputDev::setPageMap(int*page2page, int num_pages)
174 {
175     this->gfxdev->setPageMap(page2page, num_pages);
176 }
177
178 void writeBitmap(SplashBitmap*bitmap, char*filename);
179 void writeAlpha(SplashBitmap*bitmap, char*filename);
180
181 static int dbg_btm_counter=1;
182
183 void BitmapOutputDev::flushBitmap()
184 {
185     int bitmap_width = rgbdev->getBitmapWidth();
186     int bitmap_height = rgbdev->getBitmapHeight();
187
188     if(sizeof(SplashColor)!=3) {
189         msg("<error> sizeof(SplashColor)!=3");
190         return;
191     }
192
193     /*static int counter=0;
194     if(!counter) {
195         writeBitmap(rgbdev->getBitmap(), "test.png");
196     } counter++;*/
197     
198     /*static int counter=0;
199     char filename[160];
200     sprintf(filename, "test%d.png", counter++);
201     writeBitmap(rgbbitmap, filename);*/
202     
203     SplashColorPtr rgb = rgbbitmap->getDataPtr();
204     Guchar*alpha = rgbbitmap->getAlphaPtr();
205     
206     Guchar*alpha2 = stalepolybitmap->getDataPtr();
207     int bitmap_width8 = (stalepolybitmap->getWidth()+7)/8;
208
209     /*char filename[80];
210     sprintf(filename, "flush%d_mask.png", dbg_btm_counter);
211     writeAlpha(stalepolybitmap, filename);
212     sprintf(filename, "flush%d_alpha.png", dbg_btm_counter);
213     writeAlpha(rgbbitmap, filename);
214     sprintf(filename, "flush%d_bitmap.png", dbg_btm_counter);
215     writeBitmap(rgbbitmap, filename);*/
216
217     ibbox_t pagebox = {-movex, -movey, -movex + this->width, -movey + this->height, 0};
218     ibbox_t bitmapbox = {0, 0, bitmap_width, bitmap_height, 0};
219     ibbox_t c = ibbox_clip(&bitmapbox, &pagebox);
220     ibbox_t* boxes = get_bitmap_bboxes((unsigned char*)(alpha+c.ymin*bitmap_width+c.xmin), c.xmax - c.xmin, c.ymax - c.ymin, bitmap_width);
221
222     ibbox_t*b;
223     for(b=boxes;b;b=b->next) {
224         int xmin = b->xmin - this->movex;
225         int ymin = b->ymin - this->movey;
226         int xmax = b->xmax - this->movex;
227         int ymax = b->ymax - this->movey;
228
229         /* clip against (-movex, -movey, -movex+width, -movey+height) */
230
231         msg("<verbose> Flushing bitmap (bbox: %d,%d,%d,%d %dx%d) (clipped against %d,%d,%d,%d)", xmin,ymin,xmax,ymax, xmax-xmin, ymax-ymin,
232                 -this->movex, -this->movey, -this->movex+this->width, -this->movey+this->height);
233
234         if(xmin < -this->movex) {
235             xmin = -this->movex;
236             if(xmax < -this->movex) continue;
237         }
238         if(ymin < -this->movey) {
239             ymin = -this->movey;
240             if(ymax < -this->movey) continue;
241         }
242         if(xmax >= -this->movex + this->width) {
243             xmax = -this->movex+this->width;
244             if(xmin >= -this->movex + this->width) continue;
245         }
246         if(ymax >= -this->movey + this->height) {
247             ymax = -this->movey+this->height;
248             if(ymin >= -this->movey + this->height) continue;
249         }
250         
251         if((xmax-xmin)<=0 || (ymax-ymin)<=0) // no bitmap, nothing to do
252             continue;
253
254         int rangex = xmax-xmin;
255         int rangey = ymax-ymin;
256         gfximage_t*img = (gfximage_t*)malloc(sizeof(gfximage_t)); 
257         img->data = (gfxcolor_t*)malloc(rangex * rangey * 4);
258         img->width = rangex;
259         img->height = rangey;
260         int x,y;
261         for(y=0;y<rangey;y++) {
262             SplashColorPtr in=&rgb[((y+ymin)*bitmap_width+xmin)*sizeof(SplashColor)];
263             gfxcolor_t*out = &img->data[y*rangex];
264             Guchar*ain = &alpha[(y+ymin)*bitmap_width+xmin];
265             Guchar*ain2 = &alpha2[(y+ymin)*bitmap_width8];
266             if(this->emptypage) {
267                 for(x=0;x<rangex;x++) {
268                     /* the first bitmap on the page doesn't need to have an alpha channel-
269                        blend against a white background*/
270                     out[x].r = (in[x*3+0]*ain[x])/255 + 255-ain[x];
271                     out[x].g = (in[x*3+1]*ain[x])/255 + 255-ain[x];
272                     out[x].b = (in[x*3+2]*ain[x])/255 + 255-ain[x];
273                     out[x].a = 255;
274                 }
275             } else {
276                 for(x=0;x<rangex;x++) {
277                     if(!(ain2[(x+xmin)/8]&(0x80>>((x+xmin)&7)))) {
278                         /* cut away pixels that we don't remember drawing (i.e., that are
279                            not in the monochrome bitmap). Prevents some "hairlines" showing
280                            up to the left and right of bitmaps. */
281                         out[x].r = 0;out[x].g = 0;out[x].b = 0;out[x].a = 0;
282                     } else {
283                         /* according to endPage()/compositeBackground() in xpdf/SplashOutputDev.cc, this
284                            data has non-premultiplied alpha, which is exactly what the output device 
285                            expects, so don't premultiply it here, either.
286                         */
287                         out[x].r = in[x*3+0];
288                         out[x].g = in[x*3+1];
289                         out[x].b = in[x*3+2];
290                         out[x].a = ain[x];
291                     }
292                 }
293             }
294         }
295
296         /* transform bitmap rectangle to "device space" */
297         xmin += movex;
298         ymin += movey;
299         xmax += movex;
300         ymax += movey;
301
302         gfxmatrix_t m;
303         m.tx = xmin;
304         m.ty = ymin;
305         m.m00 = m.m11 = 1;
306         m.m10 = m.m01 = 0;
307         m.tx -= 0.5;
308         m.ty -= 0.5;
309
310         gfxline_t* line = gfxline_makerectangle(xmin, ymin, xmax, ymax);
311         dev->fillbitmap(dev, line, img, &m, 0);
312         gfxline_free(line);
313     
314         free(img->data);img->data=0;free(img);img=0;
315     }
316     ibbox_destroy(boxes);
317
318     memset(rgbbitmap->getAlphaPtr(), 0, rgbbitmap->getWidth()*rgbbitmap->getHeight());
319     memset(rgbbitmap->getDataPtr(), 0, rgbbitmap->getRowSize()*rgbbitmap->getHeight());
320
321     this->emptypage = 0;
322 }
323
324 void BitmapOutputDev::flushText()
325 {
326     msg("<verbose> Flushing text");
327
328     static gfxfontlist_t*output_font_list = 0;
329     static gfxdevice_t*last = 0;
330     if(last != this->dev) {
331         if(output_font_list)
332             gfxfontlist_free(output_font_list, 0);
333         output_font_list = gfxfontlist_create();
334     }
335     gfxdevice_record_flush(this->gfxoutput, this->dev, &output_font_list);
336     last = this->dev;
337     
338     this->emptypage = 0;
339 }
340
341 void writeMonoBitmap(SplashBitmap*btm, char*filename)
342 {
343     int width8 = (btm->getWidth()+7)/8;
344     int width = btm->getWidth();
345     int height = btm->getHeight();
346     gfxcolor_t*b = (gfxcolor_t*)malloc(sizeof(gfxcolor_t)*width*height);
347     unsigned char*data = btm->getDataPtr();
348     int x,y;
349     for(y=0;y<height;y++) {
350         unsigned char*l = &data[width8*y];
351         gfxcolor_t*d = &b[width*y];
352         for(x=0;x<width;x++) {
353             if(l[x>>3]&(128>>(x&7))) {
354                 d[x].r = d[x].b = d[x].a = 255;
355                 d[x].g = 0;
356             } else {
357                 d[x].r = d[x].g = d[x].b = d[x].a = 0;
358             }
359         }
360     }
361     png_write(filename, (unsigned char*)b, width, height);
362     free(b);
363 }
364
365 void writeBitmap(SplashBitmap*bitmap, char*filename)
366 {
367     int y,x;
368     
369     int width = bitmap->getWidth();
370     int height = bitmap->getHeight();
371
372     gfxcolor_t*data = (gfxcolor_t*)malloc(sizeof(gfxcolor_t)*width*height);
373
374     if(bitmap->getMode()==splashModeMono1) {
375         writeMonoBitmap(bitmap, filename);
376         return;
377     }
378
379     for(y=0;y<height;y++) {
380         gfxcolor_t*line = &data[y*width];
381         for(x=0;x<width;x++) {
382             Guchar c[4] = {0,0,0,0};
383             bitmap->getPixel(x,y,c);
384             line[x].r = c[0];
385             line[x].g = c[1];
386             line[x].b = c[2];
387             line[x].a =  bitmap->getAlpha(x,y);
388         }
389     }
390     png_write(filename, (unsigned char*)data, width, height);
391     free(data);
392 }
393
394 void writeAlpha(SplashBitmap*bitmap, char*filename)
395 {
396     int y,x;
397     
398     int width = bitmap->getWidth();
399     int height = bitmap->getHeight();
400     
401     if(bitmap->getMode()==splashModeMono1) {
402         writeMonoBitmap(bitmap, filename);
403         return;
404     }
405
406     gfxcolor_t*data = (gfxcolor_t*)malloc(sizeof(gfxcolor_t)*width*height);
407
408     for(y=0;y<height;y++) {
409         gfxcolor_t*line = &data[y*width];
410         for(x=0;x<width;x++) {
411             int a = bitmap->getAlpha(x,y);
412             line[x].r = a;
413             line[x].g = 0;
414             line[x].b = a;
415             line[x].a = a;
416         }
417     }
418     png_write(filename, (unsigned char*)data, width, height);
419     free(data);
420 }
421
422 static const char*STATE_NAME[] = {"parallel", "textabovebitmap", "bitmapabovetext"};
423
424 int checkAlphaSanity(SplashBitmap*boolbtm, SplashBitmap*alphabtm)
425 {
426     assert(boolbtm->getWidth() == alphabtm->getWidth());
427     assert(boolbtm->getHeight() == alphabtm->getHeight());
428     if(boolbtm->getMode()==splashModeMono1) {
429         return 1;
430     }
431
432     int width = boolbtm->getWidth();
433     int height = boolbtm->getHeight();
434
435     int bad=0;
436     int x,y;
437     for(y=0;y<height;y++) {
438         for(x=0;x<width;x++) {
439             int a1 = alphabtm->getAlpha(x,y);
440             int a2 = boolbtm->getAlpha(x,y);
441             if(a1!=a2) {
442                 bad++;
443             }
444         }
445     }
446     double badness = bad/(double)(width*height);
447     if(badness>0.2) {
448         msg("<error> Bitmaps don't correspond: %d out of %d pixels wrong (%.2f%%)", bad, width*height, 
449                 badness*100.0);
450         return 0;
451     }
452     msg("<notice> %f", badness);
453     return 1;
454 }
455
456 static inline GBool fixBBox(int*x1, int*y1, int*x2, int*y2, int width, int height)
457 {
458     if(!(*x1|*y1|*x2|*y2)) {
459         // undefined bbox
460         *x1 = *y1 = 0;
461         *x2 = width;
462         *y2 = height;
463         return gTrue;
464     }
465     if(*x2<=*x1) return gFalse;
466     if(*x2<0) return gFalse;
467     if(*x1<0) *x1 = 0;
468     if(*x1>=width) return gFalse;
469     if(*x2>width) *x2=width;
470
471     if(*y2<=*y1) return gFalse;
472     if(*y2<0) return gFalse;
473     if(*y1<0) *y1 = 0;
474     if(*y1>=height) return gFalse;
475     if(*y2>height) *y2=height;
476     return gTrue;
477 }
478
479 static void update_bitmap(SplashBitmap*bitmap, SplashBitmap*update, int x1, int y1, int x2, int y2, char overwrite)
480 {
481     assert(bitmap->getMode()==splashModeMono1);
482     assert(update->getMode()==splashModeMono1);
483
484     int width8 = (bitmap->getWidth()+7)/8;
485     assert(width8 == bitmap->getRowSize());
486     assert(width8 == update->getRowSize());
487     int height = bitmap->getHeight();
488     assert(height == update->getHeight());
489
490     if(!fixBBox(&x1, &y1, &x2, &y2, bitmap->getWidth(), bitmap->getHeight()))
491         return;
492     
493     Guchar*b = bitmap->getDataPtr() + y1*width8 + x1/8;
494     Guchar*u = update->getDataPtr() + y1*width8 + x1/8;
495     int yspan = y2-y1;
496     int xspan = (x2+7)/8 - x1/8;
497     int size = (y2-y1)*width8;
498
499     if(overwrite) {
500         int y;
501         for(y=0;y<yspan;y++) {
502             memcpy(b, u, xspan);
503             b += width8;
504             u += width8;
505         }
506     } else {
507         if(((ptroff_t)b&7)==((ptroff_t)u&7)) {
508             int x,y;
509             for(y=0;y<yspan;y++) {
510                 Guchar*e1 = b+xspan-8;
511                 Guchar*e2 = b+xspan;
512                 while(((ptroff_t)b&7) && b<e1) {
513                     *b |= *u;
514                     b++;u++;
515                 }
516                 while(b<e1) {
517                     *(long long*)b |= *(long long*)u;
518                     b+=8;u+=8;
519                 }
520                 while(b<e2) {
521                     *b |= *u;
522                     b++;u++;
523                 }
524                 b += width8-xspan;
525                 u += width8-xspan;
526             }
527         } else {
528             int x,y;
529             for(y=0;y<yspan;y++) {
530                 for(x=0;x<xspan;x++) {
531                     b[x] |= u[x];
532                 }
533                 b += width8;
534                 u += width8;
535             }
536         }
537     }
538 }
539
540 static void clearBooleanBitmap(SplashBitmap*btm, int x1, int y1, int x2, int y2)
541 {
542     if(!fixBBox(&x1, &y1, &x2, &y2, btm->getWidth(), btm->getHeight()))
543         return;
544     
545     if(btm->getMode()==splashModeMono1) {
546         int width8 = (btm->getWidth()+7)/8;
547         assert(width8 == btm->getRowSize());
548         int width = btm->getWidth();
549         int height = btm->getHeight();
550         Guchar*data = btm->getDataPtr();
551         memset(data+y1*width8, 0, width8*(y2-y1));
552     } else {
553         int width = btm->getAlphaRowSize();
554         int height = btm->getHeight();
555         memset(btm->getAlphaPtr(), 0, width*height);
556     }
557 }
558
559 void BitmapOutputDev::dbg_newdata(char*newdata)
560 {
561     if(0) {
562         char filename1[80];
563         char filename2[80];
564         char filename3[80];
565         sprintf(filename1, "state%03dboolbitmap_after%s.png", dbg_btm_counter, newdata);
566         sprintf(filename2, "state%03dbooltext_after%s.png", dbg_btm_counter, newdata);
567         sprintf(filename3, "state%03dbitmap_after%s.png", dbg_btm_counter, newdata);
568         msg("<verbose> %s %s %s", filename1, filename2, filename3);
569         writeAlpha(stalepolybitmap, filename1);
570         writeAlpha(booltextbitmap, filename2);
571         writeBitmap(rgbdev->getBitmap(), filename3);
572     }
573     dbg_btm_counter++;
574 }
575
576 GBool BitmapOutputDev::checkNewText(int x1, int y1, int x2, int y2)
577 {
578     /* called once some new text was drawn on booltextdev, and
579        before the same thing is drawn on gfxdev */
580    
581     msg("<trace> Testing new text data against current bitmap data, state=%s, counter=%d\n", STATE_NAME[layerstate], dbg_btm_counter);
582     
583     GBool ret = false;
584     if(intersection(booltextbitmap, stalepolybitmap, x1,y1,x2,y2)) {
585         if(layerstate==STATE_PARALLEL) {
586             /* the new text is above the bitmap. So record that fact. */
587             msg("<verbose> Text is above current bitmap/polygon data");
588             layerstate=STATE_TEXT_IS_ABOVE;
589             update_bitmap(staletextbitmap, booltextbitmap, x1, y1, x2, y2, 0);
590         } else if(layerstate==STATE_BITMAP_IS_ABOVE) {
591             /* there's a bitmap above the (old) text. So we need
592                to flush out that text, and record that the *new*
593                text is now *above* the bitmap
594              */
595             msg("<verbose> Text is above current bitmap/polygon data (which is above some other text)");
596             flushText();
597             layerstate=STATE_TEXT_IS_ABOVE;
598            
599             clearBoolTextDev();
600             /* re-apply the update (which we would otherwise lose) */
601             update_bitmap(staletextbitmap, booltextbitmap, x1, y1, x2, y2, 1);
602             ret = true;
603         } else {
604             /* we already know that the current text section is
605                above the current bitmap section- now just new
606                bitmap data *and* new text data was drawn, and
607                *again* it's above the current bitmap. */
608             msg("<verbose> Text is still above current bitmap/polygon data");
609             update_bitmap(staletextbitmap, booltextbitmap, x1, y1, x2, y2, 0);
610         }
611     }  else {
612         update_bitmap(staletextbitmap, booltextbitmap, x1, y1, x2, y2, 0);
613     }
614     
615     /* clear the thing we just drew from our temporary drawing bitmap */
616     clearBooleanBitmap(booltextbitmap, x1, y1, x2, y2);
617
618     return ret;
619 }
620 GBool BitmapOutputDev::checkNewBitmap(int x1, int y1, int x2, int y2)
621 {
622     /* similar to checkNewText() above, only in reverse */
623     msg("<trace> Testing new graphics data against current text data, state=%s, counter=%d\n", STATE_NAME[layerstate], dbg_btm_counter);
624
625     GBool ret = false;
626     if(intersection(boolpolybitmap, staletextbitmap, x1,y1,x2,y2)) {
627         if(layerstate==STATE_PARALLEL) {
628             msg("<verbose> Bitmap is above current text data");
629             layerstate=STATE_BITMAP_IS_ABOVE;
630             update_bitmap(stalepolybitmap, boolpolybitmap, x1, y1, x2, y2, 0);
631         } else if(layerstate==STATE_TEXT_IS_ABOVE) {
632             msg("<verbose> Bitmap is above current text data (which is above some bitmap)");
633             flushBitmap();
634             layerstate=STATE_BITMAP_IS_ABOVE;
635             clearBoolPolyDev();
636             update_bitmap(stalepolybitmap, boolpolybitmap, x1, y1, x2, y2, 1);
637             ret = true;
638         } else {
639             msg("<verbose> Bitmap is still above current text data");
640             update_bitmap(stalepolybitmap, boolpolybitmap, x1, y1, x2, y2, 0);
641         }
642     }  else {
643         update_bitmap(stalepolybitmap, boolpolybitmap, x1, y1, x2, y2, 0);
644     }
645     
646     /* clear the thing we just drew from our temporary drawing bitmap */
647     clearBooleanBitmap(boolpolybitmap, x1, y1, x2, y2);
648
649     return ret;
650 }
651
652 //void checkNewText() {
653 //    Guchar*alpha = rgbbitmap->getAlphaPtr();
654 //    Guchar*charpixels = clip1bitmap->getDataPtr();
655 //    int xx,yy;
656 //    for(yy=0;yy<height;yy++) {
657 //        Guchar*aline = &alpha[yy*width];
658 //        Guchar*cline = &charpixels[yy*width8];
659 //        for(xx=0;xx<width;xx++) {
660 //            int bit = xx&7;
661 //            int bytepos = xx>>3;
662 //            /* TODO: is the bit order correct? */
663 //            if(aline[xx] && (cline[bytepos]&(1<<bit))) 
664 //              break;
665 //        }
666 //        if(xx!=width)
667 //            break;
668 //}
669
670 GBool BitmapOutputDev::clip0and1differ(int x1,int y1,int x2,int y2)
671 {
672     if(clip0bitmap->getMode()==splashModeMono1) {
673         int width = clip0bitmap->getWidth();
674         int width8 = (width+7)/8;
675         int height = clip0bitmap->getHeight();
676
677         if(!fixBBox(&x1,&y1,&x2,&y2,width,height)) {
678             /* area is outside or null */
679             return gFalse;
680         }
681         
682         SplashBitmap*clip0 = clip0bitmap;
683         SplashBitmap*clip1 = clip1bitmap;
684         int x18 = x1/8;
685         int x28 = (x2+7)/8;
686         int y;
687
688         for(y=y1;y<y2;y++) {
689             unsigned char*row1 = &clip0bitmap->getDataPtr()[width8*y+x18];
690             unsigned char*row2 = &clip1bitmap->getDataPtr()[width8*y+x18];
691             if(memcmp(row1, row2, x28-x18)) {
692                 return gTrue;
693             }
694         }
695         return gFalse;
696     } else {
697         SplashBitmap*clip0 = clip0bitmap;
698         SplashBitmap*clip1 = clip1bitmap;
699         int width = clip0->getAlphaRowSize();
700         int height = clip0->getHeight();
701
702         if(!fixBBox(&x1, &y1, &x2, &y2, width, height)) {
703             x1=y1=0;x2=y2=1;
704         }
705
706         Guchar*a0 = clip0->getAlphaPtr();
707         Guchar*a1 = clip1->getAlphaPtr();
708         int x,y;
709         char differs=0;
710         for(y=y1;y<y2;y++) {
711             for(x=x1;x<x2;x++) {
712                 if(a0[y*width+x]!=a1[y*width+x]) {
713                     differs=1;
714                     break;
715                 }
716             }
717             if(differs)
718                 break;
719         }
720         char differs2 = memcmp(a0, a1, width*height);
721         if(differs && !differs2) 
722             msg("<warning> Strange internal error (2)");
723         else if(!differs && differs2) {
724             msg("<warning> Bad Bounding Box: Difference in clip0 and clip1 outside bbox");
725             msg("<warning> %d %d %d %d", x1, y1, x2, y2);
726         }
727         return differs2;
728     }
729 }
730
731 GBool compare8(unsigned char*data1, unsigned char*data2, int len)
732 {
733     if(!len)
734         return 0;
735     if(((ptroff_t)data1&7)==((ptroff_t)data2&7)) {
736         // oh good, we can align both to 8 byte
737         while((ptroff_t)data1&7) {
738             if(*data1&*data2)
739                 return 1;
740             data1++;
741             data2++;
742             if(!--len)
743                 return 0;
744         }
745     }
746     /* use 64 bit for the (hopefully aligned) middle section */
747     int l8 = len/8;
748     long long unsigned int*d1 = (long long unsigned int*)data1;
749     long long unsigned int*d2 = (long long unsigned int*)data2;
750     long long unsigned int x = 0;
751     int t;
752     for(t=0;t<l8;t++) {
753         x |= d1[t]&d2[t];
754     }
755     if(x)
756         return 1;
757
758     data1+=l8*8;
759     data2+=l8*8;
760     len -= l8*8;
761     for(t=0;t<len;t++) {
762         if(data1[t]&data2[t]) {
763             return 1;
764         }
765     }
766     return 0;
767 }
768
769 GBool BitmapOutputDev::intersection(SplashBitmap*boolpoly, SplashBitmap*booltext, int x1, int y1, int x2, int y2)
770 {
771     if(boolpoly->getMode()==splashModeMono1) {
772         /* alternative implementation, using one bit per pixel-
773            needs the no-dither patch in xpdf */
774         
775         int width = boolpoly->getWidth();
776         int height = boolpoly->getHeight();
777
778         if(!fixBBox(&x1,&y1,&x2,&y2, width, height)) {
779             return gFalse;
780         }
781
782         Guchar*polypixels = boolpoly->getDataPtr();
783         Guchar*textpixels = booltext->getDataPtr();
784
785         int width8 = (width+7)/8;
786         int runx = width8;
787         int runy = height;
788         
789         if(x1|y1|x2|y2) {
790             polypixels+=y1*width8+x1/8;
791             textpixels+=y1*width8+x1/8;
792             runx=(x2+7)/8 - x1/8;
793             runy=y2-y1;
794         }
795         
796         int t;
797         unsigned char c=0;
798         
799         /*assert(sizeof(unsigned long long int)==8);
800         if(((ptroff_t)polypixels&7) || ((ptroff_t)textpixels&7)) {
801             //msg("<warning> Non-optimal alignment");
802         }*/
803
804         int x,y;
805         unsigned char*data1 = (unsigned char*)polypixels;
806         unsigned char*data2 = (unsigned char*)textpixels;
807         msg("<verbose> Testing area (%d,%d,%d,%d), runx=%d,runy=%d", x1,y1,x2,y2, runx, runy);
808         for(y=0;y<runy;y++) {
809             if(compare8(data1,data2,runx))
810                 return gTrue;
811             data1+=width8;
812             data2+=width8;
813         }
814         return gFalse;
815     } else {
816         int width = boolpoly->getAlphaRowSize();
817         int height = boolpoly->getHeight();
818
819         if(!fixBBox(&x1, &y1, &x2, &y2, width, height)) {
820             x1=y1=0;x2=y2=1;
821         }
822         Guchar*polypixels = boolpoly->getAlphaPtr();
823         Guchar*textpixels = booltext->getAlphaPtr();
824
825         int x,y;
826         char overlap1 = 0;
827         char overlap2 = 0;
828         for(x=x1;x<x2;x++) {
829             for(y=y1;y<y2;y++) {
830                 if(polypixels[width*y+x]&&textpixels[width*y+x])
831                     overlap1 = 1;
832             }
833         }
834         int ax1=0,ay1=0,ax2=0,ay2=0;
835         for(y=0;y<height;y++) {
836             for(x=0;x<width;x++) {
837                 if(polypixels[width*y+x]&&textpixels[width*y+x]) {
838                     overlap2 = 1;
839                     if(!(ax1|ay1|ax2|ay2)) {
840                         ax1 = ax2 = x;
841                         ay1 = ay2 = y;
842                     } else {
843                         ax1 = ax1<x?ax1:x;
844                         ay1 = ay1<y?ay1:y;
845                         ax2 = ax2>x?ax2:x;
846                         ay2 = ay2>y?ay2:y;
847                     }
848                 }
849             }
850         }
851         if(overlap1 && !overlap2)
852             msg("<warning> strange internal error");
853         if(!overlap1 && overlap2) {
854             msg("<warning> Bad bounding box: intersection outside bbox");
855             msg("<warning> given bbox: %d %d %d %d", x1, y1, x2, y2);
856             msg("<warning> changed area: %d %d %d %d", ax1, ay1, ax2, ay2);
857         }
858         return overlap2;
859     }
860 }
861
862 GBool BitmapOutputDev::checkPageSlice(Page *page, double hDPI, double vDPI,
863              int rotate, GBool useMediaBox, GBool crop,
864              int sliceX, int sliceY, int sliceW, int sliceH,
865              GBool printing, Catalog *catalog,
866              GBool (*abortCheckCbk)(void *data),
867              void *abortCheckCbkData)
868 {
869     this->setPage(page);
870     gfxdev->setPage(page);
871     return gTrue;
872 }
873
874 void BitmapOutputDev::startPage(int pageNum, GfxState *state)
875 {
876     PDFRectangle *r = this->page->getCropBox();
877     double x1,y1,x2,y2;
878     state->transform(r->x1,r->y1,&x1,&y1);
879     state->transform(r->x2,r->y2,&x2,&y2);
880     if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
881     if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
882     
883     this->movex = -(int)x1 - user_movex;
884     this->movey = -(int)y1 - user_movey;
885     
886     if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
887         x1 = user_clipx1;
888         x2 = user_clipx2;
889         y1 = user_clipy1;
890         y2 = user_clipy2;
891     }
892     this->width = (int)(x2-x1);
893     this->height = (int)(y2-y1);
894
895     rgbdev->startPage(pageNum, state);
896     boolpolydev->startPage(pageNum, state);
897     booltextdev->startPage(pageNum, state);
898     clip0dev->startPage(pageNum, state);
899     clip1dev->startPage(pageNum, state);
900     gfxdev->startPage(pageNum, state);
901
902     boolpolybitmap = boolpolydev->getBitmap();
903     stalepolybitmap = new SplashBitmap(boolpolybitmap->getWidth(), boolpolybitmap->getHeight(), 1, boolpolybitmap->getMode(), 0);
904     assert(stalepolybitmap->getRowSize() == boolpolybitmap->getRowSize());
905
906     booltextbitmap = booltextdev->getBitmap();
907     staletextbitmap = new SplashBitmap(booltextbitmap->getWidth(), booltextbitmap->getHeight(), 1, booltextbitmap->getMode(), 0);
908     assert(staletextbitmap->getRowSize() == booltextbitmap->getRowSize());
909     
910     msg("<debug> startPage %dx%d (%dx%d)", this->width, this->height, booltextbitmap->getWidth(), booltextbitmap->getHeight());
911
912     clip0bitmap = clip0dev->getBitmap();
913     clip1bitmap = clip1dev->getBitmap();
914     rgbbitmap = rgbdev->getBitmap();
915     
916     flushText(); // write out the initial clipping rectangle
917
918     /* just in case any device did draw a white background rectangle 
919        into the device */
920     clearBoolTextDev();
921     clearBoolPolyDev();
922
923     this->layerstate = STATE_PARALLEL;
924     this->emptypage = 1;
925     msg("<debug> startPage done");
926 }
927
928 void BitmapOutputDev::endPage()
929 {
930     msg("<verbose> endPage (BitmapOutputDev)");
931
932     /* notice: we're not fully done yet with this page- there might still be 
933        a few calls to drawLink() yet to come */
934 }
935 void BitmapOutputDev::finishPage()
936 {
937     msg("<verbose> finishPage (BitmapOutputDev)");
938     gfxdev->endPage();
939    
940     flushEverything();
941
942     /* splash will now destroy alpha, and paint the 
943        background color into the "holes" in the bitmap */
944     boolpolydev->endPage();
945     booltextdev->endPage();
946     rgbdev->endPage();
947     clip0dev->endPage();
948     clip1dev->endPage();
949 }
950
951 GBool BitmapOutputDev::upsideDown()
952 {
953     boolpolydev->upsideDown();
954     booltextdev->upsideDown();
955     clip0dev->upsideDown();
956     clip1dev->upsideDown();
957     return rgbdev->upsideDown();
958 }
959
960 GBool BitmapOutputDev::useDrawChar()
961 {
962     boolpolydev->useDrawChar();
963     booltextdev->useDrawChar();
964     clip0dev->useDrawChar();
965     clip1dev->useDrawChar();
966     return rgbdev->useDrawChar();
967 }
968
969 GBool BitmapOutputDev::useTilingPatternFill()
970 {
971     boolpolydev->useTilingPatternFill();
972     booltextdev->useTilingPatternFill();
973     clip0dev->useTilingPatternFill();
974     clip1dev->useTilingPatternFill();
975     return rgbdev->useTilingPatternFill();
976 }
977
978 GBool BitmapOutputDev::useShadedFills()
979 {
980     boolpolydev->useShadedFills();
981     booltextdev->useShadedFills();
982     clip0dev->useShadedFills();
983     clip1dev->useShadedFills();
984     return rgbdev->useShadedFills();
985 }
986
987 GBool BitmapOutputDev::useDrawForm()
988 {
989     boolpolydev->useDrawForm();
990     booltextdev->useDrawForm();
991     clip0dev->useDrawForm();
992     clip1dev->useDrawForm();
993     return rgbdev->useDrawForm();
994 }
995
996 GBool BitmapOutputDev::interpretType3Chars()
997 {
998     boolpolydev->interpretType3Chars();
999     booltextdev->interpretType3Chars();
1000     clip0dev->interpretType3Chars();
1001     clip1dev->interpretType3Chars();
1002     return rgbdev->interpretType3Chars();
1003 }
1004
1005 GBool BitmapOutputDev::needNonText() 
1006 {
1007     boolpolydev->needNonText();
1008     booltextdev->needNonText();
1009     clip0dev->needNonText();
1010     clip1dev->needNonText();
1011     return rgbdev->needNonText();
1012 }
1013 void BitmapOutputDev::setDefaultCTM(double *ctm) 
1014 {
1015     boolpolydev->setDefaultCTM(ctm);
1016     booltextdev->setDefaultCTM(ctm);
1017     rgbdev->setDefaultCTM(ctm);
1018     clip0dev->setDefaultCTM(ctm);
1019     clip1dev->setDefaultCTM(ctm);
1020     gfxdev->setDefaultCTM(ctm);
1021 }
1022 void BitmapOutputDev::saveState(GfxState *state) 
1023 {
1024     boolpolydev->saveState(state);
1025     booltextdev->saveState(state);
1026     rgbdev->saveState(state);
1027     clip0dev->saveState(state);
1028     clip1dev->saveState(state);
1029
1030     /*ClipState*cstate = new ClipState();
1031     cstate->next = this->clipstates;
1032     this->clipstates = cstate;*/
1033 }
1034 void BitmapOutputDev::restoreState(GfxState *state) 
1035 {
1036     boolpolydev->restoreState(state);
1037     booltextdev->restoreState(state);
1038     rgbdev->restoreState(state);
1039     clip0dev->restoreState(state);
1040     clip1dev->restoreState(state);
1041
1042     /*if(this->clipstates) {
1043         ClipState*old = this->clipstates;
1044         if(old->written) {
1045             gfxdev->restoreState(state);
1046         }
1047         this->clipstates = this->clipstates->next;
1048         delete(old);
1049     } else {
1050         msg("<error> invalid restoreState()");
1051     }*/
1052 }
1053 void BitmapOutputDev::updateAll(GfxState *state)
1054 {
1055     boolpolydev->updateAll(state);
1056     booltextdev->updateAll(state);
1057     rgbdev->updateAll(state);
1058     clip0dev->updateAll(state);
1059     clip1dev->updateAll(state);
1060     gfxdev->updateAll(state);
1061 }
1062 void BitmapOutputDev::updateCTM(GfxState *state, double m11, double m12, double m21, double m22, double m31, double m32)
1063 {
1064     boolpolydev->updateCTM(state,m11,m12,m21,m22,m31,m32);
1065     booltextdev->updateCTM(state,m11,m12,m21,m22,m31,m32);
1066     rgbdev->updateCTM(state,m11,m12,m21,m22,m31,m32);
1067     clip0dev->updateCTM(state,m11,m12,m21,m22,m31,m32);
1068     clip1dev->updateCTM(state,m11,m12,m21,m22,m31,m32);
1069     gfxdev->updateCTM(state,m11,m12,m21,m22,m31,m32);
1070 }
1071 void BitmapOutputDev::updateLineDash(GfxState *state)
1072 {
1073     boolpolydev->updateLineDash(state);
1074     booltextdev->updateLineDash(state);
1075     rgbdev->updateLineDash(state);
1076     clip0dev->updateLineDash(state);
1077     clip1dev->updateLineDash(state);
1078     gfxdev->updateLineDash(state);
1079 }
1080 void BitmapOutputDev::updateFlatness(GfxState *state)
1081 {
1082     boolpolydev->updateFlatness(state);
1083     booltextdev->updateFlatness(state);
1084     rgbdev->updateFlatness(state);
1085     clip0dev->updateFlatness(state);
1086     clip1dev->updateFlatness(state);
1087     gfxdev->updateFlatness(state);
1088 }
1089 void BitmapOutputDev::updateLineJoin(GfxState *state)
1090 {
1091     boolpolydev->updateLineJoin(state);
1092     booltextdev->updateLineJoin(state);
1093     rgbdev->updateLineJoin(state);
1094     clip0dev->updateLineJoin(state);
1095     clip1dev->updateLineJoin(state);
1096     gfxdev->updateLineJoin(state);
1097 }
1098 void BitmapOutputDev::updateLineCap(GfxState *state)
1099 {
1100     boolpolydev->updateLineCap(state);
1101     booltextdev->updateLineCap(state);
1102     rgbdev->updateLineCap(state);
1103     clip0dev->updateLineCap(state);
1104     clip1dev->updateLineCap(state);
1105     gfxdev->updateLineCap(state);
1106 }
1107 void BitmapOutputDev::updateMiterLimit(GfxState *state)
1108 {
1109     boolpolydev->updateMiterLimit(state);
1110     booltextdev->updateMiterLimit(state);
1111     rgbdev->updateMiterLimit(state);
1112     clip0dev->updateMiterLimit(state);
1113     clip1dev->updateMiterLimit(state);
1114     gfxdev->updateMiterLimit(state);
1115 }
1116 void BitmapOutputDev::updateLineWidth(GfxState *state)
1117 {
1118     boolpolydev->updateLineWidth(state);
1119     booltextdev->updateLineWidth(state);
1120     rgbdev->updateLineWidth(state);
1121     clip0dev->updateLineWidth(state);
1122     clip1dev->updateLineWidth(state);
1123     gfxdev->updateLineWidth(state);
1124 }
1125 void BitmapOutputDev::updateStrokeAdjust(GfxState *state)
1126 {
1127     boolpolydev->updateStrokeAdjust(state);
1128     booltextdev->updateStrokeAdjust(state);
1129     rgbdev->updateStrokeAdjust(state);
1130     clip0dev->updateStrokeAdjust(state);
1131     clip1dev->updateStrokeAdjust(state);
1132     gfxdev->updateStrokeAdjust(state);
1133 }
1134 void BitmapOutputDev::updateFillColorSpace(GfxState *state)
1135 {
1136     boolpolydev->updateFillColorSpace(state);
1137     booltextdev->updateFillColorSpace(state);
1138     rgbdev->updateFillColorSpace(state);
1139     clip0dev->updateFillColorSpace(state);
1140     clip1dev->updateFillColorSpace(state);
1141     gfxdev->updateFillColorSpace(state);
1142 }
1143 void BitmapOutputDev::updateStrokeColorSpace(GfxState *state)
1144 {
1145     boolpolydev->updateStrokeColorSpace(state);
1146     booltextdev->updateStrokeColorSpace(state);
1147     rgbdev->updateStrokeColorSpace(state);
1148     clip0dev->updateStrokeColorSpace(state);
1149     clip1dev->updateStrokeColorSpace(state);
1150     gfxdev->updateStrokeColorSpace(state);
1151 }
1152 void BitmapOutputDev::updateFillColor(GfxState *state)
1153 {
1154     boolpolydev->updateFillColor(state);
1155     booltextdev->updateFillColor(state);
1156     rgbdev->updateFillColor(state);
1157     clip0dev->updateFillColor(state);
1158     clip1dev->updateFillColor(state);
1159     gfxdev->updateFillColor(state);
1160 }
1161 void BitmapOutputDev::updateStrokeColor(GfxState *state)
1162 {
1163     boolpolydev->updateStrokeColor(state);
1164     booltextdev->updateStrokeColor(state);
1165     rgbdev->updateStrokeColor(state);
1166     clip0dev->updateStrokeColor(state);
1167     clip1dev->updateStrokeColor(state);
1168     gfxdev->updateStrokeColor(state);
1169 }
1170 void BitmapOutputDev::updateBlendMode(GfxState *state)
1171 {
1172     boolpolydev->updateBlendMode(state);
1173     booltextdev->updateBlendMode(state);
1174     rgbdev->updateBlendMode(state);
1175     clip0dev->updateBlendMode(state);
1176     clip1dev->updateBlendMode(state);
1177     gfxdev->updateBlendMode(state);
1178 }
1179 void BitmapOutputDev::updateFillOpacity(GfxState *state)
1180 {
1181     boolpolydev->updateFillOpacity(state);
1182     booltextdev->updateFillOpacity(state);
1183     rgbdev->updateFillOpacity(state);
1184     clip0dev->updateFillOpacity(state);
1185     clip1dev->updateFillOpacity(state);
1186     gfxdev->updateFillOpacity(state);
1187 }
1188 void BitmapOutputDev::updateStrokeOpacity(GfxState *state)
1189 {
1190     boolpolydev->updateStrokeOpacity(state);
1191     booltextdev->updateStrokeOpacity(state);
1192     rgbdev->updateStrokeOpacity(state);
1193     clip0dev->updateStrokeOpacity(state);
1194     clip1dev->updateStrokeOpacity(state);
1195     gfxdev->updateStrokeOpacity(state);
1196 }
1197 void BitmapOutputDev::updateFillOverprint(GfxState *state)
1198 {
1199     boolpolydev->updateFillOverprint(state);
1200     booltextdev->updateFillOverprint(state);
1201     rgbdev->updateFillOverprint(state);
1202     clip0dev->updateFillOverprint(state);
1203     clip1dev->updateFillOverprint(state);
1204     gfxdev->updateFillOverprint(state);
1205 }
1206 void BitmapOutputDev::updateStrokeOverprint(GfxState *state)
1207 {
1208     boolpolydev->updateStrokeOverprint(state);
1209     booltextdev->updateStrokeOverprint(state);
1210     rgbdev->updateStrokeOverprint(state);
1211     clip0dev->updateStrokeOverprint(state);
1212     clip1dev->updateStrokeOverprint(state);
1213     gfxdev->updateStrokeOverprint(state);
1214 }
1215 void BitmapOutputDev::updateTransfer(GfxState *state)
1216 {
1217     boolpolydev->updateTransfer(state);
1218     booltextdev->updateTransfer(state);
1219     rgbdev->updateTransfer(state);
1220     clip0dev->updateTransfer(state);
1221     clip1dev->updateTransfer(state);
1222     gfxdev->updateTransfer(state);
1223 }
1224
1225 void BitmapOutputDev::updateFont(GfxState *state)
1226 {
1227     boolpolydev->updateFont(state);
1228     booltextdev->updateFont(state);
1229     rgbdev->updateFont(state);
1230     clip0dev->updateFont(state);
1231     clip1dev->updateFont(state);
1232     gfxdev->updateFont(state);
1233 }
1234 void BitmapOutputDev::updateTextMat(GfxState *state)
1235 {
1236     boolpolydev->updateTextMat(state);
1237     booltextdev->updateTextMat(state);
1238     rgbdev->updateTextMat(state);
1239     clip0dev->updateTextMat(state);
1240     clip1dev->updateTextMat(state);
1241     gfxdev->updateTextMat(state);
1242 }
1243 void BitmapOutputDev::updateCharSpace(GfxState *state)
1244 {
1245     boolpolydev->updateCharSpace(state);
1246     booltextdev->updateCharSpace(state);
1247     rgbdev->updateCharSpace(state);
1248     clip0dev->updateCharSpace(state);
1249     clip1dev->updateCharSpace(state);
1250     gfxdev->updateCharSpace(state);
1251 }
1252 void BitmapOutputDev::updateRender(GfxState *state)
1253 {
1254     boolpolydev->updateRender(state);
1255     booltextdev->updateRender(state);
1256     rgbdev->updateRender(state);
1257     clip0dev->updateRender(state);
1258     clip1dev->updateRender(state);
1259     gfxdev->updateRender(state);
1260 }
1261 void BitmapOutputDev::updateRise(GfxState *state)
1262 {
1263     boolpolydev->updateRise(state);
1264     booltextdev->updateRise(state);
1265     rgbdev->updateRise(state);
1266     clip0dev->updateRise(state);
1267     clip1dev->updateRise(state);
1268     gfxdev->updateRise(state);
1269 }
1270 void BitmapOutputDev::updateWordSpace(GfxState *state)
1271 {
1272     boolpolydev->updateWordSpace(state);
1273     booltextdev->updateWordSpace(state);
1274     rgbdev->updateWordSpace(state);
1275     clip0dev->updateWordSpace(state);
1276     clip1dev->updateWordSpace(state);
1277     gfxdev->updateWordSpace(state);
1278 }
1279 void BitmapOutputDev::updateHorizScaling(GfxState *state)
1280 {
1281     boolpolydev->updateHorizScaling(state);
1282     booltextdev->updateHorizScaling(state);
1283     rgbdev->updateHorizScaling(state);
1284     clip0dev->updateHorizScaling(state);
1285     clip1dev->updateHorizScaling(state);
1286     gfxdev->updateHorizScaling(state);
1287 }
1288 void BitmapOutputDev::updateTextPos(GfxState *state)
1289 {
1290     boolpolydev->updateTextPos(state);
1291     booltextdev->updateTextPos(state);
1292     rgbdev->updateTextPos(state);
1293     clip0dev->updateTextPos(state);
1294     clip1dev->updateTextPos(state);
1295     gfxdev->updateTextPos(state);
1296 }
1297 void BitmapOutputDev::updateTextShift(GfxState *state, double shift)
1298 {
1299     boolpolydev->updateTextShift(state, shift);
1300     booltextdev->updateTextShift(state, shift);
1301     rgbdev->updateTextShift(state, shift);
1302     clip0dev->updateTextShift(state, shift);
1303     clip1dev->updateTextShift(state, shift);
1304     gfxdev->updateTextShift(state, shift);
1305 }
1306
1307 double max(double x, double y) 
1308 {
1309     return x>y?x:y;
1310 }
1311 double min(double x, double y) 
1312 {
1313     return x<y?x:y;
1314 }
1315
1316 gfxbbox_t BitmapOutputDev::getBBox(GfxState*state)
1317 {
1318     GfxPath * path = state->getPath();
1319     int num = path->getNumSubpaths();
1320     gfxbbox_t bbox = {0,0,1,1};
1321     char valid=0;
1322     int t;
1323     for(t = 0; t < num; t++) {
1324         GfxSubpath *subpath = path->getSubpath(t);
1325         int subnum = subpath->getNumPoints();
1326         int s;
1327         for(s=0;s<subnum;s++) {
1328            double x,y;
1329            state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
1330            if(!valid) {
1331                bbox.xmin = x; bbox.ymin = y;
1332                bbox.xmax = x; bbox.ymax = y;
1333                valid = 1;
1334            } else {
1335                bbox.xmin = min(bbox.xmin, x);
1336                bbox.ymin = min(bbox.ymin, y);
1337                bbox.xmax = max(bbox.xmax, x);
1338                bbox.ymax = max(bbox.ymax, y);
1339            }
1340         }
1341     }
1342     return bbox;
1343 }
1344
1345 void BitmapOutputDev::stroke(GfxState *state)
1346 {
1347     msg("<debug> stroke");
1348     boolpolydev->stroke(state);
1349     gfxbbox_t bbox = getBBox(state);
1350     double width = state->getTransformedLineWidth();
1351     bbox.xmin -= width; bbox.ymin -= width;
1352     bbox.xmax += width; bbox.ymax += width;
1353     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1354     rgbdev->stroke(state);
1355     dbg_newdata("stroke");
1356 }
1357
1358 extern gfxcolor_t getFillColor(GfxState * state);
1359
1360 char area_is_plain_colored(GfxState*state, SplashBitmap*boolpoly, SplashBitmap*rgbbitmap, int x1, int y1, int x2, int y2)
1361 {
1362     int width = boolpoly->getWidth();
1363     int height = boolpoly->getHeight();
1364     if(!fixBBox(&x1, &y1, &x2, &y2, width, height)) {
1365         return 0;
1366     }
1367     gfxcolor_t color = getFillColor(state);
1368     SplashColorPtr rgb = rgbbitmap->getDataPtr() 
1369                        + (y1*width+x1)*sizeof(SplashColor);
1370     int width8 = (width+7)/8;
1371     unsigned char*bits = (unsigned char*)boolpoly->getDataPtr() 
1372                          + (y1*width8+x1);
1373     int x,y;
1374     int w = x2-x1;
1375     int h = y2-y1;
1376     for(y=0;y<h;y++) {
1377         for(x=0;x<w;x++) {
1378             if(rgb[x*3+0] != color.r ||
1379                rgb[x*3+1] != color.g ||
1380                rgb[x*3+2] != color.b)
1381                 return 0;
1382         }
1383         rgb += width*sizeof(SplashColor);
1384     }
1385     return 1;
1386 }
1387
1388 void BitmapOutputDev::fill(GfxState *state)
1389 {
1390     msg("<debug> fill");
1391     boolpolydev->fill(state);
1392     gfxbbox_t bbox = getBBox(state);
1393     if(config_optimizeplaincolorfills) {
1394         if(area_is_plain_colored(state, boolpolybitmap, rgbbitmap, bbox.xmin, bbox.ymin, bbox.xmax, bbox.ymax)) {
1395             return;
1396         }
1397     }
1398     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1399     rgbdev->fill(state);
1400     dbg_newdata("fill");
1401 }
1402 void BitmapOutputDev::eoFill(GfxState *state)
1403 {
1404     msg("<debug> eoFill");
1405     boolpolydev->eoFill(state);
1406     gfxbbox_t bbox = getBBox(state);
1407     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1408     rgbdev->eoFill(state);
1409     dbg_newdata("eofill");
1410 }
1411
1412 POPPLER_TILING_PATERN_RETURN BitmapOutputDev::tilingPatternFill(GfxState *state, POPPLER_TILING_PATERN_GFX Object *str,
1413                                int paintType, Dict *resDict,
1414                                double *mat, double *bbox,
1415                                int x0, int y0, int x1, int y1,
1416                                double xStep, double yStep) 
1417 {
1418     msg("<debug> tilingPatternFill");
1419     boolpolydev->tilingPatternFill(state, POPPLER_TILING_PATERN_GFX_ARG str, paintType, resDict, mat,
1420                                    bbox, x0, y0, x1, y1, xStep, yStep);
1421     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1422     rgbdev->tilingPatternFill(state, POPPLER_TILING_PATERN_GFX_ARG str, paintType, resDict, mat,
1423                               bbox, x0, y0, x1, y1, xStep, yStep);
1424     dbg_newdata("tilingpatternfill");
1425 #ifdef HAVE_POPPLER
1426     return gTrue;
1427 #endif
1428 }
1429
1430 GBool BitmapOutputDev::functionShadedFill(GfxState *state, GfxFunctionShading *shading) 
1431 {
1432     msg("<debug> functionShadedFill");
1433     boolpolydev->functionShadedFill(state, shading);
1434     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1435     return rgbdev->functionShadedFill(state, shading);
1436 }
1437 GBool BitmapOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading)
1438 {
1439     msg("<debug> axialShadedFill");
1440     boolpolydev->axialShadedFill(state, shading);
1441     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1442     return rgbdev->axialShadedFill(state, shading);
1443 }
1444 GBool BitmapOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading)
1445 {
1446     msg("<debug> radialShadedFill");
1447     boolpolydev->radialShadedFill(state, shading);
1448     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1449     return rgbdev->radialShadedFill(state, shading);
1450 }
1451
1452 SplashColor black = {0,0,0};
1453 SplashColor white = {255,255,255};
1454
1455 void BitmapOutputDev::clip(GfxState *state)
1456 {
1457     msg("<debug> clip");
1458     boolpolydev->clip(state);
1459     booltextdev->clip(state);
1460     rgbdev->clip(state);
1461     clip1dev->clip(state);
1462 }
1463 void BitmapOutputDev::eoClip(GfxState *state)
1464 {
1465     msg("<debug> eoClip");
1466     boolpolydev->eoClip(state);
1467     booltextdev->eoClip(state);
1468     rgbdev->eoClip(state);
1469     clip1dev->eoClip(state);
1470 }
1471 void BitmapOutputDev::clipToStrokePath(GfxState *state)
1472 {
1473     msg("<debug> clipToStrokePath");
1474     boolpolydev->clipToStrokePath(state);
1475     booltextdev->clipToStrokePath(state);
1476     rgbdev->clipToStrokePath(state);
1477     clip1dev->clipToStrokePath(state);
1478 }
1479
1480 void BitmapOutputDev::beginStringOp(GfxState *state)
1481 {
1482     msg("<debug> beginStringOp");
1483     clip0dev->beginStringOp(state);
1484     clip1dev->beginStringOp(state);
1485     booltextdev->beginStringOp(state);
1486     gfxdev->beginStringOp(state);
1487 }
1488 void BitmapOutputDev::beginString(GfxState *state, GString *s)
1489 {
1490     msg("<debug> beginString");
1491     clip0dev->beginString(state, s);
1492     clip1dev->beginString(state, s);
1493     booltextdev->beginString(state, s);
1494     gfxdev->beginString(state, s);
1495 }
1496
1497 void BitmapOutputDev::clearClips()
1498 {
1499     clearBooleanBitmap(clip0bitmap, 0, 0, 0, 0);
1500     clearBooleanBitmap(clip1bitmap, 0, 0, 0, 0);
1501 }
1502 void BitmapOutputDev::clearBoolPolyDev()
1503 {
1504     clearBooleanBitmap(stalepolybitmap, 0, 0, stalepolybitmap->getWidth(), stalepolybitmap->getHeight());
1505 }
1506 void BitmapOutputDev::clearBoolTextDev()
1507 {
1508     clearBooleanBitmap(staletextbitmap, 0, 0, staletextbitmap->getWidth(), staletextbitmap->getHeight());
1509 }
1510 void BitmapOutputDev::drawChar(GfxState *state, double x, double y,
1511                       double dx, double dy,
1512                       double originX, double originY,
1513                       CharCode code, int nBytes, Unicode *u, int uLen)
1514 {
1515     msg("<debug> drawChar render=%d", state->getRender());
1516
1517     if(state->getRender()&RENDER_CLIP) {
1518         //char is just a clipping boundary
1519         rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1520         boolpolydev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1521         booltextdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1522         clip1dev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1523     } else if(state->getRender()&RENDER_STROKE) {
1524         // we're drawing as stroke
1525         boolpolydev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1526         rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1527     } else if(rgbbitmap != rgbdev->getBitmap()) {
1528         // we're doing softmasking or transparency grouping
1529         boolpolydev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1530         rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1531     } else {
1532         // we're drawing a regular char
1533         clearClips();
1534         clip0dev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1535         clip1dev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1536    
1537         /* calculate the bbox of this character */
1538         int x1 = (int)x, x2 = (int)x+1, y1 = (int)y, y2 = (int)y+1;
1539         SplashFont*font = clip0dev->getCurrentFont();
1540         SplashPath*path = font?font->getGlyphPath(code):NULL;
1541         x-=originX;
1542         y-=originY;
1543         if(path) {
1544             path->offset((SplashCoord)x, (SplashCoord)y);
1545             int t;
1546             for(t=0;t<path->getLength();t++) {
1547                 double xx,yy;
1548                 Guchar f;
1549                 path->getPoint(t,&xx,&yy,&f);
1550                 state->transform(xx,yy,&xx,&yy);
1551                 if(xx<x1) x1=(int)xx;
1552                 if(yy<y1) y1=(int)yy;
1553                 if(xx>=x2) x2=(int)xx+1;
1554                 if(yy>=y2) y2=(int)yy+1;
1555             }
1556             delete(path);path=0;
1557         }
1558
1559         /* if this character is affected somehow by the various clippings (i.e., it looks
1560            different on a device without clipping), then draw it on the bitmap, not as
1561            text */
1562         if(clip0and1differ(x1,y1,x2,y2)) {
1563             msg("<verbose> Char %d is affected by clipping", code);
1564             boolpolydev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1565             checkNewBitmap(x1,y1,x2,y2);
1566             rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1567             if(config_extrafontdata) {
1568                 int oldrender = state->getRender();
1569                 state->setRender(3); //invisible
1570                 gfxdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1571                 state->setRender(oldrender);
1572             }
1573         } else {
1574
1575             /* this char is not at all affected by clipping. 
1576                Now just dump out the bitmap we're currently working on, if necessary. */
1577             booltextdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1578             checkNewText(x1,y1,x2,y2);
1579             /* use polygonal output device to do the actual text handling */
1580             gfxdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1581         }
1582     }
1583     dbg_newdata("text");
1584 }
1585 void BitmapOutputDev::drawString(GfxState *state, GString *s)
1586 {
1587     msg("<error> internal error: drawString not implemented");
1588     return;
1589 }
1590 void BitmapOutputDev::endTextObject(GfxState *state)
1591 {
1592     msg("<debug> endTextObject");
1593     rgbdev->endTextObject(state);
1594     clip0dev->endTextObject(state);
1595     clip1dev->endTextObject(state);
1596     booltextdev->endTextObject(state);
1597     /* the only thing "drawn" here is clipping */
1598     //checkNewText(UNKNOWN_BOUNDING_BOX);
1599     gfxdev->endTextObject(state);
1600     dbg_newdata("endtextobject");
1601 }
1602 void BitmapOutputDev::endString(GfxState *state)
1603 {
1604     msg("<debug> endString");
1605     clip0dev->endString(state);
1606     clip1dev->endString(state);
1607     booltextdev->endString(state);
1608     int render = state->getRender();
1609     if(render != RENDER_INVISIBLE && render != RENDER_FILL) {
1610         /* xpdf draws things like stroke text or fill+stroke text in the
1611            endString() method */
1612         checkNewText(UNKNOWN_BOUNDING_BOX);
1613     }
1614     gfxdev->endString(state);
1615     dbg_newdata("endstring");
1616 }
1617 void BitmapOutputDev::endStringOp(GfxState *state)
1618 {
1619     msg("<debug> endStringOp");
1620     clip0dev->endStringOp(state);
1621     clip1dev->endStringOp(state);
1622     booltextdev->endStringOp(state);
1623     gfxdev->endStringOp(state);
1624     dbg_newdata("endstringop");
1625 }
1626
1627 /* TODO: these four operations below *should* do nothing, as type3
1628          chars are drawn using operations like fill() */
1629 GBool BitmapOutputDev::beginType3Char(GfxState *state, double x, double y,
1630                              double dx, double dy,
1631                              CharCode code, Unicode *u, int uLen)
1632 {
1633     msg("<debug> beginType3Char");
1634     /* call gfxdev so that it can generate "invisible" characters
1635        on top of the actual graphic content, for text extraction */
1636     return gfxdev->beginType3Char(state, x, y, dx, dy, code, u, uLen);
1637 }
1638 void BitmapOutputDev::type3D0(GfxState *state, double wx, double wy)
1639 {
1640     msg("<debug> type3D0");
1641     return gfxdev->type3D0(state, wx, wy);
1642 }
1643 void BitmapOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury)
1644 {
1645     msg("<debug> type3D1");
1646     return gfxdev->type3D1(state, wx, wy, llx, lly, urx, ury);
1647 }
1648 void BitmapOutputDev::endType3Char(GfxState *state)
1649 {
1650     msg("<debug> endType3Char");
1651     gfxdev->endType3Char(state);
1652 }
1653
1654 class CopyStream: public Object
1655 {
1656     Dict*dict;
1657     char*buf;
1658     MemStream*memstream;
1659     public:
1660     CopyStream(Stream*str, int len)
1661     {
1662         buf = 0;
1663         str->reset();
1664         if(len) {
1665             buf = (char*)malloc(len);
1666             int t;
1667             for (t=0; t<len; t++)
1668               buf[t] = str->getChar();
1669         }
1670         str->close();
1671         this->dict = str->getDict();
1672         this->memstream = new MemStream(buf, 0, len, this);
1673     }
1674     ~CopyStream() 
1675     {
1676         ::free(this->buf);this->buf = 0;
1677         delete this->memstream;
1678     }
1679     Dict* getDict() {return dict;}
1680     Stream* getStream() {return this->memstream;};
1681 };
1682
1683 gfxbbox_t BitmapOutputDev::getImageBBox(GfxState*state)
1684 {
1685     gfxbbox_t bbox;
1686     double x,y;
1687     state->transform(0, 1, &x, &y);
1688     bbox.xmin=bbox.xmax = x;
1689     bbox.ymin=bbox.ymax = y;
1690     state->transform(0, 0, &x, &y);
1691     bbox.xmin=min(bbox.xmin,x);
1692     bbox.ymin=min(bbox.ymin,y);
1693     bbox.xmax=max(bbox.xmax,x);
1694     bbox.ymax=max(bbox.ymax,y);
1695     state->transform(1, 0, &x, &y);
1696     bbox.xmin=min(bbox.xmin,x);
1697     bbox.ymin=min(bbox.ymin,y);
1698     bbox.xmax=max(bbox.xmax,x);
1699     bbox.ymax=max(bbox.ymax,y);
1700     state->transform(1, 1, &x, &y);
1701     bbox.xmin=min(bbox.xmin,x);
1702     bbox.ymin=min(bbox.ymin,y);
1703     bbox.xmax=max(bbox.xmax,x);
1704     bbox.ymax=max(bbox.ymax,y);
1705     return bbox;
1706 }
1707
1708 GBool invalid_size(int width, int height)
1709 {
1710     if((U64)width*(U64)height > 0x7fffffffll)
1711         return 1;
1712     return 0;
1713 }
1714
1715 void BitmapOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
1716                            int width, int height, GBool invert, POPPLER_INTERPOLATE
1717                            GBool inlineImg)
1718 {
1719     msg("<debug> drawImageMask streamkind=%d", str->getKind());
1720     if(invalid_size(width,height)) return;
1721
1722     CopyStream*cpystr = new CopyStream(str, height * ((width + 7) / 8));
1723     str = cpystr->getStream();
1724     
1725     boolpolydev->drawImageMask(state, ref, str, width, height, invert, POPPLER_INTERPOLATE_ARG inlineImg);
1726     gfxbbox_t bbox = getImageBBox(state);
1727     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1728     rgbdev->drawImageMask(state, ref, str, width, height, invert, POPPLER_INTERPOLATE_ARG inlineImg);
1729     delete cpystr;
1730     dbg_newdata("imagemask");
1731 }
1732 void BitmapOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
1733                        int width, int height, GfxImageColorMap *colorMap,
1734                        POPPLER_INTERPOLATE
1735                        int *maskColors, GBool inlineImg)
1736 {
1737     msg("<debug> drawImage streamkind=%d", str->getKind());
1738     if(invalid_size(width,height)) return;
1739         
1740     CopyStream*cpystr = new CopyStream(str, height * ((width * colorMap->getNumPixelComps() * colorMap->getBits() + 7) / 8));
1741     str = cpystr->getStream();
1742
1743     boolpolydev->drawImage(state, ref, str, width, height, colorMap, POPPLER_INTERPOLATE_ARG maskColors, inlineImg);
1744     gfxbbox_t bbox=getImageBBox(state);
1745     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1746     rgbdev->drawImage(state, ref, str, width, height, colorMap, POPPLER_INTERPOLATE_ARG maskColors, inlineImg);
1747     delete cpystr;
1748     dbg_newdata("image");
1749 }
1750 void BitmapOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
1751                              int width, int height,
1752                              GfxImageColorMap *colorMap,
1753                              POPPLER_INTERPOLATE
1754                              Stream *maskStr, int maskWidth, int maskHeight,
1755                              GBool maskInvert POPPLER_MASK_INTERPOLATE)
1756 {
1757     msg("<debug> drawMaskedImage streamkind=%d", str->getKind());
1758     if(invalid_size(width,height)) return;
1759     
1760     CopyStream*cpystr = new CopyStream(str, height * ((width * colorMap->getNumPixelComps() * colorMap->getBits() + 7) / 8));
1761     str = cpystr->getStream();
1762
1763     boolpolydev->drawMaskedImage(state, ref, str, width, height, colorMap, POPPLER_INTERPOLATE_ARG maskStr, maskWidth, maskHeight, maskInvert POPPLER_MASK_INTERPOLATE_ARG);
1764     gfxbbox_t bbox=getImageBBox(state);
1765     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1766     rgbdev->drawMaskedImage(state, ref, str, width, height, colorMap, POPPLER_INTERPOLATE_ARG maskStr, maskWidth, maskHeight, maskInvert POPPLER_MASK_INTERPOLATE_ARG);
1767     delete cpystr;
1768     dbg_newdata("maskedimage");
1769 }
1770 void BitmapOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
1771                                  int width, int height,
1772                                  GfxImageColorMap *colorMap,
1773                                  POPPLER_INTERPOLATE
1774                                  Stream *maskStr,
1775                                  int maskWidth, int maskHeight,
1776                                  GfxImageColorMap *maskColorMap POPPLER_MASK_INTERPOLATE)
1777 {
1778     msg("<debug> drawSoftMaskedImage %dx%d (%dx%d) streamkind=%d", width, height, maskWidth, maskHeight, str->getKind());
1779     if(invalid_size(width,height)) return;
1780
1781     CopyStream*cpystr = new CopyStream(str, height * ((width * colorMap->getNumPixelComps() * colorMap->getBits() + 7) / 8));
1782     str = cpystr->getStream();
1783
1784     boolpolydev->drawSoftMaskedImage(state, ref, str, width, height, colorMap, POPPLER_INTERPOLATE_ARG maskStr, maskWidth, maskHeight, maskColorMap POPPLER_MASK_INTERPOLATE_ARG);
1785     gfxbbox_t bbox=getImageBBox(state);
1786     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1787     rgbdev->drawSoftMaskedImage(state, ref, str, width, height, colorMap, POPPLER_INTERPOLATE_ARG maskStr, maskWidth, maskHeight, maskColorMap POPPLER_MASK_INTERPOLATE_ARG);
1788     delete cpystr;
1789     dbg_newdata("softmaskimage");
1790 }
1791 void BitmapOutputDev::drawForm(Ref id)
1792 {
1793     msg("<debug> drawForm");
1794     boolpolydev->drawForm(id);
1795     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1796     rgbdev->drawForm(id);
1797 }
1798
1799 void BitmapOutputDev::processLink(Link *link, Catalog *catalog)
1800 {
1801     msg("<debug> processLink");
1802     flushEverything();
1803     gfxdev->processLink(link, catalog);
1804 }
1805 void BitmapOutputDev::flushEverything()
1806 {
1807     if(layerstate == STATE_BITMAP_IS_ABOVE) {
1808         this->flushText();
1809         this->flushBitmap();
1810     } else {
1811         this->flushBitmap();
1812         this->flushText();
1813     }
1814 }
1815
1816 void BitmapOutputDev::beginTransparencyGroup(GfxState *state, double *bbox,
1817                                     GfxColorSpace *blendingColorSpace,
1818                                     GBool isolated, GBool knockout,
1819                                     GBool forSoftMask)
1820 {
1821     msg("<debug> beginTransparencyGroup");
1822 #if (xpdfMajorVersion*10000 + xpdfMinorVersion*100 + xpdfUpdateVersion) < 30207
1823     GfxState*state1 = state->copy();
1824     GfxState*state2 = state->copy();
1825     state1->setPath(0);
1826     state1->setPath(state->getPath()->copy());
1827     state2->setPath(0);
1828     state2->setPath(state->getPath()->copy());
1829 #else
1830     GfxState*state1 = state->copy(gTrue);
1831     GfxState*state2 = state->copy(gTrue);
1832 #endif
1833     boolpolydev->beginTransparencyGroup(state1, bbox, blendingColorSpace, isolated, knockout, forSoftMask);
1834     rgbdev->beginTransparencyGroup(state2, bbox, blendingColorSpace, isolated, knockout, forSoftMask);
1835     clip1dev->beginTransparencyGroup(state, bbox, blendingColorSpace, isolated, knockout, forSoftMask);
1836     delete state1;
1837     delete state2;
1838     dbg_newdata("endtransparencygroup");
1839 }
1840 void BitmapOutputDev::endTransparencyGroup(GfxState *state)
1841 {
1842     msg("<debug> endTransparencyGroup");
1843 #if (xpdfMajorVersion*10000 + xpdfMinorVersion*100 + xpdfUpdateVersion) < 30207
1844     GfxState*state1 = state->copy();
1845     GfxState*state2 = state->copy();
1846     state1->setPath(0);
1847     state1->setPath(state->getPath()->copy());
1848     state2->setPath(0);
1849     state2->setPath(state->getPath()->copy());
1850 #else
1851     GfxState*state1 = state->copy(gTrue);
1852     GfxState*state2 = state->copy(gTrue);
1853 #endif
1854     boolpolydev->endTransparencyGroup(state1);
1855     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1856     rgbdev->endTransparencyGroup(state2);
1857     delete state1;
1858     delete state2;
1859     clip1dev->endTransparencyGroup(state);
1860     dbg_newdata("endtransparencygroup");
1861 }
1862 void BitmapOutputDev::paintTransparencyGroup(GfxState *state, double *bbox)
1863 {
1864     msg("<debug> paintTransparencyGroup");
1865     boolpolydev->paintTransparencyGroup(state,bbox);
1866     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1867     rgbdev->paintTransparencyGroup(state,bbox);
1868     clip1dev->paintTransparencyGroup(state,bbox);
1869     dbg_newdata("painttransparencygroup");
1870 }
1871 void BitmapOutputDev::setSoftMask(GfxState *state, double *bbox, GBool alpha, Function *transferFunc, GfxColor *backdropColor)
1872 {
1873     msg("<debug> setSoftMask");
1874     boolpolydev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
1875     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1876     rgbdev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
1877     clip1dev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
1878     dbg_newdata("setsoftmask");
1879 }
1880 void BitmapOutputDev::clearSoftMask(GfxState *state)
1881 {
1882     msg("<debug> clearSoftMask");
1883     boolpolydev->clearSoftMask(state);
1884     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1885     rgbdev->clearSoftMask(state);
1886     clip1dev->clearSoftMask(state);
1887     dbg_newdata("clearsoftmask");
1888 }