Coverage Report

Created: 2023-09-25 06:41

/src/xpdf-4.04/splash/Splash.cc
Line
Count
Source (jump to first uncovered line)
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
0
#define bezierCircle ((SplashCoord)0.55228475)
45
0
#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
0
static inline Guchar div255(int x) {
49
0
  return (Guchar)((x + (x >> 8) + 0x80) >> 8);
50
0
}
51
52
// Clip x to lie in [0, 255].
53
0
static inline Guchar clip255(int x) {
54
0
  return x < 0 ? 0 : x > 255 ? 255 : (Guchar)x;
55
0
}
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
77
  SplashPattern *pattern;
78
79
  // source alpha and color
80
  Guchar aInput;
81
  SplashColor cSrcVal;
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
87
  Guint *srcOverprintMaskPtr;
88
89
  // special cases and result color
90
  GBool noTransparency;
91
  GBool shapeOnly;
92
  SplashPipeResultColorCtrl resultColorCtrl;
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)
97
  GBool nonIsolatedGroup;
98
99
  // the "run" function
100
  void (Splash::*run)(SplashPipe *pipe, int x0, int x1, int y,
101
          Guchar *shapePtr, SplashColorPtr cSrcPtr);
102
};
103
104
SplashPipeResultColorCtrl Splash::pipeResultColorNoAlphaBlend[] = {
105
  splashPipeResultColorNoAlphaBlendMono,
106
  splashPipeResultColorNoAlphaBlendMono,
107
  splashPipeResultColorNoAlphaBlendRGB,
108
  splashPipeResultColorNoAlphaBlendRGB
109
#if SPLASH_CMYK
110
  ,
111
  splashPipeResultColorNoAlphaBlendCMYK
112
#endif
113
};
114
115
SplashPipeResultColorCtrl Splash::pipeResultColorAlphaNoBlend[] = {
116
  splashPipeResultColorAlphaNoBlendMono,
117
  splashPipeResultColorAlphaNoBlendMono,
118
  splashPipeResultColorAlphaNoBlendRGB,
119
  splashPipeResultColorAlphaNoBlendRGB
120
#if SPLASH_CMYK
121
  ,
122
  splashPipeResultColorAlphaNoBlendCMYK
123
#endif
124
};
125
126
SplashPipeResultColorCtrl Splash::pipeResultColorAlphaBlend[] = {
127
  splashPipeResultColorAlphaBlendMono,
128
  splashPipeResultColorAlphaBlendMono,
129
  splashPipeResultColorAlphaBlendRGB,
130
  splashPipeResultColorAlphaBlendRGB
131
#if SPLASH_CMYK
132
  ,
133
  splashPipeResultColorAlphaBlendCMYK
134
#endif
135
};
136
137
//------------------------------------------------------------------------
138
// modified region
139
//------------------------------------------------------------------------
140
141
0
void Splash::clearModRegion() {
142
0
  modXMin = bitmap->width;
143
0
  modYMin = bitmap->height;
144
0
  modXMax = -1;
145
0
  modYMax = -1;
146
0
}
147
148
0
inline void Splash::updateModX(int x) {
149
0
  if (x < modXMin) {
150
0
    modXMin = x;
151
0
  }
152
0
  if (x > modXMax) {
153
0
    modXMax = x;
154
0
  }
155
0
}
156
157
0
inline void Splash::updateModY(int y) {
158
0
  if (y < modYMin) {
159
0
    modYMin = y;
160
0
  }
161
0
  if (y > modYMax) {
162
0
    modYMax = y;
163
0
  }
164
0
}
165
166
//------------------------------------------------------------------------
167
// pipeline
168
//------------------------------------------------------------------------
169
170
inline void Splash::pipeInit(SplashPipe *pipe, SplashPattern *pattern,
171
           Guchar aInput, GBool usesShape,
172
0
           GBool nonIsolatedGroup, GBool usesSrcOverprint) {
173
0
  SplashColorMode mode;
174
175
0
  mode = bitmap->mode;
176
177
0
  pipe->pattern = NULL;
178
179
  // source color
180
0
  if (pattern && pattern->isStatic()) {
181
0
    pattern->getColor(0, 0, pipe->cSrcVal);
182
0
    pipe->pattern = NULL;
183
0
  } else {
184
0
    pipe->pattern = pattern;
185
0
  }
186
187
  // source alpha
188
0
  pipe->aInput = aInput;
189
190
  // source overprint mask
191
0
  pipe->srcOverprintMaskPtr = NULL;
192
193
  // special cases
194
0
  pipe->noTransparency = aInput == 255 &&
195
0
                         !state->softMask &&
196
0
                         !usesShape &&
197
0
                         !state->inNonIsolatedGroup &&
198
0
       !state->inKnockoutGroup &&
199
0
                         !nonIsolatedGroup &&
200
0
                         state->overprintMask == 0xffffffff;
201
0
  pipe->shapeOnly = aInput == 255 &&
202
0
                    !state->softMask &&
203
0
                    usesShape &&
204
0
                    !state->inNonIsolatedGroup &&
205
0
        !state->inKnockoutGroup &&
206
0
                    !nonIsolatedGroup &&
207
0
                    state->overprintMask == 0xffffffff;
208
209
  // result color
210
0
  if (pipe->noTransparency) {
211
    // the !state->blendFunc case is handled separately in pipeRun
212
0
    pipe->resultColorCtrl = pipeResultColorNoAlphaBlend[mode];
213
0
  } else if (!state->blendFunc) {
214
0
    pipe->resultColorCtrl = pipeResultColorAlphaNoBlend[mode];
215
0
  } else {
216
0
    pipe->resultColorCtrl = pipeResultColorAlphaBlend[mode];
217
0
  }
218
219
  // non-isolated group correction
220
0
  pipe->nonIsolatedGroup = nonIsolatedGroup;
221
222
  // select the 'run' function
223
0
  pipe->run = &Splash::pipeRun;
224
0
  if (overprintMaskBitmap || usesSrcOverprint) {
225
    // use Splash::pipeRun
226
0
  } else if (!pipe->pattern && pipe->noTransparency && !state->blendFunc) {
227
0
    if (mode == splashModeMono1 && !bitmap->alpha) {
228
0
      pipe->run = &Splash::pipeRunSimpleMono1;
229
0
    } else if (mode == splashModeMono8 && bitmap->alpha) {
230
0
      pipe->run = &Splash::pipeRunSimpleMono8;
231
0
    } else if (mode == splashModeRGB8 && bitmap->alpha) {
232
0
      pipe->run = &Splash::pipeRunSimpleRGB8;
233
0
    } else if (mode == splashModeBGR8 && bitmap->alpha) {
234
0
      pipe->run = &Splash::pipeRunSimpleBGR8;
235
0
#if SPLASH_CMYK
236
0
    } else if (mode == splashModeCMYK8 && bitmap->alpha) {
237
0
      pipe->run = &Splash::pipeRunSimpleCMYK8;
238
0
#endif
239
0
    }
240
0
  } else if (!pipe->pattern && pipe->shapeOnly && !state->blendFunc) {
241
0
    if (mode == splashModeMono1 && !bitmap->alpha) {
242
0
      pipe->run = &Splash::pipeRunShapeMono1;
243
0
    } else if (mode == splashModeMono8 && bitmap->alpha) {
244
0
      pipe->run = &Splash::pipeRunShapeMono8;
245
0
    } else if (mode == splashModeRGB8 && bitmap->alpha) {
246
0
      pipe->run = &Splash::pipeRunShapeRGB8;
247
0
    } else if (mode == splashModeBGR8 && bitmap->alpha) {
248
0
      pipe->run = &Splash::pipeRunShapeBGR8;
249
0
#if SPLASH_CMYK
250
0
    } else if (mode == splashModeCMYK8 && bitmap->alpha) {
251
0
      pipe->run = &Splash::pipeRunShapeCMYK8;
252
0
#endif
253
0
    } else if (mode == splashModeMono8 && !bitmap->alpha) {
254
      // this is used when drawing soft-masked images
255
0
      pipe->run = &Splash::pipeRunShapeNoAlphaMono8;
256
0
    }
257
0
  } else if (!pipe->pattern && !pipe->noTransparency && !state->softMask &&
258
0
       usesShape &&
259
0
       !(state->inNonIsolatedGroup && groupBackBitmap->alpha) &&
260
0
       !state->inKnockoutGroup &&
261
0
       !state->blendFunc && !pipe->nonIsolatedGroup) {
262
0
    if (mode == splashModeMono1 && !bitmap->alpha) {
263
0
      pipe->run = &Splash::pipeRunAAMono1;
264
0
    } else if (mode == splashModeMono8 && bitmap->alpha) {
265
0
      pipe->run = &Splash::pipeRunAAMono8;
266
0
    } else if (mode == splashModeRGB8 && bitmap->alpha) {
267
0
      pipe->run = &Splash::pipeRunAARGB8;
268
0
    } else if (mode == splashModeBGR8 && bitmap->alpha) {
269
0
      pipe->run = &Splash::pipeRunAABGR8;
270
0
#if SPLASH_CMYK
271
0
    } else if (mode == splashModeCMYK8 && bitmap->alpha) {
272
0
      pipe->run = &Splash::pipeRunAACMYK8;
273
0
#endif
274
0
    }
275
0
  } else if (!pipe->pattern &&
276
0
             aInput == 255 &&
277
0
             state->softMask &&
278
0
             usesShape &&
279
0
             !state->inNonIsolatedGroup &&
280
0
             !state->inKnockoutGroup &&
281
0
             !nonIsolatedGroup &&
282
0
             state->overprintMask == 0xffffffff &&
283
0
             !state->blendFunc) {
284
0
    if (mode == splashModeMono8 && bitmap->alpha) {
285
0
      pipe->run = &Splash::pipeRunSoftMaskMono8;
286
0
    } else if (mode == splashModeRGB8 && bitmap->alpha) {
287
0
      pipe->run = &Splash::pipeRunSoftMaskRGB8;
288
0
    } else if (mode == splashModeBGR8 && bitmap->alpha) {
289
0
      pipe->run = &Splash::pipeRunSoftMaskBGR8;
290
0
#if SPLASH_CMYK
291
0
    } else if (mode == splashModeCMYK8 && bitmap->alpha) {
292
0
      pipe->run = &Splash::pipeRunSoftMaskCMYK8;
293
0
#endif
294
0
    }
295
0
  } else if (!pipe->pattern && !pipe->noTransparency && !state->softMask &&
296
0
       usesShape &&
297
0
       state->inNonIsolatedGroup && groupBackBitmap->alpha &&
298
0
       !state->inKnockoutGroup &&
299
0
       !state->blendFunc && !pipe->nonIsolatedGroup) {
300
0
    if (mode == splashModeMono8 && bitmap->alpha) {
301
0
      pipe->run = &Splash::pipeRunNonIsoMono8;
302
0
    } else if (mode == splashModeRGB8 && bitmap->alpha) {
303
0
      pipe->run = &Splash::pipeRunNonIsoRGB8;
304
0
    } else if (mode == splashModeBGR8 && bitmap->alpha) {
305
0
      pipe->run = &Splash::pipeRunNonIsoBGR8;
306
0
#if SPLASH_CMYK
307
0
    } else if (mode == splashModeCMYK8 && bitmap->alpha) {
308
0
      pipe->run = &Splash::pipeRunNonIsoCMYK8;
309
0
#endif
310
0
    }
311
0
  }
312
0
}
313
314
// general case
315
void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y,
316
0
         Guchar *shapePtr, SplashColorPtr cSrcPtr) {
317
0
  Guchar *shapePtr2;
318
0
  Guchar shape, aSrc, aDest, alphaI, alphaIm1, alpha0, aResult;
319
0
  SplashColor cSrc, cDest, cBlend;
320
0
  Guchar shapeVal, cResult0, cResult1, cResult2, cResult3;
321
0
  int cSrcStride, shapeStride, x, lastX, t;
322
0
  SplashColorPtr destColorPtr;
323
0
  Guchar destColorMask;
324
0
  Guchar *destAlphaPtr;
325
0
  SplashColorPtr color0Ptr;
326
0
  Guchar color0Mask;
327
0
  Guchar *alpha0Ptr;
328
0
  SplashColorPtr softMaskPtr;
329
0
  Guint overprintMask;
330
0
  Guint *overprintMaskPtr;
331
0
#if SPLASH_CMYK
332
0
  Guchar aPrev;
333
0
  SplashColor cSrc2, cDest2;
334
0
#endif
335
336
0
  if (cSrcPtr && !pipe->pattern) {
337
0
    cSrcStride = bitmapComps;
338
0
  } else {
339
0
    cSrcPtr = pipe->cSrcVal;
340
0
    cSrcStride = 0;
341
0
  }
342
343
0
  if (shapePtr) {
344
0
    shapePtr2 = shapePtr;
345
0
    shapeStride = 1;
346
0
    for (; x0 <= x1; ++x0) {
347
0
      if (*shapePtr2) {
348
0
  break;
349
0
      }
350
0
      cSrcPtr += cSrcStride;
351
0
      ++shapePtr2;
352
0
      if (pipe->srcOverprintMaskPtr) {
353
0
  ++pipe->srcOverprintMaskPtr;
354
0
      }
355
0
    }
356
0
  } else {
357
0
    shapeVal = 0xff;
358
0
    shapePtr2 = &shapeVal;
359
0
    shapeStride = 0;
360
0
  }
361
0
  if (x0 > x1) {
362
0
    return;
363
0
  }
364
0
  updateModX(x0);
365
0
  updateModY(y);
366
0
  lastX = x0;
367
368
0
  useDestRow(y);
369
370
0
  if (bitmap->mode == splashModeMono1) {
371
0
    destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
372
0
    destColorMask = (Guchar)(0x80 >> (x0 & 7));
373
0
  } else {
374
0
    destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * bitmapComps];
375
0
    destColorMask = 0; // make gcc happy
376
0
  }
377
0
  if (bitmap->alpha) {
378
0
    destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
379
0
  } else {
380
0
    destAlphaPtr = NULL;
381
0
  }
382
0
  if (state->softMask) {
383
0
    softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0];
384
0
  } else {
385
0
    softMaskPtr = NULL;
386
0
  }
387
0
  if (state->inKnockoutGroup) {
388
0
    if (bitmap->mode == splashModeMono1) {
389
0
      color0Ptr =
390
0
          &groupBackBitmap->data[(groupBackY + y) * groupBackBitmap->rowSize +
391
0
         ((groupBackX + x0) >> 3)];
392
0
      color0Mask = (Guchar)(0x80 >> ((groupBackX + x0) & 7));
393
0
    } else {
394
0
      color0Ptr =
395
0
          &groupBackBitmap->data[(groupBackY + y) * groupBackBitmap->rowSize +
396
0
         (groupBackX + x0) * bitmapComps];
397
0
      color0Mask = 0; // make gcc happy
398
0
    }
399
0
  } else {
400
0
    color0Ptr = NULL;
401
0
    color0Mask = 0; // make gcc happy
402
0
  }
403
0
  if (state->inNonIsolatedGroup && groupBackBitmap->alpha) {
404
0
    alpha0Ptr =
405
0
        &groupBackBitmap->alpha[(groupBackY + y)
406
0
          * groupBackBitmap->alphaRowSize +
407
0
        (groupBackX + x0)];
408
0
  } else {
409
0
    alpha0Ptr = NULL;
410
0
  }
411
0
  if (overprintMaskBitmap) {
412
0
    overprintMaskPtr = overprintMaskBitmap + y * bitmap->width + x0;
413
0
  } else {
414
0
    overprintMaskPtr = NULL;
415
0
  }
416
417
0
  for (x = x0; x <= x1; ++x) {
418
419
    //----- shape
420
421
0
    shape = *shapePtr2;
422
0
    if (!shape) {
423
0
      if (bitmap->mode == splashModeMono1) {
424
0
  destColorPtr += destColorMask & 1;
425
0
  destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1));
426
0
      } else {
427
0
  destColorPtr += bitmapComps;
428
0
      }
429
0
      if (destAlphaPtr) {
430
0
  ++destAlphaPtr;
431
0
      }
432
0
      if (softMaskPtr) {
433
0
  ++softMaskPtr;
434
0
      }
435
0
      if (color0Ptr) {
436
0
  if (bitmap->mode == splashModeMono1) {
437
0
    color0Ptr += color0Mask & 1;
438
0
    color0Mask = (Guchar)((color0Mask << 7) | (color0Mask >> 1));
439
0
  } else {
440
0
    color0Ptr += bitmapComps;
441
0
  }
442
0
      }
443
0
      if (alpha0Ptr) {
444
0
  ++alpha0Ptr;
445
0
      }
446
0
      cSrcPtr += cSrcStride;
447
0
      shapePtr2 += shapeStride;
448
0
      if (pipe->srcOverprintMaskPtr) {
449
0
  ++pipe->srcOverprintMaskPtr;
450
0
      }
451
0
      if (overprintMaskPtr) {
452
0
  ++overprintMaskPtr;
453
0
      }
454
0
      continue;
455
0
    }
456
0
    lastX = x;
457
458
    //----- source color
459
460
    // static pattern: handled in pipeInit
461
    // fixed color: handled in pipeInit
462
463
    // dynamic pattern
464
0
    if (pipe->pattern) {
465
0
      pipe->pattern->getColor(x, y, pipe->cSrcVal);
466
0
    }
467
468
0
    cResult0 = cResult1 = cResult2 = cResult3 = 0; // make gcc happy
469
470
0
    if (pipe->noTransparency && !state->blendFunc) {
471
472
      //----- handle overprint
473
474
0
      if (overprintMaskPtr) {
475
0
  *overprintMaskPtr++ = 0xffffffff;
476
0
      }
477
478
      //----- result color
479
480
0
      switch (bitmap->mode) {
481
0
      case splashModeMono1:
482
0
      case splashModeMono8:
483
0
  cResult0 = state->grayTransfer[cSrcPtr[0]];
484
0
  break;
485
0
      case splashModeRGB8:
486
0
      case splashModeBGR8:
487
0
  cResult0 = state->rgbTransferR[cSrcPtr[0]];
488
0
  cResult1 = state->rgbTransferG[cSrcPtr[1]];
489
0
  cResult2 = state->rgbTransferB[cSrcPtr[2]];
490
0
  break;
491
0
#if SPLASH_CMYK
492
0
      case splashModeCMYK8:
493
0
  cResult0 = state->cmykTransferC[cSrcPtr[0]];
494
0
  cResult1 = state->cmykTransferM[cSrcPtr[1]];
495
0
  cResult2 = state->cmykTransferY[cSrcPtr[2]];
496
0
  cResult3 = state->cmykTransferK[cSrcPtr[3]];
497
0
  break;
498
0
#endif
499
0
      }
500
0
      aResult = 255;
501
502
0
    } else { // if (noTransparency && !blendFunc)
503
504
      //----- read destination pixel
505
      //      (or backdrop color, for knockout groups)
506
507
0
      if (color0Ptr) {
508
509
0
  switch (bitmap->mode) {
510
0
  case splashModeMono1:
511
0
    cDest[0] = (*color0Ptr & color0Mask) ? 0xff : 0x00;
512
0
    color0Ptr += color0Mask & 1;
513
0
    color0Mask = (Guchar)((color0Mask << 7) | (color0Mask >> 1));
514
0
    break;
515
0
  case splashModeMono8:
516
0
    cDest[0] = *color0Ptr++;
517
0
    break;
518
0
  case splashModeRGB8:
519
0
    cDest[0] = color0Ptr[0];
520
0
    cDest[1] = color0Ptr[1];
521
0
    cDest[2] = color0Ptr[2];
522
0
    color0Ptr += 3;
523
0
    break;
524
0
  case splashModeBGR8:
525
0
    cDest[2] = color0Ptr[0];
526
0
    cDest[1] = color0Ptr[1];
527
0
    cDest[0] = color0Ptr[2];
528
0
    color0Ptr += 3;
529
0
    break;
530
0
#if SPLASH_CMYK
531
0
  case splashModeCMYK8:
532
0
    cDest[0] = color0Ptr[0];
533
0
    cDest[1] = color0Ptr[1];
534
0
    cDest[2] = color0Ptr[2];
535
0
    cDest[3] = color0Ptr[3];
536
0
    color0Ptr += 4;
537
0
    break;
538
0
#endif
539
0
  }
540
541
0
      } else {
542
543
0
  switch (bitmap->mode) {
544
0
  case splashModeMono1:
545
0
    cDest[0] = (*destColorPtr & destColorMask) ? 0xff : 0x00;
546
0
    break;
547
0
  case splashModeMono8:
548
0
    cDest[0] = *destColorPtr;
549
0
    break;
550
0
  case splashModeRGB8:
551
0
    cDest[0] = destColorPtr[0];
552
0
    cDest[1] = destColorPtr[1];
553
0
    cDest[2] = destColorPtr[2];
554
0
    break;
555
0
  case splashModeBGR8:
556
0
    cDest[0] = destColorPtr[2];
557
0
    cDest[1] = destColorPtr[1];
558
0
    cDest[2] = destColorPtr[0];
559
0
    break;
560
0
#if SPLASH_CMYK
561
0
  case splashModeCMYK8:
562
0
    cDest[0] = destColorPtr[0];
563
0
    cDest[1] = destColorPtr[1];
564
0
    cDest[2] = destColorPtr[2];
565
0
    cDest[3] = destColorPtr[3];
566
0
    break;
567
0
#endif
568
0
  }
569
570
0
      }
571
572
0
      if (destAlphaPtr) {
573
0
  aDest = *destAlphaPtr;
574
0
      } else {
575
0
  aDest = 0xff;
576
0
      }
577
578
      //----- read source color; handle overprint
579
580
0
      if (pipe->srcOverprintMaskPtr) {
581
0
  overprintMask = *pipe->srcOverprintMaskPtr++;
582
0
      } else {
583
0
  overprintMask = state->overprintMask;
584
0
      }
585
0
      if (overprintMaskPtr) {
586
0
  *overprintMaskPtr++ |= overprintMask;
587
0
      }
588
589
0
      switch (bitmap->mode) {
590
0
      case splashModeMono1:
591
0
      case splashModeMono8:
592
0
  cSrc[0] = state->grayTransfer[cSrcPtr[0]];
593
0
  break;
594
0
      case splashModeRGB8:
595
0
      case splashModeBGR8:
596
0
  cSrc[0] = state->rgbTransferR[cSrcPtr[0]];
597
0
  cSrc[1] = state->rgbTransferG[cSrcPtr[1]];
598
0
  cSrc[2] = state->rgbTransferB[cSrcPtr[2]];
599
0
  break;
600
0
#if SPLASH_CMYK
601
0
      case splashModeCMYK8:
602
0
  if (alpha0Ptr) {   // non-isolated group
603
0
    if (color0Ptr) { //   non-isolated, knockout group
604
0
      aPrev = *alpha0Ptr;
605
0
    } else {         //   non-isolated, non-knockout group
606
0
      aPrev = (Guchar)(*alpha0Ptr + aDest - div255(*alpha0Ptr * aDest));
607
0
    }
608
0
  } else {           // isolated group
609
0
    if (color0Ptr) { //   isolated, knockout group
610
0
      aPrev = 0;
611
0
    } else {         //   isolated, non-knockout group
612
0
      aPrev = aDest;
613
0
    }
614
0
  }
615
0
  if (overprintMask & 0x01) {
616
0
    cSrc[0] = state->cmykTransferC[cSrcPtr[0]];
617
0
  } else {
618
0
    cSrc[0] = div255(aPrev * cDest[0]);
619
0
  }
620
0
  if (overprintMask & 0x02) {
621
0
    cSrc[1] = state->cmykTransferM[cSrcPtr[1]];
622
0
  } else {
623
0
    cSrc[1] = div255(aPrev * cDest[1]);
624
0
  }
625
0
  if (overprintMask & 0x04) {
626
0
    cSrc[2] = state->cmykTransferY[cSrcPtr[2]];
627
0
  } else {
628
0
    cSrc[2] = div255(aPrev * cDest[2]);
629
0
  }
630
0
  if (overprintMask & 0x08) {
631
0
    cSrc[3] = state->cmykTransferK[cSrcPtr[3]];
632
0
  } else {
633
0
    cSrc[3] = div255(aPrev * cDest[3]);
634
0
  }
635
0
  break;
636
0
#endif
637
0
      }
638
639
      //----- source alpha
640
641
0
      if (softMaskPtr) {
642
0
  if (shapePtr) {
643
0
    aSrc = div255(div255(pipe->aInput * *softMaskPtr++) * shape);
644
0
  } else {
645
0
    aSrc = div255(pipe->aInput * *softMaskPtr++);
646
0
  }
647
0
      } else if (shapePtr) {
648
0
  aSrc = div255(pipe->aInput * shape);
649
0
      } else {
650
0
  aSrc = pipe->aInput;
651
0
      }
652
653
      //----- non-isolated group correction
654
655
0
      if (pipe->nonIsolatedGroup) {
656
  // This path is only used when Splash::composite() is called to
657
  // composite a non-isolated group onto the backdrop.  In this
658
  // case, shape is the source (group) alpha.
659
  //
660
  // In a nested non-isolated group, i.e., if the destination is
661
  // also a non-isolated group (state->inNonIsolatedGroup), we
662
  // need to compute the corrected alpha, because the
663
  // destination is is storing group alpha (same computation as
664
  // blitCorrectedAlpha).
665
0
  if (alpha0Ptr) {
666
0
    t = *alpha0Ptr;
667
0
    t = (Guchar)(aDest + t - div255(aDest * t));
668
0
  } else {
669
0
    t = aDest;
670
0
  }
671
0
  t = (t * 255) / shape - t;
672
0
  switch (bitmap->mode) {
673
0
#if SPLASH_CMYK
674
0
  case splashModeCMYK8:
675
0
    cSrc[3] = clip255(cSrc[3] + ((cSrc[3] - cDest[3]) * t) / 255);
676
0
#endif
677
0
  case splashModeRGB8:
678
0
  case splashModeBGR8:
679
0
    cSrc[2] = clip255(cSrc[2] + ((cSrc[2] - cDest[2]) * t) / 255);
680
0
    cSrc[1] = clip255(cSrc[1] + ((cSrc[1] - cDest[1]) * t) / 255);
681
0
  case splashModeMono1:
682
0
  case splashModeMono8:
683
0
    cSrc[0] = clip255(cSrc[0] + ((cSrc[0] - cDest[0]) * t) / 255);
684
0
    break;
685
0
  }
686
0
      }
687
688
      //----- blend function
689
690
0
      if (state->blendFunc) {
691
0
#if SPLASH_CMYK
692
0
  if (bitmap->mode == splashModeCMYK8) {
693
    // convert colors to additive
694
0
    cSrc2[0] = (Guchar)(0xff - cSrc[0]);
695
0
    cSrc2[1] = (Guchar)(0xff - cSrc[1]);
696
0
    cSrc2[2] = (Guchar)(0xff - cSrc[2]);
697
0
    cSrc2[3] = (Guchar)(0xff - cSrc[3]);
698
0
    cDest2[0] = (Guchar)(0xff - cDest[0]);
699
0
    cDest2[1] = (Guchar)(0xff - cDest[1]);
700
0
    cDest2[2] = (Guchar)(0xff - cDest[2]);
701
0
    cDest2[3] = (Guchar)(0xff - cDest[3]);
702
0
    (*state->blendFunc)(cSrc2, cDest2, cBlend, bitmap->mode);
703
    // convert result back to subtractive
704
0
    cBlend[0] = (Guchar)(0xff - cBlend[0]);
705
0
    cBlend[1] = (Guchar)(0xff - cBlend[1]);
706
0
    cBlend[2] = (Guchar)(0xff - cBlend[2]);
707
0
    cBlend[3] = (Guchar)(0xff - cBlend[3]);
708
0
  } else
709
0
#endif
710
0
  (*state->blendFunc)(cSrc, cDest, cBlend, bitmap->mode);
711
0
      }
712
713
      //----- result alpha and non-isolated group element correction
714
715
      // alphaI = alpha_i
716
      // alphaIm1 = alpha_(i-1)
717
718
0
      if (pipe->noTransparency) {
719
0
  alphaI = alphaIm1 = aResult = 255;
720
0
      } else if (alpha0Ptr) {
721
0
  if (color0Ptr) {
722
    // non-isolated, knockout
723
0
    aResult = aSrc;
724
0
    alpha0 = *alpha0Ptr++;
725
0
    alphaI = (Guchar)(aSrc + alpha0 - div255(aSrc * alpha0));
726
0
    alphaIm1 = alpha0;
727
0
  } else {
728
    // non-isolated, non-knockout
729
0
    aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
730
0
    alpha0 = *alpha0Ptr++;
731
0
    alphaI = (Guchar)(aResult + alpha0 - div255(aResult * alpha0));
732
0
    alphaIm1 = (Guchar)(alpha0 + aDest - div255(alpha0 * aDest));
733
0
  }
734
0
      } else {
735
0
  if (color0Ptr) {
736
    // isolated, knockout
737
0
    aResult = aSrc;
738
0
    alphaI = aSrc;
739
0
    alphaIm1 = 0;
740
0
  } else {
741
    // isolated, non-knockout
742
0
    aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
743
0
    alphaI = aResult;
744
0
    alphaIm1 = aDest;
745
0
  }
746
0
      }
747
748
      //----- result color
749
750
0
      switch (pipe->resultColorCtrl) {
751
752
0
      case splashPipeResultColorNoAlphaBlendMono:
753
0
  cResult0 = div255((255 - aDest) * cSrc[0] + aDest * cBlend[0]);
754
0
  break;
755
0
      case splashPipeResultColorNoAlphaBlendRGB:
756
0
  cResult0 = div255((255 - aDest) * cSrc[0] + aDest * cBlend[0]);
757
0
  cResult1 = div255((255 - aDest) * cSrc[1] + aDest * cBlend[1]);
758
0
  cResult2 = div255((255 - aDest) * cSrc[2] + aDest * cBlend[2]);
759
0
  break;
760
0
#if SPLASH_CMYK
761
0
      case splashPipeResultColorNoAlphaBlendCMYK:
762
0
  cResult0 = div255((255 - aDest) * cSrc[0] + aDest * cBlend[0]);
763
0
  cResult1 = div255((255 - aDest) * cSrc[1] + aDest * cBlend[1]);
764
0
  cResult2 = div255((255 - aDest) * cSrc[2] + aDest * cBlend[2]);
765
0
  cResult3 = div255((255 - aDest) * cSrc[3] + aDest * cBlend[3]);
766
0
  break;
767
0
#endif
768
769
0
      case splashPipeResultColorAlphaNoBlendMono:
770
0
  if (alphaI == 0) {
771
0
    cResult0 = 0;
772
0
  } else {
773
0
    cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] + aSrc * cSrc[0])
774
0
            / alphaI);
775
0
  }
776
0
  break;
777
0
      case splashPipeResultColorAlphaNoBlendRGB:
778
0
  if (alphaI == 0) {
779
0
    cResult0 = 0;
780
0
    cResult1 = 0;
781
0
    cResult2 = 0;
782
0
  } else {
783
0
    cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] + aSrc * cSrc[0])
784
0
            / alphaI);
785
0
    cResult1 = (Guchar)(((alphaI - aSrc) * cDest[1] + aSrc * cSrc[1])
786
0
            / alphaI);
787
0
    cResult2 = (Guchar)(((alphaI - aSrc) * cDest[2] + aSrc * cSrc[2])
788
0
            / alphaI);
789
0
  }
790
0
  break;
791
0
#if SPLASH_CMYK
792
0
      case splashPipeResultColorAlphaNoBlendCMYK:
793
0
  if (alphaI == 0) {
794
0
    cResult0 = 0;
795
0
    cResult1 = 0;
796
0
    cResult2 = 0;
797
0
    cResult3 = 0;
798
0
  } else {
799
0
    cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] + aSrc * cSrc[0])
800
0
            / alphaI);
801
0
    cResult1 = (Guchar)(((alphaI - aSrc) * cDest[1] + aSrc * cSrc[1])
802
0
            / alphaI);
803
0
    cResult2 = (Guchar)(((alphaI - aSrc) * cDest[2] + aSrc * cSrc[2])
804
0
            / alphaI);
805
0
    cResult3 = (Guchar)(((alphaI - aSrc) * cDest[3] + aSrc * cSrc[3])
806
0
            / alphaI);
807
0
  }
808
0
  break;
809
0
#endif
810
811
0
      case splashPipeResultColorAlphaBlendMono:
812
0
  if (alphaI == 0) {
813
0
    cResult0 = 0;
814
0
  } else {
815
0
    cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] +
816
0
             aSrc * ((255 - alphaIm1) * cSrc[0] +
817
0
               alphaIm1 * cBlend[0]) / 255)
818
0
            / alphaI);
819
0
  }
820
0
  break;
821
0
      case splashPipeResultColorAlphaBlendRGB:
822
0
  if (alphaI == 0) {
823
0
    cResult0 = 0;
824
0
    cResult1 = 0;
825
0
    cResult2 = 0;
826
0
  } else {
827
0
    cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] +
828
0
             aSrc * ((255 - alphaIm1) * cSrc[0] +
829
0
               alphaIm1 * cBlend[0]) / 255)
830
0
            / alphaI);
831
0
    cResult1 = (Guchar)(((alphaI - aSrc) * cDest[1] +
832
0
             aSrc * ((255 - alphaIm1) * cSrc[1] +
833
0
               alphaIm1 * cBlend[1]) / 255)
834
0
            / alphaI);
835
0
    cResult2 = (Guchar)(((alphaI - aSrc) * cDest[2] +
836
0
             aSrc * ((255 - alphaIm1) * cSrc[2] +
837
0
               alphaIm1 * cBlend[2]) / 255)
838
0
            / alphaI);
839
0
  }
840
0
  break;
841
0
#if SPLASH_CMYK
842
0
      case splashPipeResultColorAlphaBlendCMYK:
843
0
  if (alphaI == 0) {
844
0
    cResult0 = 0;
845
0
    cResult1 = 0;
846
0
    cResult2 = 0;
847
0
    cResult3 = 0;
848
0
  } else {
849
0
    cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] +
850
0
             aSrc * ((255 - alphaIm1) * cSrc[0] +
851
0
               alphaIm1 * cBlend[0]) / 255)
852
0
            / alphaI);
853
0
    cResult1 = (Guchar)(((alphaI - aSrc) * cDest[1] +
854
0
             aSrc * ((255 - alphaIm1) * cSrc[1] +
855
0
               alphaIm1 * cBlend[1]) / 255)
856
0
            / alphaI);
857
0
    cResult2 = (Guchar)(((alphaI - aSrc) * cDest[2] +
858
0
             aSrc * ((255 - alphaIm1) * cSrc[2] +
859
0
               alphaIm1 * cBlend[2]) / 255)
860
0
            / alphaI);
861
0
    cResult3 = (Guchar)(((alphaI - aSrc) * cDest[3] +
862
0
             aSrc * ((255 - alphaIm1) * cSrc[3] +
863
0
               alphaIm1 * cBlend[3]) / 255)
864
0
            / alphaI);
865
0
  }
866
0
  break;
867
0
#endif
868
0
      }
869
870
0
    } // if (noTransparency && !blendFunc)
871
872
    //----- write destination pixel
873
874
0
    switch (bitmap->mode) {
875
0
    case splashModeMono1:
876
0
      if (state->screen->test(x, y, cResult0)) {
877
0
  *destColorPtr |= destColorMask;
878
0
      } else {
879
0
  *destColorPtr &= (Guchar)~destColorMask;
880
0
      }
881
0
      destColorPtr += destColorMask & 1;
882
0
      destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1));
883
0
      break;
884
0
    case splashModeMono8:
885
0
      *destColorPtr++ = cResult0;
886
0
      break;
887
0
    case splashModeRGB8:
888
0
      destColorPtr[0] = cResult0;
889
0
      destColorPtr[1] = cResult1;
890
0
      destColorPtr[2] = cResult2;
891
0
      destColorPtr += 3;
892
0
      break;
893
0
    case splashModeBGR8:
894
0
      destColorPtr[0] = cResult2;
895
0
      destColorPtr[1] = cResult1;
896
0
      destColorPtr[2] = cResult0;
897
0
      destColorPtr += 3;
898
0
      break;
899
0
#if SPLASH_CMYK
900
0
    case splashModeCMYK8:
901
0
      destColorPtr[0] = cResult0;
902
0
      destColorPtr[1] = cResult1;
903
0
      destColorPtr[2] = cResult2;
904
0
      destColorPtr[3] = cResult3;
905
0
      destColorPtr += 4;
906
0
      break;
907
0
#endif
908
0
    }
909
0
    if (destAlphaPtr) {
910
0
      *destAlphaPtr++ = aResult;
911
0
    }
912
913
0
    cSrcPtr += cSrcStride;
914
0
    shapePtr2 += shapeStride;
915
0
  } // for (x ...)
916
917
0
  updateModX(lastX);
918
0
}
919
920
// special case:
921
// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
922
// bitmap->mode == splashModeMono1 && !bitmap->alpha) {
923
void Splash::pipeRunSimpleMono1(SplashPipe *pipe, int x0, int x1, int y,
924
0
        Guchar *shapePtr, SplashColorPtr cSrcPtr) {
925
0
  Guchar cResult0;
926
0
  SplashColorPtr destColorPtr;
927
0
  Guchar destColorMask;
928
0
  SplashScreenCursor screenCursor;
929
0
  int cSrcStride, x;
930
931
0
  if (cSrcPtr) {
932
0
    cSrcStride = 1;
933
0
  } else {
934
0
    cSrcPtr = pipe->cSrcVal;
935
0
    cSrcStride = 0;
936
0
  }
937
0
  if (x0 > x1) {
938
0
    return;
939
0
  }
940
0
  updateModX(x0);
941
0
  updateModX(x1);
942
0
  updateModY(y);
943
944
0
  useDestRow(y);
945
946
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
947
0
  destColorMask = (Guchar)(0x80 >> (x0 & 7));
948
949
0
  screenCursor = state->screen->getTestCursor(y);
950
951
0
  for (x = x0; x <= x1; ++x) {
952
953
    //----- write destination pixel
954
0
    cResult0 = state->grayTransfer[cSrcPtr[0]];
955
0
    if (state->screen->testWithCursor(screenCursor, x, cResult0)) {
956
0
      *destColorPtr |= destColorMask;
957
0
    } else {
958
0
      *destColorPtr &= (Guchar)~destColorMask;
959
0
    }
960
0
    destColorPtr += destColorMask & 1;
961
0
    destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1));
962
963
0
    cSrcPtr += cSrcStride;
964
0
  }
965
0
}
966
967
// special case:
968
// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
969
// bitmap->mode == splashModeMono8 && bitmap->alpha) {
970
void Splash::pipeRunSimpleMono8(SplashPipe *pipe, int x0, int x1, int y,
971
0
        Guchar *shapePtr, SplashColorPtr cSrcPtr) {
972
0
  SplashColorPtr destColorPtr;
973
0
  Guchar *destAlphaPtr;
974
0
  int cSrcStride, x;
975
976
0
  if (cSrcPtr) {
977
0
    cSrcStride = 1;
978
0
  } else {
979
0
    cSrcPtr = pipe->cSrcVal;
980
0
    cSrcStride = 0;
981
0
  }
982
0
  if (x0 > x1) {
983
0
    return;
984
0
  }
985
0
  updateModX(x0);
986
0
  updateModX(x1);
987
0
  updateModY(y);
988
989
0
  useDestRow(y);
990
991
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
992
0
  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
993
994
0
  for (x = x0; x <= x1; ++x) {
995
996
    //----- write destination pixel
997
0
    *destColorPtr++ = state->grayTransfer[cSrcPtr[0]];
998
0
    *destAlphaPtr++ = 255;
999
1000
0
    cSrcPtr += cSrcStride;
1001
0
  }
1002
0
}
1003
1004
// special case:
1005
// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
1006
// bitmap->mode == splashModeRGB8 && bitmap->alpha) {
1007
void Splash::pipeRunSimpleRGB8(SplashPipe *pipe, int x0, int x1, int y,
1008
0
             Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1009
0
  SplashColorPtr destColorPtr;
1010
0
  Guchar *destAlphaPtr;
1011
0
  int cSrcStride, x;
1012
1013
0
  if (cSrcPtr) {
1014
0
    cSrcStride = 3;
1015
0
  } else {
1016
0
    cSrcPtr = pipe->cSrcVal;
1017
0
    cSrcStride = 0;
1018
0
  }
1019
0
  if (x0 > x1) {
1020
0
    return;
1021
0
  }
1022
0
  updateModX(x0);
1023
0
  updateModX(x1);
1024
0
  updateModY(y);
1025
1026
0
  useDestRow(y);
1027
1028
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
1029
0
  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
1030
1031
0
  for (x = x0; x <= x1; ++x) {
1032
1033
    //----- write destination pixel
1034
0
    destColorPtr[0] = state->rgbTransferR[cSrcPtr[0]];
1035
0
    destColorPtr[1] = state->rgbTransferG[cSrcPtr[1]];
1036
0
    destColorPtr[2] = state->rgbTransferB[cSrcPtr[2]];
1037
0
    destColorPtr += 3;
1038
0
    *destAlphaPtr++ = 255;
1039
1040
0
    cSrcPtr += cSrcStride;
1041
0
  }
1042
0
}
1043
1044
// special case:
1045
// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
1046
// bitmap->mode == splashModeBGR8 && bitmap->alpha) {
1047
void Splash::pipeRunSimpleBGR8(SplashPipe *pipe, int x0, int x1, int y,
1048
0
             Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1049
0
  SplashColorPtr destColorPtr;
1050
0
  Guchar *destAlphaPtr;
1051
0
  int cSrcStride, x;
1052
1053
0
  if (cSrcPtr) {
1054
0
    cSrcStride = 3;
1055
0
  } else {
1056
0
    cSrcPtr = pipe->cSrcVal;
1057
0
    cSrcStride = 0;
1058
0
  }
1059
0
  if (x0 > x1) {
1060
0
    return;
1061
0
  }
1062
0
  updateModX(x0);
1063
0
  updateModX(x1);
1064
0
  updateModY(y);
1065
1066
0
  useDestRow(y);
1067
1068
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
1069
0
  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
1070
1071
0
  for (x = x0; x <= x1; ++x) {
1072
1073
    //----- write destination pixel
1074
0
    destColorPtr[0] = state->rgbTransferB[cSrcPtr[2]];
1075
0
    destColorPtr[1] = state->rgbTransferG[cSrcPtr[1]];
1076
0
    destColorPtr[2] = state->rgbTransferR[cSrcPtr[0]];
1077
0
    destColorPtr += 3;
1078
0
    *destAlphaPtr++ = 255;
1079
1080
0
    cSrcPtr += cSrcStride;
1081
0
  }
1082
0
}
1083
1084
#if SPLASH_CMYK
1085
// special case:
1086
// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
1087
// bitmap->mode == splashModeCMYK8 && bitmap->alpha) {
1088
void Splash::pipeRunSimpleCMYK8(SplashPipe *pipe, int x0, int x1, int y,
1089
0
        Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1090
0
  SplashColorPtr destColorPtr;
1091
0
  Guchar *destAlphaPtr;
1092
0
  int cSrcStride, x;
1093
1094
0
  if (cSrcPtr) {
1095
0
    cSrcStride = 4;
1096
0
  } else {
1097
0
    cSrcPtr = pipe->cSrcVal;
1098
0
    cSrcStride = 0;
1099
0
  }
1100
0
  if (x0 > x1) {
1101
0
    return;
1102
0
  }
1103
0
  updateModX(x0);
1104
0
  updateModX(x1);
1105
0
  updateModY(y);
1106
1107
0
  useDestRow(y);
1108
1109
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x0];
1110
0
  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
1111
1112
0
  for (x = x0; x <= x1; ++x) {
1113
1114
    //----- write destination pixel
1115
0
    destColorPtr[0] = state->cmykTransferC[cSrcPtr[0]];
1116
0
    destColorPtr[1] = state->cmykTransferM[cSrcPtr[1]];
1117
0
    destColorPtr[2] = state->cmykTransferY[cSrcPtr[2]];
1118
0
    destColorPtr[3] = state->cmykTransferK[cSrcPtr[3]];
1119
0
    destColorPtr += 4;
1120
0
    *destAlphaPtr++ = 255;
1121
1122
0
    cSrcPtr += cSrcStride;
1123
0
  }
1124
0
}
1125
#endif
1126
1127
1128
// special case:
1129
// !pipe->pattern && pipe->shapeOnly && !state->blendFunc &&
1130
// bitmap->mode == splashModeMono1 && !bitmap->alpha
1131
void Splash::pipeRunShapeMono1(SplashPipe *pipe, int x0, int x1, int y,
1132
0
             Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1133
0
  Guchar shape, aSrc, cSrc0, cDest0, cResult0;
1134
0
  SplashColorPtr destColorPtr;
1135
0
  Guchar destColorMask;
1136
0
  SplashScreenCursor screenCursor;
1137
0
  int cSrcStride, x, lastX;
1138
1139
0
  if (cSrcPtr) {
1140
0
    cSrcStride = 1;
1141
0
  } else {
1142
0
    cSrcPtr = pipe->cSrcVal;
1143
0
    cSrcStride = 0;
1144
0
  }
1145
0
  for (; x0 <= x1; ++x0) {
1146
0
    if (*shapePtr) {
1147
0
      break;
1148
0
    }
1149
0
    cSrcPtr += cSrcStride;
1150
0
    ++shapePtr;
1151
0
  }
1152
0
  if (x0 > x1) {
1153
0
    return;
1154
0
  }
1155
0
  updateModX(x0);
1156
0
  updateModY(y);
1157
0
  lastX = x0;
1158
1159
0
  useDestRow(y);
1160
1161
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
1162
0
  destColorMask = (Guchar)(0x80 >> (x0 & 7));
1163
1164
0
  screenCursor = state->screen->getTestCursor(y);
1165
1166
0
  for (x = x0; x <= x1; ++x) {
1167
1168
    //----- shape
1169
0
    shape = *shapePtr;
1170
0
    if (!shape) {
1171
0
      destColorPtr += destColorMask & 1;
1172
0
      destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1));
1173
0
      cSrcPtr += cSrcStride;
1174
0
      ++shapePtr;
1175
0
      continue;
1176
0
    }
1177
0
    lastX = x;
1178
1179
    //----- source color
1180
0
    cSrc0 = state->grayTransfer[cSrcPtr[0]];
1181
1182
    //----- source alpha
1183
0
    aSrc = shape;
1184
1185
    //----- special case for aSrc = 255
1186
0
    if (aSrc == 255) {
1187
0
      cResult0 = cSrc0;
1188
0
    } else {
1189
1190
      //----- read destination pixel
1191
0
      cDest0 = (*destColorPtr & destColorMask) ? 0xff : 0x00;
1192
1193
      //----- result color
1194
      // note: aDest = alphaI = aResult = 0xff
1195
0
      cResult0 = (Guchar)div255((0xff - aSrc) * cDest0 + aSrc * cSrc0);
1196
0
    }
1197
1198
    //----- write destination pixel
1199
0
    if (state->screen->testWithCursor(screenCursor, x, cResult0)) {
1200
0
      *destColorPtr |= destColorMask;
1201
0
    } else {
1202
0
      *destColorPtr &= (Guchar)~destColorMask;
1203
0
    }
1204
0
    destColorPtr += destColorMask & 1;
1205
0
    destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1));
1206
1207
0
    cSrcPtr += cSrcStride;
1208
0
    ++shapePtr;
1209
0
  }
1210
1211
0
  updateModX(lastX);
1212
0
}
1213
1214
// special case:
1215
// !pipe->pattern && pipe->shapeOnly && !state->blendFunc &&
1216
// bitmap->mode == splashModeMono8 && bitmap->alpha
1217
void Splash::pipeRunShapeMono8(SplashPipe *pipe, int x0, int x1, int y,
1218
0
             Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1219
0
  Guchar shape, aSrc, aDest, alphaI, aResult, cSrc0, cDest0, cResult0;
1220
0
  SplashColorPtr destColorPtr;
1221
0
  Guchar *destAlphaPtr;
1222
0
  int cSrcStride, x, lastX;
1223
1224
0
  if (cSrcPtr) {
1225
0
    cSrcStride = 1;
1226
0
  } else {
1227
0
    cSrcPtr = pipe->cSrcVal;
1228
0
    cSrcStride = 0;
1229
0
  }
1230
0
  for (; x0 <= x1; ++x0) {
1231
0
    if (*shapePtr) {
1232
0
      break;
1233
0
    }
1234
0
    cSrcPtr += cSrcStride;
1235
0
    ++shapePtr;
1236
0
  }
1237
0
  if (x0 > x1) {
1238
0
    return;
1239
0
  }
1240
0
  updateModX(x0);
1241
0
  updateModY(y);
1242
0
  lastX = x0;
1243
1244
0
  useDestRow(y);
1245
1246
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
1247
0
  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
1248
1249
0
  for (x = x0; x <= x1; ++x) {
1250
1251
    //----- shape
1252
0
    shape = *shapePtr;
1253
0
    if (!shape) {
1254
0
      ++destColorPtr;
1255
0
      ++destAlphaPtr;
1256
0
      cSrcPtr += cSrcStride;
1257
0
      ++shapePtr;
1258
0
      continue;
1259
0
    }
1260
0
    lastX = x;
1261
1262
    //----- source color
1263
0
    cSrc0 = state->grayTransfer[cSrcPtr[0]];
1264
1265
    //----- source alpha
1266
0
    aSrc = shape;
1267
1268
    //----- special case for aSrc = 255
1269
0
    if (aSrc == 255) {
1270
0
      aResult = 255;
1271
0
      cResult0 = cSrc0;
1272
0
    } else {
1273
1274
      //----- read destination alpha
1275
0
      aDest = *destAlphaPtr;
1276
1277
      //----- special case for aDest = 0
1278
0
      if (aDest == 0) {
1279
0
  aResult = aSrc;
1280
0
  cResult0 = cSrc0;
1281
0
      } else {
1282
1283
  //----- read destination pixel
1284
0
  cDest0 = *destColorPtr;
1285
1286
  //----- result alpha and non-isolated group element correction
1287
0
  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
1288
0
  alphaI = aResult;
1289
1290
  //----- result color
1291
0
  cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
1292
0
      }
1293
0
    }
1294
1295
    //----- write destination pixel
1296
0
    *destColorPtr++ = cResult0;
1297
0
    *destAlphaPtr++ = aResult;
1298
1299
0
    cSrcPtr += cSrcStride;
1300
0
    ++shapePtr;
1301
0
  }
1302
1303
0
  updateModX(lastX);
1304
0
}
1305
1306
// special case:
1307
// !pipe->pattern && pipe->shapeOnly && !state->blendFunc &&
1308
// bitmap->mode == splashModeRGB8 && bitmap->alpha
1309
void Splash::pipeRunShapeRGB8(SplashPipe *pipe, int x0, int x1, int y,
1310
0
            Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1311
0
  Guchar shape, aSrc, aDest, alphaI, aResult;
1312
0
  Guchar cSrc0, cSrc1, cSrc2;
1313
0
  Guchar cDest0, cDest1, cDest2;
1314
0
  Guchar cResult0, cResult1, cResult2;
1315
0
  SplashColorPtr destColorPtr;
1316
0
  Guchar *destAlphaPtr;
1317
0
  int cSrcStride, x, lastX;
1318
1319
0
  if (cSrcPtr) {
1320
0
    cSrcStride = 3;
1321
0
  } else {
1322
0
    cSrcPtr = pipe->cSrcVal;
1323
0
    cSrcStride = 0;
1324
0
  }
1325
0
  for (; x0 <= x1; ++x0) {
1326
0
    if (*shapePtr) {
1327
0
      break;
1328
0
    }
1329
0
    cSrcPtr += cSrcStride;
1330
0
    ++shapePtr;
1331
0
  }
1332
0
  if (x0 > x1) {
1333
0
    return;
1334
0
  }
1335
0
  updateModX(x0);
1336
0
  updateModY(y);
1337
0
  lastX = x0;
1338
1339
0
  useDestRow(y);
1340
1341
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
1342
0
  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
1343
1344
0
  for (x = x0; x <= x1; ++x) {
1345
1346
    //----- shape
1347
0
    shape = *shapePtr;
1348
0
    if (!shape) {
1349
0
      destColorPtr += 3;
1350
0
      ++destAlphaPtr;
1351
0
      cSrcPtr += cSrcStride;
1352
0
      ++shapePtr;
1353
0
      continue;
1354
0
    }
1355
0
    lastX = x;
1356
1357
    //----- source color
1358
0
    cSrc0 = state->rgbTransferR[cSrcPtr[0]];
1359
0
    cSrc1 = state->rgbTransferG[cSrcPtr[1]];
1360
0
    cSrc2 = state->rgbTransferB[cSrcPtr[2]];
1361
1362
    //----- source alpha
1363
0
    aSrc = shape;
1364
1365
    //----- special case for aSrc = 255
1366
0
    if (aSrc == 255) {
1367
0
      aResult = 255;
1368
0
      cResult0 = cSrc0;
1369
0
      cResult1 = cSrc1;
1370
0
      cResult2 = cSrc2;
1371
0
    } else {
1372
1373
      //----- read destination alpha
1374
0
      aDest = *destAlphaPtr;
1375
1376
      //----- special case for aDest = 0
1377
0
      if (aDest == 0) {
1378
0
  aResult = aSrc;
1379
0
  cResult0 = cSrc0;
1380
0
  cResult1 = cSrc1;
1381
0
  cResult2 = cSrc2;
1382
0
      } else {
1383
1384
  //----- read destination pixel
1385
0
  cDest0 = destColorPtr[0];
1386
0
  cDest1 = destColorPtr[1];
1387
0
  cDest2 = destColorPtr[2];
1388
1389
  //----- result alpha and non-isolated group element correction
1390
0
  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
1391
0
  alphaI = aResult;
1392
1393
  //----- result color
1394
0
  cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
1395
0
  cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
1396
0
  cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
1397
0
      }
1398
0
    }
1399
1400
    //----- write destination pixel
1401
0
    destColorPtr[0] = cResult0;
1402
0
    destColorPtr[1] = cResult1;
1403
0
    destColorPtr[2] = cResult2;
1404
0
    destColorPtr += 3;
1405
0
    *destAlphaPtr++ = aResult;
1406
1407
0
    cSrcPtr += cSrcStride;
1408
0
    ++shapePtr;
1409
0
  }
1410
1411
0
  updateModX(lastX);
1412
0
}
1413
1414
// special case:
1415
// !pipe->pattern && pipe->shapeOnly && !state->blendFunc &&
1416
// bitmap->mode == splashModeBGR8 && bitmap->alpha
1417
void Splash::pipeRunShapeBGR8(SplashPipe *pipe, int x0, int x1, int y,
1418
0
            Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1419
0
  Guchar shape, aSrc, aDest, alphaI, aResult;
1420
0
  Guchar cSrc0, cSrc1, cSrc2;
1421
0
  Guchar cDest0, cDest1, cDest2;
1422
0
  Guchar cResult0, cResult1, cResult2;
1423
0
  SplashColorPtr destColorPtr;
1424
0
  Guchar *destAlphaPtr;
1425
0
  int cSrcStride, x, lastX;
1426
1427
0
  if (cSrcPtr) {
1428
0
    cSrcStride = 3;
1429
0
  } else {
1430
0
    cSrcPtr = pipe->cSrcVal;
1431
0
    cSrcStride = 0;
1432
0
  }
1433
0
  for (; x0 <= x1; ++x0) {
1434
0
    if (*shapePtr) {
1435
0
      break;
1436
0
    }
1437
0
    cSrcPtr += cSrcStride;
1438
0
    ++shapePtr;
1439
0
  }
1440
0
  if (x0 > x1) {
1441
0
    return;
1442
0
  }
1443
0
  updateModX(x0);
1444
0
  updateModY(y);
1445
0
  lastX = x0;
1446
1447
0
  useDestRow(y);
1448
1449
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
1450
0
  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
1451
1452
0
  for (x = x0; x <= x1; ++x) {
1453
1454
    //----- shape
1455
0
    shape = *shapePtr;
1456
0
    if (!shape) {
1457
0
      destColorPtr += 3;
1458
0
      ++destAlphaPtr;
1459
0
      cSrcPtr += cSrcStride;
1460
0
      ++shapePtr;
1461
0
      continue;
1462
0
    }
1463
0
    lastX = x;
1464
1465
    //----- source color
1466
0
    cSrc0 = state->rgbTransferR[cSrcPtr[0]];
1467
0
    cSrc1 = state->rgbTransferG[cSrcPtr[1]];
1468
0
    cSrc2 = state->rgbTransferB[cSrcPtr[2]];
1469
1470
    //----- source alpha
1471
0
    aSrc = shape;
1472
1473
    //----- special case for aSrc = 255
1474
0
    if (aSrc == 255) {
1475
0
      aResult = 255;
1476
0
      cResult0 = cSrc0;
1477
0
      cResult1 = cSrc1;
1478
0
      cResult2 = cSrc2;
1479
0
    } else {
1480
1481
      //----- read destination alpha
1482
0
      aDest = *destAlphaPtr;
1483
1484
      //----- special case for aDest = 0
1485
0
      if (aDest == 0) {
1486
0
  aResult = aSrc;
1487
0
  cResult0 = cSrc0;
1488
0
  cResult1 = cSrc1;
1489
0
  cResult2 = cSrc2;
1490
0
      } else {
1491
1492
  //----- read destination pixel
1493
0
  cDest0 = destColorPtr[2];
1494
0
  cDest1 = destColorPtr[1];
1495
0
  cDest2 = destColorPtr[0];
1496
1497
  //----- result alpha and non-isolated group element correction
1498
0
  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
1499
0
  alphaI = aResult;
1500
1501
  //----- result color
1502
0
  cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
1503
0
  cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
1504
0
  cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
1505
0
      }
1506
0
    }
1507
1508
    //----- write destination pixel
1509
0
    destColorPtr[0] = cResult2;
1510
0
    destColorPtr[1] = cResult1;
1511
0
    destColorPtr[2] = cResult0;
1512
0
    destColorPtr += 3;
1513
0
    *destAlphaPtr++ = aResult;
1514
1515
0
    cSrcPtr += cSrcStride;
1516
0
    ++shapePtr;
1517
0
  }
1518
1519
0
  updateModX(lastX);
1520
0
}
1521
1522
#if SPLASH_CMYK
1523
// special case:
1524
// !pipe->pattern && pipe->shapeOnly && !state->blendFunc &&
1525
// bitmap->mode == splashModeCMYK8 && bitmap->alpha
1526
void Splash::pipeRunShapeCMYK8(SplashPipe *pipe, int x0, int x1, int y,
1527
0
             Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1528
0
  Guchar shape, aSrc, aDest, alphaI, aResult;
1529
0
  Guchar cSrc0, cSrc1, cSrc2, cSrc3;
1530
0
  Guchar cDest0, cDest1, cDest2, cDest3;
1531
0
  Guchar cResult0, cResult1, cResult2, cResult3;
1532
0
  SplashColorPtr destColorPtr;
1533
0
  Guchar *destAlphaPtr;
1534
0
  int cSrcStride, x, lastX;
1535
1536
0
  if (cSrcPtr) {
1537
0
    cSrcStride = 4;
1538
0
  } else {
1539
0
    cSrcPtr = pipe->cSrcVal;
1540
0
    cSrcStride = 0;
1541
0
  }
1542
0
  for (; x0 <= x1; ++x0) {
1543
0
    if (*shapePtr) {
1544
0
      break;
1545
0
    }
1546
0
    cSrcPtr += cSrcStride;
1547
0
    ++shapePtr;
1548
0
  }
1549
0
  if (x0 > x1) {
1550
0
    return;
1551
0
  }
1552
0
  updateModX(x0);
1553
0
  updateModY(y);
1554
0
  lastX = x0;
1555
1556
0
  useDestRow(y);
1557
1558
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x0];
1559
0
  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
1560
1561
0
  for (x = x0; x <= x1; ++x) {
1562
1563
    //----- shape
1564
0
    shape = *shapePtr;
1565
0
    if (!shape) {
1566
0
      destColorPtr += 4;
1567
0
      ++destAlphaPtr;
1568
0
      cSrcPtr += cSrcStride;
1569
0
      ++shapePtr;
1570
0
      continue;
1571
0
    }
1572
0
    lastX = x;
1573
1574
    //----- read destination pixel
1575
0
    cDest0 = destColorPtr[0];
1576
0
    cDest1 = destColorPtr[1];
1577
0
    cDest2 = destColorPtr[2];
1578
0
    cDest3 = destColorPtr[3];
1579
0
    aDest = *destAlphaPtr;
1580
1581
    //----- overprint
1582
0
    cSrc0 = state->cmykTransferC[cSrcPtr[0]];
1583
0
    cSrc1 = state->cmykTransferM[cSrcPtr[1]];
1584
0
    cSrc2 = state->cmykTransferY[cSrcPtr[2]];
1585
0
    cSrc3 = state->cmykTransferK[cSrcPtr[3]];
1586
1587
    //----- source alpha
1588
0
    aSrc = shape;
1589
1590
    //----- special case for aSrc = 255
1591
0
    if (aSrc == 255) {
1592
0
      aResult = 255;
1593
0
      cResult0 = cSrc0;
1594
0
      cResult1 = cSrc1;
1595
0
      cResult2 = cSrc2;
1596
0
      cResult3 = cSrc3;
1597
0
    } else {
1598
1599
      //----- special case for aDest = 0
1600
0
      if (aDest == 0) {
1601
0
  aResult = aSrc;
1602
0
  cResult0 = cSrc0;
1603
0
  cResult1 = cSrc1;
1604
0
  cResult2 = cSrc2;
1605
0
  cResult3 = cSrc3;
1606
0
      } else {
1607
1608
  //----- result alpha and non-isolated group element correction
1609
0
  aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
1610
0
  alphaI = aResult;
1611
1612
  //----- result color
1613
0
  cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
1614
0
  cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
1615
0
  cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
1616
0
  cResult3 = (Guchar)(((alphaI - aSrc) * cDest3 + aSrc * cSrc3) / alphaI);
1617
0
      }
1618
0
    }
1619
1620
    //----- write destination pixel
1621
0
    destColorPtr[0] = cResult0;
1622
0
    destColorPtr[1] = cResult1;
1623
0
    destColorPtr[2] = cResult2;
1624
0
    destColorPtr[3] = cResult3;
1625
0
    destColorPtr += 4;
1626
0
    *destAlphaPtr++ = aResult;
1627
1628
0
    cSrcPtr += cSrcStride;
1629
0
    ++shapePtr;
1630
0
  }
1631
1632
0
  updateModX(lastX);
1633
0
}
1634
#endif
1635
1636
1637
// special case:
1638
// !pipe->pattern && pipe->shapeOnly && !state->blendFunc &&
1639
// bitmap->mode == splashModeMono8 && !bitmap->alpha
1640
void Splash::pipeRunShapeNoAlphaMono8(SplashPipe *pipe, int x0, int x1, int y,
1641
                                      Guchar *shapePtr,
1642
0
                                      SplashColorPtr cSrcPtr) {
1643
0
  Guchar shape, aSrc, cSrc0, cDest0, cResult0;
1644
0
  SplashColorPtr destColorPtr;
1645
0
  int cSrcStride, x, lastX;
1646
1647
0
  if (cSrcPtr) {
1648
0
    cSrcStride = 1;
1649
0
  } else {
1650
0
    cSrcPtr = pipe->cSrcVal;
1651
0
    cSrcStride = 0;
1652
0
  }
1653
0
  for (; x0 <= x1; ++x0) {
1654
0
    if (*shapePtr) {
1655
0
      break;
1656
0
    }
1657
0
    cSrcPtr += cSrcStride;
1658
0
    ++shapePtr;
1659
0
  }
1660
0
  if (x0 > x1) {
1661
0
    return;
1662
0
  }
1663
0
  updateModX(x0);
1664
0
  updateModY(y);
1665
0
  lastX = x0;
1666
1667
0
  useDestRow(y);
1668
1669
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
1670
1671
0
  for (x = x0; x <= x1; ++x) {
1672
1673
    //----- shape
1674
0
    shape = *shapePtr;
1675
0
    if (!shape) {
1676
0
      ++destColorPtr;
1677
0
      cSrcPtr += cSrcStride;
1678
0
      ++shapePtr;
1679
0
      continue;
1680
0
    }
1681
0
    lastX = x;
1682
1683
    //----- source color
1684
0
    cSrc0 = state->grayTransfer[cSrcPtr[0]];
1685
1686
    //----- source alpha
1687
0
    aSrc = shape;
1688
1689
    //----- special case for aSrc = 255
1690
0
    if (aSrc == 255) {
1691
0
      cResult0 = cSrc0;
1692
0
    } else {
1693
1694
      //----- read destination pixel
1695
0
      cDest0 = *destColorPtr;
1696
1697
      //----- result color
1698
0
      cResult0 = div255((255 - aSrc) * cDest0 + aSrc * cSrc0);
1699
0
    }
1700
1701
    //----- write destination pixel
1702
0
    *destColorPtr++ = cResult0;
1703
1704
0
    cSrcPtr += cSrcStride;
1705
0
    ++shapePtr;
1706
0
  }
1707
1708
0
  updateModX(lastX);
1709
0
}
1710
1711
// special case:
1712
// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
1713
// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
1714
// !pipe->nonIsolatedGroup &&
1715
// bitmap->mode == splashModeMono1 && !bitmap->alpha
1716
void Splash::pipeRunAAMono1(SplashPipe *pipe, int x0, int x1, int y,
1717
0
          Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1718
0
  Guchar shape, aSrc, cSrc0, cDest0, cResult0;
1719
0
  SplashColorPtr destColorPtr;
1720
0
  Guchar destColorMask;
1721
0
  SplashScreenCursor screenCursor;
1722
0
  int cSrcStride, x, lastX;
1723
1724
0
  if (cSrcPtr) {
1725
0
    cSrcStride = 1;
1726
0
  } else {
1727
0
    cSrcPtr = pipe->cSrcVal;
1728
0
    cSrcStride = 0;
1729
0
  }
1730
0
  for (; x0 <= x1; ++x0) {
1731
0
    if (*shapePtr) {
1732
0
      break;
1733
0
    }
1734
0
    cSrcPtr += cSrcStride;
1735
0
    ++shapePtr;
1736
0
  }
1737
0
  if (x0 > x1) {
1738
0
    return;
1739
0
  }
1740
0
  updateModX(x0);
1741
0
  updateModY(y);
1742
0
  lastX = x0;
1743
1744
0
  useDestRow(y);
1745
1746
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
1747
0
  destColorMask = (Guchar)(0x80 >> (x0 & 7));
1748
1749
0
  screenCursor = state->screen->getTestCursor(y);
1750
1751
0
  for (x = x0; x <= x1; ++x) {
1752
1753
    //----- shape
1754
0
    shape = *shapePtr;
1755
0
    if (!shape) {
1756
0
      destColorPtr += destColorMask & 1;
1757
0
      destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1));
1758
0
      cSrcPtr += cSrcStride;
1759
0
      ++shapePtr;
1760
0
      continue;
1761
0
    }
1762
0
    lastX = x;
1763
1764
    //----- read destination pixel
1765
0
    cDest0 = (*destColorPtr & destColorMask) ? 0xff : 0x00;
1766
1767
    //----- source color
1768
0
    cSrc0 = state->grayTransfer[cSrcPtr[0]];
1769
1770
    //----- source alpha
1771
0
    aSrc = div255(pipe->aInput * shape);
1772
1773
    //----- result color
1774
    // note: aDest = alphaI = aResult = 0xff
1775
0
    cResult0 = (Guchar)div255((0xff - aSrc) * cDest0 + aSrc * cSrc0);
1776
1777
    //----- write destination pixel
1778
0
    if (state->screen->testWithCursor(screenCursor, x, cResult0)) {
1779
0
      *destColorPtr |= destColorMask;
1780
0
    } else {
1781
0
      *destColorPtr &= (Guchar)~destColorMask;
1782
0
    }
1783
0
    destColorPtr += destColorMask & 1;
1784
0
    destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1));
1785
1786
0
    cSrcPtr += cSrcStride;
1787
0
    ++shapePtr;
1788
0
  }
1789
1790
0
  updateModX(lastX);
1791
0
}
1792
1793
// special case:
1794
// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
1795
// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
1796
// !pipe->nonIsolatedGroup &&
1797
// bitmap->mode == splashModeMono8 && bitmap->alpha
1798
void Splash::pipeRunAAMono8(SplashPipe *pipe, int x0, int x1, int y,
1799
0
          Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1800
0
  Guchar shape, aSrc, aDest, alphaI, aResult, cSrc0, cDest0, cResult0;
1801
0
  SplashColorPtr destColorPtr;
1802
0
  Guchar *destAlphaPtr;
1803
0
  int cSrcStride, x, lastX;
1804
1805
0
  if (cSrcPtr) {
1806
0
    cSrcStride = 1;
1807
0
  } else {
1808
0
    cSrcPtr = pipe->cSrcVal;
1809
0
    cSrcStride = 0;
1810
0
  }
1811
0
  for (; x0 <= x1; ++x0) {
1812
0
    if (*shapePtr) {
1813
0
      break;
1814
0
    }
1815
0
    cSrcPtr += cSrcStride;
1816
0
    ++shapePtr;
1817
0
  }
1818
0
  if (x0 > x1) {
1819
0
    return;
1820
0
  }
1821
0
  updateModX(x0);
1822
0
  updateModY(y);
1823
0
  lastX = x0;
1824
1825
0
  useDestRow(y);
1826
1827
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
1828
0
  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
1829
1830
0
  for (x = x0; x <= x1; ++x) {
1831
1832
    //----- shape
1833
0
    shape = *shapePtr;
1834
0
    if (!shape) {
1835
0
      ++destColorPtr;
1836
0
      ++destAlphaPtr;
1837
0
      cSrcPtr += cSrcStride;
1838
0
      ++shapePtr;
1839
0
      continue;
1840
0
    }
1841
0
    lastX = x;
1842
1843
    //----- read destination pixel
1844
0
    cDest0 = *destColorPtr;
1845
0
    aDest = *destAlphaPtr;
1846
1847
    //----- source color
1848
0
    cSrc0 = state->grayTransfer[cSrcPtr[0]];
1849
1850
    //----- source alpha
1851
0
    aSrc = div255(pipe->aInput * shape);
1852
1853
    //----- result alpha and non-isolated group element correction
1854
0
    aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
1855
0
    alphaI = aResult;
1856
1857
    //----- result color
1858
0
    if (alphaI == 0) {
1859
0
      cResult0 = 0;
1860
0
    } else {
1861
0
      cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
1862
0
    }
1863
1864
    //----- write destination pixel
1865
0
    *destColorPtr++ = cResult0;
1866
0
    *destAlphaPtr++ = aResult;
1867
1868
0
    cSrcPtr += cSrcStride;
1869
0
    ++shapePtr;
1870
0
  }
1871
1872
0
  updateModX(lastX);
1873
0
}
1874
1875
// special case:
1876
// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
1877
// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
1878
// !pipe->nonIsolatedGroup &&
1879
// bitmap->mode == splashModeRGB8 && bitmap->alpha
1880
void Splash::pipeRunAARGB8(SplashPipe *pipe, int x0, int x1, int y,
1881
0
         Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1882
0
  Guchar shape, aSrc, aDest, alphaI, aResult;
1883
0
  Guchar cSrc0, cSrc1, cSrc2;
1884
0
  Guchar cDest0, cDest1, cDest2;
1885
0
  Guchar cResult0, cResult1, cResult2;
1886
0
  SplashColorPtr destColorPtr;
1887
0
  Guchar *destAlphaPtr;
1888
0
  int cSrcStride, x, lastX;
1889
1890
0
  if (cSrcPtr) {
1891
0
    cSrcStride = 3;
1892
0
  } else {
1893
0
    cSrcPtr = pipe->cSrcVal;
1894
0
    cSrcStride = 0;
1895
0
  }
1896
0
  for (; x0 <= x1; ++x0) {
1897
0
    if (*shapePtr) {
1898
0
      break;
1899
0
    }
1900
0
    cSrcPtr += cSrcStride;
1901
0
    ++shapePtr;
1902
0
  }
1903
0
  if (x0 > x1) {
1904
0
    return;
1905
0
  }
1906
0
  updateModX(x0);
1907
0
  updateModY(y);
1908
0
  lastX = x0;
1909
1910
0
  useDestRow(y);
1911
1912
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
1913
0
  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
1914
1915
0
  for (x = x0; x <= x1; ++x) {
1916
1917
    //----- shape
1918
0
    shape = *shapePtr;
1919
0
    if (!shape) {
1920
0
      destColorPtr += 3;
1921
0
      ++destAlphaPtr;
1922
0
      cSrcPtr += cSrcStride;
1923
0
      ++shapePtr;
1924
0
      continue;
1925
0
    }
1926
0
    lastX = x;
1927
1928
    //----- read destination pixel
1929
0
    cDest0 = destColorPtr[0];
1930
0
    cDest1 = destColorPtr[1];
1931
0
    cDest2 = destColorPtr[2];
1932
0
    aDest = *destAlphaPtr;
1933
1934
    //----- source color
1935
0
    cSrc0 = state->rgbTransferR[cSrcPtr[0]];
1936
0
    cSrc1 = state->rgbTransferG[cSrcPtr[1]];
1937
0
    cSrc2 = state->rgbTransferB[cSrcPtr[2]];
1938
1939
    //----- source alpha
1940
0
    aSrc = div255(pipe->aInput * shape);
1941
1942
    //----- result alpha and non-isolated group element correction
1943
0
    aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
1944
0
    alphaI = aResult;
1945
1946
    //----- result color
1947
0
    if (alphaI == 0) {
1948
0
      cResult0 = 0;
1949
0
      cResult1 = 0;
1950
0
      cResult2 = 0;
1951
0
    } else {
1952
0
      cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
1953
0
      cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
1954
0
      cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
1955
0
    }
1956
1957
    //----- write destination pixel
1958
0
    destColorPtr[0] = cResult0;
1959
0
    destColorPtr[1] = cResult1;
1960
0
    destColorPtr[2] = cResult2;
1961
0
    destColorPtr += 3;
1962
0
    *destAlphaPtr++ = aResult;
1963
1964
0
    cSrcPtr += cSrcStride;
1965
0
    ++shapePtr;
1966
0
  }
1967
1968
0
  updateModX(lastX);
1969
0
}
1970
1971
// special case:
1972
// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
1973
// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
1974
// !pipe->nonIsolatedGroup &&
1975
// bitmap->mode == splashModeBGR8 && bitmap->alpha
1976
void Splash::pipeRunAABGR8(SplashPipe *pipe, int x0, int x1, int y,
1977
0
         Guchar *shapePtr, SplashColorPtr cSrcPtr) {
1978
0
  Guchar shape, aSrc, aDest, alphaI, aResult;
1979
0
  Guchar cSrc0, cSrc1, cSrc2;
1980
0
  Guchar cDest0, cDest1, cDest2;
1981
0
  Guchar cResult0, cResult1, cResult2;
1982
0
  SplashColorPtr destColorPtr;
1983
0
  Guchar *destAlphaPtr;
1984
0
  int cSrcStride, x, lastX;
1985
1986
0
  if (cSrcPtr) {
1987
0
    cSrcStride = 3;
1988
0
  } else {
1989
0
    cSrcPtr = pipe->cSrcVal;
1990
0
    cSrcStride = 0;
1991
0
  }
1992
0
  for (; x0 <= x1; ++x0) {
1993
0
    if (*shapePtr) {
1994
0
      break;
1995
0
    }
1996
0
    cSrcPtr += cSrcStride;
1997
0
    ++shapePtr;
1998
0
  }
1999
0
  if (x0 > x1) {
2000
0
    return;
2001
0
  }
2002
0
  updateModX(x0);
2003
0
  updateModY(y);
2004
0
  lastX = x0;
2005
2006
0
  useDestRow(y);
2007
2008
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
2009
0
  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
2010
2011
0
  for (x = x0; x <= x1; ++x) {
2012
2013
    //----- shape
2014
0
    shape = *shapePtr;
2015
0
    if (!shape) {
2016
0
      destColorPtr += 3;
2017
0
      ++destAlphaPtr;
2018
0
      cSrcPtr += cSrcStride;
2019
0
      ++shapePtr;
2020
0
      continue;
2021
0
    }
2022
0
    lastX = x;
2023
2024
    //----- read destination pixel
2025
0
    cDest0 = destColorPtr[2];
2026
0
    cDest1 = destColorPtr[1];
2027
0
    cDest2 = destColorPtr[0];
2028
0
    aDest = *destAlphaPtr;
2029
2030
    //----- source color
2031
0
    cSrc0 = state->rgbTransferR[cSrcPtr[0]];
2032
0
    cSrc1 = state->rgbTransferG[cSrcPtr[1]];
2033
0
    cSrc2 = state->rgbTransferB[cSrcPtr[2]];
2034
2035
    //----- source alpha
2036
0
    aSrc = div255(pipe->aInput * shape);
2037
2038
    //----- result alpha and non-isolated group element correction
2039
0
    aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
2040
0
    alphaI = aResult;
2041
2042
    //----- result color
2043
0
    if (alphaI == 0) {
2044
0
      cResult0 = 0;
2045
0
      cResult1 = 0;
2046
0
      cResult2 = 0;
2047
0
    } else {
2048
0
      cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
2049
0
      cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
2050
0
      cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
2051
0
    }
2052
2053
    //----- write destination pixel
2054
0
    destColorPtr[0] = cResult2;
2055
0
    destColorPtr[1] = cResult1;
2056
0
    destColorPtr[2] = cResult0;
2057
0
    destColorPtr += 3;
2058
0
    *destAlphaPtr++ = aResult;
2059
2060
0
    cSrcPtr += cSrcStride;
2061
0
    ++shapePtr;
2062
0
  }
2063
2064
0
  updateModX(lastX);
2065
0
}
2066
2067
#if SPLASH_CMYK
2068
// special case:
2069
// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
2070
// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
2071
// !pipe->nonIsolatedGroup &&
2072
// bitmap->mode == splashModeCMYK8 && bitmap->alpha
2073
void Splash::pipeRunAACMYK8(SplashPipe *pipe, int x0, int x1, int y,
2074
0
          Guchar *shapePtr, SplashColorPtr cSrcPtr) {
2075
0
  Guchar shape, aSrc, aDest, alphaI, aResult;
2076
0
  Guchar cSrc0, cSrc1, cSrc2, cSrc3;
2077
0
  Guchar cDest0, cDest1, cDest2, cDest3;
2078
0
  Guchar cResult0, cResult1, cResult2, cResult3;
2079
0
  SplashColorPtr destColorPtr;
2080
0
  Guchar *destAlphaPtr;
2081
0
  int cSrcStride, x, lastX;
2082
2083
0
  if (cSrcPtr) {
2084
0
    cSrcStride = 4;
2085
0
  } else {
2086
0
    cSrcPtr = pipe->cSrcVal;
2087
0
    cSrcStride = 0;
2088
0
  }
2089
0
  for (; x0 <= x1; ++x0) {
2090
0
    if (*shapePtr) {
2091
0
      break;
2092
0
    }
2093
0
    cSrcPtr += cSrcStride;
2094
0
    ++shapePtr;
2095
0
  }
2096
0
  if (x0 > x1) {
2097
0
    return;
2098
0
  }
2099
0
  updateModX(x0);
2100
0
  updateModY(y);
2101
0
  lastX = x0;
2102
2103
0
  useDestRow(y);
2104
2105
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x0];
2106
0
  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
2107
2108
0
  for (x = x0; x <= x1; ++x) {
2109
2110
    //----- shape
2111
0
    shape = *shapePtr;
2112
0
    if (!shape) {
2113
0
      destColorPtr += 4;
2114
0
      ++destAlphaPtr;
2115
0
      cSrcPtr += cSrcStride;
2116
0
      ++shapePtr;
2117
0
      continue;
2118
0
    }
2119
0
    lastX = x;
2120
2121
    //----- read destination pixel
2122
0
    cDest0 = destColorPtr[0];
2123
0
    cDest1 = destColorPtr[1];
2124
0
    cDest2 = destColorPtr[2];
2125
0
    cDest3 = destColorPtr[3];
2126
0
    aDest = *destAlphaPtr;
2127
2128
    //----- overprint
2129
0
    if (state->overprintMask & 1) {
2130
0
      cSrc0 = state->cmykTransferC[cSrcPtr[0]];
2131
0
    } else {
2132
0
      cSrc0 = div255(aDest * cDest0);
2133
0
    }
2134
0
    if (state->overprintMask & 2) {
2135
0
      cSrc1 = state->cmykTransferM[cSrcPtr[1]];
2136
0
    } else {
2137
0
      cSrc1 = div255(aDest * cDest1);
2138
0
    }
2139
0
    if (state->overprintMask & 4) {
2140
0
      cSrc2 = state->cmykTransferY[cSrcPtr[2]];
2141
0
    } else {
2142
0
      cSrc2 = div255(aDest * cDest2);
2143
0
    }
2144
0
    if (state->overprintMask & 8) {
2145
0
      cSrc3 = state->cmykTransferK[cSrcPtr[3]];
2146
0
    } else {
2147
0
      cSrc3 = div255(aDest * cDest3);
2148
0
    }
2149
2150
    //----- source alpha
2151
0
    aSrc = div255(pipe->aInput * shape);
2152
2153
    //----- result alpha and non-isolated group element correction
2154
0
    aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
2155
0
    alphaI = aResult;
2156
2157
    //----- result color
2158
0
    if (alphaI == 0) {
2159
0
      cResult0 = 0;
2160
0
      cResult1 = 0;
2161
0
      cResult2 = 0;
2162
0
      cResult3 = 0;
2163
0
    } else {
2164
0
      cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
2165
0
      cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
2166
0
      cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
2167
0
      cResult3 = (Guchar)(((alphaI - aSrc) * cDest3 + aSrc * cSrc3) / alphaI);
2168
0
    }
2169
2170
    //----- write destination pixel
2171
0
    destColorPtr[0] = cResult0;
2172
0
    destColorPtr[1] = cResult1;
2173
0
    destColorPtr[2] = cResult2;
2174
0
    destColorPtr[3] = cResult3;
2175
0
    destColorPtr += 4;
2176
0
    *destAlphaPtr++ = aResult;
2177
2178
0
    cSrcPtr += cSrcStride;
2179
0
    ++shapePtr;
2180
0
  }
2181
2182
0
  updateModX(lastX);
2183
0
}
2184
#endif
2185
2186
2187
// special case:
2188
// !pipe->pattern && aInput == 255 && state->softMask && usesShape &&
2189
// !state->inNonIsolatedGroup && !state->inKnockoutGroup &&
2190
// !nonIsolatedGroup && state->overprintMask == 0xffffffff &&
2191
// !state->blendFunc &&
2192
// bitmap->mode == splashModeMono8 && bitmap->alpha
2193
void Splash::pipeRunSoftMaskMono8(SplashPipe *pipe, int x0, int x1, int y,
2194
0
          Guchar *shapePtr, SplashColorPtr cSrcPtr) {
2195
0
  Guchar shape, aSrc, aDest, alphaI, aResult;
2196
0
  Guchar cSrc0, cDest0, cResult0;
2197
0
  SplashColorPtr destColorPtr;
2198
0
  Guchar *destAlphaPtr;
2199
0
  SplashColorPtr softMaskPtr;
2200
0
  int cSrcStride, x, lastX;
2201
2202
0
  if (cSrcPtr) {
2203
0
    cSrcStride = 1;
2204
0
  } else {
2205
0
    cSrcPtr = pipe->cSrcVal;
2206
0
    cSrcStride = 0;
2207
0
  }
2208
0
  for (; x0 <= x1; ++x0) {
2209
0
    if (*shapePtr) {
2210
0
      break;
2211
0
    }
2212
0
    cSrcPtr += cSrcStride;
2213
0
    ++shapePtr;
2214
0
  }
2215
0
  if (x0 > x1) {
2216
0
    return;
2217
0
  }
2218
0
  updateModX(x0);
2219
0
  updateModY(y);
2220
0
  lastX = x0;
2221
2222
0
  useDestRow(y);
2223
2224
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
2225
0
  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
2226
0
  softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0];
2227
2228
0
  for (x = x0; x <= x1; ++x) {
2229
2230
    //----- shape
2231
0
    shape = *shapePtr;
2232
0
    if (!shape) {
2233
0
      ++destColorPtr;
2234
0
      ++destAlphaPtr;
2235
0
      ++softMaskPtr;
2236
0
      cSrcPtr += cSrcStride;
2237
0
      ++shapePtr;
2238
0
      continue;
2239
0
    }
2240
0
    lastX = x;
2241
2242
    //----- read source color
2243
0
    cSrc0 = state->grayTransfer[cSrcPtr[0]];
2244
2245
    //----- source alpha
2246
0
    aSrc = div255(*softMaskPtr++ * shape);
2247
2248
    //----- special case for aSrc = 255
2249
0
    if (aSrc == 255) {
2250
0
      aResult = 255;
2251
0
      cResult0 = cSrc0;
2252
0
    } else {
2253
2254
      //----- read destination alpha
2255
0
      aDest = *destAlphaPtr;
2256
2257
      //----- special case for aDest = 0
2258
0
      if (aDest == 0) {
2259
0
        aResult = aSrc;
2260
0
        cResult0 = cSrc0;
2261
0
      } else {
2262
2263
        //----- read destination pixel
2264
0
        cDest0 = destColorPtr[0];
2265
2266
        //----- result alpha and non-isolated group element correction
2267
0
        aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
2268
0
        alphaI = aResult;
2269
2270
        //----- result color
2271
0
        cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
2272
0
      }
2273
0
    }
2274
2275
    //----- write destination pixel
2276
0
    destColorPtr[0] = cResult0;
2277
0
    ++destColorPtr;
2278
0
    *destAlphaPtr++ = aResult;
2279
2280
0
    cSrcPtr += cSrcStride;
2281
0
    ++shapePtr;
2282
0
  }
2283
2284
0
  updateModX(lastX);
2285
0
}
2286
2287
// special case:
2288
// !pipe->pattern && aInput == 255 && state->softMask && usesShape &&
2289
// !state->inNonIsolatedGroup && !state->inKnockoutGroup &&
2290
// !nonIsolatedGroup && state->overprintMask == 0xffffffff &&
2291
// !state->blendFunc &&
2292
// bitmap->mode == splashModeRGB8 && bitmap->alpha
2293
void Splash::pipeRunSoftMaskRGB8(SplashPipe *pipe, int x0, int x1, int y,
2294
0
                                 Guchar *shapePtr, SplashColorPtr cSrcPtr) {
2295
0
  Guchar shape, aSrc, aDest, alphaI, aResult;
2296
0
  Guchar cSrc0, cSrc1, cSrc2;
2297
0
  Guchar cDest0, cDest1, cDest2;
2298
0
  Guchar cResult0, cResult1, cResult2;
2299
0
  SplashColorPtr destColorPtr;
2300
0
  Guchar *destAlphaPtr;
2301
0
  SplashColorPtr softMaskPtr;
2302
0
  int cSrcStride, x, lastX;
2303
2304
0
  if (cSrcPtr) {
2305
0
    cSrcStride = 3;
2306
0
  } else {
2307
0
    cSrcPtr = pipe->cSrcVal;
2308
0
    cSrcStride = 0;
2309
0
  }
2310
0
  for (; x0 <= x1; ++x0) {
2311
0
    if (*shapePtr) {
2312
0
      break;
2313
0
    }
2314
0
    cSrcPtr += cSrcStride;
2315
0
    ++shapePtr;
2316
0
  }
2317
0
  if (x0 > x1) {
2318
0
    return;
2319
0
  }
2320
0
  updateModX(x0);
2321
0
  updateModY(y);
2322
0
  lastX = x0;
2323
2324
0
  useDestRow(y);
2325
2326
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3];
2327
0
  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
2328
0
  softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0];
2329
2330
0
  for (x = x0; x <= x1; ++x) {
2331
2332
    //----- shape
2333
0
    shape = *shapePtr;
2334
0
    if (!shape) {
2335
0
      destColorPtr += 3;
2336
0
      ++destAlphaPtr;
2337
0
      ++softMaskPtr;
2338
0
      cSrcPtr += cSrcStride;
2339
0
      ++shapePtr;
2340
0
      continue;
2341
0
    }
2342
0
    lastX = x;
2343
2344
    //----- read source color
2345
0
    cSrc0 = state->rgbTransferR[cSrcPtr[0]];
2346
0
    cSrc1 = state->rgbTransferG[cSrcPtr[1]];
2347
0
    cSrc2 = state->rgbTransferB[cSrcPtr[2]];
2348
2349
    //----- source alpha
2350
0
    aSrc = div255(*softMaskPtr++ * shape);
2351
2352
    //----- special case for aSrc = 255
2353
0
    if (aSrc == 255) {
2354
0
      aResult = 255;
2355
0
      cResult0 = cSrc0;
2356
0
      cResult1 = cSrc1;
2357
0
      cResult2 = cSrc2;
2358
0
    } else {
2359
2360
      //----- read destination alpha
2361
0
      aDest = *destAlphaPtr;
2362
2363
      //----- special case for aDest = 0
2364
0
      if (aDest == 0) {
2365
0
        aResult = aSrc;
2366
0
        cResult0 = cSrc0;
2367
0
        cResult1 = cSrc1;
2368
0
        cResult2 = cSrc2;
2369
0
      } else {
2370
2371
        //----- read destination pixel
2372
0
        cDest0 = destColorPtr[0];
2373
0
        cDest1 = destColorPtr[1];
2374
0
        cDest2 = destColorPtr[2];
2375
2376
        //----- result alpha and non-isolated group element correction
2377
0
        aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
2378
0
        alphaI = aResult;
2379
2380
        //----- result color
2381
0
        cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
2382
0
        cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
2383
0
        cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
2384
0
      }
2385
0
    }
2386
2387
    //----- write destination pixel
2388
0
    destColorPtr[0] = cResult0;
2389
0
    destColorPtr[1] = cResult1;
2390
0
    destColorPtr[2] = cResult2;
2391
0
    destColorPtr += 3;
2392
0
    *destAlphaPtr++ = aResult;
2393
2394
0
    cSrcPtr += cSrcStride;
2395
0
    ++shapePtr;
2396
0
  }
2397
2398
0
  updateModX(lastX);
2399
0
}
2400
2401
// special case:
2402
// !pipe->pattern && aInput == 255 && state->softMask && usesShape &&
2403
// !state->inNonIsolatedGroup && !state->inKnockoutGroup &&
2404
// !nonIsolatedGroup && state->overprintMask == 0xffffffff &&
2405
// !state->blendFunc &&
2406
// bitmap->mode == splashModeBGR8 && bitmap->alpha
2407
void Splash::pipeRunSoftMaskBGR8(SplashPipe *pipe, int x0, int x1, int y,
2408
0
                                 Guchar *shapePtr, SplashColorPtr cSrcPtr) {
2409
0
  Guchar shape, aSrc, aDest, alphaI, aResult;
2410
0
  Guchar cSrc0, cSrc1, cSrc2;
2411
0
  Guchar cDest0, cDest1, cDest2;
2412
0
  Guchar cResult0, cResult1, cResult2;
2413
0
  SplashColorPtr destColorPtr;
2414
0
  Guchar *destAlphaPtr;
2415
0
  SplashColorPtr softMaskPtr;
2416
0
  int cSrcStride, x, lastX;
2417
2418
0
  if (cSrcPtr) {
2419
0
    cSrcStride = 3;
2420
0
  } else {
2421
0
    cSrcPtr = pipe->cSrcVal;
2422
0
    cSrcStride = 0;
2423
0
  }
2424
0
  for (; x0 <= x1; ++x0) {
2425
0
    if (*shapePtr) {
2426
0
      break;
2427
0
    }
2428
0
    cSrcPtr += cSrcStride;
2429
0
    ++shapePtr;
2430
0
  }
2431
0
  if (x0 > x1) {
2432
0
    return;
2433
0
  }
2434
0
  updateModX(x0);
2435
0
  updateModY(y);
2436
0
  lastX = x0;
2437
2438
0
  useDestRow(y);
2439
2440
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3];
2441
0
  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
2442
0
  softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0];
2443
2444
0
  for (x = x0; x <= x1; ++x) {
2445
2446
    //----- shape
2447
0
    shape = *shapePtr;
2448
0
    if (!shape) {
2449
0
      destColorPtr += 3;
2450
0
      ++destAlphaPtr;
2451
0
      ++softMaskPtr;
2452
0
      cSrcPtr += cSrcStride;
2453
0
      ++shapePtr;
2454
0
      continue;
2455
0
    }
2456
0
    lastX = x;
2457
2458
    //----- read source color
2459
0
    cSrc0 = state->rgbTransferR[cSrcPtr[0]];
2460
0
    cSrc1 = state->rgbTransferG[cSrcPtr[1]];
2461
0
    cSrc2 = state->rgbTransferB[cSrcPtr[2]];
2462
2463
    //----- source alpha
2464
0
    aSrc = div255(*softMaskPtr++ * shape);
2465
2466
    //----- special case for aSrc = 255
2467
0
    if (aSrc == 255) {
2468
0
      aResult = 255;
2469
0
      cResult0 = cSrc0;
2470
0
      cResult1 = cSrc1;
2471
0
      cResult2 = cSrc2;
2472
0
    } else {
2473
2474
      //----- read destination alpha
2475
0
      aDest = *destAlphaPtr;
2476
2477
      //----- special case for aDest = 0
2478
0
      if (aDest == 0) {
2479
0
        aResult = aSrc;
2480
0
        cResult0 = cSrc0;
2481
0
        cResult1 = cSrc1;
2482
0
        cResult2 = cSrc2;
2483
0
      } else {
2484
2485
        //----- read destination pixel
2486
0
        cDest0 = destColorPtr[2];
2487
0
        cDest1 = destColorPtr[1];
2488
0
        cDest2 = destColorPtr[0];
2489
2490
        //----- result alpha and non-isolated group element correction
2491
0
        aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
2492
0
        alphaI = aResult;
2493
2494
        //----- result color
2495
0
        cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
2496
0
        cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
2497
0
        cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
2498
0
      }
2499
0
    }
2500
2501
    //----- write destination pixel
2502
0
    destColorPtr[2] = cResult0;
2503
0
    destColorPtr[1] = cResult1;
2504
0
    destColorPtr[0] = cResult2;
2505
0
    destColorPtr += 3;
2506
0
    *destAlphaPtr++ = aResult;
2507
2508
0
    cSrcPtr += cSrcStride;
2509
0
    ++shapePtr;
2510
0
  }
2511
2512
0
  updateModX(lastX);
2513
0
}
2514
2515
#if SPLASH_CMYK
2516
// special case:
2517
// !pipe->pattern && aInput == 255 && state->softMask && usesShape &&
2518
// !state->inNonIsolatedGroup && !state->inKnockoutGroup &&
2519
// !nonIsolatedGroup && state->overprintMask == 0xffffffff &&
2520
// !state->blendFunc &&
2521
// bitmap->mode == splashModeCMYK8 && bitmap->alpha
2522
void Splash::pipeRunSoftMaskCMYK8(SplashPipe *pipe, int x0, int x1, int y,
2523
0
          Guchar *shapePtr, SplashColorPtr cSrcPtr) {
2524
0
  Guchar shape, aSrc, aDest, alphaI, aResult;
2525
0
  Guchar cSrc0, cSrc1, cSrc2, cSrc3;
2526
0
  Guchar cDest0, cDest1, cDest2, cDest3;
2527
0
  Guchar cResult0, cResult1, cResult2, cResult3;
2528
0
  SplashColorPtr destColorPtr;
2529
0
  Guchar *destAlphaPtr;
2530
0
  SplashColorPtr softMaskPtr;
2531
0
  int cSrcStride, x, lastX;
2532
2533
0
  if (cSrcPtr) {
2534
0
    cSrcStride = 4;
2535
0
  } else {
2536
0
    cSrcPtr = pipe->cSrcVal;
2537
0
    cSrcStride = 0;
2538
0
  }
2539
0
  for (; x0 <= x1; ++x0) {
2540
0
    if (*shapePtr) {
2541
0
      break;
2542
0
    }
2543
0
    cSrcPtr += cSrcStride;
2544
0
    ++shapePtr;
2545
0
  }
2546
0
  if (x0 > x1) {
2547
0
    return;
2548
0
  }
2549
0
  updateModX(x0);
2550
0
  updateModY(y);
2551
0
  lastX = x0;
2552
2553
0
  useDestRow(y);
2554
2555
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 4];
2556
0
  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
2557
0
  softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0];
2558
2559
0
  for (x = x0; x <= x1; ++x) {
2560
2561
    //----- shape
2562
0
    shape = *shapePtr;
2563
0
    if (!shape) {
2564
0
      destColorPtr += 4;
2565
0
      ++destAlphaPtr;
2566
0
      ++softMaskPtr;
2567
0
      cSrcPtr += cSrcStride;
2568
0
      ++shapePtr;
2569
0
      continue;
2570
0
    }
2571
0
    lastX = x;
2572
2573
    //----- read destination pixel
2574
0
    cDest0 = destColorPtr[0];
2575
0
    cDest1 = destColorPtr[1];
2576
0
    cDest2 = destColorPtr[2];
2577
0
    cDest3 = destColorPtr[3];
2578
2579
    //----- read destination alpha
2580
0
    aDest = *destAlphaPtr;
2581
2582
    //----- overprint
2583
0
    cSrc0 = state->cmykTransferC[cSrcPtr[0]];
2584
0
    cSrc1 = state->cmykTransferM[cSrcPtr[1]];
2585
0
    cSrc2 = state->cmykTransferY[cSrcPtr[2]];
2586
0
    cSrc3 = state->cmykTransferK[cSrcPtr[3]];
2587
2588
    //----- source alpha
2589
0
    aSrc = div255(*softMaskPtr++ * shape);
2590
2591
    //----- special case for aSrc = 255
2592
0
    if (aSrc == 255) {
2593
0
      aResult = 255;
2594
0
      cResult0 = cSrc0;
2595
0
      cResult1 = cSrc1;
2596
0
      cResult2 = cSrc2;
2597
0
      cResult3 = cSrc3;
2598
0
    } else {
2599
2600
      //----- special case for aDest = 0
2601
0
      if (aDest == 0) {
2602
0
        aResult = aSrc;
2603
0
        cResult0 = cSrc0;
2604
0
        cResult1 = cSrc1;
2605
0
        cResult2 = cSrc2;
2606
0
        cResult3 = cSrc3;
2607
0
      } else {
2608
2609
        //----- result alpha and non-isolated group element correction
2610
0
        aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
2611
0
        alphaI = aResult;
2612
2613
        //----- result color
2614
0
        cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
2615
0
        cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
2616
0
        cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
2617
0
        cResult3 = (Guchar)(((alphaI - aSrc) * cDest3 + aSrc * cSrc3) / alphaI);
2618
0
      }
2619
0
    }
2620
2621
    //----- write destination pixel
2622
0
    destColorPtr[0] = cResult0;
2623
0
    destColorPtr[1] = cResult1;
2624
0
    destColorPtr[2] = cResult2;
2625
0
    destColorPtr[3] = cResult3;
2626
0
    destColorPtr += 4;
2627
0
    *destAlphaPtr++ = aResult;
2628
2629
0
    cSrcPtr += cSrcStride;
2630
0
    ++shapePtr;
2631
0
  }
2632
2633
0
  updateModX(lastX);
2634
0
}
2635
#endif
2636
2637
2638
void Splash::pipeRunNonIsoMono8(SplashPipe *pipe, int x0, int x1, int y,
2639
0
        Guchar *shapePtr, SplashColorPtr cSrcPtr) {
2640
0
  Guchar shape, aSrc, aDest, alphaI, alpha0, aResult;
2641
0
  Guchar cSrc0, cDest0, cResult0;
2642
0
  SplashColorPtr destColorPtr;
2643
0
  Guchar *destAlphaPtr;
2644
0
  Guchar *alpha0Ptr;
2645
0
  int cSrcStride, x, lastX;
2646
2647
0
  if (cSrcPtr) {
2648
0
    cSrcStride = 1;
2649
0
  } else {
2650
0
    cSrcPtr = pipe->cSrcVal;
2651
0
    cSrcStride = 0;
2652
0
  }
2653
0
  for (; x0 <= x1; ++x0) {
2654
0
    if (*shapePtr) {
2655
0
      break;
2656
0
    }
2657
0
    cSrcPtr += cSrcStride;
2658
0
    ++shapePtr;
2659
0
  }
2660
0
  if (x0 > x1) {
2661
0
    return;
2662
0
  }
2663
0
  updateModX(x0);
2664
0
  updateModY(y);
2665
0
  lastX = x0;
2666
2667
0
  useDestRow(y);
2668
2669
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
2670
0
  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
2671
0
  alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y)
2672
0
                * groupBackBitmap->alphaRowSize +
2673
0
              (groupBackX + x0)];
2674
2675
0
  for (x = x0; x <= x1; ++x) {
2676
2677
    //----- shape
2678
0
    shape = *shapePtr;
2679
0
    if (!shape) {
2680
0
      destColorPtr += 1;
2681
0
      ++destAlphaPtr;
2682
0
      ++alpha0Ptr;
2683
0
      cSrcPtr += cSrcStride;
2684
0
      ++shapePtr;
2685
0
      continue;
2686
0
    }
2687
0
    lastX = x;
2688
2689
    //----- read destination pixel
2690
0
    cDest0 = destColorPtr[0];
2691
0
    aDest = *destAlphaPtr;
2692
2693
    //----- source color
2694
0
    cSrc0 = state->grayTransfer[cSrcPtr[0]];
2695
2696
    //----- source alpha
2697
0
    aSrc = div255(pipe->aInput * shape);
2698
2699
    //----- result alpha and non-isolated group element correction
2700
0
    aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
2701
0
    alpha0 = *alpha0Ptr++;
2702
0
    alphaI = (Guchar)(aResult + alpha0 - div255(aResult * alpha0));
2703
2704
    //----- result color
2705
0
    if (alphaI == 0) {
2706
0
      cResult0 = 0;
2707
0
    } else {
2708
0
      cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
2709
0
    }
2710
2711
    //----- write destination pixel
2712
0
    *destColorPtr++ = cResult0;
2713
0
    *destAlphaPtr++ = aResult;
2714
2715
0
    cSrcPtr += cSrcStride;
2716
0
    ++shapePtr;
2717
0
  } // for (x ...)
2718
2719
0
  updateModX(lastX);
2720
0
}
2721
2722
void Splash::pipeRunNonIsoRGB8(SplashPipe *pipe, int x0, int x1, int y,
2723
0
             Guchar *shapePtr, SplashColorPtr cSrcPtr) {
2724
0
  Guchar shape, aSrc, aDest, alphaI, alpha0, aResult;
2725
0
  Guchar cSrc0, cSrc1, cSrc2;
2726
0
  Guchar cDest0, cDest1, cDest2;
2727
0
  Guchar cResult0, cResult1, cResult2;
2728
0
  SplashColorPtr destColorPtr;
2729
0
  Guchar *destAlphaPtr;
2730
0
  Guchar *alpha0Ptr;
2731
0
  int cSrcStride, x, lastX;
2732
2733
0
  if (cSrcPtr) {
2734
0
    cSrcStride = 3;
2735
0
  } else {
2736
0
    cSrcPtr = pipe->cSrcVal;
2737
0
    cSrcStride = 0;
2738
0
  }
2739
0
  for (; x0 <= x1; ++x0) {
2740
0
    if (*shapePtr) {
2741
0
      break;
2742
0
    }
2743
0
    cSrcPtr += cSrcStride;
2744
0
    ++shapePtr;
2745
0
  }
2746
0
  if (x0 > x1) {
2747
0
    return;
2748
0
  }
2749
0
  updateModX(x0);
2750
0
  updateModY(y);
2751
0
  lastX = x0;
2752
2753
0
  useDestRow(y);
2754
2755
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3];
2756
0
  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
2757
0
  alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y)
2758
0
                * groupBackBitmap->alphaRowSize +
2759
0
              (groupBackX + x0)];
2760
2761
0
  for (x = x0; x <= x1; ++x) {
2762
2763
    //----- shape
2764
0
    shape = *shapePtr;
2765
0
    if (!shape) {
2766
0
      destColorPtr += 3;
2767
0
      ++destAlphaPtr;
2768
0
      ++alpha0Ptr;
2769
0
      cSrcPtr += cSrcStride;
2770
0
      ++shapePtr;
2771
0
      continue;
2772
0
    }
2773
0
    lastX = x;
2774
2775
    //----- read destination pixel
2776
0
    cDest0 = destColorPtr[0];
2777
0
    cDest1 = destColorPtr[1];
2778
0
    cDest2 = destColorPtr[2];
2779
0
    aDest = *destAlphaPtr;
2780
2781
    //----- source color
2782
0
    cSrc0 = state->rgbTransferR[cSrcPtr[0]];
2783
0
    cSrc1 = state->rgbTransferG[cSrcPtr[1]];
2784
0
    cSrc2 = state->rgbTransferB[cSrcPtr[2]];
2785
2786
    //----- source alpha
2787
0
    aSrc = div255(pipe->aInput * shape);
2788
2789
    //----- result alpha and non-isolated group element correction
2790
0
    aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
2791
0
    alpha0 = *alpha0Ptr++;
2792
0
    alphaI = (Guchar)(aResult + alpha0 - div255(aResult * alpha0));
2793
2794
    //----- result color
2795
0
    if (alphaI == 0) {
2796
0
      cResult0 = 0;
2797
0
      cResult1 = 0;
2798
0
      cResult2 = 0;
2799
0
    } else {
2800
0
      cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
2801
0
      cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
2802
0
      cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
2803
0
    }
2804
2805
    //----- write destination pixel
2806
0
    destColorPtr[0] = cResult0;
2807
0
    destColorPtr[1] = cResult1;
2808
0
    destColorPtr[2] = cResult2;
2809
0
    destColorPtr += 3;
2810
0
    *destAlphaPtr++ = aResult;
2811
2812
0
    cSrcPtr += cSrcStride;
2813
0
    ++shapePtr;
2814
0
  } // for (x ...)
2815
2816
0
  updateModX(lastX);
2817
0
}
2818
2819
void Splash::pipeRunNonIsoBGR8(SplashPipe *pipe, int x0, int x1, int y,
2820
0
             Guchar *shapePtr, SplashColorPtr cSrcPtr) {
2821
0
  Guchar shape, aSrc, aDest, alphaI, alpha0, aResult;
2822
0
  Guchar cSrc0, cSrc1, cSrc2;
2823
0
  Guchar cDest0, cDest1, cDest2;
2824
0
  Guchar cResult0, cResult1, cResult2;
2825
0
  SplashColorPtr destColorPtr;
2826
0
  Guchar *destAlphaPtr;
2827
0
  Guchar *alpha0Ptr;
2828
0
  int cSrcStride, x, lastX;
2829
2830
0
  if (cSrcPtr) {
2831
0
    cSrcStride = 3;
2832
0
  } else {
2833
0
    cSrcPtr = pipe->cSrcVal;
2834
0
    cSrcStride = 0;
2835
0
  }
2836
0
  for (; x0 <= x1; ++x0) {
2837
0
    if (*shapePtr) {
2838
0
      break;
2839
0
    }
2840
0
    cSrcPtr += cSrcStride;
2841
0
    ++shapePtr;
2842
0
  }
2843
0
  if (x0 > x1) {
2844
0
    return;
2845
0
  }
2846
0
  updateModX(x0);
2847
0
  updateModY(y);
2848
0
  lastX = x0;
2849
2850
0
  useDestRow(y);
2851
2852
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3];
2853
0
  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
2854
0
  alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y)
2855
0
                * groupBackBitmap->alphaRowSize +
2856
0
              (groupBackX + x0)];
2857
2858
0
  for (x = x0; x <= x1; ++x) {
2859
2860
    //----- shape
2861
0
    shape = *shapePtr;
2862
0
    if (!shape) {
2863
0
      destColorPtr += 3;
2864
0
      ++destAlphaPtr;
2865
0
      ++alpha0Ptr;
2866
0
      cSrcPtr += cSrcStride;
2867
0
      ++shapePtr;
2868
0
      continue;
2869
0
    }
2870
0
    lastX = x;
2871
2872
    //----- read destination pixel
2873
0
    cDest0 = destColorPtr[2];
2874
0
    cDest1 = destColorPtr[1];
2875
0
    cDest2 = destColorPtr[0];
2876
0
    aDest = *destAlphaPtr;
2877
2878
    //----- source color
2879
0
    cSrc0 = state->rgbTransferR[cSrcPtr[0]];
2880
0
    cSrc1 = state->rgbTransferG[cSrcPtr[1]];
2881
0
    cSrc2 = state->rgbTransferB[cSrcPtr[2]];
2882
2883
    //----- source alpha
2884
0
    aSrc = div255(pipe->aInput * shape);
2885
2886
    //----- result alpha and non-isolated group element correction
2887
0
    aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
2888
0
    alpha0 = *alpha0Ptr++;
2889
0
    alphaI = (Guchar)(aResult + alpha0 - div255(aResult * alpha0));
2890
2891
    //----- result color
2892
0
    if (alphaI == 0) {
2893
0
      cResult0 = 0;
2894
0
      cResult1 = 0;
2895
0
      cResult2 = 0;
2896
0
    } else {
2897
0
      cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
2898
0
      cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
2899
0
      cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
2900
0
    }
2901
2902
    //----- write destination pixel
2903
0
    destColorPtr[0] = cResult2;
2904
0
    destColorPtr[1] = cResult1;
2905
0
    destColorPtr[2] = cResult0;
2906
0
    destColorPtr += 3;
2907
0
    *destAlphaPtr++ = aResult;
2908
2909
0
    cSrcPtr += cSrcStride;
2910
0
    ++shapePtr;
2911
0
  } // for (x ...)
2912
2913
0
  updateModX(lastX);
2914
0
}
2915
2916
#if SPLASH_CMYK
2917
void Splash::pipeRunNonIsoCMYK8(SplashPipe *pipe, int x0, int x1, int y,
2918
0
        Guchar *shapePtr, SplashColorPtr cSrcPtr) {
2919
0
  Guchar shape, aSrc, aDest, alphaI, alpha0, aResult, aPrev;
2920
0
  Guchar cSrc0, cSrc1, cSrc2, cSrc3;
2921
0
  Guchar cDest0, cDest1, cDest2, cDest3;
2922
0
  Guchar cResult0, cResult1, cResult2, cResult3;
2923
0
  SplashColorPtr destColorPtr;
2924
0
  Guchar *destAlphaPtr;
2925
0
  Guchar *alpha0Ptr;
2926
0
  int cSrcStride, x, lastX;
2927
2928
0
  if (cSrcPtr) {
2929
0
    cSrcStride = 4;
2930
0
  } else {
2931
0
    cSrcPtr = pipe->cSrcVal;
2932
0
    cSrcStride = 0;
2933
0
  }
2934
0
  for (; x0 <= x1; ++x0) {
2935
0
    if (*shapePtr) {
2936
0
      break;
2937
0
    }
2938
0
    cSrcPtr += cSrcStride;
2939
0
    ++shapePtr;
2940
0
  }
2941
0
  if (x0 > x1) {
2942
0
    return;
2943
0
  }
2944
0
  updateModX(x0);
2945
0
  updateModY(y);
2946
0
  lastX = x0;
2947
2948
0
  useDestRow(y);
2949
2950
0
  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 4];
2951
0
  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
2952
0
  alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y)
2953
0
                * groupBackBitmap->alphaRowSize +
2954
0
              (groupBackX + x0)];
2955
2956
0
  for (x = x0; x <= x1; ++x) {
2957
2958
    //----- shape
2959
0
    shape = *shapePtr;
2960
0
    if (!shape) {
2961
0
      destColorPtr += 4;
2962
0
      ++destAlphaPtr;
2963
0
      ++alpha0Ptr;
2964
0
      cSrcPtr += cSrcStride;
2965
0
      ++shapePtr;
2966
0
      continue;
2967
0
    }
2968
0
    lastX = x;
2969
2970
    //----- read destination pixel
2971
0
    cDest0 = destColorPtr[0];
2972
0
    cDest1 = destColorPtr[1];
2973
0
    cDest2 = destColorPtr[2];
2974
0
    cDest3 = destColorPtr[3];
2975
0
    aDest = *destAlphaPtr;
2976
2977
    //----- overprint
2978
0
    aPrev = (Guchar)(*alpha0Ptr + aDest - div255(*alpha0Ptr * aDest));
2979
0
    if (state->overprintMask & 0x01) {
2980
0
      cSrc0 = state->cmykTransferC[cSrcPtr[0]];
2981
0
    } else {
2982
0
      cSrc0 = div255(aPrev * cDest0);
2983
0
    }
2984
0
    if (state->overprintMask & 0x02) {
2985
0
      cSrc1 = state->cmykTransferM[cSrcPtr[1]];
2986
0
    } else {
2987
0
      cSrc1 = div255(aPrev * cDest1);
2988
0
    }
2989
0
    if (state->overprintMask & 0x04) {
2990
0
      cSrc2 = state->cmykTransferY[cSrcPtr[2]];
2991
0
    } else {
2992
0
      cSrc2 = div255(aPrev * cDest2);
2993
0
    }
2994
0
    if (state->overprintMask & 0x08) {
2995
0
      cSrc3 = state->cmykTransferK[cSrcPtr[3]];
2996
0
    } else {
2997
0
      cSrc3 = div255(aPrev * cDest3);
2998
0
    }
2999
3000
    //----- source alpha
3001
0
    aSrc = div255(pipe->aInput * shape);
3002
3003
    //----- result alpha and non-isolated group element correction
3004
0
    aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
3005
0
    alpha0 = *alpha0Ptr++;
3006
0
    alphaI = (Guchar)(aResult + alpha0 - div255(aResult * alpha0));
3007
3008
    //----- result color
3009
0
    if (alphaI == 0) {
3010
0
      cResult0 = 0;
3011
0
      cResult1 = 0;
3012
0
      cResult2 = 0;
3013
0
      cResult3 = 0;
3014
0
    } else {
3015
0
      cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
3016
0
      cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
3017
0
      cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
3018
0
      cResult3 = (Guchar)(((alphaI - aSrc) * cDest3 + aSrc * cSrc3) / alphaI);
3019
0
    }
3020
3021
    //----- write destination pixel
3022
0
    destColorPtr[0] = cResult0;
3023
0
    destColorPtr[1] = cResult1;
3024
0
    destColorPtr[2] = cResult2;
3025
0
    destColorPtr[3] = cResult3;
3026
0
    destColorPtr += 4;
3027
0
    *destAlphaPtr++ = aResult;
3028
3029
0
    cSrcPtr += cSrcStride;
3030
0
    ++shapePtr;
3031
0
  } // for (x ...)
3032
3033
0
  updateModX(lastX);
3034
0
}
3035
#endif
3036
3037
3038
0
void Splash::useDestRow(int y) {
3039
0
  int y0, y1, yy;
3040
3041
0
  if (groupDestInitMode == splashGroupDestPreInit) {
3042
0
    return;
3043
0
  }
3044
0
  if (groupDestInitYMin > groupDestInitYMax) {
3045
0
    y0 = y1 = y;
3046
0
    groupDestInitYMin = groupDestInitYMax = y;
3047
0
  } else if (y < groupDestInitYMin) {
3048
0
    y0 = y;
3049
0
    y1 = groupDestInitYMin - 1;
3050
0
    groupDestInitYMin = y;
3051
0
  } else if (y > groupDestInitYMax) {
3052
0
    y0 = groupDestInitYMax + 1;
3053
0
    y1 = y;
3054
0
    groupDestInitYMax = y;
3055
0
  } else {
3056
0
    return;
3057
0
  }
3058
0
  for (yy = y0; yy <= y1; ++yy) {
3059
0
    if (groupDestInitMode == splashGroupDestInitZero) {
3060
      // same as clear(color=0, alpha=0)
3061
0
      memset(bitmap->data + bitmap->rowSize * yy, 0,
3062
0
       bitmap->rowSize < 0 ? -bitmap->rowSize : bitmap->rowSize);
3063
0
      if (bitmap->alpha) {
3064
0
  memset(bitmap->alpha + bitmap->alphaRowSize * yy, 0,
3065
0
         bitmap->alphaRowSize);
3066
0
      }
3067
0
    } else { // (groupDestInitMode == splashGroupDestInitCopy)
3068
      // same as blitTransparent
3069
0
      copyGroupBackdropRow(yy);
3070
0
    }
3071
0
  }
3072
0
}
3073
3074
0
void Splash::copyGroupBackdropRow(int y) {
3075
0
  SplashColorPtr p, q;
3076
0
  Guchar mask, srcMask;
3077
0
  int x;
3078
3079
0
  if (groupBackBitmap->mode != bitmap->mode) {
3080
0
    return;
3081
0
  }
3082
3083
0
  if (bitmap->mode == splashModeMono1) {
3084
0
    p = &bitmap->data[y * bitmap->rowSize];
3085
0
    mask = (Guchar)0x80;
3086
0
    q = &groupBackBitmap->data[(groupBackY + y) * groupBackBitmap->rowSize
3087
0
             + (groupBackX >> 3)];
3088
0
    srcMask = (Guchar)(0x80 >> (groupBackX & 7));
3089
0
    for (x = 0; x < bitmap->width; ++x) {
3090
0
      if (*q & srcMask) {
3091
0
  *p |= mask;
3092
0
      } else {
3093
0
  *p &= (Guchar)~mask;
3094
0
      }
3095
0
      if (!(mask = (Guchar)(mask >> 1))) {
3096
0
  mask = 0x80;
3097
0
  ++p;
3098
0
      }
3099
0
      if (!(srcMask = (Guchar)(srcMask >> 1))) {
3100
0
  srcMask = 0x80;
3101
0
  ++q;
3102
0
      }
3103
0
    }
3104
0
  } else {
3105
0
    p = &bitmap->data[y * bitmap->rowSize];
3106
0
    q = &groupBackBitmap->data[(groupBackY + y) * groupBackBitmap->rowSize
3107
0
             + bitmapComps * groupBackX];
3108
0
    memcpy(p, q, bitmapComps * bitmap->width);
3109
0
  }
3110
3111
0
  if (bitmap->alpha) {
3112
0
    memset(&bitmap->alpha[y * bitmap->alphaRowSize], 0, bitmap->width);
3113
0
  }
3114
0
}
3115
3116
//------------------------------------------------------------------------
3117
3118
// Transform a point from user space to device space.
3119
inline void Splash::transform(SplashCoord *matrix,
3120
            SplashCoord xi, SplashCoord yi,
3121
0
            SplashCoord *xo, SplashCoord *yo) {
3122
  //                          [ m[0] m[1] 0 ]
3123
  // [xo yo 1] = [xi yi 1] *  [ m[2] m[3] 0 ]
3124
  //                          [ m[4] m[5] 1 ]
3125
0
  *xo = xi * matrix[0] + yi * matrix[2] + matrix[4];
3126
0
  *yo = xi * matrix[1] + yi * matrix[3] + matrix[5];
3127
0
}
3128
3129
//------------------------------------------------------------------------
3130
// SplashImageCache
3131
//------------------------------------------------------------------------
3132
3133
0
SplashImageCache::SplashImageCache() {
3134
0
  tag = NULL;
3135
0
  width = 0;
3136
0
  height = 0;
3137
0
  mode = splashModeRGB8;
3138
0
  alpha = gFalse;
3139
0
  interpolate = gFalse;
3140
0
  colorData = NULL;
3141
0
  alphaData = NULL;
3142
0
  refCount = 1;
3143
0
}
3144
3145
0
SplashImageCache::~SplashImageCache() {
3146
0
  if (tag) {
3147
0
    delete tag;
3148
0
  }
3149
0
  gfree(colorData);
3150
0
  gfree(alphaData);
3151
0
}
3152
3153
GBool SplashImageCache::match(GString *aTag, int aWidth, int aHeight,
3154
            SplashColorMode aMode, GBool aAlpha,
3155
0
            GBool aInterpolate) {
3156
0
  return aTag && tag && !aTag->cmp(tag) &&
3157
0
   aWidth == width && aHeight == height &&
3158
0
   aMode == mode && aAlpha == alpha &&
3159
0
   aInterpolate == interpolate;
3160
0
}
3161
3162
void SplashImageCache::reset(GString *aTag, int aWidth, int aHeight,
3163
           SplashColorMode aMode, GBool aAlpha,
3164
0
           GBool aInterpolate) {
3165
0
  if (tag) {
3166
0
    delete tag;
3167
0
  }
3168
0
  if (aTag) {
3169
0
    tag = aTag->copy();
3170
0
  } else {
3171
0
    tag = NULL;
3172
0
  }
3173
0
  width = aWidth;
3174
0
  height = aHeight;
3175
0
  mode = aMode;
3176
0
  alpha = aAlpha;
3177
0
  interpolate = aInterpolate; 
3178
0
  gfree(colorData);
3179
0
  colorData = NULL;
3180
0
  gfree(alphaData);
3181
0
  alphaData = NULL;
3182
0
}
3183
3184
0
void SplashImageCache::incRefCount() {
3185
0
  ++refCount;
3186
0
}
3187
3188
0
void SplashImageCache::decRefCount() {
3189
0
  --refCount;
3190
0
  if (refCount == 0) {
3191
0
    delete this;
3192
0
  }
3193
0
}
3194
3195
//------------------------------------------------------------------------
3196
// ImageScaler
3197
//------------------------------------------------------------------------
3198
3199
// Abstract base class.
3200
class ImageScaler {
3201
public:
3202
3203
0
  ImageScaler() {}
3204
0
  virtual ~ImageScaler() {}
3205
3206
  // Compute the next line of the scaled image.  This can be called up
3207
  // to [scaledHeight] times.
3208
  virtual void nextLine() = 0;
3209
3210
  // Retrieve the color and alpha data generated by the most recent
3211
  // call to nextLine().
3212
  virtual Guchar *colorData() = 0;
3213
  virtual Guchar *alphaData() = 0;
3214
};
3215
3216
//------------------------------------------------------------------------
3217
// BasicImageScaler
3218
//------------------------------------------------------------------------
3219
3220
// The actual image scaler.
3221
class BasicImageScaler: public ImageScaler {
3222
public:
3223
3224
  BasicImageScaler(SplashImageSource aSrc, void *aSrcData,
3225
       int aSrcWidth, int aSrcHeight, int aNComps, GBool aHasAlpha,
3226
       int aScaledWidth, int aScaledHeight, GBool aInterpolate);
3227
  virtual ~BasicImageScaler();
3228
  virtual void nextLine();
3229
0
  virtual Guchar *colorData() { return colorLine; }
3230
0
  virtual Guchar *alphaData() { return alphaLine; }
3231
3232
protected:
3233
3234
  void vertDownscaleHorizDownscale();
3235
  void vertDownscaleHorizUpscaleNoInterp();
3236
  void vertDownscaleHorizUpscaleInterp();
3237
  void vertUpscaleHorizDownscaleNoInterp();
3238
  void vertUpscaleHorizDownscaleInterp();
3239
  void vertUpscaleHorizUpscaleNoInterp();
3240
  void vertUpscaleHorizUpscaleInterp();
3241
3242
  // source image data function
3243
  SplashImageSource src;
3244
  void *srcData;
3245
3246
  // source image size
3247
  int srcWidth;
3248
  int srcHeight;
3249
3250
  // scaled image size
3251
  int scaledWidth;
3252
  int scaledHeight;
3253
3254
  // number of color and alpha components
3255
  int nComps;
3256
  GBool hasAlpha;
3257
3258
  // params/state for vertical scaling
3259
  int yp, yq;
3260
  int yt, yn;
3261
  int ySrcCur, yScaledCur;
3262
  SplashCoord yInvScale;
3263
3264
  // params for horizontal scaling
3265
  int xp, xq;
3266
  SplashCoord xInvScale;
3267
3268
  // scaling function
3269
  void (BasicImageScaler::*scalingFunc)();
3270
3271
  // temporary buffers for vertical scaling
3272
  Guchar *colorTmpBuf0;
3273
  Guchar *colorTmpBuf1;
3274
  Guchar *colorTmpBuf2;
3275
  Guchar *alphaTmpBuf0;
3276
  Guchar *alphaTmpBuf1;
3277
  Guchar *alphaTmpBuf2;
3278
  Guint *colorAccBuf;
3279
  Guint *alphaAccBuf;
3280
3281
  // output of horizontal scaling
3282
  Guchar *colorLine;
3283
  Guchar *alphaLine;
3284
};
3285
3286
BasicImageScaler::BasicImageScaler(SplashImageSource aSrc, void *aSrcData,
3287
           int aSrcWidth, int aSrcHeight,
3288
           int aNComps, GBool aHasAlpha,
3289
           int aScaledWidth, int aScaledHeight,
3290
0
           GBool aInterpolate) {
3291
0
  colorTmpBuf0 = NULL;
3292
0
  colorTmpBuf1 = NULL;
3293
0
  colorTmpBuf2 = NULL;
3294
0
  alphaTmpBuf0 = NULL;
3295
0
  alphaTmpBuf1 = NULL;
3296
0
  alphaTmpBuf2 = NULL;
3297
0
  colorAccBuf = NULL;
3298
0
  alphaAccBuf = NULL;
3299
0
  colorLine = NULL;
3300
0
  alphaLine = NULL;
3301
3302
0
  src = aSrc;
3303
0
  srcData = aSrcData;
3304
0
  srcWidth = aSrcWidth;
3305
0
  srcHeight = aSrcHeight;
3306
0
  scaledWidth = aScaledWidth;
3307
0
  scaledHeight = aScaledHeight;
3308
0
  nComps = aNComps;
3309
0
  hasAlpha = aHasAlpha;
3310
3311
  // select scaling function; allocate buffers
3312
0
  if (scaledHeight <= srcHeight) {
3313
    // vertical downscaling
3314
0
    yp = srcHeight / scaledHeight;
3315
0
    yq = srcHeight % scaledHeight;
3316
0
    yt = 0;
3317
0
    colorTmpBuf0 = (Guchar *)gmallocn(srcWidth, nComps);
3318
0
    colorAccBuf = (Guint *)gmallocn(srcWidth, nComps * (int)sizeof(Guint));
3319
0
    if (hasAlpha) {
3320
0
      alphaTmpBuf0 = (Guchar *)gmalloc(srcWidth);
3321
0
      alphaAccBuf = (Guint *)gmallocn(srcWidth, sizeof(Guint));
3322
0
    }
3323
0
    if (scaledWidth <= srcWidth) {
3324
0
      scalingFunc = &BasicImageScaler::vertDownscaleHorizDownscale;
3325
0
    } else {
3326
0
      if (aInterpolate) {
3327
0
  scalingFunc = &BasicImageScaler::vertDownscaleHorizUpscaleInterp;
3328
0
      } else {
3329
0
  scalingFunc = &BasicImageScaler::vertDownscaleHorizUpscaleNoInterp;
3330
0
      }
3331
0
    }
3332
0
  } else {
3333
    // vertical upscaling
3334
0
    yp = scaledHeight / srcHeight;
3335
0
    yq = scaledHeight % srcHeight;
3336
0
    yt = 0;
3337
0
    yn = 0;
3338
0
    if (aInterpolate) {
3339
0
      yInvScale = (SplashCoord)srcHeight / (SplashCoord)scaledHeight;
3340
0
      colorTmpBuf0 = (Guchar *)gmallocn(srcWidth, nComps);
3341
0
      colorTmpBuf1 = (Guchar *)gmallocn(srcWidth, nComps);
3342
0
      if (hasAlpha) {
3343
0
  alphaTmpBuf0 = (Guchar *)gmalloc(srcWidth);
3344
0
  alphaTmpBuf1 = (Guchar *)gmalloc(srcWidth);
3345
0
      }
3346
0
      ySrcCur = 0;
3347
0
      yScaledCur = 0;
3348
0
      if (scaledWidth <= srcWidth) {
3349
0
  scalingFunc = &BasicImageScaler::vertUpscaleHorizDownscaleInterp;
3350
0
      } else {
3351
0
  colorTmpBuf2 = (Guchar *)gmallocn(srcWidth, nComps);
3352
0
  if (hasAlpha) {
3353
0
    alphaTmpBuf2 = (Guchar *)gmalloc(srcWidth);
3354
0
  }
3355
0
  scalingFunc = &BasicImageScaler::vertUpscaleHorizUpscaleInterp;
3356
0
      }
3357
0
    } else {
3358
0
      colorTmpBuf0 = (Guchar *)gmallocn(srcWidth, nComps);
3359
0
      if (hasAlpha) {
3360
0
  alphaTmpBuf0 = (Guchar *)gmalloc(srcWidth);
3361
0
      }
3362
0
      if (scaledWidth <= srcWidth) {
3363
0
  scalingFunc = &BasicImageScaler::vertUpscaleHorizDownscaleNoInterp;
3364
0
      } else {
3365
0
  scalingFunc = &BasicImageScaler::vertUpscaleHorizUpscaleNoInterp;
3366
0
      }
3367
0
    }
3368
0
  }
3369
0
  if (scaledWidth <= srcWidth) {
3370
0
    xp = srcWidth / scaledWidth;
3371
0
    xq = srcWidth % scaledWidth;
3372
0
  } else {
3373
0
    xp = scaledWidth / srcWidth;
3374
0
    xq = scaledWidth % srcWidth;
3375
0
    if (aInterpolate) {
3376
0
      xInvScale = (SplashCoord)srcWidth / (SplashCoord)scaledWidth;
3377
0
    }
3378
0
  }
3379
0
  colorLine = (Guchar *)gmallocn(scaledWidth, nComps);
3380
0
  if (hasAlpha) {
3381
0
    alphaLine = (Guchar *)gmalloc(scaledWidth);
3382
0
  }
3383
0
}
3384
3385
0
BasicImageScaler::~BasicImageScaler() {
3386
0
  gfree(colorTmpBuf0);
3387
0
  gfree(colorTmpBuf1);
3388
0
  gfree(colorTmpBuf2);
3389
0
  gfree(alphaTmpBuf0);
3390
0
  gfree(alphaTmpBuf1);
3391
0
  gfree(alphaTmpBuf2);
3392
0
  gfree(colorAccBuf);
3393
0
  gfree(alphaAccBuf);
3394
0
  gfree(colorLine);
3395
0
  gfree(alphaLine);
3396
0
}
3397
3398
0
void BasicImageScaler::nextLine() {
3399
0
  (this->*scalingFunc)();
3400
0
}
3401
3402
0
void BasicImageScaler::vertDownscaleHorizDownscale() {
3403
  //--- vert downscale
3404
0
  int yStep = yp;
3405
0
  yt += yq;
3406
0
  if (yt >= scaledHeight) {
3407
0
    yt -= scaledHeight;
3408
0
    ++yStep;
3409
0
  }
3410
0
  memset(colorAccBuf, 0, (srcWidth * nComps) * sizeof(Guint));
3411
0
  if (hasAlpha) {
3412
0
    memset(alphaAccBuf, 0, srcWidth * sizeof(Guint));
3413
0
  }
3414
0
  int nRowComps = srcWidth * nComps;
3415
0
  for (int i = 0; i < yStep; ++i) {
3416
0
    (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
3417
0
    for (int j = 0; j < nRowComps; ++j) {
3418
0
      colorAccBuf[j] += colorTmpBuf0[j];
3419
0
    }
3420
0
    if (hasAlpha) {
3421
0
      for (int j = 0; j < srcWidth; ++j) {
3422
0
  alphaAccBuf[j] += alphaTmpBuf0[j];
3423
0
      }
3424
0
    }
3425
0
  }
3426
3427
  //--- horiz downscale
3428
0
  int colorAcc[splashMaxColorComps];
3429
0
  int xt = 0;
3430
0
  int unscaledColorIdx = 0;
3431
0
  int unscaledAlphaIdx = 0;
3432
0
  int scaledColorIdx = 0;
3433
3434
0
  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
3435
0
    int xStep = xp;
3436
0
    xt += xq;
3437
0
    if (xt >= scaledWidth) {
3438
0
      xt -= scaledWidth;
3439
0
      ++xStep;
3440
0
    }
3441
3442
0
    for (int j = 0; j < nComps; ++j) {
3443
0
      colorAcc[j] = 0;
3444
0
    }
3445
0
    for (int i = 0; i < xStep; ++i) {
3446
0
      for (int j = 0; j < nComps; ++j) {
3447
0
  colorAcc[j] += colorAccBuf[unscaledColorIdx + j];
3448
0
      }
3449
0
      unscaledColorIdx += nComps;
3450
0
    }
3451
0
    int nPixels = yStep * xStep;
3452
0
    for (int j = 0; j < nComps; ++j) {
3453
0
      colorLine[scaledColorIdx + j] = (Guchar)(colorAcc[j] / nPixels);
3454
0
    }
3455
0
    scaledColorIdx += nComps;
3456
3457
0
    if (hasAlpha) {
3458
0
      int alphaAcc = 0;
3459
0
      for (int i = 0; i < xStep; ++i) {
3460
0
  alphaAcc += alphaAccBuf[unscaledAlphaIdx];
3461
0
  ++unscaledAlphaIdx;
3462
0
      }
3463
0
      alphaLine[scaledIdx] = (Guchar)(alphaAcc / nPixels);
3464
0
    }
3465
0
  }
3466
0
}
3467
3468
0
void BasicImageScaler::vertDownscaleHorizUpscaleNoInterp() {
3469
  //--- vert downscale
3470
0
  int yStep = yp;
3471
0
  yt += yq;
3472
0
  if (yt >= scaledHeight) {
3473
0
    yt -= scaledHeight;
3474
0
    ++yStep;
3475
0
  }
3476
0
  memset(colorAccBuf, 0, (srcWidth * nComps) * sizeof(Guint));
3477
0
  if (hasAlpha) {
3478
0
    memset(alphaAccBuf, 0, srcWidth * sizeof(Guint));
3479
0
  }
3480
0
  int nRowComps = srcWidth * nComps;
3481
0
  for (int i = 0; i < yStep; ++i) {
3482
0
    (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
3483
0
    for (int j = 0; j < nRowComps; ++j) {
3484
0
      colorAccBuf[j] += colorTmpBuf0[j];
3485
0
    }
3486
0
    if (hasAlpha) {
3487
0
      for (int j = 0; j < srcWidth; ++j) {
3488
0
  alphaAccBuf[j] += alphaTmpBuf0[j];
3489
0
      }
3490
0
    }
3491
0
  }
3492
3493
  //--- horiz upscale
3494
0
  Guchar colorBuf[splashMaxColorComps];
3495
0
  int xt = 0;
3496
0
  int scaledColorIdx = 0;
3497
0
  int srcColorIdx = 0;
3498
0
  int scaledAlphaIdx = 0;
3499
0
  for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
3500
0
    int xStep = xp;
3501
0
    xt += xq;
3502
0
    if (xt >= srcWidth) {
3503
0
      xt -= srcWidth;
3504
0
      ++xStep;
3505
0
    }
3506
0
    for (int j = 0; j < nComps; ++j) {
3507
0
      colorBuf[j] = (Guchar)(colorAccBuf[srcColorIdx + j] / yStep);
3508
0
    }
3509
0
    srcColorIdx += nComps;
3510
0
    for (int i = 0; i < xStep; ++i) {
3511
0
      for (int j = 0; j < nComps; ++j) {
3512
0
  colorLine[scaledColorIdx + j] = colorBuf[j];
3513
0
      }
3514
0
      scaledColorIdx += nComps;
3515
0
    }
3516
0
    if (hasAlpha) {
3517
0
      Guchar alphaBuf = (Guchar)(alphaAccBuf[srcIdx] / yStep);
3518
0
      for (int i = 0; i < xStep; ++i) {
3519
0
  alphaLine[scaledAlphaIdx] = alphaBuf;
3520
0
  ++scaledAlphaIdx;
3521
0
      }
3522
0
    }
3523
0
  }
3524
0
}
3525
3526
0
void BasicImageScaler::vertDownscaleHorizUpscaleInterp() {
3527
  //--- vert downscale
3528
0
  int yStep = yp;
3529
0
  yt += yq;
3530
0
  if (yt >= scaledHeight) {
3531
0
    yt -= scaledHeight;
3532
0
    ++yStep;
3533
0
  }
3534
0
  memset(colorAccBuf, 0, (srcWidth * nComps) * sizeof(Guint));
3535
0
  if (hasAlpha) {
3536
0
    memset(alphaAccBuf, 0, srcWidth * sizeof(Guint));
3537
0
  }
3538
0
  int nRowComps = srcWidth * nComps;
3539
0
  for (int i = 0; i < yStep; ++i) {
3540
0
    (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
3541
0
    for (int j = 0; j < nRowComps; ++j) {
3542
0
      colorAccBuf[j] += colorTmpBuf0[j];
3543
0
    }
3544
0
    if (hasAlpha) {
3545
0
      for (int j = 0; j < srcWidth; ++j) {
3546
0
  alphaAccBuf[j] += alphaTmpBuf0[j];
3547
0
      }
3548
0
    }
3549
0
  }
3550
0
  for (int j = 0; j < srcWidth * nComps; ++j) {
3551
0
    colorAccBuf[j] /= yStep;
3552
0
  }
3553
0
  if (hasAlpha) {
3554
0
    for (int j = 0; j < srcWidth; ++j) {
3555
0
      alphaAccBuf[j] /= yStep;
3556
0
    }
3557
0
  }
3558
3559
  //--- horiz upscale
3560
0
  int scaledColorIdx = 0;
3561
0
  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
3562
0
    SplashCoord xs = ((SplashCoord)scaledIdx + 0.5) * xInvScale;
3563
0
    int x0 = splashFloor(xs - 0.5);
3564
0
    int x1 = x0 + 1;
3565
0
    SplashCoord s0 = (SplashCoord)x1 + 0.5 - xs;
3566
0
    SplashCoord s1 = (SplashCoord)1 - s0;
3567
0
    if (x0 < 0) {
3568
0
      x0 = 0;
3569
0
    }
3570
0
    if (x1 >= srcWidth) {
3571
0
      x1 = srcWidth - 1;
3572
0
    }
3573
0
    for (int j = 0; j < nComps; ++j) {
3574
0
      colorLine[scaledColorIdx + j] =
3575
0
    (Guchar)(int)(s0 * colorAccBuf[x0 * nComps + j] +
3576
0
      s1 * colorAccBuf[x1 * nComps + j]);
3577
0
    }
3578
0
    scaledColorIdx += nComps;
3579
0
    if (hasAlpha) {
3580
0
      alphaLine[scaledIdx] = (Guchar)(int)(s0 * alphaAccBuf[x0] +
3581
0
             s1 * alphaAccBuf[x1]);
3582
0
    }
3583
0
  }
3584
0
}
3585
3586
0
void BasicImageScaler::vertUpscaleHorizDownscaleNoInterp() {
3587
  //--- vert upscale
3588
0
  if (yn == 0) {
3589
0
    yn = yp;
3590
0
    yt += yq;
3591
0
    if (yt >= srcHeight) {
3592
0
      yt -= srcHeight;
3593
0
      ++yn;
3594
0
    }
3595
0
    (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
3596
0
  }
3597
0
  --yn;
3598
3599
  //--- horiz downscale
3600
0
  int colorAcc[splashMaxColorComps];
3601
0
  int xt = 0;
3602
0
  int unscaledColorIdx = 0;
3603
0
  int unscaledAlphaIdx = 0;
3604
0
  int scaledColorIdx = 0;
3605
0
  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
3606
0
    int xStep = xp;
3607
0
    xt += xq;
3608
0
    if (xt >= scaledWidth) {
3609
0
      xt -= scaledWidth;
3610
0
      ++xStep;
3611
0
    }
3612
3613
0
    for (int j = 0; j < nComps; ++j) {
3614
0
      colorAcc[j] = 0;
3615
0
    }
3616
0
    for (int i = 0; i < xStep; ++i) {
3617
0
      for (int j = 0; j < nComps; ++j) {
3618
0
  colorAcc[j] += colorTmpBuf0[unscaledColorIdx + j];
3619
0
      }
3620
0
      unscaledColorIdx += nComps;
3621
0
    }
3622
0
    for (int j = 0; j < nComps; ++j) {
3623
0
      colorLine[scaledColorIdx + j] = (Guchar)(colorAcc[j] / xStep);
3624
0
    }
3625
0
    scaledColorIdx += nComps;
3626
3627
0
    if (hasAlpha) {
3628
0
      int alphaAcc = 0;
3629
0
      for (int i = 0; i < xStep; ++i) {
3630
0
  alphaAcc += alphaTmpBuf0[unscaledAlphaIdx];
3631
0
  ++unscaledAlphaIdx;
3632
0
      }
3633
0
      alphaLine[scaledIdx] = (Guchar)(alphaAcc / xStep);
3634
0
    }
3635
0
  }
3636
0
}
3637
3638
0
void BasicImageScaler::vertUpscaleHorizDownscaleInterp() {
3639
  //--- vert upscale
3640
0
  if (ySrcCur == 0) {
3641
0
    (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
3642
0
    (*src)(srcData, colorTmpBuf1, alphaTmpBuf1);
3643
0
    ySrcCur = 1;
3644
0
  }
3645
0
  SplashCoord ys = ((SplashCoord)yScaledCur + 0.5) * yInvScale;
3646
0
  int y0 = splashFloor(ys - 0.5);
3647
0
  int y1 = y0 + 1;
3648
0
  SplashCoord vs0 = (SplashCoord)y1 + 0.5 - ys;
3649
0
  SplashCoord vs1 = (SplashCoord)1 - vs0;
3650
0
  if (y1 > ySrcCur && ySrcCur < srcHeight - 1) {
3651
0
    Guchar *t = colorTmpBuf0;
3652
0
    colorTmpBuf0 = colorTmpBuf1;
3653
0
    colorTmpBuf1 = t;
3654
0
    if (hasAlpha) {
3655
0
      t = alphaTmpBuf0;
3656
0
      alphaTmpBuf0 = alphaTmpBuf1;
3657
0
      alphaTmpBuf1 = t;
3658
0
    }
3659
0
    (*src)(srcData, colorTmpBuf1, alphaTmpBuf1);
3660
0
    ++ySrcCur;
3661
0
  }
3662
0
  Guchar *color0 = colorTmpBuf0;
3663
0
  Guchar *color1 = colorTmpBuf1;
3664
0
  Guchar *alpha0 = alphaTmpBuf0;
3665
0
  Guchar *alpha1 = alphaTmpBuf1;
3666
0
  if (y0 < 0) {
3667
0
    y0 = 0;
3668
0
    color1 = color0;
3669
0
    alpha1 = alpha0;
3670
0
  }
3671
0
  if (y1 >= srcHeight) {
3672
0
    y1 = srcHeight - 1;
3673
0
    color0 = color1;
3674
0
    alpha0 = alpha1;
3675
0
  }
3676
0
  ++yScaledCur;
3677
3678
  //--- horiz downscale
3679
0
  int colorAcc[splashMaxColorComps];
3680
0
  int xt = 0;
3681
0
  int unscaledColorIdx = 0;
3682
0
  int unscaledAlphaIdx = 0;
3683
0
  int scaledColorIdx = 0;
3684
0
  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
3685
0
    int xStep = xp;
3686
0
    xt += xq;
3687
0
    if (xt >= scaledWidth) {
3688
0
      xt -= scaledWidth;
3689
0
      ++xStep;
3690
0
    }
3691
3692
0
    for (int j = 0; j < nComps; ++j) {
3693
0
      colorAcc[j] = 0;
3694
0
    }
3695
0
    for (int i = 0; i < xStep; ++i) {
3696
0
      for (int j = 0; j < nComps; ++j) {
3697
0
  colorAcc[j] += (int)(vs0 * (int)color0[unscaledColorIdx + j] +
3698
0
           vs1 * (int)color1[unscaledColorIdx + j]);
3699
0
      }
3700
0
      unscaledColorIdx += nComps;
3701
0
    }
3702
0
    for (int j = 0; j < nComps; ++j) {
3703
0
      colorLine[scaledColorIdx + j] = (Guchar)(colorAcc[j] / xStep);
3704
0
    }
3705
0
    scaledColorIdx += nComps;
3706
3707
0
    if (hasAlpha) {
3708
0
      int alphaAcc = 0;
3709
0
      for (int i = 0; i < xStep; ++i) {
3710
0
  alphaAcc += (int)(vs0 * (int)alpha0[unscaledAlphaIdx] +
3711
0
        vs1 * (int)alpha1[unscaledAlphaIdx]);
3712
0
  ++unscaledAlphaIdx;
3713
0
      }
3714
0
      alphaLine[scaledIdx] = (Guchar)(alphaAcc / xStep);
3715
0
    }
3716
0
  }
3717
0
}
3718
3719
0
void BasicImageScaler::vertUpscaleHorizUpscaleNoInterp() {
3720
  //--- vert upscale
3721
0
  if (yn == 0) {
3722
0
    yn = yp;
3723
0
    yt += yq;
3724
0
    if (yt >= srcHeight) {
3725
0
      yt -= srcHeight;
3726
0
      ++yn;
3727
0
    }
3728
0
    (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
3729
0
  }
3730
0
  --yn;
3731
3732
  //--- horiz upscale
3733
0
  int xt = 0;
3734
0
  int scaledColorIdx = 0;
3735
0
  int srcColorIdx = 0;
3736
0
  int scaledAlphaIdx = 0;
3737
0
  for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
3738
0
    int xStep = xp;
3739
0
    xt += xq;
3740
0
    if (xt >= srcWidth) {
3741
0
      xt -= srcWidth;
3742
0
      ++xStep;
3743
0
    }
3744
0
    for (int i = 0; i < xStep; ++i) {
3745
0
      for (int j = 0; j < nComps; ++j) {
3746
0
  colorLine[scaledColorIdx + j] = colorTmpBuf0[srcColorIdx + j];
3747
0
      }
3748
0
      scaledColorIdx += nComps;
3749
0
    }
3750
0
    srcColorIdx += nComps;
3751
0
    if (hasAlpha) {
3752
0
      Guchar alphaBuf = alphaTmpBuf0[srcIdx];
3753
0
      for (int i = 0; i < xStep; ++i) {
3754
0
  alphaLine[scaledAlphaIdx] = alphaBuf;
3755
0
  ++scaledAlphaIdx;
3756
0
      }
3757
0
    }
3758
0
  }
3759
0
}
3760
3761
0
void BasicImageScaler::vertUpscaleHorizUpscaleInterp() {
3762
  //--- vert upscale
3763
0
  if (ySrcCur == 0) {
3764
0
    (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
3765
0
    (*src)(srcData, colorTmpBuf1, alphaTmpBuf1);
3766
0
    ySrcCur = 1;
3767
0
  }
3768
0
  SplashCoord ys = ((SplashCoord)yScaledCur + 0.5) * yInvScale;
3769
0
  int y0 = splashFloor(ys - 0.5);
3770
0
  int y1 = y0 + 1;
3771
0
  SplashCoord vs0 = (SplashCoord)y1 + 0.5 - ys;
3772
0
  SplashCoord vs1 = (SplashCoord)1 - vs0;
3773
0
  if (y1 > ySrcCur && ySrcCur < srcHeight - 1) {
3774
0
    Guchar *t = colorTmpBuf0;
3775
0
    colorTmpBuf0 = colorTmpBuf1;
3776
0
    colorTmpBuf1 = t;
3777
0
    if (hasAlpha) {
3778
0
      t = alphaTmpBuf0;
3779
0
      alphaTmpBuf0 = alphaTmpBuf1;
3780
0
      alphaTmpBuf1 = t;
3781
0
    }
3782
0
    (*src)(srcData, colorTmpBuf1, alphaTmpBuf1);
3783
0
    ++ySrcCur;
3784
0
  }
3785
0
  Guchar *color0 = colorTmpBuf0;
3786
0
  Guchar *color1 = colorTmpBuf1;
3787
0
  Guchar *alpha0 = alphaTmpBuf0;
3788
0
  Guchar *alpha1 = alphaTmpBuf1;
3789
0
  if (y0 < 0) {
3790
0
    y0 = 0;
3791
0
    color1 = color0;
3792
0
    alpha1 = alpha0;
3793
0
  }
3794
0
  if (y1 >= srcHeight) {
3795
0
    y1 = srcHeight - 1;
3796
0
    color0 = color1;
3797
0
    alpha0 = alpha1;
3798
0
  }
3799
0
  ++yScaledCur;
3800
0
  for (int srcIdx = 0; srcIdx < srcWidth * nComps; ++srcIdx) {
3801
0
    colorTmpBuf2[srcIdx] = (Guchar)(int)(vs0 * (int)color0[srcIdx] +
3802
0
           vs1 * (int)color1[srcIdx]);
3803
0
  }
3804
0
  if (hasAlpha) {
3805
0
    for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
3806
0
      alphaTmpBuf2[srcIdx] = (Guchar)(int)(vs0 * (int)alpha0[srcIdx] +
3807
0
             vs1 * (int)alpha1[srcIdx]);
3808
0
    }
3809
0
  }
3810
3811
  //--- horiz upscale
3812
0
  int scaledColorIdx = 0;
3813
0
  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
3814
0
    SplashCoord xs = ((SplashCoord)scaledIdx + 0.5) * xInvScale;
3815
0
    int x0 = splashFloor(xs - 0.5);
3816
0
    int x1 = x0 + 1;
3817
0
    SplashCoord hs0 = (SplashCoord)x1 + 0.5 - xs;
3818
0
    SplashCoord hs1 = (SplashCoord)1 - hs0;
3819
0
    if (x0 < 0) {
3820
0
      x0 = 0;
3821
0
    }
3822
0
    if (x1 >= srcWidth) {
3823
0
      x1 = srcWidth - 1;
3824
0
    }
3825
0
    for (int j = 0; j < nComps; ++j) {
3826
0
      colorLine[scaledColorIdx + j] =
3827
0
    (Guchar)(int)(hs0 * (int)colorTmpBuf2[x0 * nComps + j] +
3828
0
      hs1 * (int)colorTmpBuf2[x1 * nComps + j]);
3829
0
    }
3830
0
    scaledColorIdx += nComps;
3831
0
    if (hasAlpha) {
3832
0
      alphaLine[scaledIdx] = (Guchar)(int)(hs0 * (int)alphaTmpBuf2[x0] +
3833
0
             hs1 * (int)alphaTmpBuf2[x1]);
3834
0
    }
3835
0
  }
3836
0
}
3837
3838
//------------------------------------------------------------------------
3839
// SavingImageScaler
3840
//------------------------------------------------------------------------
3841
3842
// Wrapper around BasicImageScaler that saves the scaled image for use
3843
// by ReplayImageScaler.
3844
class SavingImageScaler: public BasicImageScaler {
3845
public:
3846
3847
  SavingImageScaler(SplashImageSource aSrc, void *aSrcData,
3848
        int aSrcWidth, int aSrcHeight, int aNComps, GBool aHasAlpha,
3849
        int aScaledWidth, int aScaledHeight, GBool aInterpolate,
3850
        Guchar *aColorCache, Guchar *aAlphaCache);
3851
  virtual void nextLine();
3852
3853
private:
3854
3855
  Guchar *colorPtr;
3856
  Guchar *alphaPtr;
3857
};
3858
3859
SavingImageScaler::SavingImageScaler(SplashImageSource aSrc, void *aSrcData,
3860
             int aSrcWidth, int aSrcHeight,
3861
             int aNComps, GBool aHasAlpha,
3862
             int aScaledWidth, int aScaledHeight,
3863
             GBool aInterpolate,
3864
             Guchar *aColorCache, Guchar *aAlphaCache):
3865
  BasicImageScaler(aSrc, aSrcData, aSrcWidth, aSrcHeight, aNComps, aHasAlpha,
3866
       aScaledWidth, aScaledHeight, aInterpolate)
3867
0
{
3868
0
  colorPtr = aColorCache;
3869
0
  alphaPtr = aAlphaCache;
3870
0
}
3871
3872
0
void SavingImageScaler::nextLine() {
3873
0
  BasicImageScaler::nextLine();
3874
0
  memcpy(colorPtr, colorData(), scaledWidth * nComps);
3875
0
  colorPtr += scaledWidth * nComps;
3876
0
  if (hasAlpha) {
3877
0
    memcpy(alphaPtr, alphaData(), scaledWidth);
3878
0
    alphaPtr += scaledWidth;
3879
0
  }
3880
0
}
3881
3882
//------------------------------------------------------------------------
3883
// ReplayImageScaler
3884
//------------------------------------------------------------------------
3885
3886
// "Replay" a scaled image saved by SavingImageScaler.
3887
class ReplayImageScaler: public ImageScaler {
3888
public:
3889
3890
  ReplayImageScaler(int aNComps, GBool aHasAlpha,
3891
        int aScaledWidth,
3892
        Guchar *aColorCache, Guchar *aAlphaCache);
3893
  virtual void nextLine();
3894
0
  virtual Guchar *colorData() { return colorLine; }
3895
0
  virtual Guchar *alphaData() { return alphaLine; }
3896
3897
private:
3898
3899
  int nComps;
3900
  GBool hasAlpha;
3901
  int scaledWidth;
3902
  Guchar *colorPtr;
3903
  Guchar *alphaPtr;
3904
  Guchar *colorLine;
3905
  Guchar *alphaLine;
3906
};
3907
3908
ReplayImageScaler::ReplayImageScaler(int aNComps, GBool aHasAlpha,
3909
             int aScaledWidth,
3910
0
             Guchar *aColorCache, Guchar *aAlphaCache) {
3911
0
  nComps = aNComps;
3912
0
  hasAlpha = aHasAlpha;
3913
0
  scaledWidth = aScaledWidth;
3914
0
  colorPtr = aColorCache;
3915
0
  alphaPtr = aAlphaCache;
3916
0
  colorLine = NULL;
3917
0
  alphaLine = NULL;
3918
0
}
3919
3920
0
void ReplayImageScaler::nextLine() {
3921
0
  colorLine = colorPtr;
3922
0
  alphaLine = alphaPtr;
3923
0
  colorPtr += scaledWidth * nComps;
3924
0
  if (hasAlpha) {
3925
0
    alphaPtr += scaledWidth;
3926
0
  }
3927
0
}
3928
3929
//------------------------------------------------------------------------
3930
// ImageMaskScaler
3931
//------------------------------------------------------------------------
3932
3933
class ImageMaskScaler {
3934
public:
3935
3936
  // Set up a MaskScaler to scale from [srcWidth]x[srcHeight] to
3937
  // [scaledWidth]x[scaledHeight].  The [interpolate] flag controls
3938
  // filtering on upsampling, and the [antialias] flag controls
3939
  // filtering on downsampling.
3940
  ImageMaskScaler(SplashImageMaskSource aSrc, void *aSrcData,
3941
      int aSrcWidth, int aSrcHeight,
3942
      int aScaledWidth, int aScaledHeight,
3943
      GBool aInterpolate, GBool aAntialias);
3944
3945
  ~ImageMaskScaler();
3946
3947
  // Compute the next line of the scaled image mask.  This can be
3948
  // called up to [scaledHeight] times.
3949
  void nextLine();
3950
3951
  // Retrieve the data generated by the most recent call to
3952
  // nextLine().
3953
0
  Guchar *data() { return line; }
3954
3955
private:
3956
3957
  void vertDownscaleHorizDownscale();
3958
  void vertDownscaleHorizDownscaleThresh();
3959
  void vertDownscaleHorizUpscaleNoInterp();
3960
  void vertDownscaleHorizUpscaleInterp();
3961
  void vertDownscaleHorizUpscaleThresh();
3962
  void vertUpscaleHorizDownscaleNoInterp();
3963
  void vertUpscaleHorizDownscaleInterp();
3964
  void vertUpscaleHorizDownscaleThresh();
3965
  void vertUpscaleHorizUpscaleNoInterp();
3966
  void vertUpscaleHorizUpscaleInterp();
3967
3968
  // source image data function
3969
  SplashImageMaskSource src;
3970
  void *srcData;
3971
3972
  // source image size
3973
  int srcWidth;
3974
  int srcHeight;
3975
3976
  // scaled image size
3977
  int scaledWidth;
3978
  int scaledHeight;
3979
3980
  // params/state for vertical scaling
3981
  int yp, yq;
3982
  int yt, yn;
3983
  int ySrcCur, yScaledCur;
3984
  SplashCoord yInvScale;
3985
3986
  // params for horizontal scaling
3987
  int xp, xq;
3988
  SplashCoord xInvScale;
3989
3990
  // vertical and horizontal scaling functions
3991
  void (ImageMaskScaler::*scalingFunc)();
3992
3993
  // temporary buffers for vertical scaling
3994
  Guchar *tmpBuf0;
3995
  Guchar *tmpBuf1;
3996
  Guchar *tmpBuf2;
3997
  Guint *accBuf;
3998
3999
  // output of horizontal scaling
4000
  Guchar *line;
4001
};
4002
4003
ImageMaskScaler::ImageMaskScaler(SplashImageMaskSource aSrc, void *aSrcData,
4004
         int aSrcWidth, int aSrcHeight,
4005
         int aScaledWidth, int aScaledHeight,
4006
0
         GBool aInterpolate, GBool aAntialias) {
4007
0
  tmpBuf0 = NULL;
4008
0
  tmpBuf1 = NULL;
4009
0
  tmpBuf2 = NULL;
4010
0
  accBuf = NULL;
4011
0
  line = NULL;
4012
4013
0
  src = aSrc;
4014
0
  srcData = aSrcData;
4015
0
  srcWidth = aSrcWidth;
4016
0
  srcHeight = aSrcHeight;
4017
0
  scaledWidth = aScaledWidth;
4018
0
  scaledHeight = aScaledHeight;
4019
4020
  // select scaling function; allocate buffers
4021
0
  if (scaledHeight <= srcHeight) {
4022
    // vertical downscaling
4023
0
    yp = srcHeight / scaledHeight;
4024
0
    yq = srcHeight % scaledHeight;
4025
0
    yt = 0;
4026
0
    tmpBuf0 = (Guchar *)gmalloc(srcWidth);
4027
0
    accBuf = (Guint *)gmallocn(srcWidth, sizeof(Guint));
4028
0
    if (scaledWidth <= srcWidth) {
4029
0
      if (!aAntialias) {
4030
0
  scalingFunc = &ImageMaskScaler::vertDownscaleHorizDownscaleThresh;
4031
0
      } else {
4032
0
  scalingFunc = &ImageMaskScaler::vertDownscaleHorizDownscale;
4033
0
      }
4034
0
    } else {
4035
0
      if (!aAntialias) {
4036
0
  scalingFunc = &ImageMaskScaler::vertDownscaleHorizUpscaleThresh;
4037
0
      } else if (aInterpolate) {
4038
0
  scalingFunc = &ImageMaskScaler::vertDownscaleHorizUpscaleInterp;
4039
0
      } else {
4040
0
  scalingFunc = &ImageMaskScaler::vertDownscaleHorizUpscaleNoInterp;
4041
0
      }
4042
0
    }
4043
0
  } else {
4044
    // vertical upscaling
4045
0
    yp = scaledHeight / srcHeight;
4046
0
    yq = scaledHeight % srcHeight;
4047
0
    yt = 0;
4048
0
    yn = 0;
4049
0
    if (!aAntialias) {
4050
0
      tmpBuf0 = (Guchar *)gmalloc(srcWidth);
4051
0
      if (scaledWidth <= srcWidth) {
4052
0
  scalingFunc = &ImageMaskScaler::vertUpscaleHorizDownscaleThresh;
4053
0
      } else {
4054
0
  scalingFunc = &ImageMaskScaler::vertUpscaleHorizUpscaleNoInterp;
4055
0
      }
4056
0
    } else if (aInterpolate) {
4057
0
      yInvScale = (SplashCoord)srcHeight / (SplashCoord)scaledHeight;
4058
0
      tmpBuf0 = (Guchar *)gmalloc(srcWidth);
4059
0
      tmpBuf1 = (Guchar *)gmalloc(srcWidth);
4060
0
      ySrcCur = 0;
4061
0
      yScaledCur = 0;
4062
0
      if (scaledWidth <= srcWidth) {
4063
0
  scalingFunc = &ImageMaskScaler::vertUpscaleHorizDownscaleInterp;
4064
0
      } else {
4065
0
  tmpBuf2 = (Guchar *)gmalloc(srcWidth);
4066
0
  scalingFunc = &ImageMaskScaler::vertUpscaleHorizUpscaleInterp;
4067
0
      }
4068
0
    } else {
4069
0
      tmpBuf0 = (Guchar *)gmalloc(srcWidth);
4070
0
      if (scaledWidth <= srcWidth) {
4071
0
  scalingFunc = &ImageMaskScaler::vertUpscaleHorizDownscaleNoInterp;
4072
0
      } else {
4073
0
  scalingFunc = &ImageMaskScaler::vertUpscaleHorizUpscaleNoInterp;
4074
0
      }
4075
0
    }
4076
0
  }
4077
0
  if (scaledWidth <= srcWidth) {
4078
0
    xp = srcWidth / scaledWidth;
4079
0
    xq = srcWidth % scaledWidth;
4080
0
  } else {
4081
0
    xp = scaledWidth / srcWidth;
4082
0
    xq = scaledWidth % srcWidth;
4083
0
    if (aInterpolate) {
4084
0
      xInvScale = (SplashCoord)srcWidth / (SplashCoord)scaledWidth;
4085
0
    }
4086
0
  }
4087
0
  line = (Guchar *)gmalloc(scaledWidth);
4088
0
}
4089
4090
0
ImageMaskScaler::~ImageMaskScaler() {
4091
0
  gfree(tmpBuf0);
4092
0
  gfree(tmpBuf1);
4093
0
  gfree(tmpBuf2);
4094
0
  gfree(accBuf);
4095
0
  gfree(line);
4096
0
}
4097
4098
0
void ImageMaskScaler::nextLine() {
4099
0
  (this->*scalingFunc)();
4100
0
}
4101
4102
0
void ImageMaskScaler::vertDownscaleHorizDownscale() {
4103
  //--- vert downscale
4104
0
  int yStep = yp;
4105
0
  yt += yq;
4106
0
  if (yt >= scaledHeight) {
4107
0
    yt -= scaledHeight;
4108
0
    ++yStep;
4109
0
  }
4110
0
  memset(accBuf, 0, srcWidth * sizeof(Guint));
4111
0
  for (int i = 0; i < yStep; ++i) {
4112
0
    (*src)(srcData, tmpBuf0);
4113
0
    for (int j = 0; j < srcWidth; ++j) {
4114
0
      accBuf[j] += tmpBuf0[j];
4115
0
    }
4116
0
  }
4117
4118
  //--- horiz downscale
4119
0
  int acc;
4120
0
  int xt = 0;
4121
0
  int unscaledIdx = 0;
4122
0
  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
4123
0
    int xStep = xp;
4124
0
    xt += xq;
4125
0
    if (xt >= scaledWidth) {
4126
0
      xt -= scaledWidth;
4127
0
      ++xStep;
4128
0
    }
4129
4130
0
    acc = 0;
4131
0
    for (int i = 0; i < xStep; ++i) {
4132
0
      acc += accBuf[unscaledIdx];
4133
0
      ++unscaledIdx;
4134
0
    }
4135
0
    line[scaledIdx] = (Guchar)((255 * acc) / (xStep * yStep));
4136
0
  }
4137
0
}
4138
4139
0
void ImageMaskScaler::vertDownscaleHorizDownscaleThresh() {
4140
  //--- vert downscale
4141
0
  int yStep = yp;
4142
0
  yt += yq;
4143
0
  if (yt >= scaledHeight) {
4144
0
    yt -= scaledHeight;
4145
0
    ++yStep;
4146
0
  }
4147
0
  memset(accBuf, 0, srcWidth * sizeof(Guint));
4148
0
  for (int i = 0; i < yStep; ++i) {
4149
0
    (*src)(srcData, tmpBuf0);
4150
0
    for (int j = 0; j < srcWidth; ++j) {
4151
0
      accBuf[j] += tmpBuf0[j];
4152
0
    }
4153
0
  }
4154
4155
  //--- horiz downscale
4156
0
  int acc;
4157
0
  int xt = 0;
4158
0
  int unscaledIdx = 0;
4159
0
  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
4160
0
    int xStep = xp;
4161
0
    xt += xq;
4162
0
    if (xt >= scaledWidth) {
4163
0
      xt -= scaledWidth;
4164
0
      ++xStep;
4165
0
    }
4166
4167
0
    acc = 0;
4168
0
    for (int i = 0; i < xStep; ++i) {
4169
0
      acc += accBuf[unscaledIdx];
4170
0
      ++unscaledIdx;
4171
0
    }
4172
0
    line[scaledIdx] = acc > ((xStep * yStep) >> 1) ? (Guchar)255 : (Guchar)0;
4173
0
  }
4174
0
}
4175
4176
0
void ImageMaskScaler::vertDownscaleHorizUpscaleNoInterp() {
4177
  //--- vert downscale
4178
0
  int yStep = yp;
4179
0
  yt += yq;
4180
0
  if (yt >= scaledHeight) {
4181
0
    yt -= scaledHeight;
4182
0
    ++yStep;
4183
0
  }
4184
0
  memset(accBuf, 0, srcWidth * sizeof(Guint));
4185
0
  for (int i = 0; i < yStep; ++i) {
4186
0
    (*src)(srcData, tmpBuf0);
4187
0
    for (int j = 0; j < srcWidth; ++j) {
4188
0
      accBuf[j] += tmpBuf0[j];
4189
0
    }
4190
0
  }
4191
4192
  //--- horiz upscale
4193
0
  int xt = 0;
4194
0
  int scaledIdx = 0;
4195
0
  for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
4196
0
    int xStep = xp;
4197
0
    xt += xq;
4198
0
    if (xt >= srcWidth) {
4199
0
      xt -= srcWidth;
4200
0
      ++xStep;
4201
0
    }
4202
0
    Guchar buf = (Guchar)((255 * accBuf[srcIdx]) / yStep);
4203
0
    for (int i = 0; i < xStep; ++i) {
4204
0
      line[scaledIdx] = buf;
4205
0
      ++scaledIdx;
4206
0
    }
4207
0
  }
4208
0
}
4209
4210
0
void ImageMaskScaler::vertDownscaleHorizUpscaleInterp() {
4211
  //--- vert downscale
4212
0
  int yStep = yp;
4213
0
  yt += yq;
4214
0
  if (yt >= scaledHeight) {
4215
0
    yt -= scaledHeight;
4216
0
    ++yStep;
4217
0
  }
4218
0
  memset(accBuf, 0, srcWidth * sizeof(Guint));
4219
0
  for (int i = 0; i < yStep; ++i) {
4220
0
    (*src)(srcData, tmpBuf0);
4221
0
    for (int j = 0; j < srcWidth; ++j) {
4222
0
      accBuf[j] += tmpBuf0[j];
4223
0
    }
4224
0
  }
4225
0
  for (int j = 0; j < srcWidth; ++j) {
4226
0
    accBuf[j] = (255 * accBuf[j]) / yStep;
4227
0
  }
4228
4229
  //--- horiz upscale
4230
0
  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
4231
0
    SplashCoord xs = ((SplashCoord)scaledIdx + 0.5) * xInvScale;
4232
0
    int x0 = splashFloor(xs - 0.5);
4233
0
    int x1 = x0 + 1;
4234
0
    SplashCoord s0 = (SplashCoord)x1 + 0.5 - xs;
4235
0
    SplashCoord s1 = (SplashCoord)1 - s0;
4236
0
    if (x0 < 0) {
4237
0
      x0 = 0;
4238
0
    }
4239
0
    if (x1 >= srcWidth) {
4240
0
      x1 = srcWidth - 1;
4241
0
    }
4242
0
    line[scaledIdx] = (Guchar)(int)(s0 * accBuf[x0] + s1 * accBuf[x1]);
4243
0
  }
4244
0
}
4245
4246
0
void ImageMaskScaler::vertDownscaleHorizUpscaleThresh() {
4247
  //--- vert downscale
4248
0
  int yStep = yp;
4249
0
  yt += yq;
4250
0
  if (yt >= scaledHeight) {
4251
0
    yt -= scaledHeight;
4252
0
    ++yStep;
4253
0
  }
4254
0
  memset(accBuf, 0, srcWidth * sizeof(Guint));
4255
0
  for (int i = 0; i < yStep; ++i) {
4256
0
    (*src)(srcData, tmpBuf0);
4257
0
    for (int j = 0; j < srcWidth; ++j) {
4258
0
      accBuf[j] += tmpBuf0[j];
4259
0
    }
4260
0
  }
4261
4262
  //--- horiz upscale
4263
0
  int xt = 0;
4264
0
  int scaledIdx = 0;
4265
0
  for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
4266
0
    int xStep = xp;
4267
0
    xt += xq;
4268
0
    if (xt >= srcWidth) {
4269
0
      xt -= srcWidth;
4270
0
      ++xStep;
4271
0
    }
4272
0
    Guchar buf = accBuf[srcIdx] > (Guint)(yStep >> 1) ? (Guchar)255 : (Guchar)0;
4273
0
    for (int i = 0; i < xStep; ++i) {
4274
0
      line[scaledIdx] = buf;
4275
0
      ++scaledIdx;
4276
0
    }
4277
0
  }
4278
0
}
4279
4280
0
void ImageMaskScaler::vertUpscaleHorizDownscaleNoInterp() {
4281
  //--- vert upscale
4282
0
  if (yn == 0) {
4283
0
    yn = yp;
4284
0
    yt += yq;
4285
0
    if (yt >= srcHeight) {
4286
0
      yt -= srcHeight;
4287
0
      ++yn;
4288
0
    }
4289
0
    (*src)(srcData, tmpBuf0);
4290
0
  }
4291
0
  --yn;
4292
4293
  //--- horiz downscale
4294
0
  int acc;
4295
0
  int xt = 0;
4296
0
  int unscaledIdx = 0;
4297
0
  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
4298
0
    int xStep = xp;
4299
0
    xt += xq;
4300
0
    if (xt >= scaledWidth) {
4301
0
      xt -= scaledWidth;
4302
0
      ++xStep;
4303
0
    }
4304
4305
0
    acc = 0;
4306
0
    for (int i = 0; i < xStep; ++i) {
4307
0
      acc += tmpBuf0[unscaledIdx];
4308
0
      ++unscaledIdx;
4309
0
    }
4310
0
    line[scaledIdx] = (Guchar)((255 * acc) / xStep);
4311
0
  }
4312
0
}
4313
4314
0
void ImageMaskScaler::vertUpscaleHorizDownscaleInterp() {
4315
  //--- vert upscale
4316
0
  if (ySrcCur == 0) {
4317
0
    (*src)(srcData, tmpBuf0);
4318
0
    (*src)(srcData, tmpBuf1);
4319
0
    ySrcCur = 1;
4320
0
  }
4321
0
  SplashCoord ys = ((SplashCoord)yScaledCur + 0.5) * yInvScale;
4322
0
  int y0 = splashFloor(ys - 0.5);
4323
0
  int y1 = y0 + 1;
4324
0
  SplashCoord vs0 = (SplashCoord)y1 + 0.5 - ys;
4325
0
  SplashCoord vs1 = (SplashCoord)1 - vs0;
4326
0
  if (y1 > ySrcCur && ySrcCur < srcHeight - 1) {
4327
0
    Guchar *t = tmpBuf0;
4328
0
    tmpBuf0 = tmpBuf1;
4329
0
    tmpBuf1 = t;
4330
0
    (*src)(srcData, tmpBuf1);
4331
0
    ++ySrcCur;
4332
0
  }
4333
0
  Guchar *mask0 = tmpBuf0;
4334
0
  Guchar *mask1 = tmpBuf1;
4335
0
  if (y0 < 0) {
4336
0
    y0 = 0;
4337
0
    mask1 = mask0;
4338
0
  }
4339
0
  if (y1 >= srcHeight) {
4340
0
    y1 = srcHeight - 1;
4341
0
    mask0 = mask1;
4342
0
  }
4343
0
  ++yScaledCur;
4344
4345
  //--- horiz downscale
4346
0
  int acc;
4347
0
  int xt = 0;
4348
0
  int unscaledIdx = 0;
4349
0
  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
4350
0
    int xStep = xp;
4351
0
    xt += xq;
4352
0
    if (xt >= scaledWidth) {
4353
0
      xt -= scaledWidth;
4354
0
      ++xStep;
4355
0
    }
4356
4357
0
    acc = 0;
4358
0
    for (int i = 0; i < xStep; ++i) {
4359
0
      acc += (int)(vs0 * (int)mask0[unscaledIdx] +
4360
0
       vs1 * (int)mask1[unscaledIdx]);
4361
0
      ++unscaledIdx;
4362
0
    }
4363
0
    line[scaledIdx] = (Guchar)((255 * acc) / xStep);
4364
0
  }
4365
0
}
4366
4367
0
void ImageMaskScaler::vertUpscaleHorizDownscaleThresh() {
4368
  //--- vert upscale
4369
0
  if (yn == 0) {
4370
0
    yn = yp;
4371
0
    yt += yq;
4372
0
    if (yt >= srcHeight) {
4373
0
      yt -= srcHeight;
4374
0
      ++yn;
4375
0
    }
4376
0
    (*src)(srcData, tmpBuf0);
4377
0
  }
4378
0
  --yn;
4379
4380
  //--- horiz downscale
4381
0
  int acc;
4382
0
  int xt = 0;
4383
0
  int unscaledIdx = 0;
4384
0
  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
4385
0
    int xStep = xp;
4386
0
    xt += xq;
4387
0
    if (xt >= scaledWidth) {
4388
0
      xt -= scaledWidth;
4389
0
      ++xStep;
4390
0
    }
4391
4392
0
    acc = 0;
4393
0
    for (int i = 0; i < xStep; ++i) {
4394
0
      acc += tmpBuf0[unscaledIdx];
4395
0
      ++unscaledIdx;
4396
0
    }
4397
0
    line[scaledIdx] = acc > (xStep >> 1) ? (Guchar)255 : (Guchar)0;
4398
0
  }
4399
0
}
4400
4401
0
void ImageMaskScaler::vertUpscaleHorizUpscaleNoInterp() {
4402
  //--- vert upscale
4403
0
  if (yn == 0) {
4404
0
    yn = yp;
4405
0
    yt += yq;
4406
0
    if (yt >= srcHeight) {
4407
0
      yt -= srcHeight;
4408
0
      ++yn;
4409
0
    }
4410
0
    (*src)(srcData, tmpBuf0);
4411
0
  }
4412
0
  --yn;
4413
4414
  //--- horiz upscale
4415
0
  int xt = 0;
4416
0
  int scaledIdx = 0;
4417
0
  for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
4418
0
    int xStep = xp;
4419
0
    xt += xq;
4420
0
    if (xt >= srcWidth) {
4421
0
      xt -= srcWidth;
4422
0
      ++xStep;
4423
0
    }
4424
0
    Guchar buf = (Guchar)(255 * tmpBuf0[srcIdx]);
4425
0
    for (int i = 0; i < xStep; ++i) {
4426
0
      line[scaledIdx] = buf;
4427
0
      ++scaledIdx;
4428
0
    }
4429
0
  }
4430
0
}
4431
4432
0
void ImageMaskScaler::vertUpscaleHorizUpscaleInterp() {
4433
  //--- vert upscale
4434
0
  if (ySrcCur == 0) {
4435
0
    (*src)(srcData, tmpBuf0);
4436
0
    (*src)(srcData, tmpBuf1);
4437
0
    ySrcCur = 1;
4438
0
  }
4439
0
  SplashCoord ys = ((SplashCoord)yScaledCur + 0.5) * yInvScale;
4440
0
  int y0 = splashFloor(ys - 0.5);
4441
0
  int y1 = y0 + 1;
4442
0
  SplashCoord vs0 = (SplashCoord)255 * ((SplashCoord)y1 + 0.5 - ys);
4443
0
  SplashCoord vs1 = (SplashCoord)255 - vs0;
4444
0
  if (y1 > ySrcCur && ySrcCur < srcHeight - 1) {
4445
0
    Guchar *t = tmpBuf0;
4446
0
    tmpBuf0 = tmpBuf1;
4447
0
    tmpBuf1 = t;
4448
0
    (*src)(srcData, tmpBuf1);
4449
0
    ++ySrcCur;
4450
0
  }
4451
0
  Guchar *mask0 = tmpBuf0;
4452
0
  Guchar *mask1 = tmpBuf1;
4453
0
  if (y0 < 0) {
4454
0
    y0 = 0;
4455
0
    mask1 = mask0;
4456
0
  }
4457
0
  if (y1 >= srcHeight) {
4458
0
    y1 = srcHeight - 1;
4459
0
    mask0 = mask1;
4460
0
  }
4461
0
  ++yScaledCur;
4462
0
  for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
4463
0
    tmpBuf2[srcIdx] = (Guchar)(int)(vs0 * (int)mask0[srcIdx] +
4464
0
            vs1 * (int)mask1[srcIdx]);
4465
0
  }
4466
4467
  //--- horiz upscale
4468
0
  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
4469
0
    SplashCoord xs = ((SplashCoord)scaledIdx + 0.5) * xInvScale;
4470
0
    int x0 = splashFloor(xs - 0.5);
4471
0
    int x1 = x0 + 1;
4472
0
    SplashCoord hs0 = (SplashCoord)x1 + 0.5 - xs;
4473
0
    SplashCoord hs1 = (SplashCoord)1 - hs0;
4474
0
    if (x0 < 0) {
4475
0
      x0 = 0;
4476
0
    }
4477
0
    if (x1 >= srcWidth) {
4478
0
      x1 = srcWidth - 1;
4479
0
    }
4480
0
    line[scaledIdx] = (Guchar)(int)(hs0 * (int)tmpBuf2[x0] +
4481
0
            hs1 * (int)tmpBuf2[x1]);
4482
0
  }
4483
0
}
4484
4485
//------------------------------------------------------------------------
4486
// Splash
4487
//------------------------------------------------------------------------
4488
4489
Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
4490
         SplashImageCache *imageCacheA,
4491
0
         SplashScreenParams *screenParams) {
4492
0
  bitmap = bitmapA;
4493
0
  bitmapComps = splashColorModeNComps[bitmap->mode];
4494
0
  vectorAntialias = vectorAntialiasA;
4495
0
  inShading = gFalse;
4496
0
  state = new SplashState(bitmap->width, bitmap->height, vectorAntialias,
4497
0
        screenParams);
4498
0
  scanBuf = (Guchar *)gmalloc(bitmap->width);
4499
0
  if (bitmap->mode == splashModeMono1) {
4500
0
    scanBuf2 = (Guchar *)gmalloc(bitmap->width);
4501
0
  } else {
4502
0
    scanBuf2 = NULL;
4503
0
  }
4504
0
  groupBackBitmap = NULL;
4505
0
  groupDestInitMode = splashGroupDestPreInit;
4506
0
  overprintMaskBitmap = NULL;
4507
0
  minLineWidth = 0;
4508
0
  clearModRegion();
4509
0
  debugMode = gFalse;
4510
4511
0
  if (imageCacheA) {
4512
0
    imageCache = imageCacheA;
4513
0
    imageCache->incRefCount();
4514
0
  } else {
4515
0
    imageCache = new SplashImageCache();
4516
0
  }
4517
0
}
4518
4519
Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
4520
0
         SplashImageCache *imageCacheA, SplashScreen *screenA) {
4521
0
  bitmap = bitmapA;
4522
0
  bitmapComps = splashColorModeNComps[bitmap->mode];
4523
0
  vectorAntialias = vectorAntialiasA;
4524
0
  inShading = gFalse;
4525
0
  state = new SplashState(bitmap->width, bitmap->height, vectorAntialias,
4526
0
        screenA);
4527
0
  scanBuf = (Guchar *)gmalloc(bitmap->width);
4528
0
  if (bitmap->mode == splashModeMono1) {
4529
0
    scanBuf2 = (Guchar *)gmalloc(bitmap->width);
4530
0
  } else {
4531
0
    scanBuf2 = NULL;
4532
0
  }
4533
0
  groupBackBitmap = NULL;
4534
0
  groupDestInitMode = splashGroupDestPreInit;
4535
0
  overprintMaskBitmap = NULL;
4536
0
  minLineWidth = 0;
4537
0
  clearModRegion();
4538
0
  debugMode = gFalse;
4539
4540
0
  if (imageCacheA) {
4541
0
    imageCache = imageCacheA;
4542
0
    imageCache->incRefCount();
4543
0
  } else {
4544
0
    imageCache = new SplashImageCache();
4545
0
  }
4546
0
}
4547
4548
0
Splash::~Splash() {
4549
0
  imageCache->decRefCount();
4550
4551
0
  while (state->next) {
4552
0
    restoreState();
4553
0
  }
4554
0
  delete state;
4555
0
  gfree(scanBuf);
4556
0
  gfree(scanBuf2);
4557
0
}
4558
4559
//------------------------------------------------------------------------
4560
// state read
4561
//------------------------------------------------------------------------
4562
4563
0
SplashCoord *Splash::getMatrix() {
4564
0
  return state->matrix;
4565
0
}
4566
4567
0
SplashPattern *Splash::getStrokePattern() {
4568
0
  return state->strokePattern;
4569
0
}
4570
4571
0
SplashPattern *Splash::getFillPattern() {
4572
0
  return state->fillPattern;
4573
0
}
4574
4575
0
SplashScreen *Splash::getScreen() {
4576
0
  return state->screen;
4577
0
}
4578
4579
0
SplashBlendFunc Splash::getBlendFunc() {
4580
0
  return state->blendFunc;
4581
0
}
4582
4583
0
SplashCoord Splash::getStrokeAlpha() {
4584
0
  return state->strokeAlpha;
4585
0
}
4586
4587
0
SplashCoord Splash::getFillAlpha() {
4588
0
  return state->fillAlpha;
4589
0
}
4590
4591
0
SplashCoord Splash::getLineWidth() {
4592
0
  return state->lineWidth;
4593
0
}
4594
4595
0
int Splash::getLineCap() {
4596
0
  return state->lineCap;
4597
0
}
4598
4599
0
int Splash::getLineJoin() {
4600
0
  return state->lineJoin;
4601
0
}
4602
4603
0
SplashCoord Splash::getMiterLimit() {
4604
0
  return state->miterLimit;
4605
0
}
4606
4607
0
SplashCoord Splash::getFlatness() {
4608
0
  return state->flatness;
4609
0
}
4610
4611
0
SplashCoord *Splash::getLineDash() {
4612
0
  return state->lineDash;
4613
0
}
4614
4615
0
int Splash::getLineDashLength() {
4616
0
  return state->lineDashLength;
4617
0
}
4618
4619
0
SplashCoord Splash::getLineDashPhase() {
4620
0
  return state->lineDashPhase;
4621
0
}
4622
4623
0
SplashStrokeAdjustMode Splash::getStrokeAdjust() {
4624
0
  return state->strokeAdjust;
4625
0
}
4626
4627
0
SplashClip *Splash::getClip() {
4628
0
  return state->clip;
4629
0
}
4630
4631
0
SplashBitmap *Splash::getSoftMask() {
4632
0
  return state->softMask;
4633
0
}
4634
4635
0
GBool Splash::getInNonIsolatedGroup() {
4636
0
  return state->inNonIsolatedGroup;
4637
0
}
4638
4639
0
GBool Splash::getInKnockoutGroup() {
4640
0
  return state->inKnockoutGroup;
4641
0
}
4642
4643
//------------------------------------------------------------------------
4644
// state write
4645
//------------------------------------------------------------------------
4646
4647
0
void Splash::setMatrix(SplashCoord *matrix) {
4648
0
  memcpy(state->matrix, matrix, 6 * sizeof(SplashCoord));
4649
0
}
4650
4651
0
void Splash::setStrokePattern(SplashPattern *strokePattern) {
4652
0
  state->setStrokePattern(strokePattern);
4653
0
}
4654
4655
0
void Splash::setFillPattern(SplashPattern *fillPattern) {
4656
0
  state->setFillPattern(fillPattern);
4657
0
}
4658
4659
0
void Splash::setScreen(SplashScreen *screen) {
4660
0
  state->setScreen(screen);
4661
0
}
4662
4663
0
void Splash::setBlendFunc(SplashBlendFunc func) {
4664
0
  state->blendFunc = func;
4665
0
}
4666
4667
0
void Splash::setStrokeAlpha(SplashCoord alpha) {
4668
0
  state->strokeAlpha = alpha;
4669
0
}
4670
4671
0
void Splash::setFillAlpha(SplashCoord alpha) {
4672
0
  state->fillAlpha = alpha;
4673
0
}
4674
4675
0
void Splash::setLineWidth(SplashCoord lineWidth) {
4676
0
  state->lineWidth = lineWidth;
4677
0
}
4678
4679
0
void Splash::setLineCap(int lineCap) {
4680
0
  if (lineCap >= 0 && lineCap <= 2) {
4681
0
    state->lineCap = lineCap;
4682
0
  } else {
4683
0
    state->lineCap = 0;
4684
0
  }
4685
0
}
4686
4687
0
void Splash::setLineJoin(int lineJoin) {
4688
0
  if (lineJoin >= 0 && lineJoin <= 2) {
4689
0
    state->lineJoin = lineJoin;
4690
0
  } else {
4691
0
    state->lineJoin = 0;
4692
0
  }
4693
0
}
4694
4695
0
void Splash::setMiterLimit(SplashCoord miterLimit) {
4696
0
  state->miterLimit = miterLimit;
4697
0
}
4698
4699
0
void Splash::setFlatness(SplashCoord flatness) {
4700
0
  if (flatness < 1) {
4701
0
    state->flatness = 1;
4702
0
  } else {
4703
0
    state->flatness = flatness;
4704
0
  }
4705
0
}
4706
4707
void Splash::setLineDash(SplashCoord *lineDash, int lineDashLength,
4708
0
       SplashCoord lineDashPhase) {
4709
0
  state->setLineDash(lineDash, lineDashLength, lineDashPhase);
4710
0
}
4711
4712
0
void Splash::setStrokeAdjust(SplashStrokeAdjustMode strokeAdjust) {
4713
0
  state->strokeAdjust = strokeAdjust;
4714
0
}
4715
4716
void Splash::clipResetToRect(SplashCoord x0, SplashCoord y0,
4717
0
           SplashCoord x1, SplashCoord y1) {
4718
0
  state->clipResetToRect(x0, y0, x1, y1);
4719
0
}
4720
4721
SplashError Splash::clipToRect(SplashCoord x0, SplashCoord y0,
4722
0
             SplashCoord x1, SplashCoord y1) {
4723
0
  return state->clipToRect(x0, y0, x1, y1);
4724
0
}
4725
4726
0
SplashError Splash::clipToPath(SplashPath *path, GBool eo) {
4727
0
  return state->clipToPath(path, eo);
4728
0
}
4729
4730
0
void Splash::setSoftMask(SplashBitmap *softMask, GBool deleteBitmap) {
4731
0
  state->setSoftMask(softMask, deleteBitmap);
4732
0
}
4733
4734
void Splash::setInTransparencyGroup(SplashBitmap *groupBackBitmapA,
4735
            int groupBackXA, int groupBackYA,
4736
            SplashGroupDestInitMode groupDestInitModeA,
4737
0
            GBool nonIsolated, GBool knockout) {
4738
0
  groupBackBitmap = groupBackBitmapA;
4739
0
  groupBackX = groupBackXA;
4740
0
  groupBackY = groupBackYA;
4741
0
  groupDestInitMode = groupDestInitModeA;
4742
0
  groupDestInitYMin = 1;
4743
0
  groupDestInitYMax = 0;
4744
0
  state->inNonIsolatedGroup = nonIsolated;
4745
0
  state->inKnockoutGroup = knockout;
4746
0
}
4747
4748
0
void Splash::forceDeferredInit(int y, int h) {
4749
0
  useDestRow(y);
4750
0
  useDestRow(y + h - 1);
4751
0
}
4752
4753
// Check that alpha is 0 in the specified rectangle.
4754
// NB: This doesn't work correctly in a non-isolated group, because
4755
//     the rasterizer temporarily stores alpha_g instead of alpha.
4756
0
GBool Splash::checkTransparentRect(int x, int y, int w, int h) {
4757
0
  if (state->inNonIsolatedGroup) {
4758
0
    return gFalse;
4759
0
  }
4760
4761
4762
0
  if (!bitmap->alpha) {
4763
0
    return gFalse;
4764
0
  }
4765
0
  int yy0, yy1;
4766
0
  if (groupDestInitMode == splashGroupDestPreInit) {
4767
0
    yy0 = y;
4768
0
    yy1 = y + h - 1;
4769
0
  } else {
4770
    // both splashGroupDestInitZero and splashGroupDestInitCopy set
4771
    // alpha to zero, so anything outside of groupDestInit[YMin,YMax]
4772
    // will have alpha=0
4773
0
    yy0 = (y > groupDestInitYMin) ? y : groupDestInitYMin;
4774
0
    yy1 = (y + h - 1 < groupDestInitYMax) ? y + h - 1 : groupDestInitYMax;
4775
0
  }
4776
0
  Guchar *alphaP = &bitmap->alpha[yy0 * bitmap->alphaRowSize + x];
4777
0
  for (int yy = yy0; yy <= yy1; ++yy) {
4778
0
    for (int xx = 0; xx < w; ++xx) {
4779
0
      if (alphaP[xx] != 0) {
4780
0
  return gFalse;
4781
0
      }
4782
0
    }
4783
0
    alphaP += bitmap->getAlphaRowSize();
4784
0
  }
4785
0
  return gTrue;
4786
0
}
4787
4788
void Splash::setTransfer(Guchar *red, Guchar *green, Guchar *blue,
4789
0
       Guchar *gray) {
4790
0
  state->setTransfer(red, green, blue, gray);
4791
0
}
4792
4793
0
void Splash::setOverprintMask(Guint overprintMask) {
4794
0
  state->overprintMask = overprintMask;
4795
0
}
4796
4797
4798
0
void Splash::setEnablePathSimplification(GBool en) {
4799
0
  state->enablePathSimplification = en;
4800
0
}
4801
4802
//------------------------------------------------------------------------
4803
// state save/restore
4804
//------------------------------------------------------------------------
4805
4806
0
void Splash::saveState() {
4807
0
  SplashState *newState;
4808
4809
0
  newState = state->copy();
4810
0
  newState->next = state;
4811
0
  state = newState;
4812
0
}
4813
4814
0
SplashError Splash::restoreState() {
4815
0
  SplashState *oldState;
4816
4817
0
  if (!state->next) {
4818
0
    return splashErrNoSave;
4819
0
  }
4820
0
  oldState = state;
4821
0
  state = state->next;
4822
0
  delete oldState;
4823
0
  return splashOk;
4824
0
}
4825
4826
//------------------------------------------------------------------------
4827
// drawing operations
4828
//------------------------------------------------------------------------
4829
4830
0
void Splash::clear(SplashColorPtr color, Guchar alpha) {
4831
0
  SplashColorPtr row, p;
4832
0
  Guchar mono;
4833
0
  int x, y;
4834
4835
0
  switch (bitmap->mode) {
4836
0
  case splashModeMono1:
4837
0
    mono = (color[0] & 0x80) ? 0xff : 0x00;
4838
0
    if (bitmap->rowSize < 0) {
4839
0
      memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
4840
0
       mono, -bitmap->rowSize * bitmap->height);
4841
0
    } else {
4842
0
      memset(bitmap->data, mono, bitmap->rowSize * bitmap->height);
4843
0
    }
4844
0
    break;
4845
0
  case splashModeMono8:
4846
0
    if (bitmap->rowSize < 0) {
4847
0
      memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
4848
0
       color[0], -bitmap->rowSize * bitmap->height);
4849
0
    } else {
4850
0
      memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
4851
0
    }
4852
0
    break;
4853
0
  case splashModeRGB8:
4854
0
    if (color[0] == color[1] && color[1] == color[2]) {
4855
0
      if (bitmap->rowSize < 0) {
4856
0
  memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
4857
0
         color[0], -bitmap->rowSize * bitmap->height);
4858
0
      } else {
4859
0
  memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
4860
0
      }
4861
0
    } else {
4862
0
      row = bitmap->data;
4863
0
      for (y = 0; y < bitmap->height; ++y) {
4864
0
  p = row;
4865
0
  for (x = 0; x < bitmap->width; ++x) {
4866
0
    *p++ = color[0];
4867
0
    *p++ = color[1];
4868
0
    *p++ = color[2];
4869
0
  }
4870
0
  row += bitmap->rowSize;
4871
0
      }
4872
0
    }
4873
0
    break;
4874
0
  case splashModeBGR8:
4875
0
    if (color[0] == color[1] && color[1] == color[2]) {
4876
0
      if (bitmap->rowSize < 0) {
4877
0
  memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
4878
0
         color[0], -bitmap->rowSize * bitmap->height);
4879
0
      } else {
4880
0
  memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
4881
0
      }
4882
0
    } else {
4883
0
      row = bitmap->data;
4884
0
      for (y = 0; y < bitmap->height; ++y) {
4885
0
  p = row;
4886
0
  for (x = 0; x < bitmap->width; ++x) {
4887
0
    *p++ = color[2];
4888
0
    *p++ = color[1];
4889
0
    *p++ = color[0];
4890
0
  }
4891
0
  row += bitmap->rowSize;
4892
0
      }
4893
0
    }
4894
0
    break;
4895
0
#if SPLASH_CMYK
4896
0
  case splashModeCMYK8:
4897
0
    if (color[0] == color[1] && color[1] == color[2] && color[2] == color[3]) {
4898
0
      if (bitmap->rowSize < 0) {
4899
0
  memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
4900
0
         color[0], -bitmap->rowSize * bitmap->height);
4901
0
      } else {
4902
0
  memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
4903
0
      }
4904
0
    } else {
4905
0
      row = bitmap->data;
4906
0
      for (y = 0; y < bitmap->height; ++y) {
4907
0
  p = row;
4908
0
  for (x = 0; x < bitmap->width; ++x) {
4909
0
    *p++ = color[0];
4910
0
    *p++ = color[1];
4911
0
    *p++ = color[2];
4912
0
    *p++ = color[3];
4913
0
  }
4914
0
  row += bitmap->rowSize;
4915
0
      }
4916
0
    }
4917
0
    break;
4918
0
#endif
4919
0
  }
4920
4921
0
  if (bitmap->alpha) {
4922
0
    memset(bitmap->alpha, alpha, bitmap->alphaRowSize * bitmap->height);
4923
0
  }
4924
4925
0
  updateModX(0);
4926
0
  updateModY(0);
4927
0
  updateModX(bitmap->width - 1);
4928
0
  updateModY(bitmap->height - 1);
4929
0
}
4930
4931
0
SplashError Splash::stroke(SplashPath *path) {
4932
0
  SplashPath *path2, *dPath;
4933
0
  SplashCoord t0, t1, t2, t3, w, w2, lineDashMax, lineDashTotal;
4934
0
  int lineCap, lineJoin, i;
4935
4936
0
  if (debugMode) {
4937
0
    printf("stroke [dash:%d] [width:%.2f]:\n",
4938
0
     state->lineDashLength, (double)state->lineWidth);
4939
0
    dumpPath(path);
4940
0
  }
4941
0
  opClipRes = splashClipAllOutside;
4942
0
  if (path->length == 0) {
4943
0
    return splashErrEmptyPath;
4944
0
  }
4945
0
  path2 = flattenPath(path, state->matrix, state->flatness);
4946
4947
  // Compute an approximation of the transformed line width.
4948
  // Given a CTM of [m0 m1],
4949
  //                [m2 m3]
4950
  // if |m0|*|m3| >= |m1|*|m2| then use min{|m0|,|m3|}, else
4951
  // use min{|m1|,|m2|}.
4952
  // This handles the common cases -- [s 0   ] and [0    s] --
4953
  //                                  [0 +/-s]     [+/-s 0]
4954
  // well, and still does something reasonable for the uncommon
4955
  // case transforms.
4956
0
  t0 = splashAbs(state->matrix[0]);
4957
0
  t1 = splashAbs(state->matrix[1]);
4958
0
  t2 = splashAbs(state->matrix[2]);
4959
0
  t3 = splashAbs(state->matrix[3]);
4960
0
  if (t0 * t3 >= t1 * t2) {
4961
0
    w = (t0 < t3) ? t0 : t3;
4962
0
  } else {
4963
0
    w = (t1 < t2) ? t1 : t2;
4964
0
  }
4965
0
  w2 = w * state->lineWidth;
4966
4967
  // construct the dashed path
4968
0
  if (state->lineDashLength > 0) {
4969
4970
    // check the maximum transformed dash element length (using the
4971
    // same approximation as for line width) -- if it's less than 0.1
4972
    // pixel, don't apply the dash pattern; this avoids a huge
4973
    // performance/memory hit with PDF files that use absurd dash
4974
    // patterns like [0.0007 0.0003]
4975
0
    lineDashTotal = 0;
4976
0
    lineDashMax = 0;
4977
0
    for (i = 0; i < state->lineDashLength; ++i) {
4978
0
      lineDashTotal += state->lineDash[i];
4979
0
      if (state->lineDash[i] > lineDashMax) {
4980
0
  lineDashMax = state->lineDash[i];
4981
0
      }
4982
0
    }
4983
    // Acrobat simply draws nothing if the dash array is [0]
4984
0
    if (lineDashTotal == 0) {
4985
0
      delete path2;
4986
0
      return splashOk;
4987
0
    }
4988
0
    if (w * lineDashMax > 0.1) {
4989
4990
0
      dPath = makeDashedPath(path2);
4991
0
      delete path2;
4992
0
      path2 = dPath;
4993
0
      if (path2->length == 0) {
4994
0
  delete path2;
4995
0
  return splashErrEmptyPath;
4996
0
      }
4997
0
    }
4998
0
  }
4999
5000
  // round caps on narrow lines look bad, and can't be
5001
  // stroke-adjusted, so use projecting caps instead (but we can't do
5002
  // this if there are zero-length dashes or segments, because those
5003
  // turn into round dots)
5004
0
  lineCap = state->lineCap;
5005
0
  lineJoin = state->lineJoin;
5006
0
  if (state->strokeAdjust == splashStrokeAdjustCAD &&
5007
0
      w2 < 3.5) {
5008
0
    if (lineCap == splashLineCapRound &&
5009
0
  !state->lineDashContainsZeroLengthDashes() &&
5010
0
  !path->containsZeroLengthSubpaths()) {
5011
0
      lineCap = splashLineCapProjecting;
5012
0
    }
5013
0
    if (lineJoin == splashLineJoinRound) {
5014
0
      lineJoin = splashLineJoinBevel;
5015
0
    }
5016
0
  }
5017
5018
  // if there is a min line width set, and the transformed line width
5019
  // is smaller, use the min line width
5020
0
  if (w > 0 && w2 < minLineWidth) {
5021
0
    strokeWide(path2, minLineWidth / w, splashLineCapButt, splashLineJoinBevel);
5022
0
  } else if (bitmap->mode == splashModeMono1 || !vectorAntialias) {
5023
    // in monochrome mode or if antialiasing is disabled, use 0-width
5024
    // lines for any transformed line width <= 1 -- lines less than 1
5025
    // pixel wide look too fat without antialiasing
5026
0
    if (w2 < 1.001) {
5027
0
      strokeNarrow(path2);
5028
0
    } else {
5029
0
      strokeWide(path2, state->lineWidth, lineCap, lineJoin);
5030
0
    }
5031
0
  } else {
5032
    // in gray and color modes, only use 0-width lines if the line
5033
    // width is explicitly set to 0
5034
0
    if (state->lineWidth == 0) {
5035
0
      strokeNarrow(path2);
5036
0
    } else {
5037
0
      strokeWide(path2, state->lineWidth, lineCap, lineJoin);
5038
0
    }
5039
0
  }
5040
5041
0
  delete path2;
5042
0
  return splashOk;
5043
0
}
5044
5045
0
void Splash::strokeNarrow(SplashPath *path) {
5046
0
  SplashPipe pipe;
5047
0
  SplashXPath *xPath;
5048
0
  SplashXPathSeg *seg;
5049
0
  int x0, x1, y0, y1, xa, xb, y;
5050
0
  SplashCoord dxdy;
5051
0
  SplashClipResult clipRes;
5052
0
  int nClipRes[3];
5053
0
  int i;
5054
5055
0
  nClipRes[0] = nClipRes[1] = nClipRes[2] = 0;
5056
5057
0
  xPath = new SplashXPath(path, state->matrix, state->flatness, gFalse,
5058
0
        state->enablePathSimplification,
5059
0
        state->strokeAdjust);
5060
5061
0
  pipeInit(&pipe, state->strokePattern,
5062
0
     (Guchar)splashRound(state->strokeAlpha * 255),
5063
0
     gTrue, gFalse);
5064
5065
0
  for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) {
5066
0
    if (seg->y0 <= seg->y1) {
5067
0
      y0 = splashFloor(seg->y0);
5068
0
      y1 = splashFloor(seg->y1);
5069
0
      x0 = splashFloor(seg->x0);
5070
0
      x1 = splashFloor(seg->x1);
5071
0
    } else {
5072
0
      y0 = splashFloor(seg->y1);
5073
0
      y1 = splashFloor(seg->y0);
5074
0
      x0 = splashFloor(seg->x1);
5075
0
      x1 = splashFloor(seg->x0);
5076
0
    }
5077
0
    if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0,
5078
0
           x0 <= x1 ? x1 : x0, y1,
5079
0
           state->strokeAdjust))
5080
0
  != splashClipAllOutside) {
5081
0
      if (y0 == y1) {
5082
0
  if (x0 <= x1) {
5083
0
    drawStrokeSpan(&pipe, x0, x1, y0, clipRes == splashClipAllInside);
5084
0
  } else {
5085
0
    drawStrokeSpan(&pipe, x1, x0, y0, clipRes == splashClipAllInside);
5086
0
  }
5087
0
      } else {
5088
0
  dxdy = seg->dxdy;
5089
0
  y = state->clip->getYMinI(state->strokeAdjust);
5090
0
  if (y0 < y) {
5091
0
    y0 = y;
5092
0
    x0 = splashFloor(seg->x0 + ((SplashCoord)y0 - seg->y0) * dxdy);
5093
0
  }
5094
0
  y = state->clip->getYMaxI(state->strokeAdjust);
5095
0
  if (y1 > y) {
5096
0
    y1 = y;
5097
0
    x1 = splashFloor(seg->x0 + ((SplashCoord)y1 - seg->y0) * dxdy);
5098
0
  }
5099
0
  if (x0 <= x1) {
5100
0
    xa = x0;
5101
0
    for (y = y0; y <= y1; ++y) {
5102
0
      if (y < y1) {
5103
0
        xb = splashFloor(seg->x0 +
5104
0
             ((SplashCoord)y + 1 - seg->y0) * dxdy);
5105
0
      } else {
5106
0
        xb = x1 + 1;
5107
0
      }
5108
0
      if (xa == xb) {
5109
0
        drawStrokeSpan(&pipe, xa, xa, y, clipRes == splashClipAllInside);
5110
0
      } else {
5111
0
        drawStrokeSpan(&pipe, xa, xb - 1, y,
5112
0
           clipRes == splashClipAllInside);
5113
0
      }
5114
0
      xa = xb;
5115
0
    }
5116
0
  } else {
5117
0
    xa = x0;
5118
0
    for (y = y0; y <= y1; ++y) {
5119
0
      if (y < y1) {
5120
0
        xb = splashFloor(seg->x0 +
5121
0
             ((SplashCoord)y + 1 - seg->y0) * dxdy);
5122
0
      } else {
5123
0
        xb = x1 - 1;
5124
0
      }
5125
0
      if (xa == xb) {
5126
0
        drawStrokeSpan(&pipe, xa, xa, y, clipRes == splashClipAllInside);
5127
0
      } else {
5128
0
        drawStrokeSpan(&pipe, xb + 1, xa, y,
5129
0
           clipRes == splashClipAllInside);
5130
0
      }
5131
0
      xa = xb;
5132
0
    }
5133
0
  }
5134
0
      }
5135
0
    }
5136
0
    ++nClipRes[clipRes];
5137
0
  }
5138
0
  if (nClipRes[splashClipPartial] ||
5139
0
      (nClipRes[splashClipAllInside] && nClipRes[splashClipAllOutside])) {
5140
0
    opClipRes = splashClipPartial;
5141
0
  } else if (nClipRes[splashClipAllInside]) {
5142
0
    opClipRes = splashClipAllInside;
5143
0
  } else {
5144
0
    opClipRes = splashClipAllOutside;
5145
0
  }
5146
5147
0
  delete xPath;
5148
0
}
5149
5150
void Splash::drawStrokeSpan(SplashPipe *pipe, int x0, int x1, int y,
5151
0
          GBool noClip) {
5152
0
  int x;
5153
5154
0
  x = state->clip->getXMinI(state->strokeAdjust);
5155
0
  if (x > x0) {
5156
0
    x0 = x;
5157
0
  }
5158
0
  x = state->clip->getXMaxI(state->strokeAdjust);
5159
0
  if (x < x1) {
5160
0
    x1 = x;
5161
0
  }
5162
0
  if (x0 > x1) {
5163
0
    return;
5164
0
  }
5165
0
  for (x = x0; x <= x1; ++x) {
5166
0
    scanBuf[x] = 0xff;
5167
0
  }
5168
0
  if (!noClip) {
5169
0
    if (!state->clip->clipSpanBinary(scanBuf, y, x0, x1, state->strokeAdjust)) {
5170
0
      return;
5171
0
    }
5172
0
  }
5173
0
  (this->*pipe->run)(pipe, x0, x1, y, scanBuf + x0, NULL);
5174
0
}
5175
5176
void Splash::strokeWide(SplashPath *path, SplashCoord w,
5177
0
      int lineCap, int lineJoin) {
5178
0
  SplashPath *path2;
5179
5180
0
  path2 = makeStrokePath(path, w, lineCap, lineJoin, gFalse);
5181
0
  fillWithPattern(path2, gFalse, state->strokePattern, state->strokeAlpha);
5182
0
  delete path2;
5183
0
}
5184
5185
SplashPath *Splash::flattenPath(SplashPath *path, SplashCoord *matrix,
5186
0
        SplashCoord flatness) {
5187
0
  SplashPath *fPath;
5188
0
  SplashCoord flatness2;
5189
0
  Guchar flag;
5190
0
  int i;
5191
5192
0
  fPath = new SplashPath();
5193
#if USE_FIXEDPOINT
5194
  flatness2 = flatness;
5195
#else
5196
0
  flatness2 = flatness * flatness;
5197
0
#endif
5198
0
  i = 0;
5199
0
  while (i < path->length) {
5200
0
    flag = path->flags[i];
5201
0
    if (flag & splashPathFirst) {
5202
0
      fPath->moveTo(path->pts[i].x, path->pts[i].y);
5203
0
      ++i;
5204
0
    } else {
5205
0
      if (flag & splashPathCurve) {
5206
0
  flattenCurve(path->pts[i-1].x, path->pts[i-1].y,
5207
0
         path->pts[i  ].x, path->pts[i  ].y,
5208
0
         path->pts[i+1].x, path->pts[i+1].y,
5209
0
         path->pts[i+2].x, path->pts[i+2].y,
5210
0
         matrix, flatness2, fPath);
5211
0
  i += 3;
5212
0
      } else {
5213
0
  fPath->lineTo(path->pts[i].x, path->pts[i].y);
5214
0
  ++i;
5215
0
      }
5216
0
      if (path->flags[i-1] & splashPathClosed) {
5217
0
  fPath->close();
5218
0
      }
5219
0
    }
5220
0
  }
5221
0
  return fPath;
5222
0
}
5223
5224
void Splash::flattenCurve(SplashCoord x0, SplashCoord y0,
5225
        SplashCoord x1, SplashCoord y1,
5226
        SplashCoord x2, SplashCoord y2,
5227
        SplashCoord x3, SplashCoord y3,
5228
        SplashCoord *matrix, SplashCoord flatness2,
5229
0
        SplashPath *fPath) {
5230
0
  SplashCoord cx[splashMaxCurveSplits + 1][3];
5231
0
  SplashCoord cy[splashMaxCurveSplits + 1][3];
5232
0
  int cNext[splashMaxCurveSplits + 1];
5233
0
  SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh;
5234
0
  SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh;
5235
0
  SplashCoord dx, dy, mx, my, tx, ty, d1, d2;
5236
0
  int p1, p2, p3;
5237
5238
  // initial segment
5239
0
  p1 = 0;
5240
0
  p2 = splashMaxCurveSplits;
5241
0
  cx[p1][0] = x0;  cy[p1][0] = y0;
5242
0
  cx[p1][1] = x1;  cy[p1][1] = y1;
5243
0
  cx[p1][2] = x2;  cy[p1][2] = y2;
5244
0
  cx[p2][0] = x3;  cy[p2][0] = y3;
5245
0
  cNext[p1] = p2;
5246
5247
0
  while (p1 < splashMaxCurveSplits) {
5248
5249
    // get the next segment
5250
0
    xl0 = cx[p1][0];  yl0 = cy[p1][0];
5251
0
    xx1 = cx[p1][1];  yy1 = cy[p1][1];
5252
0
    xx2 = cx[p1][2];  yy2 = cy[p1][2];
5253
0
    p2 = cNext[p1];
5254
0
    xr3 = cx[p2][0];  yr3 = cy[p2][0];
5255
5256
    // compute the distances (in device space) from the control points
5257
    // to the midpoint of the straight line (this is a bit of a hack,
5258
    // but it's much faster than computing the actual distances to the
5259
    // line)
5260
0
    transform(matrix, (xl0 + xr3) * 0.5, (yl0 + yr3) * 0.5, &mx, &my);
5261
0
    transform(matrix, xx1, yy1, &tx, &ty);
5262
#if USE_FIXEDPOINT
5263
    d1 = splashDist(tx, ty, mx, my);
5264
#else
5265
0
    dx = tx - mx;
5266
0
    dy = ty - my;
5267
0
    d1 = dx*dx + dy*dy;
5268
0
#endif
5269
0
    transform(matrix, xx2, yy2, &tx, &ty);
5270
#if USE_FIXEDPOINT
5271
    d2 = splashDist(tx, ty, mx, my);
5272
#else
5273
0
    dx = tx - mx;
5274
0
    dy = ty - my;
5275
0
    d2 = dx*dx + dy*dy;
5276
0
#endif
5277
5278
    // if the curve is flat enough, or no more subdivisions are
5279
    // allowed, add the straight line segment
5280
0
    if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) {
5281
0
      fPath->lineTo(xr3, yr3);
5282
0
      p1 = p2;
5283
5284
    // otherwise, subdivide the curve
5285
0
    } else {
5286
0
      xl1 = splashAvg(xl0, xx1);
5287
0
      yl1 = splashAvg(yl0, yy1);
5288
0
      xh = splashAvg(xx1, xx2);
5289
0
      yh = splashAvg(yy1, yy2);
5290
0
      xl2 = splashAvg(xl1, xh);
5291
0
      yl2 = splashAvg(yl1, yh);
5292
0
      xr2 = splashAvg(xx2, xr3);
5293
0
      yr2 = splashAvg(yy2, yr3);
5294
0
      xr1 = splashAvg(xh, xr2);
5295
0
      yr1 = splashAvg(yh, yr2);
5296
0
      xr0 = splashAvg(xl2, xr1);
5297
0
      yr0 = splashAvg(yl2, yr1);
5298
      // add the new subdivision points
5299
0
      p3 = (p1 + p2) / 2;
5300
0
      cx[p1][1] = xl1;  cy[p1][1] = yl1;
5301
0
      cx[p1][2] = xl2;  cy[p1][2] = yl2;
5302
0
      cNext[p1] = p3;
5303
0
      cx[p3][0] = xr0;  cy[p3][0] = yr0;
5304
0
      cx[p3][1] = xr1;  cy[p3][1] = yr1;
5305
0
      cx[p3][2] = xr2;  cy[p3][2] = yr2;
5306
0
      cNext[p3] = p2;
5307
0
    }
5308
0
  }
5309
0
}
5310
5311
0
SplashPath *Splash::makeDashedPath(SplashPath *path) {
5312
0
  SplashPath *dPath;
5313
0
  SplashCoord lineDashTotal;
5314
0
  SplashCoord lineDashStartPhase, lineDashDist, segLen;
5315
0
  SplashCoord x0, y0, x1, y1, xa, ya;
5316
0
  GBool lineDashStartOn, lineDashEndOn, lineDashOn, newPath;
5317
0
  int lineDashStartIdx, lineDashIdx, subpathStart, nDashes;
5318
0
  int i, j, k;
5319
5320
0
  lineDashTotal = 0;
5321
0
  for (i = 0; i < state->lineDashLength; ++i) {
5322
0
    lineDashTotal += state->lineDash[i];
5323
0
  }
5324
  // Acrobat simply draws nothing if the dash array is [0]
5325
0
  if (lineDashTotal == 0) {
5326
0
    return new SplashPath();
5327
0
  }
5328
0
  lineDashStartPhase = state->lineDashPhase;
5329
0
  if (lineDashStartPhase > lineDashTotal * 2) {
5330
0
    i = splashFloor(lineDashStartPhase / (lineDashTotal * 2));
5331
0
    lineDashStartPhase -= lineDashTotal * i * 2;
5332
0
  } else if (lineDashStartPhase < 0) {
5333
0
    i = splashCeil(-lineDashStartPhase / (lineDashTotal * 2));
5334
0
    lineDashStartPhase += lineDashTotal * i * 2;
5335
0
  }
5336
0
  i = splashFloor(lineDashStartPhase / lineDashTotal);
5337
0
  lineDashStartPhase -= (SplashCoord)i * lineDashTotal;
5338
0
  lineDashStartOn = gTrue;
5339
0
  lineDashStartIdx = 0;
5340
0
  if (lineDashStartPhase > 0) {
5341
0
    while (lineDashStartPhase >= state->lineDash[lineDashStartIdx]) {
5342
0
      lineDashStartOn = !lineDashStartOn;
5343
0
      lineDashStartPhase -= state->lineDash[lineDashStartIdx];
5344
0
      if (++lineDashStartIdx == state->lineDashLength) {
5345
0
  lineDashStartIdx = 0;
5346
0
      }
5347
0
    }
5348
0
  }
5349
5350
0
  dPath = new SplashPath();
5351
5352
  // process each subpath
5353
0
  i = 0;
5354
0
  while (i < path->length) {
5355
5356
    // find the end of the subpath
5357
0
    for (j = i;
5358
0
   j < path->length - 1 && !(path->flags[j] & splashPathLast);
5359
0
   ++j) ;
5360
5361
    // initialize the dash parameters
5362
0
    lineDashOn = lineDashStartOn;
5363
0
    lineDashEndOn = lineDashStartOn;
5364
0
    lineDashIdx = lineDashStartIdx;
5365
0
    lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase;
5366
0
    subpathStart = dPath->length;
5367
0
    nDashes = 0;
5368
5369
    // process each segment of the subpath
5370
0
    newPath = gTrue;
5371
0
    for (k = i; k < j; ++k) {
5372
5373
      // grab the segment
5374
0
      x0 = path->pts[k].x;
5375
0
      y0 = path->pts[k].y;
5376
0
      x1 = path->pts[k+1].x;
5377
0
      y1 = path->pts[k+1].y;
5378
0
      segLen = splashDist(x0, y0, x1, y1);
5379
5380
      // process the segment
5381
0
      while (segLen > 0) {
5382
5383
  // Special case for zero-length dash segments: draw a very
5384
  // short -- but not zero-length -- segment.  This ensures that
5385
  // we get the correct behavior with butt and projecting line
5386
  // caps.  The PS/PDF specs imply that zero-length segments are
5387
  // not drawn unless the line cap is round, but Acrobat and
5388
  // Ghostscript both draw very short segments (for butt caps)
5389
  // and squares (for projecting caps).
5390
0
  if (lineDashDist == 0) {
5391
0
    if (lineDashOn) {
5392
0
      if (newPath) {
5393
0
        dPath->moveTo(x0, y0);
5394
0
        newPath = gFalse;
5395
0
        ++nDashes;
5396
0
      }
5397
0
      xa = x0 + ((SplashCoord)0.001 / segLen) * (x1 - x0);
5398
0
      ya = y0 + ((SplashCoord)0.001 / segLen) * (y1 - y0);
5399
0
      dPath->lineTo(xa, ya);
5400
0
    }
5401
5402
0
  } else if (lineDashDist >= segLen) {
5403
0
    if (lineDashOn) {
5404
0
      if (newPath) {
5405
0
        dPath->moveTo(x0, y0);
5406
0
        newPath = gFalse;
5407
0
        ++nDashes;
5408
0
      }
5409
0
      dPath->lineTo(x1, y1);
5410
0
    }
5411
0
    lineDashDist -= segLen;
5412
0
    segLen = 0;
5413
5414
0
  } else {
5415
0
    xa = x0 + (lineDashDist / segLen) * (x1 - x0);
5416
0
    ya = y0 + (lineDashDist / segLen) * (y1 - y0);
5417
0
    if (lineDashOn) {
5418
0
      if (newPath) {
5419
0
        dPath->moveTo(x0, y0);
5420
0
        newPath = gFalse;
5421
0
        ++nDashes;
5422
0
      }
5423
0
      dPath->lineTo(xa, ya);
5424
0
    }
5425
0
    x0 = xa;
5426
0
    y0 = ya;
5427
0
    segLen -= lineDashDist;
5428
0
    lineDashDist = 0;
5429
0
  }
5430
5431
0
  lineDashEndOn = lineDashOn;
5432
5433
  // get the next entry in the dash array
5434
0
  if (lineDashDist <= 0) {
5435
0
    lineDashOn = !lineDashOn;
5436
0
    if (++lineDashIdx == state->lineDashLength) {
5437
0
      lineDashIdx = 0;
5438
0
    }
5439
0
    lineDashDist = state->lineDash[lineDashIdx];
5440
0
    newPath = gTrue;
5441
0
  }
5442
0
      }
5443
0
    }
5444
5445
    // in a closed subpath, where the dash pattern is "on" at both the
5446
    // start and end of the subpath, we need to merge the start and
5447
    // end to get a proper line join
5448
0
    if ((path->flags[j] & splashPathClosed) &&
5449
0
  lineDashStartOn &&
5450
0
  lineDashEndOn) {
5451
0
      if (nDashes == 1) {
5452
0
  dPath->close();
5453
0
      } else if (nDashes > 1) {
5454
0
  k = subpathStart;
5455
0
  do {
5456
0
    ++k;
5457
0
    dPath->lineTo(dPath->pts[k].x, dPath->pts[k].y);
5458
0
  } while (!(dPath->flags[k] & splashPathLast));
5459
0
  ++k;
5460
0
  memmove(&dPath->pts[subpathStart], &dPath->pts[k],
5461
0
    (dPath->length - k) * sizeof(SplashPathPoint));
5462
0
  memmove(&dPath->flags[subpathStart], &dPath->flags[k],
5463
0
    (dPath->length - k) * sizeof(Guchar));
5464
0
  dPath->length -= k - subpathStart;
5465
0
  dPath->curSubpath -= k - subpathStart;
5466
0
      }
5467
0
    }
5468
5469
0
    i = j + 1;
5470
0
  }
5471
5472
0
  return dPath;
5473
0
}
5474
5475
0
SplashError Splash::fill(SplashPath *path, GBool eo) {
5476
0
  if (debugMode) {
5477
0
    printf("fill [eo:%d]:\n", eo);
5478
0
    dumpPath(path);
5479
0
  }
5480
0
  return fillWithPattern(path, eo, state->fillPattern, state->fillAlpha);
5481
0
}
5482
5483
SplashError Splash::fillWithPattern(SplashPath *path, GBool eo,
5484
            SplashPattern *pattern,
5485
0
            SplashCoord alpha) {
5486
0
  SplashPipe pipe;
5487
0
  SplashPath *path2;
5488
0
  SplashXPath *xPath;
5489
0
  SplashXPathScanner *scanner;
5490
0
  int xMin, yMin, xMax, xMin2, xMax2, yMax, y, t;
5491
0
  SplashClipResult clipRes;
5492
5493
0
  if (path->length == 0) {
5494
0
    return splashErrEmptyPath;
5495
0
  }
5496
0
  if (pathAllOutside(path)) {
5497
0
    opClipRes = splashClipAllOutside;
5498
0
    return splashOk;
5499
0
  }
5500
5501
0
  path2 = tweakFillPath(path);
5502
5503
0
  xPath = new SplashXPath(path2, state->matrix, state->flatness, gTrue,
5504
0
        state->enablePathSimplification,
5505
0
        state->strokeAdjust);
5506
0
  if (path2 != path) {
5507
0
    delete path2;
5508
0
  }
5509
0
  xMin = xPath->getXMin();
5510
0
  yMin = xPath->getYMin();
5511
0
  xMax = xPath->getXMax();
5512
0
  yMax = xPath->getYMax();
5513
0
  if (xMin > xMax || yMin > yMax) {
5514
0
    delete xPath;
5515
0
    return splashOk;
5516
0
  }
5517
0
  scanner = new SplashXPathScanner(xPath, eo, yMin, yMax);
5518
5519
  // check clipping
5520
0
  if ((clipRes = state->clip->testRect(xMin, yMin, xMax, yMax,
5521
0
               state->strokeAdjust))
5522
0
      != splashClipAllOutside) {
5523
5524
0
    if ((t = state->clip->getXMinI(state->strokeAdjust)) > xMin) {
5525
0
      xMin = t;
5526
0
    }
5527
0
    if ((t = state->clip->getXMaxI(state->strokeAdjust)) < xMax) {
5528
0
      xMax = t;
5529
0
    }
5530
0
    if ((t = state->clip->getYMinI(state->strokeAdjust)) > yMin) {
5531
0
      yMin = t;
5532
0
    }
5533
0
    if ((t = state->clip->getYMaxI(state->strokeAdjust)) < yMax) {
5534
0
      yMax = t;
5535
0
    }
5536
0
    if (xMin > xMax || yMin > yMax) {
5537
0
      delete scanner;
5538
0
      delete xPath;
5539
0
      return splashOk;
5540
0
    }
5541
5542
0
    pipeInit(&pipe, pattern, (Guchar)splashRound(alpha * 255),
5543
0
       gTrue, gFalse);
5544
5545
    // draw the spans
5546
0
    if (vectorAntialias && !inShading) {
5547
0
      for (y = yMin; y <= yMax; ++y) {
5548
0
  scanner->getSpan(scanBuf, y, xMin, xMax, &xMin2, &xMax2);
5549
0
  if (xMin2 <= xMax2) {
5550
0
    if (clipRes != splashClipAllInside) {
5551
0
      state->clip->clipSpan(scanBuf, y, xMin2, xMax2,
5552
0
          state->strokeAdjust);
5553
0
    }
5554
0
    (this->*pipe.run)(&pipe, xMin2, xMax2, y, scanBuf + xMin2, NULL);
5555
0
  }
5556
0
      }
5557
0
    } else {
5558
0
      for (y = yMin; y <= yMax; ++y) {
5559
0
  scanner->getSpanBinary(scanBuf, y, xMin, xMax, &xMin2, &xMax2);
5560
0
  if (xMin2 <= xMax2) {
5561
0
    if (clipRes != splashClipAllInside) {
5562
0
      state->clip->clipSpanBinary(scanBuf, y, xMin2, xMax2,
5563
0
          state->strokeAdjust);
5564
0
    }
5565
0
    (this->*pipe.run)(&pipe, xMin2, xMax2, y, scanBuf + xMin2, NULL);
5566
0
  }
5567
0
      }
5568
0
    }
5569
0
  }
5570
0
  opClipRes = clipRes;
5571
5572
0
  delete scanner;
5573
0
  delete xPath;
5574
0
  return splashOk;
5575
0
}
5576
5577
// Applies various tweaks to a fill path:
5578
// (1) add stroke adjust hints to a filled rectangle
5579
// (2) applies a minimum width to a zero-width filled rectangle (so
5580
//     stroke adjustment works correctly
5581
// (3) convert a degenerate fill ('moveto lineto fill' and 'moveto
5582
//     lineto closepath fill') to a minimum-width filled rectangle
5583
//
5584
// These tweaks only apply to paths with a single subpath.
5585
//
5586
// Returns either the unchanged input path or a new path (in which
5587
// case the returned path must be deleted by the caller).
5588
0
SplashPath *Splash::tweakFillPath(SplashPath *path) {
5589
0
  SplashPath *path2;
5590
0
  SplashCoord xx0, yy0, xx1, yy1, dx, dy, d, wx, wy, w;
5591
0
  int n;
5592
5593
0
  if (state->strokeAdjust == splashStrokeAdjustOff || path->hints) {
5594
0
    return path;
5595
0
  }
5596
5597
0
  n = path->getLength();
5598
0
  if (!((n == 2) ||
5599
0
  (n == 3 &&
5600
0
   path->flags[1] == 0) ||
5601
0
  (n == 4 &&
5602
0
   path->flags[1] == 0 &&
5603
0
   path->flags[2] == 0) ||
5604
0
  (n == 5 &&
5605
0
   path->flags[1] == 0 &&
5606
0
   path->flags[2] == 0 &&
5607
0
   path->flags[3] == 0))) {
5608
0
    return path;
5609
0
  }
5610
5611
0
  path2 = path;
5612
5613
  // degenerate fill (2 or 3 points) or rectangle of (nearly) zero
5614
  // width --> replace with a min-width rectangle and hint
5615
0
  if (n == 2 ||
5616
0
      (n == 3 && (path->flags[0] & splashPathClosed)) ||
5617
0
      (n == 3 && (splashAbs(path->pts[0].x - path->pts[2].x) < 0.001 &&
5618
0
      splashAbs(path->pts[0].y - path->pts[2].y) < 0.001)) ||
5619
0
      ((n == 4 ||
5620
0
  (n == 5 && (path->flags[0] & splashPathClosed))) &&
5621
0
       ((splashAbs(path->pts[0].x - path->pts[1].x) < 0.001 &&
5622
0
   splashAbs(path->pts[0].y - path->pts[1].y) < 0.001 &&
5623
0
   splashAbs(path->pts[2].x - path->pts[3].x) < 0.001 &&
5624
0
   splashAbs(path->pts[2].y - path->pts[3].y) < 0.001) ||
5625
0
  (splashAbs(path->pts[0].x - path->pts[3].x) < 0.001 &&
5626
0
   splashAbs(path->pts[0].y - path->pts[3].y) < 0.001 &&
5627
0
   splashAbs(path->pts[1].x - path->pts[2].x) < 0.001 &&
5628
0
   splashAbs(path->pts[1].y - path->pts[2].y) < 0.001)))) {
5629
0
    wx = state->matrix[0] + state->matrix[2];
5630
0
    wy = state->matrix[1] + state->matrix[3];
5631
0
    w = splashSqrt(wx*wx + wy*wy);
5632
0
    if (w < 0.001) {
5633
0
      w = 0;
5634
0
    } else {
5635
      // min width is 0.1 -- this constant is minWidth * sqrt(2)
5636
0
      w = (SplashCoord)0.1414 / w;
5637
0
    }
5638
0
    xx0 = path->pts[0].x;
5639
0
    yy0 = path->pts[0].y;
5640
0
    if (n <= 3) {
5641
0
      xx1 = path->pts[1].x;
5642
0
      yy1 = path->pts[1].y;
5643
0
    } else {
5644
0
      xx1 = path->pts[2].x;
5645
0
      yy1 = path->pts[2].y;
5646
0
    }
5647
0
    dx = xx1 - xx0;
5648
0
    dy = yy1 - yy0;
5649
0
    d = splashSqrt(dx * dx + dy * dy);
5650
0
    if (d < 0.001) {
5651
0
      d = 0;
5652
0
    } else {
5653
0
      d = w / d;
5654
0
    }
5655
0
    dx *= d;
5656
0
    dy *= d;
5657
0
    path2 = new SplashPath();
5658
0
    path2->moveTo(xx0 + dy, yy0 - dx);
5659
0
    path2->lineTo(xx1 + dy, yy1 - dx);
5660
0
    path2->lineTo(xx1 - dy, yy1 + dx);
5661
0
    path2->lineTo(xx0 - dy, yy0 + dx);
5662
0
    path2->close(gTrue);
5663
0
    path2->addStrokeAdjustHint(0, 2, 0, 4);
5664
0
    path2->addStrokeAdjustHint(1, 3, 0, 4);
5665
5666
  // unclosed rectangle --> close and hint
5667
0
  } else if (n == 4 && !(path->flags[0] & splashPathClosed)) {
5668
0
    path2->close(gTrue);
5669
0
    path2->addStrokeAdjustHint(0, 2, 0, 4);
5670
0
    path2->addStrokeAdjustHint(1, 3, 0, 4);
5671
5672
  // closed rectangle --> hint
5673
0
  } else if (n == 5 && (path->flags[0] & splashPathClosed)) {
5674
0
    path2->addStrokeAdjustHint(0, 2, 0, 4);
5675
0
    path2->addStrokeAdjustHint(1, 3, 0, 4);
5676
0
  }
5677
5678
0
  return path2;
5679
0
}
5680
5681
0
GBool Splash::pathAllOutside(SplashPath *path) {
5682
0
  SplashCoord xMin1, yMin1, xMax1, yMax1;
5683
0
  SplashCoord xMin2, yMin2, xMax2, yMax2;
5684
0
  SplashCoord x, y;
5685
0
  int xMinI, yMinI, xMaxI, yMaxI;
5686
0
  int i;
5687
5688
0
  xMin1 = xMax1 = path->pts[0].x;
5689
0
  yMin1 = yMax1 = path->pts[0].y;
5690
0
  for (i = 1; i < path->length; ++i) {
5691
0
    if (path->pts[i].x < xMin1) {
5692
0
      xMin1 = path->pts[i].x;
5693
0
    } else if (path->pts[i].x > xMax1) {
5694
0
      xMax1 = path->pts[i].x;
5695
0
    }
5696
0
    if (path->pts[i].y < yMin1) {
5697
0
      yMin1 = path->pts[i].y;
5698
0
    } else if (path->pts[i].y > yMax1) {
5699
0
      yMax1 = path->pts[i].y;
5700
0
    }
5701
0
  }
5702
5703
0
  transform(state->matrix, xMin1, yMin1, &x, &y);
5704
0
  xMin2 = xMax2 = x;
5705
0
  yMin2 = yMax2 = y;
5706
0
  transform(state->matrix, xMin1, yMax1, &x, &y);
5707
0
  if (x < xMin2) {
5708
0
    xMin2 = x;
5709
0
  } else if (x > xMax2) {
5710
0
    xMax2 = x;
5711
0
  }
5712
0
  if (y < yMin2) {
5713
0
    yMin2 = y;
5714
0
  } else if (y > yMax2) {
5715
0
    yMax2 = y;
5716
0
  }
5717
0
  transform(state->matrix, xMax1, yMin1, &x, &y);
5718
0
  if (x < xMin2) {
5719
0
    xMin2 = x;
5720
0
  } else if (x > xMax2) {
5721
0
    xMax2 = x;
5722
0
  }
5723
0
  if (y < yMin2) {
5724
0
    yMin2 = y;
5725
0
  } else if (y > yMax2) {
5726
0
    yMax2 = y;
5727
0
  }
5728
0
  transform(state->matrix, xMax1, yMax1, &x, &y);
5729
0
  if (x < xMin2) {
5730
0
    xMin2 = x;
5731
0
  } else if (x > xMax2) {
5732
0
    xMax2 = x;
5733
0
  }
5734
0
  if (y < yMin2) {
5735
0
    yMin2 = y;
5736
0
  } else if (y > yMax2) {
5737
0
    yMax2 = y;
5738
0
  }
5739
  // sanity-check the coordinates - xMinI/yMinI/xMaxI/yMaxI are
5740
  // 32-bit integers, so coords need to be < 2^31
5741
0
  SplashXPath::clampCoords(&xMin2, &yMin2);
5742
0
  SplashXPath::clampCoords(&xMax2, &yMax2);
5743
0
  xMinI = splashFloor(xMin2);
5744
0
  yMinI = splashFloor(yMin2);
5745
0
  xMaxI = splashFloor(xMax2);
5746
0
  yMaxI = splashFloor(yMax2);
5747
5748
0
  return state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI,
5749
0
             state->strokeAdjust) ==
5750
0
         splashClipAllOutside;
5751
0
}
5752
5753
SplashError Splash::fillChar(SplashCoord x, SplashCoord y,
5754
0
           int c, SplashFont *font) {
5755
0
  SplashGlyphBitmap glyph;
5756
0
  SplashCoord xt, yt;
5757
0
  int x0, y0, xFrac, yFrac;
5758
0
  SplashError err;
5759
5760
0
  if (debugMode) {
5761
0
    printf("fillChar: x=%.2f y=%.2f c=%3d=0x%02x='%c'\n",
5762
0
     (double)x, (double)y, c, c, c);
5763
0
  }
5764
0
  transform(state->matrix, x, y, &xt, &yt);
5765
0
  x0 = splashFloor(xt);
5766
0
  xFrac = splashFloor((xt - x0) * splashFontFraction);
5767
0
  y0 = splashFloor(yt);
5768
0
  yFrac = splashFloor((yt - y0) * splashFontFraction);
5769
0
  if (!font->getGlyph(c, xFrac, yFrac, &glyph)) {
5770
0
    return splashErrNoGlyph;
5771
0
  }
5772
0
  err = fillGlyph2(x0, y0, &glyph);
5773
0
  if (glyph.freeData) {
5774
0
    gfree(glyph.data);
5775
0
  }
5776
0
  return err;
5777
0
}
5778
5779
SplashError Splash::fillGlyph(SplashCoord x, SplashCoord y,
5780
0
            SplashGlyphBitmap *glyph) {
5781
0
  SplashCoord xt, yt;
5782
0
  int x0, y0;
5783
5784
0
  transform(state->matrix, x, y, &xt, &yt);
5785
0
  x0 = splashFloor(xt);
5786
0
  y0 = splashFloor(yt);
5787
0
  return fillGlyph2(x0, y0, glyph);
5788
0
}
5789
5790
0
SplashError Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph) {
5791
0
  SplashPipe pipe;
5792
0
  SplashClipResult clipRes;
5793
0
  Guchar alpha;
5794
0
  Guchar *p;
5795
0
  int xMin, yMin, xMax, yMax;
5796
0
  int x, y, xg, yg, xx, t;
5797
5798
0
  xg = x0 - glyph->x;
5799
0
  yg = y0 - glyph->y;
5800
0
  xMin = xg;
5801
0
  xMax = xg + glyph->w - 1;
5802
0
  yMin = yg;
5803
0
  yMax = yg + glyph->h - 1;
5804
0
  if ((clipRes = state->clip->testRect(xMin, yMin, xMax, yMax,
5805
0
               state->strokeAdjust))
5806
0
      != splashClipAllOutside) {
5807
0
    pipeInit(&pipe, state->fillPattern,
5808
0
       (Guchar)splashRound(state->fillAlpha * 255),
5809
0
       gTrue, gFalse);
5810
0
    if (clipRes == splashClipAllInside) {
5811
0
      if (glyph->aa) {
5812
0
  p = glyph->data;
5813
0
  for (y = yMin; y <= yMax; ++y) {
5814
0
    (this->*pipe.run)(&pipe, xMin, xMax, y,
5815
0
          glyph->data + (y - yMin) * glyph->w, NULL);
5816
0
  }
5817
0
      } else {
5818
0
  p = glyph->data;
5819
0
  for (y = yMin; y <= yMax; ++y) {
5820
0
    for (x = xMin; x <= xMax; x += 8) {
5821
0
      alpha = *p++;
5822
0
      for (xx = 0; xx < 8 && x + xx <= xMax; ++xx) {
5823
0
        scanBuf[x + xx] = (alpha & 0x80) ? 0xff : 0x00;
5824
0
        alpha = (Guchar)(alpha << 1);
5825
0
      }
5826
0
    }
5827
0
    (this->*pipe.run)(&pipe, xMin, xMax, y, scanBuf + xMin, NULL);
5828
0
  }
5829
0
      }
5830
0
    } else {
5831
0
      if ((t = state->clip->getXMinI(state->strokeAdjust)) > xMin) {
5832
0
  xMin = t;
5833
0
      }
5834
0
      if ((t = state->clip->getXMaxI(state->strokeAdjust)) < xMax) {
5835
0
  xMax = t;
5836
0
      }
5837
0
      if ((t = state->clip->getYMinI(state->strokeAdjust)) > yMin) {
5838
0
  yMin = t;
5839
0
      }
5840
0
      if ((t = state->clip->getYMaxI(state->strokeAdjust)) < yMax) {
5841
0
  yMax = t;
5842
0
      }
5843
0
      if (xMin <= xMax && yMin <= yMax) {
5844
0
  if (glyph->aa) {
5845
0
    for (y = yMin; y <= yMax; ++y) {
5846
0
      p = glyph->data + (y - yg) * glyph->w + (xMin - xg);
5847
0
      memcpy(scanBuf + xMin, p, xMax - xMin + 1);
5848
0
      state->clip->clipSpan(scanBuf, y, xMin, xMax,
5849
0
          state->strokeAdjust);
5850
0
      (this->*pipe.run)(&pipe, xMin, xMax, y, scanBuf + xMin, NULL);
5851
0
    }
5852
0
  } else {
5853
0
    for (y = yMin; y <= yMax; ++y) {
5854
0
      p = glyph->data + (y - yg) * ((glyph->w + 7) >> 3)
5855
0
        + ((xMin - xg) >> 3);
5856
0
      alpha = *p++;
5857
0
      xx = (xMin - xg) & 7;
5858
0
      alpha = (Guchar)(alpha << xx);
5859
0
      for (x = xMin; xx < 8 && x <= xMax; ++x, ++xx) {
5860
0
        scanBuf[x] = (alpha & 0x80) ? 255 : 0;
5861
0
        alpha = (Guchar)(alpha << 1);
5862
0
      }
5863
0
      for (; x <= xMax; x += 8) {
5864
0
        alpha = *p++;
5865
0
        for (xx = 0; xx < 8 && x + xx <= xMax; ++xx) {
5866
0
    scanBuf[x + xx] = (alpha & 0x80) ? 255 : 0;
5867
0
    alpha = (Guchar)(alpha << 1);
5868
0
        }
5869
0
      }
5870
0
      state->clip->clipSpanBinary(scanBuf, y, xMin, xMax,
5871
0
          state->strokeAdjust);
5872
0
      (this->*pipe.run)(&pipe, xMin, xMax, y, scanBuf + xMin, NULL);
5873
0
    }
5874
0
  }
5875
0
      }
5876
0
    }
5877
0
  }
5878
0
  opClipRes = clipRes;
5879
5880
0
  return splashOk;
5881
0
}
5882
5883
void Splash::getImageBounds(SplashCoord xyMin, SplashCoord xyMax,
5884
0
          int *xyMinI, int *xyMaxI) {
5885
0
  if (state->strokeAdjust == splashStrokeAdjustOff) {
5886
    // make sure the coords fit in 32-bit ints
5887
#if USE_FIXEDPOINT
5888
    if (xyMin < -32767) {
5889
      xyMin = -32767;
5890
    } else if (xyMin > 32767) {
5891
      xyMin = 32767;
5892
    }
5893
    if (xyMax < -32767) {
5894
      xyMax = -32767;
5895
    } else if (xyMax > 32767) {
5896
      xyMax = 32767;
5897
    }
5898
#else
5899
0
    if (xyMin < -1e9) {
5900
0
      xyMin = -1e9;
5901
0
    } else if (xyMin > 1e9) {
5902
0
      xyMin = 1e9;
5903
0
    }
5904
0
    if (xyMax < -1e9) {
5905
0
      xyMax = -1e9;
5906
0
    } else if (xyMax > 1e9) {
5907
0
      xyMax = 1e9;
5908
0
    }
5909
0
#endif
5910
0
    *xyMinI = splashFloor(xyMin);
5911
0
    *xyMaxI = splashFloor(xyMax);
5912
0
    if (*xyMaxI <= *xyMinI) {
5913
0
      *xyMaxI = *xyMinI + 1;
5914
0
    }
5915
0
  } else {
5916
0
    splashStrokeAdjust(xyMin, xyMax, xyMinI, xyMaxI, state->strokeAdjust);
5917
0
  }
5918
0
}
5919
5920
struct SplashDrawImageMaskRowData {
5921
  SplashPipe pipe;
5922
};
5923
5924
// The glyphMode flag is not currently used, but may be useful if the
5925
// stroke adjustment behavior is changed.
5926
SplashError Splash::fillImageMask(GString *imageTag,
5927
          SplashImageMaskSource src, void *srcData,
5928
          int w, int h, SplashCoord *mat,
5929
          GBool glyphMode, GBool interpolate,
5930
0
          GBool antialias) {
5931
0
  if (debugMode) {
5932
0
    printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
5933
0
     w, h, (double)mat[0], (double)mat[1], (double)mat[2],
5934
0
     (double)mat[3], (double)mat[4], (double)mat[5]);
5935
0
  }
5936
5937
  //--- check for singular matrix
5938
0
  if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) {
5939
0
    return splashErrSingularMatrix;
5940
0
  }
5941
5942
  //--- compute image bbox, check clipping
5943
0
  GBool flipsOnly = splashAbs(mat[1]) <= 0.0001 && splashAbs(mat[2]) <= 0.0001;
5944
0
  GBool rot90Only = splashAbs(mat[0]) <= 0.0001 && splashAbs(mat[3]) <= 0.0001;
5945
0
  GBool horizFlip = gFalse;
5946
0
  GBool vertFlip = gFalse;
5947
0
  int xMin, yMin, xMax, yMax;
5948
0
  if (flipsOnly) {
5949
0
    horizFlip = mat[0] < 0;
5950
0
    vertFlip = mat[3] < 0;
5951
0
    if (horizFlip) {
5952
0
      getImageBounds(mat[0] + mat[4], mat[4], &xMin, &xMax);
5953
0
    } else {
5954
0
      getImageBounds(mat[4], mat[0] + mat[4], &xMin, &xMax);
5955
0
    }
5956
0
    if (vertFlip) {
5957
0
      getImageBounds(mat[3] + mat[5], mat[5], &yMin, &yMax);
5958
0
    } else {
5959
0
      getImageBounds(mat[5], mat[3] + mat[5], &yMin, &yMax);
5960
0
    }
5961
0
  } else if (rot90Only) {
5962
0
    horizFlip = mat[2] < 0;
5963
0
    vertFlip = mat[1] < 0;
5964
0
    if (horizFlip) {
5965
0
      getImageBounds(mat[2] + mat[4], mat[4], &xMin, &xMax);
5966
0
    } else {
5967
0
      getImageBounds(mat[4], mat[2] + mat[4], &xMin, &xMax);
5968
0
    }
5969
0
    if (vertFlip) {
5970
0
      getImageBounds(mat[1] + mat[5], mat[5], &yMin, &yMax);
5971
0
    } else {
5972
0
      getImageBounds(mat[5], mat[1] + mat[5], &yMin, &yMax);
5973
0
    }
5974
0
  } else {
5975
0
    int xx = splashRound(mat[4]);   // (0,0)
5976
0
    int yy = splashRound(mat[5]);
5977
0
    xMin = xMax = xx;
5978
0
    yMin = yMax = yy;
5979
0
    xx = splashRound(mat[0] + mat[4]);    // (1,0)
5980
0
    yy = splashRound(mat[1] + mat[5]);
5981
0
    if (xx < xMin) {
5982
0
      xMin = xx;
5983
0
    } else if (xx > xMax) {
5984
0
      xMax = xx;
5985
0
    }
5986
0
    if (yy < yMin) {
5987
0
      yMin = yy;
5988
0
    } else if (yy > yMax) {
5989
0
      yMax = yy;
5990
0
    }
5991
0
    xx = splashRound(mat[2] + mat[4]);    // (0,1)
5992
0
    yy = splashRound(mat[3] + mat[5]);
5993
0
    if (xx < xMin) {
5994
0
      xMin = xx;
5995
0
    } else if (xx > xMax) {
5996
0
      xMax = xx;
5997
0
    }
5998
0
    if (yy < yMin) {
5999
0
      yMin = yy;
6000
0
    } else if (yy > yMax) {
6001
0
      yMax = yy;
6002
0
    }
6003
0
    xx = splashRound(mat[0] + mat[2] + mat[4]); // (1,1)
6004
0
    yy = splashRound(mat[1] + mat[3] + mat[5]);
6005
0
    if (xx < xMin) {
6006
0
      xMin = xx;
6007
0
    } else if (xx > xMax) {
6008
0
      xMax = xx;
6009
0
    }
6010
0
    if (yy < yMin) {
6011
0
      yMin = yy;
6012
0
    } else if (yy > yMax) {
6013
0
      yMax = yy;
6014
0
    }
6015
0
    if (xMax <= xMin) {
6016
0
      xMax = xMin + 1;
6017
0
    }
6018
0
    if (yMax <= yMin) {
6019
0
      yMax = yMin + 1;
6020
0
    }
6021
0
  }
6022
0
  SplashClipResult clipRes =
6023
0
      state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1,
6024
0
          state->strokeAdjust);
6025
  // If the scaled mask is much wider and/or taller than the clip
6026
  // region, we use the "arbitrary" scaling path, to avoid a
6027
  // potentially very slow loop in the flips-only path (which scans
6028
  // the full width and height of the scaled mask, regardless of the
6029
  // clip region).
6030
0
  int clipW = state->clip->getXMaxI(state->strokeAdjust)
6031
0
        - state->clip->getXMinI(state->strokeAdjust);
6032
0
  int clipH = state->clip->getYMaxI(state->strokeAdjust)
6033
0
        - state->clip->getYMinI(state->strokeAdjust);
6034
0
  GBool veryLarge = ((xMax - xMin) / 8 > clipW && xMax - xMin > 1000) ||
6035
0
                    ((yMax - yMin) / 8 > clipH && yMax - yMin > 1000);
6036
6037
  //--- set up the SplashDrawImageMaskRowData object and the pipes
6038
0
  SplashDrawImageMaskRowData dd;
6039
0
  pipeInit(&dd.pipe, state->fillPattern,
6040
0
     (Guchar)splashRound(state->fillAlpha * 255),
6041
0
     gTrue, gFalse);
6042
6043
  //--- choose the drawRow function
6044
0
  SplashDrawImageMaskRowFunc drawRowFunc;
6045
0
  if (clipRes == splashClipAllInside) {
6046
0
    drawRowFunc = &Splash::drawImageMaskRowNoClip;
6047
0
  } else {
6048
0
    if (antialias) {
6049
0
      drawRowFunc = &Splash::drawImageMaskRowClipAA;
6050
0
    } else {
6051
0
      drawRowFunc = &Splash::drawImageMaskRowClipNoAA;
6052
0
    }
6053
0
  }
6054
6055
  //--- horizontal/vertical flips only
6056
0
  if (flipsOnly && !veryLarge) {
6057
0
    if (clipRes != splashClipAllOutside) {
6058
0
      int scaledWidth = xMax - xMin;
6059
0
      int scaledHeight = yMax - yMin;
6060
0
      ImageMaskScaler scaler(src, srcData, w, h,
6061
0
           scaledWidth, scaledHeight, interpolate, antialias);
6062
0
      Guchar *tmpLine = NULL;
6063
0
      if (horizFlip) {
6064
0
  tmpLine = (Guchar *)gmalloc(scaledWidth);
6065
0
      }
6066
0
      if (vertFlip) {
6067
0
  if (horizFlip) {    // bottom-up, mirrored
6068
0
    for (int y = 0; y < scaledHeight; ++y) {
6069
0
      scaler.nextLine();
6070
0
      mirrorImageMaskRow(scaler.data(), tmpLine, scaledWidth);
6071
0
      (this->*drawRowFunc)(&dd, tmpLine,
6072
0
         xMin, yMax - 1 - y, scaledWidth);
6073
0
    }
6074
0
  } else {            // bottom-up
6075
0
    for (int y = 0; y < scaledHeight; ++y) {
6076
0
      scaler.nextLine();
6077
0
      (this->*drawRowFunc)(&dd, scaler.data(),
6078
0
         xMin, yMax - 1 - y, scaledWidth);
6079
0
    }
6080
0
  }
6081
0
      } else {
6082
0
  if (horizFlip) {    // top-down, mirrored
6083
0
    for (int y = 0; y < scaledHeight; ++y) {
6084
0
      scaler.nextLine();
6085
0
      mirrorImageMaskRow(scaler.data(), tmpLine, scaledWidth);
6086
0
      (this->*drawRowFunc)(&dd, tmpLine,
6087
0
         xMin, yMin + y, scaledWidth);
6088
0
    }
6089
0
  } else {            // top-down
6090
0
    for (int y = 0; y < scaledHeight; ++y) {
6091
0
      scaler.nextLine();
6092
0
      (this->*drawRowFunc)(&dd, scaler.data(),
6093
0
         xMin, yMin + y, scaledWidth);
6094
0
    }
6095
0
  }
6096
0
      }
6097
0
      gfree(tmpLine);
6098
0
    }
6099
6100
  //--- 90/270 rotation
6101
0
  } else if (rot90Only && !veryLarge) {
6102
0
    if (clipRes != splashClipAllOutside) {
6103
6104
      // scale the mask
6105
0
      int scaledWidth = yMax - yMin;
6106
0
      int scaledHeight = xMax - xMin;
6107
0
      ImageMaskScaler scaler(src, srcData, w, h,
6108
0
           scaledWidth, scaledHeight, interpolate, antialias);
6109
0
      Guchar *scaledMask = (Guchar *)gmallocn(scaledHeight, scaledWidth);
6110
0
      Guchar *ptr = scaledMask;
6111
0
      for (int y = 0; y < scaledHeight; ++y) {
6112
0
  scaler.nextLine();
6113
0
  memcpy(ptr, scaler.data(), scaledWidth);
6114
0
  ptr += scaledWidth;
6115
0
      }
6116
6117
      // draw it
6118
0
      Guchar *tmpLine = (Guchar *)gmalloc(scaledHeight);
6119
0
      for (int y = 0; y < scaledWidth; ++y) {
6120
0
  if (vertFlip) {
6121
0
    ptr = scaledMask + (scaledWidth - 1 - y);
6122
0
  } else {
6123
0
    ptr = scaledMask + y;
6124
0
  }
6125
0
  if (horizFlip) {
6126
0
    ptr += (scaledHeight - 1) * scaledWidth;
6127
0
    for (int x = 0; x < scaledHeight; ++x) {
6128
0
      tmpLine[x] = *ptr;
6129
0
      ptr -= scaledWidth;
6130
0
    }
6131
0
  } else {
6132
0
    for (int x = 0; x < scaledHeight; ++x) {
6133
0
      tmpLine[x] = *ptr;
6134
0
      ptr += scaledWidth;
6135
0
    }
6136
0
  }
6137
0
  (this->*drawRowFunc)(&dd, tmpLine, xMin, yMin + y, scaledHeight);
6138
0
      }
6139
6140
0
      gfree(tmpLine);
6141
0
      gfree(scaledMask);
6142
0
    }
6143
6144
  //--- arbitrary transform
6145
0
  } else {
6146
    // estimate of size of scaled image
6147
0
    int scaledWidth = splashRound(splashSqrt(mat[0] * mat[0]
6148
0
               + mat[1] * mat[1]));
6149
0
    int scaledHeight = splashRound(splashSqrt(mat[2] * mat[2]
6150
0
                + mat[3] * mat[3]));
6151
0
    if (scaledWidth < 1) {
6152
0
      scaledWidth = 1;
6153
0
    }
6154
0
    if (scaledHeight < 1) {
6155
0
      scaledHeight = 1;
6156
0
    }
6157
0
    GBool downscaling = gTrue;
6158
0
    if (veryLarge || (scaledWidth >= w && scaledHeight >= h)) {
6159
0
      downscaling = gFalse;
6160
0
      scaledWidth = w;
6161
0
      scaledHeight = h;
6162
0
    }
6163
6164
    // compute mapping from device space to scaled image space
6165
0
    SplashCoord mat1[6];
6166
0
    mat1[0] = mat[0] / scaledWidth;
6167
0
    mat1[1] = mat[1] / scaledWidth;
6168
0
    mat1[2] = mat[2] / scaledHeight;
6169
0
    mat1[3] = mat[3] / scaledHeight;
6170
0
    mat1[4] = mat[4];
6171
0
    mat1[5] = mat[5];
6172
0
    SplashCoord det = mat1[0] * mat1[3] - mat1[1] * mat1[2];
6173
0
    if (splashAbs(det) < 1e-6) {
6174
      // this should be caught by the singular matrix check in drawImage
6175
0
      return splashErrSingularMatrix;
6176
0
    }
6177
0
    SplashCoord invMat[6];
6178
0
    invMat[0] = mat1[3] / det;
6179
0
    invMat[1] = -mat1[1] / det;
6180
0
    invMat[2] = -mat1[2] / det;
6181
0
    invMat[3] = mat1[0] / det;
6182
    // the extra "+ 0.5 * (...)" terms are here because the
6183
    // drawImageArbitrary(No)Interp functions multiply by pixel
6184
    // centers, (x + 0.5, y + 0.5)
6185
0
    invMat[4] = (mat1[2] * mat1[5] - mat1[3] * mat1[4]) / det
6186
0
                + (invMat[0] + invMat[2]) * 0.5;
6187
0
    invMat[5] = (mat1[1] * mat1[4] - mat1[0] * mat1[5]) / det
6188
0
                + (invMat[1] + invMat[3]) * 0.5;
6189
6190
    // if downscaling: store the downscaled image mask
6191
    // if upscaling: store the unscaled image mask
6192
0
    Guchar *scaledMask = (Guchar *)gmallocn(scaledHeight, scaledWidth);
6193
0
    if (downscaling) {
6194
0
      ImageMaskScaler scaler(src, srcData, w, h,
6195
0
           scaledWidth, scaledHeight, interpolate, antialias);
6196
0
      Guchar *ptr = scaledMask;
6197
0
      for (int y = 0; y < scaledHeight; ++y) {
6198
0
  scaler.nextLine();
6199
0
  memcpy(ptr, scaler.data(), scaledWidth);
6200
0
  ptr += scaledWidth;
6201
0
      }
6202
0
    } else {
6203
0
      Guchar *ptr = scaledMask;
6204
0
      for (int y = 0; y < scaledHeight; ++y) {
6205
0
  (*src)(srcData, ptr);
6206
0
  for (int x = 0; x < scaledWidth; ++x) {
6207
0
    *ptr = (Guchar)(*ptr * 255);
6208
0
    ++ptr;
6209
0
  }
6210
0
      }
6211
0
    }
6212
6213
    // draw it
6214
0
    if (interpolate && antialias) {
6215
0
      drawImageMaskArbitraryInterp(scaledMask,
6216
0
           &dd, drawRowFunc, invMat,
6217
0
           scaledWidth, scaledHeight,
6218
0
           xMin, yMin, xMax, yMax);
6219
0
    } else {
6220
0
      drawImageMaskArbitraryNoInterp(scaledMask,
6221
0
             &dd, drawRowFunc, invMat,
6222
0
             scaledWidth, scaledHeight,
6223
0
             xMin, yMin, xMax, yMax);
6224
0
    }
6225
6226
    // free the downscaled/unscaled image
6227
0
    gfree(scaledMask);
6228
0
  }
6229
6230
0
  return splashOk;
6231
0
}
6232
6233
void Splash::drawImageMaskArbitraryNoInterp(
6234
           Guchar *scaledMask,
6235
           SplashDrawImageMaskRowData *dd,
6236
           SplashDrawImageMaskRowFunc drawRowFunc,
6237
           SplashCoord *invMat,
6238
           int scaledWidth, int scaledHeight,
6239
0
           int xMin, int yMin, int xMax, int yMax) {
6240
0
  int tt = state->clip->getXMinI(state->strokeAdjust);
6241
0
  if (tt > xMin) {
6242
0
    xMin = tt;
6243
0
  }
6244
0
  tt = state->clip->getXMaxI(state->strokeAdjust) + 1;
6245
0
  if (tt < xMax) {
6246
0
    xMax = tt;
6247
0
  }
6248
0
  tt = state->clip->getYMinI(state->strokeAdjust);
6249
0
  if (tt > yMin) {
6250
0
    yMin = tt;
6251
0
  }
6252
0
  tt = state->clip->getYMaxI(state->strokeAdjust) + 1;
6253
0
  if (tt < yMax) {
6254
0
    yMax = tt;
6255
0
  }
6256
0
  if (xMax <= xMin || yMax <= yMin) {
6257
0
    return;
6258
0
  }
6259
6260
0
  Guchar *buf = (Guchar *)gmalloc(xMax - xMin);
6261
6262
0
  for (int y = yMin; y < yMax; ++y) {
6263
0
    int rowMin = xMax;
6264
0
    int rowMax = 0;
6265
0
    for (int x = xMin; x < xMax; ++x) {
6266
      // note: invMat includes a "+0.5" factor so that this is really
6267
      // a multiply by (x+0.5, y+0.5)
6268
0
      int xx = splashFloor((SplashCoord)x * invMat[0]
6269
0
         + (SplashCoord)y * invMat[2] + invMat[4]);
6270
0
      int yy = splashFloor((SplashCoord)x * invMat[1]
6271
0
         + (SplashCoord)y * invMat[3] + invMat[5]);
6272
0
      if (xx >= 0 && xx < scaledWidth &&
6273
0
    yy >= 0 && yy < scaledHeight) {
6274
0
  Guchar *p = scaledMask + (yy * scaledWidth + xx);
6275
0
  Guchar *q = buf + (x - xMin);
6276
0
  *q = *p;
6277
0
  if (x < rowMin) {
6278
0
    rowMin = x;
6279
0
  }
6280
0
  rowMax = x + 1;
6281
0
      }
6282
0
    }
6283
0
    if (rowMin < rowMax) {
6284
0
      (this->*drawRowFunc)(dd, buf + (rowMin - xMin),
6285
0
         rowMin, y, rowMax - rowMin);
6286
0
    }
6287
0
  }
6288
6289
0
  gfree(buf);
6290
0
}
6291
6292
void Splash::drawImageMaskArbitraryInterp(
6293
           Guchar *scaledMask,
6294
           SplashDrawImageMaskRowData *dd,
6295
           SplashDrawImageMaskRowFunc drawRowFunc,
6296
           SplashCoord *invMat,
6297
           int scaledWidth, int scaledHeight,
6298
0
           int xMin, int yMin, int xMax, int yMax) {
6299
0
  int tt = state->clip->getXMinI(state->strokeAdjust);
6300
0
  if (tt > xMin) {
6301
0
    xMin = tt;
6302
0
  }
6303
0
  tt = state->clip->getXMaxI(state->strokeAdjust) + 1;
6304
0
  if (tt < xMax) {
6305
0
    xMax = tt;
6306
0
  }
6307
0
  tt = state->clip->getYMinI(state->strokeAdjust);
6308
0
  if (tt > yMin) {
6309
0
    yMin = tt;
6310
0
  }
6311
0
  tt = state->clip->getYMaxI(state->strokeAdjust) + 1;
6312
0
  if (tt < yMax) {
6313
0
    yMax = tt;
6314
0
  }
6315
0
  if (xMax <= xMin || yMax <= yMin) {
6316
0
    return;
6317
0
  }
6318
6319
0
  Guchar *buf = (Guchar *)gmalloc(xMax - xMin);
6320
6321
0
  for (int y = yMin; y < yMax; ++y) {
6322
0
    int rowMin = xMax;
6323
0
    int rowMax = 0;
6324
0
    for (int x = xMin; x < xMax; ++x) {
6325
      // note: invMat includes a "+0.5" factor so that this is really
6326
      // a multiply by (x+0.5, y+0.5)
6327
0
      SplashCoord xs = (SplashCoord)x * invMat[0]
6328
0
                 + (SplashCoord)y * invMat[2] + invMat[4];
6329
0
      SplashCoord ys = (SplashCoord)x * invMat[1]
6330
0
                 + (SplashCoord)y * invMat[3] + invMat[5];
6331
0
      int x0 = splashFloor(xs - 0.5);
6332
0
      int x1 = x0 + 1;
6333
0
      int y0 = splashFloor(ys - 0.5);
6334
0
      int y1 = y0 + 1;
6335
0
      if (x1 >= 0 && x0 < scaledWidth && y1 >= 0 && y0 < scaledHeight) {
6336
0
  SplashCoord sx0 = (SplashCoord)x1 + 0.5 - xs;
6337
0
  SplashCoord sx1 = (SplashCoord)1 - sx0;
6338
0
  SplashCoord sy0 = (SplashCoord)y1 + 0.5 - ys;
6339
0
  SplashCoord sy1 = (SplashCoord)1 - sy0;
6340
0
  if (x0 < 0) {
6341
0
    x0 = 0;
6342
0
  }
6343
0
  if (x1 >= scaledWidth) {
6344
0
    x1 = scaledWidth - 1;
6345
0
  }
6346
0
  if (y0 < 0) {
6347
0
    y0 = 0;
6348
0
  }
6349
0
  if (y1 >= scaledHeight) {
6350
0
    y1 = scaledHeight - 1;
6351
0
  }
6352
0
  Guchar *p00 = scaledMask + (y0 * scaledWidth + x0);
6353
0
  Guchar *p10 = scaledMask + (y0 * scaledWidth + x1);
6354
0
  Guchar *p01 = scaledMask + (y1 * scaledWidth + x0);
6355
0
  Guchar *p11 = scaledMask + (y1 * scaledWidth + x1);
6356
0
  Guchar *q = buf + (x - xMin);
6357
0
  *q = (Guchar)(int)(sx0 * (sy0 * (int)*p00 + sy1 * (int)*p01) +
6358
0
         sx1 * (sy0 * (int)*p10 + sy1 * (int)*p11));
6359
0
  if (x < rowMin) {
6360
0
    rowMin = x;
6361
0
  }
6362
0
  rowMax = x + 1;
6363
0
      }
6364
0
    }
6365
0
    if (rowMin < rowMax) {
6366
0
      (this->*drawRowFunc)(dd, buf + (rowMin - xMin),
6367
0
         rowMin, y, rowMax - rowMin);
6368
0
    }
6369
0
  }
6370
6371
0
  gfree(buf);
6372
0
}
6373
6374
0
void Splash::mirrorImageMaskRow(Guchar *maskIn, Guchar *maskOut, int width) {
6375
0
  Guchar *p, *q;
6376
6377
0
  p = maskIn;
6378
0
  q = maskOut + (width - 1);
6379
0
  for (int i = 0; i < width; ++i) {
6380
0
    *q = *p;
6381
0
    ++p;
6382
0
    --q;
6383
0
  }
6384
0
}
6385
6386
void Splash::drawImageMaskRowNoClip(SplashDrawImageMaskRowData *data,
6387
            Guchar *maskData,
6388
0
            int x, int y, int width) {
6389
0
  (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, maskData, NULL);
6390
0
}
6391
6392
void Splash::drawImageMaskRowClipNoAA(SplashDrawImageMaskRowData *data,
6393
              Guchar *maskData,
6394
0
              int x, int y, int width) {
6395
0
  if (y < 0 || y >= bitmap->height) {
6396
0
    return;
6397
0
  }
6398
0
  if (x < 0) {
6399
0
    maskData -= x;
6400
0
    width += x;
6401
0
    x = 0;
6402
0
  }
6403
0
  if (x + width > bitmap->width) {
6404
0
    width = bitmap->width - x;
6405
0
  }
6406
0
  if (width <= 0) {
6407
0
    return;
6408
0
  }
6409
0
  memcpy(scanBuf + x, maskData, width);
6410
0
  state->clip->clipSpanBinary(scanBuf, y, x, x + width - 1,
6411
0
            state->strokeAdjust);
6412
0
  (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y,
6413
0
        scanBuf + x, NULL);
6414
0
}
6415
6416
void Splash::drawImageMaskRowClipAA(SplashDrawImageMaskRowData *data,
6417
            Guchar *maskData,
6418
0
            int x, int y, int width) {
6419
0
  if (y < 0 || y >= bitmap->height) {
6420
0
    return;
6421
0
  }
6422
0
  if (x < 0) {
6423
0
    maskData -= x;
6424
0
    width += x;
6425
0
    x = 0;
6426
0
  }
6427
0
  if (x + width > bitmap->width) {
6428
0
    width = bitmap->width - x;
6429
0
  }
6430
0
  if (width <= 0) {
6431
0
    return;
6432
0
  }
6433
0
  memcpy(scanBuf + x, maskData, width);
6434
0
  state->clip->clipSpan(scanBuf, y, x, x + width - 1, state->strokeAdjust);
6435
0
  (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y,
6436
0
        scanBuf + x, NULL);
6437
0
}
6438
6439
struct SplashDrawImageRowData {
6440
  int nComps;
6441
  GBool srcAlpha;
6442
  SplashPipe pipe;
6443
};
6444
6445
SplashError Splash::drawImage(GString *imageTag,
6446
            SplashImageSource src, void *srcData,
6447
            SplashColorMode srcMode, GBool srcAlpha,
6448
            int w, int h, SplashCoord *mat,
6449
0
            GBool interpolate) {
6450
0
  if (debugMode) {
6451
0
    printf("drawImage: srcMode=%d srcAlpha=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
6452
0
     srcMode, srcAlpha, w, h, (double)mat[0], (double)mat[1], (double)mat[2],
6453
0
     (double)mat[3], (double)mat[4], (double)mat[5]);
6454
0
  }
6455
6456
  //--- check color modes
6457
0
  GBool ok = gFalse;
6458
0
  int nComps = 0;
6459
0
  switch (bitmap->mode) {
6460
0
  case splashModeMono1:
6461
0
  case splashModeMono8:
6462
0
    ok = srcMode == splashModeMono8;
6463
0
    nComps = 1;
6464
0
    break;
6465
0
  case splashModeRGB8:
6466
0
  case splashModeBGR8:
6467
0
    ok = srcMode == splashModeRGB8;
6468
0
    nComps = 3;
6469
0
    break;
6470
0
#if SPLASH_CMYK
6471
0
  case splashModeCMYK8:
6472
0
    ok = srcMode == splashModeCMYK8;
6473
0
    nComps = 4;
6474
0
    break;
6475
0
#endif
6476
0
  default:
6477
0
    ok = gFalse;
6478
0
    break;
6479
0
  }
6480
0
  if (!ok) {
6481
0
    return splashErrModeMismatch;
6482
0
  }
6483
6484
  //--- check for singular matrix
6485
0
  if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) {
6486
0
    return splashErrSingularMatrix;
6487
0
  }
6488
6489
  //--- compute image bbox, check clipping
6490
0
  GBool flipsOnly = splashAbs(mat[1]) <= 0.0001 && splashAbs(mat[2]) <= 0.0001;
6491
0
  GBool rot90Only = splashAbs(mat[0]) <= 0.0001 && splashAbs(mat[3]) <= 0.0001;
6492
0
  GBool horizFlip = gFalse;
6493
0
  GBool vertFlip = gFalse;
6494
0
  int xMin, yMin, xMax, yMax;
6495
0
  if (flipsOnly) {
6496
0
    horizFlip = mat[0] < 0;
6497
0
    vertFlip = mat[3] < 0;
6498
0
    if (horizFlip) {
6499
0
      getImageBounds(mat[0] + mat[4], mat[4], &xMin, &xMax);
6500
0
    } else {
6501
0
      getImageBounds(mat[4], mat[0] + mat[4], &xMin, &xMax);
6502
0
    }
6503
0
    if (vertFlip) {
6504
0
      getImageBounds(mat[3] + mat[5], mat[5], &yMin, &yMax);
6505
0
    } else {
6506
0
      getImageBounds(mat[5], mat[3] + mat[5], &yMin, &yMax);
6507
0
    }
6508
0
  } else if (rot90Only) {
6509
0
    horizFlip = mat[2] < 0;
6510
0
    vertFlip = mat[1] < 0;
6511
0
    if (horizFlip) {
6512
0
      getImageBounds(mat[2] + mat[4], mat[4], &xMin, &xMax);
6513
0
    } else {
6514
0
      getImageBounds(mat[4], mat[2] + mat[4], &xMin, &xMax);
6515
0
    }
6516
0
    if (vertFlip) {
6517
0
      getImageBounds(mat[1] + mat[5], mat[5], &yMin, &yMax);
6518
0
    } else {
6519
0
      getImageBounds(mat[5], mat[1] + mat[5], &yMin, &yMax);
6520
0
    }
6521
0
  } else {
6522
0
    int xx = splashRound(mat[4]);   // (0,0)
6523
0
    int yy = splashRound(mat[5]);
6524
0
    xMin = xMax = xx;
6525
0
    yMin = yMax = yy;
6526
0
    xx = splashRound(mat[0] + mat[4]);    // (1,0)
6527
0
    yy = splashRound(mat[1] + mat[5]);
6528
0
    if (xx < xMin) {
6529
0
      xMin = xx;
6530
0
    } else if (xx > xMax) {
6531
0
      xMax = xx;
6532
0
    }
6533
0
    if (yy < yMin) {
6534
0
      yMin = yy;
6535
0
    } else if (yy > yMax) {
6536
0
      yMax = yy;
6537
0
    }
6538
0
    xx = splashRound(mat[2] + mat[4]);    // (0,1)
6539
0
    yy = splashRound(mat[3] + mat[5]);
6540
0
    if (xx < xMin) {
6541
0
      xMin = xx;
6542
0
    } else if (xx > xMax) {
6543
0
      xMax = xx;
6544
0
    }
6545
0
    if (yy < yMin) {
6546
0
      yMin = yy;
6547
0
    } else if (yy > yMax) {
6548
0
      yMax = yy;
6549
0
    }
6550
0
    xx = splashRound(mat[0] + mat[2] + mat[4]); // (1,1)
6551
0
    yy = splashRound(mat[1] + mat[3] + mat[5]);
6552
0
    if (xx < xMin) {
6553
0
      xMin = xx;
6554
0
    } else if (xx > xMax) {
6555
0
      xMax = xx;
6556
0
    }
6557
0
    if (yy < yMin) {
6558
0
      yMin = yy;
6559
0
    } else if (yy > yMax) {
6560
0
      yMax = yy;
6561
0
    }
6562
0
    if (xMax <= xMin) {
6563
0
      xMax = xMin + 1;
6564
0
    }
6565
0
    if (yMax <= yMin) {
6566
0
      yMax = yMin + 1;
6567
0
    }
6568
0
  }
6569
0
  SplashClipResult clipRes =
6570
0
      state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1,
6571
0
          state->strokeAdjust);
6572
  // If the scaled image is much wider and/or taller than the clip
6573
  // region, we use the arbitrary transform path, to avoid a
6574
  // potentially very slow loop in the flips-only path (which scans
6575
  // the full width and height of the scaled image, regardless of the
6576
  // clip region).
6577
0
  int clipW = state->clip->getXMaxI(state->strokeAdjust)
6578
0
        - state->clip->getXMinI(state->strokeAdjust);
6579
0
  int clipH = state->clip->getYMaxI(state->strokeAdjust)
6580
0
        - state->clip->getYMinI(state->strokeAdjust);
6581
0
  GBool veryLarge = ((xMax - xMin) / 8 > clipW && xMax - xMin > 1000) ||
6582
0
                    ((yMax - yMin) / 8 > clipH && yMax - yMin > 1000);
6583
6584
  //--- set up the SplashDrawImageRowData object and the pipes
6585
0
  SplashDrawImageRowData dd;
6586
0
  dd.nComps = nComps;
6587
0
  dd.srcAlpha = srcAlpha;
6588
0
  pipeInit(&dd.pipe, NULL,
6589
0
     (Guchar)splashRound(state->fillAlpha * 255),
6590
0
     clipRes != splashClipAllInside || srcAlpha,
6591
0
     gFalse);
6592
6593
  //--- choose the drawRow function
6594
0
  SplashDrawImageRowFunc drawRowFunc;
6595
0
  if (clipRes == splashClipAllInside) {
6596
0
    if (srcAlpha) {
6597
0
      drawRowFunc = &Splash::drawImageRowNoClipAlpha;
6598
0
    } else {
6599
0
      drawRowFunc = &Splash::drawImageRowNoClipNoAlpha;
6600
0
    }
6601
0
  } else {
6602
0
    if (srcAlpha) {
6603
0
      if (vectorAntialias) {
6604
0
  drawRowFunc = &Splash::drawImageRowClipAlphaAA;
6605
0
      } else {
6606
0
  drawRowFunc = &Splash::drawImageRowClipAlphaNoAA;
6607
0
      }
6608
0
    } else {
6609
0
      if (vectorAntialias) {
6610
0
  drawRowFunc = &Splash::drawImageRowClipNoAlphaAA;
6611
0
      } else {
6612
0
  drawRowFunc = &Splash::drawImageRowClipNoAlphaNoAA;
6613
0
      }
6614
0
    }
6615
0
  }
6616
6617
  //--- horizontal/vertical flips only
6618
0
  if (flipsOnly && !veryLarge) {
6619
0
    if (clipRes != splashClipAllOutside) {
6620
0
      int scaledWidth = xMax - xMin;
6621
0
      int scaledHeight = yMax - yMin;
6622
0
      ImageScaler *scaler = getImageScaler(imageTag, src, srcData,
6623
0
             w, h, nComps,
6624
0
             scaledWidth, scaledHeight,
6625
0
             srcMode, srcAlpha, interpolate);
6626
0
      Guchar *tmpLine = NULL;
6627
0
      Guchar *tmpAlphaLine = NULL;
6628
0
      if (horizFlip) {
6629
0
  tmpLine = (Guchar *)gmallocn(scaledWidth, nComps);
6630
0
  if (srcAlpha) {
6631
0
    tmpAlphaLine = (Guchar *)gmalloc(scaledWidth);
6632
0
  }
6633
0
      }
6634
0
      if (vertFlip) {
6635
0
  if (horizFlip) {    // bottom-up, mirrored
6636
0
    for (int y = 0; y < scaledHeight; ++y) {
6637
0
      scaler->nextLine();
6638
0
      mirrorImageRow(scaler->colorData(), scaler->alphaData(),
6639
0
         tmpLine, tmpAlphaLine,
6640
0
         scaledWidth, nComps, srcAlpha);
6641
0
      (this->*drawRowFunc)(&dd, tmpLine, tmpAlphaLine,
6642
0
         xMin, yMax - 1 - y, scaledWidth);
6643
0
    }
6644
0
  } else {            // bottom-up
6645
0
    for (int y = 0; y < scaledHeight; ++y) {
6646
0
      scaler->nextLine();
6647
0
      (this->*drawRowFunc)(&dd, scaler->colorData(), scaler->alphaData(),
6648
0
         xMin, yMax - 1 - y, scaledWidth);
6649
0
    }
6650
0
  }
6651
0
      } else {
6652
0
  if (horizFlip) {    // top-down, mirrored
6653
0
    for (int y = 0; y < scaledHeight; ++y) {
6654
0
      scaler->nextLine();
6655
0
      mirrorImageRow(scaler->colorData(), scaler->alphaData(),
6656
0
         tmpLine, tmpAlphaLine,
6657
0
         scaledWidth, nComps, srcAlpha);
6658
0
      (this->*drawRowFunc)(&dd, tmpLine, tmpAlphaLine,
6659
0
         xMin, yMin + y, scaledWidth);
6660
0
    }
6661
0
  } else {            // top-down
6662
0
    for (int y = 0; y < scaledHeight; ++y) {
6663
0
      scaler->nextLine();
6664
0
      (this->*drawRowFunc)(&dd, scaler->colorData(), scaler->alphaData(),
6665
0
         xMin, yMin + y, scaledWidth);
6666
0
    }
6667
0
  }
6668
0
      }
6669
0
      gfree(tmpLine);
6670
0
      gfree(tmpAlphaLine);
6671
0
      delete scaler;
6672
0
    }
6673
6674
  //--- 90/270 rotation
6675
0
  } else if (rot90Only && !veryLarge) {
6676
0
    if (clipRes != splashClipAllOutside) {
6677
6678
      // scale the image
6679
0
      int scaledWidth = yMax - yMin;
6680
0
      int scaledHeight = xMax - xMin;
6681
0
      Guchar *scaledColor, *scaledAlpha;
6682
0
      GBool freeScaledImage;
6683
0
      getScaledImage(imageTag, src, srcData, w, h, nComps,
6684
0
         scaledWidth, scaledHeight, srcMode, srcAlpha, interpolate,
6685
0
         &scaledColor, &scaledAlpha, &freeScaledImage);
6686
6687
      // draw it
6688
0
      Guchar *tmpLine = (Guchar *)gmallocn(scaledHeight, nComps);
6689
0
      Guchar *tmpAlphaLine = NULL;
6690
0
      if (srcAlpha) {
6691
0
  tmpAlphaLine = (Guchar *)gmalloc(scaledHeight);
6692
0
      }
6693
0
      for (int y = 0; y < scaledWidth; ++y) {
6694
0
  Guchar *ptr, *alphaPtr;
6695
0
  if (vertFlip) {
6696
0
    ptr = scaledColor + (scaledWidth - 1 - y) * nComps;
6697
0
    if (srcAlpha) {
6698
0
      alphaPtr = scaledAlpha + (scaledWidth - 1 - y);
6699
0
    }
6700
0
  } else {
6701
0
    ptr = scaledColor + y * nComps;
6702
0
    if (srcAlpha) {
6703
0
      alphaPtr = scaledAlpha + y;
6704
0
    }
6705
0
  }
6706
0
  if (horizFlip) {
6707
0
    ptr += (scaledHeight - 1) * scaledWidth * nComps;
6708
0
    Guchar *q = tmpLine;
6709
0
    for (int x = 0; x < scaledHeight; ++x) {
6710
0
      for (int i = 0; i < nComps; ++i) {
6711
0
        *q++ = ptr[i];
6712
0
      }
6713
0
      ptr -= scaledWidth * nComps;
6714
0
    }
6715
0
    if (srcAlpha) {
6716
0
      alphaPtr += (scaledHeight - 1) * scaledWidth;
6717
0
      q = tmpAlphaLine;
6718
0
      for (int x = 0; x < scaledHeight; ++x) {
6719
0
        *q++ = *alphaPtr;
6720
0
        alphaPtr -= scaledWidth;
6721
0
      }
6722
0
    }
6723
0
  } else {
6724
0
    Guchar *q = tmpLine;
6725
0
    for (int x = 0; x < scaledHeight; ++x) {
6726
0
      for (int i = 0; i < nComps; ++i) {
6727
0
        *q++ = ptr[i];
6728
0
      }
6729
0
      ptr += scaledWidth * nComps;
6730
0
    }
6731
0
    if (srcAlpha) {
6732
0
      q = tmpAlphaLine;
6733
0
      for (int x = 0; x < scaledHeight; ++x) {
6734
0
        *q++ = *alphaPtr;
6735
0
        alphaPtr += scaledWidth;
6736
0
      }
6737
0
    }
6738
0
  }
6739
0
  (this->*drawRowFunc)(&dd, tmpLine, tmpAlphaLine,
6740
0
           xMin, yMin + y, scaledHeight);
6741
0
      }
6742
6743
0
      gfree(tmpLine);
6744
0
      gfree(tmpAlphaLine);
6745
0
      if (freeScaledImage) {
6746
0
  gfree(scaledColor);
6747
0
  gfree(scaledAlpha);
6748
0
      }
6749
0
    }
6750
6751
  //--- arbitrary transform
6752
0
  } else {
6753
    // estimate of size of scaled image
6754
0
    int scaledWidth = splashRound(splashSqrt(mat[0] * mat[0]
6755
0
               + mat[1] * mat[1]));
6756
0
    int scaledHeight = splashRound(splashSqrt(mat[2] * mat[2]
6757
0
                + mat[3] * mat[3]));
6758
0
    if (scaledWidth < 1) {
6759
0
      scaledWidth = 1;
6760
0
    }
6761
0
    if (scaledHeight < 1) {
6762
0
      scaledHeight = 1;
6763
0
    }
6764
0
    if (veryLarge || (scaledWidth >= w && scaledHeight >= h)) {
6765
0
      scaledWidth = w;
6766
0
      scaledHeight = h;
6767
0
    }
6768
6769
    // compute mapping from device space to scaled image space
6770
0
    SplashCoord mat1[6];
6771
0
    mat1[0] = mat[0] / scaledWidth;
6772
0
    mat1[1] = mat[1] / scaledWidth;
6773
0
    mat1[2] = mat[2] / scaledHeight;
6774
0
    mat1[3] = mat[3] / scaledHeight;
6775
0
    mat1[4] = mat[4];
6776
0
    mat1[5] = mat[5];
6777
0
    SplashCoord det = mat1[0] * mat1[3] - mat1[1] * mat1[2];
6778
0
    if (splashAbs(det) < 1e-6) {
6779
      // this should be caught by the singular matrix check in drawImage
6780
0
      return splashErrSingularMatrix;
6781
0
    }
6782
0
    SplashCoord invMat[6];
6783
0
    invMat[0] = mat1[3] / det;
6784
0
    invMat[1] = -mat1[1] / det;
6785
0
    invMat[2] = -mat1[2] / det;
6786
0
    invMat[3] = mat1[0] / det;
6787
    // the extra "+ 0.5 * (...)" terms are here because the
6788
    // drawImageArbitrary(No)Interp functions multiply by pixel
6789
    // centers, (x + 0.5, y + 0.5)
6790
0
    invMat[4] = (mat1[2] * mat1[5] - mat1[3] * mat1[4]) / det
6791
0
                + (invMat[0] + invMat[2]) * 0.5;
6792
0
    invMat[5] = (mat1[1] * mat1[4] - mat1[0] * mat1[5]) / det
6793
0
                + (invMat[1] + invMat[3]) * 0.5;
6794
6795
0
    Guchar *scaledColor, *scaledAlpha;
6796
0
    GBool freeScaledImage;
6797
0
    getScaledImage(imageTag, src, srcData, w, h, nComps,
6798
0
       scaledWidth, scaledHeight, srcMode, srcAlpha, interpolate,
6799
0
       &scaledColor, &scaledAlpha, &freeScaledImage);
6800
6801
    // draw it
6802
0
    if (interpolate) {
6803
0
      drawImageArbitraryInterp(scaledColor, scaledAlpha,
6804
0
             &dd, drawRowFunc, invMat,
6805
0
             scaledWidth, scaledHeight,
6806
0
             xMin, yMin, xMax, yMax,
6807
0
             nComps, srcAlpha);
6808
0
    } else {
6809
0
      drawImageArbitraryNoInterp(scaledColor, scaledAlpha,
6810
0
         &dd, drawRowFunc, invMat,
6811
0
         scaledWidth, scaledHeight,
6812
0
         xMin, yMin, xMax, yMax,
6813
0
         nComps, srcAlpha);
6814
0
    }
6815
6816
    // free the downscaled/unscaled image
6817
0
    if (freeScaledImage) {
6818
0
      gfree(scaledColor);
6819
0
      gfree(scaledAlpha);
6820
0
    }
6821
0
  }
6822
6823
0
  return splashOk;
6824
0
}
6825
6826
ImageScaler *Splash::getImageScaler(GString *imageTag,
6827
            SplashImageSource src, void *srcData,
6828
            int w, int h, int nComps,
6829
            int scaledWidth, int scaledHeight,
6830
            SplashColorMode srcMode,
6831
0
            GBool srcAlpha, GBool interpolate) {
6832
  // Notes:
6833
  //
6834
  // * If the scaled image is more than 8 Mpixels, we don't cache it.
6835
  //
6836
  // * Caching is done on the third consecutive use (second
6837
  //   consecutive reuse) of an image; this avoids overhead on the
6838
  //   common case of single-use images.
6839
6840
0
  if (scaledWidth < 8000000 / scaledHeight &&
6841
0
      imageCache->match(imageTag, scaledWidth, scaledHeight,
6842
0
      srcMode, srcAlpha, interpolate)) {
6843
0
    if (imageCache->colorData) {
6844
0
      return new ReplayImageScaler(nComps, srcAlpha, scaledWidth,
6845
0
           imageCache->colorData,
6846
0
           imageCache->alphaData);
6847
0
    } else {
6848
0
      int lineSize;
6849
0
      if (scaledWidth < INT_MAX / nComps) {
6850
0
  lineSize = scaledWidth * nComps;
6851
0
      } else {
6852
0
  lineSize = -1;
6853
0
      }
6854
0
      imageCache->colorData = (Guchar *)gmallocn(scaledHeight, lineSize);
6855
0
      if (srcAlpha) {
6856
0
  imageCache->alphaData = (Guchar *)gmallocn(scaledHeight, scaledWidth);
6857
0
      }
6858
0
      return new SavingImageScaler(src, srcData,
6859
0
           w, h, nComps, srcAlpha,
6860
0
           scaledWidth, scaledHeight,
6861
0
           interpolate,
6862
0
           imageCache->colorData,
6863
0
           imageCache->alphaData);
6864
0
    }
6865
0
  } else {
6866
0
    imageCache->reset(imageTag, scaledWidth, scaledHeight,
6867
0
          srcMode, srcAlpha, interpolate);
6868
0
    return new BasicImageScaler(src, srcData,
6869
0
        w, h, nComps, srcAlpha,
6870
0
        scaledWidth, scaledHeight,
6871
0
        interpolate);
6872
0
  }
6873
0
}
6874
6875
void Splash::getScaledImage(GString *imageTag,
6876
          SplashImageSource src, void *srcData,
6877
          int w, int h, int nComps,
6878
          int scaledWidth, int scaledHeight,
6879
          SplashColorMode srcMode,
6880
          GBool srcAlpha, GBool interpolate,
6881
          Guchar **scaledColor, Guchar **scaledAlpha,
6882
0
          GBool *freeScaledImage) {
6883
  // Notes:
6884
  //
6885
  // * If the scaled image is more than 8 Mpixels, we don't cache it.
6886
  //
6887
  // * This buffers the whole image anyway, so there's no reason to
6888
  //   skip caching on the first reuse.
6889
6890
0
  if (scaledWidth >= 8000000 / scaledHeight) {
6891
0
    int lineSize;
6892
0
    if (scaledWidth < INT_MAX / nComps) {
6893
0
      lineSize = scaledWidth * nComps;
6894
0
    } else {
6895
0
      lineSize = -1;
6896
0
    }
6897
0
    *scaledColor = (Guchar *)gmallocn(scaledHeight, lineSize);
6898
0
    if (srcAlpha) {
6899
0
      *scaledAlpha = (Guchar *)gmallocn(scaledHeight, scaledWidth);
6900
0
    } else {
6901
0
      *scaledAlpha = NULL;
6902
0
    }
6903
0
    *freeScaledImage = gTrue;
6904
0
    if (scaledWidth == w && scaledHeight == h) {
6905
0
      Guchar *colorPtr = *scaledColor;
6906
0
      Guchar *alphaPtr = *scaledAlpha;
6907
0
      for (int y = 0; y < scaledHeight; ++y) {
6908
0
  (*src)(srcData, colorPtr, alphaPtr);
6909
0
  colorPtr += scaledWidth * nComps;
6910
0
  if (srcAlpha) {
6911
0
    alphaPtr += scaledWidth;
6912
0
  }
6913
0
      }
6914
0
    } else {
6915
0
      BasicImageScaler scaler(src, srcData, w, h, nComps, srcAlpha,
6916
0
            scaledWidth, scaledHeight, interpolate);
6917
0
      Guchar *colorPtr = *scaledColor;
6918
0
      Guchar *alphaPtr = *scaledAlpha;
6919
0
      for (int y = 0; y < scaledHeight; ++y) {
6920
0
  scaler.nextLine();
6921
0
  memcpy(colorPtr, scaler.colorData(), scaledWidth * nComps);
6922
0
  colorPtr += scaledWidth * nComps;
6923
0
  if (srcAlpha) {
6924
0
    memcpy(alphaPtr, scaler.alphaData(), scaledWidth);
6925
0
    alphaPtr += scaledWidth;
6926
0
  }
6927
0
      }
6928
0
    }
6929
0
  } else {
6930
0
    if (!imageCache->match(imageTag, scaledWidth, scaledHeight,
6931
0
        srcMode, srcAlpha, interpolate) ||
6932
0
  !imageCache->colorData) {
6933
0
      imageCache->reset(imageTag, scaledWidth, scaledHeight,
6934
0
      srcMode, srcAlpha, interpolate);
6935
0
      int lineSize;
6936
0
      if (scaledWidth < INT_MAX / nComps) {
6937
0
  lineSize = scaledWidth * nComps;
6938
0
      } else {
6939
0
  lineSize = -1;
6940
0
      }
6941
0
      imageCache->colorData = (Guchar *)gmallocn(scaledHeight, lineSize);
6942
0
      if (srcAlpha) {
6943
0
  imageCache->alphaData = (Guchar *)gmallocn(scaledHeight, scaledWidth);
6944
0
      }
6945
0
      if (scaledWidth == w && scaledHeight == h) {
6946
0
  Guchar *colorPtr = imageCache->colorData;
6947
0
  Guchar *alphaPtr = imageCache->alphaData;
6948
0
  for (int y = 0; y < scaledHeight; ++y) {
6949
0
    (*src)(srcData, colorPtr, alphaPtr);
6950
0
    colorPtr += scaledWidth * nComps;
6951
0
    if (srcAlpha) {
6952
0
      alphaPtr += scaledWidth;
6953
0
    }
6954
0
  }
6955
0
      } else {
6956
0
  SavingImageScaler scaler(src, srcData, w, h, nComps, srcAlpha,
6957
0
         scaledWidth, scaledHeight, interpolate,
6958
0
         imageCache->colorData, imageCache->alphaData);
6959
0
  Guchar *colorPtr = imageCache->colorData;
6960
0
  Guchar *alphaPtr = imageCache->alphaData;
6961
0
  for (int y = 0; y < scaledHeight; ++y) {
6962
0
    scaler.nextLine();
6963
0
    memcpy(colorPtr, scaler.colorData(), scaledWidth * nComps);
6964
0
    colorPtr += scaledWidth * nComps;
6965
0
    if (srcAlpha) {
6966
0
      memcpy(alphaPtr, scaler.alphaData(), scaledWidth);
6967
0
      alphaPtr += scaledWidth;
6968
0
    }
6969
0
  }
6970
0
      }
6971
0
    }
6972
0
    *scaledColor = imageCache->colorData;
6973
0
    *scaledAlpha = imageCache->alphaData;
6974
0
    *freeScaledImage = gFalse;
6975
0
  }
6976
0
}
6977
6978
void Splash::drawImageArbitraryNoInterp(Guchar *scaledColor,
6979
          Guchar *scaledAlpha,
6980
          SplashDrawImageRowData *dd,
6981
          SplashDrawImageRowFunc drawRowFunc,
6982
          SplashCoord *invMat,
6983
          int scaledWidth, int scaledHeight,
6984
          int xMin, int yMin, int xMax, int yMax,
6985
0
          int nComps, GBool srcAlpha) {
6986
0
  int tt = state->clip->getXMinI(state->strokeAdjust);
6987
0
  if (tt > xMin) {
6988
0
    xMin = tt;
6989
0
  }
6990
0
  tt = state->clip->getXMaxI(state->strokeAdjust) + 1;
6991
0
  if (tt < xMax) {
6992
0
    xMax = tt;
6993
0
  }
6994
0
  tt = state->clip->getYMinI(state->strokeAdjust);
6995
0
  if (tt > yMin) {
6996
0
    yMin = tt;
6997
0
  }
6998
0
  tt = state->clip->getYMaxI(state->strokeAdjust) + 1;
6999
0
  if (tt < yMax) {
7000
0
    yMax = tt;
7001
0
  }
7002
0
  if (xMax <= xMin || yMax <= yMin) {
7003
0
    return;
7004
0
  }
7005
7006
0
  Guchar *colorBuf = (Guchar *)gmallocn(xMax - xMin, nComps);
7007
0
  Guchar *alphaBuf = NULL;
7008
0
  if (srcAlpha) {
7009
0
    alphaBuf = (Guchar *)gmalloc(xMax - xMin);
7010
0
  }
7011
7012
0
  for (int y = yMin; y < yMax; ++y) {
7013
0
    int rowMin = xMax;
7014
0
    int rowMax = 0;
7015
0
    for (int x = xMin; x < xMax; ++x) {
7016
      // note: invMat includes a "+0.5" factor so that this is really
7017
      // a multiply by (x+0.5, y+0.5)
7018
0
      int xx = splashFloor((SplashCoord)x * invMat[0]
7019
0
         + (SplashCoord)y * invMat[2] + invMat[4]);
7020
0
      int yy = splashFloor((SplashCoord)x * invMat[1]
7021
0
         + (SplashCoord)y * invMat[3] + invMat[5]);
7022
0
      if (xx >= 0 && xx < scaledWidth &&
7023
0
    yy >= 0 && yy < scaledHeight) {
7024
0
  Guchar *p = scaledColor + (yy * scaledWidth + xx) * nComps;
7025
0
  Guchar *q = colorBuf + (x - xMin) * nComps;
7026
0
  for (int i = 0; i < nComps; ++i) {
7027
0
    *q++ = *p++;
7028
0
  }
7029
0
  if (srcAlpha) {
7030
0
    alphaBuf[x - xMin] = scaledAlpha[yy * scaledWidth + xx];
7031
0
  }
7032
0
  if (x < rowMin) {
7033
0
    rowMin = x;
7034
0
  }
7035
0
  rowMax = x + 1;
7036
0
      }
7037
0
    }
7038
0
    if (rowMin < rowMax) {
7039
0
      (this->*drawRowFunc)(dd,
7040
0
         colorBuf + (rowMin - xMin) * nComps,
7041
0
         alphaBuf + (rowMin - xMin),
7042
0
         rowMin, y, rowMax - rowMin);
7043
0
    }
7044
0
  }
7045
7046
0
  gfree(colorBuf);
7047
0
  gfree(alphaBuf);
7048
0
}
7049
7050
void Splash::drawImageArbitraryInterp(Guchar *scaledColor, Guchar *scaledAlpha,
7051
              SplashDrawImageRowData *dd,
7052
              SplashDrawImageRowFunc drawRowFunc,
7053
              SplashCoord *invMat,
7054
              int scaledWidth, int scaledHeight,
7055
              int xMin, int yMin, int xMax, int yMax,
7056
0
              int nComps, GBool srcAlpha) {
7057
0
  int tt = state->clip->getXMinI(state->strokeAdjust);
7058
0
  if (tt > xMin) {
7059
0
    xMin = tt;
7060
0
  }
7061
0
  tt = state->clip->getXMaxI(state->strokeAdjust) + 1;
7062
0
  if (tt < xMax) {
7063
0
    xMax = tt;
7064
0
  }
7065
0
  tt = state->clip->getYMinI(state->strokeAdjust);
7066
0
  if (tt > yMin) {
7067
0
    yMin = tt;
7068
0
  }
7069
0
  tt = state->clip->getYMaxI(state->strokeAdjust) + 1;
7070
0
  if (tt < yMax) {
7071
0
    yMax = tt;
7072
0
  }
7073
0
  if (xMax <= xMin || yMax <= yMin) {
7074
0
    return;
7075
0
  }
7076
7077
0
  Guchar *colorBuf = (Guchar *)gmallocn(xMax - xMin, nComps);
7078
0
  Guchar *alphaBuf = NULL;
7079
0
  if (srcAlpha) {
7080
0
    alphaBuf = (Guchar *)gmalloc(xMax - xMin);
7081
0
  }
7082
7083
0
  for (int y = yMin; y < yMax; ++y) {
7084
0
    int rowMin = xMax;
7085
0
    int rowMax = 0;
7086
0
    for (int x = xMin; x < xMax; ++x) {
7087
      // note: invMat includes a "+0.5" factor so that this is really
7088
      // a multiply by (x+0.5, y+0.5)
7089
0
      SplashCoord xs = (SplashCoord)x * invMat[0]
7090
0
                 + (SplashCoord)y * invMat[2] + invMat[4];
7091
0
      SplashCoord ys = (SplashCoord)x * invMat[1]
7092
0
                 + (SplashCoord)y * invMat[3] + invMat[5];
7093
0
      int x0 = splashFloor(xs - 0.5);
7094
0
      int x1 = x0 + 1;
7095
0
      int y0 = splashFloor(ys - 0.5);
7096
0
      int y1 = y0 + 1;
7097
0
      if (x1 >= 0 && x0 < scaledWidth && y1 >= 0 && y0 < scaledHeight) {
7098
0
  SplashCoord sx0 = (SplashCoord)x1 + 0.5 - xs;
7099
0
  SplashCoord sx1 = (SplashCoord)1 - sx0;
7100
0
  SplashCoord sy0 = (SplashCoord)y1 + 0.5 - ys;
7101
0
  SplashCoord sy1 = (SplashCoord)1 - sy0;
7102
0
  if (x0 < 0) {
7103
0
    x0 = 0;
7104
0
  }
7105
0
  if (x1 >= scaledWidth) {
7106
0
    x1 = scaledWidth - 1;
7107
0
  }
7108
0
  if (y0 < 0) {
7109
0
    y0 = 0;
7110
0
  }
7111
0
  if (y1 >= scaledHeight) {
7112
0
    y1 = scaledHeight - 1;
7113
0
  }
7114
0
  Guchar *p00 = scaledColor + (y0 * scaledWidth + x0) * nComps;
7115
0
  Guchar *p10 = scaledColor + (y0 * scaledWidth + x1) * nComps;
7116
0
  Guchar *p01 = scaledColor + (y1 * scaledWidth + x0) * nComps;
7117
0
  Guchar *p11 = scaledColor + (y1 * scaledWidth + x1) * nComps;
7118
0
  Guchar *q = colorBuf + (x - xMin) * nComps;
7119
0
  for (int i = 0; i < nComps; ++i) {
7120
0
    *q++ = (Guchar)(int)(sx0 * (sy0 * (int)*p00++ + sy1 * (int)*p01++) +
7121
0
             sx1 * (sy0 * (int)*p10++ + sy1 * (int)*p11++));
7122
0
  }
7123
0
  if (srcAlpha) {
7124
0
    p00 = scaledAlpha + (y0 * scaledWidth + x0);
7125
0
    p10 = scaledAlpha + (y0 * scaledWidth + x1);
7126
0
    p01 = scaledAlpha + (y1 * scaledWidth + x0);
7127
0
    p11 = scaledAlpha + (y1 * scaledWidth + x1);
7128
0
    q = alphaBuf + (x - xMin);
7129
0
    *q = (Guchar)(int)(sx0 * (sy0 * (int)*p00 + sy1 * (int)*p01) +
7130
0
           sx1 * (sy0 * (int)*p10 + sy1 * (int)*p11));
7131
0
  }
7132
0
  if (x < rowMin) {
7133
0
    rowMin = x;
7134
0
  }
7135
0
  rowMax = x + 1;
7136
0
      }
7137
0
    }
7138
0
    if (rowMin < rowMax) {
7139
0
      (this->*drawRowFunc)(dd,
7140
0
         colorBuf + (rowMin - xMin) * nComps,
7141
0
         alphaBuf + (rowMin - xMin),
7142
0
         rowMin, y, rowMax - rowMin);
7143
0
    }
7144
0
  }
7145
7146
0
  gfree(colorBuf);
7147
0
  gfree(alphaBuf);
7148
0
}
7149
7150
void Splash::mirrorImageRow(Guchar *colorIn, Guchar *alphaIn,
7151
          Guchar *colorOut, Guchar *alphaOut,
7152
0
          int width, int nComps, GBool srcAlpha) {
7153
0
  Guchar *p, *q;
7154
7155
0
  p = colorIn;
7156
0
  q = colorOut + (width - 1) * nComps;
7157
0
  for (int i = 0; i < width; ++i) {
7158
0
    for (int j = 0; j < nComps; ++j) {
7159
0
      q[j] = p[j];
7160
0
    }
7161
0
    p += nComps;
7162
0
    q -= nComps;
7163
0
  }
7164
7165
0
  if (srcAlpha) {
7166
0
    p = alphaIn;
7167
0
    q = alphaOut + (width - 1);
7168
0
    for (int i = 0; i < width; ++i) {
7169
0
      *q = *p;
7170
0
      ++p;
7171
0
      --q;
7172
0
    }
7173
0
  }
7174
0
}
7175
7176
void Splash::drawImageRowNoClipNoAlpha(SplashDrawImageRowData *data,
7177
               Guchar *colorData, Guchar *alphaData,
7178
0
               int x, int y, int width) {
7179
0
  (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, NULL, colorData);
7180
0
}
7181
7182
void Splash::drawImageRowNoClipAlpha(SplashDrawImageRowData *data,
7183
             Guchar *colorData, Guchar *alphaData,
7184
0
             int x, int y, int width) {
7185
0
  (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y,
7186
0
        alphaData, colorData);
7187
0
}
7188
7189
void Splash::drawImageRowClipNoAlphaNoAA(SplashDrawImageRowData *data,
7190
           Guchar *colorData,
7191
           Guchar *alphaData,
7192
0
           int x, int y, int width) {
7193
0
  if (y < 0 || y >= bitmap->height) {
7194
0
    return;
7195
0
  }
7196
0
  if (x < 0) {
7197
0
    colorData -= x * data->nComps;
7198
0
    width += x;
7199
0
    x = 0;
7200
0
  }
7201
0
  if (x + width > bitmap->width) {
7202
0
    width = bitmap->width - x;
7203
0
  }
7204
0
  if (width <= 0) {
7205
0
    return;
7206
0
  }
7207
0
  memset(scanBuf + x, 0xff, width);
7208
0
  state->clip->clipSpanBinary(scanBuf, y, x, x + width - 1,
7209
0
            state->strokeAdjust);
7210
0
  (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y,
7211
0
        scanBuf + x, colorData);
7212
0
}
7213
7214
void Splash::drawImageRowClipNoAlphaAA(SplashDrawImageRowData *data,
7215
               Guchar *colorData,
7216
               Guchar *alphaData,
7217
0
               int x, int y, int width) {
7218
0
  if (y < 0 || y >= bitmap->height) {
7219
0
    return;
7220
0
  }
7221
0
  if (x < 0) {
7222
0
    colorData -= x * data->nComps;
7223
0
    width += x;
7224
0
    x = 0;
7225
0
  }
7226
0
  if (x + width > bitmap->width) {
7227
0
    width = bitmap->width - x;
7228
0
  }
7229
0
  if (width <= 0) {
7230
0
    return;
7231
0
  }
7232
0
  memset(scanBuf + x, 0xff, width);
7233
0
  state->clip->clipSpan(scanBuf, y, x, x + width - 1, state->strokeAdjust);
7234
0
  (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y,
7235
0
        scanBuf + x, colorData);
7236
0
}
7237
7238
void Splash::drawImageRowClipAlphaNoAA(SplashDrawImageRowData *data,
7239
               Guchar *colorData,
7240
               Guchar *alphaData,
7241
0
               int x, int y, int width) {
7242
0
  if (y < 0 || y >= bitmap->height) {
7243
0
    return;
7244
0
  }
7245
0
  if (x < 0) {
7246
0
    colorData -= x * data->nComps;
7247
0
    alphaData -= x;
7248
0
    width += x;
7249
0
    x = 0;
7250
0
  }
7251
0
  if (x + width > bitmap->width) {
7252
0
    width = bitmap->width - x;
7253
0
  }
7254
0
  if (width <= 0) {
7255
0
    return;
7256
0
  }
7257
0
  memcpy(scanBuf + x, alphaData, width);
7258
0
  state->clip->clipSpanBinary(scanBuf, y, x, x + width - 1,
7259
0
            state->strokeAdjust);
7260
0
  (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y,
7261
0
        scanBuf + x, colorData);
7262
0
}
7263
7264
void Splash::drawImageRowClipAlphaAA(SplashDrawImageRowData *data,
7265
             Guchar *colorData,
7266
             Guchar *alphaData,
7267
0
             int x, int y, int width) {
7268
0
  if (y < 0 || y >= bitmap->height) {
7269
0
    return;
7270
0
  }
7271
0
  if (x < 0) {
7272
0
    colorData -= x * data->nComps;
7273
0
    alphaData -= x;
7274
0
    width += x;
7275
0
    x = 0;
7276
0
  }
7277
0
  if (x + width > bitmap->width) {
7278
0
    width = bitmap->width - x;
7279
0
  }
7280
0
  if (width <= 0) {
7281
0
    return;
7282
0
  }
7283
0
  memcpy(scanBuf + x, alphaData, width);
7284
0
  state->clip->clipSpan(scanBuf, y, x, x + width - 1, state->strokeAdjust);
7285
0
  (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y,
7286
0
        scanBuf + x, colorData);
7287
0
}
7288
7289
SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc,
7290
            int xDest, int yDest, int w, int h,
7291
0
            GBool noClip, GBool nonIsolated) {
7292
0
  SplashPipe pipe;
7293
0
  Guchar *mono1Ptr, *lineBuf, *linePtr;
7294
0
  Guchar mono1Mask, b;
7295
0
  int x0, x1, x, y0, y1, y, t;
7296
7297
0
  if (!(src->mode == bitmap->mode ||
7298
0
  (src->mode == splashModeMono8 && bitmap->mode == splashModeMono1) ||
7299
0
  (src->mode == splashModeRGB8 && bitmap->mode == splashModeBGR8))) {
7300
0
    return splashErrModeMismatch;
7301
0
  }
7302
7303
0
  pipeInit(&pipe, NULL,
7304
0
     (Guchar)splashRound(state->fillAlpha * 255),
7305
0
     !noClip || src->alpha != NULL, nonIsolated);
7306
0
  if (src->mode == splashModeMono1) {
7307
    // in mono1 mode, pipeRun expects the source to be in mono8
7308
    // format, so we need to extract the source color values into
7309
    // scanBuf, expanding them from mono1 to mono8
7310
0
    if (noClip) {
7311
0
      if (src->alpha) {
7312
0
  for (y = 0; y < h; ++y) {
7313
0
    mono1Ptr = src->data + (ySrc + y) * src->rowSize + (xSrc >> 3);
7314
0
    mono1Mask = (Guchar)(0x80 >> (xSrc & 7));
7315
0
    for (x = 0; x < w; ++x) {
7316
0
      scanBuf[x] = (*mono1Ptr & mono1Mask) ? 0xff : 0x00;
7317
0
      mono1Ptr += mono1Mask & 1;
7318
0
      mono1Mask = (Guchar)((mono1Mask << 7) | (mono1Mask >> 1));
7319
0
    }
7320
    // this uses shape instead of alpha, which isn't technically
7321
    // correct, but works out the same
7322
0
    (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
7323
0
          src->alpha +
7324
0
            (ySrc + y) * src->alphaRowSize + xSrc,
7325
0
          scanBuf);
7326
0
  }
7327
0
      } else {
7328
0
  for (y = 0; y < h; ++y) {
7329
0
    mono1Ptr = src->data + (ySrc + y) * src->rowSize + (xSrc >> 3);
7330
0
    mono1Mask = (Guchar)(0x80 >> (xSrc & 7));
7331
0
    for (x = 0; x < w; ++x) {
7332
0
      scanBuf[x] = (*mono1Ptr & mono1Mask) ? 0xff : 0x00;
7333
0
      mono1Ptr += mono1Mask & 1;
7334
0
      mono1Mask = (Guchar)((mono1Mask << 7) | (mono1Mask >> 1));
7335
0
    }
7336
0
    (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
7337
0
          NULL,
7338
0
          scanBuf);
7339
0
  }
7340
0
      }
7341
0
    } else {
7342
0
      x0 = xDest;
7343
0
      if ((t = state->clip->getXMinI(state->strokeAdjust)) > x0) {
7344
0
  x0 = t;
7345
0
      }
7346
0
      x1 = xDest + w;
7347
0
      if ((t = state->clip->getXMaxI(state->strokeAdjust) + 1) < x1) {
7348
0
  x1 = t;
7349
0
      }
7350
0
      y0 = yDest;
7351
0
      if ((t = state->clip->getYMinI(state->strokeAdjust)) > y0) {
7352
0
  y0 = t;
7353
0
      }
7354
0
      y1 = yDest + h;
7355
0
      if ((t = state->clip->getYMaxI(state->strokeAdjust) + 1) < y1) {
7356
0
  y1 = t;
7357
0
      }
7358
0
      if (x0 < x1 && y0 < y1) {
7359
0
  if (src->alpha) {
7360
0
    for (y = y0; y < y1; ++y) {
7361
0
      mono1Ptr = src->data
7362
0
                 + (ySrc + y - yDest) * src->rowSize
7363
0
                 + ((xSrc + x0 - xDest) >> 3);
7364
0
      mono1Mask = (Guchar)(0x80 >> ((xSrc + x0 - xDest) & 7));
7365
0
      for (x = x0; x < x1; ++x) {
7366
0
        scanBuf[x] = (*mono1Ptr & mono1Mask) ? 0xff : 0x00;
7367
0
        mono1Ptr += mono1Mask & 1;
7368
0
        mono1Mask = (Guchar)((mono1Mask << 7) | (mono1Mask >> 1));
7369
0
      }
7370
0
      memcpy(scanBuf2 + x0,
7371
0
       src->alpha + (ySrc + y - yDest) * src->alphaRowSize + 
7372
0
         (xSrc + x0 - xDest),
7373
0
       x1 - x0);
7374
0
      if (!state->clip->clipSpanBinary(scanBuf2, y, x0, x1 - 1,
7375
0
               state->strokeAdjust)) {
7376
0
        continue;
7377
0
      }
7378
      // this uses shape instead of alpha, which isn't technically
7379
      // correct, but works out the same
7380
0
      (this->*pipe.run)(&pipe, x0, x1 - 1, y,
7381
0
            scanBuf2 + x0,
7382
0
            scanBuf + x0);
7383
0
    }
7384
0
  } else {
7385
0
    for (y = y0; y < y1; ++y) {
7386
0
      mono1Ptr = src->data
7387
0
                 + (ySrc + y - yDest) * src->rowSize
7388
0
                 + ((xSrc + x0 - xDest) >> 3);
7389
0
      mono1Mask = (Guchar)(0x80 >> ((xSrc + x0 - xDest) & 7));
7390
0
      for (x = x0; x < x1; ++x) {
7391
0
        scanBuf[x] = (*mono1Ptr & mono1Mask) ? 0xff : 0x00;
7392
0
        mono1Ptr += mono1Mask & 1;
7393
0
        mono1Mask = (Guchar)((mono1Mask << 7) | (mono1Mask >> 1));
7394
0
      }
7395
0
      memset(scanBuf2 + x0, 0xff, x1 - x0);
7396
0
      if (!state->clip->clipSpanBinary(scanBuf2, y, x0, x1 - 1,
7397
0
               state->strokeAdjust)) {
7398
0
        continue;
7399
0
      }
7400
0
      (this->*pipe.run)(&pipe, x0, x1 - 1, y,
7401
0
            scanBuf2 + x0,
7402
0
            scanBuf + x0);
7403
0
    }
7404
0
  }
7405
0
      }
7406
0
    }
7407
7408
0
  } else if (src->mode == splashModeBGR8) {
7409
    // in BGR8 mode, pipeRun expects the source to be in RGB8 format,
7410
    // so we need to swap bytes
7411
0
    lineBuf = (Guchar *)gmallocn(w, 3);
7412
0
    if (noClip) {
7413
0
      if (src->alpha) {
7414
0
  for (y = 0; y < h; ++y) {
7415
0
    memcpy(lineBuf,
7416
0
     src->data + (ySrc + y) * src->rowSize + xSrc * 3,
7417
0
     w * 3);
7418
0
    for (x = 0, linePtr = lineBuf; x < w; ++x, linePtr += 3) {
7419
0
      b = linePtr[0];
7420
0
      linePtr[0] = linePtr[2];
7421
0
      linePtr[2] = b;
7422
0
    }
7423
    // this uses shape instead of alpha, which isn't technically
7424
    // correct, but works out the same
7425
0
    (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
7426
0
          src->alpha +
7427
0
            (ySrc + y) * src->alphaRowSize + xSrc,
7428
0
          lineBuf);
7429
0
  }
7430
0
      } else {
7431
0
  for (y = 0; y < h; ++y) {
7432
0
    memcpy(lineBuf,
7433
0
     src->data + (ySrc + y) * src->rowSize + xSrc * 3,
7434
0
     w * 3);
7435
0
    for (x = 0, linePtr = lineBuf; x < w; ++x, linePtr += 3) {
7436
0
      b = linePtr[0];
7437
0
      linePtr[0] = linePtr[2];
7438
0
      linePtr[2] = b;
7439
0
    }
7440
0
    (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
7441
0
          NULL, lineBuf);
7442
0
  }
7443
0
      }
7444
0
    } else {
7445
0
      x0 = xDest;
7446
0
      if ((t = state->clip->getXMinI(state->strokeAdjust)) > x0) {
7447
0
  x0 = t;
7448
0
      }
7449
0
      x1 = xDest + w;
7450
0
      if ((t = state->clip->getXMaxI(state->strokeAdjust) + 1) < x1) {
7451
0
  x1 = t;
7452
0
      }
7453
0
      y0 = yDest;
7454
0
      if ((t = state->clip->getYMinI(state->strokeAdjust)) > y0) {
7455
0
  y0 = t;
7456
0
      }
7457
0
      y1 = yDest + h;
7458
0
      if ((t = state->clip->getYMaxI(state->strokeAdjust) + 1) < y1) {
7459
0
  y1 = t;
7460
0
      }
7461
0
      if (x0 < x1 && y0 < y1) {
7462
0
  if (src->alpha) {
7463
0
    for (y = y0; y < y1; ++y) {
7464
0
      memcpy(scanBuf + x0,
7465
0
       src->alpha + (ySrc + y - yDest) * src->alphaRowSize + 
7466
0
         (xSrc + x0 - xDest),
7467
0
       x1 - x0);
7468
0
      state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust);
7469
0
      memcpy(lineBuf,
7470
0
       src->data +
7471
0
         (ySrc + y - yDest) * src->rowSize +
7472
0
         (xSrc + x0 - xDest) * 3,
7473
0
       (x1 - x0) * 3);
7474
0
      for (x = 0, linePtr = lineBuf; x < x1 - x0; ++x, linePtr += 3) {
7475
0
        b = linePtr[0];
7476
0
        linePtr[0] = linePtr[2];
7477
0
        linePtr[2] = b;
7478
0
      }
7479
      // this uses shape instead of alpha, which isn't technically
7480
      // correct, but works out the same
7481
0
      (this->*pipe.run)(&pipe, x0, x1 - 1, y,
7482
0
            scanBuf + x0, lineBuf);
7483
0
    }
7484
0
  } else {
7485
0
    for (y = y0; y < y1; ++y) {
7486
0
      memset(scanBuf + x0, 0xff, x1 - x0);
7487
0
      state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust);
7488
0
      memcpy(lineBuf,
7489
0
       src->data +
7490
0
         (ySrc + y - yDest) * src->rowSize +
7491
0
         (xSrc + x0 - xDest) * 3,
7492
0
       (x1 - x0) * 3);
7493
0
      for (x = 0, linePtr = lineBuf; x < x1 - x0; ++x, linePtr += 3) {
7494
0
        b = linePtr[0];
7495
0
        linePtr[0] = linePtr[2];
7496
0
        linePtr[2] = b;
7497
0
      }
7498
0
      (this->*pipe.run)(&pipe, x0, x1 - 1, yDest + y,
7499
0
            scanBuf + x0,
7500
0
            src->data +
7501
0
              (ySrc + y - yDest) * src->rowSize +
7502
0
              (xSrc + x0 - xDest) * bitmapComps);
7503
0
    }
7504
0
  }
7505
0
      }
7506
0
    }
7507
0
    gfree(lineBuf);
7508
7509
0
  } else { // src->mode not mono1 or BGR8
7510
0
    if (noClip) {
7511
0
      if (src->alpha) {
7512
0
  for (y = 0; y < h; ++y) {
7513
    // this uses shape instead of alpha, which isn't technically
7514
    // correct, but works out the same
7515
0
    (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
7516
0
          src->alpha +
7517
0
            (ySrc + y) * src->alphaRowSize + xSrc,
7518
0
          src->data + (ySrc + y) * src->rowSize +
7519
0
            xSrc * bitmapComps);
7520
0
  }
7521
0
      } else {
7522
0
  for (y = 0; y < h; ++y) {
7523
0
    (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
7524
0
          NULL,
7525
0
          src->data + (ySrc + y) * src->rowSize +
7526
0
            xSrc * bitmapComps);
7527
0
  }
7528
0
      }
7529
0
    } else {
7530
0
      x0 = xDest;
7531
0
      if ((t = state->clip->getXMinI(state->strokeAdjust)) > x0) {
7532
0
  x0 = t;
7533
0
      }
7534
0
      x1 = xDest + w;
7535
0
      if ((t = state->clip->getXMaxI(state->strokeAdjust) + 1) < x1) {
7536
0
  x1 = t;
7537
0
      }
7538
0
      y0 = yDest;
7539
0
      if ((t = state->clip->getYMinI(state->strokeAdjust)) > y0) {
7540
0
  y0 = t;
7541
0
      }
7542
0
      y1 = yDest + h;
7543
0
      if ((t = state->clip->getYMaxI(state->strokeAdjust) + 1) < y1) {
7544
0
  y1 = t;
7545
0
      }
7546
0
      if (x0 < x1 && y0 < y1) {
7547
0
  if (src->alpha) {
7548
0
    for (y = y0; y < y1; ++y) {
7549
0
      memcpy(scanBuf + x0,
7550
0
       src->alpha + (ySrc + y - yDest) * src->alphaRowSize + 
7551
0
         (xSrc + x0 - xDest),
7552
0
       x1 - x0);
7553
0
      state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust);
7554
      // this uses shape instead of alpha, which isn't technically
7555
      // correct, but works out the same
7556
0
      (this->*pipe.run)(&pipe, x0, x1 - 1, y,
7557
0
            scanBuf + x0,
7558
0
            src->data +
7559
0
              (ySrc + y - yDest) * src->rowSize +
7560
0
              (xSrc + x0 - xDest) * bitmapComps);
7561
0
    }
7562
0
  } else {
7563
0
    for (y = y0; y < y1; ++y) {
7564
0
      memset(scanBuf + x0, 0xff, x1 - x0);
7565
0
      state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust);
7566
0
      (this->*pipe.run)(&pipe, x0, x1 - 1, yDest + y,
7567
0
            scanBuf + x0,
7568
0
            src->data +
7569
0
              (ySrc + y - yDest) * src->rowSize +
7570
0
              (xSrc + x0 - xDest) * bitmapComps);
7571
0
    }
7572
0
  }
7573
0
      }
7574
0
    }
7575
0
  }
7576
7577
0
  return splashOk;
7578
0
}
7579
7580
SplashError Splash::compositeWithOverprint(SplashBitmap *src,
7581
             Guint *srcOverprintMaskBitmap,
7582
             int xSrc, int ySrc,
7583
             int xDest, int yDest, int w, int h,
7584
0
             GBool noClip, GBool nonIsolated) {
7585
0
  SplashPipe pipe;
7586
0
  int x0, x1, y0, y1, y, t;
7587
7588
0
  if (!(src->mode == bitmap->mode ||
7589
0
  (src->mode == splashModeMono8 && bitmap->mode == splashModeMono1) ||
7590
0
  (src->mode == splashModeRGB8 && bitmap->mode == splashModeBGR8))) {
7591
0
    return splashErrModeMismatch;
7592
0
  }
7593
7594
0
  pipeInit(&pipe, NULL,
7595
0
     (Guchar)splashRound(state->fillAlpha * 255),
7596
0
     !noClip || src->alpha != NULL, nonIsolated, gTrue);
7597
7598
0
  if (noClip) {
7599
0
    if (src->alpha) {
7600
0
      for (y = 0; y < h; ++y) {
7601
0
  pipe.srcOverprintMaskPtr = srcOverprintMaskBitmap + y * w + xSrc;
7602
  // this uses shape instead of alpha, which isn't technically
7603
  // correct, but works out the same
7604
0
  (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
7605
0
        src->alpha +
7606
0
          (ySrc + y) * src->alphaRowSize + xSrc,
7607
0
        src->data + (ySrc + y) * src->rowSize +
7608
0
          xSrc * bitmapComps);
7609
0
      }
7610
0
    } else {
7611
0
      for (y = 0; y < h; ++y) {
7612
0
  pipe.srcOverprintMaskPtr = srcOverprintMaskBitmap + y * w + xSrc;
7613
0
  (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
7614
0
        NULL,
7615
0
        src->data + (ySrc + y) * src->rowSize +
7616
0
          xSrc * bitmapComps);
7617
0
      }
7618
0
    }
7619
0
  } else {
7620
0
    x0 = xDest;
7621
0
    if ((t = state->clip->getXMinI(state->strokeAdjust)) > x0) {
7622
0
      x0 = t;
7623
0
    }
7624
0
    x1 = xDest + w;
7625
0
    if ((t = state->clip->getXMaxI(state->strokeAdjust) + 1) < x1) {
7626
0
      x1 = t;
7627
0
    }
7628
0
    y0 = yDest;
7629
0
    if ((t = state->clip->getYMinI(state->strokeAdjust)) > y0) {
7630
0
      y0 = t;
7631
0
    }
7632
0
    y1 = yDest + h;
7633
0
    if ((t = state->clip->getYMaxI(state->strokeAdjust) + 1) < y1) {
7634
0
      y1 = t;
7635
0
    }
7636
0
    if (x0 < x1 && y0 < y1) {
7637
0
      if (src->alpha) {
7638
0
  for (y = y0; y < y1; ++y) {
7639
0
    memcpy(scanBuf + x0,
7640
0
     src->alpha + (ySrc + y - yDest) * src->alphaRowSize + 
7641
0
       (xSrc + x0 - xDest),
7642
0
     x1 - x0);
7643
0
    state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust);
7644
0
    pipe.srcOverprintMaskPtr = srcOverprintMaskBitmap
7645
0
                               + (ySrc + y - yDest) * w
7646
0
                               + (xSrc + x0 - xDest);
7647
    // this uses shape instead of alpha, which isn't technically
7648
    // correct, but works out the same
7649
0
    (this->*pipe.run)(&pipe, x0, x1 - 1, y,
7650
0
          scanBuf + x0,
7651
0
          src->data +
7652
0
            (ySrc + y - yDest) * src->rowSize +
7653
0
            (xSrc + x0 - xDest) * bitmapComps);
7654
0
  }
7655
0
      } else {
7656
0
  for (y = y0; y < y1; ++y) {
7657
0
    memset(scanBuf + x0, 0xff, x1 - x0);
7658
0
    state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust);
7659
0
    pipe.srcOverprintMaskPtr = srcOverprintMaskBitmap
7660
0
                               + (ySrc + y - yDest) * w
7661
0
                               + (xSrc + x0 - xDest);
7662
0
    (this->*pipe.run)(&pipe, x0, x1 - 1, y,
7663
0
          scanBuf + x0,
7664
0
          src->data +
7665
0
            (ySrc + y - yDest) * src->rowSize +
7666
0
            (xSrc + x0 - xDest) * bitmapComps);
7667
0
  }
7668
0
      }
7669
0
    }
7670
0
  }
7671
7672
0
  return splashOk;
7673
0
}
7674
7675
0
void Splash::compositeBackground(SplashColorPtr color) {
7676
0
  SplashColorPtr p;
7677
0
  Guchar *q;
7678
0
  Guchar alpha, alpha1, c, color0, color1, color2, mask;
7679
0
#if SPLASH_CMYK
7680
0
  Guchar color3;
7681
0
#endif
7682
0
  int x, y;
7683
7684
0
  switch (bitmap->mode) {
7685
0
  case splashModeMono1:
7686
0
    color0 = color[0];
7687
0
    for (y = 0; y < bitmap->height; ++y) {
7688
0
      p = &bitmap->data[y * bitmap->rowSize];
7689
0
      q = &bitmap->alpha[y * bitmap->alphaRowSize];
7690
0
      mask = 0x80;
7691
0
      for (x = 0; x < bitmap->width; ++x) {
7692
0
  alpha = *q++;
7693
0
  if (alpha == 0) {
7694
0
    if (color0 & 0x80) {
7695
0
      *p |= mask;
7696
0
    } else {
7697
0
      *p &= (Guchar)~mask;
7698
0
    }
7699
0
  } else if (alpha != 255) {
7700
0
    alpha1 = (Guchar)(255 - alpha);
7701
0
    c = (*p & mask) ? 0xff : 0x00;
7702
0
    c = div255(alpha1 * color0 + alpha * c);
7703
0
    if (c & 0x80) {
7704
0
      *p |= mask;
7705
0
    } else {
7706
0
      *p &= (Guchar)~mask;
7707
0
    }
7708
0
  }
7709
0
  if (!(mask = (Guchar)(mask >> 1))) {
7710
0
    mask = 0x80;
7711
0
    ++p;
7712
0
  }
7713
0
      }
7714
0
    }
7715
0
    break;
7716
0
  case splashModeMono8:
7717
0
    color0 = color[0];
7718
0
    for (y = 0; y < bitmap->height; ++y) {
7719
0
      p = &bitmap->data[y * bitmap->rowSize];
7720
0
      q = &bitmap->alpha[y * bitmap->alphaRowSize];
7721
0
      for (x = 0; x < bitmap->width; ++x) {
7722
0
  alpha = *q++;
7723
0
  if (alpha == 0) {
7724
0
    p[0] = color0;
7725
0
  } else if (alpha != 255) {
7726
0
    alpha1 = (Guchar)(255 - alpha);
7727
0
    p[0] = div255(alpha1 * color0 + alpha * p[0]);
7728
0
  }
7729
0
  ++p;
7730
0
      }
7731
0
    }
7732
0
    break;
7733
0
  case splashModeRGB8:
7734
0
  case splashModeBGR8:
7735
0
    color0 = color[0];
7736
0
    color1 = color[1];
7737
0
    color2 = color[2];
7738
0
    for (y = 0; y < bitmap->height; ++y) {
7739
0
      p = &bitmap->data[y * bitmap->rowSize];
7740
0
      q = &bitmap->alpha[y * bitmap->alphaRowSize];
7741
0
      for (x = 0; x < bitmap->width; ++x) {
7742
0
  alpha = *q++;
7743
0
  if (alpha == 0) {
7744
0
    p[0] = color0;
7745
0
    p[1] = color1;
7746
0
    p[2] = color2;
7747
0
  } else if (alpha != 255) {
7748
0
    alpha1 = (Guchar)(255 - alpha);
7749
0
    p[0] = div255(alpha1 * color0 + alpha * p[0]);
7750
0
    p[1] = div255(alpha1 * color1 + alpha * p[1]);
7751
0
    p[2] = div255(alpha1 * color2 + alpha * p[2]);
7752
0
  }
7753
0
  p += 3;
7754
0
      }
7755
0
    }
7756
0
    break;
7757
0
#if SPLASH_CMYK
7758
0
  case splashModeCMYK8:
7759
0
    color0 = color[0];
7760
0
    color1 = color[1];
7761
0
    color2 = color[2];
7762
0
    color3 = color[3];
7763
0
    for (y = 0; y < bitmap->height; ++y) {
7764
0
      p = &bitmap->data[y * bitmap->rowSize];
7765
0
      q = &bitmap->alpha[y * bitmap->alphaRowSize];
7766
0
      for (x = 0; x < bitmap->width; ++x) {
7767
0
  alpha = *q++;
7768
0
  if (alpha == 0) {
7769
0
    p[0] = color0;
7770
0
    p[1] = color1;
7771
0
    p[2] = color2;
7772
0
    p[3] = color3;
7773
0
  } else if (alpha != 255) {
7774
0
    alpha1 = (Guchar)(255 - alpha);
7775
0
    p[0] = div255(alpha1 * color0 + alpha * p[0]);
7776
0
    p[1] = div255(alpha1 * color1 + alpha * p[1]);
7777
0
    p[2] = div255(alpha1 * color2 + alpha * p[2]);
7778
0
    p[3] = div255(alpha1 * color3 + alpha * p[3]);
7779
0
  }
7780
0
  p += 4;
7781
0
      }
7782
0
    }
7783
0
    break;
7784
0
#endif
7785
0
  }
7786
0
  memset(bitmap->alpha, 255, bitmap->alphaRowSize * bitmap->height);
7787
0
}
7788
7789
SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
7790
0
            int xDest, int yDest, int w, int h) {
7791
0
  SplashColorPtr p, q;
7792
0
  Guchar mask, srcMask;
7793
0
  int x, y;
7794
7795
0
  if (src->mode != bitmap->mode) {
7796
0
    return splashErrModeMismatch;
7797
0
  }
7798
7799
0
  switch (bitmap->mode) {
7800
0
  case splashModeMono1:
7801
0
    for (y = 0; y < h; ++y) {
7802
0
      p = &bitmap->data[(yDest + y) * bitmap->rowSize + (xDest >> 3)];
7803
0
      mask = (Guchar)(0x80 >> (xDest & 7));
7804
0
      q = &src->data[(ySrc + y) * src->rowSize + (xSrc >> 3)];
7805
0
      srcMask = (Guchar)(0x80 >> (xSrc & 7));
7806
0
      for (x = 0; x < w; ++x) {
7807
0
  if (*q & srcMask) {
7808
0
    *p |= mask;
7809
0
  } else {
7810
0
    *p &= (Guchar)~mask;
7811
0
  }
7812
0
  if (!(mask = (Guchar)(mask >> 1))) {
7813
0
    mask = 0x80;
7814
0
    ++p;
7815
0
  }
7816
0
  if (!(srcMask = (Guchar)(srcMask >> 1))) {
7817
0
    srcMask = 0x80;
7818
0
    ++q;
7819
0
  }
7820
0
      }
7821
0
    }
7822
0
    break;
7823
0
  case splashModeMono8:
7824
0
    for (y = 0; y < h; ++y) {
7825
0
      p = &bitmap->data[(yDest + y) * bitmap->rowSize + xDest];
7826
0
      q = &src->data[(ySrc + y) * src->rowSize + xSrc];
7827
0
      memcpy(p, q, w);
7828
0
    }
7829
0
    break;
7830
0
  case splashModeRGB8:
7831
0
  case splashModeBGR8:
7832
0
    for (y = 0; y < h; ++y) {
7833
0
      p = &bitmap->data[(yDest + y) * bitmap->rowSize + 3 * xDest];
7834
0
      q = &src->data[(ySrc + y) * src->rowSize + 3 * xSrc];
7835
0
      memcpy(p, q, 3 * w);
7836
0
    }
7837
0
    break;
7838
0
#if SPLASH_CMYK
7839
0
  case splashModeCMYK8:
7840
0
    for (y = 0; y < h; ++y) {
7841
0
      p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest];
7842
0
      q = &src->data[(ySrc + y) * src->rowSize + 4 * xSrc];
7843
0
      memcpy(p, q, 4 * w);
7844
0
    }
7845
0
    break;
7846
0
#endif
7847
0
  }
7848
7849
0
  if (bitmap->alpha) {
7850
0
    for (y = 0; y < h; ++y) {
7851
0
      q = &bitmap->alpha[(yDest + y) * bitmap->alphaRowSize + xDest];
7852
0
      memset(q, 0, w);
7853
0
    }
7854
0
  }
7855
7856
0
  return splashOk;
7857
0
}
7858
7859
SplashError Splash::blitCorrectedAlpha(SplashBitmap *dest, int xSrc, int ySrc,
7860
0
               int xDest, int yDest, int w, int h) {
7861
0
  SplashColorPtr p, q;
7862
0
  Guchar *alpha0Ptr;
7863
0
  Guchar alpha0, aSrc, mask, srcMask;
7864
0
  int x, y;
7865
7866
0
  if (bitmap->mode != dest->mode ||
7867
0
      !bitmap->alpha ||
7868
0
      !dest->alpha ||
7869
0
      !groupBackBitmap) {
7870
0
    return splashErrModeMismatch;
7871
0
  }
7872
7873
0
  switch (bitmap->mode) {
7874
0
  case splashModeMono1:
7875
0
    for (y = 0; y < h; ++y) {
7876
0
      p = &dest->data[(yDest + y) * dest->rowSize + (xDest >> 3)];
7877
0
      mask = (Guchar)(0x80 >> (xDest & 7));
7878
0
      q = &bitmap->data[(ySrc + y) * bitmap->rowSize + (xSrc >> 3)];
7879
0
      srcMask = (Guchar)(0x80 >> (xSrc & 7));
7880
0
      for (x = 0; x < w; ++x) {
7881
0
  if (*q & srcMask) {
7882
0
    *p |= mask;
7883
0
  } else {
7884
0
    *p &= (Guchar)~mask;
7885
0
  }
7886
0
  if (!(mask = (Guchar)(mask >> 1))) {
7887
0
    mask = 0x80;
7888
0
    ++p;
7889
0
  }
7890
0
  if (!(srcMask = (Guchar)(srcMask >> 1))) {
7891
0
    srcMask = 0x80;
7892
0
    ++q;
7893
0
  }
7894
0
      }
7895
0
    }
7896
0
    break;
7897
0
  case splashModeMono8:
7898
0
    for (y = 0; y < h; ++y) {
7899
0
      p = &dest->data[(yDest + y) * dest->rowSize + xDest];
7900
0
      q = &bitmap->data[(ySrc + y) * bitmap->rowSize + xSrc];
7901
0
      memcpy(p, q, w);
7902
0
    }
7903
0
    break;
7904
0
  case splashModeRGB8:
7905
0
  case splashModeBGR8:
7906
0
    for (y = 0; y < h; ++y) {
7907
0
      p = &dest->data[(yDest + y) * dest->rowSize + 3 * xDest];
7908
0
      q = &bitmap->data[(ySrc + y) * bitmap->rowSize + 3 * xSrc];
7909
0
      memcpy(p, q, 3 * w);
7910
0
    }
7911
0
    break;
7912
0
#if SPLASH_CMYK
7913
0
  case splashModeCMYK8:
7914
0
    for (y = 0; y < h; ++y) {
7915
0
      p = &dest->data[(yDest + y) * dest->rowSize + 4 * xDest];
7916
0
      q = &bitmap->data[(ySrc + y) * bitmap->rowSize + 4 * xSrc];
7917
0
      memcpy(p, q, 4 * w);
7918
0
    }
7919
0
    break;
7920
0
#endif
7921
0
  }
7922
7923
0
  for (y = 0; y < h; ++y) {
7924
0
    p = &dest->alpha[(yDest + y) * dest->alphaRowSize + xDest];
7925
0
    q = &bitmap->alpha[(ySrc + y) * bitmap->alphaRowSize + xSrc];
7926
0
    alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + ySrc + y)
7927
0
            * groupBackBitmap->alphaRowSize +
7928
0
          (groupBackX + xSrc)];
7929
0
    for (x = 0; x < w; ++x) {
7930
0
      alpha0 = *alpha0Ptr++;
7931
0
      aSrc = *q++;
7932
0
      *p++ = (Guchar)(alpha0 + aSrc - div255(alpha0 * aSrc));
7933
0
    }
7934
0
  }
7935
7936
0
  return splashOk;
7937
0
}
7938
7939
SplashPath *Splash::makeStrokePath(SplashPath *path, SplashCoord w,
7940
           int lineCap, int lineJoin,
7941
0
           GBool flatten) {
7942
0
  SplashPath *pathIn, *dashPath, *pathOut;
7943
0
  SplashCoord d, dx, dy, wdx, wdy, dxNext, dyNext, wdxNext, wdyNext;
7944
0
  SplashCoord crossprod, dotprod, miter, m;
7945
0
  SplashCoord angle, angleNext, dAngle, xc, yc;
7946
0
  SplashCoord dxJoin, dyJoin, dJoin, kappa;
7947
0
  SplashCoord cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
7948
0
  GBool first, last, closed;
7949
0
  int subpathStart0, subpathStart1, seg, i0, i1, j0, j1, k0, k1;
7950
0
  int left0, left1, left2, right0, right1, right2, join0, join1, join2;
7951
0
  int leftFirst, rightFirst, firstPt;
7952
7953
0
  pathOut = new SplashPath();
7954
7955
0
  if (path->length == 0) {
7956
0
    return pathOut;
7957
0
  }
7958
7959
0
  if (flatten) {
7960
0
    pathIn = flattenPath(path, state->matrix, state->flatness);
7961
0
    if (state->lineDashLength > 0) {
7962
0
      dashPath = makeDashedPath(pathIn);
7963
0
      delete pathIn;
7964
0
      pathIn = dashPath;
7965
0
      if (pathIn->length == 0) {
7966
0
  delete pathIn;
7967
0
  return pathOut;
7968
0
      }
7969
0
    }
7970
0
  } else {
7971
0
    pathIn = path;
7972
0
  }
7973
7974
0
  subpathStart0 = subpathStart1 = 0; // make gcc happy
7975
0
  seg = 0; // make gcc happy
7976
0
  closed = gFalse; // make gcc happy
7977
0
  left0 = left1 = right0 = right1 = join0 = join1 = 0; // make gcc happy
7978
0
  leftFirst = rightFirst = firstPt = 0; // make gcc happy
7979
7980
0
  i0 = 0;
7981
0
  for (i1 = i0;
7982
0
       !(pathIn->flags[i1] & splashPathLast) &&
7983
0
   i1 + 1 < pathIn->length &&
7984
0
   pathIn->pts[i1+1].x == pathIn->pts[i1].x &&
7985
0
   pathIn->pts[i1+1].y == pathIn->pts[i1].y;
7986
0
       ++i1) ;
7987
7988
0
  while (i1 < pathIn->length) {
7989
0
    if ((first = pathIn->flags[i0] & splashPathFirst)) {
7990
0
      subpathStart0 = i0;
7991
0
      subpathStart1 = i1;
7992
0
      seg = 0;
7993
0
      closed = pathIn->flags[i0] & splashPathClosed;
7994
0
    }
7995
0
    j0 = i1 + 1;
7996
0
    if (j0 < pathIn->length) {
7997
0
      for (j1 = j0;
7998
0
     !(pathIn->flags[j1] & splashPathLast) &&
7999
0
       j1 + 1 < pathIn->length &&
8000
0
       pathIn->pts[j1+1].x == pathIn->pts[j1].x &&
8001
0
       pathIn->pts[j1+1].y == pathIn->pts[j1].y;
8002
0
     ++j1) ;
8003
0
    } else {
8004
0
      j1 = j0;
8005
0
    }
8006
0
    if (pathIn->flags[i1] & splashPathLast) {
8007
0
      if (first && lineCap == splashLineCapRound) {
8008
  // special case: zero-length subpath with round line caps -->
8009
  // draw a circle
8010
0
  pathOut->moveTo(pathIn->pts[i0].x + (SplashCoord)0.5 * w,
8011
0
      pathIn->pts[i0].y);
8012
0
  pathOut->curveTo(pathIn->pts[i0].x + (SplashCoord)0.5 * w,
8013
0
       pathIn->pts[i0].y + bezierCircle2 * w,
8014
0
       pathIn->pts[i0].x + bezierCircle2 * w,
8015
0
       pathIn->pts[i0].y + (SplashCoord)0.5 * w,
8016
0
       pathIn->pts[i0].x,
8017
0
       pathIn->pts[i0].y + (SplashCoord)0.5 * w);
8018
0
  pathOut->curveTo(pathIn->pts[i0].x - bezierCircle2 * w,
8019
0
       pathIn->pts[i0].y + (SplashCoord)0.5 * w,
8020
0
       pathIn->pts[i0].x - (SplashCoord)0.5 * w,
8021
0
       pathIn->pts[i0].y + bezierCircle2 * w,
8022
0
       pathIn->pts[i0].x - (SplashCoord)0.5 * w,
8023
0
       pathIn->pts[i0].y);
8024
0
  pathOut->curveTo(pathIn->pts[i0].x - (SplashCoord)0.5 * w,
8025
0
       pathIn->pts[i0].y - bezierCircle2 * w,
8026
0
       pathIn->pts[i0].x - bezierCircle2 * w,
8027
0
       pathIn->pts[i0].y - (SplashCoord)0.5 * w,
8028
0
       pathIn->pts[i0].x,
8029
0
       pathIn->pts[i0].y - (SplashCoord)0.5 * w);
8030
0
  pathOut->curveTo(pathIn->pts[i0].x + bezierCircle2 * w,
8031
0
       pathIn->pts[i0].y - (SplashCoord)0.5 * w,
8032
0
       pathIn->pts[i0].x + (SplashCoord)0.5 * w,
8033
0
       pathIn->pts[i0].y - bezierCircle2 * w,
8034
0
       pathIn->pts[i0].x + (SplashCoord)0.5 * w,
8035
0
       pathIn->pts[i0].y);
8036
0
  pathOut->close();
8037
0
      }
8038
0
      i0 = j0;
8039
0
      i1 = j1;
8040
0
      continue;
8041
0
    }
8042
0
    last = pathIn->flags[j1] & splashPathLast;
8043
0
    if (last) {
8044
0
      k0 = subpathStart1 + 1;
8045
0
    } else {
8046
0
      k0 = j1 + 1;
8047
0
    }
8048
0
    for (k1 = k0;
8049
0
   !(pathIn->flags[k1] & splashPathLast) &&
8050
0
     k1 + 1 < pathIn->length &&
8051
0
     pathIn->pts[k1+1].x == pathIn->pts[k1].x &&
8052
0
     pathIn->pts[k1+1].y == pathIn->pts[k1].y;
8053
0
   ++k1) ;
8054
8055
    // compute the deltas for segment (i1, j0)
8056
#if USE_FIXEDPOINT
8057
    // the 1/d value can be small, which introduces significant
8058
    // inaccuracies in fixed point mode
8059
    d = splashDist(pathIn->pts[i1].x, pathIn->pts[i1].y,
8060
       pathIn->pts[j0].x, pathIn->pts[j0].y);
8061
    dx = (pathIn->pts[j0].x - pathIn->pts[i1].x) / d;
8062
    dy = (pathIn->pts[j0].y - pathIn->pts[i1].y) / d;
8063
#else
8064
0
    d = (SplashCoord)1 / splashDist(pathIn->pts[i1].x, pathIn->pts[i1].y,
8065
0
            pathIn->pts[j0].x, pathIn->pts[j0].y);
8066
0
    dx = d * (pathIn->pts[j0].x - pathIn->pts[i1].x);
8067
0
    dy = d * (pathIn->pts[j0].y - pathIn->pts[i1].y);
8068
0
#endif
8069
0
    wdx = (SplashCoord)0.5 * w * dx;
8070
0
    wdy = (SplashCoord)0.5 * w * dy;
8071
8072
    // draw the start cap
8073
0
    if (i0 == subpathStart0) {
8074
0
      firstPt = pathOut->length;
8075
0
    }
8076
0
    if (first && !closed) {
8077
0
      switch (lineCap) {
8078
0
      case splashLineCapButt:
8079
0
  pathOut->moveTo(pathIn->pts[i0].x - wdy, pathIn->pts[i0].y + wdx);
8080
0
  pathOut->lineTo(pathIn->pts[i0].x + wdy, pathIn->pts[i0].y - wdx);
8081
0
  break;
8082
0
      case splashLineCapRound:
8083
0
  pathOut->moveTo(pathIn->pts[i0].x - wdy, pathIn->pts[i0].y + wdx);
8084
0
  pathOut->curveTo(pathIn->pts[i0].x - wdy - bezierCircle * wdx,
8085
0
       pathIn->pts[i0].y + wdx - bezierCircle * wdy,
8086
0
       pathIn->pts[i0].x - wdx - bezierCircle * wdy,
8087
0
       pathIn->pts[i0].y - wdy + bezierCircle * wdx,
8088
0
       pathIn->pts[i0].x - wdx,
8089
0
       pathIn->pts[i0].y - wdy);
8090
0
  pathOut->curveTo(pathIn->pts[i0].x - wdx + bezierCircle * wdy,
8091
0
       pathIn->pts[i0].y - wdy - bezierCircle * wdx,
8092
0
       pathIn->pts[i0].x + wdy - bezierCircle * wdx,
8093
0
       pathIn->pts[i0].y - wdx - bezierCircle * wdy,
8094
0
       pathIn->pts[i0].x + wdy,
8095
0
       pathIn->pts[i0].y - wdx);
8096
0
  break;
8097
0
      case splashLineCapProjecting:
8098
0
  pathOut->moveTo(pathIn->pts[i0].x - wdx - wdy,
8099
0
      pathIn->pts[i0].y + wdx - wdy);
8100
0
  pathOut->lineTo(pathIn->pts[i0].x - wdx + wdy,
8101
0
      pathIn->pts[i0].y - wdx - wdy);
8102
0
  break;
8103
0
      }
8104
0
    } else {
8105
0
      pathOut->moveTo(pathIn->pts[i0].x - wdy, pathIn->pts[i0].y + wdx);
8106
0
      pathOut->lineTo(pathIn->pts[i0].x + wdy, pathIn->pts[i0].y - wdx);
8107
0
    }
8108
8109
    // draw the left side of the segment rectangle and the end cap
8110
0
    left2 = pathOut->length - 1;
8111
0
    if (last && !closed) {
8112
0
      switch (lineCap) {
8113
0
      case splashLineCapButt:
8114
0
  pathOut->lineTo(pathIn->pts[j0].x + wdy, pathIn->pts[j0].y - wdx);
8115
0
  pathOut->lineTo(pathIn->pts[j0].x - wdy, pathIn->pts[j0].y + wdx);
8116
0
  break;
8117
0
      case splashLineCapRound:
8118
0
  pathOut->lineTo(pathIn->pts[j0].x + wdy, pathIn->pts[j0].y - wdx);
8119
0
  pathOut->curveTo(pathIn->pts[j0].x + wdy + bezierCircle * wdx,
8120
0
       pathIn->pts[j0].y - wdx + bezierCircle * wdy,
8121
0
       pathIn->pts[j0].x + wdx + bezierCircle * wdy,
8122
0
       pathIn->pts[j0].y + wdy - bezierCircle * wdx,
8123
0
       pathIn->pts[j0].x + wdx,
8124
0
       pathIn->pts[j0].y + wdy);
8125
0
  pathOut->curveTo(pathIn->pts[j0].x + wdx - bezierCircle * wdy,
8126
0
       pathIn->pts[j0].y + wdy + bezierCircle * wdx,
8127
0
       pathIn->pts[j0].x - wdy + bezierCircle * wdx,
8128
0
       pathIn->pts[j0].y + wdx + bezierCircle * wdy,
8129
0
       pathIn->pts[j0].x - wdy,
8130
0
       pathIn->pts[j0].y + wdx);
8131
0
  break;
8132
0
      case splashLineCapProjecting:
8133
0
  pathOut->lineTo(pathIn->pts[j0].x + wdy + wdx,
8134
0
      pathIn->pts[j0].y - wdx + wdy);
8135
0
  pathOut->lineTo(pathIn->pts[j0].x - wdy + wdx,
8136
0
      pathIn->pts[j0].y + wdx + wdy);
8137
0
  break;
8138
0
      }
8139
0
    } else {
8140
0
      pathOut->lineTo(pathIn->pts[j0].x + wdy, pathIn->pts[j0].y - wdx);
8141
0
      pathOut->lineTo(pathIn->pts[j0].x - wdy, pathIn->pts[j0].y + wdx);
8142
0
    }
8143
8144
    // draw the right side of the segment rectangle
8145
    // (NB: if stroke adjustment is enabled, the closepath operation MUST
8146
    // add a segment because this segment is used for a hint)
8147
0
    right2 = pathOut->length - 1;
8148
0
    pathOut->close(state->strokeAdjust != splashStrokeAdjustOff);
8149
8150
    // draw the join
8151
0
    join2 = pathOut->length;
8152
0
    if (!last || closed) {
8153
8154
      // compute the deltas for segment (j1, k0)
8155
#if USE_FIXEDPOINT
8156
      // the 1/d value can be small, which introduces significant
8157
      // inaccuracies in fixed point mode
8158
      d = splashDist(pathIn->pts[j1].x, pathIn->pts[j1].y,
8159
         pathIn->pts[k0].x, pathIn->pts[k0].y);
8160
      dxNext = (pathIn->pts[k0].x - pathIn->pts[j1].x) / d;
8161
      dyNext = (pathIn->pts[k0].y - pathIn->pts[j1].y) / d;
8162
#else
8163
0
      d = (SplashCoord)1 / splashDist(pathIn->pts[j1].x, pathIn->pts[j1].y,
8164
0
              pathIn->pts[k0].x, pathIn->pts[k0].y);
8165
0
      dxNext = d * (pathIn->pts[k0].x - pathIn->pts[j1].x);
8166
0
      dyNext = d * (pathIn->pts[k0].y - pathIn->pts[j1].y);
8167
0
#endif
8168
0
      wdxNext = (SplashCoord)0.5 * w * dxNext;
8169
0
      wdyNext = (SplashCoord)0.5 * w * dyNext;
8170
8171
      // compute the join parameters
8172
0
      crossprod = dx * dyNext - dy * dxNext;
8173
0
      dotprod = -(dx * dxNext + dy * dyNext);
8174
0
      if (dotprod > 0.9999) {
8175
  // avoid a divide-by-zero -- set miter to something arbitrary
8176
  // such that sqrt(miter) will exceed miterLimit (and m is never
8177
  // used in that situation)
8178
  // (note: the comparison value (0.9999) has to be less than
8179
  // 1-epsilon, where epsilon is the smallest value
8180
  // representable in the fixed point format)
8181
0
  miter = (state->miterLimit + 1) * (state->miterLimit + 1);
8182
0
  m = 0;
8183
0
      } else {
8184
0
  miter = (SplashCoord)2 / ((SplashCoord)1 - dotprod);
8185
0
  if (miter < 1) {
8186
    // this can happen because of floating point inaccuracies
8187
0
    miter = 1;
8188
0
  }
8189
0
  m = splashSqrt(miter - 1);
8190
0
      }
8191
8192
      // round join
8193
0
      if (lineJoin == splashLineJoinRound) {
8194
  // join angle < 180
8195
0
  if (crossprod < 0) {
8196
0
    angle = atan2((double)dx, (double)-dy);
8197
0
    angleNext = atan2((double)dxNext, (double)-dyNext);
8198
0
    if (angle < angleNext) {
8199
0
      angle += 2 * M_PI;
8200
0
    }
8201
0
    dAngle = (angle  - angleNext) / M_PI;
8202
0
    if (dAngle < 0.501) {
8203
      // span angle is <= 90 degrees -> draw a single arc
8204
0
      kappa = dAngle * bezierCircle * w;
8205
0
      cx1 = pathIn->pts[j0].x - wdy + kappa * dx;
8206
0
      cy1 = pathIn->pts[j0].y + wdx + kappa * dy;
8207
0
      cx2 = pathIn->pts[j0].x - wdyNext - kappa * dxNext;
8208
0
      cy2 = pathIn->pts[j0].y + wdxNext - kappa * dyNext;
8209
0
      pathOut->moveTo(pathIn->pts[j0].x, pathIn->pts[j0].y);
8210
0
      pathOut->lineTo(pathIn->pts[j0].x - wdyNext,
8211
0
          pathIn->pts[j0].y + wdxNext);
8212
0
      pathOut->curveTo(cx2, cy2, cx1, cy1,
8213
0
           pathIn->pts[j0].x - wdy,
8214
0
           pathIn->pts[j0].y + wdx);
8215
0
    } else {
8216
      // span angle is > 90 degrees -> split into two arcs
8217
0
      dJoin = splashDist(-wdy, wdx, -wdyNext, wdxNext);
8218
0
      if (dJoin > 0) {
8219
0
        dxJoin = (-wdyNext + wdy) / dJoin;
8220
0
        dyJoin = (wdxNext - wdx) / dJoin;
8221
0
        xc = pathIn->pts[j0].x
8222
0
       + (SplashCoord)0.5 * w
8223
0
         * cos((double)((SplashCoord)0.5 * (angle + angleNext)));
8224
0
        yc = pathIn->pts[j0].y
8225
0
       + (SplashCoord)0.5 * w
8226
0
         * sin((double)((SplashCoord)0.5 * (angle + angleNext)));
8227
0
        kappa = dAngle * bezierCircle2 * w;
8228
0
        cx1 = pathIn->pts[j0].x - wdy + kappa * dx;
8229
0
        cy1 = pathIn->pts[j0].y + wdx + kappa * dy;
8230
0
        cx2 = xc - kappa * dxJoin;
8231
0
        cy2 = yc - kappa * dyJoin;
8232
0
        cx3 = xc + kappa * dxJoin;
8233
0
        cy3 = yc + kappa * dyJoin;
8234
0
        cx4 = pathIn->pts[j0].x - wdyNext - kappa * dxNext;
8235
0
        cy4 = pathIn->pts[j0].y + wdxNext - kappa * dyNext;
8236
0
        pathOut->moveTo(pathIn->pts[j0].x, pathIn->pts[j0].y);
8237
0
        pathOut->lineTo(pathIn->pts[j0].x - wdyNext,
8238
0
            pathIn->pts[j0].y + wdxNext);
8239
0
        pathOut->curveTo(cx4, cy4, cx3, cy3, xc, yc);
8240
0
        pathOut->curveTo(cx2, cy2, cx1, cy1,
8241
0
             pathIn->pts[j0].x - wdy,
8242
0
             pathIn->pts[j0].y + wdx);
8243
0
      }
8244
0
    }
8245
8246
  // join angle >= 180
8247
0
  } else {
8248
0
    angle = atan2((double)-dx, (double)dy);
8249
0
    angleNext = atan2((double)-dxNext, (double)dyNext);
8250
0
    if (angleNext < angle) {
8251
0
      angleNext += 2 * M_PI;
8252
0
    }
8253
0
    dAngle = (angleNext - angle) / M_PI;
8254
0
    if (dAngle < 0.501) {
8255
      // span angle is <= 90 degrees -> draw a single arc
8256
0
      kappa = dAngle * bezierCircle * w;
8257
0
        cx1 = pathIn->pts[j0].x + wdy + kappa * dx;
8258
0
        cy1 = pathIn->pts[j0].y - wdx + kappa * dy;
8259
0
        cx2 = pathIn->pts[j0].x + wdyNext - kappa * dxNext;
8260
0
        cy2 = pathIn->pts[j0].y - wdxNext - kappa * dyNext;
8261
0
        pathOut->moveTo(pathIn->pts[j0].x, pathIn->pts[j0].y);
8262
0
        pathOut->lineTo(pathIn->pts[j0].x + wdy,
8263
0
            pathIn->pts[j0].y - wdx);
8264
0
        pathOut->curveTo(cx1, cy1, cx2, cy2,
8265
0
             pathIn->pts[j0].x + wdyNext,
8266
0
             pathIn->pts[j0].y - wdxNext);
8267
0
    } else {
8268
      // span angle is > 90 degrees -> split into two arcs
8269
0
      dJoin = splashDist(wdy, -wdx, wdyNext, -wdxNext);
8270
0
      if (dJoin > 0) {
8271
0
        dxJoin = (wdyNext - wdy) / dJoin;
8272
0
        dyJoin = (-wdxNext + wdx) / dJoin;
8273
0
        xc = pathIn->pts[j0].x
8274
0
       + (SplashCoord)0.5 * w
8275
0
         * cos((double)((SplashCoord)0.5 * (angle + angleNext)));
8276
0
        yc = pathIn->pts[j0].y
8277
0
       + (SplashCoord)0.5 * w
8278
0
         * sin((double)((SplashCoord)0.5 * (angle + angleNext)));
8279
0
        kappa = dAngle * bezierCircle2 * w;
8280
0
        cx1 = pathIn->pts[j0].x + wdy + kappa * dx;
8281
0
        cy1 = pathIn->pts[j0].y - wdx + kappa * dy;
8282
0
        cx2 = xc - kappa * dxJoin;
8283
0
        cy2 = yc - kappa * dyJoin;
8284
0
        cx3 = xc + kappa * dxJoin;
8285
0
        cy3 = yc + kappa * dyJoin;
8286
0
        cx4 = pathIn->pts[j0].x + wdyNext - kappa * dxNext;
8287
0
        cy4 = pathIn->pts[j0].y - wdxNext - kappa * dyNext;
8288
0
        pathOut->moveTo(pathIn->pts[j0].x, pathIn->pts[j0].y);
8289
0
        pathOut->lineTo(pathIn->pts[j0].x + wdy,
8290
0
            pathIn->pts[j0].y - wdx);
8291
0
        pathOut->curveTo(cx1, cy1, cx2, cy2, xc, yc);
8292
0
        pathOut->curveTo(cx3, cy3, cx4, cy4,
8293
0
             pathIn->pts[j0].x + wdyNext,
8294
0
             pathIn->pts[j0].y - wdxNext);
8295
0
      }
8296
0
    }
8297
0
  }
8298
8299
0
      } else {
8300
0
  pathOut->moveTo(pathIn->pts[j0].x, pathIn->pts[j0].y);
8301
8302
  // join angle < 180
8303
0
  if (crossprod < 0) {
8304
0
    pathOut->lineTo(pathIn->pts[j0].x - wdyNext,
8305
0
        pathIn->pts[j0].y + wdxNext);
8306
    // miter join inside limit
8307
0
    if (lineJoin == splashLineJoinMiter &&
8308
0
        splashSqrt(miter) <= state->miterLimit) {
8309
0
      pathOut->lineTo(pathIn->pts[j0].x - wdy + wdx * m,
8310
0
          pathIn->pts[j0].y + wdx + wdy * m);
8311
0
      pathOut->lineTo(pathIn->pts[j0].x - wdy,
8312
0
          pathIn->pts[j0].y + wdx);
8313
    // bevel join or miter join outside limit
8314
0
    } else {
8315
0
      pathOut->lineTo(pathIn->pts[j0].x - wdy,
8316
0
          pathIn->pts[j0].y + wdx);
8317
0
    }
8318
8319
  // join angle >= 180
8320
0
  } else {
8321
0
    pathOut->lineTo(pathIn->pts[j0].x + wdy,
8322
0
        pathIn->pts[j0].y - wdx);
8323
    // miter join inside limit
8324
0
    if (lineJoin == splashLineJoinMiter &&
8325
0
        splashSqrt(miter) <= state->miterLimit) {
8326
0
      pathOut->lineTo(pathIn->pts[j0].x + wdy + wdx * m,
8327
0
          pathIn->pts[j0].y - wdx + wdy * m);
8328
0
      pathOut->lineTo(pathIn->pts[j0].x + wdyNext,
8329
0
          pathIn->pts[j0].y - wdxNext);
8330
    // bevel join or miter join outside limit
8331
0
    } else {
8332
0
      pathOut->lineTo(pathIn->pts[j0].x + wdyNext,
8333
0
          pathIn->pts[j0].y - wdxNext);
8334
0
    }
8335
0
  }
8336
0
      }
8337
8338
0
      pathOut->close();
8339
0
    }
8340
8341
    // add stroke adjustment hints
8342
0
    if (state->strokeAdjust != splashStrokeAdjustOff) {
8343
8344
      // subpath with one segment
8345
0
      if (seg == 0 && last) {
8346
0
  switch (lineCap) {
8347
0
  case splashLineCapButt:
8348
0
    pathOut->addStrokeAdjustHint(firstPt, left2 + 1,
8349
0
               firstPt, pathOut->length - 1);
8350
0
    break;
8351
0
  case splashLineCapProjecting:
8352
0
    pathOut->addStrokeAdjustHint(firstPt, left2 + 1,
8353
0
               firstPt, pathOut->length - 1, gTrue);
8354
0
    break;
8355
0
  case splashLineCapRound:
8356
0
    break;
8357
0
  }
8358
0
  pathOut->addStrokeAdjustHint(left2, right2,
8359
0
             firstPt, pathOut->length - 1);
8360
0
      } else {
8361
8362
  // start of subpath
8363
0
  if (seg == 1) {
8364
8365
    // start cap
8366
0
    if (!closed) {
8367
0
      switch (lineCap) {
8368
0
      case splashLineCapButt:
8369
0
        pathOut->addStrokeAdjustHint(firstPt, left1 + 1,
8370
0
             firstPt, firstPt + 1);
8371
0
        pathOut->addStrokeAdjustHint(firstPt, left1 + 1,
8372
0
             right1 + 1, right1 + 1);
8373
0
        break;
8374
0
      case splashLineCapProjecting:
8375
0
        pathOut->addStrokeAdjustHint(firstPt, left1 + 1,
8376
0
             firstPt, firstPt + 1, gTrue);
8377
0
        pathOut->addStrokeAdjustHint(firstPt, left1 + 1,
8378
0
             right1 + 1, right1 + 1, gTrue);
8379
0
        break;
8380
0
      case splashLineCapRound:
8381
0
        break;
8382
0
      }
8383
0
    }
8384
8385
    // first segment
8386
0
    pathOut->addStrokeAdjustHint(left1, right1, firstPt, left2);
8387
0
    pathOut->addStrokeAdjustHint(left1, right1, right2 + 1, right2 + 1);
8388
0
  }
8389
8390
  // middle of subpath
8391
0
  if (seg > 1) {
8392
0
    pathOut->addStrokeAdjustHint(left1, right1, left0 + 1, right0);
8393
0
    pathOut->addStrokeAdjustHint(left1, right1, join0, left2);
8394
0
    pathOut->addStrokeAdjustHint(left1, right1, right2 + 1, right2 + 1);
8395
0
  }
8396
8397
  // end of subpath
8398
0
  if (last) {
8399
8400
0
    if (closed) {
8401
      // first segment
8402
0
      pathOut->addStrokeAdjustHint(leftFirst, rightFirst,
8403
0
           left2 + 1, right2);
8404
0
      pathOut->addStrokeAdjustHint(leftFirst, rightFirst,
8405
0
           join2, pathOut->length - 1);
8406
8407
      // last segment
8408
0
      pathOut->addStrokeAdjustHint(left2, right2,
8409
0
           left1 + 1, right1);
8410
0
      pathOut->addStrokeAdjustHint(left2, right2,
8411
0
           join1, pathOut->length - 1);
8412
0
      pathOut->addStrokeAdjustHint(left2, right2,
8413
0
           leftFirst - 1, leftFirst);
8414
0
      pathOut->addStrokeAdjustHint(left2, right2,
8415
0
           rightFirst + 1, rightFirst + 1);
8416
8417
0
    } else {
8418
8419
      // last segment
8420
0
      pathOut->addStrokeAdjustHint(left2, right2,
8421
0
           left1 + 1, right1);
8422
0
      pathOut->addStrokeAdjustHint(left2, right2,
8423
0
           join1, pathOut->length - 1);
8424
8425
      // end cap
8426
0
      switch (lineCap) {
8427
0
      case splashLineCapButt:
8428
0
        pathOut->addStrokeAdjustHint(left2 - 1, left2 + 1,
8429
0
             left2 + 1, left2 + 2);
8430
0
        break;
8431
0
      case splashLineCapProjecting:
8432
0
        pathOut->addStrokeAdjustHint(left2 - 1, left2 + 1,
8433
0
             left2 + 1, left2 + 2, gTrue);
8434
0
        break;
8435
0
      case splashLineCapRound:
8436
0
        break;
8437
0
      }
8438
0
    }
8439
0
  }
8440
0
      }
8441
8442
0
      left0 = left1;
8443
0
      left1 = left2;
8444
0
      right0 = right1;
8445
0
      right1 = right2;
8446
0
      join0 = join1;
8447
0
      join1 = join2;
8448
0
      if (seg == 0) {
8449
0
  leftFirst = left2;
8450
0
  rightFirst = right2;
8451
0
      }
8452
0
    }
8453
8454
0
    i0 = j0;
8455
0
    i1 = j1;
8456
0
    ++seg;
8457
0
  }
8458
8459
0
  if (pathIn != path) {
8460
0
    delete pathIn;
8461
0
  }
8462
8463
0
  return pathOut;
8464
0
}
8465
8466
SplashClipResult Splash::limitRectToClipRect(int *xMin, int *yMin,
8467
0
               int *xMax, int *yMax) {
8468
0
  int t;
8469
8470
0
  if ((t = state->clip->getXMinI(state->strokeAdjust)) > *xMin) {
8471
0
    *xMin = t;
8472
0
  }
8473
0
  if ((t = state->clip->getXMaxI(state->strokeAdjust) + 1) < *xMax) {
8474
0
    *xMax = t;
8475
0
  }
8476
0
  if ((t = state->clip->getYMinI(state->strokeAdjust)) > *yMin) {
8477
0
    *yMin = t;
8478
0
  }
8479
0
  if ((t = state->clip->getYMaxI(state->strokeAdjust) + 1) < *yMax) {
8480
0
    *yMax = t;
8481
0
  }
8482
0
  if (*xMin >= *xMax || *yMin >= *yMax) {
8483
0
    return splashClipAllOutside;
8484
0
  }
8485
0
  return state->clip->testRect(*xMin, *yMin, *xMax - 1, *yMax - 1,
8486
0
             state->strokeAdjust);
8487
0
}
8488
8489
0
void Splash::dumpPath(SplashPath *path) {
8490
0
  int i;
8491
8492
0
  for (i = 0; i < path->length; ++i) {
8493
0
    printf("  %3d: x=%8.2f y=%8.2f%s%s%s%s\n",
8494
0
     i, (double)path->pts[i].x, (double)path->pts[i].y,
8495
0
     (path->flags[i] & splashPathFirst) ? " first" : "",
8496
0
     (path->flags[i] & splashPathLast) ? " last" : "",
8497
0
     (path->flags[i] & splashPathClosed) ? " closed" : "",
8498
0
     (path->flags[i] & splashPathCurve) ? " curve" : "");
8499
0
  }
8500
0
  if (path->hintsLength == 0) {
8501
0
    printf("  no hints\n");
8502
0
  } else {
8503
0
    for (i = 0; i < path->hintsLength; ++i) {
8504
0
      printf("  hint %3d: ctrl0=%d ctrl1=%d pts=%d..%d\n",
8505
0
       i, path->hints[i].ctrl0, path->hints[i].ctrl1,
8506
0
       path->hints[i].firstPt, path->hints[i].lastPt);
8507
0
    }
8508
0
  }
8509
0
}
8510
8511
0
void Splash::dumpXPath(SplashXPath *path) {
8512
0
  int i;
8513
8514
0
  for (i = 0; i < path->length; ++i) {
8515
0
    printf("  %4d: x0=%8.2f y0=%8.2f x1=%8.2f y1=%8.2f count=%d\n",
8516
0
     i, (double)path->segs[i].x0, (double)path->segs[i].y0,
8517
0
     (double)path->segs[i].x1, (double)path->segs[i].y1,
8518
0
     path->segs[i].count);
8519
0
  }
8520
0
}
8521