poppler: add new axial and radialShadedFill 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
1438 GBool BitmapOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading POPPLER_RAXIAL_MIN_MAX)
1439 {
1440     msg("<debug> axialShadedFill");
1441     boolpolydev->axialShadedFill(state, shading POPPLER_RAXIAL_MIN_MAX_ARG);
1442     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1443     return rgbdev->axialShadedFill(state, shading POPPLER_RAXIAL_MIN_MAX_ARG);
1444 }
1445
1446 GBool BitmapOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading POPPLER_RAXIAL_MIN_MAX)
1447 {
1448     msg("<debug> radialShadedFill");
1449     boolpolydev->radialShadedFill(state, shading POPPLER_RAXIAL_MIN_MAX_ARG);
1450     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1451     return rgbdev->radialShadedFill(state, shading POPPLER_RAXIAL_MIN_MAX_ARG);
1452 }
1453
1454 SplashColor black = {0,0,0};
1455 SplashColor white = {255,255,255};
1456
1457 void BitmapOutputDev::clip(GfxState *state)
1458 {
1459     msg("<debug> clip");
1460     boolpolydev->clip(state);
1461     booltextdev->clip(state);
1462     rgbdev->clip(state);
1463     clip1dev->clip(state);
1464 }
1465 void BitmapOutputDev::eoClip(GfxState *state)
1466 {
1467     msg("<debug> eoClip");
1468     boolpolydev->eoClip(state);
1469     booltextdev->eoClip(state);
1470     rgbdev->eoClip(state);
1471     clip1dev->eoClip(state);
1472 }
1473 void BitmapOutputDev::clipToStrokePath(GfxState *state)
1474 {
1475     msg("<debug> clipToStrokePath");
1476     boolpolydev->clipToStrokePath(state);
1477     booltextdev->clipToStrokePath(state);
1478     rgbdev->clipToStrokePath(state);
1479     clip1dev->clipToStrokePath(state);
1480 }
1481
1482 void BitmapOutputDev::beginStringOp(GfxState *state)
1483 {
1484     msg("<debug> beginStringOp");
1485     clip0dev->beginStringOp(state);
1486     clip1dev->beginStringOp(state);
1487     booltextdev->beginStringOp(state);
1488     gfxdev->beginStringOp(state);
1489 }
1490 void BitmapOutputDev::beginString(GfxState *state, GString *s)
1491 {
1492     msg("<debug> beginString");
1493     clip0dev->beginString(state, s);
1494     clip1dev->beginString(state, s);
1495     booltextdev->beginString(state, s);
1496     gfxdev->beginString(state, s);
1497 }
1498
1499 void BitmapOutputDev::clearClips()
1500 {
1501     clearBooleanBitmap(clip0bitmap, 0, 0, 0, 0);
1502     clearBooleanBitmap(clip1bitmap, 0, 0, 0, 0);
1503 }
1504 void BitmapOutputDev::clearBoolPolyDev()
1505 {
1506     clearBooleanBitmap(stalepolybitmap, 0, 0, stalepolybitmap->getWidth(), stalepolybitmap->getHeight());
1507 }
1508 void BitmapOutputDev::clearBoolTextDev()
1509 {
1510     clearBooleanBitmap(staletextbitmap, 0, 0, staletextbitmap->getWidth(), staletextbitmap->getHeight());
1511 }
1512 void BitmapOutputDev::drawChar(GfxState *state, double x, double y,
1513                       double dx, double dy,
1514                       double originX, double originY,
1515                       CharCode code, int nBytes, Unicode *u, int uLen)
1516 {
1517     msg("<debug> drawChar render=%d", state->getRender());
1518
1519     if(state->getRender()&RENDER_CLIP) {
1520         //char is just a clipping boundary
1521         rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1522         boolpolydev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1523         booltextdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1524         clip1dev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1525     } else if(state->getRender()&RENDER_STROKE) {
1526         // we're drawing as stroke
1527         boolpolydev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1528         rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1529     } else if(rgbbitmap != rgbdev->getBitmap()) {
1530         // we're doing softmasking or transparency grouping
1531         boolpolydev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1532         rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1533     } else {
1534         // we're drawing a regular char
1535         clearClips();
1536         clip0dev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1537         clip1dev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1538    
1539         /* calculate the bbox of this character */
1540         int x1 = (int)x, x2 = (int)x+1, y1 = (int)y, y2 = (int)y+1;
1541         SplashFont*font = clip0dev->getCurrentFont();
1542         SplashPath*path = font?font->getGlyphPath(code):NULL;
1543         x-=originX;
1544         y-=originY;
1545         if(path) {
1546             path->offset((SplashCoord)x, (SplashCoord)y);
1547             int t;
1548             for(t=0;t<path->getLength();t++) {
1549                 double xx,yy;
1550                 Guchar f;
1551                 path->getPoint(t,&xx,&yy,&f);
1552                 state->transform(xx,yy,&xx,&yy);
1553                 if(xx<x1) x1=(int)xx;
1554                 if(yy<y1) y1=(int)yy;
1555                 if(xx>=x2) x2=(int)xx+1;
1556                 if(yy>=y2) y2=(int)yy+1;
1557             }
1558             delete(path);path=0;
1559         }
1560
1561         /* if this character is affected somehow by the various clippings (i.e., it looks
1562            different on a device without clipping), then draw it on the bitmap, not as
1563            text */
1564         if(clip0and1differ(x1,y1,x2,y2)) {
1565             msg("<verbose> Char %d is affected by clipping", code);
1566             boolpolydev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1567             checkNewBitmap(x1,y1,x2,y2);
1568             rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1569             if(config_extrafontdata) {
1570                 int oldrender = state->getRender();
1571                 state->setRender(3); //invisible
1572                 gfxdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1573                 state->setRender(oldrender);
1574             }
1575         } else {
1576
1577             /* this char is not at all affected by clipping. 
1578                Now just dump out the bitmap we're currently working on, if necessary. */
1579             booltextdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1580             checkNewText(x1,y1,x2,y2);
1581             /* use polygonal output device to do the actual text handling */
1582             gfxdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
1583         }
1584     }
1585     dbg_newdata("text");
1586 }
1587 void BitmapOutputDev::drawString(GfxState *state, GString *s)
1588 {
1589     msg("<error> internal error: drawString not implemented");
1590     return;
1591 }
1592 void BitmapOutputDev::endTextObject(GfxState *state)
1593 {
1594     msg("<debug> endTextObject");
1595     rgbdev->endTextObject(state);
1596     clip0dev->endTextObject(state);
1597     clip1dev->endTextObject(state);
1598     booltextdev->endTextObject(state);
1599     /* the only thing "drawn" here is clipping */
1600     //checkNewText(UNKNOWN_BOUNDING_BOX);
1601     gfxdev->endTextObject(state);
1602     dbg_newdata("endtextobject");
1603 }
1604 void BitmapOutputDev::endString(GfxState *state)
1605 {
1606     msg("<debug> endString");
1607     clip0dev->endString(state);
1608     clip1dev->endString(state);
1609     booltextdev->endString(state);
1610     int render = state->getRender();
1611     if(render != RENDER_INVISIBLE && render != RENDER_FILL) {
1612         /* xpdf draws things like stroke text or fill+stroke text in the
1613            endString() method */
1614         checkNewText(UNKNOWN_BOUNDING_BOX);
1615     }
1616     gfxdev->endString(state);
1617     dbg_newdata("endstring");
1618 }
1619 void BitmapOutputDev::endStringOp(GfxState *state)
1620 {
1621     msg("<debug> endStringOp");
1622     clip0dev->endStringOp(state);
1623     clip1dev->endStringOp(state);
1624     booltextdev->endStringOp(state);
1625     gfxdev->endStringOp(state);
1626     dbg_newdata("endstringop");
1627 }
1628
1629 /* TODO: these four operations below *should* do nothing, as type3
1630          chars are drawn using operations like fill() */
1631 GBool BitmapOutputDev::beginType3Char(GfxState *state, double x, double y,
1632                              double dx, double dy,
1633                              CharCode code, Unicode *u, int uLen)
1634 {
1635     msg("<debug> beginType3Char");
1636     /* call gfxdev so that it can generate "invisible" characters
1637        on top of the actual graphic content, for text extraction */
1638     return gfxdev->beginType3Char(state, x, y, dx, dy, code, u, uLen);
1639 }
1640 void BitmapOutputDev::type3D0(GfxState *state, double wx, double wy)
1641 {
1642     msg("<debug> type3D0");
1643     return gfxdev->type3D0(state, wx, wy);
1644 }
1645 void BitmapOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury)
1646 {
1647     msg("<debug> type3D1");
1648     return gfxdev->type3D1(state, wx, wy, llx, lly, urx, ury);
1649 }
1650 void BitmapOutputDev::endType3Char(GfxState *state)
1651 {
1652     msg("<debug> endType3Char");
1653     gfxdev->endType3Char(state);
1654 }
1655
1656 class CopyStream: public Object
1657 {
1658     Dict*dict;
1659     char*buf;
1660     MemStream*memstream;
1661     public:
1662     CopyStream(Stream*str, int len)
1663     {
1664         buf = 0;
1665         str->reset();
1666         if(len) {
1667             buf = (char*)malloc(len);
1668             int t;
1669             for (t=0; t<len; t++)
1670               buf[t] = str->getChar();
1671         }
1672         str->close();
1673         this->dict = str->getDict();
1674         this->memstream = new MemStream(buf, 0, len, this);
1675     }
1676     ~CopyStream() 
1677     {
1678         ::free(this->buf);this->buf = 0;
1679         delete this->memstream;
1680     }
1681     Dict* getDict() {return dict;}
1682     Stream* getStream() {return this->memstream;};
1683 };
1684
1685 gfxbbox_t BitmapOutputDev::getImageBBox(GfxState*state)
1686 {
1687     gfxbbox_t bbox;
1688     double x,y;
1689     state->transform(0, 1, &x, &y);
1690     bbox.xmin=bbox.xmax = x;
1691     bbox.ymin=bbox.ymax = y;
1692     state->transform(0, 0, &x, &y);
1693     bbox.xmin=min(bbox.xmin,x);
1694     bbox.ymin=min(bbox.ymin,y);
1695     bbox.xmax=max(bbox.xmax,x);
1696     bbox.ymax=max(bbox.ymax,y);
1697     state->transform(1, 0, &x, &y);
1698     bbox.xmin=min(bbox.xmin,x);
1699     bbox.ymin=min(bbox.ymin,y);
1700     bbox.xmax=max(bbox.xmax,x);
1701     bbox.ymax=max(bbox.ymax,y);
1702     state->transform(1, 1, &x, &y);
1703     bbox.xmin=min(bbox.xmin,x);
1704     bbox.ymin=min(bbox.ymin,y);
1705     bbox.xmax=max(bbox.xmax,x);
1706     bbox.ymax=max(bbox.ymax,y);
1707     return bbox;
1708 }
1709
1710 GBool invalid_size(int width, int height)
1711 {
1712     if((U64)width*(U64)height > 0x7fffffffll)
1713         return 1;
1714     return 0;
1715 }
1716
1717 void BitmapOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
1718                            int width, int height, GBool invert, POPPLER_INTERPOLATE
1719                            GBool inlineImg)
1720 {
1721     msg("<debug> drawImageMask streamkind=%d", str->getKind());
1722     if(invalid_size(width,height)) return;
1723
1724     CopyStream*cpystr = new CopyStream(str, height * ((width + 7) / 8));
1725     str = cpystr->getStream();
1726     
1727     boolpolydev->drawImageMask(state, ref, str, width, height, invert, POPPLER_INTERPOLATE_ARG inlineImg);
1728     gfxbbox_t bbox = getImageBBox(state);
1729     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1730     rgbdev->drawImageMask(state, ref, str, width, height, invert, POPPLER_INTERPOLATE_ARG inlineImg);
1731     delete cpystr;
1732     dbg_newdata("imagemask");
1733 }
1734 void BitmapOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
1735                        int width, int height, GfxImageColorMap *colorMap,
1736                        POPPLER_INTERPOLATE
1737                        int *maskColors, GBool inlineImg)
1738 {
1739     msg("<debug> drawImage streamkind=%d", str->getKind());
1740     if(invalid_size(width,height)) return;
1741         
1742     CopyStream*cpystr = new CopyStream(str, height * ((width * colorMap->getNumPixelComps() * colorMap->getBits() + 7) / 8));
1743     str = cpystr->getStream();
1744
1745     boolpolydev->drawImage(state, ref, str, width, height, colorMap, POPPLER_INTERPOLATE_ARG maskColors, inlineImg);
1746     gfxbbox_t bbox=getImageBBox(state);
1747     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1748     rgbdev->drawImage(state, ref, str, width, height, colorMap, POPPLER_INTERPOLATE_ARG maskColors, inlineImg);
1749     delete cpystr;
1750     dbg_newdata("image");
1751 }
1752 void BitmapOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
1753                              int width, int height,
1754                              GfxImageColorMap *colorMap,
1755                              POPPLER_INTERPOLATE
1756                              Stream *maskStr, int maskWidth, int maskHeight,
1757                              GBool maskInvert POPPLER_MASK_INTERPOLATE)
1758 {
1759     msg("<debug> drawMaskedImage streamkind=%d", str->getKind());
1760     if(invalid_size(width,height)) return;
1761     
1762     CopyStream*cpystr = new CopyStream(str, height * ((width * colorMap->getNumPixelComps() * colorMap->getBits() + 7) / 8));
1763     str = cpystr->getStream();
1764
1765     boolpolydev->drawMaskedImage(state, ref, str, width, height, colorMap, POPPLER_INTERPOLATE_ARG maskStr, maskWidth, maskHeight, maskInvert POPPLER_MASK_INTERPOLATE_ARG);
1766     gfxbbox_t bbox=getImageBBox(state);
1767     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1768     rgbdev->drawMaskedImage(state, ref, str, width, height, colorMap, POPPLER_INTERPOLATE_ARG maskStr, maskWidth, maskHeight, maskInvert POPPLER_MASK_INTERPOLATE_ARG);
1769     delete cpystr;
1770     dbg_newdata("maskedimage");
1771 }
1772 void BitmapOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
1773                                  int width, int height,
1774                                  GfxImageColorMap *colorMap,
1775                                  POPPLER_INTERPOLATE
1776                                  Stream *maskStr,
1777                                  int maskWidth, int maskHeight,
1778                                  GfxImageColorMap *maskColorMap POPPLER_MASK_INTERPOLATE)
1779 {
1780     msg("<debug> drawSoftMaskedImage %dx%d (%dx%d) streamkind=%d", width, height, maskWidth, maskHeight, str->getKind());
1781     if(invalid_size(width,height)) return;
1782
1783     CopyStream*cpystr = new CopyStream(str, height * ((width * colorMap->getNumPixelComps() * colorMap->getBits() + 7) / 8));
1784     str = cpystr->getStream();
1785
1786     boolpolydev->drawSoftMaskedImage(state, ref, str, width, height, colorMap, POPPLER_INTERPOLATE_ARG maskStr, maskWidth, maskHeight, maskColorMap POPPLER_MASK_INTERPOLATE_ARG);
1787     gfxbbox_t bbox=getImageBBox(state);
1788     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
1789     rgbdev->drawSoftMaskedImage(state, ref, str, width, height, colorMap, POPPLER_INTERPOLATE_ARG maskStr, maskWidth, maskHeight, maskColorMap POPPLER_MASK_INTERPOLATE_ARG);
1790     delete cpystr;
1791     dbg_newdata("softmaskimage");
1792 }
1793 void BitmapOutputDev::drawForm(Ref id)
1794 {
1795     msg("<debug> drawForm");
1796     boolpolydev->drawForm(id);
1797     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1798     rgbdev->drawForm(id);
1799 }
1800
1801 void BitmapOutputDev::processLink(Link *link, Catalog *catalog)
1802 {
1803     msg("<debug> processLink");
1804     flushEverything();
1805     gfxdev->processLink(link, catalog);
1806 }
1807 void BitmapOutputDev::flushEverything()
1808 {
1809     if(layerstate == STATE_BITMAP_IS_ABOVE) {
1810         this->flushText();
1811         this->flushBitmap();
1812     } else {
1813         this->flushBitmap();
1814         this->flushText();
1815     }
1816 }
1817
1818 void BitmapOutputDev::beginTransparencyGroup(GfxState *state, double *bbox,
1819                                     GfxColorSpace *blendingColorSpace,
1820                                     GBool isolated, GBool knockout,
1821                                     GBool forSoftMask)
1822 {
1823     msg("<debug> beginTransparencyGroup");
1824 #if (xpdfMajorVersion*10000 + xpdfMinorVersion*100 + xpdfUpdateVersion) < 30207
1825     GfxState*state1 = state->copy();
1826     GfxState*state2 = state->copy();
1827     state1->setPath(0);
1828     state1->setPath(state->getPath()->copy());
1829     state2->setPath(0);
1830     state2->setPath(state->getPath()->copy());
1831 #else
1832     GfxState*state1 = state->copy(gTrue);
1833     GfxState*state2 = state->copy(gTrue);
1834 #endif
1835     boolpolydev->beginTransparencyGroup(state1, bbox, blendingColorSpace, isolated, knockout, forSoftMask);
1836     rgbdev->beginTransparencyGroup(state2, bbox, blendingColorSpace, isolated, knockout, forSoftMask);
1837     clip1dev->beginTransparencyGroup(state, bbox, blendingColorSpace, isolated, knockout, forSoftMask);
1838     delete state1;
1839     delete state2;
1840     dbg_newdata("endtransparencygroup");
1841 }
1842 void BitmapOutputDev::endTransparencyGroup(GfxState *state)
1843 {
1844     msg("<debug> endTransparencyGroup");
1845 #if (xpdfMajorVersion*10000 + xpdfMinorVersion*100 + xpdfUpdateVersion) < 30207
1846     GfxState*state1 = state->copy();
1847     GfxState*state2 = state->copy();
1848     state1->setPath(0);
1849     state1->setPath(state->getPath()->copy());
1850     state2->setPath(0);
1851     state2->setPath(state->getPath()->copy());
1852 #else
1853     GfxState*state1 = state->copy(gTrue);
1854     GfxState*state2 = state->copy(gTrue);
1855 #endif
1856     boolpolydev->endTransparencyGroup(state1);
1857     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1858     rgbdev->endTransparencyGroup(state2);
1859     delete state1;
1860     delete state2;
1861     clip1dev->endTransparencyGroup(state);
1862     dbg_newdata("endtransparencygroup");
1863 }
1864 void BitmapOutputDev::paintTransparencyGroup(GfxState *state, double *bbox)
1865 {
1866     msg("<debug> paintTransparencyGroup");
1867     boolpolydev->paintTransparencyGroup(state,bbox);
1868     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1869     rgbdev->paintTransparencyGroup(state,bbox);
1870     clip1dev->paintTransparencyGroup(state,bbox);
1871     dbg_newdata("painttransparencygroup");
1872 }
1873 void BitmapOutputDev::setSoftMask(GfxState *state, double *bbox, GBool alpha, Function *transferFunc, GfxColor *backdropColor)
1874 {
1875     msg("<debug> setSoftMask");
1876     boolpolydev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
1877     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1878     rgbdev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
1879     clip1dev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
1880     dbg_newdata("setsoftmask");
1881 }
1882 void BitmapOutputDev::clearSoftMask(GfxState *state)
1883 {
1884     msg("<debug> clearSoftMask");
1885     boolpolydev->clearSoftMask(state);
1886     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
1887     rgbdev->clearSoftMask(state);
1888     clip1dev->clearSoftMask(state);
1889     dbg_newdata("clearsoftmask");
1890 }