w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

Splash.cc
Go to the documentation of this file.
1 //========================================================================
2 //
3 // Splash.cc
4 //
5 // Copyright 2003-2020 Glyph & Cog, LLC
6 //
7 //========================================================================
8 
9 #include <aconf.h>
10 
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
14 
15 #include <stdlib.h>
16 #include <string.h>
17 #include <limits.h>
18 #include <math.h>
19 #include "gmem.h"
20 #include "gmempp.h"
21 #include "GString.h"
22 #include "SplashErrorCodes.h"
23 #include "SplashMath.h"
24 #include "SplashBitmap.h"
25 #include "SplashState.h"
26 #include "SplashPath.h"
27 #include "SplashXPath.h"
28 #include "SplashXPathScanner.h"
29 #include "SplashPattern.h"
30 #include "SplashScreen.h"
31 #include "SplashFont.h"
32 #include "SplashGlyphBitmap.h"
33 #include "Splash.h"
34 
35 // the MSVC math.h doesn't define this
36 #ifndef M_PI
37 #define M_PI 3.14159265358979323846
38 #endif
39 
40 //------------------------------------------------------------------------
41 
42 // distance of Bezier control point from center for circle approximation
43 // = (4 * (sqrt(2) - 1) / 3) * r
44 #define bezierCircle ((SplashCoord)0.55228475)
45 #define bezierCircle2 ((SplashCoord)(0.5 * 0.55228475))
46 
47 // Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result.
48 static inline Guchar div255(int x) {
49  return (Guchar)((x + (x >> 8) + 0x80) >> 8);
50 }
51 
52 // Clip x to lie in [0, 255].
53 static inline Guchar clip255(int x) {
54  return x < 0 ? 0 : x > 255 ? 255 : (Guchar)x;
55 }
56 
57 // Used by drawImage and fillImageMask to divide the target
58 // quadrilateral into sections.
59 struct ImageSection {
60  int y0, y1; // actual y range
61  int ia0, ia1; // vertex indices for edge A
62  int ib0, ib1; // vertex indices for edge B
63  SplashCoord xa0, ya0, xa1, ya1; // edge A
64  SplashCoord dxdya; // slope of edge A
65  SplashCoord xb0, yb0, xb1, yb1; // edge B
66  SplashCoord dxdyb; // slope of edge B
67 };
68 
69 //------------------------------------------------------------------------
70 // SplashPipe
71 //------------------------------------------------------------------------
72 
73 #define splashPipeMaxStages 9
74 
75 struct SplashPipe {
76  // source pattern
78 
79  // source alpha and color
82 
83  // source overprint mask
84  //~ this is a kludge - this pointer should be passed as an arg to the
85  //~ pipeRun function, but that would require passing in a lot of
86  //~ null pointers, since it's rarely used
88 
89  // special cases and result color
93 
94  // non-isolated group correction
95  // (this is only used when Splash::composite() is called to composite
96  // a non-isolated group onto the backdrop)
98 
99  // the "run" function
100  void (Splash::*run)(SplashPipe *pipe, int x0, int x1, int y,
101  Guchar *shapePtr, SplashColorPtr cSrcPtr);
102 };
103 
109 #if SPLASH_CMYK
110  ,
112 #endif
113 };
114 
120 #if SPLASH_CMYK
121  ,
123 #endif
124 };
125 
131 #if SPLASH_CMYK
132  ,
134 #endif
135 };
136 
137 //------------------------------------------------------------------------
138 // modified region
139 //------------------------------------------------------------------------
140 
142  modXMin = bitmap->width;
143  modYMin = bitmap->height;
144  modXMax = -1;
145  modYMax = -1;
146 }
147 
148 inline void Splash::updateModX(int x) {
149  if (x < modXMin) {
150  modXMin = x;
151  }
152  if (x > modXMax) {
153  modXMax = x;
154  }
155 }
156 
157 inline void Splash::updateModY(int y) {
158  if (y < modYMin) {
159  modYMin = y;
160  }
161  if (y > modYMax) {
162  modYMax = y;
163  }
164 }
165 
166 //------------------------------------------------------------------------
167 // pipeline
168 //------------------------------------------------------------------------
169 
171  Guchar aInput, GBool usesShape,
172  GBool nonIsolatedGroup, GBool usesSrcOverprint) {
174 
175  mode = bitmap->mode;
176 
177  pipe->pattern = NULL;
178 
179  // source color
180  if (pattern && pattern->isStatic()) {
181  pattern->getColor(0, 0, pipe->cSrcVal);
182  pipe->pattern = NULL;
183  } else {
184  pipe->pattern = pattern;
185  }
186 
187  // source alpha
188  pipe->aInput = aInput;
189 
190  // source overprint mask
191  pipe->srcOverprintMaskPtr = NULL;
192 
193  // special cases
194  pipe->noTransparency = aInput == 255 &&
195  !state->softMask &&
196  !usesShape &&
197  !state->inNonIsolatedGroup &&
198  !state->inKnockoutGroup &&
199  !nonIsolatedGroup &&
200  state->overprintMask == 0xffffffff;
201  pipe->shapeOnly = aInput == 255 &&
202  !state->softMask &&
203  usesShape &&
204  !state->inNonIsolatedGroup &&
205  !state->inKnockoutGroup &&
206  !nonIsolatedGroup &&
207  state->overprintMask == 0xffffffff;
208 
209  // result color
210  if (pipe->noTransparency) {
211  // the !state->blendFunc case is handled separately in pipeRun
212  pipe->resultColorCtrl = pipeResultColorNoAlphaBlend[mode];
213  } else if (!state->blendFunc) {
214  pipe->resultColorCtrl = pipeResultColorAlphaNoBlend[mode];
215  } else {
216  pipe->resultColorCtrl = pipeResultColorAlphaBlend[mode];
217  }
218 
219  // non-isolated group correction
220  pipe->nonIsolatedGroup = nonIsolatedGroup;
221 
222  // select the 'run' function
223  pipe->run = &Splash::pipeRun;
224  if (overprintMaskBitmap || usesSrcOverprint) {
225  // use Splash::pipeRun
226  } else if (!pipe->pattern && pipe->noTransparency && !state->blendFunc) {
227  if (mode == splashModeMono1 && !bitmap->alpha) {
229  } else if (mode == splashModeMono8 && bitmap->alpha) {
231  } else if (mode == splashModeRGB8 && bitmap->alpha) {
233  } else if (mode == splashModeBGR8 && bitmap->alpha) {
235 #if SPLASH_CMYK
236  } else if (mode == splashModeCMYK8 && bitmap->alpha) {
238 #endif
239  }
240  } else if (!pipe->pattern && pipe->shapeOnly && !state->blendFunc) {
241  if (mode == splashModeMono1 && !bitmap->alpha) {
243  } else if (mode == splashModeMono8 && bitmap->alpha) {
245  } else if (mode == splashModeRGB8 && bitmap->alpha) {
247  } else if (mode == splashModeBGR8 && bitmap->alpha) {
249 #if SPLASH_CMYK
250  } else if (mode == splashModeCMYK8 && bitmap->alpha) {
251  pipe->run = &Splash::pipeRunShapeCMYK8;
252 #endif
253  } else if (mode == splashModeMono8 && !bitmap->alpha) {
254  // this is used when drawing soft-masked images
256  }
257  } else if (!pipe->pattern && !pipe->noTransparency && !state->softMask &&
258  usesShape &&
259  !(state->inNonIsolatedGroup && groupBackBitmap->alpha) &&
260  !state->inKnockoutGroup &&
261  !state->blendFunc && !pipe->nonIsolatedGroup) {
262  if (mode == splashModeMono1 && !bitmap->alpha) {
264  } else if (mode == splashModeMono8 && bitmap->alpha) {
266  } else if (mode == splashModeRGB8 && bitmap->alpha) {
267  pipe->run = &Splash::pipeRunAARGB8;
268  } else if (mode == splashModeBGR8 && bitmap->alpha) {
269  pipe->run = &Splash::pipeRunAABGR8;
270 #if SPLASH_CMYK
271  } else if (mode == splashModeCMYK8 && bitmap->alpha) {
273 #endif
274  }
275  } else if (!pipe->pattern &&
276  aInput == 255 &&
277  state->softMask &&
278  usesShape &&
279  !state->inNonIsolatedGroup &&
280  !state->inKnockoutGroup &&
281  !nonIsolatedGroup &&
282  state->overprintMask == 0xffffffff &&
283  !state->blendFunc) {
284  if (mode == splashModeMono8 && bitmap->alpha) {
286  } else if (mode == splashModeRGB8 && bitmap->alpha) {
288  } else if (mode == splashModeBGR8 && bitmap->alpha) {
290 #if SPLASH_CMYK
291  } else if (mode == splashModeCMYK8 && bitmap->alpha) {
292  pipe->run = &Splash::pipeRunSoftMaskCMYK8;
293 #endif
294  }
295  } else if (!pipe->pattern && !pipe->noTransparency && !state->softMask &&
296  usesShape &&
297  state->inNonIsolatedGroup && groupBackBitmap->alpha &&
298  !state->inKnockoutGroup &&
299  !state->blendFunc && !pipe->nonIsolatedGroup) {
300  if (mode == splashModeMono8 && bitmap->alpha) {
302  } else if (mode == splashModeRGB8 && bitmap->alpha) {
304  } else if (mode == splashModeBGR8 && bitmap->alpha) {
306 #if SPLASH_CMYK
307  } else if (mode == splashModeCMYK8 && bitmap->alpha) {
308  pipe->run = &Splash::pipeRunNonIsoCMYK8;
309 #endif
310  }
311  }
312 }
313 
314 // general case
315 void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y,
316  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
317  Guchar *shapePtr2;
318  Guchar shape, aSrc, aDest, alphaI, alphaIm1, alpha0, aResult;
319  SplashColor cSrc, cDest, cBlend;
320  Guchar shapeVal, cResult0, cResult1, cResult2, cResult3;
321  int cSrcStride, shapeStride, x, lastX, t;
322  SplashColorPtr destColorPtr;
323  Guchar destColorMask;
324  Guchar *destAlphaPtr;
325  SplashColorPtr color0Ptr;
326  Guchar color0Mask;
327  Guchar *alpha0Ptr;
328  SplashColorPtr softMaskPtr;
329  Guint overprintMask;
330  Guint *overprintMaskPtr;
331 #if SPLASH_CMYK
332  Guchar aPrev;
333  SplashColor cSrc2, cDest2;
334 #endif
335 
336  if (cSrcPtr && !pipe->pattern) {
337  cSrcStride = bitmapComps;
338  } else {
339  cSrcPtr = pipe->cSrcVal;
340  cSrcStride = 0;
341  }
342 
343  if (shapePtr) {
344  shapePtr2 = shapePtr;
345  shapeStride = 1;
346  for (; x0 <= x1; ++x0) {
347  if (*shapePtr2) {
348  break;
349  }
350  cSrcPtr += cSrcStride;
351  ++shapePtr2;
352  if (pipe->srcOverprintMaskPtr) {
353  ++pipe->srcOverprintMaskPtr;
354  }
355  }
356  } else {
357  shapeVal = 0xff;
358  shapePtr2 = &shapeVal;
359  shapeStride = 0;
360  }
361  if (x0 > x1) {
362  return;
363  }
364  updateModX(x0);
365  updateModY(y);
366  lastX = x0;
367 
368  useDestRow(y);
369 
370  if (bitmap->mode == splashModeMono1) {
371  destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
372  destColorMask = (Guchar)(0x80 >> (x0 & 7));
373  } else {
374  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * bitmapComps];
375  destColorMask = 0; // make gcc happy
376  }
377  if (bitmap->alpha) {
378  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
379  } else {
380  destAlphaPtr = NULL;
381  }
382  if (state->softMask) {
383  softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0];
384  } else {
385  softMaskPtr = NULL;
386  }
387  if (state->inKnockoutGroup) {
388  if (bitmap->mode == splashModeMono1) {
389  color0Ptr =
391  ((groupBackX + x0) >> 3)];
392  color0Mask = (Guchar)(0x80 >> ((groupBackX + x0) & 7));
393  } else {
394  color0Ptr =
396  (groupBackX + x0) * bitmapComps];
397  color0Mask = 0; // make gcc happy
398  }
399  } else {
400  color0Ptr = NULL;
401  color0Mask = 0; // make gcc happy
402  }
403  if (state->inNonIsolatedGroup && groupBackBitmap->alpha) {
404  alpha0Ptr =
407  (groupBackX + x0)];
408  } else {
409  alpha0Ptr = NULL;
410  }
411  if (overprintMaskBitmap) {
412  overprintMaskPtr = overprintMaskBitmap + y * bitmap->width + x0;
413  } else {
414  overprintMaskPtr = NULL;
415  }
416 
417  for (x = x0; x <= x1; ++x) {
418 
419  //----- shape
420 
421  shape = *shapePtr2;
422  if (!shape) {
423  if (bitmap->mode == splashModeMono1) {
424  destColorPtr += destColorMask & 1;
425  destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1));
426  } else {
427  destColorPtr += bitmapComps;
428  }
429  if (destAlphaPtr) {
430  ++destAlphaPtr;
431  }
432  if (softMaskPtr) {
433  ++softMaskPtr;
434  }
435  if (color0Ptr) {
436  if (bitmap->mode == splashModeMono1) {
437  color0Ptr += color0Mask & 1;
438  color0Mask = (Guchar)((color0Mask << 7) | (color0Mask >> 1));
439  } else {
440  color0Ptr += bitmapComps;
441  }
442  }
443  if (alpha0Ptr) {
444  ++alpha0Ptr;
445  }
446  cSrcPtr += cSrcStride;
447  shapePtr2 += shapeStride;
448  if (pipe->srcOverprintMaskPtr) {
449  ++pipe->srcOverprintMaskPtr;
450  }
451  if (overprintMaskPtr) {
452  ++overprintMaskPtr;
453  }
454  continue;
455  }
456  lastX = x;
457 
458  //----- source color
459 
460  // static pattern: handled in pipeInit
461  // fixed color: handled in pipeInit
462 
463  // dynamic pattern
464  if (pipe->pattern) {
465  pipe->pattern->getColor(x, y, pipe->cSrcVal);
466  }
467 
468  cResult0 = cResult1 = cResult2 = cResult3 = 0; // make gcc happy
469 
470  if (pipe->noTransparency && !state->blendFunc) {
471 
472  //----- result color
473 
474  switch (bitmap->mode) {
475  case splashModeMono1:
476  case splashModeMono8:
477  cResult0 = state->grayTransfer[cSrcPtr[0]];
478  break;
479  case splashModeRGB8:
480  case splashModeBGR8:
481  cResult0 = state->rgbTransferR[cSrcPtr[0]];
482  cResult1 = state->rgbTransferG[cSrcPtr[1]];
483  cResult2 = state->rgbTransferB[cSrcPtr[2]];
484  break;
485 #if SPLASH_CMYK
486  case splashModeCMYK8:
487  cResult0 = state->cmykTransferC[cSrcPtr[0]];
488  cResult1 = state->cmykTransferM[cSrcPtr[1]];
489  cResult2 = state->cmykTransferY[cSrcPtr[2]];
490  cResult3 = state->cmykTransferK[cSrcPtr[3]];
491  break;
492 #endif
493  }
494  aResult = 255;
495 
496  } else { // if (noTransparency && !blendFunc)
497 
498  //----- read destination pixel
499  // (or backdrop color, for knockout groups)
500 
501  if (color0Ptr) {
502 
503  switch (bitmap->mode) {
504  case splashModeMono1:
505  cDest[0] = (*color0Ptr & color0Mask) ? 0xff : 0x00;
506  color0Ptr += color0Mask & 1;
507  color0Mask = (Guchar)((color0Mask << 7) | (color0Mask >> 1));
508  break;
509  case splashModeMono8:
510  cDest[0] = *color0Ptr++;
511  break;
512  case splashModeRGB8:
513  cDest[0] = color0Ptr[0];
514  cDest[1] = color0Ptr[1];
515  cDest[2] = color0Ptr[2];
516  color0Ptr += 3;
517  break;
518  case splashModeBGR8:
519  cDest[2] = color0Ptr[0];
520  cDest[1] = color0Ptr[1];
521  cDest[0] = color0Ptr[2];
522  color0Ptr += 3;
523  break;
524 #if SPLASH_CMYK
525  case splashModeCMYK8:
526  cDest[0] = color0Ptr[0];
527  cDest[1] = color0Ptr[1];
528  cDest[2] = color0Ptr[2];
529  cDest[3] = color0Ptr[3];
530  color0Ptr += 4;
531  break;
532 #endif
533  }
534 
535  } else {
536 
537  switch (bitmap->mode) {
538  case splashModeMono1:
539  cDest[0] = (*destColorPtr & destColorMask) ? 0xff : 0x00;
540  break;
541  case splashModeMono8:
542  cDest[0] = *destColorPtr;
543  break;
544  case splashModeRGB8:
545  cDest[0] = destColorPtr[0];
546  cDest[1] = destColorPtr[1];
547  cDest[2] = destColorPtr[2];
548  break;
549  case splashModeBGR8:
550  cDest[0] = destColorPtr[2];
551  cDest[1] = destColorPtr[1];
552  cDest[2] = destColorPtr[0];
553  break;
554 #if SPLASH_CMYK
555  case splashModeCMYK8:
556  cDest[0] = destColorPtr[0];
557  cDest[1] = destColorPtr[1];
558  cDest[2] = destColorPtr[2];
559  cDest[3] = destColorPtr[3];
560  break;
561 #endif
562  }
563 
564  }
565 
566  if (destAlphaPtr) {
567  aDest = *destAlphaPtr;
568  } else {
569  aDest = 0xff;
570  }
571 
572  //----- read source color; handle overprint
573 
574  if (pipe->srcOverprintMaskPtr) {
575  overprintMask = *pipe->srcOverprintMaskPtr++;
576  } else {
577  overprintMask = state->overprintMask;
578  }
579  if (overprintMaskPtr) {
580  *overprintMaskPtr++ |= overprintMask;
581  }
582 
583  switch (bitmap->mode) {
584  case splashModeMono1:
585  case splashModeMono8:
586  cSrc[0] = state->grayTransfer[cSrcPtr[0]];
587  break;
588  case splashModeRGB8:
589  case splashModeBGR8:
590  cSrc[0] = state->rgbTransferR[cSrcPtr[0]];
591  cSrc[1] = state->rgbTransferG[cSrcPtr[1]];
592  cSrc[2] = state->rgbTransferB[cSrcPtr[2]];
593  break;
594 #if SPLASH_CMYK
595  case splashModeCMYK8:
596  if (alpha0Ptr) { // non-isolated group
597  if (color0Ptr) { // non-isolated, knockout group
598  aPrev = *alpha0Ptr;
599  } else { // non-isolated, non-knockout group
600  aPrev = (Guchar)(*alpha0Ptr + aDest - div255(*alpha0Ptr * aDest));
601  }
602  } else { // isolated group
603  if (color0Ptr) { // isolated, knockout group
604  aPrev = 0;
605  } else { // isolated, non-knockout group
606  aPrev = aDest;
607  }
608  }
609  if (overprintMask & 0x01) {
610  cSrc[0] = state->cmykTransferC[cSrcPtr[0]];
611  } else {
612  cSrc[0] = div255(aPrev * cDest[0]);
613  }
614  if (overprintMask & 0x02) {
615  cSrc[1] = state->cmykTransferM[cSrcPtr[1]];
616  } else {
617  cSrc[1] = div255(aPrev * cDest[1]);
618  }
619  if (overprintMask & 0x04) {
620  cSrc[2] = state->cmykTransferY[cSrcPtr[2]];
621  } else {
622  cSrc[2] = div255(aPrev * cDest[2]);
623  }
624  if (overprintMask & 0x08) {
625  cSrc[3] = state->cmykTransferK[cSrcPtr[3]];
626  } else {
627  cSrc[3] = div255(aPrev * cDest[3]);
628  }
629  break;
630 #endif
631  }
632 
633  //----- source alpha
634 
635  if (softMaskPtr) {
636  if (shapePtr) {
637  aSrc = div255(div255(pipe->aInput * *softMaskPtr++) * shape);
638  } else {
639  aSrc = div255(pipe->aInput * *softMaskPtr++);
640  }
641  } else if (shapePtr) {
642  aSrc = div255(pipe->aInput * shape);
643  } else {
644  aSrc = pipe->aInput;
645  }
646 
647  //----- non-isolated group correction
648 
649  if (pipe->nonIsolatedGroup) {
650  // This path is only used when Splash::composite() is called to
651  // composite a non-isolated group onto the backdrop. In this
652  // case, shape is the source (group) alpha.
653  t = (aDest * 255) / shape - aDest;
654  switch (bitmap->mode) {
655 #if SPLASH_CMYK
656  case splashModeCMYK8:
657  cSrc[3] = clip255(cSrc[3] + ((cSrc[3] - cDest[3]) * t) / 255);
658 #endif
659  case splashModeRGB8:
660  case splashModeBGR8:
661  cSrc[2] = clip255(cSrc[2] + ((cSrc[2] - cDest[2]) * t) / 255);
662  cSrc[1] = clip255(cSrc[1] + ((cSrc[1] - cDest[1]) * t) / 255);
663  case splashModeMono1:
664  case splashModeMono8:
665  cSrc[0] = clip255(cSrc[0] + ((cSrc[0] - cDest[0]) * t) / 255);
666  break;
667  }
668  }
669 
670  //----- blend function
671 
672  if (state->blendFunc) {
673 #if SPLASH_CMYK
674  if (bitmap->mode == splashModeCMYK8) {
675  // convert colors to additive
676  cSrc2[0] = (Guchar)(0xff - cSrc[0]);
677  cSrc2[1] = (Guchar)(0xff - cSrc[1]);
678  cSrc2[2] = (Guchar)(0xff - cSrc[2]);
679  cSrc2[3] = (Guchar)(0xff - cSrc[3]);
680  cDest2[0] = (Guchar)(0xff - cDest[0]);
681  cDest2[1] = (Guchar)(0xff - cDest[1]);
682  cDest2[2] = (Guchar)(0xff - cDest[2]);
683  cDest2[3] = (Guchar)(0xff - cDest[3]);
684  (*state->blendFunc)(cSrc2, cDest2, cBlend, bitmap->mode);
685  // convert result back to subtractive
686  cBlend[0] = (Guchar)(0xff - cBlend[0]);
687  cBlend[1] = (Guchar)(0xff - cBlend[1]);
688  cBlend[2] = (Guchar)(0xff - cBlend[2]);
689  cBlend[3] = (Guchar)(0xff - cBlend[3]);
690  } else
691 #endif
692  (*state->blendFunc)(cSrc, cDest, cBlend, bitmap->mode);
693  }
694 
695  //----- result alpha and non-isolated group element correction
696 
697  // alphaI = alpha_i
698  // alphaIm1 = alpha_(i-1)
699 
700  if (pipe->noTransparency) {
701  alphaI = alphaIm1 = aResult = 255;
702  } else if (alpha0Ptr) {
703  if (color0Ptr) {
704  // non-isolated, knockout
705  aResult = aSrc;
706  alpha0 = *alpha0Ptr++;
707  alphaI = (Guchar)(aSrc + alpha0 - div255(aSrc * alpha0));
708  alphaIm1 = alpha0;
709  } else {
710  // non-isolated, non-knockout
711  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
712  alpha0 = *alpha0Ptr++;
713  alphaI = (Guchar)(aResult + alpha0 - div255(aResult * alpha0));
714  alphaIm1 = (Guchar)(alpha0 + aDest - div255(alpha0 * aDest));
715  }
716  } else {
717  if (color0Ptr) {
718  // isolated, knockout
719  aResult = aSrc;
720  alphaI = aSrc;
721  alphaIm1 = 0;
722  } else {
723  // isolated, non-knockout
724  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
725  alphaI = aResult;
726  alphaIm1 = aDest;
727  }
728  }
729 
730  //----- result color
731 
732  switch (pipe->resultColorCtrl) {
733 
735  cResult0 = div255((255 - aDest) * cSrc[0] + aDest * cBlend[0]);
736  break;
738  cResult0 = div255((255 - aDest) * cSrc[0] + aDest * cBlend[0]);
739  cResult1 = div255((255 - aDest) * cSrc[1] + aDest * cBlend[1]);
740  cResult2 = div255((255 - aDest) * cSrc[2] + aDest * cBlend[2]);
741  break;
742 #if SPLASH_CMYK
744  cResult0 = div255((255 - aDest) * cSrc[0] + aDest * cBlend[0]);
745  cResult1 = div255((255 - aDest) * cSrc[1] + aDest * cBlend[1]);
746  cResult2 = div255((255 - aDest) * cSrc[2] + aDest * cBlend[2]);
747  cResult3 = div255((255 - aDest) * cSrc[3] + aDest * cBlend[3]);
748  break;
749 #endif
750 
752  if (alphaI == 0) {
753  cResult0 = 0;
754  } else {
755  cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] + aSrc * cSrc[0])
756  / alphaI);
757  }
758  break;
760  if (alphaI == 0) {
761  cResult0 = 0;
762  cResult1 = 0;
763  cResult2 = 0;
764  } else {
765  cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] + aSrc * cSrc[0])
766  / alphaI);
767  cResult1 = (Guchar)(((alphaI - aSrc) * cDest[1] + aSrc * cSrc[1])
768  / alphaI);
769  cResult2 = (Guchar)(((alphaI - aSrc) * cDest[2] + aSrc * cSrc[2])
770  / alphaI);
771  }
772  break;
773 #if SPLASH_CMYK
775  if (alphaI == 0) {
776  cResult0 = 0;
777  cResult1 = 0;
778  cResult2 = 0;
779  cResult3 = 0;
780  } else {
781  cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] + aSrc * cSrc[0])
782  / alphaI);
783  cResult1 = (Guchar)(((alphaI - aSrc) * cDest[1] + aSrc * cSrc[1])
784  / alphaI);
785  cResult2 = (Guchar)(((alphaI - aSrc) * cDest[2] + aSrc * cSrc[2])
786  / alphaI);
787  cResult3 = (Guchar)(((alphaI - aSrc) * cDest[3] + aSrc * cSrc[3])
788  / alphaI);
789  }
790  break;
791 #endif
792 
794  if (alphaI == 0) {
795  cResult0 = 0;
796  } else {
797  cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] +
798  aSrc * ((255 - alphaIm1) * cSrc[0] +
799  alphaIm1 * cBlend[0]) / 255)
800  / alphaI);
801  }
802  break;
804  if (alphaI == 0) {
805  cResult0 = 0;
806  cResult1 = 0;
807  cResult2 = 0;
808  } else {
809  cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] +
810  aSrc * ((255 - alphaIm1) * cSrc[0] +
811  alphaIm1 * cBlend[0]) / 255)
812  / alphaI);
813  cResult1 = (Guchar)(((alphaI - aSrc) * cDest[1] +
814  aSrc * ((255 - alphaIm1) * cSrc[1] +
815  alphaIm1 * cBlend[1]) / 255)
816  / alphaI);
817  cResult2 = (Guchar)(((alphaI - aSrc) * cDest[2] +
818  aSrc * ((255 - alphaIm1) * cSrc[2] +
819  alphaIm1 * cBlend[2]) / 255)
820  / alphaI);
821  }
822  break;
823 #if SPLASH_CMYK
825  if (alphaI == 0) {
826  cResult0 = 0;
827  cResult1 = 0;
828  cResult2 = 0;
829  cResult3 = 0;
830  } else {
831  cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] +
832  aSrc * ((255 - alphaIm1) * cSrc[0] +
833  alphaIm1 * cBlend[0]) / 255)
834  / alphaI);
835  cResult1 = (Guchar)(((alphaI - aSrc) * cDest[1] +
836  aSrc * ((255 - alphaIm1) * cSrc[1] +
837  alphaIm1 * cBlend[1]) / 255)
838  / alphaI);
839  cResult2 = (Guchar)(((alphaI - aSrc) * cDest[2] +
840  aSrc * ((255 - alphaIm1) * cSrc[2] +
841  alphaIm1 * cBlend[2]) / 255)
842  / alphaI);
843  cResult3 = (Guchar)(((alphaI - aSrc) * cDest[3] +
844  aSrc * ((255 - alphaIm1) * cSrc[3] +
845  alphaIm1 * cBlend[3]) / 255)
846  / alphaI);
847  }
848  break;
849 #endif
850  }
851 
852  } // if (noTransparency && !blendFunc)
853 
854  //----- write destination pixel
855 
856  switch (bitmap->mode) {
857  case splashModeMono1:
858  if (state->screen->test(x, y, cResult0)) {
859  *destColorPtr |= destColorMask;
860  } else {
861  *destColorPtr &= (Guchar)~destColorMask;
862  }
863  destColorPtr += destColorMask & 1;
864  destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1));
865  break;
866  case splashModeMono8:
867  *destColorPtr++ = cResult0;
868  break;
869  case splashModeRGB8:
870  destColorPtr[0] = cResult0;
871  destColorPtr[1] = cResult1;
872  destColorPtr[2] = cResult2;
873  destColorPtr += 3;
874  break;
875  case splashModeBGR8:
876  destColorPtr[0] = cResult2;
877  destColorPtr[1] = cResult1;
878  destColorPtr[2] = cResult0;
879  destColorPtr += 3;
880  break;
881 #if SPLASH_CMYK
882  case splashModeCMYK8:
883  destColorPtr[0] = cResult0;
884  destColorPtr[1] = cResult1;
885  destColorPtr[2] = cResult2;
886  destColorPtr[3] = cResult3;
887  destColorPtr += 4;
888  break;
889 #endif
890  }
891  if (destAlphaPtr) {
892  *destAlphaPtr++ = aResult;
893  }
894 
895  cSrcPtr += cSrcStride;
896  shapePtr2 += shapeStride;
897  } // for (x ...)
898 
899  updateModX(lastX);
900 }
901 
902 // special case:
903 // !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
904 // bitmap->mode == splashModeMono1 && !bitmap->alpha) {
906  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
907  Guchar cResult0;
908  SplashColorPtr destColorPtr;
909  Guchar destColorMask;
910  SplashScreenCursor screenCursor;
911  int cSrcStride, x;
912 
913  if (cSrcPtr) {
914  cSrcStride = 1;
915  } else {
916  cSrcPtr = pipe->cSrcVal;
917  cSrcStride = 0;
918  }
919  if (x0 > x1) {
920  return;
921  }
922  updateModX(x0);
923  updateModX(x1);
924  updateModY(y);
925 
926  useDestRow(y);
927 
928  destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
929  destColorMask = (Guchar)(0x80 >> (x0 & 7));
930 
931  screenCursor = state->screen->getTestCursor(y);
932 
933  for (x = x0; x <= x1; ++x) {
934 
935  //----- write destination pixel
936  cResult0 = state->grayTransfer[cSrcPtr[0]];
937  if (state->screen->testWithCursor(screenCursor, x, cResult0)) {
938  *destColorPtr |= destColorMask;
939  } else {
940  *destColorPtr &= (Guchar)~destColorMask;
941  }
942  destColorPtr += destColorMask & 1;
943  destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1));
944 
945  cSrcPtr += cSrcStride;
946  }
947 }
948 
949 // special case:
950 // !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
951 // bitmap->mode == splashModeMono8 && bitmap->alpha) {
953  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
954  SplashColorPtr destColorPtr;
955  Guchar *destAlphaPtr;
956  int cSrcStride, x;
957 
958  if (cSrcPtr) {
959  cSrcStride = 1;
960  } else {
961  cSrcPtr = pipe->cSrcVal;
962  cSrcStride = 0;
963  }
964  if (x0 > x1) {
965  return;
966  }
967  updateModX(x0);
968  updateModX(x1);
969  updateModY(y);
970 
971  useDestRow(y);
972 
973  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
974  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
975 
976  for (x = x0; x <= x1; ++x) {
977 
978  //----- write destination pixel
979  *destColorPtr++ = state->grayTransfer[cSrcPtr[0]];
980  *destAlphaPtr++ = 255;
981 
982  cSrcPtr += cSrcStride;
983  }
984 }
985 
986 // special case:
987 // !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
988 // bitmap->mode == splashModeRGB8 && bitmap->alpha) {
990  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
991  SplashColorPtr destColorPtr;
992  Guchar *destAlphaPtr;
993  int cSrcStride, x;
994 
995  if (cSrcPtr) {
996  cSrcStride = 3;
997  } else {
998  cSrcPtr = pipe->cSrcVal;
999  cSrcStride = 0;
1000  }
1001  if (x0 > x1) {
1002  return;
1003  }
1004  updateModX(x0);
1005  updateModX(x1);
1006  updateModY(y);
1007 
1008  useDestRow(y);
1009 
1010  destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
1011  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
1012 
1013  for (x = x0; x <= x1; ++x) {
1014 
1015  //----- write destination pixel
1016  destColorPtr[0] = state->rgbTransferR[cSrcPtr[0]];
1017  destColorPtr[1] = state->rgbTransferG[cSrcPtr[1]];
1018  destColorPtr[2] = state->rgbTransferB[cSrcPtr[2]];
1019  destColorPtr += 3;
1020  *destAlphaPtr++ = 255;
1021 
1022  cSrcPtr += cSrcStride;
1023  }
1024 }
1025 
1026 // special case:
1027 // !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
1028 // bitmap->mode == splashModeBGR8 && bitmap->alpha) {
1030  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1031  SplashColorPtr destColorPtr;
1032  Guchar *destAlphaPtr;
1033  int cSrcStride, x;
1034 
1035  if (cSrcPtr) {
1036  cSrcStride = 3;
1037  } else {
1038  cSrcPtr = pipe->cSrcVal;
1039  cSrcStride = 0;
1040  }
1041  if (x0 > x1) {
1042  return;
1043  }
1044  updateModX(x0);
1045  updateModX(x1);
1046  updateModY(y);
1047 
1048  useDestRow(y);
1049 
1050  destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
1051  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
1052 
1053  for (x = x0; x <= x1; ++x) {
1054 
1055  //----- write destination pixel
1056  destColorPtr[0] = state->rgbTransferB[cSrcPtr[2]];
1057  destColorPtr[1] = state->rgbTransferG[cSrcPtr[1]];
1058  destColorPtr[2] = state->rgbTransferR[cSrcPtr[0]];
1059  destColorPtr += 3;
1060  *destAlphaPtr++ = 255;
1061 
1062  cSrcPtr += cSrcStride;
1063  }
1064 }
1065 
1066 #if SPLASH_CMYK
1067 // special case:
1068 // !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
1069 // bitmap->mode == splashModeCMYK8 && bitmap->alpha) {
1070 void Splash::pipeRunSimpleCMYK8(SplashPipe *pipe, int x0, int x1, int y,
1071  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1072  SplashColorPtr destColorPtr;
1073  Guchar *destAlphaPtr;
1074  int cSrcStride, x;
1075 
1076  if (cSrcPtr) {
1077  cSrcStride = 4;
1078  } else {
1079  cSrcPtr = pipe->cSrcVal;
1080  cSrcStride = 0;
1081  }
1082  if (x0 > x1) {
1083  return;
1084  }
1085  updateModX(x0);
1086  updateModX(x1);
1087  updateModY(y);
1088 
1089  useDestRow(y);
1090 
1091  destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x0];
1092  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
1093 
1094  for (x = x0; x <= x1; ++x) {
1095 
1096  //----- write destination pixel
1097  destColorPtr[0] = state->cmykTransferC[cSrcPtr[0]];
1098  destColorPtr[1] = state->cmykTransferM[cSrcPtr[1]];
1099  destColorPtr[2] = state->cmykTransferY[cSrcPtr[2]];
1100  destColorPtr[3] = state->cmykTransferK[cSrcPtr[3]];
1101  destColorPtr += 4;
1102  *destAlphaPtr++ = 255;
1103 
1104  cSrcPtr += cSrcStride;
1105  }
1106 }
1107 #endif
1108 
1109 
1110 // special case:
1111 // !pipe->pattern && pipe->shapeOnly && !state->blendFunc &&
1112 // bitmap->mode == splashModeMono1 && !bitmap->alpha
1114  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1115  Guchar shape, aSrc, cSrc0, cDest0, cResult0;
1116  SplashColorPtr destColorPtr;
1117  Guchar destColorMask;
1118  SplashScreenCursor screenCursor;
1119  int cSrcStride, x, lastX;
1120 
1121  if (cSrcPtr) {
1122  cSrcStride = 1;
1123  } else {
1124  cSrcPtr = pipe->cSrcVal;
1125  cSrcStride = 0;
1126  }
1127  for (; x0 <= x1; ++x0) {
1128  if (*shapePtr) {
1129  break;
1130  }
1131  cSrcPtr += cSrcStride;
1132  ++shapePtr;
1133  }
1134  if (x0 > x1) {
1135  return;
1136  }
1137  updateModX(x0);
1138  updateModY(y);
1139  lastX = x0;
1140 
1141  useDestRow(y);
1142 
1143  destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
1144  destColorMask = (Guchar)(0x80 >> (x0 & 7));
1145 
1146  screenCursor = state->screen->getTestCursor(y);
1147 
1148  for (x = x0; x <= x1; ++x) {
1149 
1150  //----- shape
1151  shape = *shapePtr;
1152  if (!shape) {
1153  destColorPtr += destColorMask & 1;
1154  destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1));
1155  cSrcPtr += cSrcStride;
1156  ++shapePtr;
1157  continue;
1158  }
1159  lastX = x;
1160 
1161  //----- source color
1162  cSrc0 = state->grayTransfer[cSrcPtr[0]];
1163 
1164  //----- source alpha
1165  aSrc = shape;
1166 
1167  //----- special case for aSrc = 255
1168  if (aSrc == 255) {
1169  cResult0 = cSrc0;
1170  } else {
1171 
1172  //----- read destination pixel
1173  cDest0 = (*destColorPtr & destColorMask) ? 0xff : 0x00;
1174 
1175  //----- result color
1176  // note: aDest = alphaI = aResult = 0xff
1177  cResult0 = (Guchar)div255((0xff - aSrc) * cDest0 + aSrc * cSrc0);
1178  }
1179 
1180  //----- write destination pixel
1181  if (state->screen->testWithCursor(screenCursor, x, cResult0)) {
1182  *destColorPtr |= destColorMask;
1183  } else {
1184  *destColorPtr &= (Guchar)~destColorMask;
1185  }
1186  destColorPtr += destColorMask & 1;
1187  destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1));
1188 
1189  cSrcPtr += cSrcStride;
1190  ++shapePtr;
1191  }
1192 
1193  updateModX(lastX);
1194 }
1195 
1196 // special case:
1197 // !pipe->pattern && pipe->shapeOnly && !state->blendFunc &&
1198 // bitmap->mode == splashModeMono8 && bitmap->alpha
1200  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1201  Guchar shape, aSrc, aDest, alphaI, aResult, cSrc0, cDest0, cResult0;
1202  SplashColorPtr destColorPtr;
1203  Guchar *destAlphaPtr;
1204  int cSrcStride, x, lastX;
1205 
1206  if (cSrcPtr) {
1207  cSrcStride = 1;
1208  } else {
1209  cSrcPtr = pipe->cSrcVal;
1210  cSrcStride = 0;
1211  }
1212  for (; x0 <= x1; ++x0) {
1213  if (*shapePtr) {
1214  break;
1215  }
1216  cSrcPtr += cSrcStride;
1217  ++shapePtr;
1218  }
1219  if (x0 > x1) {
1220  return;
1221  }
1222  updateModX(x0);
1223  updateModY(y);
1224  lastX = x0;
1225 
1226  useDestRow(y);
1227 
1228  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
1229  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
1230 
1231  for (x = x0; x <= x1; ++x) {
1232 
1233  //----- shape
1234  shape = *shapePtr;
1235  if (!shape) {
1236  ++destColorPtr;
1237  ++destAlphaPtr;
1238  cSrcPtr += cSrcStride;
1239  ++shapePtr;
1240  continue;
1241  }
1242  lastX = x;
1243 
1244  //----- source color
1245  cSrc0 = state->grayTransfer[cSrcPtr[0]];
1246 
1247  //----- source alpha
1248  aSrc = shape;
1249 
1250  //----- special case for aSrc = 255
1251  if (aSrc == 255) {
1252  aResult = 255;
1253  cResult0 = cSrc0;
1254  } else {
1255 
1256  //----- read destination alpha
1257  aDest = *destAlphaPtr;
1258 
1259  //----- special case for aDest = 0
1260  if (aDest == 0) {
1261  aResult = aSrc;
1262  cResult0 = cSrc0;
1263  } else {
1264 
1265  //----- read destination pixel
1266  cDest0 = *destColorPtr;
1267 
1268  //----- result alpha and non-isolated group element correction
1269  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
1270  alphaI = aResult;
1271 
1272  //----- result color
1273  cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
1274  }
1275  }
1276 
1277  //----- write destination pixel
1278  *destColorPtr++ = cResult0;
1279  *destAlphaPtr++ = aResult;
1280 
1281  cSrcPtr += cSrcStride;
1282  ++shapePtr;
1283  }
1284 
1285  updateModX(lastX);
1286 }
1287 
1288 // special case:
1289 // !pipe->pattern && pipe->shapeOnly && !state->blendFunc &&
1290 // bitmap->mode == splashModeRGB8 && bitmap->alpha
1292  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1293  Guchar shape, aSrc, aDest, alphaI, aResult;
1294  Guchar cSrc0, cSrc1, cSrc2;
1295  Guchar cDest0, cDest1, cDest2;
1296  Guchar cResult0, cResult1, cResult2;
1297  SplashColorPtr destColorPtr;
1298  Guchar *destAlphaPtr;
1299  int cSrcStride, x, lastX;
1300 
1301  if (cSrcPtr) {
1302  cSrcStride = 3;
1303  } else {
1304  cSrcPtr = pipe->cSrcVal;
1305  cSrcStride = 0;
1306  }
1307  for (; x0 <= x1; ++x0) {
1308  if (*shapePtr) {
1309  break;
1310  }
1311  cSrcPtr += cSrcStride;
1312  ++shapePtr;
1313  }
1314  if (x0 > x1) {
1315  return;
1316  }
1317  updateModX(x0);
1318  updateModY(y);
1319  lastX = x0;
1320 
1321  useDestRow(y);
1322 
1323  destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
1324  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
1325 
1326  for (x = x0; x <= x1; ++x) {
1327 
1328  //----- shape
1329  shape = *shapePtr;
1330  if (!shape) {
1331  destColorPtr += 3;
1332  ++destAlphaPtr;
1333  cSrcPtr += cSrcStride;
1334  ++shapePtr;
1335  continue;
1336  }
1337  lastX = x;
1338 
1339  //----- source color
1340  cSrc0 = state->rgbTransferR[cSrcPtr[0]];
1341  cSrc1 = state->rgbTransferG[cSrcPtr[1]];
1342  cSrc2 = state->rgbTransferB[cSrcPtr[2]];
1343 
1344  //----- source alpha
1345  aSrc = shape;
1346 
1347  //----- special case for aSrc = 255
1348  if (aSrc == 255) {
1349  aResult = 255;
1350  cResult0 = cSrc0;
1351  cResult1 = cSrc1;
1352  cResult2 = cSrc2;
1353  } else {
1354 
1355  //----- read destination alpha
1356  aDest = *destAlphaPtr;
1357 
1358  //----- special case for aDest = 0
1359  if (aDest == 0) {
1360  aResult = aSrc;
1361  cResult0 = cSrc0;
1362  cResult1 = cSrc1;
1363  cResult2 = cSrc2;
1364  } else {
1365 
1366  //----- read destination pixel
1367  cDest0 = destColorPtr[0];
1368  cDest1 = destColorPtr[1];
1369  cDest2 = destColorPtr[2];
1370 
1371  //----- result alpha and non-isolated group element correction
1372  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
1373  alphaI = aResult;
1374 
1375  //----- result color
1376  cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
1377  cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
1378  cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
1379  }
1380  }
1381 
1382  //----- write destination pixel
1383  destColorPtr[0] = cResult0;
1384  destColorPtr[1] = cResult1;
1385  destColorPtr[2] = cResult2;
1386  destColorPtr += 3;
1387  *destAlphaPtr++ = aResult;
1388 
1389  cSrcPtr += cSrcStride;
1390  ++shapePtr;
1391  }
1392 
1393  updateModX(lastX);
1394 }
1395 
1396 // special case:
1397 // !pipe->pattern && pipe->shapeOnly && !state->blendFunc &&
1398 // bitmap->mode == splashModeBGR8 && bitmap->alpha
1400  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1401  Guchar shape, aSrc, aDest, alphaI, aResult;
1402  Guchar cSrc0, cSrc1, cSrc2;
1403  Guchar cDest0, cDest1, cDest2;
1404  Guchar cResult0, cResult1, cResult2;
1405  SplashColorPtr destColorPtr;
1406  Guchar *destAlphaPtr;
1407  int cSrcStride, x, lastX;
1408 
1409  if (cSrcPtr) {
1410  cSrcStride = 3;
1411  } else {
1412  cSrcPtr = pipe->cSrcVal;
1413  cSrcStride = 0;
1414  }
1415  for (; x0 <= x1; ++x0) {
1416  if (*shapePtr) {
1417  break;
1418  }
1419  cSrcPtr += cSrcStride;
1420  ++shapePtr;
1421  }
1422  if (x0 > x1) {
1423  return;
1424  }
1425  updateModX(x0);
1426  updateModY(y);
1427  lastX = x0;
1428 
1429  useDestRow(y);
1430 
1431  destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
1432  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
1433 
1434  for (x = x0; x <= x1; ++x) {
1435 
1436  //----- shape
1437  shape = *shapePtr;
1438  if (!shape) {
1439  destColorPtr += 3;
1440  ++destAlphaPtr;
1441  cSrcPtr += cSrcStride;
1442  ++shapePtr;
1443  continue;
1444  }
1445  lastX = x;
1446 
1447  //----- source color
1448  cSrc0 = state->rgbTransferR[cSrcPtr[0]];
1449  cSrc1 = state->rgbTransferG[cSrcPtr[1]];
1450  cSrc2 = state->rgbTransferB[cSrcPtr[2]];
1451 
1452  //----- source alpha
1453  aSrc = shape;
1454 
1455  //----- special case for aSrc = 255
1456  if (aSrc == 255) {
1457  aResult = 255;
1458  cResult0 = cSrc0;
1459  cResult1 = cSrc1;
1460  cResult2 = cSrc2;
1461  } else {
1462 
1463  //----- read destination alpha
1464  aDest = *destAlphaPtr;
1465 
1466  //----- special case for aDest = 0
1467  if (aDest == 0) {
1468  aResult = aSrc;
1469  cResult0 = cSrc0;
1470  cResult1 = cSrc1;
1471  cResult2 = cSrc2;
1472  } else {
1473 
1474  //----- read destination pixel
1475  cDest0 = destColorPtr[2];
1476  cDest1 = destColorPtr[1];
1477  cDest2 = destColorPtr[0];
1478 
1479  //----- result alpha and non-isolated group element correction
1480  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
1481  alphaI = aResult;
1482 
1483  //----- result color
1484  cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
1485  cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
1486  cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
1487  }
1488  }
1489 
1490  //----- write destination pixel
1491  destColorPtr[0] = cResult2;
1492  destColorPtr[1] = cResult1;
1493  destColorPtr[2] = cResult0;
1494  destColorPtr += 3;
1495  *destAlphaPtr++ = aResult;
1496 
1497  cSrcPtr += cSrcStride;
1498  ++shapePtr;
1499  }
1500 
1501  updateModX(lastX);
1502 }
1503 
1504 #if SPLASH_CMYK
1505 // special case:
1506 // !pipe->pattern && pipe->shapeOnly && !state->blendFunc &&
1507 // bitmap->mode == splashModeCMYK8 && bitmap->alpha
1508 void Splash::pipeRunShapeCMYK8(SplashPipe *pipe, int x0, int x1, int y,
1509  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1510  Guchar shape, aSrc, aDest, alphaI, aResult;
1511  Guchar cSrc0, cSrc1, cSrc2, cSrc3;
1512  Guchar cDest0, cDest1, cDest2, cDest3;
1513  Guchar cResult0, cResult1, cResult2, cResult3;
1514  SplashColorPtr destColorPtr;
1515  Guchar *destAlphaPtr;
1516  int cSrcStride, x, lastX;
1517 
1518  if (cSrcPtr) {
1519  cSrcStride = 4;
1520  } else {
1521  cSrcPtr = pipe->cSrcVal;
1522  cSrcStride = 0;
1523  }
1524  for (; x0 <= x1; ++x0) {
1525  if (*shapePtr) {
1526  break;
1527  }
1528  cSrcPtr += cSrcStride;
1529  ++shapePtr;
1530  }
1531  if (x0 > x1) {
1532  return;
1533  }
1534  updateModX(x0);
1535  updateModY(y);
1536  lastX = x0;
1537 
1538  useDestRow(y);
1539 
1540  destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x0];
1541  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
1542 
1543  for (x = x0; x <= x1; ++x) {
1544 
1545  //----- shape
1546  shape = *shapePtr;
1547  if (!shape) {
1548  destColorPtr += 4;
1549  ++destAlphaPtr;
1550  cSrcPtr += cSrcStride;
1551  ++shapePtr;
1552  continue;
1553  }
1554  lastX = x;
1555 
1556  //----- read destination pixel
1557  cDest0 = destColorPtr[0];
1558  cDest1 = destColorPtr[1];
1559  cDest2 = destColorPtr[2];
1560  cDest3 = destColorPtr[3];
1561  aDest = *destAlphaPtr;
1562 
1563  //----- overprint
1564  cSrc0 = state->cmykTransferC[cSrcPtr[0]];
1565  cSrc1 = state->cmykTransferM[cSrcPtr[1]];
1566  cSrc2 = state->cmykTransferY[cSrcPtr[2]];
1567  cSrc3 = state->cmykTransferK[cSrcPtr[3]];
1568 
1569  //----- source alpha
1570  aSrc = shape;
1571 
1572  //----- special case for aSrc = 255
1573  if (aSrc == 255) {
1574  aResult = 255;
1575  cResult0 = cSrc0;
1576  cResult1 = cSrc1;
1577  cResult2 = cSrc2;
1578  cResult3 = cSrc3;
1579  } else {
1580 
1581  //----- special case for aDest = 0
1582  if (aDest == 0) {
1583  aResult = aSrc;
1584  cResult0 = cSrc0;
1585  cResult1 = cSrc1;
1586  cResult2 = cSrc2;
1587  cResult3 = cSrc3;
1588  } else {
1589 
1590  //----- result alpha and non-isolated group element correction
1591  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
1592  alphaI = aResult;
1593 
1594  //----- result color
1595  cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
1596  cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
1597  cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
1598  cResult3 = (Guchar)(((alphaI - aSrc) * cDest3 + aSrc * cSrc3) / alphaI);
1599  }
1600  }
1601 
1602  //----- write destination pixel
1603  destColorPtr[0] = cResult0;
1604  destColorPtr[1] = cResult1;
1605  destColorPtr[2] = cResult2;
1606  destColorPtr[3] = cResult3;
1607  destColorPtr += 4;
1608  *destAlphaPtr++ = aResult;
1609 
1610  cSrcPtr += cSrcStride;
1611  ++shapePtr;
1612  }
1613 
1614  updateModX(lastX);
1615 }
1616 #endif
1617 
1618 
1619 // special case:
1620 // !pipe->pattern && pipe->shapeOnly && !state->blendFunc &&
1621 // bitmap->mode == splashModeMono8 && !bitmap->alpha
1623  Guchar *shapePtr,
1624  SplashColorPtr cSrcPtr) {
1625  Guchar shape, aSrc, cSrc0, cDest0, cResult0;
1626  SplashColorPtr destColorPtr;
1627  int cSrcStride, x, lastX;
1628 
1629  if (cSrcPtr) {
1630  cSrcStride = 1;
1631  } else {
1632  cSrcPtr = pipe->cSrcVal;
1633  cSrcStride = 0;
1634  }
1635  for (; x0 <= x1; ++x0) {
1636  if (*shapePtr) {
1637  break;
1638  }
1639  cSrcPtr += cSrcStride;
1640  ++shapePtr;
1641  }
1642  if (x0 > x1) {
1643  return;
1644  }
1645  updateModX(x0);
1646  updateModY(y);
1647  lastX = x0;
1648 
1649  useDestRow(y);
1650 
1651  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
1652 
1653  for (x = x0; x <= x1; ++x) {
1654 
1655  //----- shape
1656  shape = *shapePtr;
1657  if (!shape) {
1658  ++destColorPtr;
1659  cSrcPtr += cSrcStride;
1660  ++shapePtr;
1661  continue;
1662  }
1663  lastX = x;
1664 
1665  //----- source color
1666  cSrc0 = state->grayTransfer[cSrcPtr[0]];
1667 
1668  //----- source alpha
1669  aSrc = shape;
1670 
1671  //----- special case for aSrc = 255
1672  if (aSrc == 255) {
1673  cResult0 = cSrc0;
1674  } else {
1675 
1676  //----- read destination pixel
1677  cDest0 = *destColorPtr;
1678 
1679  //----- result color
1680  cResult0 = div255((255 - aSrc) * cDest0 + aSrc * cSrc0);
1681  }
1682 
1683  //----- write destination pixel
1684  *destColorPtr++ = cResult0;
1685 
1686  cSrcPtr += cSrcStride;
1687  ++shapePtr;
1688  }
1689 
1690  updateModX(lastX);
1691 }
1692 
1693 // special case:
1694 // !pipe->pattern && !pipe->noTransparency && !state->softMask &&
1695 // pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
1696 // !pipe->nonIsolatedGroup &&
1697 // bitmap->mode == splashModeMono1 && !bitmap->alpha
1699  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1700  Guchar shape, aSrc, cSrc0, cDest0, cResult0;
1701  SplashColorPtr destColorPtr;
1702  Guchar destColorMask;
1703  SplashScreenCursor screenCursor;
1704  int cSrcStride, x, lastX;
1705 
1706  if (cSrcPtr) {
1707  cSrcStride = 1;
1708  } else {
1709  cSrcPtr = pipe->cSrcVal;
1710  cSrcStride = 0;
1711  }
1712  for (; x0 <= x1; ++x0) {
1713  if (*shapePtr) {
1714  break;
1715  }
1716  cSrcPtr += cSrcStride;
1717  ++shapePtr;
1718  }
1719  if (x0 > x1) {
1720  return;
1721  }
1722  updateModX(x0);
1723  updateModY(y);
1724  lastX = x0;
1725 
1726  useDestRow(y);
1727 
1728  destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
1729  destColorMask = (Guchar)(0x80 >> (x0 & 7));
1730 
1731  screenCursor = state->screen->getTestCursor(y);
1732 
1733  for (x = x0; x <= x1; ++x) {
1734 
1735  //----- shape
1736  shape = *shapePtr;
1737  if (!shape) {
1738  destColorPtr += destColorMask & 1;
1739  destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1));
1740  cSrcPtr += cSrcStride;
1741  ++shapePtr;
1742  continue;
1743  }
1744  lastX = x;
1745 
1746  //----- read destination pixel
1747  cDest0 = (*destColorPtr & destColorMask) ? 0xff : 0x00;
1748 
1749  //----- source color
1750  cSrc0 = state->grayTransfer[cSrcPtr[0]];
1751 
1752  //----- source alpha
1753  aSrc = div255(pipe->aInput * shape);
1754 
1755  //----- result color
1756  // note: aDest = alphaI = aResult = 0xff
1757  cResult0 = (Guchar)div255((0xff - aSrc) * cDest0 + aSrc * cSrc0);
1758 
1759  //----- write destination pixel
1760  if (state->screen->testWithCursor(screenCursor, x, cResult0)) {
1761  *destColorPtr |= destColorMask;
1762  } else {
1763  *destColorPtr &= (Guchar)~destColorMask;
1764  }
1765  destColorPtr += destColorMask & 1;
1766  destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1));
1767 
1768  cSrcPtr += cSrcStride;
1769  ++shapePtr;
1770  }
1771 
1772  updateModX(lastX);
1773 }
1774 
1775 // special case:
1776 // !pipe->pattern && !pipe->noTransparency && !state->softMask &&
1777 // pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
1778 // !pipe->nonIsolatedGroup &&
1779 // bitmap->mode == splashModeMono8 && bitmap->alpha
1781  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1782  Guchar shape, aSrc, aDest, alphaI, aResult, cSrc0, cDest0, cResult0;
1783  SplashColorPtr destColorPtr;
1784  Guchar *destAlphaPtr;
1785  int cSrcStride, x, lastX;
1786 
1787  if (cSrcPtr) {
1788  cSrcStride = 1;
1789  } else {
1790  cSrcPtr = pipe->cSrcVal;
1791  cSrcStride = 0;
1792  }
1793  for (; x0 <= x1; ++x0) {
1794  if (*shapePtr) {
1795  break;
1796  }
1797  cSrcPtr += cSrcStride;
1798  ++shapePtr;
1799  }
1800  if (x0 > x1) {
1801  return;
1802  }
1803  updateModX(x0);
1804  updateModY(y);
1805  lastX = x0;
1806 
1807  useDestRow(y);
1808 
1809  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
1810  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
1811 
1812  for (x = x0; x <= x1; ++x) {
1813 
1814  //----- shape
1815  shape = *shapePtr;
1816  if (!shape) {
1817  ++destColorPtr;
1818  ++destAlphaPtr;
1819  cSrcPtr += cSrcStride;
1820  ++shapePtr;
1821  continue;
1822  }
1823  lastX = x;
1824 
1825  //----- read destination pixel
1826  cDest0 = *destColorPtr;
1827  aDest = *destAlphaPtr;
1828 
1829  //----- source color
1830  cSrc0 = state->grayTransfer[cSrcPtr[0]];
1831 
1832  //----- source alpha
1833  aSrc = div255(pipe->aInput * shape);
1834 
1835  //----- result alpha and non-isolated group element correction
1836  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
1837  alphaI = aResult;
1838 
1839  //----- result color
1840  if (alphaI == 0) {
1841  cResult0 = 0;
1842  } else {
1843  cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
1844  }
1845 
1846  //----- write destination pixel
1847  *destColorPtr++ = cResult0;
1848  *destAlphaPtr++ = aResult;
1849 
1850  cSrcPtr += cSrcStride;
1851  ++shapePtr;
1852  }
1853 
1854  updateModX(lastX);
1855 }
1856 
1857 // special case:
1858 // !pipe->pattern && !pipe->noTransparency && !state->softMask &&
1859 // pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
1860 // !pipe->nonIsolatedGroup &&
1861 // bitmap->mode == splashModeRGB8 && bitmap->alpha
1863  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1864  Guchar shape, aSrc, aDest, alphaI, aResult;
1865  Guchar cSrc0, cSrc1, cSrc2;
1866  Guchar cDest0, cDest1, cDest2;
1867  Guchar cResult0, cResult1, cResult2;
1868  SplashColorPtr destColorPtr;
1869  Guchar *destAlphaPtr;
1870  int cSrcStride, x, lastX;
1871 
1872  if (cSrcPtr) {
1873  cSrcStride = 3;
1874  } else {
1875  cSrcPtr = pipe->cSrcVal;
1876  cSrcStride = 0;
1877  }
1878  for (; x0 <= x1; ++x0) {
1879  if (*shapePtr) {
1880  break;
1881  }
1882  cSrcPtr += cSrcStride;
1883  ++shapePtr;
1884  }
1885  if (x0 > x1) {
1886  return;
1887  }
1888  updateModX(x0);
1889  updateModY(y);
1890  lastX = x0;
1891 
1892  useDestRow(y);
1893 
1894  destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
1895  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
1896 
1897  for (x = x0; x <= x1; ++x) {
1898 
1899  //----- shape
1900  shape = *shapePtr;
1901  if (!shape) {
1902  destColorPtr += 3;
1903  ++destAlphaPtr;
1904  cSrcPtr += cSrcStride;
1905  ++shapePtr;
1906  continue;
1907  }
1908  lastX = x;
1909 
1910  //----- read destination pixel
1911  cDest0 = destColorPtr[0];
1912  cDest1 = destColorPtr[1];
1913  cDest2 = destColorPtr[2];
1914  aDest = *destAlphaPtr;
1915 
1916  //----- source color
1917  cSrc0 = state->rgbTransferR[cSrcPtr[0]];
1918  cSrc1 = state->rgbTransferG[cSrcPtr[1]];
1919  cSrc2 = state->rgbTransferB[cSrcPtr[2]];
1920 
1921  //----- source alpha
1922  aSrc = div255(pipe->aInput * shape);
1923 
1924  //----- result alpha and non-isolated group element correction
1925  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
1926  alphaI = aResult;
1927 
1928  //----- result color
1929  if (alphaI == 0) {
1930  cResult0 = 0;
1931  cResult1 = 0;
1932  cResult2 = 0;
1933  } else {
1934  cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
1935  cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
1936  cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
1937  }
1938 
1939  //----- write destination pixel
1940  destColorPtr[0] = cResult0;
1941  destColorPtr[1] = cResult1;
1942  destColorPtr[2] = cResult2;
1943  destColorPtr += 3;
1944  *destAlphaPtr++ = aResult;
1945 
1946  cSrcPtr += cSrcStride;
1947  ++shapePtr;
1948  }
1949 
1950  updateModX(lastX);
1951 }
1952 
1953 // special case:
1954 // !pipe->pattern && !pipe->noTransparency && !state->softMask &&
1955 // pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
1956 // !pipe->nonIsolatedGroup &&
1957 // bitmap->mode == splashModeBGR8 && bitmap->alpha
1959  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1960  Guchar shape, aSrc, aDest, alphaI, aResult;
1961  Guchar cSrc0, cSrc1, cSrc2;
1962  Guchar cDest0, cDest1, cDest2;
1963  Guchar cResult0, cResult1, cResult2;
1964  SplashColorPtr destColorPtr;
1965  Guchar *destAlphaPtr;
1966  int cSrcStride, x, lastX;
1967 
1968  if (cSrcPtr) {
1969  cSrcStride = 3;
1970  } else {
1971  cSrcPtr = pipe->cSrcVal;
1972  cSrcStride = 0;
1973  }
1974  for (; x0 <= x1; ++x0) {
1975  if (*shapePtr) {
1976  break;
1977  }
1978  cSrcPtr += cSrcStride;
1979  ++shapePtr;
1980  }
1981  if (x0 > x1) {
1982  return;
1983  }
1984  updateModX(x0);
1985  updateModY(y);
1986  lastX = x0;
1987 
1988  useDestRow(y);
1989 
1990  destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
1991  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
1992 
1993  for (x = x0; x <= x1; ++x) {
1994 
1995  //----- shape
1996  shape = *shapePtr;
1997  if (!shape) {
1998  destColorPtr += 3;
1999  ++destAlphaPtr;
2000  cSrcPtr += cSrcStride;
2001  ++shapePtr;
2002  continue;
2003  }
2004  lastX = x;
2005 
2006  //----- read destination pixel
2007  cDest0 = destColorPtr[2];
2008  cDest1 = destColorPtr[1];
2009  cDest2 = destColorPtr[0];
2010  aDest = *destAlphaPtr;
2011 
2012  //----- source color
2013  cSrc0 = state->rgbTransferR[cSrcPtr[0]];
2014  cSrc1 = state->rgbTransferG[cSrcPtr[1]];
2015  cSrc2 = state->rgbTransferB[cSrcPtr[2]];
2016 
2017  //----- source alpha
2018  aSrc = div255(pipe->aInput * shape);
2019 
2020  //----- result alpha and non-isolated group element correction
2021  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
2022  alphaI = aResult;
2023 
2024  //----- result color
2025  if (alphaI == 0) {
2026  cResult0 = 0;
2027  cResult1 = 0;
2028  cResult2 = 0;
2029  } else {
2030  cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
2031  cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
2032  cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
2033  }
2034 
2035  //----- write destination pixel
2036  destColorPtr[0] = cResult2;
2037  destColorPtr[1] = cResult1;
2038  destColorPtr[2] = cResult0;
2039  destColorPtr += 3;
2040  *destAlphaPtr++ = aResult;
2041 
2042  cSrcPtr += cSrcStride;
2043  ++shapePtr;
2044  }
2045 
2046  updateModX(lastX);
2047 }
2048 
2049 #if SPLASH_CMYK
2050 // special case:
2051 // !pipe->pattern && !pipe->noTransparency && !state->softMask &&
2052 // pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
2053 // !pipe->nonIsolatedGroup &&
2054 // bitmap->mode == splashModeCMYK8 && bitmap->alpha
2055 void Splash::pipeRunAACMYK8(SplashPipe *pipe, int x0, int x1, int y,
2056  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
2057  Guchar shape, aSrc, aDest, alphaI, aResult;
2058  Guchar cSrc0, cSrc1, cSrc2, cSrc3;
2059  Guchar cDest0, cDest1, cDest2, cDest3;
2060  Guchar cResult0, cResult1, cResult2, cResult3;
2061  SplashColorPtr destColorPtr;
2062  Guchar *destAlphaPtr;
2063  int cSrcStride, x, lastX;
2064 
2065  if (cSrcPtr) {
2066  cSrcStride = 4;
2067  } else {
2068  cSrcPtr = pipe->cSrcVal;
2069  cSrcStride = 0;
2070  }
2071  for (; x0 <= x1; ++x0) {
2072  if (*shapePtr) {
2073  break;
2074  }
2075  cSrcPtr += cSrcStride;
2076  ++shapePtr;
2077  }
2078  if (x0 > x1) {
2079  return;
2080  }
2081  updateModX(x0);
2082  updateModY(y);
2083  lastX = x0;
2084 
2085  useDestRow(y);
2086 
2087  destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x0];
2088  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
2089 
2090  for (x = x0; x <= x1; ++x) {
2091 
2092  //----- shape
2093  shape = *shapePtr;
2094  if (!shape) {
2095  destColorPtr += 4;
2096  ++destAlphaPtr;
2097  cSrcPtr += cSrcStride;
2098  ++shapePtr;
2099  continue;
2100  }
2101  lastX = x;
2102 
2103  //----- read destination pixel
2104  cDest0 = destColorPtr[0];
2105  cDest1 = destColorPtr[1];
2106  cDest2 = destColorPtr[2];
2107  cDest3 = destColorPtr[3];
2108  aDest = *destAlphaPtr;
2109 
2110  //----- overprint
2111  if (state->overprintMask & 1) {
2112  cSrc0 = state->cmykTransferC[cSrcPtr[0]];
2113  } else {
2114  cSrc0 = div255(aDest * cDest0);
2115  }
2116  if (state->overprintMask & 2) {
2117  cSrc1 = state->cmykTransferM[cSrcPtr[1]];
2118  } else {
2119  cSrc1 = div255(aDest * cDest1);
2120  }
2121  if (state->overprintMask & 4) {
2122  cSrc2 = state->cmykTransferY[cSrcPtr[2]];
2123  } else {
2124  cSrc2 = div255(aDest * cDest2);
2125  }
2126  if (state->overprintMask & 8) {
2127  cSrc3 = state->cmykTransferK[cSrcPtr[3]];
2128  } else {
2129  cSrc3 = div255(aDest * cDest3);
2130  }
2131 
2132  //----- source alpha
2133  aSrc = div255(pipe->aInput * shape);
2134 
2135  //----- result alpha and non-isolated group element correction
2136  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
2137  alphaI = aResult;
2138 
2139  //----- result color
2140  if (alphaI == 0) {
2141  cResult0 = 0;
2142  cResult1 = 0;
2143  cResult2 = 0;
2144  cResult3 = 0;
2145  } else {
2146  cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
2147  cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
2148  cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
2149  cResult3 = (Guchar)(((alphaI - aSrc) * cDest3 + aSrc * cSrc3) / alphaI);
2150  }
2151 
2152  //----- write destination pixel
2153  destColorPtr[0] = cResult0;
2154  destColorPtr[1] = cResult1;
2155  destColorPtr[2] = cResult2;
2156  destColorPtr[3] = cResult3;
2157  destColorPtr += 4;
2158  *destAlphaPtr++ = aResult;
2159 
2160  cSrcPtr += cSrcStride;
2161  ++shapePtr;
2162  }
2163 
2164  updateModX(lastX);
2165 }
2166 #endif
2167 
2168 
2169 // special case:
2170 // !pipe->pattern && aInput == 255 && state->softMask && usesShape &&
2171 // !state->inNonIsolatedGroup && !state->inKnockoutGroup &&
2172 // !nonIsolatedGroup && state->overprintMask == 0xffffffff &&
2173 // !state->blendFunc &&
2174 // bitmap->mode == splashModeMono8 && bitmap->alpha
2176  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
2177  Guchar shape, aSrc, aDest, alphaI, aResult;
2178  Guchar cSrc0, cDest0, cResult0;
2179  SplashColorPtr destColorPtr;
2180  Guchar *destAlphaPtr;
2181  SplashColorPtr softMaskPtr;
2182  int cSrcStride, x, lastX;
2183 
2184  if (cSrcPtr) {
2185  cSrcStride = 1;
2186  } else {
2187  cSrcPtr = pipe->cSrcVal;
2188  cSrcStride = 0;
2189  }
2190  for (; x0 <= x1; ++x0) {
2191  if (*shapePtr) {
2192  break;
2193  }
2194  cSrcPtr += cSrcStride;
2195  ++shapePtr;
2196  }
2197  if (x0 > x1) {
2198  return;
2199  }
2200  updateModX(x0);
2201  updateModY(y);
2202  lastX = x0;
2203 
2204  useDestRow(y);
2205 
2206  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
2207  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
2208  softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0];
2209 
2210  for (x = x0; x <= x1; ++x) {
2211 
2212  //----- shape
2213  shape = *shapePtr;
2214  if (!shape) {
2215  ++destColorPtr;
2216  ++destAlphaPtr;
2217  ++softMaskPtr;
2218  cSrcPtr += cSrcStride;
2219  ++shapePtr;
2220  continue;
2221  }
2222  lastX = x;
2223 
2224  //----- read source color
2225  cSrc0 = state->grayTransfer[cSrcPtr[0]];
2226 
2227  //----- source alpha
2228  aSrc = div255(*softMaskPtr++ * shape);
2229 
2230  //----- special case for aSrc = 255
2231  if (aSrc == 255) {
2232  aResult = 255;
2233  cResult0 = cSrc0;
2234  } else {
2235 
2236  //----- read destination alpha
2237  aDest = *destAlphaPtr;
2238 
2239  //----- special case for aDest = 0
2240  if (aDest == 0) {
2241  aResult = aSrc;
2242  cResult0 = cSrc0;
2243  } else {
2244 
2245  //----- read destination pixel
2246  cDest0 = destColorPtr[0];
2247 
2248  //----- result alpha and non-isolated group element correction
2249  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
2250  alphaI = aResult;
2251 
2252  //----- result color
2253  cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
2254  }
2255  }
2256 
2257  //----- write destination pixel
2258  destColorPtr[0] = cResult0;
2259  ++destColorPtr;
2260  *destAlphaPtr++ = aResult;
2261 
2262  cSrcPtr += cSrcStride;
2263  ++shapePtr;
2264  }
2265 
2266  updateModX(lastX);
2267 }
2268 
2269 // special case:
2270 // !pipe->pattern && aInput == 255 && state->softMask && usesShape &&
2271 // !state->inNonIsolatedGroup && !state->inKnockoutGroup &&
2272 // !nonIsolatedGroup && state->overprintMask == 0xffffffff &&
2273 // !state->blendFunc &&
2274 // bitmap->mode == splashModeRGB8 && bitmap->alpha
2276  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
2277  Guchar shape, aSrc, aDest, alphaI, aResult;
2278  Guchar cSrc0, cSrc1, cSrc2;
2279  Guchar cDest0, cDest1, cDest2;
2280  Guchar cResult0, cResult1, cResult2;
2281  SplashColorPtr destColorPtr;
2282  Guchar *destAlphaPtr;
2283  SplashColorPtr softMaskPtr;
2284  int cSrcStride, x, lastX;
2285 
2286  if (cSrcPtr) {
2287  cSrcStride = 3;
2288  } else {
2289  cSrcPtr = pipe->cSrcVal;
2290  cSrcStride = 0;
2291  }
2292  for (; x0 <= x1; ++x0) {
2293  if (*shapePtr) {
2294  break;
2295  }
2296  cSrcPtr += cSrcStride;
2297  ++shapePtr;
2298  }
2299  if (x0 > x1) {
2300  return;
2301  }
2302  updateModX(x0);
2303  updateModY(y);
2304  lastX = x0;
2305 
2306  useDestRow(y);
2307 
2308  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3];
2309  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
2310  softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0];
2311 
2312  for (x = x0; x <= x1; ++x) {
2313 
2314  //----- shape
2315  shape = *shapePtr;
2316  if (!shape) {
2317  destColorPtr += 3;
2318  ++destAlphaPtr;
2319  ++softMaskPtr;
2320  cSrcPtr += cSrcStride;
2321  ++shapePtr;
2322  continue;
2323  }
2324  lastX = x;
2325 
2326  //----- read source color
2327  cSrc0 = state->rgbTransferR[cSrcPtr[0]];
2328  cSrc1 = state->rgbTransferG[cSrcPtr[1]];
2329  cSrc2 = state->rgbTransferB[cSrcPtr[2]];
2330 
2331  //----- source alpha
2332  aSrc = div255(*softMaskPtr++ * shape);
2333 
2334  //----- special case for aSrc = 255
2335  if (aSrc == 255) {
2336  aResult = 255;
2337  cResult0 = cSrc0;
2338  cResult1 = cSrc1;
2339  cResult2 = cSrc2;
2340  } else {
2341 
2342  //----- read destination alpha
2343  aDest = *destAlphaPtr;
2344 
2345  //----- special case for aDest = 0
2346  if (aDest == 0) {
2347  aResult = aSrc;
2348  cResult0 = cSrc0;
2349  cResult1 = cSrc1;
2350  cResult2 = cSrc2;
2351  } else {
2352 
2353  //----- read destination pixel
2354  cDest0 = destColorPtr[0];
2355  cDest1 = destColorPtr[1];
2356  cDest2 = destColorPtr[2];
2357 
2358  //----- result alpha and non-isolated group element correction
2359  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
2360  alphaI = aResult;
2361 
2362  //----- result color
2363  cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
2364  cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
2365  cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
2366  }
2367  }
2368 
2369  //----- write destination pixel
2370  destColorPtr[0] = cResult0;
2371  destColorPtr[1] = cResult1;
2372  destColorPtr[2] = cResult2;
2373  destColorPtr += 3;
2374  *destAlphaPtr++ = aResult;
2375 
2376  cSrcPtr += cSrcStride;
2377  ++shapePtr;
2378  }
2379 
2380  updateModX(lastX);
2381 }
2382 
2383 // special case:
2384 // !pipe->pattern && aInput == 255 && state->softMask && usesShape &&
2385 // !state->inNonIsolatedGroup && !state->inKnockoutGroup &&
2386 // !nonIsolatedGroup && state->overprintMask == 0xffffffff &&
2387 // !state->blendFunc &&
2388 // bitmap->mode == splashModeBGR8 && bitmap->alpha
2390  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
2391  Guchar shape, aSrc, aDest, alphaI, aResult;
2392  Guchar cSrc0, cSrc1, cSrc2;
2393  Guchar cDest0, cDest1, cDest2;
2394  Guchar cResult0, cResult1, cResult2;
2395  SplashColorPtr destColorPtr;
2396  Guchar *destAlphaPtr;
2397  SplashColorPtr softMaskPtr;
2398  int cSrcStride, x, lastX;
2399 
2400  if (cSrcPtr) {
2401  cSrcStride = 3;
2402  } else {
2403  cSrcPtr = pipe->cSrcVal;
2404  cSrcStride = 0;
2405  }
2406  for (; x0 <= x1; ++x0) {
2407  if (*shapePtr) {
2408  break;
2409  }
2410  cSrcPtr += cSrcStride;
2411  ++shapePtr;
2412  }
2413  if (x0 > x1) {
2414  return;
2415  }
2416  updateModX(x0);
2417  updateModY(y);
2418  lastX = x0;
2419 
2420  useDestRow(y);
2421 
2422  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3];
2423  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
2424  softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0];
2425 
2426  for (x = x0; x <= x1; ++x) {
2427 
2428  //----- shape
2429  shape = *shapePtr;
2430  if (!shape) {
2431  destColorPtr += 3;
2432  ++destAlphaPtr;
2433  ++softMaskPtr;
2434  cSrcPtr += cSrcStride;
2435  ++shapePtr;
2436  continue;
2437  }
2438  lastX = x;
2439 
2440  //----- read source color
2441  cSrc0 = state->rgbTransferR[cSrcPtr[0]];
2442  cSrc1 = state->rgbTransferG[cSrcPtr[1]];
2443  cSrc2 = state->rgbTransferB[cSrcPtr[2]];
2444 
2445  //----- source alpha
2446  aSrc = div255(*softMaskPtr++ * shape);
2447 
2448  //----- special case for aSrc = 255
2449  if (aSrc == 255) {
2450  aResult = 255;
2451  cResult0 = cSrc0;
2452  cResult1 = cSrc1;
2453  cResult2 = cSrc2;
2454  } else {
2455 
2456  //----- read destination alpha
2457  aDest = *destAlphaPtr;
2458 
2459  //----- special case for aDest = 0
2460  if (aDest == 0) {
2461  aResult = aSrc;
2462  cResult0 = cSrc0;
2463  cResult1 = cSrc1;
2464  cResult2 = cSrc2;
2465  } else {
2466 
2467  //----- read destination pixel
2468  cDest0 = destColorPtr[2];
2469  cDest1 = destColorPtr[1];
2470  cDest2 = destColorPtr[0];
2471 
2472  //----- result alpha and non-isolated group element correction
2473  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
2474  alphaI = aResult;
2475 
2476  //----- result color
2477  cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
2478  cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
2479  cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
2480  }
2481  }
2482 
2483  //----- write destination pixel
2484  destColorPtr[2] = cResult0;
2485  destColorPtr[1] = cResult1;
2486  destColorPtr[0] = cResult2;
2487  destColorPtr += 3;
2488  *destAlphaPtr++ = aResult;
2489 
2490  cSrcPtr += cSrcStride;
2491  ++shapePtr;
2492  }
2493 
2494  updateModX(lastX);
2495 }
2496 
2497 #if SPLASH_CMYK
2498 // special case:
2499 // !pipe->pattern && aInput == 255 && state->softMask && usesShape &&
2500 // !state->inNonIsolatedGroup && !state->inKnockoutGroup &&
2501 // !nonIsolatedGroup && state->overprintMask == 0xffffffff &&
2502 // !state->blendFunc &&
2503 // bitmap->mode == splashModeCMYK8 && bitmap->alpha
2504 void Splash::pipeRunSoftMaskCMYK8(SplashPipe *pipe, int x0, int x1, int y,
2505  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
2506  Guchar shape, aSrc, aDest, alphaI, aResult;
2507  Guchar cSrc0, cSrc1, cSrc2, cSrc3;
2508  Guchar cDest0, cDest1, cDest2, cDest3;
2509  Guchar cResult0, cResult1, cResult2, cResult3;
2510  SplashColorPtr destColorPtr;
2511  Guchar *destAlphaPtr;
2512  SplashColorPtr softMaskPtr;
2513  int cSrcStride, x, lastX;
2514 
2515  if (cSrcPtr) {
2516  cSrcStride = 4;
2517  } else {
2518  cSrcPtr = pipe->cSrcVal;
2519  cSrcStride = 0;
2520  }
2521  for (; x0 <= x1; ++x0) {
2522  if (*shapePtr) {
2523  break;
2524  }
2525  cSrcPtr += cSrcStride;
2526  ++shapePtr;
2527  }
2528  if (x0 > x1) {
2529  return;
2530  }
2531  updateModX(x0);
2532  updateModY(y);
2533  lastX = x0;
2534 
2535  useDestRow(y);
2536 
2537  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 4];
2538  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
2539  softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0];
2540 
2541  for (x = x0; x <= x1; ++x) {
2542 
2543  //----- shape
2544  shape = *shapePtr;
2545  if (!shape) {
2546  destColorPtr += 4;
2547  ++destAlphaPtr;
2548  ++softMaskPtr;
2549  cSrcPtr += cSrcStride;
2550  ++shapePtr;
2551  continue;
2552  }
2553  lastX = x;
2554 
2555  //----- read destination pixel
2556  cDest0 = destColorPtr[0];
2557  cDest1 = destColorPtr[1];
2558  cDest2 = destColorPtr[2];
2559  cDest3 = destColorPtr[3];
2560 
2561  //----- read destination alpha
2562  aDest = *destAlphaPtr;
2563 
2564  //----- overprint
2565  cSrc0 = state->cmykTransferC[cSrcPtr[0]];
2566  cSrc1 = state->cmykTransferM[cSrcPtr[1]];
2567  cSrc2 = state->cmykTransferY[cSrcPtr[2]];
2568  cSrc3 = state->cmykTransferK[cSrcPtr[3]];
2569 
2570  //----- source alpha
2571  aSrc = div255(*softMaskPtr++ * shape);
2572 
2573  //----- special case for aSrc = 255
2574  if (aSrc == 255) {
2575  aResult = 255;
2576  cResult0 = cSrc0;
2577  cResult1 = cSrc1;
2578  cResult2 = cSrc2;
2579  cResult3 = cSrc3;
2580  } else {
2581 
2582  //----- special case for aDest = 0
2583  if (aDest == 0) {
2584  aResult = aSrc;
2585  cResult0 = cSrc0;
2586  cResult1 = cSrc1;
2587  cResult2 = cSrc2;
2588  cResult3 = cSrc3;
2589  } else {
2590 
2591  //----- result alpha and non-isolated group element correction
2592  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
2593  alphaI = aResult;
2594 
2595  //----- result color
2596  cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
2597  cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
2598  cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
2599  cResult3 = (Guchar)(((alphaI - aSrc) * cDest3 + aSrc * cSrc3) / alphaI);
2600  }
2601  }
2602 
2603  //----- write destination pixel
2604  destColorPtr[0] = cResult0;
2605  destColorPtr[1] = cResult1;
2606  destColorPtr[2] = cResult2;
2607  destColorPtr[3] = cResult3;
2608  destColorPtr += 4;
2609  *destAlphaPtr++ = aResult;
2610 
2611  cSrcPtr += cSrcStride;
2612  ++shapePtr;
2613  }
2614 
2615  updateModX(lastX);
2616 }
2617 #endif
2618 
2619 
2621  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
2622  Guchar shape, aSrc, aDest, alphaI, alpha0, aResult;
2623  Guchar cSrc0, cDest0, cResult0;
2624  SplashColorPtr destColorPtr;
2625  Guchar *destAlphaPtr;
2626  Guchar *alpha0Ptr;
2627  int cSrcStride, x, lastX;
2628 
2629  if (cSrcPtr) {
2630  cSrcStride = 1;
2631  } else {
2632  cSrcPtr = pipe->cSrcVal;
2633  cSrcStride = 0;
2634  }
2635  for (; x0 <= x1; ++x0) {
2636  if (*shapePtr) {
2637  break;
2638  }
2639  cSrcPtr += cSrcStride;
2640  ++shapePtr;
2641  }
2642  if (x0 > x1) {
2643  return;
2644  }
2645  updateModX(x0);
2646  updateModY(y);
2647  lastX = x0;
2648 
2649  useDestRow(y);
2650 
2651  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
2652  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
2653  alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y)
2655  (groupBackX + x0)];
2656 
2657  for (x = x0; x <= x1; ++x) {
2658 
2659  //----- shape
2660  shape = *shapePtr;
2661  if (!shape) {
2662  destColorPtr += 1;
2663  ++destAlphaPtr;
2664  ++alpha0Ptr;
2665  cSrcPtr += cSrcStride;
2666  ++shapePtr;
2667  continue;
2668  }
2669  lastX = x;
2670 
2671  //----- read destination pixel
2672  cDest0 = destColorPtr[0];
2673  aDest = *destAlphaPtr;
2674 
2675  //----- source color
2676  cSrc0 = state->grayTransfer[cSrcPtr[0]];
2677 
2678  //----- source alpha
2679  aSrc = div255(pipe->aInput * shape);
2680 
2681  //----- result alpha and non-isolated group element correction
2682  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
2683  alpha0 = *alpha0Ptr++;
2684  alphaI = (Guchar)(aResult + alpha0 - div255(aResult * alpha0));
2685 
2686  //----- result color
2687  if (alphaI == 0) {
2688  cResult0 = 0;
2689  } else {
2690  cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
2691  }
2692 
2693  //----- write destination pixel
2694  *destColorPtr++ = cResult0;
2695  *destAlphaPtr++ = aResult;
2696 
2697  cSrcPtr += cSrcStride;
2698  ++shapePtr;
2699  } // for (x ...)
2700 
2701  updateModX(lastX);
2702 }
2703 
2705  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
2706  Guchar shape, aSrc, aDest, alphaI, alpha0, aResult;
2707  Guchar cSrc0, cSrc1, cSrc2;
2708  Guchar cDest0, cDest1, cDest2;
2709  Guchar cResult0, cResult1, cResult2;
2710  SplashColorPtr destColorPtr;
2711  Guchar *destAlphaPtr;
2712  Guchar *alpha0Ptr;
2713  int cSrcStride, x, lastX;
2714 
2715  if (cSrcPtr) {
2716  cSrcStride = 3;
2717  } else {
2718  cSrcPtr = pipe->cSrcVal;
2719  cSrcStride = 0;
2720  }
2721  for (; x0 <= x1; ++x0) {
2722  if (*shapePtr) {
2723  break;
2724  }
2725  cSrcPtr += cSrcStride;
2726  ++shapePtr;
2727  }
2728  if (x0 > x1) {
2729  return;
2730  }
2731  updateModX(x0);
2732  updateModY(y);
2733  lastX = x0;
2734 
2735  useDestRow(y);
2736 
2737  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3];
2738  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
2739  alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y)
2741  (groupBackX + x0)];
2742 
2743  for (x = x0; x <= x1; ++x) {
2744 
2745  //----- shape
2746  shape = *shapePtr;
2747  if (!shape) {
2748  destColorPtr += 3;
2749  ++destAlphaPtr;
2750  ++alpha0Ptr;
2751  cSrcPtr += cSrcStride;
2752  ++shapePtr;
2753  continue;
2754  }
2755  lastX = x;
2756 
2757  //----- read destination pixel
2758  cDest0 = destColorPtr[0];
2759  cDest1 = destColorPtr[1];
2760  cDest2 = destColorPtr[2];
2761  aDest = *destAlphaPtr;
2762 
2763  //----- source color
2764  cSrc0 = state->rgbTransferR[cSrcPtr[0]];
2765  cSrc1 = state->rgbTransferG[cSrcPtr[1]];
2766  cSrc2 = state->rgbTransferB[cSrcPtr[2]];
2767 
2768  //----- source alpha
2769  aSrc = div255(pipe->aInput * shape);
2770 
2771  //----- result alpha and non-isolated group element correction
2772  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
2773  alpha0 = *alpha0Ptr++;
2774  alphaI = (Guchar)(aResult + alpha0 - div255(aResult * alpha0));
2775 
2776  //----- result color
2777  if (alphaI == 0) {
2778  cResult0 = 0;
2779  cResult1 = 0;
2780  cResult2 = 0;
2781  } else {
2782  cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
2783  cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
2784  cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
2785  }
2786 
2787  //----- write destination pixel
2788  destColorPtr[0] = cResult0;
2789  destColorPtr[1] = cResult1;
2790  destColorPtr[2] = cResult2;
2791  destColorPtr += 3;
2792  *destAlphaPtr++ = aResult;
2793 
2794  cSrcPtr += cSrcStride;
2795  ++shapePtr;
2796  } // for (x ...)
2797 
2798  updateModX(lastX);
2799 }
2800 
2802  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
2803  Guchar shape, aSrc, aDest, alphaI, alpha0, aResult;
2804  Guchar cSrc0, cSrc1, cSrc2;
2805  Guchar cDest0, cDest1, cDest2;
2806  Guchar cResult0, cResult1, cResult2;
2807  SplashColorPtr destColorPtr;
2808  Guchar *destAlphaPtr;
2809  Guchar *alpha0Ptr;
2810  int cSrcStride, x, lastX;
2811 
2812  if (cSrcPtr) {
2813  cSrcStride = 3;
2814  } else {
2815  cSrcPtr = pipe->cSrcVal;
2816  cSrcStride = 0;
2817  }
2818  for (; x0 <= x1; ++x0) {
2819  if (*shapePtr) {
2820  break;
2821  }
2822  cSrcPtr += cSrcStride;
2823  ++shapePtr;
2824  }
2825  if (x0 > x1) {
2826  return;
2827  }
2828  updateModX(x0);
2829  updateModY(y);
2830  lastX = x0;
2831 
2832  useDestRow(y);
2833 
2834  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3];
2835  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
2836  alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y)
2838  (groupBackX + x0)];
2839 
2840  for (x = x0; x <= x1; ++x) {
2841 
2842  //----- shape
2843  shape = *shapePtr;
2844  if (!shape) {
2845  destColorPtr += 3;
2846  ++destAlphaPtr;
2847  ++alpha0Ptr;
2848  cSrcPtr += cSrcStride;
2849  ++shapePtr;
2850  continue;
2851  }
2852  lastX = x;
2853 
2854  //----- read destination pixel
2855  cDest0 = destColorPtr[2];
2856  cDest1 = destColorPtr[1];
2857  cDest2 = destColorPtr[0];
2858  aDest = *destAlphaPtr;
2859 
2860  //----- source color
2861  cSrc0 = state->rgbTransferR[cSrcPtr[0]];
2862  cSrc1 = state->rgbTransferG[cSrcPtr[1]];
2863  cSrc2 = state->rgbTransferB[cSrcPtr[2]];
2864 
2865  //----- source alpha
2866  aSrc = div255(pipe->aInput * shape);
2867 
2868  //----- result alpha and non-isolated group element correction
2869  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
2870  alpha0 = *alpha0Ptr++;
2871  alphaI = (Guchar)(aResult + alpha0 - div255(aResult * alpha0));
2872 
2873  //----- result color
2874  if (alphaI == 0) {
2875  cResult0 = 0;
2876  cResult1 = 0;
2877  cResult2 = 0;
2878  } else {
2879  cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
2880  cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
2881  cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
2882  }
2883 
2884  //----- write destination pixel
2885  destColorPtr[0] = cResult2;
2886  destColorPtr[1] = cResult1;
2887  destColorPtr[2] = cResult0;
2888  destColorPtr += 3;
2889  *destAlphaPtr++ = aResult;
2890 
2891  cSrcPtr += cSrcStride;
2892  ++shapePtr;
2893  } // for (x ...)
2894 
2895  updateModX(lastX);
2896 }
2897 
2898 #if SPLASH_CMYK
2899 void Splash::pipeRunNonIsoCMYK8(SplashPipe *pipe, int x0, int x1, int y,
2900  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
2901  Guchar shape, aSrc, aDest, alphaI, alpha0, aResult, aPrev;
2902  Guchar cSrc0, cSrc1, cSrc2, cSrc3;
2903  Guchar cDest0, cDest1, cDest2, cDest3;
2904  Guchar cResult0, cResult1, cResult2, cResult3;
2905  SplashColorPtr destColorPtr;
2906  Guchar *destAlphaPtr;
2907  Guchar *alpha0Ptr;
2908  int cSrcStride, x, lastX;
2909 
2910  if (cSrcPtr) {
2911  cSrcStride = 4;
2912  } else {
2913  cSrcPtr = pipe->cSrcVal;
2914  cSrcStride = 0;
2915  }
2916  for (; x0 <= x1; ++x0) {
2917  if (*shapePtr) {
2918  break;
2919  }
2920  cSrcPtr += cSrcStride;
2921  ++shapePtr;
2922  }
2923  if (x0 > x1) {
2924  return;
2925  }
2926  updateModX(x0);
2927  updateModY(y);
2928  lastX = x0;
2929 
2930  useDestRow(y);
2931 
2932  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 4];
2933  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
2934  alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y)
2936  (groupBackX + x0)];
2937 
2938  for (x = x0; x <= x1; ++x) {
2939 
2940  //----- shape
2941  shape = *shapePtr;
2942  if (!shape) {
2943  destColorPtr += 4;
2944  ++destAlphaPtr;
2945  ++alpha0Ptr;
2946  cSrcPtr += cSrcStride;
2947  ++shapePtr;
2948  continue;
2949  }
2950  lastX = x;
2951 
2952  //----- read destination pixel
2953  cDest0 = destColorPtr[0];
2954  cDest1 = destColorPtr[1];
2955  cDest2 = destColorPtr[2];
2956  cDest3 = destColorPtr[3];
2957  aDest = *destAlphaPtr;
2958 
2959  //----- overprint
2960  aPrev = (Guchar)(*alpha0Ptr + aDest - div255(*alpha0Ptr * aDest));
2961  if (state->overprintMask & 0x01) {
2962  cSrc0 = state->cmykTransferC[cSrcPtr[0]];
2963  } else {
2964  cSrc0 = div255(aPrev * cDest0);
2965  }
2966  if (state->overprintMask & 0x02) {
2967  cSrc1 = state->cmykTransferM[cSrcPtr[1]];
2968  } else {
2969  cSrc1 = div255(aPrev * cDest1);
2970  }
2971  if (state->overprintMask & 0x04) {
2972  cSrc2 = state->cmykTransferY[cSrcPtr[2]];
2973  } else {
2974  cSrc2 = div255(aPrev * cDest2);
2975  }
2976  if (state->overprintMask & 0x08) {
2977  cSrc3 = state->cmykTransferK[cSrcPtr[3]];
2978  } else {
2979  cSrc3 = div255(aPrev * cDest3);
2980  }
2981 
2982  //----- source alpha
2983  aSrc = div255(pipe->aInput * shape);
2984 
2985  //----- result alpha and non-isolated group element correction
2986  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
2987  alpha0 = *alpha0Ptr++;
2988  alphaI = (Guchar)(aResult + alpha0 - div255(aResult * alpha0));
2989 
2990  //----- result color
2991  if (alphaI == 0) {
2992  cResult0 = 0;
2993  cResult1 = 0;
2994  cResult2 = 0;
2995  cResult3 = 0;
2996  } else {
2997  cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
2998  cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
2999  cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
3000  cResult3 = (Guchar)(((alphaI - aSrc) * cDest3 + aSrc * cSrc3) / alphaI);
3001  }
3002 
3003  //----- write destination pixel
3004  destColorPtr[0] = cResult0;
3005  destColorPtr[1] = cResult1;
3006  destColorPtr[2] = cResult2;
3007  destColorPtr[3] = cResult3;
3008  destColorPtr += 4;
3009  *destAlphaPtr++ = aResult;
3010 
3011  cSrcPtr += cSrcStride;
3012  ++shapePtr;
3013  } // for (x ...)
3014 
3015  updateModX(lastX);
3016 }
3017 #endif
3018 
3019 
3021  int y0, y1, yy;
3022 
3024  return;
3025  }
3027  y0 = y1 = y;
3029  } else if (y < groupDestInitYMin) {
3030  y0 = y;
3031  y1 = groupDestInitYMin - 1;
3032  groupDestInitYMin = y;
3033  } else if (y > groupDestInitYMax) {
3034  y0 = groupDestInitYMax + 1;
3035  y1 = y;
3036  groupDestInitYMax = y;
3037  } else {
3038  return;
3039  }
3040  for (yy = y0; yy <= y1; ++yy) {
3042  // same as clear(color=0, alpha=0)
3043  memset(bitmap->data + bitmap->rowSize * yy, 0,
3044  bitmap->rowSize < 0 ? -bitmap->rowSize : bitmap->rowSize);
3045  if (bitmap->alpha) {
3046  memset(bitmap->alpha + bitmap->alphaRowSize * yy, 0,
3047  bitmap->alphaRowSize);
3048  }
3049  } else { // (groupDestInitMode == splashGroupDestInitCopy)
3050  // same as blitTransparent
3052  }
3053  }
3054 }
3055 
3057  SplashColorPtr p, q;
3058  Guchar mask, srcMask;
3059  int x;
3060 
3061  if (groupBackBitmap->mode != bitmap->mode) {
3062  return;
3063  }
3064 
3065  if (bitmap->mode == splashModeMono1) {
3066  p = &bitmap->data[y * bitmap->rowSize];
3067  mask = (Guchar)0x80;
3069  + (groupBackX >> 3)];
3070  srcMask = (Guchar)(0x80 >> (groupBackX & 7));
3071  for (x = 0; x < bitmap->width; ++x) {
3072  if (*q & srcMask) {
3073  *p |= mask;
3074  } else {
3075  *p &= (Guchar)~mask;
3076  }
3077  if (!(mask = (Guchar)(mask >> 1))) {
3078  mask = 0x80;
3079  ++p;
3080  }
3081  if (!(srcMask = (Guchar)(srcMask >> 1))) {
3082  srcMask = 0x80;
3083  ++q;
3084  }
3085  }
3086  } else {
3087  p = &bitmap->data[y * bitmap->rowSize];
3089  + bitmapComps * groupBackX];
3090  memcpy(p, q, bitmapComps * bitmap->width);
3091  }
3092 
3093  if (bitmap->alpha) {
3094  memset(&bitmap->alpha[y * bitmap->alphaRowSize], 0, bitmap->width);
3095  }
3096 }
3097 
3098 //------------------------------------------------------------------------
3099 
3100 // Transform a point from user space to device space.
3102  SplashCoord xi, SplashCoord yi,
3103  SplashCoord *xo, SplashCoord *yo) {
3104  // [ m[0] m[1] 0 ]
3105  // [xo yo 1] = [xi yi 1] * [ m[2] m[3] 0 ]
3106  // [ m[4] m[5] 1 ]
3107  *xo = xi * matrix[0] + yi * matrix[2] + matrix[4];
3108  *yo = xi * matrix[1] + yi * matrix[3] + matrix[5];
3109 }
3110 
3111 //------------------------------------------------------------------------
3112 // SplashImageCache
3113 //------------------------------------------------------------------------
3114 
3116  tag = NULL;
3117  width = 0;
3118  height = 0;
3119  mode = splashModeRGB8;
3120  alpha = gFalse;
3121  interpolate = gFalse;
3122  colorData = NULL;
3123  alphaData = NULL;
3124  refCount = 1;
3125 }
3126 
3128  if (tag) {
3129  delete tag;
3130  }
3131  gfree(colorData);
3132  gfree(alphaData);
3133 }
3134 
3135 GBool SplashImageCache::match(GString *aTag, int aWidth, int aHeight,
3136  SplashColorMode aMode, GBool aAlpha,
3137  GBool aInterpolate) {
3138  return aTag && tag && !aTag->cmp(tag) &&
3139  aWidth == width && aHeight == height &&
3140  aMode == mode && aAlpha == alpha &&
3141  aInterpolate == interpolate;
3142 }
3143 
3144 void SplashImageCache::reset(GString *aTag, int aWidth, int aHeight,
3145  SplashColorMode aMode, GBool aAlpha,
3146  GBool aInterpolate) {
3147  if (tag) {
3148  delete tag;
3149  }
3150  if (aTag) {
3151  tag = aTag->copy();
3152  } else {
3153  tag = NULL;
3154  }
3155  width = aWidth;
3156  height = aHeight;
3157  mode = aMode;
3158  alpha = aAlpha;
3159  interpolate = aInterpolate;
3160  gfree(colorData);
3161  colorData = NULL;
3162  gfree(alphaData);
3163  alphaData = NULL;
3164 }
3165 
3167  ++refCount;
3168 }
3169 
3171  --refCount;
3172  if (refCount == 0) {
3173  delete this;
3174  }
3175 }
3176 
3177 //------------------------------------------------------------------------
3178 // ImageScaler
3179 //------------------------------------------------------------------------
3180 
3181 // Abstract base class.
3183 public:
3184 
3186  virtual ~ImageScaler() {}
3187 
3188  // Compute the next line of the scaled image. This can be called up
3189  // to [scaledHeight] times.
3190  virtual void nextLine() = 0;
3191 
3192  // Retrieve the color and alpha data generated by the most recent
3193  // call to nextLine().
3194  virtual Guchar *colorData() = 0;
3195  virtual Guchar *alphaData() = 0;
3196 };
3197 
3198 //------------------------------------------------------------------------
3199 // BasicImageScaler
3200 //------------------------------------------------------------------------
3201 
3202 // The actual image scaler.
3204 public:
3205 
3206  BasicImageScaler(SplashImageSource aSrc, void *aSrcData,
3207  int aSrcWidth, int aSrcHeight, int aNComps, GBool aHasAlpha,
3208  int aScaledWidth, int aScaledHeight, GBool aInterpolate);
3209  virtual ~BasicImageScaler();
3210  virtual void nextLine();
3211  virtual Guchar *colorData() { return colorLine; }
3212  virtual Guchar *alphaData() { return alphaLine; }
3213 
3214 protected:
3215 
3223 
3224  // source image data function
3226  void *srcData;
3227 
3228  // source image size
3231 
3232  // scaled image size
3235 
3236  // number of color and alpha components
3237  int nComps;
3239 
3240  // params/state for vertical scaling
3241  int yp, yq;
3242  int yt, yn;
3245 
3246  // params for horizontal scaling
3247  int xp, xq;
3249 
3250  // scaling function
3252 
3253  // temporary buffers for vertical scaling
3262 
3263  // output of horizontal scaling
3266 };
3267 
3269  int aSrcWidth, int aSrcHeight,
3270  int aNComps, GBool aHasAlpha,
3271  int aScaledWidth, int aScaledHeight,
3272  GBool aInterpolate) {
3273  colorTmpBuf0 = NULL;
3274  colorTmpBuf1 = NULL;
3275  colorTmpBuf2 = NULL;
3276  alphaTmpBuf0 = NULL;
3277  alphaTmpBuf1 = NULL;
3278  alphaTmpBuf2 = NULL;
3279  colorAccBuf = NULL;
3280  alphaAccBuf = NULL;
3281  colorLine = NULL;
3282  alphaLine = NULL;
3283 
3284  src = aSrc;
3285  srcData = aSrcData;
3286  srcWidth = aSrcWidth;
3287  srcHeight = aSrcHeight;
3288  scaledWidth = aScaledWidth;
3289  scaledHeight = aScaledHeight;
3290  nComps = aNComps;
3291  hasAlpha = aHasAlpha;
3292 
3293  // select scaling function; allocate buffers
3294  if (scaledHeight <= srcHeight) {
3295  // vertical downscaling
3298  yt = 0;
3300  colorAccBuf = (Guint *)gmallocn(srcWidth, nComps * (int)sizeof(Guint));
3301  if (hasAlpha) {
3303  alphaAccBuf = (Guint *)gmallocn(srcWidth, sizeof(Guint));
3304  }
3305  if (scaledWidth <= srcWidth) {
3307  } else {
3308  if (aInterpolate) {
3310  } else {
3312  }
3313  }
3314  } else {
3315  // vertical upscaling
3318  yt = 0;
3319  yn = 0;
3320  if (aInterpolate) {
3324  if (hasAlpha) {
3327  }
3328  ySrcCur = 0;
3329  yScaledCur = 0;
3330  if (scaledWidth <= srcWidth) {
3332  } else {
3334  if (hasAlpha) {
3336  }
3338  }
3339  } else {
3341  if (hasAlpha) {
3343  }
3344  if (scaledWidth <= srcWidth) {
3346  } else {
3348  }
3349  }
3350  }
3351  if (scaledWidth <= srcWidth) {
3352  xp = srcWidth / scaledWidth;
3353  xq = srcWidth % scaledWidth;
3354  } else {
3355  xp = scaledWidth / srcWidth;
3356  xq = scaledWidth % srcWidth;
3357  if (aInterpolate) {
3359  }
3360  }
3362  if (hasAlpha) {
3364  }
3365 }
3366 
3374  gfree(colorAccBuf);
3375  gfree(alphaAccBuf);
3376  gfree(colorLine);
3377  gfree(alphaLine);
3378 }
3379 
3381  (this->*scalingFunc)();
3382 }
3383 
3385  //--- vert downscale
3386  int yStep = yp;
3387  yt += yq;
3388  if (yt >= scaledHeight) {
3389  yt -= scaledHeight;
3390  ++yStep;
3391  }
3392  memset(colorAccBuf, 0, (srcWidth * nComps) * sizeof(Guint));
3393  if (hasAlpha) {
3394  memset(alphaAccBuf, 0, srcWidth * sizeof(Guint));
3395  }
3396  int nRowComps = srcWidth * nComps;
3397  for (int i = 0; i < yStep; ++i) {
3398  (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
3399  for (int j = 0; j < nRowComps; ++j) {
3400  colorAccBuf[j] += colorTmpBuf0[j];
3401  }
3402  if (hasAlpha) {
3403  for (int j = 0; j < srcWidth; ++j) {
3404  alphaAccBuf[j] += alphaTmpBuf0[j];
3405  }
3406  }
3407  }
3408 
3409  //--- horiz downscale
3410  int colorAcc[splashMaxColorComps];
3411  int xt = 0;
3412  int unscaledColorIdx = 0;
3413  int unscaledAlphaIdx = 0;
3414  int scaledColorIdx = 0;
3415 
3416  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
3417  int xStep = xp;
3418  xt += xq;
3419  if (xt >= scaledWidth) {
3420  xt -= scaledWidth;
3421  ++xStep;
3422  }
3423 
3424  for (int j = 0; j < nComps; ++j) {
3425  colorAcc[j] = 0;
3426  }
3427  for (int i = 0; i < xStep; ++i) {
3428  for (int j = 0; j < nComps; ++j) {
3429  colorAcc[j] += colorAccBuf[unscaledColorIdx + j];
3430  }
3431  unscaledColorIdx += nComps;
3432  }
3433  int nPixels = yStep * xStep;
3434  for (int j = 0; j < nComps; ++j) {
3435  colorLine[scaledColorIdx + j] = (Guchar)(colorAcc[j] / nPixels);
3436  }
3437  scaledColorIdx += nComps;
3438 
3439  if (hasAlpha) {
3440  int alphaAcc = 0;
3441  for (int i = 0; i < xStep; ++i) {
3442  alphaAcc += alphaAccBuf[unscaledAlphaIdx];
3443  ++unscaledAlphaIdx;
3444  }
3445  alphaLine[scaledIdx] = (Guchar)(alphaAcc / nPixels);
3446  }
3447  }
3448 }
3449 
3451  //--- vert downscale
3452  int yStep = yp;
3453  yt += yq;
3454  if (yt >= scaledHeight) {
3455  yt -= scaledHeight;
3456  ++yStep;
3457  }
3458  memset(colorAccBuf, 0, (srcWidth * nComps) * sizeof(Guint));
3459  if (hasAlpha) {
3460  memset(alphaAccBuf, 0, srcWidth * sizeof(Guint));
3461  }
3462  int nRowComps = srcWidth * nComps;
3463  for (int i = 0; i < yStep; ++i) {
3464  (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
3465  for (int j = 0; j < nRowComps; ++j) {
3466  colorAccBuf[j] += colorTmpBuf0[j];
3467  }
3468  if (hasAlpha) {
3469  for (int j = 0; j < srcWidth; ++j) {
3470  alphaAccBuf[j] += alphaTmpBuf0[j];
3471  }
3472  }
3473  }
3474 
3475  //--- horiz upscale
3476  Guchar colorBuf[splashMaxColorComps];
3477  int xt = 0;
3478  int scaledColorIdx = 0;
3479  int srcColorIdx = 0;
3480  int scaledAlphaIdx = 0;
3481  for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
3482  int xStep = xp;
3483  xt += xq;
3484  if (xt >= srcWidth) {
3485  xt -= srcWidth;
3486  ++xStep;
3487  }
3488  for (int j = 0; j < nComps; ++j) {
3489  colorBuf[j] = (Guchar)(colorAccBuf[srcColorIdx + j] / yStep);
3490  }
3491  srcColorIdx += nComps;
3492  for (int i = 0; i < xStep; ++i) {
3493  for (int j = 0; j < nComps; ++j) {
3494  colorLine[scaledColorIdx + j] = colorBuf[j];
3495  }
3496  scaledColorIdx += nComps;
3497  }
3498  if (hasAlpha) {
3499  Guchar alphaBuf = (Guchar)(alphaAccBuf[srcIdx] / yStep);
3500  for (int i = 0; i < xStep; ++i) {
3501  alphaLine[scaledAlphaIdx] = alphaBuf;
3502  ++scaledAlphaIdx;
3503  }
3504  }
3505  }
3506 }
3507 
3509  //--- vert downscale
3510  int yStep = yp;
3511  yt += yq;
3512  if (yt >= scaledHeight) {
3513  yt -= scaledHeight;
3514  ++yStep;
3515  }
3516  memset(colorAccBuf, 0, (srcWidth * nComps) * sizeof(Guint));
3517  if (hasAlpha) {
3518  memset(alphaAccBuf, 0, srcWidth * sizeof(Guint));
3519  }
3520  int nRowComps = srcWidth * nComps;
3521  for (int i = 0; i < yStep; ++i) {
3522  (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
3523  for (int j = 0; j < nRowComps; ++j) {
3524  colorAccBuf[j] += colorTmpBuf0[j];
3525  }
3526  if (hasAlpha) {
3527  for (int j = 0; j < srcWidth; ++j) {
3528  alphaAccBuf[j] += alphaTmpBuf0[j];
3529  }
3530  }
3531  }
3532  for (int j = 0; j < srcWidth * nComps; ++j) {
3533  colorAccBuf[j] /= yStep;
3534  }
3535  if (hasAlpha) {
3536  for (int j = 0; j < srcWidth; ++j) {
3537  alphaAccBuf[j] /= yStep;
3538  }
3539  }
3540 
3541  //--- horiz upscale
3542  int scaledColorIdx = 0;
3543  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
3544  SplashCoord xs = ((SplashCoord)scaledIdx + 0.5) * xInvScale;
3545  int x0 = splashFloor(xs - 0.5);
3546  int x1 = x0 + 1;
3547  SplashCoord s0 = (SplashCoord)x1 + 0.5 - xs;
3548  SplashCoord s1 = (SplashCoord)1 - s0;
3549  if (x0 < 0) {
3550  x0 = 0;
3551  }
3552  if (x1 >= srcWidth) {
3553  x1 = srcWidth - 1;
3554  }
3555  for (int j = 0; j < nComps; ++j) {
3556  colorLine[scaledColorIdx + j] =
3557  (Guchar)(int)(s0 * colorAccBuf[x0 * nComps + j] +
3558  s1 * colorAccBuf[x1 * nComps + j]);
3559  }
3560  scaledColorIdx += nComps;
3561  if (hasAlpha) {
3562  alphaLine[scaledIdx] = (Guchar)(int)(s0 * alphaAccBuf[x0] +
3563  s1 * alphaAccBuf[x1]);
3564  }
3565  }
3566 }
3567 
3569  //--- vert upscale
3570  if (yn == 0) {
3571  yn = yp;
3572  yt += yq;
3573  if (yt >= srcHeight) {
3574  yt -= srcHeight;
3575  ++yn;
3576  }
3577  (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
3578  }
3579  --yn;
3580 
3581  //--- horiz downscale
3582  int colorAcc[splashMaxColorComps];
3583  int xt = 0;
3584  int unscaledColorIdx = 0;
3585  int unscaledAlphaIdx = 0;
3586  int scaledColorIdx = 0;
3587  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
3588  int xStep = xp;
3589  xt += xq;
3590  if (xt >= scaledWidth) {
3591  xt -= scaledWidth;
3592  ++xStep;
3593  }
3594 
3595  for (int j = 0; j < nComps; ++j) {
3596  colorAcc[j] = 0;
3597  }
3598  for (int i = 0; i < xStep; ++i) {
3599  for (int j = 0; j < nComps; ++j) {
3600  colorAcc[j] += colorTmpBuf0[unscaledColorIdx + j];
3601  }
3602  unscaledColorIdx += nComps;
3603  }
3604  for (int j = 0; j < nComps; ++j) {
3605  colorLine[scaledColorIdx + j] = (Guchar)(colorAcc[j] / xStep);
3606  }
3607  scaledColorIdx += nComps;
3608 
3609  if (hasAlpha) {
3610  int alphaAcc = 0;
3611  for (int i = 0; i < xStep; ++i) {
3612  alphaAcc += alphaTmpBuf0[unscaledAlphaIdx];
3613  ++unscaledAlphaIdx;
3614  }
3615  alphaLine[scaledIdx] = (Guchar)(alphaAcc / xStep);
3616  }
3617  }
3618 }
3619 
3621  //--- vert upscale
3622  if (ySrcCur == 0) {
3623  (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
3624  (*src)(srcData, colorTmpBuf1, alphaTmpBuf1);
3625  ySrcCur = 1;
3626  }
3627  SplashCoord ys = ((SplashCoord)yScaledCur + 0.5) * yInvScale;
3628  int y0 = splashFloor(ys - 0.5);
3629  int y1 = y0 + 1;
3630  SplashCoord vs0 = (SplashCoord)y1 + 0.5 - ys;
3631  SplashCoord vs1 = (SplashCoord)1 - vs0;
3632  if (y1 > ySrcCur && ySrcCur < srcHeight - 1) {
3633  Guchar *t = colorTmpBuf0;
3635  colorTmpBuf1 = t;
3636  if (hasAlpha) {
3637  t = alphaTmpBuf0;
3639  alphaTmpBuf1 = t;
3640  }
3641  (*src)(srcData, colorTmpBuf1, alphaTmpBuf1);
3642  ++ySrcCur;
3643  }
3644  Guchar *color0 = colorTmpBuf0;
3645  Guchar *color1 = colorTmpBuf1;
3646  Guchar *alpha0 = alphaTmpBuf0;
3647  Guchar *alpha1 = alphaTmpBuf1;
3648  if (y0 < 0) {
3649  y0 = 0;
3650  color1 = color0;
3651  alpha1 = alpha0;
3652  }
3653  if (y1 >= srcHeight) {
3654  y1 = srcHeight - 1;
3655  color0 = color1;
3656  alpha0 = alpha1;
3657  }
3658  ++yScaledCur;
3659 
3660  //--- horiz downscale
3661  int colorAcc[splashMaxColorComps];
3662  int xt = 0;
3663  int unscaledColorIdx = 0;
3664  int unscaledAlphaIdx = 0;
3665  int scaledColorIdx = 0;
3666  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
3667  int xStep = xp;
3668  xt += xq;
3669  if (xt >= scaledWidth) {
3670  xt -= scaledWidth;
3671  ++xStep;
3672  }
3673 
3674  for (int j = 0; j < nComps; ++j) {
3675  colorAcc[j] = 0;
3676  }
3677  for (int i = 0; i < xStep; ++i) {
3678  for (int j = 0; j < nComps; ++j) {
3679  colorAcc[j] += (int)(vs0 * (int)color0[unscaledColorIdx + j] +
3680  vs1 * (int)color1[unscaledColorIdx + j]);
3681  }
3682  unscaledColorIdx += nComps;
3683  }
3684  for (int j = 0; j < nComps; ++j) {
3685  colorLine[scaledColorIdx + j] = (Guchar)(colorAcc[j] / xStep);
3686  }
3687  scaledColorIdx += nComps;
3688 
3689  if (hasAlpha) {
3690  int alphaAcc = 0;
3691  for (int i = 0; i < xStep; ++i) {
3692  alphaAcc += (int)(vs0 * (int)alpha0[unscaledAlphaIdx] +
3693  vs1 * (int)alpha1[unscaledAlphaIdx]);
3694  ++unscaledAlphaIdx;
3695  }
3696  alphaLine[scaledIdx] = (Guchar)(alphaAcc / xStep);
3697  }
3698  }
3699 }
3700 
3702  //--- vert upscale
3703  if (yn == 0) {
3704  yn = yp;
3705  yt += yq;
3706  if (yt >= srcHeight) {
3707  yt -= srcHeight;
3708  ++yn;
3709  }
3710  (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
3711  }
3712  --yn;
3713 
3714  //--- horiz upscale
3715  int xt = 0;
3716  int scaledColorIdx = 0;
3717  int srcColorIdx = 0;
3718  int scaledAlphaIdx = 0;
3719  for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
3720  int xStep = xp;
3721  xt += xq;
3722  if (xt >= srcWidth) {
3723  xt -= srcWidth;
3724  ++xStep;
3725  }
3726  for (int i = 0; i < xStep; ++i) {
3727  for (int j = 0; j < nComps; ++j) {
3728  colorLine[scaledColorIdx + j] = colorTmpBuf0[srcColorIdx + j];
3729  }
3730  scaledColorIdx += nComps;
3731  }
3732  srcColorIdx += nComps;
3733  if (hasAlpha) {
3734  Guchar alphaBuf = alphaTmpBuf0[srcIdx];
3735  for (int i = 0; i < xStep; ++i) {
3736  alphaLine[scaledAlphaIdx] = alphaBuf;
3737  ++scaledAlphaIdx;
3738  }
3739  }
3740  }
3741 }
3742 
3744  //--- vert upscale
3745  if (ySrcCur == 0) {
3746  (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
3747  (*src)(srcData, colorTmpBuf1, alphaTmpBuf1);
3748  ySrcCur = 1;
3749  }
3750  SplashCoord ys = ((SplashCoord)yScaledCur + 0.5) * yInvScale;
3751  int y0 = splashFloor(ys - 0.5);
3752  int y1 = y0 + 1;
3753  SplashCoord vs0 = (SplashCoord)y1 + 0.5 - ys;
3754  SplashCoord vs1 = (SplashCoord)1 - vs0;
3755  if (y1 > ySrcCur && ySrcCur < srcHeight - 1) {
3756  Guchar *t = colorTmpBuf0;
3758  colorTmpBuf1 = t;
3759  if (hasAlpha) {
3760  t = alphaTmpBuf0;
3762  alphaTmpBuf1 = t;
3763  }
3764  (*src)(srcData, colorTmpBuf1, alphaTmpBuf1);
3765  ++ySrcCur;
3766  }
3767  Guchar *color0 = colorTmpBuf0;
3768  Guchar *color1 = colorTmpBuf1;
3769  Guchar *alpha0 = alphaTmpBuf0;
3770  Guchar *alpha1 = alphaTmpBuf1;
3771  if (y0 < 0) {
3772  y0 = 0;
3773  color1 = color0;
3774  alpha1 = alpha0;
3775  }
3776  if (y1 >= srcHeight) {
3777  y1 = srcHeight - 1;
3778  color0 = color1;
3779  alpha0 = alpha1;
3780  }
3781  ++yScaledCur;
3782  for (int srcIdx = 0; srcIdx < srcWidth * nComps; ++srcIdx) {
3783  colorTmpBuf2[srcIdx] = (Guchar)(int)(vs0 * (int)color0[srcIdx] +
3784  vs1 * (int)color1[srcIdx]);
3785  }
3786  if (hasAlpha) {
3787  for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
3788  alphaTmpBuf2[srcIdx] = (Guchar)(int)(vs0 * (int)alpha0[srcIdx] +
3789  vs1 * (int)alpha1[srcIdx]);
3790  }
3791  }
3792 
3793  //--- horiz upscale
3794  int scaledColorIdx = 0;
3795  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
3796  SplashCoord xs = ((SplashCoord)scaledIdx + 0.5) * xInvScale;
3797  int x0 = splashFloor(xs - 0.5);
3798  int x1 = x0 + 1;
3799  SplashCoord hs0 = (SplashCoord)x1 + 0.5 - xs;
3800  SplashCoord hs1 = (SplashCoord)1 - hs0;
3801  if (x0 < 0) {
3802  x0 = 0;
3803  }
3804  if (x1 >= srcWidth) {
3805  x1 = srcWidth - 1;
3806  }
3807  for (int j = 0; j < nComps; ++j) {
3808  colorLine[scaledColorIdx + j] =
3809  (Guchar)(int)(hs0 * (int)colorTmpBuf2[x0 * nComps + j] +
3810  hs1 * (int)colorTmpBuf2[x1 * nComps + j]);
3811  }
3812  scaledColorIdx += nComps;
3813  if (hasAlpha) {
3814  alphaLine[scaledIdx] = (Guchar)(int)(hs0 * (int)alphaTmpBuf2[x0] +
3815  hs1 * (int)alphaTmpBuf2[x1]);
3816  }
3817  }
3818 }
3819 
3820 //------------------------------------------------------------------------
3821 // SavingImageScaler
3822 //------------------------------------------------------------------------
3823 
3824 // Wrapper around BasicImageScaler that saves the scaled image for use
3825 // by ReplayImageScaler.
3827 public:
3828 
3829  SavingImageScaler(SplashImageSource aSrc, void *aSrcData,
3830  int aSrcWidth, int aSrcHeight, int aNComps, GBool aHasAlpha,
3831  int aScaledWidth, int aScaledHeight, GBool aInterpolate,
3832  Guchar *aColorCache, Guchar *aAlphaCache);
3833  virtual void nextLine();
3834 
3835 private:
3836 
3839 };
3840 
3842  int aSrcWidth, int aSrcHeight,
3843  int aNComps, GBool aHasAlpha,
3844  int aScaledWidth, int aScaledHeight,
3845  GBool aInterpolate,
3846  Guchar *aColorCache, Guchar *aAlphaCache):
3847  BasicImageScaler(aSrc, aSrcData, aSrcWidth, aSrcHeight, aNComps, aHasAlpha,
3848  aScaledWidth, aScaledHeight, aInterpolate)
3849 {
3850  colorPtr = aColorCache;
3851  alphaPtr = aAlphaCache;
3852 }
3853 
3858  if (hasAlpha) {
3860  alphaPtr += scaledWidth;
3861  }
3862 }
3863 
3864 //------------------------------------------------------------------------
3865 // ReplayImageScaler
3866 //------------------------------------------------------------------------
3867 
3868 // "Replay" a scaled image saved by SavingImageScaler.
3870 public:
3871 
3872  ReplayImageScaler(int aNComps, GBool aHasAlpha,
3873  int aScaledWidth,
3874  Guchar *aColorCache, Guchar *aAlphaCache);
3875  virtual void nextLine();
3876  virtual Guchar *colorData() { return colorLine; }
3877  virtual Guchar *alphaData() { return alphaLine; }
3878 
3879 private:
3880 
3881  int nComps;
3888 };
3889 
3891  int aScaledWidth,
3892  Guchar *aColorCache, Guchar *aAlphaCache) {
3893  nComps = aNComps;
3894  hasAlpha = aHasAlpha;
3895  scaledWidth = aScaledWidth;
3896  colorPtr = aColorCache;
3897  alphaPtr = aAlphaCache;
3898  colorLine = NULL;
3899  alphaLine = NULL;
3900 }
3901 
3903  colorLine = colorPtr;
3904  alphaLine = alphaPtr;
3906  if (hasAlpha) {
3907  alphaPtr += scaledWidth;
3908  }
3909 }
3910 
3911 //------------------------------------------------------------------------
3912 // ImageMaskScaler
3913 //------------------------------------------------------------------------
3914 
3916 public:
3917 
3918  // Set up a MaskScaler to scale from [srcWidth]x[srcHeight] to
3919  // [scaledWidth]x[scaledHeight].
3920  ImageMaskScaler(SplashImageMaskSource aSrc, void *aSrcData,
3921  int aSrcWidth, int aSrcHeight,
3922  int aScaledWidth, int aScaledHeight, GBool aInterpolate);
3923 
3924  ~ImageMaskScaler();
3925 
3926  // Compute the next line of the scaled image mask. This can be
3927  // called up to [scaledHeight] times.
3928  void nextLine();
3929 
3930  // Retrieve the data generated by the most recent call to
3931  // nextLine().
3932  Guchar *data() { return line; }
3933 
3934 private:
3935 
3943 
3944  // source image data function
3946  void *srcData;
3947 
3948  // source image size
3951 
3952  // scaled image size
3955 
3956  // params/state for vertical scaling
3957  int yp, yq;
3958  int yt, yn;
3961 
3962  // params for horizontal scaling
3963  int xp, xq;
3965 
3966  // vertical and horizontal scaling functions
3968 
3969  // temporary buffers for vertical scaling
3974 
3975  // output of horizontal scaling
3977 };
3978 
3980  int aSrcWidth, int aSrcHeight,
3981  int aScaledWidth, int aScaledHeight,
3982  GBool aInterpolate) {
3983  tmpBuf0 = NULL;
3984  tmpBuf1 = NULL;
3985  tmpBuf2 = NULL;
3986  accBuf = NULL;
3987  line = NULL;
3988 
3989  src = aSrc;
3990  srcData = aSrcData;
3991  srcWidth = aSrcWidth;
3992  srcHeight = aSrcHeight;
3993  scaledWidth = aScaledWidth;
3994  scaledHeight = aScaledHeight;
3995 
3996  // select scaling function; allocate buffers
3997  if (scaledHeight <= srcHeight) {
3998  // vertical downscaling
4001  yt = 0;
4003  accBuf = (Guint *)gmallocn(srcWidth, sizeof(Guint));
4004  if (scaledWidth <= srcWidth) {
4006  } else {
4007  if (aInterpolate) {
4009  } else {
4011  }
4012  }
4013  } else {
4014  // vertical upscaling
4017  yt = 0;
4018  yn = 0;
4019  if (aInterpolate) {
4023  ySrcCur = 0;
4024  yScaledCur = 0;
4025  if (scaledWidth <= srcWidth) {
4027  } else {
4030  }
4031  } else {
4033  if (scaledWidth <= srcWidth) {
4035  } else {
4037  }
4038  }
4039  }
4040  if (scaledWidth <= srcWidth) {
4041  xp = srcWidth / scaledWidth;
4042  xq = srcWidth % scaledWidth;
4043  } else {
4044  xp = scaledWidth / srcWidth;
4045  xq = scaledWidth % srcWidth;
4046  if (aInterpolate) {
4048  }
4049  }
4051 }
4052 
4054  gfree(tmpBuf0);
4055  gfree(tmpBuf1);
4056  gfree(tmpBuf2);
4057  gfree(accBuf);
4058  gfree(line);
4059 }
4060 
4062  (this->*scalingFunc)();
4063 }
4064 
4066  //--- vert downscale
4067  int yStep = yp;
4068  yt += yq;
4069  if (yt >= scaledHeight) {
4070  yt -= scaledHeight;
4071  ++yStep;
4072  }
4073  memset(accBuf, 0, srcWidth * sizeof(Guint));
4074  for (int i = 0; i < yStep; ++i) {
4075  (*src)(srcData, tmpBuf0);
4076  for (int j = 0; j < srcWidth; ++j) {
4077  accBuf[j] += tmpBuf0[j];
4078  }
4079  }
4080 
4081  //--- horiz downscale
4082  int acc;
4083  int xt = 0;
4084  int unscaledIdx = 0;
4085  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
4086  int xStep = xp;
4087  xt += xq;
4088  if (xt >= scaledWidth) {
4089  xt -= scaledWidth;
4090  ++xStep;
4091  }
4092 
4093  acc = 0;
4094  for (int i = 0; i < xStep; ++i) {
4095  acc += accBuf[unscaledIdx];
4096  ++unscaledIdx;
4097  }
4098  line[scaledIdx] = (Guchar)((255 * acc) / (xStep * yStep));
4099  }
4100 }
4101 
4103  //--- vert downscale
4104  int yStep = yp;
4105  yt += yq;
4106  if (yt >= scaledHeight) {
4107  yt -= scaledHeight;
4108  ++yStep;
4109  }
4110  memset(accBuf, 0, srcWidth * sizeof(Guint));
4111  for (int i = 0; i < yStep; ++i) {
4112  (*src)(srcData, tmpBuf0);
4113  for (int j = 0; j < srcWidth; ++j) {
4114  accBuf[j] += tmpBuf0[j];
4115  }
4116  }
4117 
4118  //--- horiz upscale
4119  int xt = 0;
4120  int scaledIdx = 0;
4121  for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
4122  int xStep = xp;
4123  xt += xq;
4124  if (xt >= srcWidth) {
4125  xt -= srcWidth;
4126  ++xStep;
4127  }
4128  Guchar buf = (Guchar)((255 * accBuf[srcIdx]) / yStep);
4129  for (int i = 0; i < xStep; ++i) {
4130  line[scaledIdx] = buf;
4131  ++scaledIdx;
4132  }
4133  }
4134 }
4135 
4137  //--- vert downscale
4138  int yStep = yp;
4139  yt += yq;
4140  if (yt >= scaledHeight) {
4141  yt -= scaledHeight;
4142  ++yStep;
4143  }
4144  memset(accBuf, 0, srcWidth * sizeof(Guint));
4145  for (int i = 0; i < yStep; ++i) {
4146  (*src)(srcData, tmpBuf0);
4147  for (int j = 0; j < srcWidth; ++j) {
4148  accBuf[j] += tmpBuf0[j];
4149  }
4150  }
4151  for (int j = 0; j < srcWidth; ++j) {
4152  accBuf[j] = (255 * accBuf[j]) / yStep;
4153  }
4154 
4155  //--- horiz upscale
4156  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
4157  SplashCoord xs = ((SplashCoord)scaledIdx + 0.5) * xInvScale;
4158  int x0 = splashFloor(xs - 0.5);
4159  int x1 = x0 + 1;
4160  SplashCoord s0 = (SplashCoord)x1 + 0.5 - xs;
4161  SplashCoord s1 = (SplashCoord)1 - s0;
4162  if (x0 < 0) {
4163  x0 = 0;
4164  }
4165  if (x1 >= srcWidth) {
4166  x1 = srcWidth - 1;
4167  }
4168  line[scaledIdx] = (Guchar)(int)(s0 * accBuf[x0] + s1 * accBuf[x1]);
4169  }
4170 }
4171 
4173  //--- vert upscale
4174  if (yn == 0) {
4175  yn = yp;
4176  yt += yq;
4177  if (yt >= srcHeight) {
4178  yt -= srcHeight;
4179  ++yn;
4180  }
4181  (*src)(srcData, tmpBuf0);
4182  }
4183  --yn;
4184 
4185  //--- horiz downscale
4186  int acc;
4187  int xt = 0;
4188  int unscaledIdx = 0;
4189  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
4190  int xStep = xp;
4191  xt += xq;
4192  if (xt >= scaledWidth) {
4193  xt -= scaledWidth;
4194  ++xStep;
4195  }
4196 
4197  acc = 0;
4198  for (int i = 0; i < xStep; ++i) {
4199  acc += tmpBuf0[unscaledIdx];
4200  ++unscaledIdx;
4201  }
4202  line[scaledIdx] = (Guchar)((255 * acc) / xStep);
4203  }
4204 }
4205 
4207  //--- vert upscale
4208  if (ySrcCur == 0) {
4209  (*src)(srcData, tmpBuf0);
4210  (*src)(srcData, tmpBuf1);
4211  ySrcCur = 1;
4212  }
4213  SplashCoord ys = ((SplashCoord)yScaledCur + 0.5) * yInvScale;
4214  int y0 = splashFloor(ys - 0.5);
4215  int y1 = y0 + 1;
4216  SplashCoord vs0 = (SplashCoord)y1 + 0.5 - ys;
4217  SplashCoord vs1 = (SplashCoord)1 - vs0;
4218  if (y1 > ySrcCur && ySrcCur < srcHeight - 1) {
4219  Guchar *t = tmpBuf0;
4220  tmpBuf0 = tmpBuf1;
4221  tmpBuf1 = t;
4222  (*src)(srcData, tmpBuf1);
4223  ++ySrcCur;
4224  }
4225  Guchar *mask0 = tmpBuf0;
4226  Guchar *mask1 = tmpBuf1;
4227  if (y0 < 0) {
4228  y0 = 0;
4229  mask1 = mask0;
4230  }
4231  if (y1 >= srcHeight) {
4232  y1 = srcHeight - 1;
4233  mask0 = mask1;
4234  }
4235  ++yScaledCur;
4236 
4237  //--- horiz downscale
4238  int acc;
4239  int xt = 0;
4240  int unscaledIdx = 0;
4241  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
4242  int xStep = xp;
4243  xt += xq;
4244  if (xt >= scaledWidth) {
4245  xt -= scaledWidth;
4246  ++xStep;
4247  }
4248 
4249  acc = 0;
4250  for (int i = 0; i < xStep; ++i) {
4251  acc += (int)(vs0 * (int)mask0[unscaledIdx] +
4252  vs1 * (int)mask1[unscaledIdx]);
4253  ++unscaledIdx;
4254  }
4255  line[scaledIdx] = (Guchar)((255 * acc) / xStep);
4256  }
4257 }
4258 
4260  //--- vert upscale
4261  if (yn == 0) {
4262  yn = yp;
4263  yt += yq;
4264  if (yt >= srcHeight) {
4265  yt -= srcHeight;
4266  ++yn;
4267  }
4268  (*src)(srcData, tmpBuf0);
4269  }
4270  --yn;
4271 
4272  //--- horiz upscale
4273  int xt = 0;
4274  int scaledIdx = 0;
4275  for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
4276  int xStep = xp;
4277  xt += xq;
4278  if (xt >= srcWidth) {
4279  xt -= srcWidth;
4280  ++xStep;
4281  }
4282  Guchar buf = (Guchar)(255 * tmpBuf0[srcIdx]);
4283  for (int i = 0; i < xStep; ++i) {
4284  line[scaledIdx] = buf;
4285  ++scaledIdx;
4286  }
4287  }
4288 }
4289 
4291  //--- vert upscale
4292  if (ySrcCur == 0) {
4293  (*src)(srcData, tmpBuf0);
4294  (*src)(srcData, tmpBuf1);
4295  ySrcCur = 1;
4296  }
4297  SplashCoord ys = ((SplashCoord)yScaledCur + 0.5) * yInvScale;
4298  int y0 = splashFloor(ys - 0.5);
4299  int y1 = y0 + 1;
4300  SplashCoord vs0 = (SplashCoord)255 * ((SplashCoord)y1 + 0.5 - ys);
4301  SplashCoord vs1 = (SplashCoord)255 - vs0;
4302  if (y1 > ySrcCur && ySrcCur < srcHeight - 1) {
4303  Guchar *t = tmpBuf0;
4304  tmpBuf0 = tmpBuf1;
4305  tmpBuf1 = t;
4306  (*src)(srcData, tmpBuf1);
4307  ++ySrcCur;
4308  }
4309  Guchar *mask0 = tmpBuf0;
4310  Guchar *mask1 = tmpBuf1;
4311  if (y0 < 0) {
4312  y0 = 0;
4313  mask1 = mask0;
4314  }
4315  if (y1 >= srcHeight) {
4316  y1 = srcHeight - 1;
4317  mask0 = mask1;
4318  }
4319  ++yScaledCur;
4320  for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
4321  tmpBuf2[srcIdx] = (Guchar)(int)(vs0 * (int)mask0[srcIdx] +
4322  vs1 * (int)mask1[srcIdx]);
4323  }
4324 
4325  //--- horiz upscale
4326  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
4327  SplashCoord xs = ((SplashCoord)scaledIdx + 0.5) * xInvScale;
4328  int x0 = splashFloor(xs - 0.5);
4329  int x1 = x0 + 1;
4330  SplashCoord hs0 = (SplashCoord)x1 + 0.5 - xs;
4331  SplashCoord hs1 = (SplashCoord)1 - hs0;
4332  if (x0 < 0) {
4333  x0 = 0;
4334  }
4335  if (x1 >= srcWidth) {
4336  x1 = srcWidth - 1;
4337  }
4338  line[scaledIdx] = (Guchar)(int)(hs0 * (int)tmpBuf2[x0] +
4339  hs1 * (int)tmpBuf2[x1]);
4340  }
4341 }
4342 
4343 //------------------------------------------------------------------------
4344 // Splash
4345 //------------------------------------------------------------------------
4346 
4347 Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
4348  SplashImageCache *imageCacheA,
4349  SplashScreenParams *screenParams) {
4350  bitmap = bitmapA;
4352  vectorAntialias = vectorAntialiasA;
4353  inShading = gFalse;
4354  state = new SplashState(bitmap->width, bitmap->height, vectorAntialias,
4355  screenParams);
4356  scanBuf = (Guchar *)gmalloc(bitmap->width);
4357  if (bitmap->mode == splashModeMono1) {
4358  scanBuf2 = (Guchar *)gmalloc(bitmap->width);
4359  } else {
4360  scanBuf2 = NULL;
4361  }
4365  minLineWidth = 0;
4366  clearModRegion();
4367  debugMode = gFalse;
4368 
4369  if (imageCacheA) {
4370  imageCache = imageCacheA;
4372  } else {
4373  imageCache = new SplashImageCache();
4374  }
4375 }
4376 
4377 Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
4378  SplashImageCache *imageCacheA, SplashScreen *screenA) {
4379  bitmap = bitmapA;
4381  vectorAntialias = vectorAntialiasA;
4382  inShading = gFalse;
4383  state = new SplashState(bitmap->width, bitmap->height, vectorAntialias,
4384  screenA);
4385  scanBuf = (Guchar *)gmalloc(bitmap->width);
4386  if (bitmap->mode == splashModeMono1) {
4387  scanBuf2 = (Guchar *)gmalloc(bitmap->width);
4388  } else {
4389  scanBuf2 = NULL;
4390  }
4394  minLineWidth = 0;
4395  clearModRegion();
4396  debugMode = gFalse;
4397 
4398  if (imageCacheA) {
4399  imageCache = imageCacheA;
4401  } else {
4402  imageCache = new SplashImageCache();
4403  }
4404 }
4405 
4408 
4409  while (state->next) {
4410  restoreState();
4411  }
4412  delete state;
4413  gfree(scanBuf);
4414  gfree(scanBuf2);
4415 }
4416 
4417 //------------------------------------------------------------------------
4418 // state read
4419 //------------------------------------------------------------------------
4420 
4422  return state->matrix;
4423 }
4424 
4426  return state->strokePattern;
4427 }
4428 
4430  return state->fillPattern;
4431 }
4432 
4434  return state->screen;
4435 }
4436 
4438  return state->blendFunc;
4439 }
4440 
4442  return state->strokeAlpha;
4443 }
4444 
4446  return state->fillAlpha;
4447 }
4448 
4450  return state->lineWidth;
4451 }
4452 
4454  return state->lineCap;
4455 }
4456 
4458  return state->lineJoin;
4459 }
4460 
4462  return state->miterLimit;
4463 }
4464 
4466  return state->flatness;
4467 }
4468 
4470  return state->lineDash;
4471 }
4472 
4474  return state->lineDashLength;
4475 }
4476 
4478  return state->lineDashPhase;
4479 }
4480 
4482  return state->strokeAdjust;
4483 }
4484 
4486  return state->clip;
4487 }
4488 
4490  return state->softMask;
4491 }
4492 
4494  return state->inNonIsolatedGroup;
4495 }
4496 
4498  return state->inKnockoutGroup;
4499 }
4500 
4501 //------------------------------------------------------------------------
4502 // state write
4503 //------------------------------------------------------------------------
4504 
4506  memcpy(state->matrix, matrix, 6 * sizeof(SplashCoord));
4507 }
4508 
4510  state->setStrokePattern(strokePattern);
4511 }
4512 
4514  state->setFillPattern(fillPattern);
4515 }
4516 
4518  state->setScreen(screen);
4519 }
4520 
4522  state->blendFunc = func;
4523 }
4524 
4526  state->strokeAlpha = alpha;
4527 }
4528 
4530  state->fillAlpha = alpha;
4531 }
4532 
4534  state->lineWidth = lineWidth;
4535 }
4536 
4537 void Splash::setLineCap(int lineCap) {
4538  if (lineCap >= 0 && lineCap <= 2) {
4539  state->lineCap = lineCap;
4540  } else {
4541  state->lineCap = 0;
4542  }
4543 }
4544 
4545 void Splash::setLineJoin(int lineJoin) {
4546  if (lineJoin >= 0 && lineJoin <= 2) {
4547  state->lineJoin = lineJoin;
4548  } else {
4549  state->lineJoin = 0;
4550  }
4551 }
4552 
4554  state->miterLimit = miterLimit;
4555 }
4556 
4558  if (flatness < 1) {
4559  state->flatness = 1;
4560  } else {
4561  state->flatness = flatness;
4562  }
4563 }
4564 
4565 void Splash::setLineDash(SplashCoord *lineDash, int lineDashLength,
4566  SplashCoord lineDashPhase) {
4567  state->setLineDash(lineDash, lineDashLength, lineDashPhase);
4568 }
4569 
4571  state->strokeAdjust = strokeAdjust;
4572 }
4573 
4576  state->clipResetToRect(x0, y0, x1, y1);
4577 }
4578 
4581  return state->clipToRect(x0, y0, x1, y1);
4582 }
4583 
4585  return state->clipToPath(path, eo);
4586 }
4587 
4589  state->setSoftMask(softMask);
4590 }
4591 
4593  int groupBackXA, int groupBackYA,
4594  SplashGroupDestInitMode groupDestInitModeA,
4595  GBool nonIsolated, GBool knockout) {
4596  groupBackBitmap = groupBackBitmapA;
4597  groupBackX = groupBackXA;
4598  groupBackY = groupBackYA;
4599  groupDestInitMode = groupDestInitModeA;
4600  groupDestInitYMin = 1;
4601  groupDestInitYMax = 0;
4602  state->inNonIsolatedGroup = nonIsolated;
4603  state->inKnockoutGroup = knockout;
4604 }
4605 
4607  useDestRow(y);
4608  useDestRow(y + h - 1);
4609 }
4610 
4612  Guchar *gray) {
4613  state->setTransfer(red, green, blue, gray);
4614 }
4615 
4616 void Splash::setOverprintMask(Guint overprintMask) {
4617  state->overprintMask = overprintMask;
4618 }
4619 
4620 
4622  state->enablePathSimplification = en;
4623 }
4624 
4625 //------------------------------------------------------------------------
4626 // state save/restore
4627 //------------------------------------------------------------------------
4628 
4630  SplashState *newState;
4631 
4632  newState = state->copy();
4633  newState->next = state;
4634  state = newState;
4635 }
4636 
4638  SplashState *oldState;
4639 
4640  if (!state->next) {
4641  return splashErrNoSave;
4642  }
4643  oldState = state;
4644  state = state->next;
4645  delete oldState;
4646  return splashOk;
4647 }
4648 
4649 //------------------------------------------------------------------------
4650 // drawing operations
4651 //------------------------------------------------------------------------
4652 
4654  SplashColorPtr row, p;
4655  Guchar mono;
4656  int x, y;
4657 
4658  switch (bitmap->mode) {
4659  case splashModeMono1:
4660  mono = (color[0] & 0x80) ? 0xff : 0x00;
4661  if (bitmap->rowSize < 0) {
4662  memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
4663  mono, -bitmap->rowSize * bitmap->height);
4664  } else {
4665  memset(bitmap->data, mono, bitmap->rowSize * bitmap->height);
4666  }
4667  break;
4668  case splashModeMono8:
4669  if (bitmap->rowSize < 0) {
4670  memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
4671  color[0], -bitmap->rowSize * bitmap->height);
4672  } else {
4673  memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
4674  }
4675  break;
4676  case splashModeRGB8:
4677  if (color[0] == color[1] && color[1] == color[2]) {
4678  if (bitmap->rowSize < 0) {
4679  memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
4680  color[0], -bitmap->rowSize * bitmap->height);
4681  } else {
4682  memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
4683  }
4684  } else {
4685  row = bitmap->data;
4686  for (y = 0; y < bitmap->height; ++y) {
4687  p = row;
4688  for (x = 0; x < bitmap->width; ++x) {
4689  *p++ = color[0];
4690  *p++ = color[1];
4691  *p++ = color[2];
4692  }
4693  row += bitmap->rowSize;
4694  }
4695  }
4696  break;
4697  case splashModeBGR8:
4698  if (color[0] == color[1] && color[1] == color[2]) {
4699  if (bitmap->rowSize < 0) {
4700  memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
4701  color[0], -bitmap->rowSize * bitmap->height);
4702  } else {
4703  memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
4704  }
4705  } else {
4706  row = bitmap->data;
4707  for (y = 0; y < bitmap->height; ++y) {
4708  p = row;
4709  for (x = 0; x < bitmap->width; ++x) {
4710  *p++ = color[2];
4711  *p++ = color[1];
4712  *p++ = color[0];
4713  }
4714  row += bitmap->rowSize;
4715  }
4716  }
4717  break;
4718 #if SPLASH_CMYK
4719  case splashModeCMYK8:
4720  if (color[0] == color[1] && color[1] == color[2] && color[2] == color[3]) {
4721  if (bitmap->rowSize < 0) {
4722  memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
4723  color[0], -bitmap->rowSize * bitmap->height);
4724  } else {
4725  memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
4726  }
4727  } else {
4728  row = bitmap->data;
4729  for (y = 0; y < bitmap->height; ++y) {
4730  p = row;
4731  for (x = 0; x < bitmap->width; ++x) {
4732  *p++ = color[0];
4733  *p++ = color[1];
4734  *p++ = color[2];
4735  *p++ = color[3];
4736  }
4737  row += bitmap->rowSize;
4738  }
4739  }
4740  break;
4741 #endif
4742  }
4743 
4744  if (bitmap->alpha) {
4745  memset(bitmap->alpha, alpha, bitmap->alphaRowSize * bitmap->height);
4746  }
4747 
4748  updateModX(0);
4749  updateModY(0);
4750  updateModX(bitmap->width - 1);
4751  updateModY(bitmap->height - 1);
4752 }
4753 
4755  SplashPath *path2, *dPath;
4756  SplashCoord t0, t1, t2, t3, w, w2, lineDashMax, lineDashTotal;
4757  int lineCap, lineJoin, i;
4758 
4759  if (debugMode) {
4760  printf("stroke [dash:%d] [width:%.2f]:\n",
4761  state->lineDashLength, (double)state->lineWidth);
4762  dumpPath(path);
4763  }
4765  if (path->length == 0) {
4766  return splashErrEmptyPath;
4767  }
4768  path2 = flattenPath(path, state->matrix, state->flatness);
4769 
4770  // Compute an approximation of the transformed line width.
4771  // Given a CTM of [m0 m1],
4772  // [m2 m3]
4773  // if |m0|*|m3| >= |m1|*|m2| then use min{|m0|,|m3|}, else
4774  // use min{|m1|,|m2|}.
4775  // This handles the common cases -- [s 0 ] and [0 s] --
4776  // [0 +/-s] [+/-s 0]
4777  // well, and still does something reasonable for the uncommon
4778  // case transforms.
4779  t0 = splashAbs(state->matrix[0]);
4780  t1 = splashAbs(state->matrix[1]);
4781  t2 = splashAbs(state->matrix[2]);
4782  t3 = splashAbs(state->matrix[3]);
4783  if (t0 * t3 >= t1 * t2) {
4784  w = (t0 < t3) ? t0 : t3;
4785  } else {
4786  w = (t1 < t2) ? t1 : t2;
4787  }
4788  w2 = w * state->lineWidth;
4789 
4790  // construct the dashed path
4791  if (state->lineDashLength > 0) {
4792 
4793  // check the maximum transformed dash element length (using the
4794  // same approximation as for line width) -- if it's less than 0.1
4795  // pixel, don't apply the dash pattern; this avoids a huge
4796  // performance/memory hit with PDF files that use absurd dash
4797  // patterns like [0.0007 0.0003]
4798  lineDashTotal = 0;
4799  lineDashMax = 0;
4800  for (i = 0; i < state->lineDashLength; ++i) {
4801  lineDashTotal += state->lineDash[i];
4802  if (state->lineDash[i] > lineDashMax) {
4803  lineDashMax = state->lineDash[i];
4804  }
4805  }
4806  // Acrobat simply draws nothing if the dash array is [0]
4807  if (lineDashTotal == 0) {
4808  delete path2;
4809  return splashOk;
4810  }
4811  if (w * lineDashMax > 0.1) {
4812 
4813  dPath = makeDashedPath(path2);
4814  delete path2;
4815  path2 = dPath;
4816  if (path2->length == 0) {
4817  delete path2;
4818  return splashErrEmptyPath;
4819  }
4820  }
4821  }
4822 
4823  // round caps on narrow lines look bad, and can't be
4824  // stroke-adjusted, so use projecting caps instead (but we can't do
4825  // this if there are zero-length dashes or segments, because those
4826  // turn into round dots)
4827  lineCap = state->lineCap;
4828  lineJoin = state->lineJoin;
4829  if (state->strokeAdjust == splashStrokeAdjustCAD &&
4830  w2 < 3.5) {
4831  if (lineCap == splashLineCapRound &&
4832  !state->lineDashContainsZeroLengthDashes() &&
4833  !path->containsZeroLengthSubpaths()) {
4834  lineCap = splashLineCapProjecting;
4835  }
4836  if (lineJoin == splashLineJoinRound) {
4837  lineJoin = splashLineJoinBevel;
4838  }
4839  }
4840 
4841  // if there is a min line width set, and the transformed line width
4842  // is smaller, use the min line width
4843  if (w > 0 && w2 < minLineWidth) {
4845  } else if (bitmap->mode == splashModeMono1 || !vectorAntialias) {
4846  // in monochrome mode or if antialiasing is disabled, use 0-width
4847  // lines for any transformed line width <= 1 -- lines less than 1
4848  // pixel wide look too fat without antialiasing
4849  if (w2 < 1.001) {
4850  strokeNarrow(path2);
4851  } else {
4852  strokeWide(path2, state->lineWidth, lineCap, lineJoin);
4853  }
4854  } else {
4855  // in gray and color modes, only use 0-width lines if the line
4856  // width is explicitly set to 0
4857  if (state->lineWidth == 0) {
4858  strokeNarrow(path2);
4859  } else {
4860  strokeWide(path2, state->lineWidth, lineCap, lineJoin);
4861  }
4862  }
4863 
4864  delete path2;
4865  return splashOk;
4866 }
4867 
4869  SplashPipe pipe;
4870  SplashXPath *xPath;
4872  int x0, x1, y0, y1, xa, xb, y;
4873  SplashCoord dxdy;
4874  SplashClipResult clipRes;
4875  int nClipRes[3];
4876  int i;
4877 
4878  nClipRes[0] = nClipRes[1] = nClipRes[2] = 0;
4879 
4880  xPath = new SplashXPath(path, state->matrix, state->flatness, gFalse,
4881  state->enablePathSimplification,
4882  state->strokeAdjust);
4883 
4884  pipeInit(&pipe, state->strokePattern,
4885  (Guchar)splashRound(state->strokeAlpha * 255),
4886  gTrue, gFalse);
4887 
4888  for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) {
4889  if (seg->y0 <= seg->y1) {
4890  y0 = splashFloor(seg->y0);
4891  y1 = splashFloor(seg->y1);
4892  x0 = splashFloor(seg->x0);
4893  x1 = splashFloor(seg->x1);
4894  } else {
4895  y0 = splashFloor(seg->y1);
4896  y1 = splashFloor(seg->y0);
4897  x0 = splashFloor(seg->x1);
4898  x1 = splashFloor(seg->x0);
4899  }
4900  if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0,
4901  x0 <= x1 ? x1 : x0, y1,
4902  state->strokeAdjust))
4903  != splashClipAllOutside) {
4904  if (y0 == y1) {
4905  if (x0 <= x1) {
4906  drawStrokeSpan(&pipe, x0, x1, y0, clipRes == splashClipAllInside);
4907  } else {
4908  drawStrokeSpan(&pipe, x1, x0, y0, clipRes == splashClipAllInside);
4909  }
4910  } else {
4911  dxdy = seg->dxdy;
4912  y = state->clip->getYMinI(state->strokeAdjust);
4913  if (y0 < y) {
4914  y0 = y;
4915  x0 = splashFloor(seg->x0 + ((SplashCoord)y0 - seg->y0) * dxdy);
4916  }
4917  y = state->clip->getYMaxI(state->strokeAdjust);
4918  if (y1 > y) {
4919  y1 = y;
4920  x1 = splashFloor(seg->x0 + ((SplashCoord)y1 - seg->y0) * dxdy);
4921  }
4922  if (x0 <= x1) {
4923  xa = x0;
4924  for (y = y0; y <= y1; ++y) {
4925  if (y < y1) {
4926  xb = splashFloor(seg->x0 +
4927  ((SplashCoord)y + 1 - seg->y0) * dxdy);
4928  } else {
4929  xb = x1 + 1;
4930  }
4931  if (xa == xb) {
4932  drawStrokeSpan(&pipe, xa, xa, y, clipRes == splashClipAllInside);
4933  } else {
4934  drawStrokeSpan(&pipe, xa, xb - 1, y,
4935  clipRes == splashClipAllInside);
4936  }
4937  xa = xb;
4938  }
4939  } else {
4940  xa = x0;
4941  for (y = y0; y <= y1; ++y) {
4942  if (y < y1) {
4943  xb = splashFloor(seg->x0 +
4944  ((SplashCoord)y + 1 - seg->y0) * dxdy);
4945  } else {
4946  xb = x1 - 1;
4947  }
4948  if (xa == xb) {
4949  drawStrokeSpan(&pipe, xa, xa, y, clipRes == splashClipAllInside);
4950  } else {
4951  drawStrokeSpan(&pipe, xb + 1, xa, y,
4952  clipRes == splashClipAllInside);
4953  }
4954  xa = xb;
4955  }
4956  }
4957  }
4958  }
4959  ++nClipRes[clipRes];
4960  }
4961  if (nClipRes[splashClipPartial] ||
4962  (nClipRes[splashClipAllInside] && nClipRes[splashClipAllOutside])) {
4964  } else if (nClipRes[splashClipAllInside]) {
4966  } else {
4968  }
4969 
4970  delete xPath;
4971 }
4972 
4974  GBool noClip) {
4975  int x;
4976 
4977  x = state->clip->getXMinI(state->strokeAdjust);
4978  if (x > x0) {
4979  x0 = x;
4980  }
4981  x = state->clip->getXMaxI(state->strokeAdjust);
4982  if (x < x1) {
4983  x1 = x;
4984  }
4985  if (x0 > x1) {
4986  return;
4987  }
4988  for (x = x0; x <= x1; ++x) {
4989  scanBuf[x] = 0xff;
4990  }
4991  if (!noClip) {
4992  if (!state->clip->clipSpanBinary(scanBuf, y, x0, x1, state->strokeAdjust)) {
4993  return;
4994  }
4995  }
4996  (this->*pipe->run)(pipe, x0, x1, y, scanBuf + x0, NULL);
4997 }
4998 
5000  int lineCap, int lineJoin) {
5001  SplashPath *path2;
5002 
5003  path2 = makeStrokePath(path, w, lineCap, lineJoin, gFalse);
5004  fillWithPattern(path2, gFalse, state->strokePattern, state->strokeAlpha);
5005  delete path2;
5006 }
5007 
5010  SplashPath *fPath;
5011  SplashCoord flatness2;
5012  Guchar flag;
5013  int i;
5014 
5015  fPath = new SplashPath();
5016 #if USE_FIXEDPOINT
5017  flatness2 = flatness;
5018 #else
5019  flatness2 = flatness * flatness;
5020 #endif
5021  i = 0;
5022  while (i < path->length) {
5023  flag = path->flags[i];
5024  if (flag & splashPathFirst) {
5025  fPath->moveTo(path->pts[i].x, path->pts[i].y);
5026  ++i;
5027  } else {
5028  if (flag & splashPathCurve) {
5029  flattenCurve(path->pts[i-1].x, path->pts[i-1].y,
5030  path->pts[i ].x, path->pts[i ].y,
5031  path->pts[i+1].x, path->pts[i+1].y,
5032  path->pts[i+2].x, path->pts[i+2].y,
5033  matrix, flatness2, fPath);
5034  i += 3;
5035  } else {
5036  fPath->lineTo(path->pts[i].x, path->pts[i].y);
5037  ++i;
5038  }
5039  if (path->flags[i-1] & splashPathClosed) {
5040  fPath->close();
5041  }
5042  }
5043  }
5044  return fPath;
5045 }
5046 
5051  SplashCoord *matrix, SplashCoord flatness2,
5052  SplashPath *fPath) {
5055  int cNext[splashMaxCurveSplits + 1];
5056  SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh;
5057  SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh;
5058  SplashCoord dx, dy, mx, my, tx, ty, d1, d2;
5059  int p1, p2, p3;
5060 
5061  // initial segment
5062  p1 = 0;
5064  cx[p1][0] = x0; cy[p1][0] = y0;
5065  cx[p1][1] = x1; cy[p1][1] = y1;
5066  cx[p1][2] = x2; cy[p1][2] = y2;
5067  cx[p2][0] = x3; cy[p2][0] = y3;
5068  cNext[p1] = p2;
5069 
5070  while (p1 < splashMaxCurveSplits) {
5071 
5072  // get the next segment
5073  xl0 = cx[p1][0]; yl0 = cy[p1][0];
5074  xx1 = cx[p1][1]; yy1 = cy[p1][1];
5075  xx2 = cx[p1][2]; yy2 = cy[p1][2];
5076  p2 = cNext[p1];
5077  xr3 = cx[p2][0]; yr3 = cy[p2][0];
5078 
5079  // compute the distances (in device space) from the control points
5080  // to the midpoint of the straight line (this is a bit of a hack,
5081  // but it's much faster than computing the actual distances to the
5082  // line)
5083  transform(matrix, (xl0 + xr3) * 0.5, (yl0 + yr3) * 0.5, &mx, &my);
5084  transform(matrix, xx1, yy1, &tx, &ty);
5085 #if USE_FIXEDPOINT
5086  d1 = splashDist(tx, ty, mx, my);
5087 #else
5088  dx = tx - mx;
5089  dy = ty - my;
5090  d1 = dx*dx + dy*dy;
5091 #endif
5092  transform(matrix, xx2, yy2, &tx, &ty);
5093 #if USE_FIXEDPOINT
5094  d2 = splashDist(tx, ty, mx, my);
5095 #else
5096  dx = tx - mx;
5097  dy = ty - my;
5098  d2 = dx*dx + dy*dy;
5099 #endif
5100 
5101  // if the curve is flat enough, or no more subdivisions are
5102  // allowed, add the straight line segment
5103  if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) {
5104  fPath->lineTo(xr3, yr3);
5105  p1 = p2;
5106 
5107  // otherwise, subdivide the curve
5108  } else {
5109  xl1 = splashAvg(xl0, xx1);
5110  yl1 = splashAvg(yl0, yy1);
5111  xh = splashAvg(xx1, xx2);
5112  yh = splashAvg(yy1, yy2);
5113  xl2 = splashAvg(xl1, xh);
5114  yl2 = splashAvg(yl1, yh);
5115  xr2 = splashAvg(xx2, xr3);
5116  yr2 = splashAvg(yy2, yr3);
5117  xr1 = splashAvg(xh, xr2);
5118  yr1 = splashAvg(yh, yr2);
5119  xr0 = splashAvg(xl2, xr1);
5120  yr0 = splashAvg(yl2, yr1);
5121  // add the new subdivision points
5122  p3 = (p1 + p2) / 2;
5123  cx[p1][1] = xl1; cy[p1][1] = yl1;
5124  cx[p1][2] = xl2; cy[p1][2] = yl2;
5125  cNext[p1] = p3;
5126  cx[p3][0] = xr0; cy[p3][0] = yr0;
5127  cx[p3][1] = xr1; cy[p3][1] = yr1;
5128  cx[p3][2] = xr2; cy[p3][2] = yr2;
5129  cNext[p3] = p2;
5130  }
5131  }
5132 }
5133 
5135  SplashPath *dPath;
5136  SplashCoord lineDashTotal;
5137  SplashCoord lineDashStartPhase, lineDashDist, segLen;
5138  SplashCoord x0, y0, x1, y1, xa, ya;
5139  GBool lineDashStartOn, lineDashEndOn, lineDashOn, newPath;
5140  int lineDashStartIdx, lineDashIdx, subpathStart, nDashes;
5141  int i, j, k;
5142 
5143  lineDashTotal = 0;
5144  for (i = 0; i < state->lineDashLength; ++i) {
5145  lineDashTotal += state->lineDash[i];
5146  }
5147  // Acrobat simply draws nothing if the dash array is [0]
5148  if (lineDashTotal == 0) {
5149  return new SplashPath();
5150  }
5151  lineDashStartPhase = state->lineDashPhase;
5152  if (lineDashStartPhase > lineDashTotal * 2) {
5153  i = splashFloor(lineDashStartPhase / (lineDashTotal * 2));
5154  lineDashStartPhase -= lineDashTotal * i * 2;
5155  } else if (lineDashStartPhase < 0) {
5156  i = splashCeil(-lineDashStartPhase / (lineDashTotal * 2));
5157  lineDashStartPhase += lineDashTotal * i * 2;
5158  }
5159  i = splashFloor(lineDashStartPhase / lineDashTotal);
5160  lineDashStartPhase -= (SplashCoord)i * lineDashTotal;
5161  lineDashStartOn = gTrue;
5162  lineDashStartIdx = 0;
5163  if (lineDashStartPhase > 0) {
5164  while (lineDashStartPhase >= state->lineDash[lineDashStartIdx]) {
5165  lineDashStartOn = !lineDashStartOn;
5166  lineDashStartPhase -= state->lineDash[lineDashStartIdx];
5167  if (++lineDashStartIdx == state->lineDashLength) {
5168  lineDashStartIdx = 0;
5169  }
5170  }
5171  }
5172 
5173  dPath = new SplashPath();
5174 
5175  // process each subpath
5176  i = 0;
5177  while (i < path->length) {
5178 
5179  // find the end of the subpath
5180  for (j = i;
5181  j < path->length - 1 && !(path->flags[j] & splashPathLast);
5182  ++j) ;
5183 
5184  // initialize the dash parameters
5185  lineDashOn = lineDashStartOn;
5186  lineDashEndOn = lineDashStartOn;
5187  lineDashIdx = lineDashStartIdx;
5188  lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase;
5189  subpathStart = dPath->length;
5190  nDashes = 0;
5191 
5192  // process each segment of the subpath
5193  newPath = gTrue;
5194  for (k = i; k < j; ++k) {
5195 
5196  // grab the segment
5197  x0 = path->pts[k].x;
5198  y0 = path->pts[k].y;
5199  x1 = path->pts[k+1].x;
5200  y1 = path->pts[k+1].y;
5201  segLen = splashDist(x0, y0, x1, y1);
5202 
5203  // process the segment
5204  while (segLen > 0) {
5205 
5206  // Special case for zero-length dash segments: draw a very
5207  // short -- but not zero-length -- segment. This ensures that
5208  // we get the correct behavior with butt and projecting line
5209  // caps. The PS/PDF specs imply that zero-length segments are
5210  // not drawn unless the line cap is round, but Acrobat and
5211  // Ghostscript both draw very short segments (for butt caps)
5212  // and squares (for projecting caps).
5213  if (lineDashDist == 0) {
5214  if (lineDashOn) {
5215  if (newPath) {
5216  dPath->moveTo(x0, y0);
5217  newPath = gFalse;
5218  ++nDashes;
5219  }
5220  xa = x0 + ((SplashCoord)0.001 / segLen) * (x1 - x0);
5221  ya = y0 + ((SplashCoord)0.001 / segLen) * (y1 - y0);
5222  dPath->lineTo(xa, ya);
5223  }
5224 
5225  } else if (lineDashDist >= segLen) {
5226  if (lineDashOn) {
5227  if (newPath) {
5228  dPath->moveTo(x0, y0);
5229  newPath = gFalse;
5230  ++nDashes;
5231  }
5232  dPath->lineTo(x1, y1);
5233  }
5234  lineDashDist -= segLen;
5235  segLen = 0;
5236 
5237  } else {
5238  xa = x0 + (lineDashDist /