Coverage Report

Created: 2022-03-21 07:20

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