1 //========================================================================
2 //
3 // Splash.cc
4 //
5 //========================================================================
6 
7 #include <aconf.h>
8 
9 #ifdef USE_GCC_PRAGMAS
10 #pragma implementation
11 #endif
12 
13 #include <stdlib.h>
14 #include <string.h>
15 #include "gmem.h"
16 #include "SplashErrorCodes.h"
17 #include "SplashMath.h"
18 #include "SplashBitmap.h"
19 #include "SplashState.h"
20 #include "SplashPath.h"
21 #include "SplashXPath.h"
22 #include "SplashXPathScanner.h"
23 #include "SplashPattern.h"
24 #include "SplashScreen.h"
25 #include "SplashFont.h"
26 #include "SplashGlyphBitmap.h"
27 #include "Splash.h"
28 
29 //------------------------------------------------------------------------
30 
blendNormal(SplashColorPtr src,SplashColorPtr dest,SplashColorPtr blend,SplashColorMode cm)31 static void blendNormal(SplashColorPtr src, SplashColorPtr dest,
32 			SplashColorPtr blend, SplashColorMode cm) {
33   int i;
34 
35   for (i = 0; i < splashColorModeNComps[cm]; ++i) {
36     blend[i] = src[i];
37   }
38 }
39 
40 //------------------------------------------------------------------------
41 // Splash
42 //------------------------------------------------------------------------
43 
Splash(SplashBitmap * bitmapA)44 Splash::Splash(SplashBitmap *bitmapA) {
45   bitmap = bitmapA;
46   state = new SplashState(bitmap->width, bitmap->height);
47   softMask = NULL;
48   clearModRegion();
49   debugMode = gFalse;
50 }
51 
~Splash()52 Splash::~Splash() {
53   while (state->next) {
54     restoreState();
55   }
56   delete state;
57   if (softMask) {
58     delete softMask;
59   }
60 }
61 
62 //------------------------------------------------------------------------
63 // state read
64 //------------------------------------------------------------------------
65 
getStrokePattern()66 SplashPattern *Splash::getStrokePattern() {
67   return state->strokePattern;
68 }
69 
getFillPattern()70 SplashPattern *Splash::getFillPattern() {
71   return state->fillPattern;
72 }
73 
getScreen()74 SplashScreen *Splash::getScreen() {
75   return state->screen;
76 }
77 
getBlendFunc()78 SplashBlendFunc Splash::getBlendFunc() {
79   return state->blendFunc;
80 }
81 
getStrokeAlpha()82 SplashCoord Splash::getStrokeAlpha() {
83   return state->strokeAlpha;
84 }
85 
getFillAlpha()86 SplashCoord Splash::getFillAlpha() {
87   return state->fillAlpha;
88 }
89 
getLineWidth()90 SplashCoord Splash::getLineWidth() {
91   return state->lineWidth;
92 }
93 
getLineCap()94 int Splash::getLineCap() {
95   return state->lineCap;
96 }
97 
getLineJoin()98 int Splash::getLineJoin() {
99   return state->lineJoin;
100 }
101 
getMiterLimit()102 SplashCoord Splash::getMiterLimit() {
103   return state->miterLimit;
104 }
105 
getFlatness()106 SplashCoord Splash::getFlatness() {
107   return state->flatness;
108 }
109 
getLineDash()110 SplashCoord *Splash::getLineDash() {
111   return state->lineDash;
112 }
113 
getLineDashLength()114 int Splash::getLineDashLength() {
115   return state->lineDashLength;
116 }
117 
getLineDashPhase()118 SplashCoord Splash::getLineDashPhase() {
119   return state->lineDashPhase;
120 }
121 
getClip()122 SplashClip *Splash::getClip() {
123   return state->clip;
124 }
125 
126 //------------------------------------------------------------------------
127 // state write
128 //------------------------------------------------------------------------
129 
setStrokePattern(SplashPattern * strokePattern)130 void Splash::setStrokePattern(SplashPattern *strokePattern) {
131   state->setStrokePattern(strokePattern);
132 }
133 
setFillPattern(SplashPattern * fillPattern)134 void Splash::setFillPattern(SplashPattern *fillPattern) {
135   state->setFillPattern(fillPattern);
136 }
137 
setScreen(SplashScreen * screen)138 void Splash::setScreen(SplashScreen *screen) {
139   state->setScreen(screen);
140 }
141 
setBlendFunc(SplashBlendFunc func)142 void Splash::setBlendFunc(SplashBlendFunc func) {
143   state->blendFunc = func;
144 }
145 
setStrokeAlpha(SplashCoord alpha)146 void Splash::setStrokeAlpha(SplashCoord alpha) {
147   state->strokeAlpha = alpha;
148 }
149 
setFillAlpha(SplashCoord alpha)150 void Splash::setFillAlpha(SplashCoord alpha) {
151   state->fillAlpha = alpha;
152 }
153 
setLineWidth(SplashCoord lineWidth)154 void Splash::setLineWidth(SplashCoord lineWidth) {
155   state->lineWidth = lineWidth;
156 }
157 
setLineCap(int lineCap)158 void Splash::setLineCap(int lineCap) {
159   state->lineCap = lineCap;
160 }
161 
setLineJoin(int lineJoin)162 void Splash::setLineJoin(int lineJoin) {
163   state->lineJoin = lineJoin;
164 }
165 
setMiterLimit(SplashCoord miterLimit)166 void Splash::setMiterLimit(SplashCoord miterLimit) {
167   state->miterLimit = miterLimit;
168 }
169 
setFlatness(SplashCoord flatness)170 void Splash::setFlatness(SplashCoord flatness) {
171   if (flatness < 1) {
172     state->flatness = 1;
173   } else {
174     state->flatness = flatness;
175   }
176 }
177 
setLineDash(SplashCoord * lineDash,int lineDashLength,SplashCoord lineDashPhase)178 void Splash::setLineDash(SplashCoord *lineDash, int lineDashLength,
179 			 SplashCoord lineDashPhase) {
180   state->setLineDash(lineDash, lineDashLength, lineDashPhase);
181 }
182 
clipResetToRect(SplashCoord x0,SplashCoord y0,SplashCoord x1,SplashCoord y1)183 void Splash::clipResetToRect(SplashCoord x0, SplashCoord y0,
184 			     SplashCoord x1, SplashCoord y1) {
185   state->clip->resetToRect(x0, y0, x1, y1);
186 }
187 
clipToRect(SplashCoord x0,SplashCoord y0,SplashCoord x1,SplashCoord y1)188 SplashError Splash::clipToRect(SplashCoord x0, SplashCoord y0,
189 			       SplashCoord x1, SplashCoord y1) {
190   return state->clip->clipToRect(x0, y0, x1, y1);
191 }
192 
clipToPath(SplashPath * path,GBool eo)193 SplashError Splash::clipToPath(SplashPath *path, GBool eo) {
194   return state->clip->clipToPath(path, state->flatness, eo);
195 }
196 
197 //------------------------------------------------------------------------
198 // state save/restore
199 //------------------------------------------------------------------------
200 
saveState()201 void Splash::saveState() {
202   SplashState *newState;
203 
204   newState = state->copy();
205   newState->next = state;
206   state = newState;
207 }
208 
restoreState()209 SplashError Splash::restoreState() {
210   SplashState *oldState;
211 
212   if (!state->next) {
213     return splashErrNoSave;
214   }
215   oldState = state;
216   state = state->next;
217   delete oldState;
218   return splashOk;
219 }
220 
221 //------------------------------------------------------------------------
222 // soft mask
223 //------------------------------------------------------------------------
224 
setSoftMask(SplashBitmap * softMaskA)225 void Splash::setSoftMask(SplashBitmap *softMaskA) {
226   if (softMask) {
227     delete softMask;
228   }
229   softMask = softMaskA;
230 }
231 
232 //------------------------------------------------------------------------
233 // modified region
234 //------------------------------------------------------------------------
235 
clearModRegion()236 void Splash::clearModRegion() {
237   modXMin = bitmap->getWidth();
238   modYMin = bitmap->getHeight();
239   modXMax = -1;
240   modYMax = -1;
241 }
242 
updateModX(int x)243 inline void Splash::updateModX(int x) {
244   if (x < modXMin) {
245     modXMin = x;
246   }
247   if (x > modXMax) {
248     modXMax = x;
249   }
250 }
251 
updateModY(int y)252 inline void Splash::updateModY(int y) {
253   if (y < modYMin) {
254     modYMin = y;
255   }
256   if (y > modYMax) {
257     modYMax = y;
258   }
259 }
260 
261 //------------------------------------------------------------------------
262 // drawing operations
263 //------------------------------------------------------------------------
264 
clear(SplashColorPtr color)265 void Splash::clear(SplashColorPtr color) {
266   SplashColorPtr row, p;
267   Guchar mono;
268   int x, y;
269 
270   switch (bitmap->mode) {
271   case splashModeMono1:
272     mono = color[0] ? 0xff : 0x00;
273     if (bitmap->rowSize < 0) {
274       memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
275 	     mono, -bitmap->rowSize * bitmap->height);
276     } else {
277       memset(bitmap->data, mono, bitmap->rowSize * bitmap->height);
278     }
279     break;
280   case splashModeMono8:
281     if (bitmap->rowSize < 0) {
282       memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
283 	     color[0], -bitmap->rowSize * bitmap->height);
284     } else {
285       memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
286     }
287     break;
288   case splashModeAMono8:
289     if (color[0] == color[1]) {
290       if (bitmap->rowSize < 0) {
291 	memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
292 	       color[0], -bitmap->rowSize * bitmap->height);
293       } else {
294 	memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
295       }
296     } else {
297       row = bitmap->data;
298       for (y = 0; y < bitmap->height; ++y) {
299 	p = row;
300 	for (x = 0; x < bitmap->width; ++x) {
301 	  *p++ = color[0];
302 	  *p++ = color[1];
303 	}
304 	row += bitmap->rowSize;
305       }
306     }
307     break;
308   case splashModeRGB8:
309   case splashModeBGR8:
310     if (color[0] == color[1] && color[1] == color[2]) {
311       if (bitmap->rowSize < 0) {
312 	memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
313 	       color[0], -bitmap->rowSize * bitmap->height);
314       } else {
315 	memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
316       }
317     } else {
318       row = bitmap->data;
319       for (y = 0; y < bitmap->height; ++y) {
320 	p = row;
321 	for (x = 0; x < bitmap->width; ++x) {
322 	  *p++ = color[0];
323 	  *p++ = color[1];
324 	  *p++ = color[2];
325 	}
326 	row += bitmap->rowSize;
327       }
328     }
329     break;
330   case splashModeARGB8:
331   case splashModeBGRA8:
332 #if SPLASH_CMYK
333   case splashModeCMYK8:
334 #endif
335     if (color[0] == color[1] && color[1] == color[2] && color[2] == color[3]) {
336       if (bitmap->rowSize < 0) {
337 	memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
338 	       color[0], -bitmap->rowSize * bitmap->height);
339       } else {
340 	memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
341       }
342     } else {
343       row = bitmap->data;
344       for (y = 0; y < bitmap->height; ++y) {
345 	p = row;
346 	for (x = 0; x < bitmap->width; ++x) {
347 	  *p++ = color[0];
348 	  *p++ = color[1];
349 	  *p++ = color[2];
350 	  *p++ = color[3];
351 	}
352 	row += bitmap->rowSize;
353       }
354     }
355     break;
356 #if SPLASH_CMYK
357   case splashModeACMYK8:
358     if (color[0] == color[1] && color[1] == color[2] &&
359 	color[2] == color[3] && color[3] == color[4]) {
360       if (bitmap->rowSize < 0) {
361 	memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
362 	       color[0], -bitmap->rowSize * bitmap->height);
363       } else {
364 	memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
365       }
366     } else {
367       row = bitmap->data;
368       for (y = 0; y < bitmap->height; ++y) {
369 	p = row;
370 	for (x = 0; x < bitmap->width; ++x) {
371 	  *p++ = color[0];
372 	  *p++ = color[1];
373 	  *p++ = color[2];
374 	  *p++ = color[3];
375 	  *p++ = color[4];
376 	}
377 	row += bitmap->rowSize;
378       }
379     }
380     break;
381 #endif
382   }
383 
384   updateModX(0);
385   updateModY(0);
386   updateModX(bitmap->width - 1);
387   updateModY(bitmap->height - 1);
388 }
389 
stroke(SplashPath * path)390 SplashError Splash::stroke(SplashPath *path) {
391   SplashXPath *xPath, *xPath2;
392 
393   if (debugMode)
394   {
395     printf("stroke [dash:%d] [width:%.2f]:\n",
396 	   state->lineDashLength, (double)state->lineWidth);
397     dumpPath(path);
398   }
399   opClipRes = splashClipAllOutside;
400   if (path->length == 0) {
401     return splashErrEmptyPath;
402   }
403   xPath = new SplashXPath(path, state->flatness, gFalse);
404   if (xPath->length == 0) {
405     delete xPath;
406     return splashErrEmptyPath;
407   }
408   if (state->lineDashLength > 0)
409   {
410     xPath2 = makeDashedPath(xPath);
411     delete xPath;
412     xPath = xPath2;
413   }
414   if (state->lineWidth <= 1)
415   {
416     strokeNarrow(xPath);
417   } else {
418     strokeWide(xPath);
419   }
420   delete xPath;
421   return splashOk;
422 }
423 
strokeNarrow(SplashXPath * xPath)424 void Splash::strokeNarrow(SplashXPath *xPath) {
425   SplashXPathSeg *seg;
426   int x0, x1, x2, x3, y0, y1, x, y, t;
427   SplashCoord dx, dy, dxdy;
428   SplashClipResult clipRes;
429   int nClipRes[3];
430   int i;
431 
432   for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) {
433 
434     x0 = splashFloor(seg->x0);
435     x1 = splashFloor(seg->x1);
436     y0 = splashFloor(seg->y0);
437     y1 = splashFloor(seg->y1);
438 
439     // horizontal segment
440     if (y0 == y1) {
441       if (x0 > x1) {
442 	t = x0; x0 = x1; x1 = t;
443       }
444       if ((clipRes = state->clip->testSpan(x0, x1, y0))
445 	  != splashClipAllOutside) {
446 	drawSpan(x0, x1, y0, state->strokePattern, state->strokeAlpha,
447 		 clipRes == splashClipAllInside);
448       }
449 
450     // segment with |dx| > |dy|
451     } else if (splashAbs(seg->dxdy) > 1) {
452       dx = seg->x1 - seg->x0;
453       dy = seg->y1 - seg->y0;
454       dxdy = seg->dxdy;
455       if (y0 > y1) {
456 	t = y0; y0 = y1; y1 = t;
457 	t = x0; x0 = x1; x1 = t;
458 	dx = -dx;
459 	dy = -dy;
460       }
461       if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0,
462 					   x0 <= x1 ? x1 : x0, y1))
463 	  != splashClipAllOutside) {
464 	if (dx > 0) {
465 	  x2 = x0;
466 	  x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy);
467 	  drawSpan(x2, (x2 <= x3 - 1) ? x3 - 1 : x2, y0, state->strokePattern,
468 		   state->strokeAlpha, clipRes == splashClipAllInside);
469 	  x2 = x3;
470 	  for (y = y0 + 1; y <= y1 - 1; ++y) {
471 	    x3 = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy);
472 	    drawSpan(x2, x3 - 1, y, state->strokePattern,
473 		     state->strokeAlpha, clipRes == splashClipAllInside);
474 	    x2 = x3;
475 	  }
476 	  drawSpan(x2, x2 <= x1 ? x1 : x2, y1, state->strokePattern,
477 		   state->strokeAlpha, clipRes == splashClipAllInside);
478 	} else {
479 	  x2 = x0;
480 	  x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy);
481 	  drawSpan((x3 + 1 <= x2) ? x3 + 1 : x2, x2, y0, state->strokePattern,
482 		   state->strokeAlpha, clipRes == splashClipAllInside);
483 	  x2 = x3;
484 	  for (y = y0 + 1; y <= y1 - 1; ++y) {
485 	    x3 = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy);
486 	    drawSpan(x3 + 1, x2, y, state->strokePattern,
487 		     state->strokeAlpha, clipRes == splashClipAllInside);
488 	    x2 = x3;
489 	  }
490 	  drawSpan(x1, (x1 <= x2) ? x2 : x1, y1, state->strokePattern,
491 		   state->strokeAlpha, clipRes == splashClipAllInside);
492 	}
493       }
494 
495     // segment with |dy| > |dx|
496     } else {
497       dxdy = seg->dxdy;
498       if (y0 > y1) {
499 	t = x0; x0 = x1; x1 = t;
500 	t = y0; y0 = y1; y1 = t;
501       }
502       if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0,
503 					   x0 <= x1 ? x1 : x0, y1))
504 	  != splashClipAllOutside) {
505 	drawPixel(x0, y0, state->strokePattern, state->strokeAlpha,
506 		  clipRes == splashClipAllInside);
507 	for (y = y0 + 1; y <= y1 - 1; ++y) {
508 	  x = splashFloor(seg->x0 + ((SplashCoord)y - seg->y0) * dxdy);
509 	  drawPixel(x, y, state->strokePattern, state->strokeAlpha,
510 		    clipRes == splashClipAllInside);
511 	}
512 	drawPixel(x1, y1, state->strokePattern, state->strokeAlpha,
513 		  clipRes == splashClipAllInside);
514       }
515     }
516     ++nClipRes[clipRes];
517   }
518   if (nClipRes[splashClipPartial] ||
519       (nClipRes[splashClipAllInside] && nClipRes[splashClipAllOutside])) {
520     opClipRes = splashClipPartial;
521   } else if (nClipRes[splashClipAllInside]) {
522     opClipRes = splashClipAllInside;
523   } else {
524     opClipRes = splashClipAllOutside;
525   }
526 }
527 
strokeWide(SplashXPath * xPath)528 void Splash::strokeWide(SplashXPath *xPath) {
529   SplashXPathSeg *seg, *seg2;
530   SplashPath *widePath;
531   SplashCoord d, dx, dy, wdx, wdy, dxPrev, dyPrev, wdxPrev, wdyPrev;
532   SplashCoord dotprod, miter;
533   int i, j;
534 
535   dx = dy = wdx = wdy = 0; // make gcc happy
536   dxPrev = dyPrev = wdxPrev = wdyPrev = 0; // make gcc happy
537 
538   for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) {
539 
540     // save the deltas for the previous segment; if this is the first
541     // segment on a subpath, compute the deltas for the last segment
542     // on the subpath (which may be used to draw a line join)
543     if (seg->flags & splashXPathFirst) {
544       for (j = i + 1, seg2 = &xPath->segs[j]; j < xPath->length; ++j, ++seg2) {
545 	if (seg2->flags & splashXPathLast) {
546 	  d = splashDist(seg2->x0, seg2->y0, seg2->x1, seg2->y1);
547 	  if (d == 0) {
548 	    //~ not clear what the behavior should be for joins with d==0
549 	    dxPrev = 0;
550 	    dyPrev = 1;
551 	  } else {
552 	    d = (SplashCoord)1 / d;
553 	    dxPrev = d * (seg2->x1 - seg2->x0);
554 	    dyPrev = d * (seg2->y1 - seg2->y0);
555 	  }
556 	  wdxPrev = (SplashCoord)0.5 * state->lineWidth * dxPrev;
557 	  wdyPrev = (SplashCoord)0.5 * state->lineWidth * dyPrev;
558 	  break;
559 	}
560       }
561     } else {
562       dxPrev = dx;
563       dyPrev = dy;
564       wdxPrev = wdx;
565       wdyPrev = wdy;
566     }
567 
568     // compute deltas for this line segment
569     d = splashDist(seg->x0, seg->y0, seg->x1, seg->y1);
570     if (d == 0) {
571       // we need to draw end caps on zero-length lines
572       //~ not clear what the behavior should be for splashLineCapButt with d==0
573       dx = 0;
574       dy = 1;
575     } else {
576       d = (SplashCoord)1 / d;
577       dx = d * (seg->x1 - seg->x0);
578       dy = d * (seg->y1 - seg->y0);
579     }
580     wdx = (SplashCoord)0.5 * state->lineWidth * dx;
581     wdy = (SplashCoord)0.5 * state->lineWidth * dy;
582 
583     // initialize the path (which will be filled)
584     widePath = new SplashPath();
585     widePath->moveTo(seg->x0 - wdy, seg->y0 + wdx);
586 
587     // draw the start cap
588     if (seg->flags & splashXPathEnd0) {
589       switch (state->lineCap) {
590       case splashLineCapButt:
591 	widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
592 	break;
593       case splashLineCapRound:
594 	widePath->arcCWTo(seg->x0 + wdy, seg->y0 - wdx, seg->x0, seg->y0);
595 	break;
596       case splashLineCapProjecting:
597 	widePath->lineTo(seg->x0 - wdx - wdy, seg->y0 + wdx - wdy);
598 	widePath->lineTo(seg->x0 - wdx + wdy, seg->y0 - wdx - wdy);
599 	widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
600 	break;
601       }
602     } else {
603       widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
604     }
605 
606     // draw the left side of the segment
607     widePath->lineTo(seg->x1 + wdy, seg->y1 - wdx);
608 
609     // draw the end cap
610     if (seg->flags & splashXPathEnd1) {
611       switch (state->lineCap) {
612       case splashLineCapButt:
613 	widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx);
614 	break;
615       case splashLineCapRound:
616 	widePath->arcCWTo(seg->x1 - wdy, seg->y1 + wdx, seg->x1, seg->y1);
617 	break;
618       case splashLineCapProjecting:
619 	widePath->lineTo(seg->x1 + wdx + wdy, seg->y1 - wdx + wdy);
620 	widePath->lineTo(seg->x1 + wdx - wdy, seg->y1 + wdx + wdy);
621 	widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx);
622 	break;
623       }
624     } else {
625       widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx);
626     }
627 
628     // draw the right side of the segment
629     widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx);
630 
631     // fill the segment
632     fillWithPattern(widePath, gTrue, state->strokePattern, state->strokeAlpha);
633     delete widePath;
634 
635     // draw the line join
636     if (!(seg->flags & splashXPathEnd0)) {
637       widePath = NULL;
638       switch (state->lineJoin) {
639       case splashLineJoinMiter:
640 	dotprod = -(dx * dxPrev + dy * dyPrev);
641 	if (splashAbs(splashAbs(dotprod) - 1) > 0.01) {
642 	  widePath = new SplashPath();
643 	  widePath->moveTo(seg->x0, seg->y0);
644 	  miter = (SplashCoord)2 / ((SplashCoord)1 - dotprod);
645 	  if (splashSqrt(miter) <= state->miterLimit) {
646 	    miter = splashSqrt(miter - 1);
647 	    if (dy * dxPrev > dx * dyPrev) {
648 	      widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev);
649 	      widePath->lineTo(seg->x0 + wdy - miter * wdx,
650 			       seg->y0 - wdx - miter * wdy);
651 	      widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
652 	    } else {
653 	      widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev);
654 	      widePath->lineTo(seg->x0 - wdy - miter * wdx,
655 			       seg->y0 + wdx - miter * wdy);
656 	      widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx);
657 	    }
658 	  } else {
659 	    if (dy * dxPrev > dx * dyPrev) {
660 	      widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev);
661 	      widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
662 	    } else {
663 	      widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev);
664 	      widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx);
665 	    }
666 	  }
667 	}
668 	break;
669       case splashLineJoinRound:
670 	widePath = new SplashPath();
671 	widePath->moveTo(seg->x0 + wdy, seg->y0 - wdx);
672 	widePath->arcCWTo(seg->x0 + wdy, seg->y0 - wdx, seg->x0, seg->y0);
673 	break;
674       case splashLineJoinBevel:
675 	widePath = new SplashPath();
676 	widePath->moveTo(seg->x0, seg->y0);
677 	if (dy * dxPrev > dx * dyPrev) {
678 	  widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev);
679 	  widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
680 	} else {
681 	  widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev);
682 	  widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx);
683 	}
684 	break;
685       }
686       if (widePath) {
687 	fillWithPattern(widePath, gTrue, state->strokePattern,
688 			state->strokeAlpha);
689 	delete widePath;
690       }
691     }
692   }
693 }
694 
makeDashedPath(SplashXPath * xPath)695 SplashXPath *Splash::makeDashedPath(SplashXPath *xPath) {
696   SplashXPath *dPath;
697   GBool lineDashStartOn, lineDashOn;
698   GBool atSegStart, atSegEnd, atDashStart, atDashEnd;
699   int lineDashStartIdx, lineDashIdx, subpathStart;
700   SplashCoord lineDashTotal, lineDashStartPhase, lineDashDist;
701   int segIdx;
702   SplashXPathSeg *seg;
703   SplashCoord sx0, sy0, sx1, sy1, ax0, ay0, ax1, ay1, dist;
704   int i;
705 
706   dPath = new SplashXPath();
707 
708   lineDashTotal = 0;
709   for (i = 0; i < state->lineDashLength; ++i) {
710     lineDashTotal += state->lineDash[i];
711   }
712   lineDashStartPhase = state->lineDashPhase;
713   i = splashFloor(lineDashStartPhase / lineDashTotal);
714   lineDashStartPhase -= (SplashCoord)i * lineDashTotal;
715   lineDashStartOn = gTrue;
716   lineDashStartIdx = 0;
717   while (lineDashStartPhase >= state->lineDash[lineDashStartIdx]) {
718     lineDashStartOn = !lineDashStartOn;
719     lineDashStartPhase -= state->lineDash[lineDashStartIdx];
720     ++lineDashStartIdx;
721   }
722 
723   segIdx = 0;
724   seg = xPath->segs;
725   sx0 = seg->x0;
726   sy0 = seg->y0;
727   sx1 = seg->x1;
728   sy1 = seg->y1;
729   dist = splashDist(sx0, sy0, sx1, sy1);
730   lineDashOn = lineDashStartOn;
731   lineDashIdx = lineDashStartIdx;
732   lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase;
733   atSegStart = gTrue;
734   atDashStart = gTrue;
735   subpathStart = dPath->length;
736 
737   while (segIdx < xPath->length) {
738 
739     ax0 = sx0;
740     ay0 = sy0;
741     if (dist <= lineDashDist) {
742       ax1 = sx1;
743       ay1 = sy1;
744       lineDashDist -= dist;
745       dist = 0;
746       atSegEnd = gTrue;
747       atDashEnd = lineDashDist == 0 || (seg->flags & splashXPathLast);
748     } else {
749       ax1 = sx0 + (lineDashDist / dist) * (sx1 - sx0);
750       ay1 = sy0 + (lineDashDist / dist) * (sy1 - sy0);
751       sx0 = ax1;
752       sy0 = ay1;
753       dist -= lineDashDist;
754       lineDashDist = 0;
755       atSegEnd = gFalse;
756       atDashEnd = gTrue;
757     }
758 
759     if (lineDashOn) {
760       dPath->addSegment(ax0, ay0, ax1, ay1,
761 			atDashStart, atDashEnd,
762 			atDashStart, atDashEnd);
763       // end of closed subpath
764       if (atSegEnd &&
765 	  (seg->flags & splashXPathLast) &&
766 	  !(seg->flags & splashXPathEnd1)) {
767 	dPath->segs[subpathStart].flags &= ~splashXPathEnd0;
768 	dPath->segs[dPath->length - 1].flags &= ~splashXPathEnd1;
769       }
770     }
771 
772     if (atDashEnd) {
773       lineDashOn = !lineDashOn;
774       if (++lineDashIdx == state->lineDashLength) {
775 	lineDashIdx = 0;
776       }
777       lineDashDist = state->lineDash[lineDashIdx];
778       atDashStart = gTrue;
779     } else {
780       atDashStart = gFalse;
781     }
782     if (atSegEnd) {
783       if (++segIdx < xPath->length) {
784 	++seg;
785 	sx0 = seg->x0;
786 	sy0 = seg->y0;
787 	sx1 = seg->x1;
788 	sy1 = seg->y1;
789 	dist = splashDist(sx0, sy0, sx1, sy1);
790 	if (seg->flags & splashXPathFirst) {
791 	  lineDashOn = lineDashStartOn;
792 	  lineDashIdx = lineDashStartIdx;
793 	  lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase;
794 	  atDashStart = gTrue;
795 	  subpathStart = dPath->length;
796 	}
797       }
798       atSegStart = gTrue;
799     } else {
800       atSegStart = gFalse;
801     }
802   }
803 
804   return dPath;
805 }
806 
fill(SplashPath * path,GBool eo)807 SplashError Splash::fill(SplashPath *path, GBool eo) {
808   if (debugMode) {
809     printf("fill [eo:%d]:\n", eo);
810     dumpPath(path);
811   }
812   return fillWithPattern(path, eo, state->fillPattern, state->fillAlpha);
813 }
814 
fillWithPattern(SplashPath * path,GBool eo,SplashPattern * pattern,SplashCoord alpha)815 SplashError Splash::fillWithPattern(SplashPath *path, GBool eo,
816 				    SplashPattern *pattern,
817 				    SplashCoord alpha) {
818   SplashXPath *xPath;
819   SplashXPathScanner *scanner;
820   int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
821   SplashClipResult clipRes, clipRes2;
822 
823   if (path->length == 0) {
824     return splashErrEmptyPath;
825   }
826   xPath = new SplashXPath(path, state->flatness, gTrue);
827   xPath->sort();
828   scanner = new SplashXPathScanner(xPath, eo);
829 
830   // get the min and max x and y values
831   scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI);
832 
833   // check clipping
834   if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI))
835       != splashClipAllOutside) {
836 
837     // limit the y range
838     if (yMinI < state->clip->getYMin()) {
839       yMinI = state->clip->getYMin();
840     }
841     if (yMaxI > state->clip->getYMax()) {
842       yMaxI = state->clip->getYMax();
843     }
844 
845     // draw the spans
846     for (y = yMinI; y <= yMaxI; ++y) {
847       while (scanner->getNextSpan(y, &x0, &x1)) {
848 	if (clipRes == splashClipAllInside) {
849 	  drawSpan(x0, x1, y, pattern, alpha, gTrue);
850 	} else {
851 	  // limit the x range
852 	  if (x0 < state->clip->getXMin()) {
853 	    x0 = state->clip->getXMin();
854 	  }
855 	  if (x1 > state->clip->getXMax()) {
856 	    x1 = state->clip->getXMax();
857 	  }
858 	  clipRes2 = state->clip->testSpan(x0, x1, y);
859 	  drawSpan(x0, x1, y, pattern, alpha, clipRes2 == splashClipAllInside);
860 	}
861       }
862     }
863   }
864   opClipRes = clipRes;
865 
866   delete scanner;
867   delete xPath;
868   return splashOk;
869 }
870 
xorFill(SplashPath * path,GBool eo)871 SplashError Splash::xorFill(SplashPath *path, GBool eo) {
872   SplashXPath *xPath;
873   SplashXPathScanner *scanner;
874   int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
875   SplashClipResult clipRes, clipRes2;
876 
877   if (path->length == 0) {
878     return splashErrEmptyPath;
879   }
880   xPath = new SplashXPath(path, state->flatness, gTrue);
881   xPath->sort();
882   scanner = new SplashXPathScanner(xPath, eo);
883 
884   // get the min and max x and y values
885   scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI);
886 
887   // check clipping
888   if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI))
889       != splashClipAllOutside) {
890 
891     // limit the y range
892     if (yMinI < state->clip->getYMin()) {
893       yMinI = state->clip->getYMin();
894     }
895     if (yMaxI > state->clip->getYMax()) {
896       yMaxI = state->clip->getYMax();
897     }
898 
899     // draw the spans
900     for (y = yMinI; y <= yMaxI; ++y) {
901       while (scanner->getNextSpan(y, &x0, &x1)) {
902 	if (clipRes == splashClipAllInside) {
903 	  xorSpan(x0, x1, y, state->fillPattern, gTrue);
904 	} else {
905 	  // limit the x range
906 	  if (x0 < state->clip->getXMin()) {
907 	    x0 = state->clip->getXMin();
908 	  }
909 	  if (x1 > state->clip->getXMax()) {
910 	    x1 = state->clip->getXMax();
911 	  }
912 	  clipRes2 = state->clip->testSpan(x0, x1, y);
913 	  xorSpan(x0, x1, y, state->fillPattern,
914 		  clipRes2 == splashClipAllInside);
915 	}
916       }
917     }
918   }
919   opClipRes = clipRes;
920 
921   delete scanner;
922   delete xPath;
923   return splashOk;
924 }
925 
drawPixel(int x,int y,SplashColorPtr color,SplashCoord alpha,GBool noClip)926 void Splash::drawPixel(int x, int y, SplashColorPtr color,
927 		       SplashCoord alpha, GBool noClip) {
928   SplashBlendFunc blendFunc;
929   SplashColorPtr p;
930   SplashColor dest, blend;
931   int alpha2, ialpha2;
932   Guchar t;
933 
934   if (noClip || state->clip->test(x, y)) {
935     if (alpha != 1 || softMask || state->blendFunc) {
936       blendFunc = state->blendFunc ? state->blendFunc : &blendNormal;
937       if (softMask) {
938 	alpha2 = (int)(alpha * softMask->data[y * softMask->rowSize + x]);
939       } else {
940 	alpha2 = (int)(alpha * 255);
941       }
942       ialpha2 = 255 - alpha2;
943       switch (bitmap->mode) {
944       case splashModeMono1:
945 	p = &bitmap->data[y * bitmap->rowSize + (x >> 3)];
946 	dest[0] = (*p >> (7 - (x & 7))) & 1;
947 	(*blendFunc)(color, dest, blend, bitmap->mode);
948 	t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8;
949 	if (t) {
950 	  *p |= 0x80 >> (x & 7);
951 	} else {
952 	  *p &= ~(0x80 >> (x & 7));
953 	}
954 	break;
955       case splashModeMono8:
956 	p = &bitmap->data[y * bitmap->rowSize + x];
957 	(*blendFunc)(color, p, blend, bitmap->mode);
958 	// note: floor(x / 255) = x >> 8 (for 16-bit x)
959 	p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
960 	break;
961       case splashModeAMono8:
962 	p = &bitmap->data[y * bitmap->rowSize + 2 * x];
963 	(*blendFunc)(color, p, blend, bitmap->mode);
964 	p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
965 	p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
966 	break;
967       case splashModeRGB8:
968       case splashModeBGR8:
969 	p = &bitmap->data[y * bitmap->rowSize + 3 * x];
970 	(*blendFunc)(color, p, blend, bitmap->mode);
971 	p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
972 	p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
973 	p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
974 	break;
975       case splashModeARGB8:
976       case splashModeBGRA8:
977 #if SPLASH_CMYK
978       case splashModeCMYK8:
979 #endif
980 	p = &bitmap->data[y * bitmap->rowSize + 4 * x];
981 	(*blendFunc)(color, p, blend, bitmap->mode);
982 	p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
983 	p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
984 	p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
985 	p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
986 	break;
987 #if SPLASH_CMYK
988       case splashModeACMYK8:
989 	p = &bitmap->data[y * bitmap->rowSize + 5 * x];
990 	(*blendFunc)(color, p, blend, bitmap->mode);
991 	p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
992 	p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
993 	p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
994 	p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
995 	p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8;
996 	break;
997 #endif
998       }
999     } else {
1000       switch (bitmap->mode) {
1001       case splashModeMono1:
1002 	p = &bitmap->data[y * bitmap->rowSize + (x >> 3)];
1003 	if (color[0]) {
1004 	  *p |= 0x80 >> (x & 7);
1005 	} else {
1006 	  *p &= ~(0x80 >> (x & 7));
1007 	}
1008 	break;
1009       case splashModeMono8:
1010 	p = &bitmap->data[y * bitmap->rowSize + x];
1011 	p[0] = color[0];
1012 	break;
1013       case splashModeAMono8:
1014 	p = &bitmap->data[y * bitmap->rowSize + 2 * x];
1015 	p[0] = color[0];
1016 	p[1] = color[1];
1017 	break;
1018       case splashModeRGB8:
1019       case splashModeBGR8:
1020 	p = &bitmap->data[y * bitmap->rowSize + 3 * x];
1021 	p[0] = color[0];
1022 	p[1] = color[1];
1023 	p[2] = color[2];
1024 	break;
1025       case splashModeARGB8:
1026       case splashModeBGRA8:
1027 #if SPLASH_CMYK
1028       case splashModeCMYK8:
1029 #endif
1030 	p = &bitmap->data[y * bitmap->rowSize + 4 * x];
1031 	p[0] = color[0];
1032 	p[1] = color[1];
1033 	p[2] = color[2];
1034 	p[3] = color[3];
1035 	break;
1036 #if SPLASH_CMYK
1037       case splashModeACMYK8:
1038 	p = &bitmap->data[y * bitmap->rowSize + 5 * x];
1039 	p[0] = color[0];
1040 	p[1] = color[1];
1041 	p[2] = color[2];
1042 	p[3] = color[3];
1043 	p[4] = color[4];
1044 	break;
1045 #endif
1046       }
1047     }
1048     updateModX(x);
1049     updateModY(y);
1050   }
1051 }
1052 
drawPixel(int x,int y,SplashPattern * pattern,SplashCoord alpha,GBool noClip)1053 void Splash::drawPixel(int x, int y, SplashPattern *pattern,
1054 		       SplashCoord alpha, GBool noClip) {
1055   SplashBlendFunc blendFunc;
1056   SplashColor color;
1057   SplashColorPtr p;
1058   SplashColor dest, blend;
1059   int alpha2, ialpha2;
1060   Guchar t;
1061 
1062   if (noClip || state->clip->test(x, y)) {
1063     if (alpha != 1 || softMask || state->blendFunc) {
1064       blendFunc = state->blendFunc ? state->blendFunc : &blendNormal;
1065       pattern->getColor(x, y, color);
1066       if (softMask) {
1067 	alpha2 = (int)(alpha * softMask->data[y * softMask->rowSize + x]);
1068       } else {
1069 	alpha2 = (int)(alpha * 255);
1070       }
1071       ialpha2 = 255 - alpha2;
1072       switch (bitmap->mode) {
1073       case splashModeMono1:
1074 	p = &bitmap->data[y * bitmap->rowSize + (x >> 3)];
1075 	dest[0] = (*p >> (7 - (x & 7))) & 1;
1076 	(*blendFunc)(color, dest, blend, bitmap->mode);
1077 	t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8;
1078 	if (t) {
1079 	  *p |= 0x80 >> (x & 7);
1080 	} else {
1081 	  *p &= ~(0x80 >> (x & 7));
1082 	}
1083 	break;
1084       case splashModeMono8:
1085 	p = &bitmap->data[y * bitmap->rowSize + x];
1086 	(*blendFunc)(color, p, blend, bitmap->mode);
1087 	// note: floor(x / 255) = x >> 8 (for 16-bit x)
1088 	p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1089 	break;
1090       case splashModeAMono8:
1091 	p = &bitmap->data[y * bitmap->rowSize + 2 * x];
1092 	(*blendFunc)(color, p, blend, bitmap->mode);
1093 	p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1094 	p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1095 	break;
1096       case splashModeRGB8:
1097       case splashModeBGR8:
1098 	p = &bitmap->data[y * bitmap->rowSize + 3 * x];
1099 	(*blendFunc)(color, p, blend, bitmap->mode);
1100 	p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1101 	p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1102 	p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
1103 	break;
1104       case splashModeARGB8:
1105       case splashModeBGRA8:
1106 #if SPLASH_CMYK
1107       case splashModeCMYK8:
1108 #endif
1109 	p = &bitmap->data[y * bitmap->rowSize + 4 * x];
1110 	(*blendFunc)(color, p, blend, bitmap->mode);
1111 	p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1112 	p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1113 	p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
1114 	p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
1115 	break;
1116 #if SPLASH_CMYK
1117       case splashModeACMYK8:
1118 	p = &bitmap->data[y * bitmap->rowSize + 5 * x];
1119 	(*blendFunc)(color, p, blend, bitmap->mode);
1120 	p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1121 	p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1122 	p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
1123 	p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
1124 	p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8;
1125 	break;
1126 #endif
1127       }
1128     } else {
1129       pattern->getColor(x, y, color);
1130       switch (bitmap->mode) {
1131       case splashModeMono1:
1132 	p = &bitmap->data[y * bitmap->rowSize + (x >> 3)];
1133 	if (color[0]) {
1134 	  *p |= 0x80 >> (x & 7);
1135 	} else {
1136 	  *p &= ~(0x80 >> (x & 7));
1137 	}
1138 	break;
1139       case splashModeMono8:
1140 	p = &bitmap->data[y * bitmap->rowSize + x];
1141 	p[0] = color[0];
1142 	break;
1143       case splashModeAMono8:
1144 	p = &bitmap->data[y * bitmap->rowSize + 2 * x];
1145 	p[0] = color[0];
1146 	p[1] = color[1];
1147 	break;
1148       case splashModeRGB8:
1149       case splashModeBGR8:
1150 	p = &bitmap->data[y * bitmap->rowSize + 3 * x];
1151 	p[0] = color[0];
1152 	p[1] = color[1];
1153 	p[2] = color[2];
1154 	break;
1155       case splashModeARGB8:
1156       case splashModeBGRA8:
1157 #if SPLASH_CMYK
1158       case splashModeCMYK8:
1159 #endif
1160 	p = &bitmap->data[y * bitmap->rowSize + 4 * x];
1161 	p[0] = color[0];
1162 	p[1] = color[1];
1163 	p[2] = color[2];
1164 	p[3] = color[3];
1165 	break;
1166 #if SPLASH_CMYK
1167       case splashModeACMYK8:
1168 	p = &bitmap->data[y * bitmap->rowSize + 5 * x];
1169 	p[0] = color[0];
1170 	p[1] = color[1];
1171 	p[2] = color[2];
1172 	p[3] = color[3];
1173 	p[4] = color[4];
1174 	break;
1175 #endif
1176       }
1177     }
1178     updateModX(x);
1179     updateModY(y);
1180   }
1181 }
1182 
drawSpan(int x0,int x1,int y,SplashPattern * pattern,SplashCoord alpha,GBool noClip)1183 void Splash::drawSpan(int x0, int x1, int y, SplashPattern *pattern,
1184 		      SplashCoord alpha, GBool noClip) {
1185   SplashBlendFunc blendFunc;
1186   SplashColor color;
1187   SplashColorPtr p;
1188   SplashColor dest, blend;
1189   Guchar mask, t;
1190   int alpha2, ialpha2;
1191   int i, j, n;
1192 
1193   n = x1 - x0 + 1;
1194 
1195   if (noClip) {
1196     updateModX(x0);
1197     updateModX(x1);
1198     updateModY(y);
1199   }
1200 
1201   if (alpha != 1 || softMask || state->blendFunc) {
1202     blendFunc = state->blendFunc ? state->blendFunc : &blendNormal;
1203     if (softMask) {
1204       alpha2 = ialpha2 = 0; // make gcc happy
1205     } else {
1206       alpha2 = (int)(alpha * 255);
1207       ialpha2 = 255 - alpha2;
1208     }
1209     switch (bitmap->mode) {
1210     case splashModeMono1:
1211       p = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
1212       i = 0;
1213       if (pattern->isStatic()) {
1214 	pattern->getColor(0, 0, color);
1215 	if ((j = x0 & 7)) {
1216 	  mask = 0x80 >> j;
1217 	  for (; j < 8 && i < n; ++i, ++j) {
1218 	    if (noClip || state->clip->test(x0 + i, y)) {
1219 	      if (softMask) {
1220 		alpha2 = (int)(alpha *
1221 			       softMask->data[y * softMask->rowSize + x0 + i]);
1222 		ialpha2 = 255 - alpha2;
1223 	      }
1224 	      dest[0] = (*p >> (7 - j)) & 1;
1225 	      (*blendFunc)(color, dest, blend, bitmap->mode);
1226 	      t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8;
1227 	      if (t) {
1228 		*p |= mask;
1229 	      } else {
1230 		*p &= ~mask;
1231 	      }
1232 	      if (!noClip) {
1233 		updateModX(x0 + i);
1234 		updateModY(y);
1235 	      }
1236 	    }
1237 	    mask >>= 1;
1238 	  }
1239 	  ++p;
1240 	}
1241 	while (i < n) {
1242 	  mask = 0x80;
1243 	  for (j = 0; j < 8 && i < n; ++i, ++j) {
1244 	    if (noClip || state->clip->test(x0 + i, y)) {
1245 	      if (softMask) {
1246 		alpha2 = (int)(alpha *
1247 			       softMask->data[y * softMask->rowSize + x0 + i]);
1248 		ialpha2 = 255 - alpha2;
1249 	      }
1250 	      dest[0] = (*p >> (7 - j)) & 1;
1251 	      (*blendFunc)(color, dest, blend, bitmap->mode);
1252 	      t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8;
1253 	      if (t) {
1254 		*p |= mask;
1255 	      } else {
1256 		*p &= ~mask;
1257 	      }
1258 	      if (!noClip) {
1259 		updateModX(x0 + i);
1260 		updateModY(y);
1261 	      }
1262 	    }
1263 	    mask >>= 1;
1264 	  }
1265 	  ++p;
1266 	}
1267       } else {
1268 	if ((j = x0 & 7)) {
1269 	  mask = 0x80 >> j;
1270 	  for (; j < 8 && i < n; ++i, ++j) {
1271 	    if (noClip || state->clip->test(x0 + i, y)) {
1272 	      pattern->getColor(x0 + i, y, color);
1273 	      if (softMask) {
1274 		alpha2 = (int)(alpha *
1275 			       softMask->data[y * softMask->rowSize + x0 + i]);
1276 		ialpha2 = 255 - alpha2;
1277 	      }
1278 	      dest[0] = (*p >> (7 - j)) & 1;
1279 	      (*blendFunc)(color, dest, blend, bitmap->mode);
1280 	      t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8;
1281 	      if (t) {
1282 		*p |= mask;
1283 	      } else {
1284 		*p &= ~mask;
1285 	      }
1286 	      if (!noClip) {
1287 		updateModX(x0 + i);
1288 		updateModY(y);
1289 	      }
1290 	    }
1291 	    mask >>= 1;
1292 	  }
1293 	  ++p;
1294 	}
1295 	while (i < n) {
1296 	  mask = 0x80;
1297 	  for (j = 0; j < 8 && i < n; ++i, ++j) {
1298 	    if (noClip || state->clip->test(x0 + i, y)) {
1299 	      pattern->getColor(x0 + i, y, color);
1300 	      if (softMask) {
1301 		alpha2 = (int)(alpha *
1302 			       softMask->data[y * softMask->rowSize + x0 + i]);
1303 		ialpha2 = 255 - alpha2;
1304 	      }
1305 	      dest[0] = (*p >> (7 - j)) & 1;
1306 	      (*blendFunc)(color, dest, blend, bitmap->mode);
1307 	      t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8;
1308 	      if (t) {
1309 		*p |= mask;
1310 	      } else {
1311 		*p &= ~mask;
1312 	      }
1313 	      if (!noClip) {
1314 		updateModX(x0 + i);
1315 		updateModY(y);
1316 	      }
1317 	    }
1318 	    mask >>= 1;
1319 	  }
1320 	  ++p;
1321 	}
1322       }
1323       break;
1324 
1325     case splashModeMono8:
1326       p = &bitmap->data[y * bitmap->rowSize + x0];
1327       if (pattern->isStatic()) {
1328 	pattern->getColor(0, 0, color);
1329 	for (i = 0; i < n; ++i) {
1330 	  if (noClip || state->clip->test(x0 + i, y)) {
1331 	    if (softMask) {
1332 	      alpha2 = (int)(alpha *
1333 			     softMask->data[y * softMask->rowSize + x0 + i]);
1334 	      ialpha2 = 255 - alpha2;
1335 	    }
1336 	    (*blendFunc)(color, p, blend, bitmap->mode);
1337 	    *p = (alpha2 * blend[0] + ialpha2 * *p) >> 8;
1338 	    if (!noClip) {
1339 	      updateModX(x0 + i);
1340 	      updateModY(y);
1341 	    }
1342 	  }
1343 	  ++p;
1344 	}
1345       } else {
1346 	for (i = 0; i < n; ++i) {
1347 	  if (noClip || state->clip->test(x0 + i, y)) {
1348 	    pattern->getColor(x0 + i, y, color);
1349 	    if (softMask) {
1350 	      alpha2 = (int)(alpha *
1351 			     softMask->data[y * softMask->rowSize + x0 + i]);
1352 	      ialpha2 = 255 - alpha2;
1353 	    }
1354 	    (*blendFunc)(color, p, blend, bitmap->mode);
1355 	    *p = (alpha2 * blend[0] + ialpha2 * *p) >> 8;
1356 	    if (!noClip) {
1357 	      updateModX(x0 + i);
1358 	      updateModY(y);
1359 	    }
1360 	  }
1361 	  ++p;
1362 	}
1363       }
1364       break;
1365 
1366     case splashModeAMono8:
1367       p = &bitmap->data[y * bitmap->rowSize + 2 * x0];
1368       if (pattern->isStatic()) {
1369 	pattern->getColor(0, 0, color);
1370 	for (i = 0; i < n; ++i) {
1371 	  if (noClip || state->clip->test(x0 + i, y)) {
1372 	    if (softMask) {
1373 	      alpha2 = (int)(alpha *
1374 			     softMask->data[y * softMask->rowSize + x0 + i]);
1375 	      ialpha2 = 255 - alpha2;
1376 	    }
1377 	    (*blendFunc)(color, p, blend, bitmap->mode);
1378 	    p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1379 	    p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1380 	    if (!noClip) {
1381 	      updateModX(x0 + i);
1382 	      updateModY(y);
1383 	    }
1384 	  }
1385 	  p += 2;
1386 	}
1387       } else {
1388 	for (i = 0; i < n; ++i) {
1389 	  if (noClip || state->clip->test(x0 + i, y)) {
1390 	    pattern->getColor(x0 + i, y, color);
1391 	    if (softMask) {
1392 	      alpha2 = (int)(alpha *
1393 			     softMask->data[y * softMask->rowSize + x0 + i]);
1394 	      ialpha2 = 255 - alpha2;
1395 	    }
1396 	    (*blendFunc)(color, p, blend, bitmap->mode);
1397 	    p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1398 	    p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1399 	    if (!noClip) {
1400 	      updateModX(x0 + i);
1401 	      updateModY(y);
1402 	    }
1403 	  }
1404 	  p += 2;
1405 	}
1406       }
1407       break;
1408 
1409     case splashModeRGB8:
1410     case splashModeBGR8:
1411       p = &bitmap->data[y * bitmap->rowSize + 3 * x0];
1412       if (pattern->isStatic()) {
1413 	pattern->getColor(0, 0, color);
1414 	for (i = 0; i < n; ++i) {
1415 	  if (noClip || state->clip->test(x0 + i, y)) {
1416 	    if (softMask) {
1417 	      alpha2 = (int)(alpha *
1418 			     softMask->data[y * softMask->rowSize + x0 + i]);
1419 	      ialpha2 = 255 - alpha2;
1420 	    }
1421 	    (*blendFunc)(color, p, blend, bitmap->mode);
1422 	    p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1423 	    p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1424 	    p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
1425 	    if (!noClip) {
1426 	      updateModX(x0 + i);
1427 	      updateModY(y);
1428 	    }
1429 	  }
1430 	  p += 3;
1431 	}
1432       } else {
1433 	for (i = 0; i < n; ++i) {
1434 	  if (noClip || state->clip->test(x0 + i, y)) {
1435 	    pattern->getColor(x0 + i, y, color);
1436 	    if (softMask) {
1437 	      alpha2 = (int)(alpha *
1438 			     softMask->data[y * softMask->rowSize + x0 + i]);
1439 	      ialpha2 = 255 - alpha2;
1440 	    }
1441 	    (*blendFunc)(color, p, blend, bitmap->mode);
1442 	    p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1443 	    p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1444 	    p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
1445 	    if (!noClip) {
1446 	      updateModX(x0 + i);
1447 	      updateModY(y);
1448 	    }
1449 	  }
1450 	  p += 3;
1451 	}
1452       }
1453       break;
1454 
1455     case splashModeARGB8:
1456     case splashModeBGRA8:
1457 #if SPLASH_CMYK
1458     case splashModeCMYK8:
1459 #endif
1460       p = &bitmap->data[y * bitmap->rowSize + 4 * x0];
1461       if (pattern->isStatic()) {
1462 	pattern->getColor(0, 0, color);
1463 	for (i = 0; i < n; ++i) {
1464 	  if (noClip || state->clip->test(x0 + i, y)) {
1465 	    if (softMask) {
1466 	      alpha2 = (int)(alpha *
1467 			     softMask->data[y * softMask->rowSize + x0 + i]);
1468 	      ialpha2 = 255 - alpha2;
1469 	    }
1470 	    (*blendFunc)(color, p, blend, bitmap->mode);
1471 	    p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1472 	    p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1473 	    p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
1474 	    p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
1475 	    if (!noClip) {
1476 	      updateModX(x0 + i);
1477 	      updateModY(y);
1478 	    }
1479 	  }
1480 	  p += 4;
1481 	}
1482       } else {
1483 	for (i = 0; i < n; ++i) {
1484 	  if (noClip || state->clip->test(x0 + i, y)) {
1485 	    pattern->getColor(x0 + i, y, color);
1486 	    if (softMask) {
1487 	      alpha2 = (int)(alpha *
1488 			     softMask->data[y * softMask->rowSize + x0 + i]);
1489 	      ialpha2 = 255 - alpha2;
1490 	    }
1491 	    (*blendFunc)(color, p, blend, bitmap->mode);
1492 	    p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1493 	    p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1494 	    p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
1495 	    p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
1496 	    if (!noClip) {
1497 	      updateModX(x0 + i);
1498 	      updateModY(y);
1499 	    }
1500 	  }
1501 	  p += 4;
1502 	}
1503       }
1504       break;
1505 #if SPLASH_CMYK
1506     case splashModeACMYK8:
1507       p = &bitmap->data[y * bitmap->rowSize + 5 * x0];
1508       if (pattern->isStatic()) {
1509 	pattern->getColor(0, 0, color);
1510 	for (i = 0; i < n; ++i) {
1511 	  if (noClip || state->clip->test(x0 + i, y)) {
1512 	    if (softMask) {
1513 	      alpha2 = (int)(alpha *
1514 			     softMask->data[y * softMask->rowSize + x0 + i]);
1515 	      ialpha2 = 255 - alpha2;
1516 	    }
1517 	    (*blendFunc)(color, p, blend, bitmap->mode);
1518 	    p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1519 	    p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1520 	    p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
1521 	    p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
1522 	    p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8;
1523 	    if (!noClip) {
1524 	      updateModX(x0 + i);
1525 	      updateModY(y);
1526 	    }
1527 	  }
1528 	  p += 4;
1529 	}
1530       } else {
1531 	for (i = 0; i < n; ++i) {
1532 	  if (noClip || state->clip->test(x0 + i, y)) {
1533 	    pattern->getColor(x0 + i, y, color);
1534 	    if (softMask) {
1535 	      alpha2 = (int)(alpha *
1536 			     softMask->data[y * softMask->rowSize + x0 + i]);
1537 	      ialpha2 = 255 - alpha2;
1538 	    }
1539 	    (*blendFunc)(color, p, blend, bitmap->mode);
1540 	    p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
1541 	    p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
1542 	    p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
1543 	    p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
1544 	    p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8;
1545 	    if (!noClip) {
1546 	      updateModX(x0 + i);
1547 	      updateModY(y);
1548 	    }
1549 	  }
1550 	  p += 4;
1551 	}
1552       }
1553       break;
1554 #endif
1555     }
1556 
1557   } else {
1558     switch (bitmap->mode) {
1559     case splashModeMono1:
1560       p = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
1561       i = 0;
1562       if (pattern->isStatic()) {
1563 	pattern->getColor(0, 0, color);
1564 	if ((j = x0 & 7)) {
1565 	  mask = 0x80 >> j;
1566 	  for (; j < 8 && i < n; ++i, ++j) {
1567 	    if (noClip || state->clip->test(x0 + i, y)) {
1568 	      if (color[0]) {
1569 		*p |= mask;
1570 	      } else {
1571 		*p &= ~mask;
1572 	      }
1573 	      if (!noClip) {
1574 		updateModX(x0 + i);
1575 		updateModY(y);
1576 	      }
1577 	    }
1578 	    mask >>= 1;
1579 	  }
1580 	  ++p;
1581 	}
1582 	while (i < n) {
1583 	  mask = 0x80;
1584 	  for (j = 0; j < 8 && i < n; ++i, ++j) {
1585 	    if (noClip || state->clip->test(x0 + i, y)) {
1586 	      if (color[0]) {
1587 		*p |= mask;
1588 	      } else {
1589 		*p &= ~mask;
1590 	      }
1591 	      if (!noClip) {
1592 		updateModX(x0 + i);
1593 		updateModY(y);
1594 	      }
1595 	    }
1596 	    mask >>= 1;
1597 	  }
1598 	  ++p;
1599 	}
1600       } else {
1601 	if ((j = x0 & 7)) {
1602 	  mask = 0x80 >> j;
1603 	  for (; j < 8 && i < n; ++i, ++j) {
1604 	    if (noClip || state->clip->test(x0 + i, y)) {
1605 	      pattern->getColor(x0 + i, y, color);
1606 	      if (color[0]) {
1607 		*p |= mask;
1608 	      } else {
1609 		*p &= ~mask;
1610 	      }
1611 	      if (!noClip) {
1612 		updateModX(x0 + i);
1613 		updateModY(y);
1614 	      }
1615 	    }
1616 	    mask >>= 1;
1617 	  }
1618 	  ++p;
1619 	}
1620 	while (i < n) {
1621 	  mask = 0x80;
1622 	  for (j = 0; j < 8 && i < n; ++i, ++j) {
1623 	    if (noClip || state->clip->test(x0 + i, y)) {
1624 	      pattern->getColor(x0 + i, y, color);
1625 	      if (color[0]) {
1626 		*p |= mask;
1627 	      } else {
1628 		*p &= ~mask;
1629 	      }
1630 	      if (!noClip) {
1631 		updateModX(x0 + i);
1632 		updateModY(y);
1633 	      }
1634 	    }
1635 	    mask >>= 1;
1636 	  }
1637 	  ++p;
1638 	}
1639       }
1640       break;
1641 
1642     case splashModeMono8:
1643       p = &bitmap->data[y * bitmap->rowSize + x0];
1644       if (pattern->isStatic()) {
1645 	pattern->getColor(0, 0, color);
1646 	for (i = 0; i < n; ++i) {
1647 	  if (noClip || state->clip->test(x0 + i, y)) {
1648 	    *p = color[0];
1649 	    if (!noClip) {
1650 	      updateModX(x0 + i);
1651 	      updateModY(y);
1652 	    }
1653 	  }
1654 	  ++p;
1655 	}
1656       } else {
1657 	for (i = 0; i < n; ++i) {
1658 	  if (noClip || state->clip->test(x0 + i, y)) {
1659 	    pattern->getColor(x0 + i, y, color);
1660 	    *p = color[0];
1661 	    if (!noClip) {
1662 	      updateModX(x0 + i);
1663 	      updateModY(y);
1664 	    }
1665 	  }
1666 	  ++p;
1667 	}
1668       }
1669       break;
1670 
1671     case splashModeAMono8:
1672       p = &bitmap->data[y * bitmap->rowSize + 2 * x0];
1673       if (pattern->isStatic()) {
1674 	pattern->getColor(0, 0, color);
1675 	for (i = 0; i < n; ++i) {
1676 	  if (noClip || state->clip->test(x0 + i, y)) {
1677 	    p[0] = color[0];
1678 	    p[1] = color[1];
1679 	    if (!noClip) {
1680 	      updateModX(x0 + i);
1681 	      updateModY(y);
1682 	    }
1683 	  }
1684 	  p += 2;
1685 	}
1686       } else {
1687 	for (i = 0; i < n; ++i) {
1688 	  if (noClip || state->clip->test(x0 + i, y)) {
1689 	    pattern->getColor(x0 + i, y, color);
1690 	    p[0] = color[0];
1691 	    p[1] = color[1];
1692 	    if (!noClip) {
1693 	      updateModX(x0 + i);
1694 	      updateModY(y);
1695 	    }
1696 	  }
1697 	  p += 2;
1698 	}
1699       }
1700       break;
1701 
1702     case splashModeRGB8:
1703     case splashModeBGR8:
1704       p = &bitmap->data[y * bitmap->rowSize + 3 * x0];
1705       if (pattern->isStatic()) {
1706 	pattern->getColor(0, 0, color);
1707 	for (i = 0; i < n; ++i) {
1708 	  if (noClip || state->clip->test(x0 + i, y)) {
1709 	    p[0] = color[0];
1710 	    p[1] = color[1];
1711 	    p[2] = color[2];
1712 	    if (!noClip) {
1713 	      updateModX(x0 + i);
1714 	      updateModY(y);
1715 	    }
1716 	  }
1717 	  p += 3;
1718 	}
1719       } else {
1720 	for (i = 0; i < n; ++i) {
1721 	  if (noClip || state->clip->test(x0 + i, y)) {
1722 	    pattern->getColor(x0 + i, y, color);
1723 	    p[0] = color[0];
1724 	    p[1] = color[1];
1725 	    p[2] = color[2];
1726 	    if (!noClip) {
1727 	      updateModX(x0 + i);
1728 	      updateModY(y);
1729 	    }
1730 	  }
1731 	  p += 3;
1732 	}
1733       }
1734       break;
1735 
1736     case splashModeARGB8:
1737     case splashModeBGRA8:
1738 #if SPLASH_CMYK
1739     case splashModeCMYK8:
1740 #endif
1741       p = &bitmap->data[y * bitmap->rowSize + 4 * x0];
1742       if (pattern->isStatic()) {
1743 	pattern->getColor(0, 0, color);
1744 	for (i = 0; i < n; ++i) {
1745 	  if (noClip || state->clip->test(x0 + i, y)) {
1746 	    p[0] = color[0];
1747 	    p[1] = color[1];
1748 	    p[2] = color[2];
1749 	    p[3] = color[3];
1750 	    if (!noClip) {
1751 	      updateModX(x0 + i);
1752 	      updateModY(y);
1753 	    }
1754 	  }
1755 	  p += 4;
1756 	}
1757       } else {
1758 	for (i = 0; i < n; ++i) {
1759 	  if (noClip || state->clip->test(x0 + i, y)) {
1760 	    pattern->getColor(x0 + i, y, color);
1761 	    p[0] = color[0];
1762 	    p[1] = color[1];
1763 	    p[2] = color[2];
1764 	    p[3] = color[3];
1765 	    if (!noClip) {
1766 	      updateModX(x0 + i);
1767 	      updateModY(y);
1768 	    }
1769 	  }
1770 	  p += 4;
1771 	}
1772       }
1773       break;
1774 #if SPLASH_CMYK
1775     case splashModeACMYK8:
1776       p = &bitmap->data[y * bitmap->rowSize + 5 * x0];
1777       if (pattern->isStatic()) {
1778 	pattern->getColor(0, 0, color);
1779 	for (i = 0; i < n; ++i) {
1780 	  if (noClip || state->clip->test(x0 + i, y)) {
1781 	    p[0] = color[0];
1782 	    p[1] = color[1];
1783 	    p[2] = color[2];
1784 	    p[3] = color[3];
1785 	    p[4] = color[4];
1786 	    if (!noClip) {
1787 	      updateModX(x0 + i);
1788 	      updateModY(y);
1789 	    }
1790 	  }
1791 	  p += 4;
1792 	}
1793       } else {
1794 	for (i = 0; i < n; ++i) {
1795 	  if (noClip || state->clip->test(x0 + i, y)) {
1796 	    pattern->getColor(x0 + i, y, color);
1797 	    p[0] = color[0];
1798 	    p[1] = color[1];
1799 	    p[2] = color[2];
1800 	    p[3] = color[3];
1801 	    p[4] = color[4];
1802 	    if (!noClip) {
1803 	      updateModX(x0 + i);
1804 	      updateModY(y);
1805 	    }
1806 	  }
1807 	  p += 4;
1808 	}
1809       }
1810       break;
1811 #endif
1812     }
1813   }
1814 }
1815 
xorSpan(int x0,int x1,int y,SplashPattern * pattern,GBool noClip)1816 void Splash::xorSpan(int x0, int x1, int y, SplashPattern *pattern,
1817 		     GBool noClip) {
1818   SplashColor color;
1819   SplashColorPtr p;
1820   Guchar mask;
1821   int i, j, n;
1822 
1823   n = x1 - x0 + 1;
1824 
1825   if (noClip) {
1826     updateModX(x0);
1827     updateModX(x1);
1828     updateModY(y);
1829   }
1830 
1831   switch (bitmap->mode) {
1832   case splashModeMono1:
1833     p = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
1834     i = 0;
1835     if ((j = x0 & 7)) {
1836       mask = 0x80 >> j;
1837       for (; j < 8 && i < n; ++i, ++j) {
1838 	if (noClip || state->clip->test(x0 + i, y)) {
1839 	  pattern->getColor(x0 + i, y, color);
1840 	  if (color[0]) {
1841 	    *p ^= mask;
1842 	  }
1843 	  if (!noClip) {
1844 	    updateModX(x0 + i);
1845 	    updateModY(y);
1846 	  }
1847 	}
1848 	mask >>= 1;
1849       }
1850       ++p;
1851     }
1852     while (i < n) {
1853       mask = 0x80;
1854       for (j = 0; j < 8 && i < n; ++i, ++j) {
1855 	if (noClip || state->clip->test(x0 + i, y)) {
1856 	  pattern->getColor(x0 + i, y, color);
1857 	  if (color[0]) {
1858 	    *p ^= mask;
1859 	  }
1860 	  if (!noClip) {
1861 	    updateModX(x0 + i);
1862 	    updateModY(y);
1863 	  }
1864 	}
1865 	mask >>= 1;
1866       }
1867       ++p;
1868     }
1869     break;
1870 
1871   case splashModeMono8:
1872     p = &bitmap->data[y * bitmap->rowSize + x0];
1873     for (i = 0; i < n; ++i) {
1874       if (noClip || state->clip->test(x0 + i, y)) {
1875 	pattern->getColor(x0 + i, y, color);
1876 	*p ^= color[0];
1877 	if (!noClip) {
1878 	  updateModX(x0 + i);
1879 	  updateModY(y);
1880 	}
1881       }
1882       ++p;
1883     }
1884     break;
1885 
1886   case splashModeAMono8:
1887     p = &bitmap->data[y * bitmap->rowSize + 2 * x0];
1888     for (i = 0; i < n; ++i) {
1889       if (noClip || state->clip->test(x0 + i, y)) {
1890 	pattern->getColor(x0 + i, y, color);
1891 	p[0] ^= color[0];
1892 	p[1] ^= color[1];
1893 	if (!noClip) {
1894 	  updateModX(x0 + i);
1895 	  updateModY(y);
1896 	}
1897       }
1898       p += 2;
1899     }
1900     break;
1901 
1902   case splashModeRGB8:
1903   case splashModeBGR8:
1904     p = &bitmap->data[y * bitmap->rowSize + 3 * x0];
1905     for (i = 0; i < n; ++i) {
1906       if (noClip || state->clip->test(x0 + i, y)) {
1907 	pattern->getColor(x0 + i, y, color);
1908 	p[0] ^= color[0];
1909 	p[1] ^= color[1];
1910 	p[2] ^= color[2];
1911 	if (!noClip) {
1912 	  updateModX(x0 + i);
1913 	  updateModY(y);
1914 	}
1915       }
1916       p += 3;
1917     }
1918     break;
1919 
1920   case splashModeARGB8:
1921   case splashModeBGRA8:
1922 #if SPLASH_CMYK
1923   case splashModeCMYK8:
1924 #endif
1925     p = &bitmap->data[y * bitmap->rowSize + 4 * x0];
1926     for (i = 0; i < n; ++i) {
1927       if (noClip || state->clip->test(x0 + i, y)) {
1928 	pattern->getColor(x0 + i, y, color);
1929 	p[0] ^= color[0];
1930 	p[1] ^= color[1];
1931 	p[2] ^= color[2];
1932 	p[3] ^= color[3];
1933 	if (!noClip) {
1934 	  updateModX(x0 + i);
1935 	  updateModY(y);
1936 	}
1937       }
1938       p += 4;
1939     }
1940     break;
1941 #if SPLASH_CMYK
1942   case splashModeACMYK8:
1943     p = &bitmap->data[y * bitmap->rowSize + 5 * x0];
1944     for (i = 0; i < n; ++i) {
1945       if (noClip || state->clip->test(x0 + i, y)) {
1946 	pattern->getColor(x0 + i, y, color);
1947 	p[0] ^= color[0];
1948 	p[1] ^= color[1];
1949 	p[2] ^= color[2];
1950 	p[3] ^= color[3];
1951 	p[4] ^= color[4];
1952 	if (!noClip) {
1953 	  updateModX(x0 + i);
1954 	  updateModY(y);
1955 	}
1956       }
1957       p += 4;
1958     }
1959     break;
1960 #endif
1961   }
1962 }
1963 
fillChar(SplashCoord x,SplashCoord y,int c,SplashFont * font)1964 SplashError Splash::fillChar(SplashCoord x, SplashCoord y,
1965 			     int c, SplashFont *font) {
1966   SplashGlyphBitmap glyph;
1967   int x0, y0, xFrac, yFrac;
1968   SplashError err;
1969 
1970   if (debugMode) {
1971     printf("fillChar: x=%.2f y=%.2f c=%3d=0x%02x='%c'\n",
1972 	   (double)x, (double)y, c, c, c);
1973   }
1974   x0 = splashFloor(x);
1975   xFrac = splashFloor((x - x0) * splashFontFraction);
1976   y0 = splashFloor(y);
1977   yFrac = splashFloor((y - y0) * splashFontFraction);
1978   if (!font->getGlyph(c, xFrac, yFrac, &glyph)) {
1979     return splashErrNoGlyph;
1980   }
1981   err = fillGlyph(x, y, &glyph);
1982   if (glyph.freeData) {
1983     gfree(glyph.data);
1984   }
1985   return err;
1986 }
1987 
fillGlyph(SplashCoord x,SplashCoord y,SplashGlyphBitmap * glyph)1988 SplashError Splash::fillGlyph(SplashCoord x, SplashCoord y,
1989 			      SplashGlyphBitmap *glyph) {
1990   SplashBlendFunc blendFunc;
1991   int alpha0, alpha, ialpha;
1992   Guchar *p;
1993   SplashColor fg, dest, blend;
1994   SplashColorPtr pix;
1995   SplashClipResult clipRes;
1996   GBool noClip;
1997   Guchar t;
1998   int x0, y0, x1, y1, xx, xx1, yy;
1999 
2000   x0 = splashFloor(x);
2001   y0 = splashFloor(y);
2002 
2003   if ((clipRes = state->clip->testRect(x0 - glyph->x,
2004 				       y0 - glyph->y,
2005 				       x0 - glyph->x + glyph->w - 1,
2006 				       y0 - glyph->y + glyph->h - 1))
2007       != splashClipAllOutside) {
2008     noClip = clipRes == splashClipAllInside;
2009 
2010     if (noClip) {
2011       updateModX(x0 - glyph->x);
2012       updateModX(x0 - glyph->x + glyph->w - 1);
2013       updateModY(y0 - glyph->y);
2014       updateModY(y0 - glyph->y + glyph->h - 1);
2015     }
2016 
2017     //~ optimize this
2018     if (state->fillAlpha != 1 || softMask || state->blendFunc) {
2019       blendFunc = state->blendFunc ? state->blendFunc : &blendNormal;
2020       if (glyph->aa) {
2021 	p = glyph->data;
2022 	for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
2023 	  for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; ++xx, ++x1) {
2024 	    alpha = *p++;
2025 	    if (softMask) {
2026 	      alpha = (int)(alpha * state->fillAlpha *
2027 			    softMask->data[y1 * softMask->rowSize + x1]);
2028 	    } else {
2029 	      alpha = (int)(alpha * state->fillAlpha);
2030 	    }
2031 	    if (alpha > 0) {
2032 	      if (noClip || state->clip->test(x1, y1)) {
2033 		ialpha = 255 - alpha;
2034 		state->fillPattern->getColor(x1, y1, fg);
2035 		switch (bitmap->mode) {
2036 		case splashModeMono1:
2037 		  pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)];
2038 		  dest[0] = (*pix >> (7 - (x1 & 7))) & 1;
2039 		  (*blendFunc)(fg, dest, blend, bitmap->mode);
2040 		  t = (alpha * blend[0] + ialpha * dest[0]) >> 8;
2041 		  if (t) {
2042 		    *pix |= 0x80 >> (x1 & 7);
2043 		  } else {
2044 		    *pix &= ~(0x80 >> (x1 & 7));
2045 		  }
2046 		  break;
2047 		case splashModeMono8:
2048 		  pix = &bitmap->data[y1 * bitmap->rowSize + x1];
2049 		  (*blendFunc)(fg, pix, blend, bitmap->mode);
2050 		  // note: floor(x / 255) = x >> 8 (for 16-bit x)
2051 		  pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
2052 		  break;
2053 		case splashModeAMono8:
2054 		  pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1];
2055 		  (*blendFunc)(fg, pix, blend, bitmap->mode);
2056 		  pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
2057 		  pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
2058 		  break;
2059 		case splashModeRGB8:
2060 		case splashModeBGR8:
2061 		  pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1];
2062 		  (*blendFunc)(fg, pix, blend, bitmap->mode);
2063 		  pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
2064 		  pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
2065 		  pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8;
2066 		  break;
2067 		case splashModeARGB8:
2068 		case splashModeBGRA8:
2069 #if SPLASH_CMYK
2070 		case splashModeCMYK8:
2071 #endif
2072 		  pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1];
2073 		  (*blendFunc)(fg, pix, blend, bitmap->mode);
2074 		  pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
2075 		  pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
2076 		  pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8;
2077 		  pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8;
2078 		  break;
2079 #if SPLASH_CMYK
2080 		case splashModeACMYK8:
2081 		  pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1];
2082 		  (*blendFunc)(fg, pix, blend, bitmap->mode);
2083 		  pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
2084 		  pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
2085 		  pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8;
2086 		  pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8;
2087 		  pix[4] = (alpha * blend[4] + ialpha * pix[4]) >> 8;
2088 		  break;
2089 #endif
2090 		}
2091 		if (!noClip) {
2092 		  updateModX(x1);
2093 		  updateModY(y1);
2094 		}
2095 	      }
2096 	    }
2097 	  }
2098 	}
2099 
2100       } else {
2101 	p = glyph->data;
2102 	for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
2103 	  for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; xx += 8) {
2104 	    alpha0 = *p++;
2105 	    for (xx1 = 0; xx1 < 8 && xx + xx1 < glyph->w; ++xx1, ++x1) {
2106 	      if (alpha0 & 0x80) {
2107 		if (noClip || state->clip->test(x1, y1)) {
2108 		  if (softMask) {
2109 		    alpha = (int)(state->fillAlpha *
2110 				  softMask->data[y1 * softMask->rowSize + x1]);
2111 		  } else {
2112 		    alpha = (int)(state->fillAlpha * 255);
2113 		  }
2114 		  ialpha = 255 - alpha;
2115 		  state->fillPattern->getColor(x1, y1, fg);
2116 		  switch (bitmap->mode) {
2117 		  case splashModeMono1:
2118 		    pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)];
2119 		    dest[0] = (*pix >> (7 - (x1 & 7))) & 1;
2120 		    (*blendFunc)(fg, dest, blend, bitmap->mode);
2121 		    t = (alpha * blend[0] + ialpha * dest[0]) >> 8;
2122 		    if (t) {
2123 		      *pix |= 0x80 >> (x1 & 7);
2124 		    } else {
2125 		      *pix &= ~(0x80 >> (x1 & 7));
2126 		    }
2127 		    break;
2128 		  case splashModeMono8:
2129 		    pix = &bitmap->data[y1 * bitmap->rowSize + x1];
2130 		    (*blendFunc)(fg, pix, blend, bitmap->mode);
2131 		    // note: floor(x / 255) = x >> 8 (for 16-bit x)
2132 		    pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
2133 		    break;
2134 		  case splashModeAMono8:
2135 		    pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1];
2136 		    (*blendFunc)(fg, pix, blend, bitmap->mode);
2137 		    pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
2138 		    pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
2139 		    break;
2140 		  case splashModeRGB8:
2141 		  case splashModeBGR8:
2142 		    pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1];
2143 		    (*blendFunc)(fg, pix, blend, bitmap->mode);
2144 		    pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
2145 		    pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
2146 		    pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8;
2147 		    break;
2148 		  case splashModeARGB8:
2149 		  case splashModeBGRA8:
2150 #if SPLASH_CMYK
2151 		  case splashModeCMYK8:
2152 #endif
2153 		    pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1];
2154 		    (*blendFunc)(fg, pix, blend, bitmap->mode);
2155 		    pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
2156 		    pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
2157 		    pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8;
2158 		    pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8;
2159 		    break;
2160 #if SPLASH_CMYK
2161 		  case splashModeACMYK8:
2162 		    pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1];
2163 		    (*blendFunc)(fg, pix, blend, bitmap->mode);
2164 		    pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
2165 		    pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
2166 		    pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8;
2167 		    pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8;
2168 		    pix[4] = (alpha * blend[4] + ialpha * pix[4]) >> 8;
2169 		    break;
2170 #endif
2171 		  }
2172 		  if (!noClip) {
2173 		    updateModX(x1);
2174 		    updateModY(y1);
2175 		  }
2176 		}
2177 	      }
2178 	      alpha0 <<= 1;
2179 	    }
2180 	  }
2181 	}
2182       }
2183 
2184     } else {
2185       if (glyph->aa) {
2186 	p = glyph->data;
2187 	for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
2188 	  for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; ++xx, ++x1) {
2189 	    alpha = *p++;
2190 	    if (alpha > 0) {
2191 	      if (noClip || state->clip->test(x1, y1)) {
2192 		ialpha = 255 - alpha;
2193 		state->fillPattern->getColor(x1, y1, fg);
2194 		switch (bitmap->mode) {
2195 		case splashModeMono1:
2196 		  if (alpha >= 0x80) {
2197 		    pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)];
2198 		    if (fg[0]) {
2199 		      *pix |= 0x80 >> (x1 & 7);
2200 		    } else {
2201 		      *pix &= ~(0x80 >> (x1 & 7));
2202 		    }
2203 		  }
2204 		  break;
2205 		case splashModeMono8:
2206 		  pix = &bitmap->data[y1 * bitmap->rowSize + x1];
2207 		  // note: floor(x / 255) = x >> 8 (for 16-bit x)
2208 		  pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8;
2209 		  break;
2210 		case splashModeAMono8:
2211 		  pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1];
2212 		  pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8;
2213 		  pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8;
2214 		  break;
2215 		case splashModeRGB8:
2216 		case splashModeBGR8:
2217 		  pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1];
2218 		  pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8;
2219 		  pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8;
2220 		  pix[2] = (alpha * fg[2] + ialpha * pix[2]) >> 8;
2221 		  break;
2222 		case splashModeARGB8:
2223 		case splashModeBGRA8:
2224 #if SPLASH_CMYK
2225 		case splashModeCMYK8:
2226 #endif
2227 		  pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1];
2228 		  pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8;
2229 		  pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8;
2230 		  pix[2] = (alpha * fg[2] + ialpha * pix[2]) >> 8;
2231 		  pix[3] = (alpha * fg[3] + ialpha * pix[3]) >> 8;
2232 		  break;
2233 #if SPLASH_CMYK
2234 		case splashModeACMYK8:
2235 		  pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1];
2236 		  pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8;
2237 		  pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8;
2238 		  pix[2] = (alpha * fg[2] + ialpha * pix[2]) >> 8;
2239 		  pix[3] = (alpha * fg[3] + ialpha * pix[3]) >> 8;
2240 		  pix[4] = (alpha * fg[4] + ialpha * pix[4]) >> 8;
2241 		  break;
2242 #endif
2243 		}
2244 		if (!noClip) {
2245 		  updateModX(x1);
2246 		  updateModY(y1);
2247 		}
2248 	      }
2249 	    }
2250 	  }
2251 	}
2252 
2253       } else {
2254 	p = glyph->data;
2255 	for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
2256 	  for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; xx += 8) {
2257 	    alpha0 = *p++;
2258 	    for (xx1 = 0; xx1 < 8 && xx + xx1 < glyph->w; ++xx1, ++x1) {
2259 	      if (alpha0 & 0x80) {
2260 		if (noClip || state->clip->test(x1, y1)) {
2261 		  state->fillPattern->getColor(x1, y1, fg);
2262 		  switch (bitmap->mode) {
2263 		  case splashModeMono1:
2264 		    pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)];
2265 		    if (fg[0]) {
2266 		      *pix |= 0x80 >> (x1 & 7);
2267 		    } else {
2268 		      *pix &= ~(0x80 >> (x1 & 7));
2269 		    }
2270 		    break;
2271 		  case splashModeMono8:
2272 		    pix = &bitmap->data[y1 * bitmap->rowSize + x1];
2273 		    pix[0] = fg[0];
2274 		    break;
2275 		  case splashModeAMono8:
2276 		    pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1];
2277 		    pix[0] = fg[0];
2278 		    pix[1] = fg[1];
2279 		    break;
2280 		  case splashModeRGB8:
2281 		  case splashModeBGR8:
2282 		    pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1];
2283 		    pix[0] = fg[0];
2284 		    pix[1] = fg[1];
2285 		    pix[2] = fg[2];
2286 		    break;
2287 		  case splashModeARGB8:
2288 		  case splashModeBGRA8:
2289 #if SPLASH_CMYK
2290 		  case splashModeCMYK8:
2291 #endif
2292 		    pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1];
2293 		    pix[0] = fg[0];
2294 		    pix[1] = fg[1];
2295 		    pix[2] = fg[2];
2296 		    pix[3] = fg[3];
2297 		    break;
2298 #if SPLASH_CMYK
2299 		  case splashModeACMYK8:
2300 		    pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1];
2301 		    pix[0] = fg[0];
2302 		    pix[1] = fg[1];
2303 		    pix[2] = fg[2];
2304 		    pix[3] = fg[3];
2305 		    pix[4] = fg[4];
2306 		    break;
2307 #endif
2308 		  }
2309 		  if (!noClip) {
2310 		    updateModX(x1);
2311 		    updateModY(y1);
2312 		  }
2313 		}
2314 	      }
2315 	      alpha0 <<= 1;
2316 	    }
2317 	  }
2318 	}
2319       }
2320     }
2321   }
2322   opClipRes = clipRes;
2323 
2324   return splashOk;
2325 }
2326 
fillImageMask(SplashImageMaskSource src,void * srcData,int w,int h,SplashCoord * mat)2327 SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
2328 				  int w, int h, SplashCoord *mat) {
2329   GBool rot;
2330   SplashCoord xScale, yScale, xShear, yShear, yShear1;
2331   int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign;
2332   int ulx, uly, llx, lly, urx, ury, lrx, lry;
2333   int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
2334   int xMin, xMax, yMin, yMax;
2335   SplashClipResult clipRes, clipRes2;
2336   int yp, yq, yt, yStep, lastYStep;
2337   int xp, xq, xt, xStep, xSrc;
2338   int k1, spanXMin, spanXMax, spanY;
2339   SplashColorPtr pixBuf, p;
2340   int pixAcc;
2341   SplashCoord alpha;
2342   int x, y, x1, x2, y2;
2343   SplashCoord y1;
2344   int n, m, i, j;
2345 
2346   if (debugMode) {
2347     printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
2348 	   w, h, (double)mat[0], (double)mat[1], (double)mat[2],
2349 	   (double)mat[3], (double)mat[4], (double)mat[5]);
2350   }
2351 
2352   // check for singular matrix
2353   if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) {
2354     return splashErrSingularMatrix;
2355   }
2356 
2357   // compute scale, shear, rotation, translation parameters
2358   rot = splashAbs(mat[1]) > splashAbs(mat[0]);
2359   if (rot) {
2360     xScale = -mat[1];
2361     yScale = mat[2] - (mat[0] * mat[3]) / mat[1];
2362     xShear = -mat[3] / yScale;
2363     yShear = -mat[0] / mat[1];
2364   } else {
2365     xScale = mat[0];
2366     yScale = mat[3] - (mat[1] * mat[2]) / mat[0];
2367     xShear = mat[2] / yScale;
2368     yShear = mat[1] / mat[0];
2369   }
2370   // the +/-0.01 in these computations is to avoid floating point
2371   // precision problems which can lead to gaps between image stripes
2372   // (it can cause image stripes to overlap, but that's a much less
2373   // visible problem)
2374   if (xScale >= 0) {
2375     tx = splashRound(mat[4] - 0.01);
2376     tx2 = splashRound(mat[4] + xScale + 0.01) - 1;
2377   } else {
2378     tx = splashRound(mat[4] + 0.01) - 1;
2379     tx2 = splashRound(mat[4] + xScale - 0.01);
2380   }
2381   scaledWidth = abs(tx2 - tx) + 1;
2382   if (scaledWidth == 0) {
2383     // technically, this should draw nothing, but it generally seems
2384     // better to draw a one-pixel-wide stripe rather than throwing it
2385     // away
2386     scaledWidth = 1;
2387   }
2388   if (yScale >= 0) {
2389     ty = splashRound(mat[5] - 0.01);
2390     ty2 = splashRound(mat[5] + yScale + 0.01) - 1;
2391   } else {
2392     ty = splashRound(mat[5] + 0.01) - 1;
2393     ty2 = splashRound(mat[5] + yScale - 0.01);
2394   }
2395   scaledHeight = abs(ty2 - ty) + 1;
2396   if (scaledHeight == 0) {
2397     // technically, this should draw nothing, but it generally seems
2398     // better to draw a one-pixel-wide stripe rather than throwing it
2399     // away
2400     scaledHeight = 1;
2401   }
2402   xSign = (xScale < 0) ? -1 : 1;
2403   ySign = (yScale < 0) ? -1 : 1;
2404   yShear1 = (SplashCoord)xSign * yShear;
2405 
2406   // clipping
2407   ulx1 = 0;
2408   uly1 = 0;
2409   urx1 = xSign * (scaledWidth - 1);
2410   ury1 = (int)(yShear * urx1);
2411   llx1 = splashRound(xShear * ySign * (scaledHeight - 1));
2412   lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1);
2413   lrx1 = xSign * (scaledWidth - 1) +
2414            splashRound(xShear * ySign * (scaledHeight - 1));
2415   lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1);
2416   if (rot) {
2417     ulx = tx + uly1;    uly = ty - ulx1;
2418     urx = tx + ury1;    ury = ty - urx1;
2419     llx = tx + lly1;    lly = ty - llx1;
2420     lrx = tx + lry1;    lry = ty - lrx1;
2421   } else {
2422     ulx = tx + ulx1;    uly = ty + uly1;
2423     urx = tx + urx1;    ury = ty + ury1;
2424     llx = tx + llx1;    lly = ty + lly1;
2425     lrx = tx + lrx1;    lry = ty + lry1;
2426   }
2427   xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
2428                                    : (llx < lrx) ? llx : lrx
2429 		     : (urx < llx) ? (urx < lrx) ? urx : lrx
2430                                    : (llx < lrx) ? llx : lrx;
2431   xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
2432                                    : (llx > lrx) ? llx : lrx
2433 		     : (urx > llx) ? (urx > lrx) ? urx : lrx
2434                                    : (llx > lrx) ? llx : lrx;
2435   yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
2436                                    : (lly < lry) ? lly : lry
2437 		     : (ury < lly) ? (ury < lry) ? ury : lry
2438                                    : (lly < lry) ? lly : lry;
2439   yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
2440                                    : (lly > lry) ? lly : lry
2441 		     : (ury > lly) ? (ury > lry) ? ury : lry
2442                                    : (lly > lry) ? lly : lry;
2443   clipRes = state->clip->testRect(xMin, yMin, xMax, yMax);
2444   opClipRes = clipRes;
2445 
2446   // compute Bresenham parameters for x and y scaling
2447   yp = h / scaledHeight;
2448   yq = h % scaledHeight;
2449   xp = w / scaledWidth;
2450   xq = w % scaledWidth;
2451 
2452   // allocate pixel buffer
2453   pixBuf = (SplashColorPtr)gmalloc((yp + 1) * w);
2454 
2455   // init y scale Bresenham
2456   yt = 0;
2457   lastYStep = 1;
2458 
2459   for (y = 0; y < scaledHeight; ++y) {
2460 
2461     // y scale Bresenham
2462     yStep = yp;
2463     yt += yq;
2464     if (yt >= scaledHeight) {
2465       yt -= scaledHeight;
2466       ++yStep;
2467     }
2468 
2469     // read row(s) from image
2470     n = (yp > 0) ? yStep : lastYStep;
2471     if (n > 0) {
2472       p = pixBuf;
2473       for (i = 0; i < n; ++i) {
2474 	(*src)(srcData, p);
2475 	p += w;
2476       }
2477     }
2478     lastYStep = yStep;
2479 
2480     // loop-invariant constants
2481     k1 = splashRound(xShear * ySign * y);
2482 
2483     // clipping test
2484     if (clipRes != splashClipAllInside &&
2485 	!rot &&
2486 	(int)(yShear * k1) ==
2487 	  (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
2488       if (xSign > 0) {
2489 	spanXMin = tx + k1;
2490 	spanXMax = spanXMin + (scaledWidth - 1);
2491       } else {
2492 	spanXMax = tx + k1;
2493 	spanXMin = spanXMax - (scaledWidth - 1);
2494       }
2495       spanY = ty + ySign * y + (int)(yShear * k1);
2496       clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
2497       if (clipRes2 == splashClipAllOutside) {
2498 	continue;
2499       }
2500     } else {
2501       clipRes2 = clipRes;
2502     }
2503 
2504     // init x scale Bresenham
2505     xt = 0;
2506     xSrc = 0;
2507 
2508     // x shear
2509     x1 = k1;
2510 
2511     // y shear
2512     y1 = (SplashCoord)ySign * y + yShear * x1;
2513     // this is a kludge: if yShear1 is negative, then (int)y1 would
2514     // change immediately after the first pixel, which is not what we
2515     // want
2516     if (yShear1 < 0) {
2517       y1 += 0.999;
2518     }
2519 
2520     // loop-invariant constants
2521     n = yStep > 0 ? yStep : 1;
2522 
2523     for (x = 0; x < scaledWidth; ++x) {
2524 
2525       // x scale Bresenham
2526       xStep = xp;
2527       xt += xq;
2528       if (xt >= scaledWidth) {
2529 	xt -= scaledWidth;
2530 	++xStep;
2531       }
2532 
2533       // rotation
2534       if (rot) {
2535 	x2 = (int)y1;
2536 	y2 = -x1;
2537       } else {
2538 	x2 = x1;
2539 	y2 = (int)y1;
2540       }
2541 
2542       // compute the alpha value for (x,y) after the x and y scaling
2543       // operations
2544       m = xStep > 0 ? xStep : 1;
2545       p = pixBuf + xSrc;
2546       pixAcc = 0;
2547       for (i = 0; i < n; ++i) {
2548 	for (j = 0; j < m; ++j) {
2549 	  pixAcc += *p++;
2550 	}
2551 	p += w - m;
2552       }
2553 
2554       // blend fill color with background
2555       if (pixAcc != 0) {
2556 	if (pixAcc == n * m) {
2557 	  drawPixel(tx + x2, ty + y2, state->fillPattern, state->fillAlpha,
2558 		    clipRes2 == splashClipAllInside);
2559 	} else {
2560 	  alpha = (SplashCoord)pixAcc / (SplashCoord)(n * m);
2561 	  drawPixel(tx + x2, ty + y2, state->fillPattern,
2562 		    state->fillAlpha * alpha,
2563 		    clipRes2 == splashClipAllInside);
2564 	}
2565       }
2566 
2567       // x scale Bresenham
2568       xSrc += xStep;
2569 
2570       // x shear
2571       x1 += xSign;
2572 
2573       // y shear
2574       y1 += yShear1;
2575     }
2576   }
2577 
2578   // free memory
2579   gfree(pixBuf);
2580 
2581   return splashOk;
2582 }
2583 
drawImage(SplashImageSource src,void * srcData,SplashColorMode srcMode,int w,int h,SplashCoord * mat)2584 SplashError Splash::drawImage(SplashImageSource src, void *srcData,
2585 			      SplashColorMode srcMode,
2586 			      int w, int h, SplashCoord *mat) {
2587   GBool ok, rot, halftone, srcAlpha;
2588   SplashCoord xScale, yScale, xShear, yShear, yShear1;
2589   int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign;
2590   int ulx, uly, llx, lly, urx, ury, lrx, lry;
2591   int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
2592   int xMin, xMax, yMin, yMax;
2593   SplashClipResult clipRes, clipRes2;
2594   int yp, yq, yt, yStep, lastYStep;
2595   int xp, xq, xt, xStep, xSrc;
2596   int k1, spanXMin, spanXMax, spanY;
2597   SplashColorPtr pixBuf, p;
2598   SplashColor pix;
2599 #if SPLASH_CMYK
2600   int pixAcc0, pixAcc1, pixAcc2, pixAcc3;
2601 #else
2602   int pixAcc0, pixAcc1, pixAcc2;
2603 #endif
2604   int alphaAcc;
2605   SplashCoord pixMul, alphaMul, alpha;
2606   int x, y, x1, x2, y2;
2607   SplashCoord y1;
2608   int nComps, n, m, i, j;
2609 
2610   if (debugMode) {
2611     printf("drawImage: srcMode=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
2612 	   srcMode, w, h, (double)mat[0], (double)mat[1], (double)mat[2],
2613 	   (double)mat[3], (double)mat[4], (double)mat[5]);
2614   }
2615 
2616   // check color modes
2617   ok = gFalse; // make gcc happy
2618   nComps = 0; // make gcc happy
2619   halftone = gFalse;
2620   srcAlpha = gFalse;
2621   switch (bitmap->mode) {
2622   case splashModeMono1:
2623     ok = srcMode == splashModeMono1 || srcMode == splashModeMono8 ||
2624          srcMode == splashModeAMono8;
2625     halftone = srcMode == splashModeMono8 || srcMode == splashModeAMono8;
2626     srcAlpha = srcMode == splashModeAMono8;
2627     nComps = srcAlpha ? 2 : 1;
2628     break;
2629   case splashModeMono8:
2630     ok = srcMode == splashModeMono8 || srcMode == splashModeAMono8;
2631     srcAlpha = srcMode == splashModeAMono8;
2632     nComps = srcAlpha ? 2 : 1;
2633     break;
2634   case splashModeAMono8:
2635     //~ not implemented yet
2636     ok = gFalse;
2637     nComps = 2;
2638     break;
2639   case splashModeRGB8:
2640     ok = srcMode == splashModeRGB8 || srcMode == splashModeARGB8;
2641     srcAlpha = srcMode == splashModeARGB8;
2642     nComps = srcAlpha ? 4 : 3;
2643     break;
2644   case splashModeBGR8:
2645     ok = srcMode == splashModeBGR8 || srcMode == splashModeBGRA8;
2646     srcAlpha = srcMode == splashModeBGRA8;
2647     nComps = srcAlpha ? 4 : 3;
2648     break;
2649 #if SPLASH_CMYK
2650   case splashModeCMYK8:
2651     ok = srcMode == splashModeCMYK8 || srcMode == splashModeACMYK8;
2652     srcAlpha = srcMode == splashModeACMYK8;
2653     nComps = srcAlpha ? 5 : 4;
2654     break;
2655 #endif
2656   case splashModeARGB8:
2657   case splashModeBGRA8:
2658 #if SPLASH_CMYK
2659   case splashModeACMYK8:
2660 #endif
2661     //~ not implemented yet
2662     ok = gFalse;
2663     nComps = 4;
2664     break;
2665   }
2666   if (!ok) {
2667     return splashErrModeMismatch;
2668   }
2669 
2670   // check for singular matrix
2671   if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) {
2672     return splashErrSingularMatrix;
2673   }
2674 
2675   // compute scale, shear, rotation, translation parameters
2676   rot = splashAbs(mat[1]) > splashAbs(mat[0]);
2677   if (rot) {
2678     xScale = -mat[1];
2679     yScale = mat[2] - (mat[0] * mat[3]) / mat[1];
2680     xShear = -mat[3] / yScale;
2681     yShear = -mat[0] / mat[1];
2682   } else {
2683     xScale = mat[0];
2684     yScale = mat[3] - (mat[1] * mat[2]) / mat[0];
2685     xShear = mat[2] / yScale;
2686     yShear = mat[1] / mat[0];
2687   }
2688   // the +/-0.01 in these computations is to avoid floating point
2689   // precision problems which can lead to gaps between image stripes
2690   // (it can cause image stripes to overlap, but that's a much less
2691   // visible problem)
2692   if (xScale >= 0) {
2693     tx = splashRound(mat[4] - 0.01);
2694     tx2 = splashRound(mat[4] + xScale + 0.01) - 1;
2695   } else {
2696     tx = splashRound(mat[4] + 0.01) - 1;
2697     tx2 = splashRound(mat[4] + xScale - 0.01);
2698   }
2699   scaledWidth = abs(tx2 - tx) + 1;
2700   if (scaledWidth == 0) {
2701     // technically, this should draw nothing, but it generally seems
2702     // better to draw a one-pixel-wide stripe rather than throwing it
2703     // away
2704     scaledWidth = 1;
2705   }
2706   if (yScale >= 0) {
2707     ty = splashRound(mat[5] - 0.01);
2708     ty2 = splashRound(mat[5] + yScale + 0.01) - 1;
2709   } else {
2710     ty = splashRound(mat[5] + 0.01) - 1;
2711     ty2 = splashRound(mat[5] + yScale - 0.01);
2712   }
2713   scaledHeight = abs(ty2 - ty) + 1;
2714   if (scaledHeight == 0) {
2715     // technically, this should draw nothing, but it generally seems
2716     // better to draw a one-pixel-wide stripe rather than throwing it
2717     // away
2718     scaledHeight = 1;
2719   }
2720   xSign = (xScale < 0) ? -1 : 1;
2721   ySign = (yScale < 0) ? -1 : 1;
2722   yShear1 = (SplashCoord)xSign * yShear;
2723 
2724   // clipping
2725   ulx1 = 0;
2726   uly1 = 0;
2727   urx1 = xSign * (scaledWidth - 1);
2728   ury1 = (int)(yShear * urx1);
2729   llx1 = splashRound(xShear * ySign * (scaledHeight - 1));
2730   lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1);
2731   lrx1 = xSign * (scaledWidth - 1) +
2732            splashRound(xShear * ySign * (scaledHeight - 1));
2733   lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1);
2734   if (rot) {
2735     ulx = tx + uly1;    uly = ty - ulx1;
2736     urx = tx + ury1;    ury = ty - urx1;
2737     llx = tx + lly1;    lly = ty - llx1;
2738     lrx = tx + lry1;    lry = ty - lrx1;
2739   } else {
2740     ulx = tx + ulx1;    uly = ty + uly1;
2741     urx = tx + urx1;    ury = ty + ury1;
2742     llx = tx + llx1;    lly = ty + lly1;
2743     lrx = tx + lrx1;    lry = ty + lry1;
2744   }
2745   xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
2746                                    : (llx < lrx) ? llx : lrx
2747 		     : (urx < llx) ? (urx < lrx) ? urx : lrx
2748                                    : (llx < lrx) ? llx : lrx;
2749   xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
2750                                    : (llx > lrx) ? llx : lrx
2751 		     : (urx > llx) ? (urx > lrx) ? urx : lrx
2752                                    : (llx > lrx) ? llx : lrx;
2753   yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
2754                                    : (lly < lry) ? lly : lry
2755 		     : (ury < lly) ? (ury < lry) ? ury : lry
2756                                    : (lly < lry) ? lly : lry;
2757   yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
2758                                    : (lly > lry) ? lly : lry
2759 		     : (ury > lly) ? (ury > lry) ? ury : lry
2760                                    : (lly > lry) ? lly : lry;
2761   clipRes = state->clip->testRect(xMin, yMin, xMax, yMax);
2762   opClipRes = clipRes;
2763   if (clipRes == splashClipAllOutside) {
2764     return splashOk;
2765   }
2766 
2767   // compute Bresenham parameters for x and y scaling
2768   yp = h / scaledHeight;
2769   yq = h % scaledHeight;
2770   xp = w / scaledWidth;
2771   xq = w % scaledWidth;
2772 
2773   // allocate pixel buffer
2774   pixBuf = (SplashColorPtr)gmalloc((yp + 1) * w * nComps);
2775 
2776   pixAcc0 = pixAcc1 = pixAcc2 = 0; // make gcc happy
2777 #if SPLASH_CMYK
2778   pixAcc3 = 0; // make gcc happy
2779 #endif
2780 
2781   if (srcAlpha) {
2782 
2783     // init y scale Bresenham
2784     yt = 0;
2785     lastYStep = 1;
2786 
2787     for (y = 0; y < scaledHeight; ++y) {
2788 
2789       // y scale Bresenham
2790       yStep = yp;
2791       yt += yq;
2792       if (yt >= scaledHeight) {
2793 	yt -= scaledHeight;
2794 	++yStep;
2795       }
2796 
2797       // read row(s) from image
2798       n = (yp > 0) ? yStep : lastYStep;
2799       if (n > 0) {
2800 	p = pixBuf;
2801 	for (i = 0; i < n; ++i) {
2802 	  (*src)(srcData, p);
2803 	  p += w * nComps;
2804 	}
2805       }
2806       lastYStep = yStep;
2807 
2808       // loop-invariant constants
2809       k1 = splashRound(xShear * ySign * y);
2810 
2811       // clipping test
2812       if (clipRes != splashClipAllInside &&
2813 	  !rot &&
2814 	  (int)(yShear * k1) ==
2815 	    (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
2816 	if (xSign > 0) {
2817 	  spanXMin = tx + k1;
2818 	  spanXMax = spanXMin + (scaledWidth - 1);
2819 	} else {
2820 	  spanXMax = tx + k1;
2821 	  spanXMin = spanXMax - (scaledWidth - 1);
2822 	}
2823 	spanY = ty + ySign * y + (int)(yShear * k1);
2824 	clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
2825 	if (clipRes2 == splashClipAllOutside) {
2826 	  continue;
2827 	}
2828       } else {
2829 	clipRes2 = clipRes;
2830       }
2831 
2832       // init x scale Bresenham
2833       xt = 0;
2834       xSrc = 0;
2835 
2836       // x shear
2837       x1 = k1;
2838 
2839       // y shear
2840       y1 = (SplashCoord)ySign * y + yShear * x1;
2841       // this is a kludge: if yShear1 is negative, then (int)y1 would
2842       // change immediately after the first pixel, which is not what
2843       // we want
2844       if (yShear1 < 0) {
2845 	y1 += 0.999;
2846       }
2847 
2848       // loop-invariant constants
2849       n = yStep > 0 ? yStep : 1;
2850 
2851       for (x = 0; x < scaledWidth; ++x) {
2852 
2853 	// x scale Bresenham
2854 	xStep = xp;
2855 	xt += xq;
2856 	if (xt >= scaledWidth) {
2857 	  xt -= scaledWidth;
2858 	  ++xStep;
2859 	}
2860 
2861 	// rotation
2862 	if (rot) {
2863 	  x2 = (int)y1;
2864 	  y2 = -x1;
2865 	} else {
2866 	  x2 = x1;
2867 	  y2 = (int)y1;
2868 	}
2869 
2870 	// compute the filtered pixel at (x,y) after the x and y scaling
2871 	// operations
2872 	m = xStep > 0 ? xStep : 1;
2873 	alphaAcc = 0;
2874 	switch (srcMode) {
2875 	case splashModeAMono8:
2876 	  p = pixBuf + xSrc * 2;
2877 	  pixAcc0 = 0;
2878 	  for (i = 0; i < n; ++i) {
2879 	    for (j = 0; j < m; ++j) {
2880 	      alphaAcc += *p++;
2881 	      pixAcc0 += *p++;
2882 	    }
2883 	    p += 2 * (w - m);
2884 	  }
2885 	  break;
2886 	case splashModeARGB8:
2887 	  p = pixBuf + xSrc * 4;
2888 	  pixAcc0 = pixAcc1 = pixAcc2 = 0;
2889 	  for (i = 0; i < n; ++i) {
2890 	    for (j = 0; j < m; ++j) {
2891 	      alphaAcc += *p++;
2892 	      pixAcc0 += *p++;
2893 	      pixAcc1 += *p++;
2894 	      pixAcc2 += *p++;
2895 	    }
2896 	    p += 4 * (w - m);
2897 	  }
2898 	  break;
2899 	case splashModeBGRA8:
2900 	  p = pixBuf + xSrc * 4;
2901 	  pixAcc0 = pixAcc1 = pixAcc2 = 0;
2902 	  for (i = 0; i < n; ++i) {
2903 	    for (j = 0; j < m; ++j) {
2904 	      pixAcc0 += *p++;
2905 	      pixAcc1 += *p++;
2906 	      pixAcc2 += *p++;
2907 	      alphaAcc += *p++;
2908 	    }
2909 	    p += 4 * (w - m);
2910 	  }
2911 	  break;
2912 #if SPLASH_CMYK
2913 	case splashModeACMYK8:
2914 	  p = pixBuf + xSrc * 5;
2915 	  pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0;
2916 	  for (i = 0; i < n; ++i) {
2917 	    for (j = 0; j < m; ++j) {
2918 	      alphaAcc += *p++;
2919 	      pixAcc0 += *p++;
2920 	      pixAcc1 += *p++;
2921 	      pixAcc2 += *p++;
2922 	      pixAcc3 += *p++;
2923 	    }
2924 	    p += 5 * (w - m);
2925 	  }
2926 	  break;
2927 #endif
2928 	default: // make gcc happy
2929 	  break;
2930 	}
2931 	pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
2932 	alphaMul = pixMul * (1.0 / 256.0);
2933 	alpha = (SplashCoord)alphaAcc * alphaMul;
2934 
2935 	if (alpha > 0) {
2936 	  // mono8 -> mono1 conversion, with halftoning
2937 	  if (halftone) {
2938 	    pix[0] = state->screen->test(tx + x2, ty + y2,
2939 			    (SplashCoord)pixAcc0 * pixMul * (1.0 / 256.0));
2940 
2941 	  // no conversion, no halftoning
2942 	  } else {
2943 	    switch (bitmap->mode) {
2944 #if SPLASH_CMYK
2945 	    case splashModeCMYK8:
2946 	      pix[3] = (int)((SplashCoord)pixAcc3 * pixMul);
2947 	      // fall through
2948 #endif
2949 	    case splashModeRGB8:
2950 	    case splashModeBGR8:
2951 	      pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
2952 	      pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
2953 	      // fall through
2954 	    case splashModeMono1:
2955 	    case splashModeMono8:
2956 	      pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
2957 	      break;
2958 	    default: // make gcc happy
2959 	      break;
2960 	    }
2961 	  }
2962 
2963 	  // set pixel
2964 	  drawPixel(tx + x2, ty + y2, pix, alpha * state->fillAlpha,
2965 		    clipRes2 == splashClipAllInside);
2966 	}
2967 
2968 	// x scale Bresenham
2969 	xSrc += xStep;
2970 
2971 	// x shear
2972 	x1 += xSign;
2973 
2974 	// y shear
2975 	y1 += yShear1;
2976       }
2977     }
2978 
2979   } else {
2980 
2981     // init y scale Bresenham
2982     yt = 0;
2983     lastYStep = 1;
2984 
2985     for (y = 0; y < scaledHeight; ++y) {
2986 
2987       // y scale Bresenham
2988       yStep = yp;
2989       yt += yq;
2990       if (yt >= scaledHeight) {
2991 	yt -= scaledHeight;
2992 	++yStep;
2993       }
2994 
2995       // read row(s) from image
2996       n = (yp > 0) ? yStep : lastYStep;
2997       if (n > 0) {
2998 	p = pixBuf;
2999 	for (i = 0; i < n; ++i) {
3000 	  (*src)(srcData, p);
3001 	  p += w * nComps;
3002 	}
3003       }
3004       lastYStep = yStep;
3005 
3006       // loop-invariant constants
3007       k1 = splashRound(xShear * ySign * y);
3008 
3009       // clipping test
3010       if (clipRes != splashClipAllInside &&
3011 	  !rot &&
3012 	  (int)(yShear * k1) ==
3013 	    (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
3014 	if (xSign > 0) {
3015 	  spanXMin = tx + k1;
3016 	  spanXMax = spanXMin + (scaledWidth - 1);
3017 	} else {
3018 	  spanXMax = tx + k1;
3019 	  spanXMin = spanXMax - (scaledWidth - 1);
3020 	}
3021 	spanY = ty + ySign * y + (int)(yShear * k1);
3022 	clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
3023 	if (clipRes2 == splashClipAllOutside) {
3024 	  continue;
3025 	}
3026       } else {
3027 	clipRes2 = clipRes;
3028       }
3029 
3030       // init x scale Bresenham
3031       xt = 0;
3032       xSrc = 0;
3033 
3034       // x shear
3035       x1 = k1;
3036 
3037       // y shear
3038       y1 = (SplashCoord)ySign * y + yShear * x1;
3039       // this is a kludge: if yShear1 is negative, then (int)y1 would
3040       // change immediately after the first pixel, which is not what
3041       // we want
3042       if (yShear1 < 0) {
3043 	y1 += 0.999;
3044       }
3045 
3046       // loop-invariant constants
3047       n = yStep > 0 ? yStep : 1;
3048 
3049       for (x = 0; x < scaledWidth; ++x) {
3050 
3051 	// x scale Bresenham
3052 	xStep = xp;
3053 	xt += xq;
3054 	if (xt >= scaledWidth) {
3055 	  xt -= scaledWidth;
3056 	  ++xStep;
3057 	}
3058 
3059 	// rotation
3060 	if (rot) {
3061 	  x2 = (int)y1;
3062 	  y2 = -x1;
3063 	} else {
3064 	  x2 = x1;
3065 	  y2 = (int)y1;
3066 	}
3067 
3068 	// compute the filtered pixel at (x,y) after the x and y scaling
3069 	// operations
3070 	m = xStep > 0 ? xStep : 1;
3071 	switch (srcMode) {
3072 	case splashModeMono1:
3073 	case splashModeMono8:
3074 	  p = pixBuf + xSrc;
3075 	  pixAcc0 = 0;
3076 	  for (i = 0; i < n; ++i) {
3077 	    for (j = 0; j < m; ++j) {
3078 	      pixAcc0 += *p++;
3079 	    }
3080 	    p += w - m;
3081 	  }
3082 	  break;
3083 	case splashModeRGB8:
3084 	case splashModeBGR8:
3085 	  p = pixBuf + xSrc * 3;
3086 	  pixAcc0 = pixAcc1 = pixAcc2 = 0;
3087 	  for (i = 0; i < n; ++i) {
3088 	    for (j = 0; j < m; ++j) {
3089 	      pixAcc0 += *p++;
3090 	      pixAcc1 += *p++;
3091 	      pixAcc2 += *p++;
3092 	    }
3093 	    p += 3 * (w - m);
3094 	  }
3095 	  break;
3096 #if SPLASH_CMYK
3097 	case splashModeCMYK8:
3098 	  p = pixBuf + xSrc * 4;
3099 	  pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0;
3100 	  for (i = 0; i < n; ++i) {
3101 	    for (j = 0; j < m; ++j) {
3102 	      pixAcc0 += *p++;
3103 	      pixAcc1 += *p++;
3104 	      pixAcc2 += *p++;
3105 	      pixAcc3 += *p++;
3106 	    }
3107 	    p += 4 * (w - m);
3108 	  }
3109 	  break;
3110 #endif
3111 	default: // make gcc happy
3112 	  break;
3113 	}
3114 	pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
3115 
3116 	// mono8 -> mono1 conversion, with halftoning
3117 	if (halftone) {
3118 	  pix[0] = state->screen->test(tx + x2, ty + y2,
3119 			  (SplashCoord)pixAcc0 * pixMul * (1.0 / 256.0));
3120 
3121 	// no conversion, no halftoning
3122 	} else {
3123 	  switch (bitmap->mode) {
3124 #if SPLASH_CMYK
3125 	  case splashModeCMYK8:
3126 	    pix[3] = (int)((SplashCoord)pixAcc3 * pixMul);
3127 	    // fall through
3128 #endif
3129 	  case splashModeRGB8:
3130 	  case splashModeBGR8:
3131 	    pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
3132 	    pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
3133 	    // fall through
3134 	  case splashModeMono1:
3135 	  case splashModeMono8:
3136 	    pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
3137 	    break;
3138 	  default: // make gcc happy
3139 	    break;
3140 	  }
3141 	}
3142 
3143 	// set pixel
3144 	drawPixel(tx + x2, ty + y2, pix, state->fillAlpha,
3145 		  clipRes2 == splashClipAllInside);
3146 
3147 	// x scale Bresenham
3148 	xSrc += xStep;
3149 
3150 	// x shear
3151 	x1 += xSign;
3152 
3153 	// y shear
3154 	y1 += yShear1;
3155       }
3156     }
3157 
3158   }
3159 
3160   gfree(pixBuf);
3161 
3162   return splashOk;
3163 }
3164 
dumpPath(SplashPath * path)3165 void Splash::dumpPath(SplashPath *path) {
3166   int i;
3167 
3168   for (i = 0; i < path->length; ++i) {
3169     printf("  %3d: x=%8.2f y=%8.2f%s%s%s%s%s\n",
3170 	   i, (double)path->pts[i].x, (double)path->pts[i].y,
3171 	   (path->flags[i] & splashPathFirst) ? " first" : "",
3172 	   (path->flags[i] & splashPathLast) ? " last" : "",
3173 	   (path->flags[i] & splashPathClosed) ? " closed" : "",
3174 	   (path->flags[i] & splashPathCurve) ? " curve" : "",
3175 	   (path->flags[i] & splashPathArcCW) ? " arcCW" : "");
3176   }
3177 }
3178 
dumpXPath(SplashXPath * path)3179 void Splash::dumpXPath(SplashXPath *path) {
3180   int i;
3181 
3182   for (i = 0; i < path->length; ++i) {
3183     printf("  %4d: x0=%8.2f y0=%8.2f x1=%8.2f y1=%8.2f %s%s%s%s%s%s%s\n",
3184 	   i, (double)path->segs[i].x0, (double)path->segs[i].y0,
3185 	   (double)path->segs[i].x1, (double)path->segs[i].y1,
3186 	   (path->segs[i].flags	& splashXPathFirst) ? "F" : " ",
3187 	   (path->segs[i].flags	& splashXPathLast) ? "L" : " ",
3188 	   (path->segs[i].flags	& splashXPathEnd0) ? "0" : " ",
3189 	   (path->segs[i].flags	& splashXPathEnd1) ? "1" : " ",
3190 	   (path->segs[i].flags	& splashXPathHoriz) ? "H" : " ",
3191 	   (path->segs[i].flags	& splashXPathVert) ? "V" : " ",
3192 	   (path->segs[i].flags	& splashXPathFlip) ? "P" : " ");
3193   }
3194 }
3195