Coverage Report

Created: 2026-05-30 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/xpdf-4.06/xpdf/ShadingImage.cc
Line
Count
Source
1
//========================================================================
2
//
3
// ShadingImage.cc
4
//
5
// Copyright 2020 Glyph & Cog, LLC
6
//
7
//========================================================================
8
9
#include <aconf.h>
10
11
#include <math.h>
12
#include "Trace.h"
13
#include "GfxState.h"
14
#include "SplashBitmap.h"
15
#include "SplashPattern.h"
16
#include "SplashPath.h"
17
#include "Splash.h"
18
#include "ShadingImage.h"
19
20
// Max recursive depth for a patch mesh shading fill.
21
2.07M
#define patchMaxDepth 10
22
23
// Max delta allowed in any color component for a patch mesh shading
24
// fill.
25
51.8M
#define patchColorDelta (dblToCol(1 / 256.0))
26
27
SplashBitmap *ShadingImage::generateBitmap(
28
        GfxState *state,
29
        GfxShading *shading,
30
        SplashColorMode mode,
31
        GBool reverseVideo,
32
        Splash *parentSplash,
33
        SplashBitmapMemCache *bitmapMemCache,
34
1.78k
        int *xOut, int *yOut) {
35
1.78k
  switch (shading->getType()) {
36
0
  case 1:
37
0
    return generateFunctionBitmap(state, (GfxFunctionShading *)shading,
38
0
          mode, reverseVideo,
39
0
          parentSplash, bitmapMemCache, xOut, yOut);
40
0
    break;
41
1.13k
  case 2:
42
1.13k
    return generateAxialBitmap(state, (GfxAxialShading *)shading,
43
1.13k
             mode, reverseVideo,
44
1.13k
             parentSplash, bitmapMemCache, xOut, yOut);
45
0
    break;
46
11
  case 3:
47
11
    return generateRadialBitmap(state, (GfxRadialShading *)shading,
48
11
        mode, reverseVideo,
49
11
        parentSplash, bitmapMemCache, xOut, yOut);
50
0
    break;
51
56
  case 4:
52
287
  case 5:
53
287
    return generateGouraudTriangleBitmap(state,
54
287
           (GfxGouraudTriangleShading *)shading,
55
287
           mode, reverseVideo,
56
287
           parentSplash, bitmapMemCache,
57
287
           xOut, yOut);
58
0
    break;
59
60
  case 6:
60
347
  case 7:
61
347
    return generatePatchMeshBitmap(state, (GfxPatchMeshShading *)shading,
62
347
           mode, reverseVideo,
63
347
           parentSplash, bitmapMemCache, xOut, yOut);
64
0
    break;
65
0
  default:
66
0
    return NULL;
67
1.78k
  }
68
1.78k
}
69
70
762
static double max4(double x0, double x1, double x2, double x3) {
71
762
  double t = x0;
72
762
  t = (x1 > t) ? x1 : t;
73
762
  t = (x2 > t) ? x2 : t;
74
762
  t = (x3 > t) ? x3 : t;
75
762
  return t;
76
762
}
77
78
SplashBitmap *ShadingImage::generateFunctionBitmap(
79
        GfxState *state,
80
        GfxFunctionShading *shading,
81
        SplashColorMode mode,
82
        GBool reverseVideo,
83
        Splash *parentSplash,
84
        SplashBitmapMemCache *bitmapMemCache,
85
0
        int *xOut, int *yOut) {
86
  // get the shading parameters
87
0
  double x0, y0, x1, y1;
88
0
  shading->getDomain(&x0, &y0, &x1, &y1);
89
0
  double *patternMat = shading->getMatrix();
90
91
  // get the clip bbox
92
0
  double fxMin, fyMin, fxMax, fyMax;
93
0
  state->getClipBBox(&fxMin, &fyMin, &fxMax, &fyMax);
94
0
  if (fxMin > fxMax || fyMin > fyMax) {
95
0
    return NULL;
96
0
  }
97
98
  // convert to integer coords
99
0
  int xMin = (int)floor(fxMin);
100
0
  int yMin = (int)floor(fyMin);
101
0
  int xMax = (int)floor(fxMax) + 1;
102
0
  int yMax = (int)floor(fyMax) + 1;
103
0
  int bitmapWidth = xMax - xMin;
104
0
  int bitmapHeight = yMax - yMin;
105
106
  // allocate the bitmap
107
0
  traceMessage("function shading fill bitmap");
108
0
  SplashBitmap *bitmap = new SplashBitmap(bitmapWidth, bitmapHeight, 1, mode,
109
0
            gTrue, gTrue, bitmapMemCache);
110
0
  int nComps = splashColorModeNComps[mode];
111
112
  // compute the domain -> device space transform = mat * CTM
113
0
  double *ctm = state->getCTM();
114
0
  double mat[6];
115
0
  mat[0] = patternMat[0] * ctm[0] + patternMat[1] * ctm[2];
116
0
  mat[1] = patternMat[0] * ctm[1] + patternMat[1] * ctm[3];
117
0
  mat[2] = patternMat[2] * ctm[0] + patternMat[3] * ctm[2];
118
0
  mat[3] = patternMat[2] * ctm[1] + patternMat[3] * ctm[3];
119
0
  mat[4] = patternMat[4] * ctm[0] + patternMat[5] * ctm[2] + ctm[4];
120
0
  mat[5] = patternMat[4] * ctm[1] + patternMat[5] * ctm[3] + ctm[5];
121
122
  // compute the device space -> domain transform
123
0
  double det = mat[0] * mat[3] - mat[1] * mat[2];
124
0
  if (fabs(det) < 0.000001) {
125
0
    return NULL;
126
0
  }
127
0
  det = 1 / det;
128
0
  double iMat[6];
129
0
  iMat[0] = mat[3] * det;
130
0
  iMat[1] = -mat[1] * det;
131
0
  iMat[2] = -mat[2] * det;
132
0
  iMat[3] = mat[0] * det;
133
0
  iMat[4] = (mat[2] * mat[5] - mat[3] * mat[4]) * det;
134
0
  iMat[5] = (mat[1] * mat[4] - mat[0] * mat[5]) * det;
135
136
  // fill the bitmap
137
0
  SplashColorPtr dataPtr = bitmap->getDataPtr();
138
0
  Guchar *alphaPtr = bitmap->getAlphaPtr();
139
0
  for (int y = 0; y < bitmapHeight; ++y) {
140
0
    for (int x = 0; x < bitmapWidth; ++x) {
141
142
      // convert coords to the pattern domain
143
0
      double tx = xMin + x + 0.5;
144
0
      double ty = yMin + y + 0.5;
145
0
      double xx = tx * iMat[0] + ty * iMat[2] + iMat[4];
146
0
      double yy = tx * iMat[1] + ty * iMat[3] + iMat[5];
147
148
      // get the color
149
0
      if (xx >= x0 && xx <= x1 && yy >= y0 && yy <= y1) {
150
0
  GfxColor color;
151
0
  shading->getColor(xx, yy, &color);
152
0
  SplashColor sColor;
153
0
  computeShadingColor(state, mode, reverseVideo, &color, sColor);
154
0
  for (int i = 0; i < nComps; ++i) {
155
0
    *dataPtr++ = sColor[i];
156
0
  }
157
0
  *alphaPtr++ = 0xff;
158
0
      } else {
159
0
  dataPtr += nComps;
160
0
  *alphaPtr++ = 0;
161
0
      }
162
0
    }
163
0
  }
164
165
0
  *xOut = xMin;
166
0
  *yOut = yMin;
167
0
  return bitmap;
168
0
}
169
170
SplashBitmap *ShadingImage::generateAxialBitmap(
171
        GfxState *state,
172
        GfxAxialShading *shading,
173
        SplashColorMode mode,
174
        GBool reverseVideo,
175
        Splash *parentSplash,
176
        SplashBitmapMemCache *bitmapMemCache,
177
1.13k
        int *xOut, int *yOut) {
178
  // get the shading parameters
179
1.13k
  double x0, y0, x1, y1;
180
1.13k
  shading->getCoords(&x0, &y0, &x1, &y1);
181
1.13k
  double t0 = shading->getDomain0();
182
1.13k
  double t1 = shading->getDomain1();
183
1.13k
  GBool ext0 = shading->getExtend0();
184
1.13k
  GBool ext1 = shading->getExtend1();
185
1.13k
  double dx = x1 - x0;
186
1.13k
  double dy = y1 - y0;
187
1.13k
  double d = dx * dx + dy * dy;
188
1.13k
  GBool dZero = fabs(d) < 0.0001;
189
1.13k
  if (!dZero) {
190
1.04k
    d = 1 / d;
191
1.04k
  }
192
1.13k
  if (dZero && !ext0 && !ext1) {
193
45
    return NULL;
194
45
  }
195
196
  // get the clip bbox
197
1.09k
  double fxMin, fyMin, fxMax, fyMax;
198
1.09k
  state->getClipBBox(&fxMin, &fyMin, &fxMax, &fyMax);
199
1.09k
  if (fxMin > fxMax || fyMin > fyMax) {
200
339
    return NULL;
201
339
  }
202
203
  // convert to integer coords
204
753
  int xMin = (int)floor(fxMin);
205
753
  int yMin = (int)floor(fyMin);
206
753
  int xMax = (int)floor(fxMax) + 1;
207
753
  int yMax = (int)floor(fyMax) + 1;
208
753
  int bitmapWidth = xMax - xMin;
209
753
  int bitmapHeight = yMax - yMin;
210
211
  // compute the inverse CTM
212
753
  double *ctm = state->getCTM();
213
753
  double det = ctm[0] * ctm[3] - ctm[1] * ctm[2];
214
753
  if (fabs(det) < 1e-10 * max4(fabs(ctm[0]), fabs(ctm[1]),
215
753
             fabs(ctm[2]), fabs(ctm[3]))) {
216
176
    return NULL;
217
176
  }
218
577
  det = 1 / det;
219
577
  double ictm[6];
220
577
  ictm[0] = ctm[3] * det;
221
577
  ictm[1] = -ctm[1] * det;
222
577
  ictm[2] = -ctm[2] * det;
223
577
  ictm[3] = ctm[0] * det;
224
577
  ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
225
577
  ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
226
227
  // convert axis endpoints to device space
228
577
  double xx0, yy0, xx1, yy1;
229
577
  state->transform(x0, y0, &xx0, &yy0);
230
577
  state->transform(x1, y1, &xx1, &yy1);
231
232
  // allocate the bitmap
233
577
  traceMessage("axial shading fill bitmap");
234
577
  SplashBitmap *bitmap = new SplashBitmap(bitmapWidth, bitmapHeight, 1, mode,
235
577
            gTrue, gTrue, bitmapMemCache);
236
577
  int nComps = splashColorModeNComps[mode];
237
238
  // special case: zero-length axis
239
577
  if (dZero) {
240
13
    GfxColor color;
241
13
    if (ext0) {
242
13
      shading->getColor(t0, &color);
243
13
    } else {
244
0
      shading->getColor(t1, &color);
245
0
    }
246
13
    SplashColor sColor;
247
13
    computeShadingColor(state, mode, reverseVideo, &color, sColor);
248
13
    SplashColorPtr dataPtr = bitmap->getDataPtr();
249
26
    for (int y = 0; y < bitmapHeight; ++y) {
250
26
      for (int x = 0; x < bitmapWidth; ++x) {
251
52
  for (int i = 0; i < nComps; ++i) {
252
39
    *dataPtr++ = sColor[i];
253
39
  }
254
13
      }
255
13
    }
256
13
    memset(bitmap->getAlphaPtr(), 0xff, (size_t)bitmapWidth * bitmapHeight);
257
258
  // special case: horizontal axis (in device space)
259
564
  } else if (fabs(yy0 - yy1) < 0.01) {
260
86
    for (int x = 0; x < bitmapWidth; ++x) {
261
43
      SplashColorPtr dataPtr = bitmap->getDataPtr() + x * nComps;
262
43
      Guchar *alphaPtr = bitmap->getAlphaPtr() + x;
263
43
      double tx = xMin + x + 0.5;
264
43
      double ty = yMin + 0.5;
265
43
      double xx = tx * ictm[0] + ty * ictm[2] + ictm[4];
266
43
      double yy = tx * ictm[1] + ty * ictm[3] + ictm[5];
267
43
      double s = ((xx - x0) * dx + (yy - y0) * dy) * d;
268
43
      GBool go = gFalse;
269
43
      if (s < 0) {
270
0
  go = ext0;
271
43
      } else if (s > 1) {
272
35
  go = ext1;
273
35
      } else {
274
8
  go = gTrue;
275
8
      }
276
43
      if (go) {
277
13
  GfxColor color;
278
13
  if (s <= 0) {
279
0
    shading->getColor(t0, &color);
280
13
  } else if (s >= 1) {
281
5
    shading->getColor(t1, &color);
282
8
  } else {
283
8
    double t = t0 + s * (t1 - t0);
284
8
    shading->getColor(t, &color);
285
8
  }
286
13
  SplashColor sColor;
287
13
  computeShadingColor(state, mode, reverseVideo, &color, sColor);
288
26
  for (int y = 0; y < bitmapHeight; ++y) {
289
52
    for (int i = 0; i < nComps; ++i) {
290
39
      dataPtr[i] = sColor[i];
291
39
    }
292
13
    dataPtr += bitmap->getRowSize();
293
13
    *alphaPtr = 0xff;
294
13
    alphaPtr += bitmapWidth;
295
13
  }
296
30
      } else {
297
60
  for (int y = 0; y < bitmapHeight; ++y) {
298
30
    *alphaPtr = 0;
299
30
    alphaPtr += bitmapWidth;
300
30
  }
301
30
      }
302
43
    }
303
304
  // special case: vertical axis (in device space)
305
521
  } else if (fabs(xx0 - xx1) < 0.01) {
306
496
    for (int y = 0; y < bitmapHeight; ++y) {
307
248
      SplashColorPtr dataPtr = bitmap->getDataPtr() + y * bitmap->getRowSize();
308
248
      Guchar *alphaPtr = bitmap->getAlphaPtr() + y * bitmapWidth;
309
248
      double tx = xMin + 0.5;
310
248
      double ty = yMin + y + 0.5;
311
248
      double xx = tx * ictm[0] + ty * ictm[2] + ictm[4];
312
248
      double yy = tx * ictm[1] + ty * ictm[3] + ictm[5];
313
248
      double s = ((xx - x0) * dx + (yy - y0) * dy) * d;
314
248
      GBool go = gFalse;
315
248
      if (s < 0) {
316
103
  go = ext0;
317
145
      } else if (s > 1) {
318
67
  go = ext1;
319
78
      } else {
320
78
  go = gTrue;
321
78
      }
322
248
      if (go) {
323
176
  GfxColor color;
324
176
  if (s <= 0) {
325
47
    shading->getColor(t0, &color);
326
129
  } else if (s >= 1) {
327
51
    shading->getColor(t1, &color);
328
78
  } else {
329
78
    double t = t0 + s * (t1 - t0);
330
78
    shading->getColor(t, &color);
331
78
  }
332
176
  SplashColor sColor;
333
176
  computeShadingColor(state, mode, reverseVideo, &color, sColor);
334
352
  for (int x = 0; x < bitmapWidth; ++x) {
335
704
    for (int i = 0; i < nComps; ++i) {
336
528
      dataPtr[i] = sColor[i];
337
528
    }
338
176
    dataPtr += nComps;
339
176
  }
340
176
  memset(alphaPtr, 0xff, bitmapWidth);
341
176
      } else {
342
72
  memset(alphaPtr, 0, bitmapWidth);
343
72
      }
344
248
    }
345
346
  // general case
347
273
  } else {
348
    // pre-compute colors along the axis
349
273
    int nColors = (int)(1.5 * sqrt((xx1 - xx0) * (xx1 - xx0)
350
273
           + (yy1 - yy0) * (yy1 - yy0)));
351
273
    if (nColors < 16) {
352
269
      nColors = 16;
353
269
    } else if (nColors > 1024) {
354
0
      nColors = 1024;
355
0
    }
356
273
    SplashColorPtr sColors = (SplashColorPtr)gmallocn(nColors, nComps);
357
273
    SplashColorPtr sColor = sColors;
358
4.57k
    for (int i = 0; i < nColors; ++i) {
359
4.30k
      double s = (double)i / (double)(nColors - 1);
360
4.30k
      double t = t0 + s * (t1 - t0);
361
4.30k
      GfxColor color;
362
4.30k
      shading->getColor(t, &color);
363
4.30k
      computeShadingColor(state, mode, reverseVideo, &color, sColor);
364
4.30k
      sColor += nComps;
365
4.30k
    }
366
367
273
    SplashColorPtr dataPtr = bitmap->getDataPtr();
368
273
    Guchar *alphaPtr = bitmap->getAlphaPtr();
369
542
    for (int y = 0; y < bitmapHeight; ++y) {
370
538
      for (int x = 0; x < bitmapWidth; ++x) {
371
372
  // convert coords to user space
373
269
  double tx = xMin + x + 0.5;
374
269
  double ty = yMin + y + 0.5;
375
269
  double xx = tx * ictm[0] + ty * ictm[2] + ictm[4];
376
269
  double yy = tx * ictm[1] + ty * ictm[3] + ictm[5];
377
378
  // compute the position along the axis
379
269
  double s = ((xx - x0) * dx + (yy - y0) * dy) * d;
380
269
  GBool go = gFalse;
381
269
  if (s < 0) {
382
68
    go = ext0;
383
201
  } else if (s > 1) {
384
71
    go = ext1;
385
130
  } else {
386
130
    go = gTrue;
387
130
  }
388
269
  if (go) {
389
229
    if (s <= 0) {
390
107
      sColor = sColors;
391
122
    } else if (s >= 1) {
392
31
      sColor = sColors + (nColors - 1) * nComps;
393
91
    } else {
394
91
      int i = (int)((nColors - 1) * s + 0.5);
395
91
      sColor = sColors + i * nComps;
396
91
    }
397
916
    for (int i = 0; i < nComps; ++i) {
398
687
      *dataPtr++ = sColor[i];
399
687
    }
400
229
    *alphaPtr++ = 0xff;
401
229
  } else {
402
40
    dataPtr += nComps;
403
40
    *alphaPtr++ = 0;
404
40
  }
405
269
      }
406
269
    }
407
273
    gfree(sColors);
408
273
  }
409
410
577
  *xOut = xMin;
411
577
  *yOut = yMin;
412
577
  return bitmap;
413
753
}
414
415
SplashBitmap *ShadingImage::generateRadialBitmap(
416
        GfxState *state,
417
        GfxRadialShading *shading,
418
        SplashColorMode mode,
419
        GBool reverseVideo,
420
        Splash *parentSplash,
421
        SplashBitmapMemCache *bitmapMemCache,
422
11
        int *xOut, int *yOut) {
423
  // get the shading parameters
424
11
  double x0, y0, r0, x1, y1, r1;
425
11
  shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
426
11
  double t0 = shading->getDomain0();
427
11
  double t1 = shading->getDomain1();
428
11
  GBool ext0 = shading->getExtend0();
429
11
  GBool ext1 = shading->getExtend1();
430
11
  double h = sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
431
11
  GBool enclosed = fabs(r1 - r0) >= h;
432
433
  // get the clip bbox
434
11
  double fxMin, fyMin, fxMax, fyMax;
435
11
  state->getClipBBox(&fxMin, &fyMin, &fxMax, &fyMax);
436
11
  if (fxMin > fxMax || fyMin > fyMax) {
437
1
    return NULL;
438
1
  }
439
440
  // intersect with shading region (in user space): if the extend
441
  // flags are false (or just the larger extend flag is false, in the
442
  // "enclosed" case), we can use the bbox for the two circles
443
10
  if ((!ext0 && !ext1) ||
444
6
      (enclosed && !(r0 > r1 ? ext0 : ext1))) {
445
6
    double uxMin = (x0 - r0) < (x1 - r1) ? (x0 - r0) : (x1 - r1);
446
6
    double uxMax = (x0 + r0) > (x1 + r1) ? (x0 + r0) : (x1 + r1);
447
6
    double uyMin = (y0 - r0) < (y1 - r1) ? (y0 - r0) : (y1 - r1);
448
6
    double uyMax = (y0 + r0) > (y1 + r1) ? (y0 + r0) : (y1 + r1);
449
6
    double dxMin, dyMin, dxMax, dyMax;
450
6
    transformBBox(state, uxMin, uyMin, uxMax, uyMax,
451
6
      &dxMin, &dyMin, &dxMax, &dyMax);
452
6
    if (dxMin > fxMin) {
453
0
      fxMin = dxMin;
454
0
    }
455
6
    if (dxMax < dxMax) {
456
0
      fxMax = dxMax;
457
0
    }
458
6
    if (dyMin > fyMin) {
459
2
      fyMin = dyMin;
460
2
    }
461
6
    if (dyMax < fyMax) {
462
1
      fyMax = dyMax;
463
1
    }
464
6
    if (fxMin > fxMax || fyMin > fyMax) {
465
1
      return NULL;
466
1
    }
467
6
  }
468
469
  // convert to integer coords
470
9
  int xMin = (int)floor(fxMin);
471
9
  int yMin = (int)floor(fyMin);
472
9
  int xMax = (int)floor(fxMax) + 1;
473
9
  int yMax = (int)floor(fyMax) + 1;
474
9
  int bitmapWidth = xMax - xMin;
475
9
  int bitmapHeight = yMax - yMin;
476
477
  // compute the inverse CTM
478
9
  double *ctm = state->getCTM();
479
9
  double det = ctm[0] * ctm[3] - ctm[1] * ctm[2];
480
9
  if (fabs(det) < 1e-10 * max4(fabs(ctm[0]), fabs(ctm[1]),
481
9
             fabs(ctm[2]), fabs(ctm[3]))) {
482
0
    return NULL;
483
0
  }
484
9
  det = 1 / det;
485
9
  double ictm[6];
486
9
  ictm[0] = ctm[3] * det;
487
9
  ictm[1] = -ctm[1] * det;
488
9
  ictm[2] = -ctm[2] * det;
489
9
  ictm[3] = ctm[0] * det;
490
9
  ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
491
9
  ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
492
493
  // allocate the bitmap
494
9
  traceMessage("radial shading fill bitmap");
495
9
  SplashBitmap *bitmap = new SplashBitmap(bitmapWidth, bitmapHeight, 1, mode,
496
9
            gTrue, gTrue, bitmapMemCache);
497
9
  int nComps = splashColorModeNComps[mode];
498
499
  // pre-compute colors along the axis
500
9
  int nColors = (int)sqrt((double)(bitmapWidth * bitmapWidth
501
9
           + bitmapHeight * bitmapHeight));
502
9
  if (nColors < 16) {
503
7
    nColors = 16;
504
7
  } else if (nColors > 1024) {
505
0
    nColors = 1024;
506
0
  }
507
9
  SplashColorPtr sColors = (SplashColorPtr)gmallocn(nColors, nComps);
508
9
  SplashColorPtr sColor = sColors;
509
121
  for (int i = 0; i < nColors; ++i) {
510
112
    double s = (double)i / (double)(nColors - 1);
511
112
    double t = t0 + s * (t1 - t0);
512
112
    GfxColor color;
513
112
    shading->getColor(t, &color);
514
112
    computeShadingColor(state, mode, reverseVideo, &color, sColor);
515
112
    sColor += nComps;
516
112
  }
517
518
  // special case: in the "enclosed" + extended case, we can fill the
519
  // bitmap with the outer color and just render inside the larger
520
  // circle
521
9
  int bxMin, byMin, bxMax, byMax;
522
9
  if (enclosed &&
523
6
      ((r0 > r1 && ext0) || (r1 > r0 && ext1))) {
524
2
    double uxMin, uyMin, uxMax, uyMax;
525
2
    if (r0 > r1) {
526
0
      sColor = sColors;
527
0
      uxMin = x0 - r0;
528
0
      uxMax = x0 + r0;
529
0
      uyMin = y0 - r0;
530
0
      uyMax = y0 + r0;
531
2
    } else {
532
2
      sColor = sColors + (nColors - 1) * nComps;
533
2
      uxMin = x1 - r1;
534
2
      uxMax = x1 + r1;
535
2
      uyMin = y1 - r1;
536
2
      uyMax = y1 + r1;
537
2
    }
538
539
    // convert bbox of larger circle to device space
540
2
    double dxMin, dyMin, dxMax, dyMax;
541
2
    transformBBox(state, uxMin, uyMin, uxMax, uyMax,
542
2
      &dxMin, &dyMin, &dxMax, &dyMax);
543
2
    bxMin = (int)floor(dxMin - xMin);
544
2
    if (bxMin < 0) {
545
2
      bxMin = 0;
546
2
    }
547
2
    byMin = (int)floor(dyMin - yMin);
548
2
    if (byMin < 0) {
549
2
      byMin = 0;
550
2
    }
551
2
    bxMax = (int)floor(dxMax - xMin) + 1;
552
2
    if (bxMax > bitmapWidth) {
553
0
      bxMax = bitmapWidth;
554
0
    }
555
2
    byMax = (int)floor(dyMax - yMin) + 1;
556
2
    if (byMax > bitmapHeight) {
557
0
      byMax = bitmapHeight;
558
0
    }
559
560
    // fill bitmap (except for the rectangle containing the larger circle)
561
2
    SplashColorPtr dataPtr = bitmap->getDataPtr();
562
2
    Guchar *alphaPtr = bitmap->getAlphaPtr();
563
4
    for (int y = 0; y < bitmapHeight; ++y) {
564
4
      for (int x = 0; x < bitmapWidth; ++x) {
565
2
  if (y >= byMin && y < byMax && x >= bxMin && x < bxMax) {
566
0
    dataPtr += nComps;
567
0
    ++alphaPtr;
568
2
  } else {
569
8
    for (int i = 0; i < nComps; ++i) {
570
6
      *dataPtr++ = sColor[i];
571
6
    }
572
2
    *alphaPtr++ = 0xff;
573
2
  }
574
2
      }
575
2
    }
576
577
7
  } else {
578
7
    bxMin = 0;
579
7
    byMin = 0;
580
7
    bxMax = bitmapWidth;
581
7
    byMax = bitmapHeight;
582
7
  }
583
584
  // render the shading into the bitmap
585
9
  double dx = x1 - x0;
586
9
  double dy = y1 - y0;
587
9
  double dr = r1 - r0;
588
9
  double r0dr = r0 * dr;
589
9
  double r02 = r0 * r0;
590
9
  double a = dx * dx + dy * dy - dr * dr;
591
9
  GBool aIsZero;
592
9
  double a2;
593
9
  if (fabs(a) < 0.00001) {
594
5
    aIsZero = gTrue;
595
5
    a2 = 0;
596
5
  } else {
597
4
    aIsZero = gFalse;
598
4
    a2 = 1 / (2 * a);
599
4
  }
600
14
  for (int y = byMin; y < byMax; ++y) {
601
5
    SplashColorPtr dataPtr = bitmap->getDataPtr()
602
5
                             + y * bitmap->getRowSize() + bxMin * nComps;
603
5
    Guchar *alphaPtr = bitmap->getAlphaPtr()
604
5
                       + y * bitmap->getAlphaRowSize() + bxMin;
605
10
    for (int x = bxMin; x < bxMax; ++x) {
606
607
      // convert coords to user space
608
5
      double tx = xMin + x + 0.5;
609
5
      double ty = yMin + y + 0.5;
610
5
      double xx = tx * ictm[0] + ty * ictm[2] + ictm[4];
611
5
      double yy = tx * ictm[1] + ty * ictm[3] + ictm[5];
612
613
      // compute the radius of the circle at x,y
614
5
      double b = 2 * ((xx - x0) * dx + (yy - y0) * dy + r0dr);
615
5
      double c = (xx - x0) * (xx - x0) + (yy - y0) * (yy - y0) - r02;
616
5
      double s = 0;
617
5
      GBool go = gFalse;
618
5
      if (aIsZero) {
619
3
  if (fabs(b) < 0.000001) {
620
1
    if (c <= 0) {
621
0
      if (ext0) {
622
0
        s = 0;
623
0
        go = gTrue;
624
0
      }
625
1
    } else {
626
1
      if (ext1) {
627
0
        s = 1;
628
0
        go = gTrue;
629
0
      }
630
1
    }
631
2
  } else {
632
2
    double s0 = c / b;
633
2
    double rs0 = r0 + s0 * (r1 - r0);
634
2
    if ((s0 >= 0 || ext0) && (s0 <= 1 || ext1) && rs0 >= 0) { 
635
0
      s = s0;
636
0
      go = gTrue;
637
0
    }
638
2
  }
639
3
      } else {
640
2
  double e = b*b - 4*a*c;
641
2
  if (e >= 0) {
642
1
    double es = sqrt(e);
643
1
    double s0 = (b + es) * a2;
644
1
    double s1 = (b - es) * a2;
645
1
    double rs0 = r0 + s0 * (r1 - r0);
646
1
    double rs1 = r0 + s1 * (r1 - r0);
647
1
    if (s0 > s1) {
648
0
      if ((s0 >= 0 || ext0) && (s0 <= 1 || ext1) && rs0 >= 0) {
649
0
        s = s0;
650
0
        go = gTrue;
651
0
      } else if ((s1 >= 0 || ext0) && (s1 <= 1 || ext1) && rs1 >= 0) {
652
0
        s = s1;
653
0
        go = gTrue;
654
0
      }
655
1
    } else {
656
1
      if ((s1 >= 0 || ext0) && (s1 <= 1 || ext1) && rs1 >= 0) {
657
0
        s = s1;
658
0
        go = gTrue;
659
1
      } else if ((s0 >= 0 || ext0) && (s0 <= 1 || ext1) && rs0 >= 0) {
660
1
        s = s0;
661
1
        go = gTrue;
662
1
      }
663
1
    }
664
1
  }
665
2
      }
666
5
      if (!go) {
667
4
  dataPtr += nComps;
668
4
  *alphaPtr++ = 0x00;
669
4
  continue;
670
4
      }
671
1
      if (s <= 0) {
672
0
  sColor = sColors;
673
1
      } else if (s >= 1) {
674
0
  sColor = sColors + (nColors - 1) * nComps;
675
1
      } else {
676
1
  int i = (int)((nColors - 1) * s + 0.5);
677
1
  sColor = sColors + i * nComps;
678
1
      }
679
4
      for (int i = 0; i < nComps; ++i) {
680
3
  *dataPtr++ = sColor[i];
681
3
      }
682
1
      *alphaPtr++ = 0xff;
683
1
    }
684
5
  }
685
686
9
  gfree(sColors);
687
688
9
  *xOut = xMin;
689
9
  *yOut = yMin;
690
9
  return bitmap;
691
9
}
692
693
SplashBitmap *ShadingImage::generateGouraudTriangleBitmap(
694
          GfxState *state,
695
          GfxGouraudTriangleShading *shading,
696
          SplashColorMode mode,
697
          GBool reverseVideo,
698
          Splash *parentSplash,
699
          SplashBitmapMemCache *bitmapMemCache,
700
287
          int *xOut, int *yOut) {
701
  // get the clip bbox
702
287
  double fxMin, fyMin, fxMax, fyMax;
703
287
  state->getClipBBox(&fxMin, &fyMin, &fxMax, &fyMax);
704
287
  if (fxMin > fxMax || fyMin > fyMax) {
705
20
    return NULL;
706
20
  }
707
708
  // get the shading bbox
709
267
  double tx0, ty0, tx1, ty1, dx, dy, txMin, tyMin, txMax, tyMax;
710
267
  shading->getBBox(&tx0, &ty0, &tx1, &ty1);
711
267
  state->transform(tx0, ty0, &dx, &dy);
712
267
  txMin = txMax = dx;
713
267
  tyMin = tyMax = dy;
714
267
  state->transform(tx0, ty1, &dx, &dy);
715
267
  if (dx < txMin) {
716
7
    txMin = dx;
717
260
  } else if (dx > txMax) {
718
5
    txMax = dx;
719
5
  }
720
267
  if (dy < tyMin) {
721
32
    tyMin = dy;
722
235
  } else if (dy > tyMax) {
723
10
    tyMax = dy;
724
10
  }
725
267
  state->transform(tx1, ty0, &dx, &dy);
726
267
  if (dx < txMin) {
727
18
    txMin = dx;
728
249
  } else if (dx > txMax) {
729
186
    txMax = dx;
730
186
  }
731
267
  if (dy < tyMin) {
732
187
    tyMin = dy;
733
187
  } else if (dy > tyMax) {
734
7
    tyMax = dy;
735
7
  }
736
267
  state->transform(tx1, ty1, &dx, &dy);
737
267
  if (dx < txMin) {
738
2
    txMin = dx;
739
265
  } else if (dx > txMax) {
740
0
    txMax = dx;
741
0
  }
742
267
  if (dy < tyMin) {
743
20
    tyMin = dy;
744
247
  } else if (dy > tyMax) {
745
2
    tyMax = dy;
746
2
  }
747
267
  if (txMin > fxMin) {
748
14
    fxMin = txMin;
749
14
  }
750
267
  if (txMax < fxMax) {
751
21
    fxMax = txMax;
752
21
  }
753
267
  if (tyMin > fyMin) {
754
14
    fyMin = tyMin;
755
14
  }
756
267
  if (tyMax < fyMax) {
757
18
    fyMax = tyMax;
758
18
  }
759
267
  if (fxMin > fxMax || fyMin > fyMax) {
760
28
    return NULL;
761
28
  }
762
763
  // convert to integer coords
764
239
  int xMin = (int)floor(fxMin);
765
239
  int yMin = (int)floor(fyMin);
766
239
  int xMax = (int)floor(fxMax) + 1;
767
239
  int yMax = (int)floor(fyMax) + 1;
768
239
  int bitmapWidth = xMax - xMin;
769
239
  int bitmapHeight = yMax - yMin;
770
771
  // allocate the bitmap
772
239
  traceMessage("Gouraud triangle shading fill bitmap");
773
239
  SplashBitmap *bitmap = new SplashBitmap(bitmapWidth, bitmapHeight, 1, mode,
774
239
            gTrue, gTrue, bitmapMemCache);
775
776
  // clear the bitmap
777
239
  memset(bitmap->getDataPtr(), 0, bitmap->getHeight() * bitmap->getRowSize());
778
239
  memset(bitmap->getAlphaPtr(), 0, bitmap->getHeight() * bitmap->getWidth());
779
780
  // draw the triangles
781
1.22M
  for (int i = 0; i < shading->getNTriangles(); ++i) {
782
1.22M
    double x0, y0, x1, y1, x2, y2;
783
1.22M
    double color0[gfxColorMaxComps];
784
1.22M
    double color1[gfxColorMaxComps];
785
1.22M
    double color2[gfxColorMaxComps];
786
1.22M
    shading->getTriangle(i, &x0, &y0, color0,
787
1.22M
       &x1, &y1, color1,
788
1.22M
       &x2, &y2, color2);
789
1.22M
    gouraudFillTriangle(state, bitmap, mode, reverseVideo,
790
1.22M
      xMin, yMin, xMax, yMax,
791
1.22M
      x0, y0, color0, x1, y1, color1, x2, y2, color2,
792
1.22M
      shading);
793
1.22M
  }
794
795
239
  *xOut = xMin;
796
239
  *yOut = yMin;
797
239
  return bitmap;
798
267
}
799
800
void ShadingImage::gouraudFillTriangle(GfxState *state, SplashBitmap *bitmap,
801
               SplashColorMode mode,
802
               GBool reverseVideo,
803
               int xMin, int yMin, int xMax, int yMax,
804
               double x0, double y0, double *color0,
805
               double x1, double y1, double *color1,
806
               double x2, double y2, double *color2,
807
1.22M
               GfxGouraudTriangleShading *shading) {
808
1.22M
  int nShadingComps = shading->getNComps();
809
1.22M
  int nBitmapComps = splashColorModeNComps[mode];
810
811
  //--- transform the vertices to device space, sort by y
812
1.22M
  double dx0, dy0, dx1, dy1, dx2, dy2;
813
1.22M
  state->transform(x0, y0, &dx0, &dy0);
814
1.22M
  state->transform(x1, y1, &dx1, &dy1);
815
1.22M
  state->transform(x2, y2, &dx2, &dy2);
816
1.22M
  if (dy0 > dy1) {
817
222k
    double t = dx0;  dx0 = dx1;  dx1 = t;
818
222k
    t = dy0;  dy0 = dy1;  dy1 = t;
819
222k
    double *tc = color0;  color0 = color1;  color1 = tc;
820
222k
  }
821
1.22M
  if (dy1 > dy2) {
822
306k
    double t = dx1;  dx1 = dx2;  dx2 = t;
823
306k
    t = dy1;  dy1 = dy2;  dy2 = t;
824
306k
    double *tc = color1;  color1 = color2;  color2 = tc;
825
306k
  }
826
1.22M
  if (dy0 > dy1) {
827
155k
    double t = dx0;  dx0 = dx1;  dx1 = t;
828
155k
    t = dy0;  dy0 = dy1;  dy1 = t;
829
155k
    double *tc = color0;  color0 = color1;  color1 = tc;
830
155k
  }
831
832
  //--- y loop
833
1.22M
  int syMin = (int)floor(dy0);
834
1.22M
  if (syMin < yMin) {
835
73.5k
    syMin = yMin;
836
73.5k
  }
837
1.22M
  int syMax = (int)floor(dy2) + 1;
838
1.22M
  if (syMax > yMax) {
839
31.9k
    syMax = yMax;
840
31.9k
  }
841
2.27M
  for (int sy = syMin; sy < syMax; ++sy) {
842
843
    //--- vertical interpolation
844
1.05M
    double xx0, xx1;
845
1.05M
    double cc0[gfxColorMaxComps], cc1[gfxColorMaxComps];
846
1.05M
    if (sy <= dy0) {
847
657k
      xx0 = xx1 = dx0;
848
1.96M
      for (int i = 0; i < nShadingComps; ++i) {
849
1.30M
  cc0[i] = cc1[i] = color0[i];
850
1.30M
      }
851
657k
    } else if (sy >= dy2) {
852
163k
      xx0 = xx1 = dx2;
853
481k
      for (int i = 0; i < nShadingComps; ++i) {
854
318k
  cc0[i] = cc1[i] = color2[i];
855
318k
      }
856
237k
    } else {
857
237k
      if (sy <= dy1) {
858
143k
  double interp = (sy - dy0) / (dy1 - dy0);
859
143k
  xx0 = dx0 + interp * (dx1 - dx0);
860
428k
  for (int i = 0; i < nShadingComps; ++i) {
861
284k
    cc0[i] = color0[i] + interp * (color1[i] - color0[i]);
862
284k
  }
863
143k
      } else {
864
93.6k
  double interp = (sy - dy1) / (dy2 - dy1);
865
93.6k
  xx0 = dx1 + interp * (dx2 - dx1);
866
295k
  for (int i = 0; i < nShadingComps; ++i) {
867
202k
    cc0[i] = color1[i] + interp * (color2[i] - color1[i]);
868
202k
  }
869
93.6k
      }
870
237k
      double interp = (sy - dy0) / (dy2 - dy0);
871
237k
      xx1 = dx0 + interp * (dx2 - dx0);
872
724k
      for (int i = 0; i < nShadingComps; ++i) {
873
487k
  cc1[i] = color0[i] + interp * (color2[i] - color0[i]);
874
487k
      }
875
237k
    }
876
877
    //--- x loop
878
1.05M
    if (xx0 > xx1) {
879
36.4k
      double t = xx0;  xx0 = xx1;  xx1 = t;
880
106k
      for (int i = 0; i < nShadingComps; ++i) {
881
70.2k
  t = cc0[i];  cc0[i] = cc1[i];  cc1[i] = t;
882
70.2k
      }
883
36.4k
    }
884
1.05M
    int sxMin = (int)floor(xx0);
885
1.05M
    if (sxMin < xMin) {
886
543k
      sxMin = xMin;
887
543k
    }
888
1.05M
    int sxMax = (int)floor(xx1) + 1;
889
1.05M
    if (sxMax > xMax) {
890
419k
      sxMax = xMax;
891
419k
    }
892
1.05M
    SplashColorPtr dataPtr = bitmap->getDataPtr()
893
1.05M
                             + (sy - yMin) * bitmap->getRowSize()
894
1.05M
                             + (sxMin - xMin) * nBitmapComps;
895
1.05M
    if (sxMin < sxMax) {
896
94.5k
      Guchar *alphaPtr = bitmap->getAlphaPtr()
897
94.5k
                   + (sy - yMin) * bitmap->getWidth()
898
94.5k
                   + (sxMin - xMin);
899
94.5k
      memset(alphaPtr, 0xff, sxMax - sxMin);
900
94.5k
    }
901
1.15M
    for (int sx = sxMin; sx < sxMax; ++sx) {
902
903
      //--- horizontal interpolation
904
94.5k
      double cc[gfxColorMaxComps];
905
94.5k
      if (sx <= xx0) {
906
147k
  for (int i = 0; i < nShadingComps; ++i) {
907
96.1k
    cc[i] = cc0[i];
908
96.1k
  }
909
51.0k
      } else if (sx >= xx1) {
910
55.3k
  for (int i = 0; i < nShadingComps; ++i) {
911
30.6k
    cc[i] = cc1[i];
912
30.6k
  }
913
24.7k
      } else {
914
75.3k
  for (int i = 0; i < nShadingComps; ++i) {
915
56.4k
    double interp = (sx - xx0) / (xx1 - xx0);
916
56.4k
    cc[i] = cc0[i] + interp * (cc1[i] - cc0[i]);
917
56.4k
  }
918
18.8k
      }
919
920
      //--- compute color and set pixel
921
94.5k
      GfxColor gColor;
922
94.5k
      shading->getColor(cc, &gColor);
923
94.5k
      SplashColor sColor;
924
94.5k
      computeShadingColor(state, mode, reverseVideo, &gColor, sColor);
925
378k
      for (int i = 0; i < nBitmapComps; ++i) {
926
283k
  dataPtr[i] = sColor[i];
927
283k
      }
928
94.5k
      dataPtr += nBitmapComps;
929
94.5k
    }
930
1.05M
  }
931
1.22M
}
932
933
SplashBitmap *ShadingImage::generatePatchMeshBitmap(
934
          GfxState *state,
935
          GfxPatchMeshShading *shading,
936
          SplashColorMode mode,
937
          GBool reverseVideo,
938
          Splash *parentSplash,
939
          SplashBitmapMemCache *bitmapMemCache,
940
347
          int *xOut, int *yOut) {
941
  // get the clip bbox
942
347
  double fxMin, fyMin, fxMax, fyMax;
943
347
  state->getClipBBox(&fxMin, &fyMin, &fxMax, &fyMax);
944
347
  if (fxMin > fxMax || fyMin > fyMax) {
945
79
    return NULL;
946
79
  }
947
948
  // get the shading bbox
949
268
  double tx0, ty0, tx1, ty1, dx, dy, txMin, tyMin, txMax, tyMax;
950
268
  shading->getBBox(&tx0, &ty0, &tx1, &ty1);
951
268
  state->transform(tx0, ty0, &dx, &dy);
952
268
  txMin = txMax = dx;
953
268
  tyMin = tyMax = dy;
954
268
  state->transform(tx0, ty1, &dx, &dy);
955
268
  if (dx < txMin) {
956
15
    txMin = dx;
957
253
  } else if (dx > txMax) {
958
50
    txMax = dx;
959
50
  }
960
268
  if (dy < tyMin) {
961
130
    tyMin = dy;
962
138
  } else if (dy > tyMax) {
963
77
    tyMax = dy;
964
77
  }
965
268
  state->transform(tx1, ty0, &dx, &dy);
966
268
  if (dx < txMin) {
967
10
    txMin = dx;
968
258
  } else if (dx > txMax) {
969
122
    txMax = dx;
970
122
  }
971
268
  if (dy < tyMin) {
972
27
    tyMin = dy;
973
241
  } else if (dy > tyMax) {
974
31
    tyMax = dy;
975
31
  }
976
268
  state->transform(tx1, ty1, &dx, &dy);
977
268
  if (dx < txMin) {
978
8
    txMin = dx;
979
260
  } else if (dx > txMax) {
980
38
    txMax = dx;
981
38
  }
982
268
  if (dy < tyMin) {
983
35
    tyMin = dy;
984
233
  } else if (dy > tyMax) {
985
23
    tyMax = dy;
986
23
  }
987
268
  if (txMin > fxMin) {
988
117
    fxMin = txMin;
989
117
  }
990
268
  if (txMax < fxMax) {
991
246
    fxMax = txMax;
992
246
  }
993
268
  if (tyMin > fyMin) {
994
33
    fyMin = tyMin;
995
33
  }
996
268
  if (tyMax < fyMax) {
997
78
    fyMax = tyMax;
998
78
  }
999
268
  if (fxMin > fxMax || fyMin > fyMax) {
1000
90
    return NULL;
1001
90
  }
1002
1003
  // convert to integer coords
1004
178
  int xMin = (int)floor(fxMin);
1005
178
  int yMin = (int)floor(fyMin);
1006
178
  int xMax = (int)floor(fxMax) + 1;
1007
178
  int yMax = (int)floor(fyMax) + 1;
1008
178
  int bitmapWidth = xMax - xMin;
1009
178
  int bitmapHeight = yMax - yMin;
1010
1011
  // allocate the bitmap
1012
178
  traceMessage("Gouraud triangle shading fill bitmap");
1013
178
  SplashBitmap *bitmap = new SplashBitmap(bitmapWidth, bitmapHeight, 1, mode,
1014
178
            gTrue, gTrue, bitmapMemCache);
1015
1016
  // allocate a Splash object
1017
  // vector antialiasing is disabled to avoid artifacts along triangle edges
1018
178
  Splash *splash = new Splash(bitmap, gFalse,
1019
178
            parentSplash->getImageCache(),
1020
178
            parentSplash->getScreen());
1021
178
  SplashColor zero;
1022
679
  for (int i = 0; i < splashColorModeNComps[mode]; ++i) {
1023
501
    zero[i] = 0;
1024
501
  }
1025
178
  splash->clear(zero, 0x00);
1026
1027
  // draw the patches
1028
178
  int start;
1029
178
  if (shading->getNPatches() > 128) {
1030
1
    start = 3;
1031
177
  } else if (shading->getNPatches() > 64) {
1032
1
    start = 2;
1033
176
  } else if (shading->getNPatches() > 16) {
1034
2
    start = 1;
1035
174
  } else {
1036
174
    start = 0;
1037
174
  }
1038
820
  for (int i = 0; i < shading->getNPatches(); ++i) {
1039
642
    fillPatch(state, splash, mode, reverseVideo,
1040
642
        xMin, yMin, shading->getPatch(i), shading, start);
1041
642
  }
1042
1043
178
  delete splash;
1044
1045
178
  *xOut = xMin;
1046
178
  *yOut = yMin;
1047
178
  return bitmap;
1048
268
}
1049
1050
void ShadingImage::fillPatch(GfxState *state, Splash *splash,
1051
           SplashColorMode mode, GBool reverseVideo,
1052
           int xMin, int yMin,
1053
           GfxPatch *patch,
1054
           GfxPatchMeshShading *shading,
1055
2.07M
           int depth) {
1056
2.07M
  GfxColor c00;
1057
2.07M
  shading->getColor(patch->color[0][0], &c00);
1058
2.07M
  GBool stop = gFalse;
1059
1060
  // stop subdivision at max depth
1061
2.07M
  if (depth == patchMaxDepth) {
1062
0
    stop = gTrue;
1063
0
  }
1064
1065
  // stop subdivision if colors are close enough
1066
2.07M
  if (!stop) {
1067
2.07M
    int nComps = shading->getColorSpace()->getNComps();
1068
2.07M
    GfxColor c01, c10, c11;
1069
2.07M
    shading->getColor(patch->color[0][1], &c01);
1070
2.07M
    shading->getColor(patch->color[1][0], &c10);
1071
2.07M
    shading->getColor(patch->color[1][1], &c11);
1072
2.07M
    int i;
1073
9.16M
    for (i = 0; i < nComps; ++i) {
1074
7.61M
      if (abs(c00.c[i] - c01.c[i]) > patchColorDelta ||
1075
7.25M
    abs(c01.c[i] - c11.c[i]) > patchColorDelta ||
1076
7.10M
    abs(c11.c[i] - c10.c[i]) > patchColorDelta ||
1077
7.09M
    abs(c10.c[i] - c00.c[i]) > patchColorDelta) {
1078
518k
  break;
1079
518k
      }
1080
7.61M
    }
1081
2.07M
    if (i == nComps) {
1082
1.55M
      stop = gTrue;
1083
1.55M
    }
1084
2.07M
  }
1085
1086
  // stop subdivision if patch is small enough
1087
2.07M
  if (!stop) {
1088
518k
    double xxMin = 0;
1089
518k
    double yyMin = 0;
1090
518k
    double xxMax = 0;
1091
518k
    double yyMax = 0;
1092
2.59M
    for (int j = 0; j < 4; ++j) {
1093
10.3M
      for (int i = 0; i < 4; ++i) {
1094
8.29M
  double xx, yy;
1095
8.29M
  state->transformDelta(patch->x[i][j], patch->y[i][j], &xx, &yy);
1096
8.29M
  if (i == 0 && j == 0) {
1097
518k
    xxMin = xxMax = xx;
1098
518k
    yyMin = yyMax = yy;
1099
7.77M
  } else {
1100
7.77M
    if (xx < xxMin) {
1101
1.42M
      xxMin = xx;
1102
6.34M
    } else if (xx > xxMax) {
1103
1.32M
      xxMax = xx;
1104
1.32M
    }
1105
7.77M
    if (yy < yyMin) {
1106
2.08M
      yyMin = yy;
1107
5.69M
    } else if (yy > yyMax) {
1108
1.62M
      yyMax = yy;
1109
1.62M
    }
1110
7.77M
  }
1111
8.29M
      }
1112
2.07M
    }
1113
518k
    if (xxMax - xxMin < 1 && yyMax - yyMin < 1) {
1114
258
      stop = gTrue;
1115
258
    }
1116
518k
  }
1117
1118
  // draw the patch
1119
2.07M
  if (stop) {
1120
1.55M
    SplashColor sColor;
1121
1.55M
    computeShadingColor(state, mode, reverseVideo, &c00, sColor);
1122
1.55M
    splash->setFillPattern(new SplashSolidColor(sColor));
1123
1.55M
    SplashPath *path = new SplashPath();
1124
1.55M
    double xx0, yy0, xx1, yy1, xx2, yy2, xx3, yy3;
1125
1.55M
    state->transform(patch->x[0][0], patch->y[0][0], &xx0, &yy0);
1126
1.55M
    path->moveTo(xx0 - xMin, yy0 - yMin);
1127
1.55M
    state->transform(patch->x[0][1], patch->y[0][1], &xx1, &yy1);
1128
1.55M
    state->transform(patch->x[0][2], patch->y[0][2], &xx2, &yy2);
1129
1.55M
    state->transform(patch->x[0][3], patch->y[0][3], &xx3, &yy3);
1130
1.55M
    path->curveTo(xx1 - xMin, yy1 - yMin, xx2 - xMin, yy2 - yMin,
1131
1.55M
      xx3 - xMin, yy3 - yMin);
1132
1.55M
    state->transform(patch->x[1][3], patch->y[1][3], &xx1, &yy1);
1133
1.55M
    state->transform(patch->x[2][3], patch->y[2][3], &xx2, &yy2);
1134
1.55M
    state->transform(patch->x[3][3], patch->y[3][3], &xx3, &yy3);
1135
1.55M
    path->curveTo(xx1 - xMin, yy1 - yMin, xx2 - xMin, yy2 - yMin,
1136
1.55M
      xx3 - xMin, yy3 - yMin);
1137
1.55M
    state->transform(patch->x[3][2], patch->y[3][2], &xx1, &yy1);
1138
1.55M
    state->transform(patch->x[3][1], patch->y[3][1], &xx2, &yy2);
1139
1.55M
    state->transform(patch->x[3][0], patch->y[3][0], &xx3, &yy3);
1140
1.55M
    path->curveTo(xx1 - xMin, yy1 - yMin, xx2 - xMin, yy2 - yMin,
1141
1.55M
      xx3 - xMin, yy3 - yMin);
1142
1.55M
    state->transform(patch->x[2][0], patch->y[2][0], &xx1, &yy1);
1143
1.55M
    state->transform(patch->x[1][0], patch->y[1][0], &xx2, &yy2);
1144
1.55M
    path->curveTo(xx1 - xMin, yy1 - yMin, xx2 - xMin, yy2 - yMin,
1145
1.55M
      xx0 - xMin, yy0 - yMin);
1146
1.55M
    path->close();
1147
1.55M
    splash->fill(path, gFalse);
1148
1.55M
    delete path;
1149
1150
  // subdivide the patch
1151
1.55M
  } else {
1152
518k
    double xx[4][8], yy[4][8];
1153
2.59M
    for (int i = 0; i < 4; ++i) {
1154
2.07M
      xx[i][0] = patch->x[i][0];
1155
2.07M
      yy[i][0] = patch->y[i][0];
1156
2.07M
      xx[i][1] = 0.5 * (patch->x[i][0] + patch->x[i][1]);
1157
2.07M
      yy[i][1] = 0.5 * (patch->y[i][0] + patch->y[i][1]);
1158
2.07M
      double xxm = 0.5 * (patch->x[i][1] + patch->x[i][2]);
1159
2.07M
      double yym = 0.5 * (patch->y[i][1] + patch->y[i][2]);
1160
2.07M
      xx[i][6] = 0.5 * (patch->x[i][2] + patch->x[i][3]);
1161
2.07M
      yy[i][6] = 0.5 * (patch->y[i][2] + patch->y[i][3]);
1162
2.07M
      xx[i][2] = 0.5 * (xx[i][1] + xxm);
1163
2.07M
      yy[i][2] = 0.5 * (yy[i][1] + yym);
1164
2.07M
      xx[i][5] = 0.5 * (xxm + xx[i][6]);
1165
2.07M
      yy[i][5] = 0.5 * (yym + yy[i][6]);
1166
2.07M
      xx[i][3] = xx[i][4] = 0.5 * (xx[i][2] + xx[i][5]);
1167
2.07M
      yy[i][3] = yy[i][4] = 0.5 * (yy[i][2] + yy[i][5]);
1168
2.07M
      xx[i][7] = patch->x[i][3];
1169
2.07M
      yy[i][7] = patch->y[i][3];
1170
2.07M
    }
1171
518k
    GfxPatch patch00, patch01, patch10, patch11;
1172
2.59M
    for (int i = 0; i < 4; ++i) {
1173
2.07M
      patch00.x[0][i] = xx[0][i];
1174
2.07M
      patch00.y[0][i] = yy[0][i];
1175
2.07M
      patch00.x[1][i] = 0.5 * (xx[0][i] + xx[1][i]);
1176
2.07M
      patch00.y[1][i] = 0.5 * (yy[0][i] + yy[1][i]);
1177
2.07M
      double xxm = 0.5 * (xx[1][i] + xx[2][i]);
1178
2.07M
      double yym = 0.5 * (yy[1][i] + yy[2][i]);
1179
2.07M
      patch10.x[2][i] = 0.5 * (xx[2][i] + xx[3][i]);
1180
2.07M
      patch10.y[2][i] = 0.5 * (yy[2][i] + yy[3][i]);
1181
2.07M
      patch00.x[2][i] = 0.5 * (patch00.x[1][i] + xxm);
1182
2.07M
      patch00.y[2][i] = 0.5 * (patch00.y[1][i] + yym);
1183
2.07M
      patch10.x[1][i] = 0.5 * (xxm + patch10.x[2][i]);
1184
2.07M
      patch10.y[1][i] = 0.5 * (yym + patch10.y[2][i]);
1185
2.07M
      patch00.x[3][i] = 0.5 * (patch00.x[2][i] + patch10.x[1][i]);
1186
2.07M
      patch00.y[3][i] = 0.5 * (patch00.y[2][i] + patch10.y[1][i]);
1187
2.07M
      patch10.x[0][i] = patch00.x[3][i];
1188
2.07M
      patch10.y[0][i] = patch00.y[3][i];
1189
2.07M
      patch10.x[3][i] = xx[3][i];
1190
2.07M
      patch10.y[3][i] = yy[3][i];
1191
2.07M
    }
1192
2.59M
    for (int i = 4; i < 8; ++i) {
1193
2.07M
      patch01.x[0][i-4] = xx[0][i];
1194
2.07M
      patch01.y[0][i-4] = yy[0][i];
1195
2.07M
      patch01.x[1][i-4] = 0.5 * (xx[0][i] + xx[1][i]);
1196
2.07M
      patch01.y[1][i-4] = 0.5 * (yy[0][i] + yy[1][i]);
1197
2.07M
      double xxm = 0.5 * (xx[1][i] + xx[2][i]);
1198
2.07M
      double yym = 0.5 * (yy[1][i] + yy[2][i]);
1199
2.07M
      patch11.x[2][i-4] = 0.5 * (xx[2][i] + xx[3][i]);
1200
2.07M
      patch11.y[2][i-4] = 0.5 * (yy[2][i] + yy[3][i]);
1201
2.07M
      patch01.x[2][i-4] = 0.5 * (patch01.x[1][i-4] + xxm);
1202
2.07M
      patch01.y[2][i-4] = 0.5 * (patch01.y[1][i-4] + yym);
1203
2.07M
      patch11.x[1][i-4] = 0.5 * (xxm + patch11.x[2][i-4]);
1204
2.07M
      patch11.y[1][i-4] = 0.5 * (yym + patch11.y[2][i-4]);
1205
2.07M
      patch01.x[3][i-4] = 0.5 * (patch01.x[2][i-4] + patch11.x[1][i-4]);
1206
2.07M
      patch01.y[3][i-4] = 0.5 * (patch01.y[2][i-4] + patch11.y[1][i-4]);
1207
2.07M
      patch11.x[0][i-4] = patch01.x[3][i-4];
1208
2.07M
      patch11.y[0][i-4] = patch01.y[3][i-4];
1209
2.07M
      patch11.x[3][i-4] = xx[3][i];
1210
2.07M
      patch11.y[3][i-4] = yy[3][i];
1211
2.07M
    }
1212
2.59M
    for (int i = 0; i < shading->getNComps(); ++i) {
1213
2.07M
      patch00.color[0][0][i] = patch->color[0][0][i];
1214
2.07M
      patch00.color[0][1][i] = 0.5 * (patch->color[0][0][i] +
1215
2.07M
              patch->color[0][1][i]);
1216
2.07M
      patch01.color[0][0][i] = patch00.color[0][1][i];
1217
2.07M
      patch01.color[0][1][i] = patch->color[0][1][i];
1218
2.07M
      patch01.color[1][1][i] = 0.5 * (patch->color[0][1][i] +
1219
2.07M
              patch->color[1][1][i]);
1220
2.07M
      patch11.color[0][1][i] = patch01.color[1][1][i];
1221
2.07M
      patch11.color[1][1][i] = patch->color[1][1][i];
1222
2.07M
      patch11.color[1][0][i] = 0.5 * (patch->color[1][1][i] +
1223
2.07M
              patch->color[1][0][i]);
1224
2.07M
      patch10.color[1][1][i] = patch11.color[1][0][i];
1225
2.07M
      patch10.color[1][0][i] = patch->color[1][0][i];
1226
2.07M
      patch10.color[0][0][i] = 0.5 * (patch->color[1][0][i] +
1227
2.07M
              patch->color[0][0][i]);
1228
2.07M
      patch00.color[1][0][i] = patch10.color[0][0][i];
1229
2.07M
      patch00.color[1][1][i] = 0.5 * (patch00.color[1][0][i] +
1230
2.07M
              patch01.color[1][1][i]);
1231
2.07M
      patch01.color[1][0][i] = patch00.color[1][1][i];
1232
2.07M
      patch11.color[0][0][i] = patch00.color[1][1][i];
1233
2.07M
      patch10.color[0][1][i] = patch00.color[1][1][i];
1234
2.07M
    }
1235
518k
    fillPatch(state, splash, mode, reverseVideo, xMin, yMin, &patch00,
1236
518k
        shading, depth + 1);
1237
518k
    fillPatch(state, splash, mode, reverseVideo, xMin, yMin, &patch10,
1238
518k
        shading, depth + 1);
1239
518k
    fillPatch(state, splash, mode, reverseVideo, xMin, yMin, &patch01,
1240
518k
        shading, depth + 1);
1241
518k
    fillPatch(state, splash, mode, reverseVideo, xMin, yMin, &patch11,
1242
518k
        shading, depth + 1);
1243
518k
  }
1244
2.07M
}
1245
1246
void ShadingImage::computeShadingColor(GfxState *state,
1247
               SplashColorMode mode,
1248
               GBool reverseVideo,
1249
               GfxColor *color,
1250
1.65M
               SplashColorPtr sColor) {
1251
1.65M
  GfxGray gray;
1252
1.65M
  GfxRGB rgb;
1253
1.65M
#if SPLASH_CMYK
1254
1.65M
  GfxCMYK cmyk;
1255
1.65M
#endif
1256
1257
1.65M
  state->setFillColor(color);
1258
1.65M
  switch (mode) {
1259
0
  case splashModeMono8:
1260
0
    state->getFillGray(&gray);
1261
0
    if (reverseVideo) {
1262
0
      gray = gfxColorComp1 - gray;
1263
0
    }
1264
0
    sColor[0] = colToByte(gray);
1265
0
    break;
1266
1.65M
  case splashModeRGB8:
1267
1.65M
    state->getFillRGB(&rgb);
1268
1.65M
    if (reverseVideo) {
1269
0
      rgb.r = gfxColorComp1 - rgb.r;
1270
0
      rgb.g = gfxColorComp1 - rgb.g;
1271
0
      rgb.b = gfxColorComp1 - rgb.b;
1272
0
    }
1273
1.65M
    sColor[0] = colToByte(rgb.r);
1274
1.65M
    sColor[1] = colToByte(rgb.g);
1275
1.65M
    sColor[2] = colToByte(rgb.b);
1276
1.65M
    break;
1277
0
#if SPLASH_CMYK
1278
0
  case splashModeCMYK8:
1279
0
    state->getFillCMYK(&cmyk);
1280
0
    sColor[0] = colToByte(cmyk.c);
1281
0
    sColor[1] = colToByte(cmyk.m);
1282
0
    sColor[2] = colToByte(cmyk.y);
1283
0
    sColor[3] = colToByte(cmyk.k);
1284
0
    break;
1285
0
#endif
1286
0
  case splashModeMono1:
1287
0
  case splashModeBGR8:
1288
    // mode cannot be Mono1 or BGR8
1289
0
    break;
1290
1.65M
  }
1291
1.65M
}
1292
1293
// Transform a user space bbox to a device space bbox.
1294
void ShadingImage::transformBBox(GfxState *state,
1295
         double uxMin, double uyMin,
1296
         double uxMax, double uyMax,
1297
         double *dxMin, double *dyMin,
1298
8
         double *dxMax, double *dyMax) {
1299
8
  double tx, ty;
1300
8
  state->transform(uxMin, uyMin, &tx, &ty);
1301
8
  *dxMin = *dxMax = tx;
1302
8
  *dyMin = *dyMax = ty;
1303
8
  state->transform(uxMin, uyMax, &tx, &ty);
1304
8
  if (tx < *dxMin) {
1305
1
    *dxMin = tx;
1306
7
  } else if (tx > *dxMax) {
1307
0
    *dxMax = tx;
1308
0
  }
1309
8
  if (ty < *dyMin) {
1310
2
    *dyMin = ty;
1311
6
  } else if (ty > *dyMax) {
1312
1
    *dyMax = ty;
1313
1
  }
1314
8
  state->transform(uxMax, uyMin, &tx, &ty);
1315
8
  if (tx < *dxMin) {
1316
0
    *dxMin = tx;
1317
8
  } else if (tx > *dxMax) {
1318
5
    *dxMax = tx;
1319
5
  }
1320
8
  if (ty < *dyMin) {
1321
0
    *dyMin = ty;
1322
8
  } else if (ty > *dyMax) {
1323
0
    *dyMax = ty;
1324
0
  }
1325
8
  state->transform(uxMax, uyMax, &tx, &ty);
1326
8
  if (tx < *dxMin) {
1327
0
    *dxMin = tx;
1328
8
  } else if (tx > *dxMax) {
1329
0
    *dxMax = tx;
1330
0
  }
1331
8
  if (ty < *dyMin) {
1332
0
    *dyMin = ty;
1333
8
  } else if (ty > *dyMax) {
1334
0
    *dyMax = ty;
1335
0
  }
1336
8
}
1337