1 //========================================================================
2 //
3 // Splash.cc
4 //
5 //========================================================================
6 
7 //========================================================================
8 //
9 // Modified under the Poppler project - http://poppler.freedesktop.org
10 //
11 // All changes made under the Poppler project to this file are licensed
12 // under GPL version 2 or later
13 //
14 // Copyright (C) 2005-2010 Albert Astals Cid <aacid@kde.org>
15 // Copyright (C) 2005 Marco Pesenti Gritti <mpg@redhat.com>
16 // Copyright (C) 2010 Thomas Freitag <Thomas.Freitag@alfa.de>
17 // Copyright (C) 2010 Christian Feuers�nger <cfeuersaenger@googlemail.com>
18 //
19 // To see a description of the changes please see the Changelog file that
20 // came with your tarball or type make ChangeLog if you are building from git
21 //
22 //========================================================================
23 
24 #include <config.h>
25 
26 #ifdef USE_GCC_PRAGMAS
27 #pragma implementation
28 #endif
29 
30 #include <stdlib.h>
31 #include <string.h>
32 #include <limits.h>
33 #include <assert.h>
34 #include "goo/gmem.h"
35 #include "goo/GooLikely.h"
36 #include "poppler/Error.h"
37 #include "SplashErrorCodes.h"
38 #include "SplashMath.h"
39 #include "SplashBitmap.h"
40 #include "SplashState.h"
41 #include "SplashPath.h"
42 #include "SplashXPath.h"
43 #include "SplashXPathScanner.h"
44 #include "SplashPattern.h"
45 #include "SplashScreen.h"
46 #include "SplashFont.h"
47 #include "SplashGlyphBitmap.h"
48 #include "Splash.h"
49 
50 //------------------------------------------------------------------------
51 
52 // distance of Bezier control point from center for circle approximation
53 // = (4 * (sqrt(2) - 1) / 3) * r
54 #define bezierCircle ((SplashCoord)0.55228475)
55 #define bezierCircle2 ((SplashCoord)(0.5 * 0.55228475))
56 
57 // Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result.
div255(int x)58 static inline Guchar div255(int x) {
59   return (Guchar)((x + (x >> 8) + 0x80) >> 8);
60 }
61 
62 template<typename T>
Guswap(T & a,T & b)63 inline void Guswap( T&a, T&b ) { T tmp = a; a=b; b=tmp; }
64 
65 //------------------------------------------------------------------------
66 // SplashPipe
67 //------------------------------------------------------------------------
68 
69 #define splashPipeMaxStages 9
70 
71 struct SplashPipe {
72   // pixel coordinates
73   int x, y;
74 
75   // source pattern
76   SplashPattern *pattern;
77 
78   // source alpha and color
79   SplashCoord aInput;
80   GBool usesShape;
81   Guchar aSrc;
82   SplashColorPtr cSrc;
83   SplashColor cSrcVal;
84 
85   // non-isolated group alpha0
86   Guchar *alpha0Ptr;
87 
88   // soft mask
89   SplashColorPtr softMaskPtr;
90 
91   // destination alpha and color
92   SplashColorPtr destColorPtr;
93   int destColorMask;
94   Guchar *destAlphaPtr;
95 
96   // shape
97   SplashCoord shape;
98 
99   // result alpha and color
100   GBool noTransparency;
101   SplashPipeResultColorCtrl resultColorCtrl;
102 
103   // non-isolated group correction
104   int nonIsolatedGroup;
105 };
106 
107 SplashPipeResultColorCtrl Splash::pipeResultColorNoAlphaBlend[] = {
108   splashPipeResultColorNoAlphaBlendMono,
109   splashPipeResultColorNoAlphaBlendMono,
110   splashPipeResultColorNoAlphaBlendRGB,
111   splashPipeResultColorNoAlphaBlendRGB,
112   splashPipeResultColorNoAlphaBlendRGB
113 #if SPLASH_CMYK
114   ,
115   splashPipeResultColorNoAlphaBlendCMYK
116 #endif
117 };
118 
119 SplashPipeResultColorCtrl Splash::pipeResultColorAlphaNoBlend[] = {
120   splashPipeResultColorAlphaNoBlendMono,
121   splashPipeResultColorAlphaNoBlendMono,
122   splashPipeResultColorAlphaNoBlendRGB,
123   splashPipeResultColorNoAlphaBlendRGB,
124   splashPipeResultColorAlphaNoBlendRGB
125 #if SPLASH_CMYK
126   ,
127   splashPipeResultColorAlphaNoBlendCMYK
128 #endif
129 };
130 
131 SplashPipeResultColorCtrl Splash::pipeResultColorAlphaBlend[] = {
132   splashPipeResultColorAlphaBlendMono,
133   splashPipeResultColorAlphaBlendMono,
134   splashPipeResultColorAlphaBlendRGB,
135   splashPipeResultColorNoAlphaBlendRGB,
136   splashPipeResultColorAlphaBlendRGB
137 #if SPLASH_CMYK
138   ,
139   splashPipeResultColorAlphaBlendCMYK
140 #endif
141 };
142 
143 //------------------------------------------------------------------------
144 
blendXor(SplashColorPtr src,SplashColorPtr dest,SplashColorPtr blend,SplashColorMode cm)145 static void blendXor(SplashColorPtr src, SplashColorPtr dest,
146 		     SplashColorPtr blend, SplashColorMode cm) {
147   int i;
148 
149   for (i = 0; i < splashColorModeNComps[cm]; ++i) {
150     blend[i] = src[i] ^ dest[i];
151   }
152 }
153 
154 //------------------------------------------------------------------------
155 // modified region
156 //------------------------------------------------------------------------
157 
clearModRegion()158 void Splash::clearModRegion() {
159   modXMin = bitmap->getWidth();
160   modYMin = bitmap->getHeight();
161   modXMax = -1;
162   modYMax = -1;
163 }
164 
updateModX(int x)165 inline void Splash::updateModX(int x) {
166   if (x < modXMin) {
167     modXMin = x;
168   }
169   if (x > modXMax) {
170     modXMax = x;
171   }
172 }
173 
updateModY(int y)174 inline void Splash::updateModY(int y) {
175   if (y < modYMin) {
176     modYMin = y;
177   }
178   if (y > modYMax) {
179     modYMax = y;
180   }
181 }
182 
183 //------------------------------------------------------------------------
184 // pipeline
185 //------------------------------------------------------------------------
186 
pipeInit(SplashPipe * pipe,int x,int y,SplashPattern * pattern,SplashColorPtr cSrc,SplashCoord aInput,GBool usesShape,GBool nonIsolatedGroup)187 inline void Splash::pipeInit(SplashPipe *pipe, int x, int y,
188 			     SplashPattern *pattern, SplashColorPtr cSrc,
189 			     SplashCoord aInput, GBool usesShape,
190 			     GBool nonIsolatedGroup) {
191   pipeSetXY(pipe, x, y);
192   pipe->pattern = NULL;
193 
194   // source color
195   if (pattern) {
196     if (pattern->isStatic()) {
197       pattern->getColor(x, y, pipe->cSrcVal);
198     } else {
199       pipe->pattern = pattern;
200     }
201     pipe->cSrc = pipe->cSrcVal;
202   } else {
203     pipe->cSrc = cSrc;
204   }
205 
206   // source alpha
207   pipe->aInput = aInput;
208   if (!state->softMask) {
209     if (usesShape) {
210       pipe->aInput *= 255;
211     } else {
212       pipe->aSrc = (Guchar)splashRound(pipe->aInput * 255);
213     }
214   }
215   pipe->usesShape = usesShape;
216 
217   // result alpha
218   if (aInput == 1 && !state->softMask && !usesShape &&
219       !state->inNonIsolatedGroup) {
220     pipe->noTransparency = gTrue;
221   } else {
222     pipe->noTransparency = gFalse;
223   }
224 
225   // result color
226   if (pipe->noTransparency) {
227     // the !state->blendFunc case is handled separately in pipeRun
228     pipe->resultColorCtrl = pipeResultColorNoAlphaBlend[bitmap->mode];
229   } else if (!state->blendFunc) {
230     pipe->resultColorCtrl = pipeResultColorAlphaNoBlend[bitmap->mode];
231   } else {
232     pipe->resultColorCtrl = pipeResultColorAlphaBlend[bitmap->mode];
233   }
234 
235   // non-isolated group correction
236   if (nonIsolatedGroup) {
237     pipe->nonIsolatedGroup = splashColorModeNComps[bitmap->mode];
238   } else {
239     pipe->nonIsolatedGroup = 0;
240   }
241 }
242 
pipeRun(SplashPipe * pipe)243 inline void Splash::pipeRun(SplashPipe *pipe) {
244   Guchar aSrc, aDest, alpha2, alpha0, aResult;
245   SplashColor cDest, cBlend;
246   Guchar cResult0, cResult1, cResult2, cResult3;
247 
248   //----- source color
249 
250   // static pattern: handled in pipeInit
251   // fixed color: handled in pipeInit
252 
253   // dynamic pattern
254   if (pipe->pattern) {
255     if (!pipe->pattern->getColor(pipe->x, pipe->y, pipe->cSrcVal)) {
256       switch (bitmap->mode) {
257         case splashModeMono1:
258           if (!(pipe->destColorMask >>= 1))
259             ++pipe->destColorPtr;
260         break;
261         case splashModeMono8:
262           ++pipe->destColorPtr;
263         break;
264         case splashModeBGR8:
265         case splashModeRGB8:
266           pipe->destColorPtr += 3;
267         break;
268         case splashModeXBGR8:
269 #if SPLASH_CMYK
270         case splashModeCMYK8:
271 #endif
272           pipe->destColorPtr += 4;
273         break;
274       }
275       if (pipe->destAlphaPtr) {
276         ++pipe->destAlphaPtr;
277       }
278       ++pipe->x;
279       return;
280     }
281   }
282 
283   if (pipe->noTransparency && !state->blendFunc) {
284 
285     //----- write destination pixel
286 
287     switch (bitmap->mode) {
288     case splashModeMono1:
289       cResult0 = pipe->cSrc[0];
290       if (state->screen->test(pipe->x, pipe->y, cResult0)) {
291 	*pipe->destColorPtr |= pipe->destColorMask;
292       } else {
293 	*pipe->destColorPtr &= ~pipe->destColorMask;
294       }
295       if (!(pipe->destColorMask >>= 1)) {
296 	pipe->destColorMask = 0x80;
297 	++pipe->destColorPtr;
298       }
299       break;
300     case splashModeMono8:
301       *pipe->destColorPtr++ = pipe->cSrc[0];
302       break;
303     case splashModeRGB8:
304       *pipe->destColorPtr++ = pipe->cSrc[0];
305       *pipe->destColorPtr++ = pipe->cSrc[1];
306       *pipe->destColorPtr++ = pipe->cSrc[2];
307       break;
308     case splashModeXBGR8:
309       *pipe->destColorPtr++ = pipe->cSrc[2];
310       *pipe->destColorPtr++ = pipe->cSrc[1];
311       *pipe->destColorPtr++ = pipe->cSrc[0];
312       *pipe->destColorPtr++ = 255;
313       break;
314     case splashModeBGR8:
315       *pipe->destColorPtr++ = pipe->cSrc[2];
316       *pipe->destColorPtr++ = pipe->cSrc[1];
317       *pipe->destColorPtr++ = pipe->cSrc[0];
318       break;
319 #if SPLASH_CMYK
320     case splashModeCMYK8:
321       *pipe->destColorPtr++ = pipe->cSrc[0];
322       *pipe->destColorPtr++ = pipe->cSrc[1];
323       *pipe->destColorPtr++ = pipe->cSrc[2];
324       *pipe->destColorPtr++ = pipe->cSrc[3];
325       break;
326 #endif
327     }
328     if (pipe->destAlphaPtr) {
329       *pipe->destAlphaPtr++ = 255;
330     }
331 
332   } else {
333 
334     //----- read destination pixel
335 
336     switch (bitmap->mode) {
337     case splashModeMono1:
338       cDest[0] = (*pipe->destColorPtr & pipe->destColorMask) ? 0xff : 0x00;
339       break;
340     case splashModeMono8:
341       cDest[0] = *pipe->destColorPtr;
342       break;
343     case splashModeRGB8:
344       cDest[0] = pipe->destColorPtr[0];
345       cDest[1] = pipe->destColorPtr[1];
346       cDest[2] = pipe->destColorPtr[2];
347       break;
348     case splashModeXBGR8:
349       cDest[0] = pipe->destColorPtr[2];
350       cDest[1] = pipe->destColorPtr[1];
351       cDest[2] = pipe->destColorPtr[0];
352       cDest[3] = 255;
353       break;
354     case splashModeBGR8:
355       cDest[0] = pipe->destColorPtr[2];
356       cDest[1] = pipe->destColorPtr[1];
357       cDest[2] = pipe->destColorPtr[0];
358       break;
359 #if SPLASH_CMYK
360     case splashModeCMYK8:
361       cDest[0] = pipe->destColorPtr[0];
362       cDest[1] = pipe->destColorPtr[1];
363       cDest[2] = pipe->destColorPtr[2];
364       cDest[3] = pipe->destColorPtr[3];
365       break;
366 #endif
367     }
368     if (pipe->destAlphaPtr) {
369       aDest = *pipe->destAlphaPtr;
370     } else {
371       aDest = 0xff;
372     }
373 
374     //----- blend function
375 
376     if (state->blendFunc) {
377       (*state->blendFunc)(pipe->cSrc, cDest, cBlend, bitmap->mode);
378     }
379 
380     //----- source alpha
381 
382     if (state->softMask) {
383       if (pipe->usesShape) {
384 	aSrc = (Guchar)splashRound(pipe->aInput * *pipe->softMaskPtr++
385 				   * pipe->shape);
386       } else {
387 	aSrc = (Guchar)splashRound(pipe->aInput * *pipe->softMaskPtr++);
388       }
389     } else if (pipe->usesShape) {
390       // pipe->aInput is premultiplied by 255 in pipeInit
391       aSrc = (Guchar)splashRound(pipe->aInput * pipe->shape);
392     } else {
393       // precomputed in pipeInit
394       aSrc = pipe->aSrc;
395     }
396 
397     //----- result alpha and non-isolated group element correction
398 
399     if (pipe->noTransparency) {
400       alpha2 = aResult = 255;
401     } else {
402       aResult = aSrc + aDest - div255(aSrc * aDest);
403 
404       if (pipe->alpha0Ptr) {
405 	alpha0 = *pipe->alpha0Ptr++;
406 	alpha2 = aResult + alpha0 - div255(aResult * alpha0);
407       } else {
408 	alpha2 = aResult;
409       }
410     }
411 
412     //----- result color
413 
414     cResult0 = cResult1 = cResult2 = cResult3 = 0; // make gcc happy
415 
416     switch (pipe->resultColorCtrl) {
417 
418 #if SPLASH_CMYK
419     case splashPipeResultColorNoAlphaBlendCMYK:
420       cResult3 = div255((255 - aDest) * pipe->cSrc[3] + aDest * cBlend[3]);
421 #endif
422     case splashPipeResultColorNoAlphaBlendRGB:
423       cResult2 = div255((255 - aDest) * pipe->cSrc[2] + aDest * cBlend[2]);
424       cResult1 = div255((255 - aDest) * pipe->cSrc[1] + aDest * cBlend[1]);
425     case splashPipeResultColorNoAlphaBlendMono:
426       cResult0 = div255((255 - aDest) * pipe->cSrc[0] + aDest * cBlend[0]);
427       break;
428 
429     case splashPipeResultColorAlphaNoBlendMono:
430       if (alpha2 == 0) {
431 	cResult0 = 0;
432       } else {
433 	cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
434 			     aSrc * pipe->cSrc[0]) / alpha2);
435       }
436       break;
437     case splashPipeResultColorAlphaNoBlendRGB:
438       if (alpha2 == 0) {
439 	cResult0 = 0;
440 	cResult1 = 0;
441 	cResult2 = 0;
442       } else {
443 	cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
444 			     aSrc * pipe->cSrc[0]) / alpha2);
445 	cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] +
446 			     aSrc * pipe->cSrc[1]) / alpha2);
447 	cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] +
448 			     aSrc * pipe->cSrc[2]) / alpha2);
449       }
450       break;
451 #if SPLASH_CMYK
452     case splashPipeResultColorAlphaNoBlendCMYK:
453       if (alpha2 == 0) {
454 	cResult0 = 0;
455 	cResult1 = 0;
456 	cResult2 = 0;
457 	cResult3 = 0;
458       } else {
459 	cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
460 			     aSrc * pipe->cSrc[0]) / alpha2);
461 	cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] +
462 			     aSrc * pipe->cSrc[1]) / alpha2);
463 	cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] +
464 			     aSrc * pipe->cSrc[2]) / alpha2);
465 	cResult3 = (Guchar)(((alpha2 - aSrc) * cDest[3] +
466 			     aSrc * pipe->cSrc[3]) / alpha2);
467       }
468       break;
469 #endif
470 
471     case splashPipeResultColorAlphaBlendMono:
472       if (alpha2 == 0) {
473 	cResult0 = 0;
474       } else {
475 	cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
476 			     aSrc * ((255 - aDest) * pipe->cSrc[0] +
477 				     aDest * cBlend[0]) / 255) /
478 			    alpha2);
479       }
480       break;
481     case splashPipeResultColorAlphaBlendRGB:
482       if (alpha2 == 0) {
483 	cResult0 = 0;
484 	cResult1 = 0;
485 	cResult2 = 0;
486       } else {
487 	cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
488 			     aSrc * ((255 - aDest) * pipe->cSrc[0] +
489 				     aDest * cBlend[0]) / 255) /
490 			    alpha2);
491 	cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] +
492 			     aSrc * ((255 - aDest) * pipe->cSrc[1] +
493 				     aDest * cBlend[1]) / 255) /
494 			    alpha2);
495 	cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] +
496 			     aSrc * ((255 - aDest) * pipe->cSrc[2] +
497 				     aDest * cBlend[2]) / 255) /
498 			    alpha2);
499       }
500       break;
501 #if SPLASH_CMYK
502     case splashPipeResultColorAlphaBlendCMYK:
503       if (alpha2 == 0) {
504 	cResult0 = 0;
505 	cResult1 = 0;
506 	cResult2 = 0;
507 	cResult3 = 0;
508       } else {
509 	cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
510 			     aSrc * ((255 - aDest) * pipe->cSrc[0] +
511 				     aDest * cBlend[0]) / 255) /
512 			    alpha2);
513 	cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] +
514 			     aSrc * ((255 - aDest) * pipe->cSrc[1] +
515 				     aDest * cBlend[1]) / 255) /
516 			    alpha2);
517 	cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] +
518 			     aSrc * ((255 - aDest) * pipe->cSrc[2] +
519 				     aDest * cBlend[2]) / 255) /
520 			    alpha2);
521 	cResult3 = (Guchar)(((alpha2 - aSrc) * cDest[3] +
522 			     aSrc * ((255 - aDest) * pipe->cSrc[3] +
523 				     aDest * cBlend[3]) / 255) /
524 			    alpha2);
525       }
526       break;
527 #endif
528     }
529 
530     //----- non-isolated group correction
531 
532     if (aResult != 0) {
533       switch (pipe->nonIsolatedGroup) {
534 #if SPLASH_CMYK
535       case 4:
536 	cResult3 += (cResult3 - cDest[3]) * aDest *
537 	            (255 - aResult) / (255 * aResult);
538 #endif
539       case 3:
540 	cResult2 += (cResult2 - cDest[2]) * aDest *
541 	            (255 - aResult) / (255 * aResult);
542 	cResult1 += (cResult1 - cDest[1]) * aDest *
543 	            (255 - aResult) / (255 * aResult);
544       case 1:
545 	cResult0 += (cResult0 - cDest[0]) * aDest *
546 	            (255 - aResult) / (255 * aResult);
547       case 0:
548 	break;
549       }
550     }
551 
552     //----- write destination pixel
553 
554     switch (bitmap->mode) {
555     case splashModeMono1:
556       if (state->screen->test(pipe->x, pipe->y, cResult0)) {
557 	*pipe->destColorPtr |= pipe->destColorMask;
558       } else {
559 	*pipe->destColorPtr &= ~pipe->destColorMask;
560       }
561       if (!(pipe->destColorMask >>= 1)) {
562 	pipe->destColorMask = 0x80;
563 	++pipe->destColorPtr;
564       }
565       break;
566     case splashModeMono8:
567       *pipe->destColorPtr++ = cResult0;
568       break;
569     case splashModeRGB8:
570       *pipe->destColorPtr++ = cResult0;
571       *pipe->destColorPtr++ = cResult1;
572       *pipe->destColorPtr++ = cResult2;
573       break;
574     case splashModeXBGR8:
575       *pipe->destColorPtr++ = cResult2;
576       *pipe->destColorPtr++ = cResult1;
577       *pipe->destColorPtr++ = cResult0;
578       *pipe->destColorPtr++ = 255;
579       break;
580     case splashModeBGR8:
581       *pipe->destColorPtr++ = cResult2;
582       *pipe->destColorPtr++ = cResult1;
583       *pipe->destColorPtr++ = cResult0;
584       break;
585 #if SPLASH_CMYK
586     case splashModeCMYK8:
587       *pipe->destColorPtr++ = cResult0;
588       *pipe->destColorPtr++ = cResult1;
589       *pipe->destColorPtr++ = cResult2;
590       *pipe->destColorPtr++ = cResult3;
591       break;
592 #endif
593     }
594     if (pipe->destAlphaPtr) {
595       *pipe->destAlphaPtr++ = aResult;
596     }
597 
598   }
599 
600   ++pipe->x;
601 }
602 
pipeSetXY(SplashPipe * pipe,int x,int y)603 inline void Splash::pipeSetXY(SplashPipe *pipe, int x, int y) {
604   pipe->x = x;
605   pipe->y = y;
606   if (state->softMask) {
607     pipe->softMaskPtr =
608         &state->softMask->data[y * state->softMask->rowSize + x];
609   }
610   switch (bitmap->mode) {
611   case splashModeMono1:
612     pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + (x >> 3)];
613     pipe->destColorMask = 0x80 >> (x & 7);
614     break;
615   case splashModeMono8:
616     pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + x];
617     break;
618   case splashModeRGB8:
619   case splashModeBGR8:
620     pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x];
621     break;
622   case splashModeXBGR8:
623     pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x];
624     break;
625 #if SPLASH_CMYK
626   case splashModeCMYK8:
627     pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x];
628     break;
629 #endif
630   }
631   if (bitmap->alpha) {
632     pipe->destAlphaPtr = &bitmap->alpha[y * bitmap->width + x];
633   } else {
634     pipe->destAlphaPtr = NULL;
635   }
636   if (state->inNonIsolatedGroup && alpha0Bitmap->alpha) {
637     pipe->alpha0Ptr =
638         &alpha0Bitmap->alpha[(alpha0Y + y) * alpha0Bitmap->width +
639 			     (alpha0X + x)];
640   } else {
641     pipe->alpha0Ptr = NULL;
642   }
643 }
644 
pipeIncX(SplashPipe * pipe)645 inline void Splash::pipeIncX(SplashPipe *pipe) {
646   ++pipe->x;
647   if (state->softMask) {
648     ++pipe->softMaskPtr;
649   }
650   switch (bitmap->mode) {
651   case splashModeMono1:
652     if (!(pipe->destColorMask >>= 1)) {
653       pipe->destColorMask = 0x80;
654       ++pipe->destColorPtr;
655     }
656     break;
657   case splashModeMono8:
658     ++pipe->destColorPtr;
659     break;
660   case splashModeRGB8:
661   case splashModeBGR8:
662     pipe->destColorPtr += 3;
663     break;
664   case splashModeXBGR8:
665     pipe->destColorPtr += 4;
666     break;
667 #if SPLASH_CMYK
668   case splashModeCMYK8:
669     pipe->destColorPtr += 4;
670     break;
671 #endif
672   }
673   if (pipe->destAlphaPtr) {
674     ++pipe->destAlphaPtr;
675   }
676   if (pipe->alpha0Ptr) {
677     ++pipe->alpha0Ptr;
678   }
679 }
680 
drawPixel(SplashPipe * pipe,int x,int y,GBool noClip)681 inline void Splash::drawPixel(SplashPipe *pipe, int x, int y, GBool noClip) {
682   if (unlikely(y < 0))
683     return;
684 
685   if (noClip || state->clip->test(x, y)) {
686     pipeSetXY(pipe, x, y);
687     pipeRun(pipe);
688     updateModX(x);
689     updateModY(y);
690   }
691 }
692 
drawAAPixelInit()693 inline void Splash::drawAAPixelInit() {
694   aaBufY = -1;
695 }
696 
drawAAPixel(SplashPipe * pipe,int x,int y)697 inline void Splash::drawAAPixel(SplashPipe *pipe, int x, int y) {
698 #if splashAASize == 4
699   static int bitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
700 			       1, 2, 2, 3, 2, 3, 3, 4 };
701   int w;
702 #else
703   int xx, yy;
704 #endif
705   SplashColorPtr p;
706   int x0, x1, t;
707 
708   if (x < 0 || x >= bitmap->width ||
709       y < state->clip->getYMinI() || y > state->clip->getYMaxI()) {
710     return;
711   }
712 
713   // update aaBuf
714   if (y != aaBufY) {
715     memset(aaBuf->getDataPtr(), 0xff,
716 	   aaBuf->getRowSize() * aaBuf->getHeight());
717     x0 = 0;
718     x1 = bitmap->width - 1;
719     state->clip->clipAALine(aaBuf, &x0, &x1, y);
720     aaBufY = y;
721   }
722 
723   // compute the shape value
724 #if splashAASize == 4
725   p = aaBuf->getDataPtr() + (x >> 1);
726   w = aaBuf->getRowSize();
727   if (x & 1) {
728     t = bitCount4[*p & 0x0f] + bitCount4[p[w] & 0x0f] +
729         bitCount4[p[2*w] & 0x0f] + bitCount4[p[3*w] & 0x0f];
730   } else {
731     t = bitCount4[*p >> 4] + bitCount4[p[w] >> 4] +
732         bitCount4[p[2*w] >> 4] + bitCount4[p[3*w] >> 4];
733   }
734 #else
735   t = 0;
736   for (yy = 0; yy < splashAASize; ++yy) {
737     for (xx = 0; xx < splashAASize; ++xx) {
738       p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() +
739 	  ((x * splashAASize + xx) >> 3);
740       t += (*p >> (7 - ((x * splashAASize + xx) & 7))) & 1;
741     }
742   }
743 #endif
744 
745   // draw the pixel
746   if (t != 0) {
747     pipeSetXY(pipe, x, y);
748     pipe->shape *= aaGamma[t];
749     pipeRun(pipe);
750     updateModX(x);
751     updateModY(y);
752   }
753 }
754 
drawSpan(SplashPipe * pipe,int x0,int x1,int y,GBool noClip)755 inline void Splash::drawSpan(SplashPipe *pipe, int x0, int x1, int y,
756 			     GBool noClip) {
757   int x;
758 
759   pipeSetXY(pipe, x0, y);
760   if (noClip) {
761     for (x = x0; x <= x1; ++x) {
762       pipeRun(pipe);
763     }
764     updateModX(x0);
765     updateModX(x1);
766     updateModY(y);
767   } else {
768     for (x = x0; x <= x1; ++x) {
769       if (state->clip->test(x, y)) {
770 	pipeRun(pipe);
771 	updateModX(x);
772 	updateModY(y);
773       } else {
774 	pipeIncX(pipe);
775       }
776     }
777   }
778 }
779 
drawAALine(SplashPipe * pipe,int x0,int x1,int y)780 inline void Splash::drawAALine(SplashPipe *pipe, int x0, int x1, int y) {
781 #if splashAASize == 4
782   static int bitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
783 			       1, 2, 2, 3, 2, 3, 3, 4 };
784   SplashColorPtr p0, p1, p2, p3;
785   int t;
786 #else
787   SplashColorPtr p;
788   int xx, yy, t;
789 #endif
790   int x;
791 
792 #if splashAASize == 4
793   p0 = aaBuf->getDataPtr() + (x0 >> 1);
794   p1 = p0 + aaBuf->getRowSize();
795   p2 = p1 + aaBuf->getRowSize();
796   p3 = p2 + aaBuf->getRowSize();
797 #endif
798   pipeSetXY(pipe, x0, y);
799   for (x = x0; x <= x1; ++x) {
800 
801     // compute the shape value
802 #if splashAASize == 4
803     if (x & 1) {
804       t = bitCount4[*p0 & 0x0f] + bitCount4[*p1 & 0x0f] +
805 	  bitCount4[*p2 & 0x0f] + bitCount4[*p3 & 0x0f];
806       ++p0; ++p1; ++p2; ++p3;
807     } else {
808       t = bitCount4[*p0 >> 4] + bitCount4[*p1 >> 4] +
809 	  bitCount4[*p2 >> 4] + bitCount4[*p3 >> 4];
810     }
811 #else
812     t = 0;
813     for (yy = 0; yy < splashAASize; ++yy) {
814       for (xx = 0; xx < splashAASize; ++xx) {
815 	p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() +
816 	    ((x * splashAASize + xx) >> 3);
817 	t += (*p >> (7 - ((x * splashAASize + xx) & 7))) & 1;
818       }
819     }
820 #endif
821 
822     if (t != 0) {
823       pipe->shape = aaGamma[t];
824       pipeRun(pipe);
825       updateModX(x);
826       updateModY(y);
827     } else {
828       pipeIncX(pipe);
829     }
830   }
831 }
832 
833 //------------------------------------------------------------------------
834 
835 // Transform a point from user space to device space.
transform(SplashCoord * matrix,SplashCoord xi,SplashCoord yi,SplashCoord * xo,SplashCoord * yo)836 inline void Splash::transform(SplashCoord *matrix,
837 			      SplashCoord xi, SplashCoord yi,
838 			      SplashCoord *xo, SplashCoord *yo) {
839   //                          [ m[0] m[1] 0 ]
840   // [xo yo 1] = [xi yi 1] *  [ m[2] m[3] 0 ]
841   //                          [ m[4] m[5] 1 ]
842   *xo = xi * matrix[0] + yi * matrix[2] + matrix[4];
843   *yo = xi * matrix[1] + yi * matrix[3] + matrix[5];
844 }
845 
846 //------------------------------------------------------------------------
847 // Splash
848 //------------------------------------------------------------------------
849 
Splash(SplashBitmap * bitmapA,GBool vectorAntialiasA,SplashScreenParams * screenParams)850 Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
851 	       SplashScreenParams *screenParams) {
852   int i;
853 
854   bitmap = bitmapA;
855   vectorAntialias = vectorAntialiasA;
856   state = new SplashState(bitmap->width, bitmap->height, vectorAntialias,
857 			  screenParams);
858   if (vectorAntialias) {
859     aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize,
860 			     1, splashModeMono1, gFalse);
861     for (i = 0; i <= splashAASize * splashAASize; ++i) {
862       aaGamma[i] = splashPow((SplashCoord)i /
863 			       (SplashCoord)(splashAASize * splashAASize),
864 			     1.5);
865     }
866   } else {
867     aaBuf = NULL;
868   }
869   clearModRegion();
870   debugMode = gFalse;
871 }
872 
Splash(SplashBitmap * bitmapA,GBool vectorAntialiasA,SplashScreen * screenA)873 Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
874 	       SplashScreen *screenA) {
875   int i;
876 
877   bitmap = bitmapA;
878   vectorAntialias = vectorAntialiasA;
879   state = new SplashState(bitmap->width, bitmap->height, vectorAntialias,
880 			  screenA);
881   if (vectorAntialias) {
882     aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize,
883 			     1, splashModeMono1, gFalse);
884     for (i = 0; i <= splashAASize * splashAASize; ++i) {
885       aaGamma[i] = splashPow((SplashCoord)i /
886 			       (SplashCoord)(splashAASize * splashAASize),
887 			     1.5);
888     }
889   } else {
890     aaBuf = NULL;
891   }
892   clearModRegion();
893   debugMode = gFalse;
894 }
895 
~Splash()896 Splash::~Splash() {
897   while (state->next) {
898     restoreState();
899   }
900   delete state;
901   if (vectorAntialias) {
902     delete aaBuf;
903   }
904 }
905 
906 //------------------------------------------------------------------------
907 // state read
908 //------------------------------------------------------------------------
909 
getMatrix()910 SplashCoord *Splash::getMatrix() {
911   return state->matrix;
912 }
913 
getStrokePattern()914 SplashPattern *Splash::getStrokePattern() {
915   return state->strokePattern;
916 }
917 
getFillPattern()918 SplashPattern *Splash::getFillPattern() {
919   return state->fillPattern;
920 }
921 
getScreen()922 SplashScreen *Splash::getScreen() {
923   return state->screen;
924 }
925 
getBlendFunc()926 SplashBlendFunc Splash::getBlendFunc() {
927   return state->blendFunc;
928 }
929 
getStrokeAlpha()930 SplashCoord Splash::getStrokeAlpha() {
931   return state->strokeAlpha;
932 }
933 
getFillAlpha()934 SplashCoord Splash::getFillAlpha() {
935   return state->fillAlpha;
936 }
937 
getLineWidth()938 SplashCoord Splash::getLineWidth() {
939   return state->lineWidth;
940 }
941 
getLineCap()942 int Splash::getLineCap() {
943   return state->lineCap;
944 }
945 
getLineJoin()946 int Splash::getLineJoin() {
947   return state->lineJoin;
948 }
949 
getMiterLimit()950 SplashCoord Splash::getMiterLimit() {
951   return state->miterLimit;
952 }
953 
getFlatness()954 SplashCoord Splash::getFlatness() {
955   return state->flatness;
956 }
957 
getLineDash()958 SplashCoord *Splash::getLineDash() {
959   return state->lineDash;
960 }
961 
getLineDashLength()962 int Splash::getLineDashLength() {
963   return state->lineDashLength;
964 }
965 
getLineDashPhase()966 SplashCoord Splash::getLineDashPhase() {
967   return state->lineDashPhase;
968 }
969 
getClip()970 SplashClip *Splash::getClip() {
971   return state->clip;
972 }
973 
getSoftMask()974 SplashBitmap *Splash::getSoftMask() {
975   return state->softMask;
976 }
977 
getInNonIsolatedGroup()978 GBool Splash::getInNonIsolatedGroup() {
979   return state->inNonIsolatedGroup;
980 }
981 
982 //------------------------------------------------------------------------
983 // state write
984 //------------------------------------------------------------------------
985 
setMatrix(SplashCoord * matrix)986 void Splash::setMatrix(SplashCoord *matrix) {
987   memcpy(state->matrix, matrix, 6 * sizeof(SplashCoord));
988 }
989 
setStrokePattern(SplashPattern * strokePattern)990 void Splash::setStrokePattern(SplashPattern *strokePattern) {
991   state->setStrokePattern(strokePattern);
992 }
993 
setFillPattern(SplashPattern * fillPattern)994 void Splash::setFillPattern(SplashPattern *fillPattern) {
995   state->setFillPattern(fillPattern);
996 }
997 
setScreen(SplashScreen * screen)998 void Splash::setScreen(SplashScreen *screen) {
999   state->setScreen(screen);
1000 }
1001 
setBlendFunc(SplashBlendFunc func)1002 void Splash::setBlendFunc(SplashBlendFunc func) {
1003   state->blendFunc = func;
1004 }
1005 
setStrokeAlpha(SplashCoord alpha)1006 void Splash::setStrokeAlpha(SplashCoord alpha) {
1007   state->strokeAlpha = alpha;
1008 }
1009 
setFillAlpha(SplashCoord alpha)1010 void Splash::setFillAlpha(SplashCoord alpha) {
1011   state->fillAlpha = alpha;
1012 }
1013 
setLineWidth(SplashCoord lineWidth)1014 void Splash::setLineWidth(SplashCoord lineWidth) {
1015   state->lineWidth = lineWidth;
1016 }
1017 
setLineCap(int lineCap)1018 void Splash::setLineCap(int lineCap) {
1019   state->lineCap = lineCap;
1020 }
1021 
setLineJoin(int lineJoin)1022 void Splash::setLineJoin(int lineJoin) {
1023   state->lineJoin = lineJoin;
1024 }
1025 
setMiterLimit(SplashCoord miterLimit)1026 void Splash::setMiterLimit(SplashCoord miterLimit) {
1027   state->miterLimit = miterLimit;
1028 }
1029 
setFlatness(SplashCoord flatness)1030 void Splash::setFlatness(SplashCoord flatness) {
1031   if (flatness < 1) {
1032     state->flatness = 1;
1033   } else {
1034     state->flatness = flatness;
1035   }
1036 }
1037 
setLineDash(SplashCoord * lineDash,int lineDashLength,SplashCoord lineDashPhase)1038 void Splash::setLineDash(SplashCoord *lineDash, int lineDashLength,
1039 			 SplashCoord lineDashPhase) {
1040   state->setLineDash(lineDash, lineDashLength, lineDashPhase);
1041 }
1042 
setStrokeAdjust(GBool strokeAdjust)1043 void Splash::setStrokeAdjust(GBool strokeAdjust) {
1044   state->strokeAdjust = strokeAdjust;
1045 }
1046 
clipResetToRect(SplashCoord x0,SplashCoord y0,SplashCoord x1,SplashCoord y1)1047 void Splash::clipResetToRect(SplashCoord x0, SplashCoord y0,
1048 			     SplashCoord x1, SplashCoord y1) {
1049   state->clip->resetToRect(x0, y0, x1, y1);
1050 }
1051 
clipToRect(SplashCoord x0,SplashCoord y0,SplashCoord x1,SplashCoord y1)1052 SplashError Splash::clipToRect(SplashCoord x0, SplashCoord y0,
1053 			       SplashCoord x1, SplashCoord y1) {
1054   return state->clip->clipToRect(x0, y0, x1, y1);
1055 }
1056 
clipToPath(SplashPath * path,GBool eo)1057 SplashError Splash::clipToPath(SplashPath *path, GBool eo) {
1058   return state->clip->clipToPath(path, state->matrix, state->flatness, eo);
1059 }
1060 
setSoftMask(SplashBitmap * softMask)1061 void Splash::setSoftMask(SplashBitmap *softMask) {
1062   state->setSoftMask(softMask);
1063 }
1064 
setInNonIsolatedGroup(SplashBitmap * alpha0BitmapA,int alpha0XA,int alpha0YA)1065 void Splash::setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA,
1066 				   int alpha0XA, int alpha0YA) {
1067   alpha0Bitmap = alpha0BitmapA;
1068   alpha0X = alpha0XA;
1069   alpha0Y = alpha0YA;
1070   state->inNonIsolatedGroup = gTrue;
1071 }
1072 
1073 //------------------------------------------------------------------------
1074 // state save/restore
1075 //------------------------------------------------------------------------
1076 
saveState()1077 void Splash::saveState() {
1078   SplashState *newState;
1079 
1080   newState = state->copy();
1081   newState->next = state;
1082   state = newState;
1083 }
1084 
restoreState()1085 SplashError Splash::restoreState() {
1086   SplashState *oldState;
1087 
1088   if (!state->next) {
1089     return splashErrNoSave;
1090   }
1091   oldState = state;
1092   state = state->next;
1093   delete oldState;
1094   return splashOk;
1095 }
1096 
1097 //------------------------------------------------------------------------
1098 // drawing operations
1099 //------------------------------------------------------------------------
1100 
clear(SplashColorPtr color,Guchar alpha)1101 void Splash::clear(SplashColorPtr color, Guchar alpha) {
1102   SplashColorPtr row, p;
1103   Guchar mono;
1104   int x, y;
1105 
1106   switch (bitmap->mode) {
1107   case splashModeMono1:
1108     mono = (color[0] & 0x80) ? 0xff : 0x00;
1109     if (bitmap->rowSize < 0) {
1110       memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
1111 	     mono, -bitmap->rowSize * bitmap->height);
1112     } else {
1113       memset(bitmap->data, mono, bitmap->rowSize * bitmap->height);
1114     }
1115     break;
1116   case splashModeMono8:
1117     if (bitmap->rowSize < 0) {
1118       memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
1119 	     color[0], -bitmap->rowSize * bitmap->height);
1120     } else {
1121       memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
1122     }
1123     break;
1124   case splashModeRGB8:
1125     if (color[0] == color[1] && color[1] == color[2]) {
1126       if (bitmap->rowSize < 0) {
1127 	memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
1128 	       color[0], -bitmap->rowSize * bitmap->height);
1129       } else {
1130 	memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
1131       }
1132     } else {
1133       row = bitmap->data;
1134       for (y = 0; y < bitmap->height; ++y) {
1135 	p = row;
1136 	for (x = 0; x < bitmap->width; ++x) {
1137 	  *p++ = color[2];
1138 	  *p++ = color[1];
1139 	  *p++ = color[0];
1140 	}
1141 	row += bitmap->rowSize;
1142       }
1143     }
1144     break;
1145   case splashModeXBGR8:
1146     if (color[0] == color[1] && color[1] == color[2]) {
1147       if (bitmap->rowSize < 0) {
1148 	memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
1149 	       color[0], -bitmap->rowSize * bitmap->height);
1150       } else {
1151 	memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
1152       }
1153     } else {
1154       row = bitmap->data;
1155       for (y = 0; y < bitmap->height; ++y) {
1156 	p = row;
1157 	for (x = 0; x < bitmap->width; ++x) {
1158 	  *p++ = color[0];
1159 	  *p++ = color[1];
1160 	  *p++ = color[2];
1161 	  *p++ = 255;
1162 	}
1163 	row += bitmap->rowSize;
1164       }
1165     }
1166     break;
1167   case splashModeBGR8:
1168     if (color[0] == color[1] && color[1] == color[2]) {
1169       if (bitmap->rowSize < 0) {
1170 	memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
1171 	       color[0], -bitmap->rowSize * bitmap->height);
1172       } else {
1173 	memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
1174       }
1175     } else {
1176       row = bitmap->data;
1177       for (y = 0; y < bitmap->height; ++y) {
1178 	p = row;
1179 	for (x = 0; x < bitmap->width; ++x) {
1180 	  *p++ = color[0];
1181 	  *p++ = color[1];
1182 	  *p++ = color[2];
1183 	}
1184 	row += bitmap->rowSize;
1185       }
1186     }
1187     break;
1188 #if SPLASH_CMYK
1189   case splashModeCMYK8:
1190     if (color[0] == color[1] && color[1] == color[2] && color[2] == color[3]) {
1191       if (bitmap->rowSize < 0) {
1192 	memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
1193 	       color[0], -bitmap->rowSize * bitmap->height);
1194       } else {
1195 	memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
1196       }
1197     } else {
1198       row = bitmap->data;
1199       for (y = 0; y < bitmap->height; ++y) {
1200 	p = row;
1201 	for (x = 0; x < bitmap->width; ++x) {
1202 	  *p++ = color[0];
1203 	  *p++ = color[1];
1204 	  *p++ = color[2];
1205 	  *p++ = color[3];
1206 	}
1207 	row += bitmap->rowSize;
1208       }
1209     }
1210     break;
1211 #endif
1212   }
1213 
1214   if (bitmap->alpha) {
1215     memset(bitmap->alpha, alpha, bitmap->width * bitmap->height);
1216   }
1217 
1218   updateModX(0);
1219   updateModY(0);
1220   updateModX(bitmap->width - 1);
1221   updateModY(bitmap->height - 1);
1222 }
1223 
stroke(SplashPath * path)1224 SplashError Splash::stroke(SplashPath *path) {
1225   SplashPath *path2, *dPath;
1226 
1227   if (debugMode) {
1228     printf("stroke [dash:%d] [width:%.2f]:\n",
1229 	   state->lineDashLength, (double)state->lineWidth);
1230     dumpPath(path);
1231   }
1232   opClipRes = splashClipAllOutside;
1233   if (path->length == 0) {
1234     return splashErrEmptyPath;
1235   }
1236   path2 = flattenPath(path, state->matrix, state->flatness);
1237   if (state->lineDashLength > 0) {
1238     dPath = makeDashedPath(path2);
1239     delete path2;
1240     path2 = dPath;
1241   }
1242   if (state->lineWidth == 0) {
1243     strokeNarrow(path2);
1244   } else {
1245     strokeWide(path2);
1246   }
1247   delete path2;
1248   return splashOk;
1249 }
1250 
strokeNarrow(SplashPath * path)1251 void Splash::strokeNarrow(SplashPath *path) {
1252   SplashPipe pipe;
1253   SplashXPath *xPath;
1254   SplashXPathSeg *seg;
1255   int x0, x1, x2, x3, y0, y1, x, y, t;
1256   SplashCoord dx, dy, dxdy;
1257   SplashClipResult clipRes;
1258   int nClipRes[3];
1259   int i;
1260 
1261   nClipRes[0] = nClipRes[1] = nClipRes[2] = 0;
1262 
1263   xPath = new SplashXPath(path, state->matrix, state->flatness, gFalse);
1264 
1265   pipeInit(&pipe, 0, 0, state->strokePattern, NULL, state->strokeAlpha,
1266 	   gFalse, gFalse);
1267 
1268   for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) {
1269 
1270     x0 = splashFloor(seg->x0);
1271     x1 = splashFloor(seg->x1);
1272     y0 = splashFloor(seg->y0);
1273     y1 = splashFloor(seg->y1);
1274 
1275     // horizontal segment
1276     if (y0 == y1) {
1277       if (x0 > x1) {
1278 	t = x0; x0 = x1; x1 = t;
1279       }
1280       if ((clipRes = state->clip->testSpan(x0, x1, y0))
1281 	  != splashClipAllOutside) {
1282 	drawSpan(&pipe, x0, x1, y0, clipRes == splashClipAllInside);
1283       }
1284 
1285     // segment with |dx| > |dy|
1286     } else if (splashAbs(seg->dxdy) > 1) {
1287       dx = seg->x1 - seg->x0;
1288       dy = seg->y1 - seg->y0;
1289       dxdy = seg->dxdy;
1290       if (y0 > y1) {
1291 	t = y0; y0 = y1; y1 = t;
1292 	t = x0; x0 = x1; x1 = t;
1293 	dx = -dx;
1294 	dy = -dy;
1295       }
1296       if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0,
1297 					   x0 <= x1 ? x1 : x0, y1))
1298 	  != splashClipAllOutside) {
1299 	if (dx > 0) {
1300 	  x2 = x0;
1301 	  x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy);
1302 	  drawSpan(&pipe, x2, (x2 <= x3 - 1) ? x3 - 1 : x2, y0,
1303 		   clipRes == splashClipAllInside);
1304 	  x2 = x3;
1305 	  for (y = y0 + 1; y <= y1 - 1; ++y) {
1306 	    x3 = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy);
1307 	    drawSpan(&pipe, x2, x3 - 1, y, clipRes == splashClipAllInside);
1308 	    x2 = x3;
1309 	  }
1310 	  drawSpan(&pipe, x2, x2 <= x1 ? x1 : x2, y1,
1311 		   clipRes == splashClipAllInside);
1312 	} else {
1313 	  x2 = x0;
1314 	  x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy);
1315 	  drawSpan(&pipe, (x3 + 1 <= x2) ? x3 + 1 : x2, x2, y0,
1316 		   clipRes == splashClipAllInside);
1317 	  x2 = x3;
1318 	  for (y = y0 + 1; y <= y1 - 1; ++y) {
1319 	    x3 = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy);
1320 	    drawSpan(&pipe, x3 + 1, x2, y, clipRes == splashClipAllInside);
1321 	    x2 = x3;
1322 	  }
1323 	  drawSpan(&pipe, x1, (x1 <= x2) ? x2 : x1, y1,
1324 		   clipRes == splashClipAllInside);
1325 	}
1326       }
1327 
1328     // segment with |dy| > |dx|
1329     } else {
1330       dxdy = seg->dxdy;
1331       if (y0 > y1) {
1332 	t = x0; x0 = x1; x1 = t;
1333 	t = y0; y0 = y1; y1 = t;
1334       }
1335       if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0,
1336 					   x0 <= x1 ? x1 : x0, y1))
1337 	  != splashClipAllOutside) {
1338 	drawPixel(&pipe, x0, y0, clipRes == splashClipAllInside);
1339 	for (y = y0 + 1; y <= y1 - 1; ++y) {
1340 	  x = splashFloor(seg->x0 + ((SplashCoord)y - seg->y0) * dxdy);
1341 	  drawPixel(&pipe, x, y, clipRes == splashClipAllInside);
1342 	}
1343 	drawPixel(&pipe, x1, y1, clipRes == splashClipAllInside);
1344     }
1345     }
1346     ++nClipRes[clipRes];
1347   }
1348   if (nClipRes[splashClipPartial] ||
1349       (nClipRes[splashClipAllInside] && nClipRes[splashClipAllOutside])) {
1350     opClipRes = splashClipPartial;
1351   } else if (nClipRes[splashClipAllInside]) {
1352     opClipRes = splashClipAllInside;
1353   } else {
1354     opClipRes = splashClipAllOutside;
1355   }
1356 
1357   delete xPath;
1358 }
1359 
strokeWide(SplashPath * path)1360 void Splash::strokeWide(SplashPath *path) {
1361   SplashPath *path2;
1362 
1363   path2 = makeStrokePath(path, gFalse);
1364   fillWithPattern(path2, gFalse, state->strokePattern, state->strokeAlpha);
1365   delete path2;
1366 }
1367 
flattenPath(SplashPath * path,SplashCoord * matrix,SplashCoord flatness)1368 SplashPath *Splash::flattenPath(SplashPath *path, SplashCoord *matrix,
1369 				SplashCoord flatness) {
1370   SplashPath *fPath;
1371   SplashCoord flatness2;
1372   Guchar flag;
1373   int i;
1374 
1375   fPath = new SplashPath();
1376   flatness2 = flatness * flatness;
1377   i = 0;
1378   while (i < path->length) {
1379     flag = path->flags[i];
1380     if (flag & splashPathFirst) {
1381       fPath->moveTo(path->pts[i].x, path->pts[i].y);
1382       ++i;
1383     } else {
1384       if (flag & splashPathCurve) {
1385 	flattenCurve(path->pts[i-1].x, path->pts[i-1].y,
1386 		     path->pts[i  ].x, path->pts[i  ].y,
1387 		     path->pts[i+1].x, path->pts[i+1].y,
1388 		     path->pts[i+2].x, path->pts[i+2].y,
1389 		     matrix, flatness2, fPath);
1390 	i += 3;
1391       } else {
1392 	fPath->lineTo(path->pts[i].x, path->pts[i].y);
1393 	++i;
1394       }
1395       if (path->flags[i-1] & splashPathClosed) {
1396 	fPath->close();
1397       }
1398     }
1399   }
1400   return fPath;
1401 }
1402 
flattenCurve(SplashCoord x0,SplashCoord y0,SplashCoord x1,SplashCoord y1,SplashCoord x2,SplashCoord y2,SplashCoord x3,SplashCoord y3,SplashCoord * matrix,SplashCoord flatness2,SplashPath * fPath)1403 void Splash::flattenCurve(SplashCoord x0, SplashCoord y0,
1404 			  SplashCoord x1, SplashCoord y1,
1405 			  SplashCoord x2, SplashCoord y2,
1406 			  SplashCoord x3, SplashCoord y3,
1407 			  SplashCoord *matrix, SplashCoord flatness2,
1408 			  SplashPath *fPath) {
1409   SplashCoord cx[splashMaxCurveSplits + 1][3];
1410   SplashCoord cy[splashMaxCurveSplits + 1][3];
1411   int cNext[splashMaxCurveSplits + 1];
1412   SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh;
1413   SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh;
1414   SplashCoord dx, dy, mx, my, tx, ty, d1, d2;
1415   int p1, p2, p3;
1416 
1417   // initial segment
1418   p1 = 0;
1419   p2 = splashMaxCurveSplits;
1420   cx[p1][0] = x0;  cy[p1][0] = y0;
1421   cx[p1][1] = x1;  cy[p1][1] = y1;
1422   cx[p1][2] = x2;  cy[p1][2] = y2;
1423   cx[p2][0] = x3;  cy[p2][0] = y3;
1424   cNext[p1] = p2;
1425 
1426   while (p1 < splashMaxCurveSplits) {
1427 
1428     // get the next segment
1429     xl0 = cx[p1][0];  yl0 = cy[p1][0];
1430     xx1 = cx[p1][1];  yy1 = cy[p1][1];
1431     xx2 = cx[p1][2];  yy2 = cy[p1][2];
1432     p2 = cNext[p1];
1433     xr3 = cx[p2][0];  yr3 = cy[p2][0];
1434 
1435     // compute the distances (in device space) from the control points
1436     // to the midpoint of the straight line (this is a bit of a hack,
1437     // but it's much faster than computing the actual distances to the
1438     // line)
1439     transform(matrix, (xl0 + xr3) * 0.5, (yl0 + yr3) * 0.5, &mx, &my);
1440     transform(matrix, xx1, yy1, &tx, &ty);
1441     dx = tx - mx;
1442     dy = ty - my;
1443     d1 = dx*dx + dy*dy;
1444     transform(matrix, xx2, yy2, &tx, &ty);
1445     dx = tx - mx;
1446     dy = ty - my;
1447     d2 = dx*dx + dy*dy;
1448 
1449     // if the curve is flat enough, or no more subdivisions are
1450     // allowed, add the straight line segment
1451     if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) {
1452       fPath->lineTo(xr3, yr3);
1453       p1 = p2;
1454 
1455     // otherwise, subdivide the curve
1456     } else {
1457       xl1 = (xl0 + xx1) * 0.5;
1458       yl1 = (yl0 + yy1) * 0.5;
1459       xh = (xx1 + xx2) * 0.5;
1460       yh = (yy1 + yy2) * 0.5;
1461       xl2 = (xl1 + xh) * 0.5;
1462       yl2 = (yl1 + yh) * 0.5;
1463       xr2 = (xx2 + xr3) * 0.5;
1464       yr2 = (yy2 + yr3) * 0.5;
1465       xr1 = (xh + xr2) * 0.5;
1466       yr1 = (yh + yr2) * 0.5;
1467       xr0 = (xl2 + xr1) * 0.5;
1468       yr0 = (yl2 + yr1) * 0.5;
1469       // add the new subdivision points
1470       p3 = (p1 + p2) / 2;
1471       cx[p1][1] = xl1;  cy[p1][1] = yl1;
1472       cx[p1][2] = xl2;  cy[p1][2] = yl2;
1473       cNext[p1] = p3;
1474       cx[p3][0] = xr0;  cy[p3][0] = yr0;
1475       cx[p3][1] = xr1;  cy[p3][1] = yr1;
1476       cx[p3][2] = xr2;  cy[p3][2] = yr2;
1477       cNext[p3] = p2;
1478     }
1479   }
1480 }
1481 
makeDashedPath(SplashPath * path)1482 SplashPath *Splash::makeDashedPath(SplashPath *path) {
1483   SplashPath *dPath;
1484   SplashCoord lineDashTotal;
1485   SplashCoord lineDashStartPhase, lineDashDist, segLen;
1486   SplashCoord x0, y0, x1, y1, xa, ya;
1487   GBool lineDashStartOn, lineDashOn, newPath;
1488   int lineDashStartIdx, lineDashIdx;
1489   int i, j, k;
1490 
1491   lineDashTotal = 0;
1492   for (i = 0; i < state->lineDashLength; ++i) {
1493     lineDashTotal += state->lineDash[i];
1494   }
1495   lineDashStartPhase = state->lineDashPhase;
1496   i = splashFloor(lineDashStartPhase / lineDashTotal);
1497   lineDashStartPhase -= (SplashCoord)i * lineDashTotal;
1498   lineDashStartOn = gTrue;
1499   lineDashStartIdx = 0;
1500   while (lineDashStartPhase >= state->lineDash[lineDashStartIdx]) {
1501     lineDashStartOn = !lineDashStartOn;
1502     lineDashStartPhase -= state->lineDash[lineDashStartIdx];
1503     ++lineDashStartIdx;
1504   }
1505 
1506   dPath = new SplashPath();
1507 
1508   // process each subpath
1509   i = 0;
1510   while (i < path->length) {
1511 
1512     // find the end of the subpath
1513     for (j = i;
1514 	 j < path->length - 1 && !(path->flags[j] & splashPathLast);
1515 	 ++j) ;
1516 
1517     // initialize the dash parameters
1518     lineDashOn = lineDashStartOn;
1519     lineDashIdx = lineDashStartIdx;
1520     lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase;
1521 
1522     // process each segment of the subpath
1523     newPath = gTrue;
1524     for (k = i; k < j; ++k) {
1525 
1526       // grab the segment
1527       x0 = path->pts[k].x;
1528       y0 = path->pts[k].y;
1529       x1 = path->pts[k+1].x;
1530       y1 = path->pts[k+1].y;
1531       segLen = splashDist(x0, y0, x1, y1);
1532 
1533       // process the segment
1534       while (segLen > 0) {
1535 
1536 	if (lineDashDist >= segLen) {
1537 	  if (lineDashOn) {
1538 	    if (newPath) {
1539 	      dPath->moveTo(x0, y0);
1540 	      newPath = gFalse;
1541 	    }
1542 	    dPath->lineTo(x1, y1);
1543 	  }
1544 	  lineDashDist -= segLen;
1545 	  segLen = 0;
1546 
1547 	} else {
1548 	  xa = x0 + (lineDashDist / segLen) * (x1 - x0);
1549 	  ya = y0 + (lineDashDist / segLen) * (y1 - y0);
1550 	  if (lineDashOn) {
1551 	    if (newPath) {
1552 	      dPath->moveTo(x0, y0);
1553 	      newPath = gFalse;
1554 	    }
1555 	    dPath->lineTo(xa, ya);
1556 	  }
1557 	  x0 = xa;
1558 	  y0 = ya;
1559 	  segLen -= lineDashDist;
1560 	  lineDashDist = 0;
1561 	}
1562 
1563 	// get the next entry in the dash array
1564 	if (lineDashDist <= 0) {
1565 	  lineDashOn = !lineDashOn;
1566 	  if (++lineDashIdx == state->lineDashLength) {
1567 	    lineDashIdx = 0;
1568 	  }
1569 	  lineDashDist = state->lineDash[lineDashIdx];
1570 	  newPath = gTrue;
1571 	}
1572       }
1573     }
1574     i = j + 1;
1575   }
1576 
1577   return dPath;
1578 }
1579 
fill(SplashPath * path,GBool eo)1580 SplashError Splash::fill(SplashPath *path, GBool eo) {
1581   if (debugMode) {
1582     printf("fill [eo:%d]:\n", eo);
1583     dumpPath(path);
1584   }
1585   return fillWithPattern(path, eo, state->fillPattern, state->fillAlpha);
1586 }
1587 
fillWithPattern(SplashPath * path,GBool eo,SplashPattern * pattern,SplashCoord alpha)1588 SplashError Splash::fillWithPattern(SplashPath *path, GBool eo,
1589 				    SplashPattern *pattern,
1590 				    SplashCoord alpha) {
1591   SplashPipe pipe;
1592   SplashXPath *xPath;
1593   SplashXPathScanner *scanner;
1594   int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
1595   SplashClipResult clipRes, clipRes2;
1596 
1597   if (path->length == 0) {
1598     return splashErrEmptyPath;
1599   }
1600   xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue);
1601   if (vectorAntialias) {
1602     xPath->aaScale();
1603   }
1604   xPath->sort();
1605   scanner = new SplashXPathScanner(xPath, eo);
1606 
1607   // get the min and max x and y values
1608   if (vectorAntialias) {
1609     scanner->getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI);
1610   } else {
1611     scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI);
1612   }
1613 
1614   // check clipping
1615   if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI))
1616       != splashClipAllOutside) {
1617 
1618     // limit the y range
1619     if (yMinI < state->clip->getYMinI()) {
1620       yMinI = state->clip->getYMinI();
1621     }
1622     if (yMaxI > state->clip->getYMaxI()) {
1623       yMaxI = state->clip->getYMaxI();
1624     }
1625 
1626     pipeInit(&pipe, 0, yMinI, pattern, NULL, alpha, vectorAntialias, gFalse);
1627 
1628     // draw the spans
1629     if (vectorAntialias) {
1630       for (y = yMinI; y <= yMaxI; ++y) {
1631 	scanner->renderAALine(aaBuf, &x0, &x1, y);
1632 	if (clipRes != splashClipAllInside) {
1633 	  state->clip->clipAALine(aaBuf, &x0, &x1, y);
1634 	}
1635 	drawAALine(&pipe, x0, x1, y);
1636       }
1637     } else {
1638       for (y = yMinI; y <= yMaxI; ++y) {
1639 	while (scanner->getNextSpan(y, &x0, &x1)) {
1640 	  if (clipRes == splashClipAllInside) {
1641 	    drawSpan(&pipe, x0, x1, y, gTrue);
1642 	  } else {
1643 	    // limit the x range
1644 	    if (x0 < state->clip->getXMinI()) {
1645 	      x0 = state->clip->getXMinI();
1646 	    }
1647 	    if (x1 > state->clip->getXMaxI()) {
1648 	      x1 = state->clip->getXMaxI();
1649 	    }
1650 	    clipRes2 = state->clip->testSpan(x0, x1, y);
1651 	    drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside);
1652 	  }
1653 	}
1654       }
1655     }
1656   }
1657   opClipRes = clipRes;
1658 
1659   delete scanner;
1660   delete xPath;
1661   return splashOk;
1662 }
1663 
xorFill(SplashPath * path,GBool eo)1664 SplashError Splash::xorFill(SplashPath *path, GBool eo) {
1665   SplashPipe pipe;
1666   SplashXPath *xPath;
1667   SplashXPathScanner *scanner;
1668   int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
1669   SplashClipResult clipRes, clipRes2;
1670   SplashBlendFunc origBlendFunc;
1671 
1672   if (path->length == 0) {
1673     return splashErrEmptyPath;
1674   }
1675   xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue);
1676   xPath->sort();
1677   scanner = new SplashXPathScanner(xPath, eo);
1678 
1679   // get the min and max x and y values
1680   scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI);
1681 
1682   // check clipping
1683   if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI))
1684       != splashClipAllOutside) {
1685 
1686     // limit the y range
1687     if (yMinI < state->clip->getYMinI()) {
1688       yMinI = state->clip->getYMinI();
1689     }
1690     if (yMaxI > state->clip->getYMaxI()) {
1691       yMaxI = state->clip->getYMaxI();
1692     }
1693 
1694     origBlendFunc = state->blendFunc;
1695     state->blendFunc = &blendXor;
1696     pipeInit(&pipe, 0, yMinI, state->fillPattern, NULL, 1, gFalse, gFalse);
1697 
1698     // draw the spans
1699     for (y = yMinI; y <= yMaxI; ++y) {
1700       while (scanner->getNextSpan(y, &x0, &x1)) {
1701 	if (clipRes == splashClipAllInside) {
1702 	  drawSpan(&pipe, x0, x1, y, gTrue);
1703 	} else {
1704 	  // limit the x range
1705 	  if (x0 < state->clip->getXMinI()) {
1706 	    x0 = state->clip->getXMinI();
1707 	  }
1708 	  if (x1 > state->clip->getXMaxI()) {
1709 	    x1 = state->clip->getXMaxI();
1710 	  }
1711 	  clipRes2 = state->clip->testSpan(x0, x1, y);
1712 	  drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside);
1713 	}
1714       }
1715     }
1716     state->blendFunc = origBlendFunc;
1717   }
1718   opClipRes = clipRes;
1719 
1720   delete scanner;
1721   delete xPath;
1722   return splashOk;
1723 }
1724 
fillChar(SplashCoord x,SplashCoord y,int c,SplashFont * font)1725 SplashError Splash::fillChar(SplashCoord x, SplashCoord y,
1726 			     int c, SplashFont *font) {
1727   SplashGlyphBitmap glyph;
1728   SplashCoord xt, yt;
1729   int x0, y0, xFrac, yFrac;
1730   SplashClipResult clipRes;
1731 
1732   if (debugMode) {
1733     printf("fillChar: x=%.2f y=%.2f c=%3d=0x%02x='%c'\n",
1734 	   (double)x, (double)y, c, c, c);
1735   }
1736   transform(state->matrix, x, y, &xt, &yt);
1737   x0 = splashFloor(xt);
1738   xFrac = splashFloor((xt - x0) * splashFontFraction);
1739   y0 = splashFloor(yt);
1740   yFrac = splashFloor((yt - y0) * splashFontFraction);
1741   if (!font->getGlyph(c, xFrac, yFrac, &glyph, x0, y0, state->clip, &clipRes)) {
1742     return splashErrNoGlyph;
1743   }
1744   if (clipRes != splashClipAllOutside) {
1745     fillGlyph2(x0, y0, &glyph, clipRes == splashClipAllInside);
1746   }
1747   opClipRes = clipRes;
1748   if (glyph.freeData) {
1749     gfree(glyph.data);
1750   }
1751   return splashOk;
1752 }
1753 
fillGlyph(SplashCoord x,SplashCoord y,SplashGlyphBitmap * glyph)1754 void Splash::fillGlyph(SplashCoord x, SplashCoord y,
1755 			      SplashGlyphBitmap *glyph) {
1756   SplashCoord xt, yt;
1757   int x0, y0;
1758 
1759   transform(state->matrix, x, y, &xt, &yt);
1760   x0 = splashFloor(xt);
1761   y0 = splashFloor(yt);
1762   SplashClipResult clipRes = state->clip->testRect(x0 - glyph->x,
1763                              y0 - glyph->y,
1764                              x0 - glyph->x + glyph->w - 1,
1765                              y0 - glyph->y + glyph->h - 1);
1766   if (clipRes != splashClipAllOutside) {
1767     fillGlyph2(x0, y0, glyph, clipRes == splashClipAllInside);
1768   }
1769   opClipRes = clipRes;
1770 }
1771 
fillGlyph2(int x0,int y0,SplashGlyphBitmap * glyph,GBool noClip)1772 void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noClip) {
1773   SplashPipe pipe;
1774   int alpha0, alpha;
1775   Guchar *p;
1776   int x1, y1, xx, xx1, yy;
1777 
1778   p = glyph->data;
1779   int xStart = x0 - glyph->x;
1780   int yStart = y0 - glyph->y;
1781   int xxLimit = glyph->w;
1782   int yyLimit = glyph->h;
1783 
1784   if (yStart < 0)
1785   {
1786     p += glyph->w * -yStart; // move p to the beginning of the first painted row
1787     yyLimit += yStart;
1788     yStart = 0;
1789   }
1790 
1791   if (xStart < 0)
1792   {
1793     p += -xStart; // move p to the first painted pixel
1794     xxLimit += xStart;
1795     xStart = 0;
1796   }
1797 
1798   if (xxLimit + xStart >= bitmap->width) xxLimit = bitmap->width - xStart;
1799   if (yyLimit + yStart >= bitmap->height) yyLimit = bitmap->height - yStart;
1800 
1801   if (noClip) {
1802     if (glyph->aa) {
1803       pipeInit(&pipe, xStart, yStart,
1804                state->fillPattern, NULL, state->fillAlpha, gTrue, gFalse);
1805       for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
1806         pipeSetXY(&pipe, xStart, y1);
1807         for (xx = 0, x1 = xStart; xx < xxLimit; ++xx, ++x1) {
1808           alpha = p[xx];
1809           if (alpha != 0) {
1810             pipe.shape = (SplashCoord)(alpha / 255.0);
1811             pipeRun(&pipe);
1812             updateModX(x1);
1813             updateModY(y1);
1814           } else {
1815             pipeIncX(&pipe);
1816           }
1817         }
1818         p += glyph->w;
1819       }
1820     } else {
1821       const int widthEight = splashCeil(glyph->w / 8.0);
1822 
1823       pipeInit(&pipe, xStart, yStart,
1824                state->fillPattern, NULL, state->fillAlpha, gFalse, gFalse);
1825       for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
1826         pipeSetXY(&pipe, xStart, y1);
1827         for (xx = 0, x1 = xStart; xx < xxLimit; xx += 8) {
1828           alpha0 = p[xx / 8];
1829           for (xx1 = 0; xx1 < 8 && xx + xx1 < xxLimit; ++xx1, ++x1) {
1830             if (alpha0 & 0x80) {
1831               pipeRun(&pipe);
1832               updateModX(x1);
1833               updateModY(y1);
1834             } else {
1835               pipeIncX(&pipe);
1836             }
1837             alpha0 <<= 1;
1838           }
1839         }
1840         p += widthEight;
1841       }
1842     }
1843   } else {
1844     if (glyph->aa) {
1845       pipeInit(&pipe, xStart, yStart,
1846                state->fillPattern, NULL, state->fillAlpha, gTrue, gFalse);
1847       for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
1848         pipeSetXY(&pipe, xStart, y1);
1849         for (xx = 0, x1 = xStart; xx < xxLimit; ++xx, ++x1) {
1850           if (state->clip->test(x1, y1)) {
1851             alpha = p[xx];
1852             if (alpha != 0) {
1853               pipe.shape = (SplashCoord)(alpha / 255.0);
1854               pipeRun(&pipe);
1855               updateModX(x1);
1856               updateModY(y1);
1857             } else {
1858               pipeIncX(&pipe);
1859             }
1860           } else {
1861             pipeIncX(&pipe);
1862           }
1863         }
1864         p += glyph->w;
1865       }
1866     } else {
1867       const int widthEight = splashCeil(glyph->w / 8.0);
1868 
1869       pipeInit(&pipe, xStart, yStart,
1870                state->fillPattern, NULL, state->fillAlpha, gFalse, gFalse);
1871       for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
1872         pipeSetXY(&pipe, xStart, y1);
1873         for (xx = 0, x1 = xStart; xx < xxLimit; xx += 8) {
1874           alpha0 = p[xx / 8];
1875           for (xx1 = 0; xx1 < 8 && xx + xx1 < xxLimit; ++xx1, ++x1) {
1876             if (state->clip->test(x1, y1)) {
1877               if (alpha0 & 0x80) {
1878                 pipeRun(&pipe);
1879                 updateModX(x1);
1880                 updateModY(y1);
1881               } else {
1882                 pipeIncX(&pipe);
1883               }
1884             } else {
1885               pipeIncX(&pipe);
1886             }
1887             alpha0 <<= 1;
1888           }
1889         }
1890         p += widthEight;
1891       }
1892     }
1893   }
1894 }
1895 
fillImageMask(SplashImageMaskSource src,void * srcData,int w,int h,SplashCoord * mat,GBool glyphMode)1896 SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
1897 				  int w, int h, SplashCoord *mat,
1898 				  GBool glyphMode) {
1899   SplashPipe pipe;
1900   GBool rot;
1901   SplashCoord xScale, yScale, xShear, yShear, yShear1;
1902   int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign;
1903   int ulx, uly, llx, lly, urx, ury, lrx, lry;
1904   int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
1905   int xMin, xMax, yMin, yMax;
1906   SplashClipResult clipRes, clipRes2;
1907   int yp, yq, yt, yStep, lastYStep;
1908   int xp, xq, xt, xStep, xSrc;
1909   int k1, spanXMin, spanXMax, spanY;
1910   SplashColorPtr pixBuf, p;
1911   int pixAcc;
1912   int x, y, x1, x2, y2;
1913   SplashCoord y1;
1914   int n, m, i, j;
1915 
1916   if (debugMode) {
1917     printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
1918 	   w, h, (double)mat[0], (double)mat[1], (double)mat[2],
1919 	   (double)mat[3], (double)mat[4], (double)mat[5]);
1920   }
1921 
1922   if (w == 0 && h == 0) return splashErrZeroImage;
1923 
1924   // check for singular matrix
1925   if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) {
1926     return splashErrSingularMatrix;
1927   }
1928 
1929   // compute scale, shear, rotation, translation parameters
1930   rot = splashAbs(mat[1]) > splashAbs(mat[0]);
1931   if (rot) {
1932     xScale = -mat[1];
1933     yScale = mat[2] - (mat[0] * mat[3]) / mat[1];
1934     xShear = -mat[3] / yScale;
1935     yShear = -mat[0] / mat[1];
1936   } else {
1937     xScale = mat[0];
1938     yScale = mat[3] - (mat[1] * mat[2]) / mat[0];
1939     xShear = mat[2] / yScale;
1940     yShear = mat[1] / mat[0];
1941   }
1942   // Note 1: The PDF spec says that all pixels whose *centers* lie
1943   // within the region get painted -- but that doesn't seem to match
1944   // up with what Acrobat actually does: it ends up leaving gaps
1945   // between image stripes.  So we use the same rule here as for
1946   // fills: any pixel that overlaps the region gets painted.
1947   // Note 2: The "glyphMode" flag is a kludge: it switches back to
1948   // "correct" behavior (matching the spec), for use in rendering Type
1949   // 3 fonts.
1950   // Note 3: The +/-0.01 in these computations is to avoid floating
1951   // point precision problems which can lead to gaps between image
1952   // stripes (it can cause image stripes to overlap, but that's a much
1953   // less visible problem).
1954   if (glyphMode) {
1955     if (xScale >= 0) {
1956       tx = splashRound(mat[4]);
1957       tx2 = splashRound(mat[4] + xScale) - 1;
1958     } else {
1959       tx = splashRound(mat[4]) - 1;
1960       tx2 = splashRound(mat[4] + xScale);
1961     }
1962   } else {
1963     if (xScale >= 0) {
1964       tx = splashFloor(mat[4] - 0.01);
1965       tx2 = splashFloor(mat[4] + xScale + 0.01);
1966     } else {
1967       tx = splashFloor(mat[4] + 0.01);
1968       tx2 = splashFloor(mat[4] + xScale - 0.01);
1969     }
1970   }
1971   scaledWidth = abs(tx2 - tx) + 1;
1972   if (glyphMode) {
1973     if (yScale >= 0) {
1974       ty = splashRound(mat[5]);
1975       ty2 = splashRound(mat[5] + yScale) - 1;
1976     } else {
1977       ty = splashRound(mat[5]) - 1;
1978       ty2 = splashRound(mat[5] + yScale);
1979     }
1980   } else {
1981     if (yScale >= 0) {
1982       ty = splashFloor(mat[5] - 0.01);
1983       ty2 = splashFloor(mat[5] + yScale + 0.01);
1984     } else {
1985       ty = splashFloor(mat[5] + 0.01);
1986       ty2 = splashFloor(mat[5] + yScale - 0.01);
1987     }
1988   }
1989   scaledHeight = abs(ty2 - ty) + 1;
1990   xSign = (xScale < 0) ? -1 : 1;
1991   ySign = (yScale < 0) ? -1 : 1;
1992   yShear1 = (SplashCoord)xSign * yShear;
1993 
1994   // clipping
1995   ulx1 = 0;
1996   uly1 = 0;
1997   urx1 = xSign * (scaledWidth - 1);
1998   ury1 = (int)(yShear * urx1);
1999   llx1 = splashRound(xShear * ySign * (scaledHeight - 1));
2000   lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1);
2001   lrx1 = xSign * (scaledWidth - 1) +
2002            splashRound(xShear * ySign * (scaledHeight - 1));
2003   lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1);
2004   if (rot) {
2005     ulx = tx + uly1;    uly = ty - ulx1;
2006     urx = tx + ury1;    ury = ty - urx1;
2007     llx = tx + lly1;    lly = ty - llx1;
2008     lrx = tx + lry1;    lry = ty - lrx1;
2009   } else {
2010     ulx = tx + ulx1;    uly = ty + uly1;
2011     urx = tx + urx1;    ury = ty + ury1;
2012     llx = tx + llx1;    lly = ty + lly1;
2013     lrx = tx + lrx1;    lry = ty + lry1;
2014   }
2015   xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
2016                                    : (llx < lrx) ? llx : lrx
2017 		     : (urx < llx) ? (urx < lrx) ? urx : lrx
2018                                    : (llx < lrx) ? llx : lrx;
2019   xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
2020                                    : (llx > lrx) ? llx : lrx
2021 		     : (urx > llx) ? (urx > lrx) ? urx : lrx
2022                                    : (llx > lrx) ? llx : lrx;
2023   yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
2024                                    : (lly < lry) ? lly : lry
2025 		     : (ury < lly) ? (ury < lry) ? ury : lry
2026                                    : (lly < lry) ? lly : lry;
2027   yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
2028                                    : (lly > lry) ? lly : lry
2029 		     : (ury > lly) ? (ury > lry) ? ury : lry
2030                                    : (lly > lry) ? lly : lry;
2031   clipRes = state->clip->testRect(xMin, yMin, xMax, yMax);
2032   opClipRes = clipRes;
2033 
2034   // compute Bresenham parameters for x and y scaling
2035   yp = h / scaledHeight;
2036   yq = h % scaledHeight;
2037   xp = w / scaledWidth;
2038   xq = w % scaledWidth;
2039 
2040   // allocate pixel buffer
2041   if (yp < 0 || yp > INT_MAX - 1) {
2042     return splashErrBadArg;
2043   }
2044   pixBuf = (SplashColorPtr)gmallocn((yp + 1), w);
2045 
2046   // initialize the pixel pipe
2047   pipeInit(&pipe, 0, 0, state->fillPattern, NULL, state->fillAlpha,
2048 	   gTrue, gFalse);
2049   if (vectorAntialias) {
2050     drawAAPixelInit();
2051   }
2052 
2053   // init y scale Bresenham
2054   yt = 0;
2055   lastYStep = 1;
2056 
2057   for (y = 0; y < scaledHeight; ++y) {
2058 
2059     // y scale Bresenham
2060     yStep = yp;
2061     yt += yq;
2062     if (yt >= scaledHeight) {
2063       yt -= scaledHeight;
2064       ++yStep;
2065     }
2066 
2067     // read row(s) from image
2068     n = (yp > 0) ? yStep : lastYStep;
2069     if (n > 0) {
2070       p = pixBuf;
2071       for (i = 0; i < n; ++i) {
2072 	(*src)(srcData, p);
2073 	p += w;
2074       }
2075     }
2076     lastYStep = yStep;
2077 
2078     // loop-invariant constants
2079     k1 = splashRound(xShear * ySign * y);
2080 
2081     // clipping test
2082     if (clipRes != splashClipAllInside &&
2083 	!rot &&
2084 	(int)(yShear * k1) ==
2085 	  (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
2086       if (xSign > 0) {
2087 	spanXMin = tx + k1;
2088 	spanXMax = spanXMin + (scaledWidth - 1);
2089       } else {
2090 	spanXMax = tx + k1;
2091 	spanXMin = spanXMax - (scaledWidth - 1);
2092       }
2093       spanY = ty + ySign * y + (int)(yShear * k1);
2094       clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
2095       if (clipRes2 == splashClipAllOutside) {
2096 	continue;
2097       }
2098     } else {
2099       clipRes2 = clipRes;
2100     }
2101 
2102     // init x scale Bresenham
2103     xt = 0;
2104     xSrc = 0;
2105 
2106     // x shear
2107     x1 = k1;
2108 
2109     // y shear
2110     y1 = (SplashCoord)ySign * y + yShear * x1;
2111     // this is a kludge: if yShear1 is negative, then (int)y1 would
2112     // change immediately after the first pixel, which is not what we
2113     // want
2114     if (yShear1 < 0) {
2115       y1 += 0.999;
2116     }
2117 
2118     // loop-invariant constants
2119     n = yStep > 0 ? yStep : 1;
2120 
2121     for (x = 0; x < scaledWidth; ++x) {
2122 
2123       // x scale Bresenham
2124       xStep = xp;
2125       xt += xq;
2126       if (xt >= scaledWidth) {
2127 	xt -= scaledWidth;
2128 	++xStep;
2129       }
2130 
2131       // rotation
2132       if (rot) {
2133 	x2 = (int)y1;
2134 	y2 = -x1;
2135       } else {
2136 	x2 = x1;
2137 	y2 = (int)y1;
2138       }
2139 
2140       // compute the alpha value for (x,y) after the x and y scaling
2141       // operations
2142       m = xStep > 0 ? xStep : 1;
2143       p = pixBuf + xSrc;
2144       pixAcc = 0;
2145       for (i = 0; i < n; ++i) {
2146 	for (j = 0; j < m; ++j) {
2147 	  pixAcc += *p++;
2148 	}
2149 	p += w - m;
2150       }
2151 
2152       // blend fill color with background
2153       if (pixAcc != 0) {
2154 	pipe.shape = (pixAcc == n * m)
2155 	                 ? (SplashCoord)1
2156 	                 : (SplashCoord)pixAcc / (SplashCoord)(n * m);
2157 	if (vectorAntialias && clipRes2 != splashClipAllInside) {
2158 	  drawAAPixel(&pipe, tx + x2, ty + y2);
2159 	} else {
2160 	  drawPixel(&pipe, tx + x2, ty + y2, clipRes2 == splashClipAllInside);
2161 	}
2162       }
2163 
2164       // x scale Bresenham
2165       xSrc += xStep;
2166 
2167       // x shear
2168       x1 += xSign;
2169 
2170       // y shear
2171       y1 += yShear1;
2172     }
2173   }
2174 
2175   // free memory
2176   gfree(pixBuf);
2177 
2178   return splashOk;
2179 }
2180 
drawImage(SplashImageSource src,void * srcData,SplashColorMode srcMode,GBool srcAlpha,int w,int h,SplashCoord * mat)2181 SplashError Splash::drawImage(SplashImageSource src, void *srcData,
2182 			      SplashColorMode srcMode, GBool srcAlpha,
2183 			      int w, int h, SplashCoord *mat) {
2184   SplashPipe pipe;
2185   GBool ok, rot;
2186   SplashCoord xScale, yScale, xShear, yShear, yShear1;
2187   int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign;
2188   int ulx, uly, llx, lly, urx, ury, lrx, lry;
2189   int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
2190   int xMin, xMax, yMin, yMax;
2191   SplashClipResult clipRes, clipRes2;
2192   int yp, yq, yt, yStep, lastYStep;
2193   int xp, xq, xt, xStep, xSrc;
2194   int k1, spanXMin, spanXMax, spanY;
2195   SplashColorPtr colorBuf, p;
2196   SplashColor pix;
2197   Guchar *alphaBuf, *q;
2198 #if SPLASH_CMYK
2199   int pixAcc0, pixAcc1, pixAcc2, pixAcc3;
2200 #else
2201   int pixAcc0, pixAcc1, pixAcc2;
2202 #endif
2203   int alphaAcc;
2204   SplashCoord pixMul, alphaMul, alpha;
2205   int x, y, x1, x2, y2;
2206   SplashCoord y1;
2207   int nComps, n, m, i, j;
2208 
2209   if (debugMode) {
2210     printf("drawImage: srcMode=%d srcAlpha=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
2211 	   srcMode, srcAlpha, w, h, (double)mat[0], (double)mat[1], (double)mat[2],
2212 	   (double)mat[3], (double)mat[4], (double)mat[5]);
2213   }
2214 
2215   // check color modes
2216   ok = gFalse; // make gcc happy
2217   nComps = 0; // make gcc happy
2218   switch (bitmap->mode) {
2219   case splashModeMono1:
2220   case splashModeMono8:
2221     ok = srcMode == splashModeMono8;
2222     nComps = 1;
2223     break;
2224   case splashModeRGB8:
2225     ok = srcMode == splashModeRGB8;
2226     nComps = 3;
2227     break;
2228   case splashModeXBGR8:
2229     ok = srcMode == splashModeXBGR8;
2230     nComps = 4;
2231     break;
2232   case splashModeBGR8:
2233     ok = srcMode == splashModeBGR8;
2234     nComps = 3;
2235     break;
2236 #if SPLASH_CMYK
2237   case splashModeCMYK8:
2238     ok = srcMode == splashModeCMYK8;
2239     nComps = 4;
2240     break;
2241 #endif
2242   }
2243   if (!ok) {
2244     return splashErrModeMismatch;
2245   }
2246 
2247   // check for singular matrix
2248   if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) {
2249     return splashErrSingularMatrix;
2250   }
2251 
2252   // compute scale, shear, rotation, translation parameters
2253   rot = splashAbs(mat[1]) > splashAbs(mat[0]);
2254   if (rot) {
2255     xScale = -mat[1];
2256     yScale = mat[2] - (mat[0] * mat[3]) / mat[1];
2257     xShear = -mat[3] / yScale;
2258     yShear = -mat[0] / mat[1];
2259   } else {
2260     xScale = mat[0];
2261     yScale = mat[3] - (mat[1] * mat[2]) / mat[0];
2262     xShear = mat[2] / yScale;
2263     yShear = mat[1] / mat[0];
2264   }
2265   // Note 1: The PDF spec says that all pixels whose *centers* lie
2266   // within the region get painted -- but that doesn't seem to match
2267   // up with what Acrobat actually does: it ends up leaving gaps
2268   // between image stripes.  So we use the same rule here as for
2269   // fills: any pixel that overlaps the region gets painted.
2270   // Note 2: The +/-0.01 in these computations is to avoid floating
2271   // point precision problems which can lead to gaps between image
2272   // stripes (it can cause image stripes to overlap, but that's a much
2273   // less visible problem).
2274   if (xScale >= 0) {
2275     tx = splashFloor(mat[4] - 0.01);
2276     tx2 = splashFloor(mat[4] + xScale + 0.01);
2277   } else {
2278     tx = splashFloor(mat[4] + 0.01);
2279     tx2 = splashFloor(mat[4] + xScale - 0.01);
2280   }
2281   scaledWidth = abs(tx2 - tx) + 1;
2282   if (yScale >= 0) {
2283     ty = splashFloor(mat[5] - 0.01);
2284     ty2 = splashFloor(mat[5] + yScale + 0.01);
2285   } else {
2286     ty = splashFloor(mat[5] + 0.01);
2287     ty2 = splashFloor(mat[5] + yScale - 0.01);
2288   }
2289   scaledHeight = abs(ty2 - ty) + 1;
2290   xSign = (xScale < 0) ? -1 : 1;
2291   ySign = (yScale < 0) ? -1 : 1;
2292   yShear1 = (SplashCoord)xSign * yShear;
2293 
2294   // clipping
2295   ulx1 = 0;
2296   uly1 = 0;
2297   urx1 = xSign * (scaledWidth - 1);
2298   ury1 = (int)(yShear * urx1);
2299   llx1 = splashRound(xShear * ySign * (scaledHeight - 1));
2300   lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1);
2301   lrx1 = xSign * (scaledWidth - 1) +
2302            splashRound(xShear * ySign * (scaledHeight - 1));
2303   lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1);
2304   if (rot) {
2305     ulx = tx + uly1;    uly = ty - ulx1;
2306     urx = tx + ury1;    ury = ty - urx1;
2307     llx = tx + lly1;    lly = ty - llx1;
2308     lrx = tx + lry1;    lry = ty - lrx1;
2309   } else {
2310     ulx = tx + ulx1;    uly = ty + uly1;
2311     urx = tx + urx1;    ury = ty + ury1;
2312     llx = tx + llx1;    lly = ty + lly1;
2313     lrx = tx + lrx1;    lry = ty + lry1;
2314   }
2315   xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
2316                                    : (llx < lrx) ? llx : lrx
2317 		     : (urx < llx) ? (urx < lrx) ? urx : lrx
2318                                    : (llx < lrx) ? llx : lrx;
2319   xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
2320                                    : (llx > lrx) ? llx : lrx
2321 		     : (urx > llx) ? (urx > lrx) ? urx : lrx
2322                                    : (llx > lrx) ? llx : lrx;
2323   yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
2324                                    : (lly < lry) ? lly : lry
2325 		     : (ury < lly) ? (ury < lry) ? ury : lry
2326                                    : (lly < lry) ? lly : lry;
2327   yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
2328                                    : (lly > lry) ? lly : lry
2329 		     : (ury > lly) ? (ury > lry) ? ury : lry
2330                                    : (lly > lry) ? lly : lry;
2331   clipRes = state->clip->testRect(xMin, yMin, xMax, yMax);
2332   opClipRes = clipRes;
2333   if (clipRes == splashClipAllOutside) {
2334     return splashOk;
2335   }
2336 
2337   // compute Bresenham parameters for x and y scaling
2338   yp = h / scaledHeight;
2339   yq = h % scaledHeight;
2340   xp = w / scaledWidth;
2341   xq = w % scaledWidth;
2342 
2343   // allocate pixel buffers
2344   if (yp < 0 || yp > INT_MAX - 1) {
2345     return splashErrBadArg;
2346   }
2347   colorBuf = (SplashColorPtr)gmallocn3((yp + 1), w, nComps);
2348   if (srcAlpha) {
2349     alphaBuf = (Guchar *)gmallocn((yp + 1), w);
2350   } else {
2351     alphaBuf = NULL;
2352   }
2353 
2354   pixAcc0 = pixAcc1 = pixAcc2 = 0; // make gcc happy
2355 #if SPLASH_CMYK
2356   pixAcc3 = 0; // make gcc happy
2357 #endif
2358 
2359   // initialize the pixel pipe
2360   pipeInit(&pipe, 0, 0, NULL, pix, state->fillAlpha,
2361 	   srcAlpha || (vectorAntialias && clipRes != splashClipAllInside),
2362 	   gFalse);
2363   if (vectorAntialias) {
2364     drawAAPixelInit();
2365   }
2366 
2367   if (srcAlpha) {
2368 
2369     // init y scale Bresenham
2370     yt = 0;
2371     lastYStep = 1;
2372 
2373     for (y = 0; y < scaledHeight; ++y) {
2374 
2375       // y scale Bresenham
2376       yStep = yp;
2377       yt += yq;
2378       if (yt >= scaledHeight) {
2379 	yt -= scaledHeight;
2380 	++yStep;
2381       }
2382 
2383       // read row(s) from image
2384       n = (yp > 0) ? yStep : lastYStep;
2385       if (n > 0) {
2386 	p = colorBuf;
2387 	q = alphaBuf;
2388 	for (i = 0; i < n; ++i) {
2389 	  (*src)(srcData, p, q);
2390 	  p += w * nComps;
2391 	  q += w;
2392 	}
2393       }
2394       lastYStep = yStep;
2395 
2396       // loop-invariant constants
2397       k1 = splashRound(xShear * ySign * y);
2398 
2399       // clipping test
2400       if (clipRes != splashClipAllInside &&
2401 	  !rot &&
2402 	  (int)(yShear * k1) ==
2403 	    (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
2404 	if (xSign > 0) {
2405 	  spanXMin = tx + k1;
2406 	  spanXMax = spanXMin + (scaledWidth - 1);
2407 	} else {
2408 	  spanXMax = tx + k1;
2409 	  spanXMin = spanXMax - (scaledWidth - 1);
2410 	}
2411 	spanY = ty + ySign * y + (int)(yShear * k1);
2412 	clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
2413 	if (clipRes2 == splashClipAllOutside) {
2414 	  continue;
2415 	}
2416       } else {
2417 	clipRes2 = clipRes;
2418       }
2419 
2420       // init x scale Bresenham
2421       xt = 0;
2422       xSrc = 0;
2423 
2424       // x shear
2425       x1 = k1;
2426 
2427       // y shear
2428       y1 = (SplashCoord)ySign * y + yShear * x1;
2429       // this is a kludge: if yShear1 is negative, then (int)y1 would
2430       // change immediately after the first pixel, which is not what
2431       // we want
2432       if (yShear1 < 0) {
2433 	y1 += 0.999;
2434       }
2435 
2436       // loop-invariant constants
2437       n = yStep > 0 ? yStep : 1;
2438 
2439       switch (srcMode) {
2440 
2441       case splashModeMono1:
2442       case splashModeMono8:
2443 	for (x = 0; x < scaledWidth; ++x) {
2444 
2445 	  // x scale Bresenham
2446 	  xStep = xp;
2447 	  xt += xq;
2448 	  if (xt >= scaledWidth) {
2449 	    xt -= scaledWidth;
2450 	    ++xStep;
2451 	  }
2452 
2453 	  // rotation
2454 	  if (rot) {
2455 	    x2 = (int)y1;
2456 	    y2 = -x1;
2457 	  } else {
2458 	    x2 = x1;
2459 	    y2 = (int)y1;
2460 	  }
2461 
2462 	  // compute the filtered pixel at (x,y) after the x and y scaling
2463 	  // operations
2464 	  m = xStep > 0 ? xStep : 1;
2465 	  alphaAcc = 0;
2466 	  p = colorBuf + xSrc;
2467 	  q = alphaBuf + xSrc;
2468 	  pixAcc0 = 0;
2469 	  for (i = 0; i < n; ++i) {
2470 	    for (j = 0; j < m; ++j) {
2471 	      pixAcc0 += *p++;
2472 	      alphaAcc += *q++;
2473 	    }
2474 	    p += w - m;
2475 	    q += w - m;
2476 	  }
2477 	  pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
2478 	  alphaMul = pixMul * (1.0 / 255.0);
2479 	  alpha = (SplashCoord)alphaAcc * alphaMul;
2480 
2481 	  if (alpha > 0) {
2482 	    pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
2483 
2484 	    // set pixel
2485 	    pipe.shape = alpha;
2486 	    if (vectorAntialias && clipRes != splashClipAllInside) {
2487 	      drawAAPixel(&pipe, tx + x2, ty + y2);
2488 	    } else {
2489 	      drawPixel(&pipe, tx + x2, ty + y2,
2490 			clipRes2 == splashClipAllInside);
2491 	    }
2492 	  }
2493 
2494 	  // x scale Bresenham
2495 	  xSrc += xStep;
2496 
2497 	  // x shear
2498 	  x1 += xSign;
2499 
2500 	  // y shear
2501 	  y1 += yShear1;
2502 	}
2503 	break;
2504 
2505       case splashModeRGB8:
2506       case splashModeBGR8:
2507 	for (x = 0; x < scaledWidth; ++x) {
2508 
2509 	  // x scale Bresenham
2510 	  xStep = xp;
2511 	  xt += xq;
2512 	  if (xt >= scaledWidth) {
2513 	    xt -= scaledWidth;
2514 	    ++xStep;
2515 	  }
2516 
2517 	  // rotation
2518 	  if (rot) {
2519 	    x2 = (int)y1;
2520 	    y2 = -x1;
2521 	  } else {
2522 	    x2 = x1;
2523 	    y2 = (int)y1;
2524 	  }
2525 
2526 	  // compute the filtered pixel at (x,y) after the x and y scaling
2527 	  // operations
2528 	  m = xStep > 0 ? xStep : 1;
2529 	  alphaAcc = 0;
2530 	  p = colorBuf + xSrc * 3;
2531 	  q = alphaBuf + xSrc;
2532 	  pixAcc0 = pixAcc1 = pixAcc2 = 0;
2533 	  for (i = 0; i < n; ++i) {
2534 	    for (j = 0; j < m; ++j) {
2535 	      pixAcc0 += *p++;
2536 	      pixAcc1 += *p++;
2537 	      pixAcc2 += *p++;
2538 	      alphaAcc += *q++;
2539 	    }
2540 	    p += 3 * (w - m);
2541 	    q += w - m;
2542 	  }
2543 	  pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
2544 	  alphaMul = pixMul * (1.0 / 255.0);
2545 	  alpha = (SplashCoord)alphaAcc * alphaMul;
2546 
2547 	  if (alpha > 0) {
2548 	    pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
2549 	    pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
2550 	    pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
2551 
2552 	    // set pixel
2553 	    pipe.shape = alpha;
2554 	    if (vectorAntialias && clipRes != splashClipAllInside) {
2555 	      drawAAPixel(&pipe, tx + x2, ty + y2);
2556 	    } else {
2557 	      drawPixel(&pipe, tx + x2, ty + y2,
2558 			clipRes2 == splashClipAllInside);
2559 	    }
2560 	  }
2561 
2562 	  // x scale Bresenham
2563 	  xSrc += xStep;
2564 
2565 	  // x shear
2566 	  x1 += xSign;
2567 
2568 	  // y shear
2569 	  y1 += yShear1;
2570 	}
2571 	break;
2572 
2573       case splashModeXBGR8:
2574 	for (x = 0; x < scaledWidth; ++x) {
2575 	  // x scale Bresenham
2576 	  xStep = xp;
2577 	  xt += xq;
2578 	  if (xt >= scaledWidth) {
2579 	    xt -= scaledWidth;
2580 	    ++xStep;
2581 	  }
2582 
2583 	  // rotation
2584 	  if (rot) {
2585 	    x2 = (int)y1;
2586 	    y2 = -x1;
2587 	  } else {
2588 	    x2 = x1;
2589 	    y2 = (int)y1;
2590 	  }
2591 
2592 	  // compute the filtered pixel at (x,y) after the x and y scaling
2593 	  // operations
2594 	  m = xStep > 0 ? xStep : 1;
2595 	  alphaAcc = 0;
2596 	  p = colorBuf + xSrc * 4;
2597 	  q = alphaBuf + xSrc;
2598 	  pixAcc0 = pixAcc1 = pixAcc2 = 0;
2599 	  for (i = 0; i < n; ++i) {
2600 	    for (j = 0; j < m; ++j) {
2601 	      pixAcc0 += *p++;
2602 	      pixAcc1 += *p++;
2603 	      pixAcc2 += *p++;
2604 	      p++;
2605 	      alphaAcc += *q++;
2606 	    }
2607 	    p += 4 * (w - m);
2608 	    q += w - m;
2609 	  }
2610 	  pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
2611 	  alphaMul = pixMul * (1.0 / 255.0);
2612 	  alpha = (SplashCoord)alphaAcc * alphaMul;
2613 
2614 	  if (alpha > 0) {
2615 	    pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
2616 	    pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
2617 	    pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
2618 	    pix[3] = 255;
2619 
2620 	    // set pixel
2621 	    pipe.shape = alpha;
2622 	    if (vectorAntialias && clipRes != splashClipAllInside) {
2623 	      drawAAPixel(&pipe, tx + x2, ty + y2);
2624 	    } else {
2625 	      drawPixel(&pipe, tx + x2, ty + y2,
2626 			clipRes2 == splashClipAllInside);
2627 	    }
2628 	  }
2629 
2630 	  // x scale Bresenham
2631 	  xSrc += xStep;
2632 
2633 	  // x shear
2634 	  x1 += xSign;
2635 
2636 	  // y shear
2637 	  y1 += yShear1;
2638 	}
2639 	break;
2640 
2641 
2642 #if SPLASH_CMYK
2643       case splashModeCMYK8:
2644 	for (x = 0; x < scaledWidth; ++x) {
2645 
2646 	  // x scale Bresenham
2647 	  xStep = xp;
2648 	  xt += xq;
2649 	  if (xt >= scaledWidth) {
2650 	    xt -= scaledWidth;
2651 	    ++xStep;
2652 	  }
2653 
2654 	  // rotation
2655 	  if (rot) {
2656 	    x2 = (int)y1;
2657 	    y2 = -x1;
2658 	  } else {
2659 	    x2 = x1;
2660 	    y2 = (int)y1;
2661 	  }
2662 
2663 	  // compute the filtered pixel at (x,y) after the x and y scaling
2664 	  // operations
2665 	  m = xStep > 0 ? xStep : 1;
2666 	  alphaAcc = 0;
2667 	  p = colorBuf + xSrc * 4;
2668 	  q = alphaBuf + xSrc;
2669 	  pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0;
2670 	  for (i = 0; i < n; ++i) {
2671 	    for (j = 0; j < m; ++j) {
2672 	      pixAcc0 += *p++;
2673 	      pixAcc1 += *p++;
2674 	      pixAcc2 += *p++;
2675 	      pixAcc3 += *p++;
2676 	      alphaAcc += *q++;
2677 	    }
2678 	    p += 4 * (w - m);
2679 	    q += w - m;
2680 	  }
2681 	  pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
2682 	  alphaMul = pixMul * (1.0 / 255.0);
2683 	  alpha = (SplashCoord)alphaAcc * alphaMul;
2684 
2685 	  if (alpha > 0) {
2686 	    pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
2687 	    pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
2688 	    pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
2689 	    pix[3] = (int)((SplashCoord)pixAcc3 * pixMul);
2690 
2691 	    // set pixel
2692 	    pipe.shape = alpha;
2693 	    if (vectorAntialias && clipRes != splashClipAllInside) {
2694 	      drawAAPixel(&pipe, tx + x2, ty + y2);
2695 	    } else {
2696 	      drawPixel(&pipe, tx + x2, ty + y2,
2697 			clipRes2 == splashClipAllInside);
2698 	    }
2699 	  }
2700 
2701 	  // x scale Bresenham
2702 	  xSrc += xStep;
2703 
2704 	  // x shear
2705 	  x1 += xSign;
2706 
2707 	  // y shear
2708 	  y1 += yShear1;
2709 	}
2710 	break;
2711 #endif // SPLASH_CMYK
2712       }
2713     }
2714 
2715   } else {
2716 
2717     // init y scale Bresenham
2718     yt = 0;
2719     lastYStep = 1;
2720 
2721     for (y = 0; y < scaledHeight; ++y) {
2722 
2723       // y scale Bresenham
2724       yStep = yp;
2725       yt += yq;
2726       if (yt >= scaledHeight) {
2727 	yt -= scaledHeight;
2728 	++yStep;
2729       }
2730 
2731       // read row(s) from image
2732       n = (yp > 0) ? yStep : lastYStep;
2733       if (n > 0) {
2734 	p = colorBuf;
2735 	for (i = 0; i < n; ++i) {
2736 	  (*src)(srcData, p, NULL);
2737 	  p += w * nComps;
2738 	}
2739       }
2740       lastYStep = yStep;
2741 
2742       // loop-invariant constants
2743       k1 = splashRound(xShear * ySign * y);
2744 
2745       // clipping test
2746       if (clipRes != splashClipAllInside &&
2747 	  !rot &&
2748 	  (int)(yShear * k1) ==
2749 	    (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
2750 	if (xSign > 0) {
2751 	  spanXMin = tx + k1;
2752 	  spanXMax = spanXMin + (scaledWidth - 1);
2753 	} else {
2754 	  spanXMax = tx + k1;
2755 	  spanXMin = spanXMax - (scaledWidth - 1);
2756 	}
2757 	spanY = ty + ySign * y + (int)(yShear * k1);
2758 	clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
2759 	if (clipRes2 == splashClipAllOutside) {
2760 	  continue;
2761 	}
2762       } else {
2763 	clipRes2 = clipRes;
2764       }
2765 
2766       // init x scale Bresenham
2767       xt = 0;
2768       xSrc = 0;
2769 
2770       // x shear
2771       x1 = k1;
2772 
2773       // y shear
2774       y1 = (SplashCoord)ySign * y + yShear * x1;
2775       // this is a kludge: if yShear1 is negative, then (int)y1 would
2776       // change immediately after the first pixel, which is not what
2777       // we want
2778       if (yShear1 < 0) {
2779 	y1 += 0.999;
2780       }
2781 
2782       // loop-invariant constants
2783       n = yStep > 0 ? yStep : 1;
2784 
2785       switch (srcMode) {
2786 
2787       case splashModeMono1:
2788       case splashModeMono8:
2789 	for (x = 0; x < scaledWidth; ++x) {
2790 
2791 	  // x scale Bresenham
2792 	  xStep = xp;
2793 	  xt += xq;
2794 	  if (xt >= scaledWidth) {
2795 	    xt -= scaledWidth;
2796 	    ++xStep;
2797 	  }
2798 
2799 	  // rotation
2800 	  if (rot) {
2801 	    x2 = (int)y1;
2802 	    y2 = -x1;
2803 	  } else {
2804 	    x2 = x1;
2805 	    y2 = (int)y1;
2806 	  }
2807 
2808 	  // compute the filtered pixel at (x,y) after the x and y scaling
2809 	  // operations
2810 	  m = xStep > 0 ? xStep : 1;
2811 	  p = colorBuf + xSrc;
2812 	  pixAcc0 = 0;
2813 	  for (i = 0; i < n; ++i) {
2814 	    for (j = 0; j < m; ++j) {
2815 	      pixAcc0 += *p++;
2816 	    }
2817 	    p += w - m;
2818 	  }
2819 	  pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
2820 
2821 	  pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
2822 
2823 	  // set pixel
2824 	  if (vectorAntialias && clipRes != splashClipAllInside) {
2825 	    pipe.shape = (SplashCoord)1;
2826 	    drawAAPixel(&pipe, tx + x2, ty + y2);
2827 	  } else {
2828 	    drawPixel(&pipe, tx + x2, ty + y2,
2829 		      clipRes2 == splashClipAllInside);
2830 	  }
2831 
2832 	  // x scale Bresenham
2833 	  xSrc += xStep;
2834 
2835 	  // x shear
2836 	  x1 += xSign;
2837 
2838 	  // y shear
2839 	  y1 += yShear1;
2840 	}
2841 	break;
2842 
2843       case splashModeRGB8:
2844       case splashModeBGR8:
2845 	for (x = 0; x < scaledWidth; ++x) {
2846 
2847 	  // x scale Bresenham
2848 	  xStep = xp;
2849 	  xt += xq;
2850 	  if (xt >= scaledWidth) {
2851 	    xt -= scaledWidth;
2852 	    ++xStep;
2853 	  }
2854 
2855 	  // rotation
2856 	  if (rot) {
2857 	    x2 = (int)y1;
2858 	    y2 = -x1;
2859 	  } else {
2860 	    x2 = x1;
2861 	    y2 = (int)y1;
2862 	  }
2863 
2864 	  // compute the filtered pixel at (x,y) after the x and y scaling
2865 	  // operations
2866 	  m = xStep > 0 ? xStep : 1;
2867 	  p = colorBuf + xSrc * 3;
2868 	  pixAcc0 = pixAcc1 = pixAcc2 = 0;
2869 	  for (i = 0; i < n; ++i) {
2870 	    for (j = 0; j < m; ++j) {
2871 	      pixAcc0 += *p++;
2872 	      pixAcc1 += *p++;
2873 	      pixAcc2 += *p++;
2874 	    }
2875 	    p += 3 * (w - m);
2876 	  }
2877 	  pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
2878 
2879 	  pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
2880 	  pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
2881 	  pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
2882 
2883 	  // set pixel
2884 	  if (vectorAntialias && clipRes != splashClipAllInside) {
2885 	    pipe.shape = (SplashCoord)1;
2886 	    drawAAPixel(&pipe, tx + x2, ty + y2);
2887 	  } else {
2888 	    drawPixel(&pipe, tx + x2, ty + y2,
2889 		      clipRes2 == splashClipAllInside);
2890 	  }
2891 
2892 	  // x scale Bresenham
2893 	  xSrc += xStep;
2894 
2895 	  // x shear
2896 	  x1 += xSign;
2897 
2898 	  // y shear
2899 	  y1 += yShear1;
2900 	}
2901 	break;
2902 
2903       case splashModeXBGR8:
2904 	for (x = 0; x < scaledWidth; ++x) {
2905 
2906 	  // x scale Bresenham
2907 	  xStep = xp;
2908 	  xt += xq;
2909 	  if (xt >= scaledWidth) {
2910 	    xt -= scaledWidth;
2911 	    ++xStep;
2912 	  }
2913 
2914 	  // rotation
2915 	  if (rot) {
2916 	    x2 = (int)y1;
2917 	    y2 = -x1;
2918 	  } else {
2919 	    x2 = x1;
2920 	    y2 = (int)y1;
2921 	  }
2922 
2923 	  // compute the filtered pixel at (x,y) after the x and y scaling
2924 	  // operations
2925 	  m = xStep > 0 ? xStep : 1;
2926 	  p = colorBuf + xSrc * 4;
2927 	  pixAcc0 = pixAcc1 = pixAcc2 = 0;
2928 	  for (i = 0; i < n; ++i) {
2929 	    for (j = 0; j < m; ++j) {
2930 	      pixAcc0 += *p++;
2931 	      pixAcc1 += *p++;
2932 	      pixAcc2 += *p++;
2933 	      p++;
2934 	    }
2935 	    p += 4 * (w - m);
2936 	  }
2937 	  pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
2938 
2939 	  pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
2940 	  pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
2941 	  pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
2942 	  pix[3] = 255;
2943 
2944 	  // set pixel
2945 	  if (vectorAntialias && clipRes != splashClipAllInside) {
2946 	    pipe.shape = (SplashCoord)1;
2947 	    drawAAPixel(&pipe, tx + x2, ty + y2);
2948 	  } else {
2949 	    drawPixel(&pipe, tx + x2, ty + y2,
2950 		      clipRes2 == splashClipAllInside);
2951 	  }
2952 
2953 	  // x scale Bresenham
2954 	  xSrc += xStep;
2955 
2956 	  // x shear
2957 	  x1 += xSign;
2958 
2959 	  // y shear
2960 	  y1 += yShear1;
2961 	}
2962 	break;
2963 
2964 #if SPLASH_CMYK
2965       case splashModeCMYK8:
2966 	for (x = 0; x < scaledWidth; ++x) {
2967 
2968 	  // x scale Bresenham
2969 	  xStep = xp;
2970 	  xt += xq;
2971 	  if (xt >= scaledWidth) {
2972 	    xt -= scaledWidth;
2973 	    ++xStep;
2974 	  }
2975 
2976 	  // rotation
2977 	  if (rot) {
2978 	    x2 = (int)y1;
2979 	    y2 = -x1;
2980 	  } else {
2981 	    x2 = x1;
2982 	    y2 = (int)y1;
2983 	  }
2984 
2985 	  // compute the filtered pixel at (x,y) after the x and y scaling
2986 	  // operations
2987 	  m = xStep > 0 ? xStep : 1;
2988 	  p = colorBuf + xSrc * 4;
2989 	  pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0;
2990 	  for (i = 0; i < n; ++i) {
2991 	    for (j = 0; j < m; ++j) {
2992 	      pixAcc0 += *p++;
2993 	      pixAcc1 += *p++;
2994 	      pixAcc2 += *p++;
2995 	      pixAcc3 += *p++;
2996 	    }
2997 	    p += 4 * (w - m);
2998 	  }
2999 	  pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
3000 
3001 	  pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
3002 	  pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
3003 	  pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
3004 	  pix[3] = (int)((SplashCoord)pixAcc3 * pixMul);
3005 
3006 	  // set pixel
3007 	  if (vectorAntialias && clipRes != splashClipAllInside) {
3008 	    pipe.shape = (SplashCoord)1;
3009 	    drawAAPixel(&pipe, tx + x2, ty + y2);
3010 	  } else {
3011 	    drawPixel(&pipe, tx + x2, ty + y2,
3012 		      clipRes2 == splashClipAllInside);
3013 	  }
3014 
3015 	  // x scale Bresenham
3016 	  xSrc += xStep;
3017 
3018 	  // x shear
3019 	  x1 += xSign;
3020 
3021 	  // y shear
3022 	  y1 += yShear1;
3023 	}
3024 	break;
3025 #endif // SPLASH_CMYK
3026       }
3027     }
3028 
3029   }
3030 
3031   gfree(colorBuf);
3032   gfree(alphaBuf);
3033 
3034   return splashOk;
3035 }
3036 
composite(SplashBitmap * src,int xSrc,int ySrc,int xDest,int yDest,int w,int h,GBool noClip,GBool nonIsolated)3037 SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc,
3038 			      int xDest, int yDest, int w, int h,
3039 			      GBool noClip, GBool nonIsolated) {
3040   SplashPipe pipe;
3041   SplashColor pixel;
3042   Guchar alpha;
3043   Guchar *ap;
3044   int x, y;
3045 
3046   if (src->mode != bitmap->mode) {
3047     return splashErrModeMismatch;
3048   }
3049 
3050   if (src->alpha) {
3051     pipeInit(&pipe, xDest, yDest, NULL, pixel, state->fillAlpha,
3052 	     gTrue, nonIsolated);
3053     for (y = 0; y < h; ++y) {
3054       pipeSetXY(&pipe, xDest, yDest + y);
3055       ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
3056       for (x = 0; x < w; ++x) {
3057 	alpha = *ap++;
3058 	if (noClip || state->clip->test(xDest + x, yDest + y)) {
3059 	  // this uses shape instead of alpha, which isn't technically
3060 	  // correct, but works out the same
3061 	  src->getPixel(xSrc + x, ySrc + y, pixel);
3062 	  pipe.shape = (SplashCoord)(alpha / 255.0);
3063 	  pipeRun(&pipe);
3064 	  updateModX(xDest + x);
3065 	  updateModY(yDest + y);
3066 	} else {
3067 	  pipeIncX(&pipe);
3068 	}
3069       }
3070     }
3071   } else {
3072     pipeInit(&pipe, xDest, yDest, NULL, pixel, state->fillAlpha,
3073 	     gFalse, nonIsolated);
3074     for (y = 0; y < h; ++y) {
3075       pipeSetXY(&pipe, xDest, yDest + y);
3076       for (x = 0; x < w; ++x) {
3077 	if (noClip || state->clip->test(xDest + x, yDest + y)) {
3078 	  src->getPixel(xSrc + x, ySrc + y, pixel);
3079 	  pipeRun(&pipe);
3080 	  updateModX(xDest + x);
3081 	  updateModY(yDest + y);
3082 	} else {
3083 	  pipeIncX(&pipe);
3084 	}
3085       }
3086     }
3087   }
3088 
3089   return splashOk;
3090 }
3091 
compositeBackground(SplashColorPtr color)3092 void Splash::compositeBackground(SplashColorPtr color) {
3093   SplashColorPtr p;
3094   Guchar *q;
3095   Guchar alpha, alpha1, c, color0, color1, color2;
3096 #if SPLASH_CMYK
3097   Guchar color3;
3098 #endif
3099   int x, y, mask;
3100 
3101   if (unlikely(bitmap->alpha == NULL)) {
3102     error(-1, "bitmap->alpha is NULL in Splash::compositeBackground");
3103     return;
3104   }
3105 
3106   switch (bitmap->mode) {
3107   case splashModeMono1:
3108     color0 = color[0];
3109     for (y = 0; y < bitmap->height; ++y) {
3110       p = &bitmap->data[y * bitmap->rowSize];
3111       q = &bitmap->alpha[y * bitmap->width];
3112       mask = 0x80;
3113       for (x = 0; x < bitmap->width; ++x) {
3114 	alpha = *q++;
3115 	alpha1 = 255 - alpha;
3116 	c = (*p & mask) ? 0xff : 0x00;
3117 	c = div255(alpha1 * color0 + alpha * c);
3118 	if (c & 0x80) {
3119 	  *p |= mask;
3120 	} else {
3121 	  *p &= ~mask;
3122 	}
3123 	if (!(mask >>= 1)) {
3124 	  mask = 0x80;
3125 	  ++p;
3126 	}
3127       }
3128     }
3129     break;
3130   case splashModeMono8:
3131     color0 = color[0];
3132     for (y = 0; y < bitmap->height; ++y) {
3133       p = &bitmap->data[y * bitmap->rowSize];
3134       q = &bitmap->alpha[y * bitmap->width];
3135       for (x = 0; x < bitmap->width; ++x) {
3136 	alpha = *q++;
3137 	alpha1 = 255 - alpha;
3138 	p[0] = div255(alpha1 * color0 + alpha * p[0]);
3139 	++p;
3140       }
3141     }
3142     break;
3143   case splashModeRGB8:
3144   case splashModeBGR8:
3145     color0 = color[0];
3146     color1 = color[1];
3147     color2 = color[2];
3148     for (y = 0; y < bitmap->height; ++y) {
3149       p = &bitmap->data[y * bitmap->rowSize];
3150       q = &bitmap->alpha[y * bitmap->width];
3151       for (x = 0; x < bitmap->width; ++x) {
3152 	alpha = *q++;
3153 	if (alpha == 0)
3154 	{
3155 	  p[0] = color0;
3156 	  p[1] = color1;
3157 	  p[2] = color2;
3158 	}
3159 	else if (alpha != 255)
3160 	{
3161 	  alpha1 = 255 - alpha;
3162 	  p[0] = div255(alpha1 * color0 + alpha * p[0]);
3163 	  p[1] = div255(alpha1 * color1 + alpha * p[1]);
3164 	  p[2] = div255(alpha1 * color2 + alpha * p[2]);
3165 	}
3166 	p += 3;
3167       }
3168     }
3169     break;
3170   case splashModeXBGR8:
3171     color0 = color[0];
3172     color1 = color[1];
3173     color2 = color[2];
3174     for (y = 0; y < bitmap->height; ++y) {
3175       p = &bitmap->data[y * bitmap->rowSize];
3176       q = &bitmap->alpha[y * bitmap->width];
3177       for (x = 0; x < bitmap->width; ++x) {
3178 	alpha = *q++;
3179 	if (alpha == 0)
3180 	{
3181 	  p[0] = color0;
3182 	  p[1] = color1;
3183 	  p[2] = color2;
3184 	}
3185 	else if (alpha != 255)
3186 	{
3187 	  alpha1 = 255 - alpha;
3188 	  p[0] = div255(alpha1 * color0 + alpha * p[0]);
3189 	  p[1] = div255(alpha1 * color1 + alpha * p[1]);
3190 	  p[2] = div255(alpha1 * color2 + alpha * p[2]);
3191 	}
3192 	p[3] = 255;
3193 	p += 4;
3194       }
3195     }
3196     break;
3197 #if SPLASH_CMYK
3198   case splashModeCMYK8:
3199     color0 = color[0];
3200     color1 = color[1];
3201     color2 = color[2];
3202     color3 = color[3];
3203     for (y = 0; y < bitmap->height; ++y) {
3204       p = &bitmap->data[y * bitmap->rowSize];
3205       q = &bitmap->alpha[y * bitmap->width];
3206       for (x = 0; x < bitmap->width; ++x) {
3207 	alpha = *q++;
3208 	alpha1 = 255 - alpha;
3209 	p[0] = div255(alpha1 * color0 + alpha * p[0]);
3210 	p[1] = div255(alpha1 * color1 + alpha * p[1]);
3211 	p[2] = div255(alpha1 * color2 + alpha * p[2]);
3212 	p[3] = div255(alpha1 * color3 + alpha * p[3]);
3213 	p += 4;
3214       }
3215     }
3216     break;
3217 #endif
3218   }
3219   memset(bitmap->alpha, 255, bitmap->width * bitmap->height);
3220 }
3221 
gouraudTriangleShadedFill(SplashGouraudColor * shading)3222 GBool Splash::gouraudTriangleShadedFill(SplashGouraudColor *shading)
3223 {
3224   double xdbl[3] = {0., 0., 0.};
3225   double ydbl[3] = {0., 0., 0.};
3226   int    x[3] = {0, 0, 0};
3227   int    y[3] = {0, 0, 0};
3228   double xt=0., xa=0., yt=0.;
3229   double ca=0., ct=0.;
3230 
3231   // triangle interpolation:
3232   //
3233   double scanLimitMapL[2] = {0., 0.};
3234   double scanLimitMapR[2] = {0., 0.};
3235   double scanColorMapL[2] = {0., 0.};
3236   double scanColorMapR[2] = {0., 0.};
3237   double scanColorMap[2] = {0., 0.};
3238   int scanEdgeL[2] = { 0, 0 };
3239   int scanEdgeR[2] = { 0, 0 };
3240   GBool hasFurtherSegment = gFalse;
3241 
3242   int scanLineOff = 0;
3243   int bitmapOff = 0;
3244   int scanLimitR = 0, scanLimitL = 0, Yt = 0;
3245 
3246   int bitmapWidth = bitmap->getWidth();
3247   SplashClip* clip = getClip();
3248   SplashBitmap *blitTarget = bitmap;
3249   SplashColorPtr bitmapData = bitmap->getDataPtr();
3250   SplashColorPtr bitmapAlpha = bitmap->getAlphaPtr();
3251   SplashColorPtr cur = NULL;
3252   SplashCoord* userToCanvasMatrix = getMatrix();
3253   SplashColorMode bitmapMode = bitmap->getMode();
3254   GBool hasAlpha = (bitmapAlpha != NULL);
3255   int rowSize = bitmap->getRowSize();
3256   int colorComps = 0;
3257   switch (bitmapMode) {
3258     case splashModeMono1:
3259     break;
3260     case splashModeMono8:
3261       colorComps=1;
3262     break;
3263     case splashModeRGB8:
3264       colorComps=3;
3265     break;
3266     case splashModeBGR8:
3267       colorComps=3;
3268     break;
3269     case splashModeXBGR8:
3270       colorComps=4;
3271     break;
3272 #if SPLASH_CMYK
3273     case splashModeCMYK8:
3274       colorComps=4;
3275     break;
3276 #endif
3277   }
3278 
3279   SplashPipe pipe;
3280   SplashColor cSrcVal;
3281 
3282   pipeInit(&pipe, 0, 0, NULL, cSrcVal, state->strokeAlpha, gFalse, gFalse);
3283 
3284   if (vectorAntialias) {
3285     if (aaBuf == NULL)
3286       return gFalse; // fall back to old behaviour
3287     drawAAPixelInit();
3288   }
3289 
3290   // idea:
3291   // 1. If pipe->noTransparency && !state->blendFunc
3292   //  -> blit directly into the drawing surface!
3293   //  -> disable alpha manually.
3294   // 2. Otherwise:
3295   // - blit also directly, but into an intermediate surface.
3296   // Afterwards, blit the intermediate surface using the drawing pipeline.
3297   // This is necessary because triangle elements can be on top of each
3298   // other, so the complete shading needs to be drawn before opacity is
3299   // applied.
3300   // - the final step, is performed using a SplashPipe:
3301   // - assign the actual color into cSrcVal: pipe uses cSrcVal by reference
3302   // - invoke drawPixel(&pipe,X,Y,bNoClip);
3303   GBool bDirectBlit = vectorAntialias ? gFalse : pipe.noTransparency && !state->blendFunc;
3304   if (!bDirectBlit) {
3305     blitTarget = new SplashBitmap(bitmap->getWidth(),
3306                                   bitmap->getHeight(),
3307                                   bitmap->getRowPad(),
3308                                   bitmap->getMode(),
3309                                   gTrue,
3310                                   bitmap->getRowSize() >= 0);
3311     bitmapData = blitTarget->getDataPtr();
3312     bitmapAlpha = blitTarget->getAlphaPtr();
3313 
3314     // initialisation seems to be necessary:
3315     int S = bitmap->getWidth() * bitmap->getHeight();
3316     for (int i = 0; i < S; ++i)
3317       bitmapAlpha[i] = 0;
3318     hasAlpha = gTrue;
3319   }
3320 
3321   if (shading->isParameterized()) {
3322     double color[3];
3323     double colorinterp;
3324 
3325     for (int i = 0; i < shading->getNTriangles(); ++i) {
3326       shading->getTriangle(i,
3327                            xdbl + 0, ydbl + 0, color + 0,
3328                            xdbl + 1, ydbl + 1, color + 1,
3329                            xdbl + 2, ydbl + 2, color + 2);
3330       for (int m = 0; m < 3; ++m) {
3331         xt = xdbl[m] * userToCanvasMatrix[0] + ydbl[m] * userToCanvasMatrix[2] + userToCanvasMatrix[4];
3332         yt = xdbl[m] * userToCanvasMatrix[1] + ydbl[m] * userToCanvasMatrix[3] + userToCanvasMatrix[5];
3333         xdbl[m] = xt;
3334         ydbl[m] = yt;
3335         // we operate on scanlines which are integer offsets into the
3336         // raster image. The double offsets are of no use here.
3337         x[m] = splashRound(xt);
3338         y[m] = splashRound(yt);
3339       }
3340       // sort according to y coordinate to simplify sweep through scanlines:
3341       // INSERTION SORT.
3342       if (y[0] > y[1]) {
3343         Guswap(x[0], x[1]);
3344         Guswap(y[0], y[1]);
3345         Guswap(color[0], color[1]);
3346       }
3347       // first two are sorted.
3348       assert(y[0] <= y[1]);
3349       if (y[1] > y[2]) {
3350         int tmpX = x[2];
3351         int tmpY = y[2];
3352         double tmpC = color[2];
3353         x[2] = x[1]; y[2] = y[1]; color[2] = color[1];
3354 
3355         if (y[0] > tmpY) {
3356           x[1] = x[0]; y[1] = y[0]; color[1] = color[0];
3357           x[0] = tmpX; y[0] = tmpY; color[0] = tmpC;
3358         } else {
3359           x[1] = tmpX; y[1] = tmpY; color[1] = tmpC;
3360         }
3361       }
3362       // first three are sorted
3363       assert(y[0] <= y[1]);
3364       assert(y[1] <= y[2]);
3365       /////
3366 
3367       // this here is det( T ) == 0
3368       // where T is the matrix to map to barycentric coordinates.
3369       if ((x[0] - x[2]) * (y[1] - y[2]) - (x[1] - x[2]) * (y[0] - y[2]) == 0)
3370         continue; // degenerate triangle.
3371 
3372       // this here initialises the scanline generation.
3373       // We start with low Y coordinates and sweep up to the large Y
3374       // coordinates.
3375       //
3376       // scanEdgeL[m] in {0,1,2} m=0,1
3377       // scanEdgeR[m] in {0,1,2} m=0,1
3378       //
3379       // are the two edges between which scanlines are (currently)
3380       // sweeped. The values {0,1,2} are indices into 'x' and 'y'.
3381       // scanEdgeL[0] = 0 means: the left scan edge has (x[0],y[0]) as vertex.
3382       //
3383       scanEdgeL[0] = 0;
3384       scanEdgeR[0] = 0;
3385       if (y[0] == y[1]) {
3386         scanEdgeL[0] = 1;
3387         scanEdgeL[1] = scanEdgeR[1] = 2;
3388 
3389       } else {
3390         scanEdgeL[1] = 1; scanEdgeR[1] = 2;
3391       }
3392       assert(y[scanEdgeL[0]] < y[scanEdgeL[1]]);
3393       assert(y[scanEdgeR[0]] < y[scanEdgeR[1]]);
3394 
3395       // Ok. Now prepare the linear maps which map the y coordinate of
3396       // the current scanline to the corresponding LEFT and RIGHT x
3397       // coordinate (which define the scanline).
3398       scanLimitMapL[0] = double(x[scanEdgeL[1]] - x[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]);
3399       scanLimitMapL[1] = x[scanEdgeL[0]] - y[scanEdgeL[0]] * scanLimitMapL[0];
3400       scanLimitMapR[0] = double(x[scanEdgeR[1]] - x[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
3401       scanLimitMapR[1] = x[scanEdgeR[0]] - y[scanEdgeR[0]] * scanLimitMapR[0];
3402 
3403       xa = y[1] * scanLimitMapL[0] + scanLimitMapL[1];
3404       xt = y[1] * scanLimitMapR[0] + scanLimitMapR[1];
3405       if (xa > xt) {
3406         // I have "left" is to the right of "right".
3407         // Exchange sides!
3408         Guswap(scanEdgeL[0], scanEdgeR[0]);
3409         Guswap(scanEdgeL[1], scanEdgeR[1]);
3410         Guswap(scanLimitMapL[0], scanLimitMapR[0]);
3411         Guswap(scanLimitMapL[1], scanLimitMapR[1]);
3412         // FIXME I'm sure there is a more efficient way to check this.
3413       }
3414 
3415       // Same game: we can linearly interpolate the color based on the
3416       // current y coordinate (that's correct for triangle
3417       // interpolation due to linearity. We could also have done it in
3418       // barycentric coordinates, but that's slightly more involved)
3419       scanColorMapL[0] = (color[scanEdgeL[1]] - color[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]);
3420       scanColorMapL[1] = color[scanEdgeL[0]] - y[scanEdgeL[0]] * scanColorMapL[0];
3421       scanColorMapR[0] = (color[scanEdgeR[1]] - color[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
3422       scanColorMapR[1] = color[scanEdgeR[0]] - y[scanEdgeR[0]] * scanColorMapR[0];
3423 
3424       Yt = y[2];
3425       hasFurtherSegment = (y[1] < y[2]);
3426       scanLineOff = y[0] * rowSize;
3427 
3428       for (int Y = y[0]; Y <= y[2]; ++Y, scanLineOff += rowSize) {
3429         if (hasFurtherSegment && Y == y[1]) {
3430           // SWEEP EVENT: we encountered the next segment.
3431           //
3432           // switch to next segment, either at left end or at right
3433           // end:
3434           if (scanEdgeL[1] == 1) {
3435             scanEdgeL[0] = 1;
3436             scanEdgeL[1] = 2;
3437             scanLimitMapL[0] = double(x[scanEdgeL[1]] - x[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]);
3438             scanLimitMapL[1] = x[scanEdgeL[0]] - y[scanEdgeL[0]] * scanLimitMapL[0];
3439 
3440             scanColorMapL[0] = (color[scanEdgeL[1]] - color[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]);
3441             scanColorMapL[1] = color[scanEdgeL[0]] - y[scanEdgeL[0]] * scanColorMapL[0];
3442           } else if (scanEdgeR[1] == 1) {
3443             scanEdgeR[0] = 1;
3444             scanEdgeR[1] = 2;
3445             scanLimitMapR[0] = double(x[scanEdgeR[1]] - x[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
3446             scanLimitMapR[1] = x[scanEdgeR[0]] - y[scanEdgeR[0]] * scanLimitMapR[0];
3447 
3448             scanColorMapR[0] = (color[scanEdgeR[1]] - color[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
3449             scanColorMapR[1] = color[scanEdgeR[0]] - y[scanEdgeR[0]] * scanColorMapR[0];
3450           }
3451           assert( y[scanEdgeL[0]]  <  y[scanEdgeL[1]] );
3452           assert( y[scanEdgeR[0]] <  y[scanEdgeR[1]] );
3453           hasFurtherSegment = gFalse;
3454         }
3455 
3456         yt = Y;
3457 
3458         xa = yt * scanLimitMapL[0] + scanLimitMapL[1];
3459         xt = yt * scanLimitMapR[0] + scanLimitMapR[1];
3460 
3461         ca = yt * scanColorMapL[0] + scanColorMapL[1];
3462         ct = yt * scanColorMapR[0] + scanColorMapR[1];
3463 
3464         scanLimitL = splashRound(xa);
3465         scanLimitR = splashRound(xt);
3466 
3467         // Ok. Now: init the color interpolation depending on the X
3468         // coordinate inside of the current scanline:
3469         scanColorMap[0] = (scanLimitR == scanLimitL) ? 0. : ((ct - ca) / (scanLimitR - scanLimitL));
3470         scanColorMap[1] = ca - scanLimitL * scanColorMap[0];
3471 
3472         // handled by clipping:
3473         // assert( scanLimitL >= 0 && scanLimitR < bitmap->getWidth() );
3474         assert(scanLimitL <= scanLimitR || abs(scanLimitL - scanLimitR) <= 2); // allow rounding inaccuracies
3475         assert(scanLineOff == Y * rowSize);
3476 
3477         colorinterp = scanColorMap[0] * scanLimitL + scanColorMap[1];
3478 
3479         bitmapOff = scanLineOff + scanLimitL * colorComps;
3480         for (int X = scanLimitL; X <= scanLimitR; ++X, colorinterp += scanColorMap[0], bitmapOff += colorComps) {
3481           // FIXME : standard rectangular clipping can be done for a
3482           // complete scanline which is faster
3483           // --> see SplashClip and its methods
3484           if (!clip->test(X, Y))
3485             continue;
3486 
3487           assert(fabs(colorinterp - (scanColorMap[0] * X + scanColorMap[1])) < 1e-10);
3488           assert(bitmapOff == Y * rowSize + colorComps * X && scanLineOff == Y * rowSize);
3489 
3490           shading->getParameterizedColor(colorinterp, bitmapMode, &bitmapData[bitmapOff]);
3491 
3492           // make the shading visible.
3493           // Note that opacity is handled by the bDirectBlit stuff, see
3494           // above for comments and below for implementation.
3495           if (hasAlpha)
3496             bitmapAlpha[Y * bitmapWidth + X] = 255;
3497         }
3498       }
3499     }
3500   } else {
3501     return gFalse;
3502   }
3503 
3504   if (!bDirectBlit) {
3505     // ok. Finalize the stuff by blitting the shading into the final
3506     // geometry, this time respecting the rendering pipe.
3507     int W = blitTarget->getWidth();
3508     int H = blitTarget->getHeight();
3509     cur = cSrcVal;
3510 
3511     for (int X = 0; X < W; ++X) {
3512       for (int Y = 0; Y < H; ++Y) {
3513         if (!bitmapAlpha[Y * bitmapWidth + X])
3514           continue; // draw only parts of the shading!
3515         bitmapOff = Y * rowSize + colorComps * X;
3516 
3517         for (int m = 0; m < colorComps; ++m)
3518           cur[m] = bitmapData[bitmapOff + m];
3519         if (vectorAntialias) {
3520           drawAAPixel(&pipe, X, Y);
3521         } else {
3522           drawPixel(&pipe, X, Y, gTrue); // no clipping - has already been done.
3523         }
3524       }
3525     }
3526 
3527     delete blitTarget;
3528     blitTarget = NULL;
3529   }
3530 
3531   return gTrue;
3532 }
3533 
blitTransparent(SplashBitmap * src,int xSrc,int ySrc,int xDest,int yDest,int w,int h)3534 SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
3535 				    int xDest, int yDest, int w, int h) {
3536   SplashColor pixel;
3537   SplashColorPtr p, sp;
3538   Guchar *q;
3539   int x, y, mask;
3540 
3541   if (src->mode != bitmap->mode) {
3542     return splashErrModeMismatch;
3543   }
3544 
3545   switch (bitmap->mode) {
3546   case splashModeMono1:
3547     for (y = 0; y < h; ++y) {
3548       p = &bitmap->data[(yDest + y) * bitmap->rowSize + (xDest >> 3)];
3549       mask = 0x80 >> (xDest & 7);
3550       for (x = 0; x < w; ++x) {
3551 	src->getPixel(xSrc + x, ySrc + y, pixel);
3552 	if (pixel[0]) {
3553 	  *p |= mask;
3554 	} else {
3555 	  *p &= ~mask;
3556 	}
3557 	if (!(mask >>= 1)) {
3558 	  mask = 0x80;
3559 	  ++p;
3560 	}
3561       }
3562     }
3563     break;
3564   case splashModeMono8:
3565     for (y = 0; y < h; ++y) {
3566       p = &bitmap->data[(yDest + y) * bitmap->rowSize + xDest];
3567       for (x = 0; x < w; ++x) {
3568 	src->getPixel(xSrc + x, ySrc + y, pixel);
3569 	*p++ = pixel[0];
3570       }
3571     }
3572     break;
3573   case splashModeRGB8:
3574   case splashModeBGR8:
3575     for (y = 0; y < h; ++y) {
3576       p = &bitmap->data[(yDest + y) * bitmap->rowSize + 3 * xDest];
3577       sp = &src->data[(ySrc + y) * src->rowSize + 3 * xSrc];
3578       for (x = 0; x < w; ++x) {
3579 	*p++ = *sp++;
3580 	*p++ = *sp++;
3581 	*p++ = *sp++;
3582       }
3583     }
3584     break;
3585   case splashModeXBGR8:
3586     for (y = 0; y < h; ++y) {
3587       p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest];
3588       sp = &src->data[(ySrc + y) * src->rowSize + 4 * xSrc];
3589       for (x = 0; x < w; ++x) {
3590 	*p++ = *sp++;
3591 	*p++ = *sp++;
3592 	*p++ = *sp++;
3593 	*p++ = 255;
3594 	sp++;
3595       }
3596     }
3597     break;
3598 #if SPLASH_CMYK
3599   case splashModeCMYK8:
3600     for (y = 0; y < h; ++y) {
3601       p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest];
3602       for (x = 0; x < w; ++x) {
3603 	src->getPixel(xSrc + x, ySrc + y, pixel);
3604 	*p++ = pixel[0];
3605 	*p++ = pixel[1];
3606 	*p++ = pixel[2];
3607 	*p++ = pixel[3];
3608       }
3609     }
3610     break;
3611 #endif
3612   }
3613 
3614   if (bitmap->alpha) {
3615     for (y = 0; y < h; ++y) {
3616       q = &bitmap->alpha[(yDest + y) * bitmap->width + xDest];
3617       memset(q, 0x00, w);
3618     }
3619   }
3620 
3621   return splashOk;
3622 }
3623 
makeStrokePath(SplashPath * path,GBool flatten)3624 SplashPath *Splash::makeStrokePath(SplashPath *path, GBool flatten) {
3625   SplashPath *pathIn, *pathOut;
3626   SplashCoord w, d, dx, dy, wdx, wdy, dxNext, dyNext, wdxNext, wdyNext;
3627   SplashCoord crossprod, dotprod, miter, m;
3628   GBool first, last, closed;
3629   int subpathStart, next, i;
3630   int left0, left1, left2, right0, right1, right2, join0, join1, join2;
3631   int leftFirst, rightFirst, firstPt;
3632 
3633   if (flatten) {
3634     pathIn = flattenPath(path, state->matrix, state->flatness);
3635     if (state->lineDashLength > 0) {
3636       pathOut = makeDashedPath(pathIn);
3637       delete pathIn;
3638       pathIn = pathOut;
3639     }
3640   } else {
3641     pathIn = path;
3642   }
3643 
3644   subpathStart = 0; // make gcc happy
3645   closed = gFalse; // make gcc happy
3646   left0 = left1 = right0 = right1 = join0 = join1 = 0; // make gcc happy
3647   leftFirst = rightFirst = firstPt = 0; // make gcc happy
3648 
3649   pathOut = new SplashPath();
3650   w = state->lineWidth;
3651 
3652   for (i = 0; i < pathIn->length - 1; ++i) {
3653     if (pathIn->flags[i] & splashPathLast) {
3654       continue;
3655     }
3656     if ((first = pathIn->flags[i] & splashPathFirst)) {
3657       subpathStart = i;
3658       closed = pathIn->flags[i] & splashPathClosed;
3659     }
3660     last = pathIn->flags[i+1] & splashPathLast;
3661 
3662     // compute the deltas for segment (i, i+1)
3663     d = splashDist(pathIn->pts[i].x, pathIn->pts[i].y,
3664 		   pathIn->pts[i+1].x, pathIn->pts[i+1].y);
3665     if (d == 0) {
3666       // we need to draw end caps on zero-length lines
3667       //~ not clear what the behavior should be for splashLineCapButt
3668       //~   with d==0
3669       dx = 0;
3670       dy = 1;
3671     } else {
3672       d = (SplashCoord)1 / d;
3673       dx = d * (pathIn->pts[i+1].x - pathIn->pts[i].x);
3674       dy = d * (pathIn->pts[i+1].y - pathIn->pts[i].y);
3675     }
3676     wdx = (SplashCoord)0.5 * w * dx;
3677     wdy = (SplashCoord)0.5 * w * dy;
3678 
3679     // compute the deltas for segment (i+1, next)
3680     next = last ? subpathStart + 1 : i + 2;
3681     d = splashDist(pathIn->pts[i+1].x, pathIn->pts[i+1].y,
3682 		   pathIn->pts[next].x, pathIn->pts[next].y);
3683     if (d == 0) {
3684       // we need to draw end caps on zero-length lines
3685       //~ not clear what the behavior should be for splashLineCapButt
3686       //~   with d==0
3687       dxNext = 0;
3688       dyNext = 1;
3689     } else {
3690       d = (SplashCoord)1 / d;
3691       dxNext = d * (pathIn->pts[next].x - pathIn->pts[i+1].x);
3692       dyNext = d * (pathIn->pts[next].y - pathIn->pts[i+1].y);
3693     }
3694     wdxNext = (SplashCoord)0.5 * w * dxNext;
3695     wdyNext = (SplashCoord)0.5 * w * dyNext;
3696 
3697     // draw the start cap
3698     pathOut->moveTo(pathIn->pts[i].x - wdy, pathIn->pts[i].y + wdx);
3699     if (i == subpathStart) {
3700       firstPt = pathOut->length - 1;
3701     }
3702     if (first && !closed) {
3703       switch (state->lineCap) {
3704       case splashLineCapButt:
3705 	pathOut->lineTo(pathIn->pts[i].x + wdy, pathIn->pts[i].y - wdx);
3706 	break;
3707       case splashLineCapRound:
3708 	pathOut->curveTo(pathIn->pts[i].x - wdy - bezierCircle * wdx,
3709 			 pathIn->pts[i].y + wdx - bezierCircle * wdy,
3710 			 pathIn->pts[i].x - wdx - bezierCircle * wdy,
3711 			 pathIn->pts[i].y - wdy + bezierCircle * wdx,
3712 			 pathIn->pts[i].x - wdx,
3713 			 pathIn->pts[i].y - wdy);
3714 	pathOut->curveTo(pathIn->pts[i].x - wdx + bezierCircle * wdy,
3715 			 pathIn->pts[i].y - wdy - bezierCircle * wdx,
3716 			 pathIn->pts[i].x + wdy - bezierCircle * wdx,
3717 			 pathIn->pts[i].y - wdx - bezierCircle * wdy,
3718 			 pathIn->pts[i].x + wdy,
3719 			 pathIn->pts[i].y - wdx);
3720 	break;
3721       case splashLineCapProjecting:
3722 	pathOut->lineTo(pathIn->pts[i].x - wdx - wdy,
3723 			pathIn->pts[i].y + wdx - wdy);
3724 	pathOut->lineTo(pathIn->pts[i].x - wdx + wdy,
3725 			pathIn->pts[i].y - wdx - wdy);
3726 	pathOut->lineTo(pathIn->pts[i].x + wdy,
3727 			pathIn->pts[i].y - wdx);
3728 	break;
3729       }
3730     } else {
3731       pathOut->lineTo(pathIn->pts[i].x + wdy, pathIn->pts[i].y - wdx);
3732     }
3733 
3734     // draw the left side of the segment rectangle
3735     left2 = pathOut->length - 1;
3736     pathOut->lineTo(pathIn->pts[i+1].x + wdy, pathIn->pts[i+1].y - wdx);
3737 
3738     // draw the end cap
3739     if (last && !closed) {
3740       switch (state->lineCap) {
3741       case splashLineCapButt:
3742 	pathOut->lineTo(pathIn->pts[i+1].x - wdy, pathIn->pts[i+1].y + wdx);
3743 	break;
3744       case splashLineCapRound:
3745 	pathOut->curveTo(pathIn->pts[i+1].x + wdy + bezierCircle * wdx,
3746 			 pathIn->pts[i+1].y - wdx + bezierCircle * wdy,
3747 			 pathIn->pts[i+1].x + wdx + bezierCircle * wdy,
3748 			 pathIn->pts[i+1].y + wdy - bezierCircle * wdx,
3749 			 pathIn->pts[i+1].x + wdx,
3750 			 pathIn->pts[i+1].y + wdy);
3751 	pathOut->curveTo(pathIn->pts[i+1].x + wdx - bezierCircle * wdy,
3752 			 pathIn->pts[i+1].y + wdy + bezierCircle * wdx,
3753 			 pathIn->pts[i+1].x - wdy + bezierCircle * wdx,
3754 			 pathIn->pts[i+1].y + wdx + bezierCircle * wdy,
3755 			 pathIn->pts[i+1].x - wdy,
3756 			 pathIn->pts[i+1].y + wdx);
3757 	break;
3758       case splashLineCapProjecting:
3759 	pathOut->lineTo(pathIn->pts[i+1].x + wdy + wdx,
3760 			pathIn->pts[i+1].y - wdx + wdy);
3761 	pathOut->lineTo(pathIn->pts[i+1].x - wdy + wdx,
3762 			pathIn->pts[i+1].y + wdx + wdy);
3763 	pathOut->lineTo(pathIn->pts[i+1].x - wdy,
3764 			pathIn->pts[i+1].y + wdx);
3765 	break;
3766       }
3767     } else {
3768       pathOut->lineTo(pathIn->pts[i+1].x - wdy, pathIn->pts[i+1].y + wdx);
3769     }
3770 
3771     // draw the right side of the segment rectangle
3772     right2 = pathOut->length - 1;
3773     pathOut->close();
3774 
3775     // draw the join
3776     join2 = pathOut->length;
3777     if (!last || closed) {
3778       crossprod = dx * dyNext - dy * dxNext;
3779       dotprod = -(dx * dxNext + dy * dyNext);
3780       if (dotprod > 0.99999) {
3781 	// avoid a divide-by-zero -- set miter to something arbitrary
3782 	// such that sqrt(miter) will exceed miterLimit (and m is never
3783 	// used in that situation)
3784 	miter = (state->miterLimit + 1) * (state->miterLimit + 1);
3785 	m = 0;
3786       } else {
3787 	miter = (SplashCoord)2 / ((SplashCoord)1 - dotprod);
3788 	if (miter < 1) {
3789 	  // this can happen because of floating point inaccuracies
3790 	  miter = 1;
3791 	}
3792 	m = splashSqrt(miter - 1);
3793       }
3794 
3795       // round join
3796       if (state->lineJoin == splashLineJoinRound) {
3797 	pathOut->moveTo(pathIn->pts[i+1].x + (SplashCoord)0.5 * w,
3798 			pathIn->pts[i+1].y);
3799 	pathOut->curveTo(pathIn->pts[i+1].x + (SplashCoord)0.5 * w,
3800 			 pathIn->pts[i+1].y + bezierCircle2 * w,
3801 			 pathIn->pts[i+1].x + bezierCircle2 * w,
3802 			 pathIn->pts[i+1].y + (SplashCoord)0.5 * w,
3803 			 pathIn->pts[i+1].x,
3804 			 pathIn->pts[i+1].y + (SplashCoord)0.5 * w);
3805 	pathOut->curveTo(pathIn->pts[i+1].x - bezierCircle2 * w,
3806 			 pathIn->pts[i+1].y + (SplashCoord)0.5 * w,
3807 			 pathIn->pts[i+1].x - (SplashCoord)0.5 * w,
3808 			 pathIn->pts[i+1].y + bezierCircle2 * w,
3809 			 pathIn->pts[i+1].x - (SplashCoord)0.5 * w,
3810 			 pathIn->pts[i+1].y);
3811 	pathOut->curveTo(pathIn->pts[i+1].x - (SplashCoord)0.5 * w,
3812 			 pathIn->pts[i+1].y - bezierCircle2 * w,
3813 			 pathIn->pts[i+1].x - bezierCircle2 * w,
3814 			 pathIn->pts[i+1].y - (SplashCoord)0.5 * w,
3815 			 pathIn->pts[i+1].x,
3816 			 pathIn->pts[i+1].y - (SplashCoord)0.5 * w);
3817 	pathOut->curveTo(pathIn->pts[i+1].x + bezierCircle2 * w,
3818 			 pathIn->pts[i+1].y - (SplashCoord)0.5 * w,
3819 			 pathIn->pts[i+1].x + (SplashCoord)0.5 * w,
3820 			 pathIn->pts[i+1].y - bezierCircle2 * w,
3821 			 pathIn->pts[i+1].x + (SplashCoord)0.5 * w,
3822 			 pathIn->pts[i+1].y);
3823 
3824       } else {
3825 	pathOut->moveTo(pathIn->pts[i+1].x, pathIn->pts[i+1].y);
3826 
3827 	// angle < 180
3828 	if (crossprod < 0) {
3829 	  pathOut->lineTo(pathIn->pts[i+1].x - wdyNext,
3830 			  pathIn->pts[i+1].y + wdxNext);
3831 	  // miter join inside limit
3832 	  if (state->lineJoin == splashLineJoinMiter &&
3833 	      splashSqrt(miter) <= state->miterLimit) {
3834 	    pathOut->lineTo(pathIn->pts[i+1].x - wdy + wdx * m,
3835 			    pathIn->pts[i+1].y + wdx + wdy * m);
3836 	    pathOut->lineTo(pathIn->pts[i+1].x - wdy,
3837 			    pathIn->pts[i+1].y + wdx);
3838 	  // bevel join or miter join outside limit
3839 	  } else {
3840 	    pathOut->lineTo(pathIn->pts[i+1].x - wdy, pathIn->pts[i+1].y + wdx);
3841 	  }
3842 
3843 	// angle >= 180
3844 	} else {
3845 	  pathOut->lineTo(pathIn->pts[i+1].x + wdy,
3846 			  pathIn->pts[i+1].y - wdx);
3847 	  // miter join inside limit
3848 	  if (state->lineJoin == splashLineJoinMiter &&
3849 	      splashSqrt(miter) <= state->miterLimit) {
3850 	    pathOut->lineTo(pathIn->pts[i+1].x + wdy + wdx * m,
3851 			    pathIn->pts[i+1].y - wdx + wdy * m);
3852 	    pathOut->lineTo(pathIn->pts[i+1].x + wdyNext,
3853 			    pathIn->pts[i+1].y - wdxNext);
3854 	  // bevel join or miter join outside limit
3855 	  } else {
3856 	    pathOut->lineTo(pathIn->pts[i+1].x + wdyNext,
3857 			    pathIn->pts[i+1].y - wdxNext);
3858 	  }
3859 	}
3860       }
3861 
3862       pathOut->close();
3863     }
3864 
3865     // add stroke adjustment hints
3866     if (state->strokeAdjust) {
3867       if (i >= subpathStart + 1) {
3868 	if (i >= subpathStart + 2) {
3869 	  pathOut->addStrokeAdjustHint(left1, right1, left0 + 1, right0);
3870 	  pathOut->addStrokeAdjustHint(left1, right1, join0, left2);
3871 	} else {
3872 	  pathOut->addStrokeAdjustHint(left1, right1, firstPt, left2);
3873 	}
3874 	pathOut->addStrokeAdjustHint(left1, right1, right2 + 1, right2 + 1);
3875       }
3876       left0 = left1;
3877       left1 = left2;
3878       right0 = right1;
3879       right1 = right2;
3880       join0 = join1;
3881       join1 = join2;
3882       if (i == subpathStart) {
3883 	leftFirst = left2;
3884 	rightFirst = right2;
3885       }
3886       if (last) {
3887 	if (i >= subpathStart + 2) {
3888 	  pathOut->addStrokeAdjustHint(left1, right1, left0 + 1, right0);
3889 	  pathOut->addStrokeAdjustHint(left1, right1,
3890 				       join0, pathOut->length - 1);
3891 	} else {
3892 	  pathOut->addStrokeAdjustHint(left1, right1,
3893 				       firstPt, pathOut->length - 1);
3894 	}
3895 	if (closed) {
3896 	  pathOut->addStrokeAdjustHint(left1, right1, firstPt, leftFirst);
3897 	  pathOut->addStrokeAdjustHint(left1, right1,
3898 				       rightFirst + 1, rightFirst + 1);
3899 	  pathOut->addStrokeAdjustHint(leftFirst, rightFirst,
3900 				       left1 + 1, right1);
3901 	  pathOut->addStrokeAdjustHint(leftFirst, rightFirst,
3902 				       join1, pathOut->length - 1);
3903 	}
3904       }
3905     }
3906   }
3907 
3908   if (pathIn != path) {
3909     delete pathIn;
3910   }
3911 
3912   return pathOut;
3913 }
3914 
dumpPath(SplashPath * path)3915 void Splash::dumpPath(SplashPath *path) {
3916   int i;
3917 
3918   for (i = 0; i < path->length; ++i) {
3919     printf("  %3d: x=%8.2f y=%8.2f%s%s%s%s\n",
3920 	   i, (double)path->pts[i].x, (double)path->pts[i].y,
3921 	   (path->flags[i] & splashPathFirst) ? " first" : "",
3922 	   (path->flags[i] & splashPathLast) ? " last" : "",
3923 	   (path->flags[i] & splashPathClosed) ? " closed" : "",
3924 	   (path->flags[i] & splashPathCurve) ? " curve" : "");
3925   }
3926 }
3927 
dumpXPath(SplashXPath * path)3928 void Splash::dumpXPath(SplashXPath *path) {
3929   int i;
3930 
3931   for (i = 0; i < path->length; ++i) {
3932     printf("  %4d: x0=%8.2f y0=%8.2f x1=%8.2f y1=%8.2f %s%s%s%s%s%s%s\n",
3933 	   i, (double)path->segs[i].x0, (double)path->segs[i].y0,
3934 	   (double)path->segs[i].x1, (double)path->segs[i].y1,
3935 	   (path->segs[i].flags	& splashXPathFirst) ? "F" : " ",
3936 	   (path->segs[i].flags	& splashXPathLast) ? "L" : " ",
3937 	   (path->segs[i].flags	& splashXPathEnd0) ? "0" : " ",
3938 	   (path->segs[i].flags	& splashXPathEnd1) ? "1" : " ",
3939 	   (path->segs[i].flags	& splashXPathHoriz) ? "H" : " ",
3940 	   (path->segs[i].flags	& splashXPathVert) ? "V" : " ",
3941 	   (path->segs[i].flags	& splashXPathFlip) ? "P" : " ");
3942   }
3943 }
3944 
shadedFill(SplashPath * path,GBool hasBBox,SplashPattern * pattern)3945 SplashError Splash::shadedFill(SplashPath *path, GBool hasBBox,
3946                                SplashPattern *pattern) {
3947   SplashPipe pipe;
3948   SplashXPath *xPath;
3949   SplashXPathScanner *scanner;
3950   int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
3951   SplashClipResult clipRes;
3952 
3953   if (aaBuf == NULL) { // should not happen, but to be secure
3954     return splashErrGeneric;
3955   }
3956   if (path->length == 0) {
3957     return splashErrEmptyPath;
3958   }
3959   xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue);
3960   xPath->aaScale();
3961   xPath->sort();
3962   scanner = new SplashXPathScanner(xPath, gFalse);
3963 
3964   // get the min and max x and y values
3965   scanner->getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI);
3966 
3967   // check clipping
3968   if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) != splashClipAllOutside) {
3969     // limit the y range
3970     if (yMinI < state->clip->getYMinI()) {
3971       yMinI = state->clip->getYMinI();
3972     }
3973     if (yMaxI > state->clip->getYMaxI()) {
3974       yMaxI = state->clip->getYMaxI();
3975     }
3976 
3977     pipeInit(&pipe, 0, yMinI, pattern, NULL, state->fillAlpha, vectorAntialias && !hasBBox, gFalse);
3978 
3979     // draw the spans
3980     for (y = yMinI; y <= yMaxI; ++y) {
3981       scanner->renderAALine(aaBuf, &x0, &x1, y);
3982       if (clipRes != splashClipAllInside) {
3983         state->clip->clipAALine(aaBuf, &x0, &x1, y);
3984       }
3985       drawAALine(&pipe, x0, x1, y);
3986     }
3987   }
3988   opClipRes = clipRes;
3989 
3990   delete scanner;
3991   delete xPath;
3992   return splashOk;
3993 }
3994