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