fixed compile for new xpdf versions
[swftools.git] / lib / pdf / BitmapOutputDev.cc
1 /* InfoOutputDev.h
2
3    Output Device which creates a bitmap.
4
5    Swftools is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    Swftools is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with swftools; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <memory.h>
22 #include "config.h"
23 #include "BitmapOutputDev.h"
24 #include "GFXOutputDev.h"
25 #include "SplashBitmap.h"
26 #include "SplashPattern.h"
27 #include "Splash.h"
28 #include "../log.h"
29
30 static SplashColor splash_white = {255,255,255};
31 static SplashColor splash_black = {255,255,255};
32     
33 ClipState::ClipState()
34 {
35     this->next = 0;
36     this->clipbitmap = 0;
37     this->written = 0;
38 }
39
40 BitmapOutputDev::BitmapOutputDev(InfoOutputDev*info, PDFDoc*doc)
41 {
42     this->info = info;
43     this->doc = doc;
44     this->xref = doc->getXRef();
45     this->rgbdev = new SplashOutputDev(splashModeRGB8, 1, gFalse, splash_white, gTrue, gTrue);
46     this->clip0dev = new SplashOutputDev(splashModeMono1, 1, gFalse, splash_black, gTrue, gFalse);
47     this->clip1dev = new SplashOutputDev(splashModeMono1, 1, gFalse, splash_black, gTrue, gFalse);
48     this->gfxdev = new GFXOutputDev(info, this->doc);
49     this->rgbdev->startDoc(this->xref);
50     this->clip0dev->startDoc(this->xref);
51     this->clip1dev->startDoc(this->xref);
52     
53     this->config_bitmapfonts = 0;
54     this->config_extrafontdata = 0;
55     this->bboxpath = 0;
56     //this->clipdev = 0;
57     //this->clipstates = 0;
58 }
59 BitmapOutputDev::~BitmapOutputDev()
60 {
61     if(this->bboxpath) {
62         delete this->bboxpath;this->bboxpath = 0;
63     }
64     if(this->rgbdev) {
65         delete this->rgbdev;this->rgbdev= 0;
66     }
67     if(this->clip0dev) {
68         delete this->clip0dev;this->clip0dev= 0;
69     }
70     if(this->clip1dev) {
71         delete this->clip1dev;this->clip1dev= 0;
72     }
73     //if(this->clipbitmap) {
74     //    delete this->clipbitmap;this->clipbitmap = 0;
75     //}
76     //if(this->clipdev) {
77     //    delete this->clipdev;this->clipdev = 0;
78     //}
79
80 }
81
82 void BitmapOutputDev::setDevice(gfxdevice_t*dev)
83 {
84     this->dev = dev;
85     this->gfxdev->setDevice(dev);
86 }
87 void BitmapOutputDev::setMove(int x,int y)
88 {
89     this->gfxdev->setMove(x,y);
90     this->user_movex = x;
91     this->user_movey = y;
92 }
93 void BitmapOutputDev::setClip(int x1,int y1,int x2,int y2)
94 {
95     this->gfxdev->setClip(x1,y1,x2,y2);
96     this->user_clipx1 = x1;
97     this->user_clipy1 = y1;
98     this->user_clipx2 = x2;
99     this->user_clipy2 = y2;
100 }
101 void BitmapOutputDev::setParameter(const char*key, const char*value)
102 {
103     if(!strcmp(key, "extrafontdata")) {
104         this->config_extrafontdata = atoi(value);
105     } else if(!strcmp(key, "bitmapfonts")) {
106         this->config_bitmapfonts = atoi(value);
107     }
108     this->gfxdev->setParameter(key, value);
109 }
110 void BitmapOutputDev::preparePage(int pdfpage, int outputpage)
111 {
112 }
113
114 void getBitmapBBox(Guchar*alpha, int width, int height, int*xmin, int*ymin, int*xmax, int*ymax)
115 {
116     *ymin = -1;
117     *xmin = width;
118     *xmax = 0;
119     int x,y;
120     for(y=0;y<height;y++) {
121         Guchar*a = &alpha[y*width];
122         for(x=0;x<width;x++) {
123             if(a[x]) break;
124         }
125         int left = x; //first occupied pixel from left
126         int right = x+1; //last non-occupied pixel from right
127         for(;x<width;x++) {
128             if(a[x]) right=x+1;
129         }
130
131         if(left!=width) {
132             if(*ymin<0) 
133                 *ymin=y;
134             *ymax=y+1;
135             if(left<*xmin) *xmin = left;
136             if(right>*xmax) *xmax = right;
137         }
138     }
139     if(*xmin>=*xmax || *ymin>=*ymax) {
140         *xmin = 0;
141         *ymin = 0;
142         *xmax = 0;
143         *ymax = 0;
144     }
145 }
146
147 void BitmapOutputDev::flush()
148 {
149     int width = rgbdev->getBitmapWidth();
150     int height = rgbdev->getBitmapHeight();
151     SplashColorPtr rgb = rgbdev->getBitmap()->getDataPtr();
152     Guchar*alpha = rgbdev->getBitmap()->getAlphaPtr();
153
154     int xmin,ymin,xmax,ymax;
155     getBitmapBBox(alpha, width, height, &xmin,&ymin,&xmax,&ymax);
156
157     /* clip against (-movex, -movey, -movex+width, -movey+height) */
158     if(xmin < -this->movex) xmin = -this->movex;
159     if(ymin < -this->movey) ymin = -this->movey;
160     if(xmax > -this->movex + width) xmax = -this->movex+this->width;
161     if(ymax > -this->movey + height) ymax = -this->movey+this->height;
162
163     msg("<verbose> Flushing graphics (bbox: %d,%d,%d,%d)", xmin,ymin,xmax,ymax);
164     
165     if((xmax-xmin)<=0 || (ymax-ymin)<=0) // no bitmap, nothing to do
166         return;
167
168     if(sizeof(SplashColor)!=3) {
169         msg("<error> sizeof(SplashColor)!=3");
170         return;
171     }
172     //xmin = ymin = 0;
173     //xmax = width;
174     //ymax = height;
175
176     int rangex = xmax-xmin;
177     int rangey = ymax-ymin;
178     gfximage_t*img = (gfximage_t*)malloc(sizeof(gfximage_t)); 
179     img->data = (gfxcolor_t*)malloc(rangex * rangey * 4);
180     img->width = rangex;
181     img->height = rangey;
182     int x,y;
183     for(y=0;y<rangey;y++) {
184         SplashColorPtr in=&rgb[((y+ymin)*width+xmin)*sizeof(SplashColor)];
185         gfxcolor_t*out = &img->data[y*rangex];
186         Guchar*ain = &alpha[(y+ymin)*width+xmin];
187         for(x=0;x<rangex;x++) {
188             out[x].r = in[x*3+0];
189             out[x].g = in[x*3+1];
190             out[x].b = in[x*3+2];
191             out[x].a = ain[x];
192         }
193     }
194     /* transform bitmap rectangle to "device space" */
195     xmin += movex;
196     ymin += movey;
197     xmax += movex;
198     ymax += movey;
199
200     gfxmatrix_t m;
201     m.tx = xmin;
202     m.ty = ymin;
203     m.m00 = m.m11 = 1;
204     m.m10 = m.m01 = 0;
205
206     gfxline_t* line = gfxline_makerectangle(xmin, ymin, xmax, ymax);
207     dev->fillbitmap(dev, line, img, &m, 0);
208     gfxline_free(line);
209
210     memset(rgbdev->getBitmap()->getAlphaPtr(), 0, rgbdev->getBitmap()->getWidth()*rgbdev->getBitmap()->getHeight());
211     memset(rgbdev->getBitmap()->getDataPtr(), 0, rgbdev->getBitmap()->getWidth()*rgbdev->getBitmap()->getHeight()*sizeof(SplashColor));
212
213     free(img->data);img->data=0;free(img);img=0;
214 }
215
216 void BitmapOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
217 {
218     double x1,y1,x2,y2;
219     state->transform(crop_x1,crop_y1,&x1,&y1);
220     state->transform(crop_x2,crop_y2,&x2,&y2);
221     if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
222     if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
223     
224     this->movex = -(int)x1 - user_movex;
225     this->movey = -(int)y1 - user_movey;
226     
227     if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
228         x1 = user_clipx1;
229         x2 = user_clipx2;
230         y1 = user_clipy1;
231         y2 = user_clipy2;
232     }
233     this->width = (int)(x2-x1);
234     this->height = (int)(y2-y1);
235
236     msg("<verbose> startPage");
237     rgbdev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
238     clip0dev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
239     clip1dev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
240     gfxdev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
241
242     /*int width = this->rgbdev->getBitmap()->getWidth();
243     int height = this->rgbdev->getBitmap()->getHeight();
244     this->bboxpath = new SplashPath();
245     this->bboxpath->moveTo(0,0);
246     this->bboxpath->lineTo(width,0);
247     this->bboxpath->lineTo(width,height);
248     this->bboxpath->lineTo(0,height);
249     this->bboxpath->lineTo(0,0);
250
251     if(this->clipbitmap) {
252         delete this->clipbitmap;this->clipbitmap = 0;
253     }
254     this->clipbitmap = new SplashBitmap(width, height, 1, splashModeMono1, gFalse, gTrue);
255     if(this->clipdev) {
256         delete this->clipdev;this->clipdev = 0;
257     }
258     SplashScreenParams params;
259     params.type = splashScreenDispersed;
260     params.size = 0;
261     params.dotRadius = 0;
262     this->clipdev = new Splash(this->clipbitmap, 0, (SplashScreenParams*)0);*/
263 }
264
265 void BitmapOutputDev::endPage()
266 {
267     msg("<verbose> endPage");
268     this->flush();
269
270     /* splash will now destroy alpha, and paint the 
271        background color into the "holes" in the bitmap */
272     rgbdev->endPage();
273     clip0dev->endPage();
274     clip1dev->endPage();
275 }
276
277 GBool BitmapOutputDev::upsideDown()
278 {
279     clip0dev->upsideDown();
280     clip1dev->upsideDown();
281     return rgbdev->upsideDown();
282 }
283
284 GBool BitmapOutputDev::useDrawChar()
285 {
286     clip0dev->useDrawChar();
287     clip1dev->useDrawChar();
288     return rgbdev->useDrawChar();
289 }
290
291 GBool BitmapOutputDev::useTilingPatternFill()
292 {
293     clip0dev->useTilingPatternFill();
294     clip1dev->useTilingPatternFill();
295     return rgbdev->useTilingPatternFill();
296 }
297
298 GBool BitmapOutputDev::useShadedFills()
299 {
300     clip0dev->useTilingPatternFill();
301     clip1dev->useTilingPatternFill();
302     return rgbdev->useTilingPatternFill();
303 }
304
305 GBool BitmapOutputDev::useDrawForm()
306 {
307     clip0dev->useDrawForm();
308     clip1dev->useDrawForm();
309     return rgbdev->useDrawForm();
310 }
311
312 GBool BitmapOutputDev::interpretType3Chars()
313 {
314     if(!config_bitmapfonts) {
315         clip0dev->interpretType3Chars();
316         clip1dev->interpretType3Chars();
317         return rgbdev->interpretType3Chars();
318     } else {
319         return gfxdev->interpretType3Chars();
320     }
321 }
322
323 GBool BitmapOutputDev::needNonText() 
324 {
325     clip0dev->needNonText();
326     clip1dev->needNonText();
327     return rgbdev->needNonText();
328 }
329 /*GBool BitmapOutputDev::checkPageSlice(Page *page, double hDPI, double vDPI,
330                            int rotate, GBool useMediaBox, GBool crop,
331                            int sliceX, int sliceY, int sliceW, int sliceH,
332                            GBool printing, Catalog *catalog,
333                            GBool (*abortCheckCbk)(void *data),
334                            void *abortCheckCbkData)
335 {
336     return gTrue;
337 }*/
338 void BitmapOutputDev::setDefaultCTM(double *ctm) 
339 {
340     rgbdev->setDefaultCTM(ctm);
341     clip0dev->setDefaultCTM(ctm);
342     clip1dev->setDefaultCTM(ctm);
343 }
344 void BitmapOutputDev::saveState(GfxState *state) 
345 {
346     rgbdev->saveState(state);
347     clip0dev->saveState(state);
348     clip1dev->saveState(state);
349
350     /*ClipState*cstate = new ClipState();
351     cstate->next = this->clipstates;
352     this->clipstates = cstate;*/
353 }
354 void BitmapOutputDev::restoreState(GfxState *state) 
355 {
356     rgbdev->restoreState(state);
357     clip0dev->restoreState(state);
358     clip1dev->restoreState(state);
359
360     /*if(this->clipstates) {
361         ClipState*old = this->clipstates;
362         if(old->written) {
363             gfxdev->restoreState(state);
364         }
365         this->clipstates = this->clipstates->next;
366         delete(old);
367     } else {
368         msg("<error> invalid restoreState()");
369     }*/
370 }
371 void BitmapOutputDev::updateAll(GfxState *state)
372 {
373     rgbdev->updateAll(state);
374     clip0dev->updateAll(state);
375     clip1dev->updateAll(state);
376 }
377 void BitmapOutputDev::updateCTM(GfxState *state, double m11, double m12, double m21, double m22, double m31, double m32)
378 {
379     rgbdev->updateCTM(state,m11,m12,m21,m22,m31,m32);
380     clip0dev->updateCTM(state,m11,m12,m21,m22,m31,m32);
381     clip1dev->updateCTM(state,m11,m12,m21,m22,m31,m32);
382 }
383 void BitmapOutputDev::updateLineDash(GfxState *state)
384 {
385     rgbdev->updateLineDash(state);
386     clip0dev->updateLineDash(state);
387     clip1dev->updateLineDash(state);
388 }
389 void BitmapOutputDev::updateFlatness(GfxState *state)
390 {
391     rgbdev->updateFlatness(state);
392     clip0dev->updateFlatness(state);
393     clip1dev->updateFlatness(state);
394 }
395 void BitmapOutputDev::updateLineJoin(GfxState *state)
396 {
397     rgbdev->updateLineJoin(state);
398     clip0dev->updateLineJoin(state);
399     clip1dev->updateLineJoin(state);
400 }
401 void BitmapOutputDev::updateLineCap(GfxState *state)
402 {
403     rgbdev->updateLineCap(state);
404     clip0dev->updateLineCap(state);
405     clip1dev->updateLineCap(state);
406 }
407 void BitmapOutputDev::updateMiterLimit(GfxState *state)
408 {
409     rgbdev->updateMiterLimit(state);
410     clip0dev->updateMiterLimit(state);
411     clip1dev->updateMiterLimit(state);
412 }
413 void BitmapOutputDev::updateLineWidth(GfxState *state)
414 {
415     rgbdev->updateLineWidth(state);
416     clip0dev->updateLineWidth(state);
417     clip1dev->updateLineWidth(state);
418 }
419 void BitmapOutputDev::updateStrokeAdjust(GfxState *state)
420 {
421     rgbdev->updateStrokeAdjust(state);
422     clip0dev->updateStrokeAdjust(state);
423     clip1dev->updateStrokeAdjust(state);
424 }
425 void BitmapOutputDev::updateFillColorSpace(GfxState *state)
426 {
427     rgbdev->updateFillColorSpace(state);
428     clip0dev->updateFillColorSpace(state);
429     clip1dev->updateFillColorSpace(state);
430 }
431 void BitmapOutputDev::updateStrokeColorSpace(GfxState *state)
432 {
433     rgbdev->updateStrokeColorSpace(state);
434     clip0dev->updateStrokeColorSpace(state);
435     clip1dev->updateStrokeColorSpace(state);
436 }
437 void BitmapOutputDev::updateFillColor(GfxState *state)
438 {
439     rgbdev->updateFillColor(state);
440     clip0dev->updateFillColor(state);
441     clip0dev->updateFillColor(state);
442     clip1dev->updateFillColor(state);
443 }
444 void BitmapOutputDev::updateStrokeColor(GfxState *state)
445 {
446     rgbdev->updateStrokeColor(state);
447     clip0dev->updateStrokeColor(state);
448     clip1dev->updateStrokeColor(state);
449 }
450 void BitmapOutputDev::updateBlendMode(GfxState *state)
451 {
452     rgbdev->updateBlendMode(state);
453     clip0dev->updateBlendMode(state);
454     clip1dev->updateBlendMode(state);
455 }
456 void BitmapOutputDev::updateFillOpacity(GfxState *state)
457 {
458     rgbdev->updateFillOpacity(state);
459     clip0dev->updateFillOpacity(state);
460     clip1dev->updateFillOpacity(state);
461 }
462 void BitmapOutputDev::updateStrokeOpacity(GfxState *state)
463 {
464     rgbdev->updateStrokeOpacity(state);
465     clip0dev->updateStrokeOpacity(state);
466     clip1dev->updateStrokeOpacity(state);
467 }
468 void BitmapOutputDev::updateFillOverprint(GfxState *state)
469 {
470     rgbdev->updateFillOverprint(state);
471     clip0dev->updateFillOverprint(state);
472     clip1dev->updateFillOverprint(state);
473 }
474 void BitmapOutputDev::updateStrokeOverprint(GfxState *state)
475 {
476     rgbdev->updateStrokeOverprint(state);
477     clip0dev->updateStrokeOverprint(state);
478     clip1dev->updateStrokeOverprint(state);
479 }
480 void BitmapOutputDev::updateTransfer(GfxState *state)
481 {
482     rgbdev->updateTransfer(state);
483     clip0dev->updateTransfer(state);
484     clip1dev->updateTransfer(state);
485 }
486 void BitmapOutputDev::updateFont(GfxState *state)
487 {
488     rgbdev->updateFont(state);
489     clip0dev->updateFont(state);
490     clip1dev->updateFont(state);
491     if(!config_bitmapfonts)
492         gfxdev->updateFont(state);
493 }
494 void BitmapOutputDev::updateTextMat(GfxState *state)
495 {
496     rgbdev->updateTextMat(state);
497     clip0dev->updateTextMat(state);
498     clip1dev->updateTextMat(state);
499     if(!config_bitmapfonts)
500         gfxdev->updateTextMat(state);
501 }
502 void BitmapOutputDev::updateCharSpace(GfxState *state)
503 {
504     rgbdev->updateCharSpace(state);
505     clip0dev->updateCharSpace(state);
506     clip1dev->updateCharSpace(state);
507     if(!config_bitmapfonts)
508         gfxdev->updateCharSpace(state);
509 }
510 void BitmapOutputDev::updateRender(GfxState *state)
511 {
512     rgbdev->updateRender(state);
513     clip0dev->updateRender(state);
514     clip1dev->updateRender(state);
515     if(!config_bitmapfonts)
516         gfxdev->updateRender(state);
517 }
518 void BitmapOutputDev::updateRise(GfxState *state)
519 {
520     rgbdev->updateRise(state);
521     clip0dev->updateRise(state);
522     clip1dev->updateRise(state);
523     if(!config_bitmapfonts)
524         gfxdev->updateRise(state);
525 }
526 void BitmapOutputDev::updateWordSpace(GfxState *state)
527 {
528     rgbdev->updateWordSpace(state);
529     clip0dev->updateWordSpace(state);
530     clip1dev->updateWordSpace(state);
531     if(!config_bitmapfonts)
532         gfxdev->updateWordSpace(state);
533 }
534 void BitmapOutputDev::updateHorizScaling(GfxState *state)
535 {
536     rgbdev->updateHorizScaling(state);
537     clip0dev->updateHorizScaling(state);
538     clip1dev->updateHorizScaling(state);
539     if(!config_bitmapfonts)
540         gfxdev->updateHorizScaling(state);
541 }
542 void BitmapOutputDev::updateTextPos(GfxState *state)
543 {
544     rgbdev->updateTextPos(state);
545     clip0dev->updateTextPos(state);
546     clip1dev->updateTextPos(state);
547     if(!config_bitmapfonts)
548         gfxdev->updateTextPos(state);
549 }
550 void BitmapOutputDev::updateTextShift(GfxState *state, double shift)
551 {
552     rgbdev->updateTextShift(state, shift);
553     clip0dev->updateTextShift(state, shift);
554     clip1dev->updateTextShift(state, shift);
555 }
556
557 void BitmapOutputDev::stroke(GfxState *state)
558 {
559     msg("<verbose> stroke");
560     rgbdev->stroke(state);
561 }
562 void BitmapOutputDev::fill(GfxState *state)
563 {
564     msg("<verbose> fill");
565     rgbdev->fill(state);
566 }
567 void BitmapOutputDev::eoFill(GfxState *state)
568 {
569     msg("<verbose> eoFill");
570     rgbdev->eoFill(state);
571 }
572 #if (xpdfMajorVersion < 3) || (xpdfMinorVersion < 2) || (xpdfUpdateVersion < 7)
573 void BitmapOutputDev::tilingPatternFill(GfxState *state, Object *str,
574                                int paintType, Dict *resDict,
575                                double *mat, double *bbox,
576                                int x0, int y0, int x1, int y1,
577                                double xStep, double yStep)
578 {
579     msg("<verbose> tilingPatternFill");
580     rgbdev->tilingPatternFill(state, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep);
581 }
582 #else
583 void BitmapOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Object *str,
584                                int paintType, Dict *resDict,
585                                double *mat, double *bbox,
586                                int x0, int y0, int x1, int y1,
587                                double xStep, double yStep) 
588 {
589     msg("<verbose> tilingPatternFill");
590     rgbdev->tilingPatternFill(state, gfx, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep);
591 }
592 #endif
593
594 GBool BitmapOutputDev::functionShadedFill(GfxState *state, GfxFunctionShading *shading) 
595 {
596     msg("<verbose> functionShadedFill");
597     return rgbdev->functionShadedFill(state, shading);
598 }
599 GBool BitmapOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading)
600 {
601     msg("<verbose> axialShadedFill");
602     return rgbdev->axialShadedFill(state, shading);
603 }
604 GBool BitmapOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading)
605 {
606     msg("<verbose> radialShadedFill");
607     return rgbdev->radialShadedFill(state, shading);
608 }
609
610 SplashColor black = {0,0,0};
611 SplashColor white = {255,255,255};
612
613 void BitmapOutputDev::doClip(GfxState *state, GBool eo)
614 {
615     if(!eo) {
616         rgbdev->clip(state);
617         clip1dev->clip(state);
618     } else {
619         rgbdev->eoClip(state);
620         clip1dev->eoClip(state);
621     }
622
623     //SplashPattern *pblack = new SplashSolidColor(black);
624     //SplashPattern *pwhite = new SplashSolidColor(white);
625     //SplashPath* path = rgbdev->convertPath(state, state->getPath());
626     //clipdev->clear(black, 0);
627     //clipdev->clipToPath(path, eo);
628     //clipdev->setFillPattern(pwhite);
629     //clipdev->fill(bboxpath,gFalse);
630     //delete path;
631 }
632
633 void BitmapOutputDev::clip(GfxState *state)
634 {
635     msg("<verbose> clip");
636     doClip(state, gFalse);
637 }
638 void BitmapOutputDev::eoClip(GfxState *state)
639 {
640     msg("<verbose> eoClip");
641     doClip(state, gTrue);
642 }
643 void BitmapOutputDev::clipToStrokePath(GfxState *state)
644 {
645     msg("<verbose> clipToStrokePath");
646     rgbdev->clipToStrokePath(state);
647     clip1dev->clipToStrokePath(state);
648 }
649
650 void BitmapOutputDev::beginStringOp(GfxState *state)
651 {
652     msg("<verbose> beginStringOp");
653     if(this->config_bitmapfonts) {
654         rgbdev->beginStringOp(state);
655         clip0dev->beginStringOp(state);
656         clip1dev->beginStringOp(state);
657     } else {
658         gfxdev->beginStringOp(state);
659     }
660 }
661 void BitmapOutputDev::endStringOp(GfxState *state)
662 {
663     msg("<verbose> endStringOp");
664     if(this->config_bitmapfonts) {
665         rgbdev->endStringOp(state);
666         clip0dev->endStringOp(state);
667         clip1dev->endStringOp(state);
668     } else {
669         gfxdev->endStringOp(state);
670     }
671 }
672 void BitmapOutputDev::beginString(GfxState *state, GString *s)
673 {
674     msg("<verbose> beginString");
675     if(this->config_bitmapfonts) {
676         rgbdev->beginString(state, s);
677         clip0dev->beginString(state, s);
678         clip1dev->beginString(state, s);
679     } else {
680         gfxdev->beginString(state, s);
681     }
682 }
683 void BitmapOutputDev::endString(GfxState *state)
684 {
685     msg("<verbose> endString");
686     if(this->config_bitmapfonts) {
687         rgbdev->endString(state);
688         clip0dev->endString(state);
689         clip1dev->endString(state);
690     } else {
691         gfxdev->endString(state);
692     }
693 }
694 void BitmapOutputDev::drawChar(GfxState *state, double x, double y,
695                       double dx, double dy,
696                       double originX, double originY,
697                       CharCode code, int nBytes, Unicode *u, int uLen)
698 {
699     msg("<verbose> drawChar");
700     if(this->config_bitmapfonts || (state->getRender()&4) /*clip*/ ) {
701         rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
702     } else {
703         SplashBitmap*clip0 = clip0dev->getBitmap();
704         SplashBitmap*clip1 = clip1dev->getBitmap();
705         int width8 = (clip0->getWidth()+7)/8;
706         int width = clip0->getWidth();
707         int height = clip0->getHeight();
708         memset(clip0->getDataPtr(), 0, width8*height);
709         memset(clip1->getDataPtr(), 0, width8*height);
710         clip0dev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
711         clip1dev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
712
713         /* if this character is affected somehow by the various clippings (i.e., it looks
714            different on a device without clipping), then draw it on the bitmap, not as
715            text */
716         if(memcmp(clip0->getDataPtr(), clip1->getDataPtr(), width8*height)) {
717             msg("<verbose> Char %d is affected by clipping", code);
718
719             rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
720             if(config_extrafontdata) {
721                 int oldrender = state->getRender();
722                 state->setRender(3); //invisible
723                 gfxdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
724                 state->setRender(oldrender);
725             }
726         } else {
727             /* this char is not at all affected by clipping. Now just find out whether the
728                bitmap we're currently working on needs to be dumped out first */
729     
730             Guchar*alpha = rgbdev->getBitmap()->getAlphaPtr();
731             Guchar*charpixels = clip1dev->getBitmap()->getDataPtr();
732             int xx,yy;
733             for(yy=0;yy<height;yy++) {
734                 Guchar*aline = &alpha[yy*width];
735                 Guchar*cline = &charpixels[yy*width8];
736                 for(xx=0;xx<width;xx++) {
737                     int bit = xx&7;
738                     int bytepos = xx>>3;
739                     /* TODO: is the bit order correct? */
740                     if(aline[xx] && (cline[bytepos]&(1<<bit))) 
741                         break;
742                 }
743                 if(xx!=width)
744                     break;
745             }
746
747             if(yy!=height) {
748                 /* yes, the graphic data and the characters overlap (the char is
749                    above the current bitmap. Flush the bitmap to the output. */
750                 msg("<verbose> Char %d is above current bitmap data", code);
751                 flush();
752             } 
753             gfxdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
754         }
755     }
756 }
757 void BitmapOutputDev::drawString(GfxState *state, GString *s)
758 {
759     msg("<verbose> drawString");
760     if(this->config_bitmapfonts) {
761         rgbdev->drawString(state, s);
762         clip0dev->drawString(state, s);
763         clip1dev->drawString(state, s);
764     } else {
765         gfxdev->drawString(state, s);
766     }
767 }
768 void BitmapOutputDev::endTextObject(GfxState *state)
769 {
770     msg("<verbose> endTextObject");
771     if(this->config_bitmapfonts) {
772         rgbdev->endTextObject(state);
773         clip0dev->endTextObject(state);
774         clip1dev->endTextObject(state);
775     } else {
776         gfxdev->endType3Char(state);
777     }
778 }
779 GBool BitmapOutputDev::beginType3Char(GfxState *state, double x, double y,
780                              double dx, double dy,
781                              CharCode code, Unicode *u, int uLen)
782 {
783     msg("<verbose> beginType3Char");
784     if(this->config_bitmapfonts) {
785         return rgbdev->beginType3Char(state, x, y, dx, dy, code, u, uLen);
786     } else {
787         return gfxdev->beginType3Char(state, x, y, dx, dy, code, u, uLen);
788     }
789 }
790 void BitmapOutputDev::type3D0(GfxState *state, double wx, double wy)
791 {
792     msg("<verbose> type3D0");
793     if(this->config_bitmapfonts) {
794         rgbdev->type3D0(state, wx, wy);
795     } else {
796         return gfxdev->type3D0(state, wx, wy);
797     }
798 }
799 void BitmapOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury)
800 {
801     msg("<verbose> type3D1");
802     if(this->config_bitmapfonts) {
803         rgbdev->type3D1(state, wx, wy, llx, lly, urx, ury);
804     } else {
805         return gfxdev->type3D1(state, wx, wy, llx, lly, urx, ury);
806     }
807 }
808 void BitmapOutputDev::endType3Char(GfxState *state)
809 {
810     msg("<verbose> endType3Char");
811     if(this->config_bitmapfonts) {
812         rgbdev->endType3Char(state);
813     } else {
814         gfxdev->endType3Char(state);
815     }
816 }
817 void BitmapOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
818                            int width, int height, GBool invert,
819                            GBool inlineImg)
820 {
821     msg("<verbose> drawImageMask");
822     rgbdev->drawImageMask(state, ref, str, width, height, invert, inlineImg);
823 }
824 void BitmapOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
825                        int width, int height, GfxImageColorMap *colorMap,
826                        int *maskColors, GBool inlineImg)
827 {
828     msg("<verbose> drawImage");
829     rgbdev->drawImage(state, ref, str, width, height, colorMap, maskColors, inlineImg);
830 }
831 void BitmapOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
832                              int width, int height,
833                              GfxImageColorMap *colorMap,
834                              Stream *maskStr, int maskWidth, int maskHeight,
835                              GBool maskInvert)
836 {
837     msg("<verbose> drawMaskedImage");
838     rgbdev->drawMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert);
839 }
840 void BitmapOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
841                                  int width, int height,
842                                  GfxImageColorMap *colorMap,
843                                  Stream *maskStr,
844                                  int maskWidth, int maskHeight,
845                                  GfxImageColorMap *maskColorMap)
846 {
847     msg("<verbose> drawSoftMaskedImage");
848     rgbdev->drawSoftMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap);
849 }
850 void BitmapOutputDev::drawForm(Ref id)
851 {
852     msg("<verbose> drawForm");
853     rgbdev->drawForm(id);
854 }
855
856 void BitmapOutputDev::processLink(Link *link, Catalog *catalog)
857 {
858     msg("<verbose> processLink");
859     gfxdev->processLink(link, catalog);
860 }
861
862 void BitmapOutputDev::beginTransparencyGroup(GfxState *state, double *bbox,
863                                     GfxColorSpace *blendingColorSpace,
864                                     GBool isolated, GBool knockout,
865                                     GBool forSoftMask)
866 {
867     msg("<verbose> beginTransparencyGroup");
868     rgbdev->beginTransparencyGroup(state, bbox, blendingColorSpace, isolated, knockout, forSoftMask);
869     clip1dev->beginTransparencyGroup(state, bbox, blendingColorSpace, isolated, knockout, forSoftMask);
870 }
871 void BitmapOutputDev::endTransparencyGroup(GfxState *state)
872 {
873     msg("<verbose> endTransparencyGroup");
874     rgbdev->endTransparencyGroup(state);
875     clip1dev->endTransparencyGroup(state);
876 }
877 void BitmapOutputDev::paintTransparencyGroup(GfxState *state, double *bbox)
878 {
879     msg("<verbose> paintTransparencyGroup");
880     rgbdev->paintTransparencyGroup(state,bbox);
881 }
882 void BitmapOutputDev::setSoftMask(GfxState *state, double *bbox, GBool alpha, Function *transferFunc, GfxColor *backdropColor)
883 {
884     msg("<verbose> setSoftMask");
885     rgbdev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
886     clip1dev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
887 }
888 void BitmapOutputDev::clearSoftMask(GfxState *state)
889 {
890     msg("<verbose> clearSoftMask");
891     rgbdev->clearSoftMask(state);
892     clip1dev->clearSoftMask(state);
893 }