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