Coverage Report

Created: 2023-09-25 06:41

/src/xpdf-4.04/splash/SplashClip.cc
Line
Count
Source (jump to first uncovered line)
1
//========================================================================
2
//
3
// SplashClip.cc
4
//
5
// Copyright 2003-2013 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 "gmem.h"
18
#include "gmempp.h"
19
#include "SplashErrorCodes.h"
20
#include "SplashPath.h"
21
#include "SplashXPath.h"
22
#include "SplashXPathScanner.h"
23
#include "SplashClip.h"
24
25
//------------------------------------------------------------------------
26
27
// Compute x * y / 255, where x and y are in [0, 255].
28
0
static inline Guchar mul255(Guchar x, Guchar y) {
29
0
  int z;
30
31
0
  z = (int)x * (int)y;
32
0
  return (Guchar)((z + (z >> 8) + 0x80) >> 8);
33
0
}
34
35
//------------------------------------------------------------------------
36
// SplashClip
37
//------------------------------------------------------------------------
38
39
SplashClip::SplashClip(int hardXMinA, int hardYMinA,
40
0
           int hardXMaxA, int hardYMaxA) {
41
0
  int w;
42
43
0
  hardXMin = hardXMinA;
44
0
  hardYMin = hardYMinA;
45
0
  hardXMax = hardXMaxA;
46
0
  hardYMax = hardYMaxA;
47
0
  xMin = hardXMin;
48
0
  yMin = hardYMin;
49
0
  xMax = hardXMax;
50
0
  yMax = hardYMax;
51
0
  intBoundsValid = gFalse;
52
0
  paths = NULL;
53
0
  eo = NULL;
54
0
  scanners = NULL;
55
0
  length = size = 0;
56
0
  isSimple = gTrue;
57
0
  prev = NULL;
58
0
  if ((w = hardXMax + 1) <= 0) {
59
0
    w = 1;
60
0
  }
61
0
  buf = (Guchar *)gmalloc(w);
62
0
}
63
64
0
SplashClip::SplashClip(SplashClip *clip) {
65
0
  int w;
66
67
0
  hardXMin = clip->hardXMin;
68
0
  hardYMin = clip->hardYMin;
69
0
  hardXMax = clip->hardXMax;
70
0
  hardYMax = clip->hardYMax;
71
0
  xMin = clip->xMin;
72
0
  yMin = clip->yMin;
73
0
  xMax = clip->xMax;
74
0
  yMax = clip->yMax;
75
0
  xMinI = clip->xMinI;
76
0
  yMinI = clip->yMinI;
77
0
  xMaxI = clip->xMaxI;
78
0
  yMaxI = clip->yMaxI;
79
0
  intBoundsValid = clip->intBoundsValid;
80
0
  intBoundsStrokeAdjust = clip->intBoundsStrokeAdjust;
81
0
  paths = NULL;
82
0
  eo = NULL;
83
0
  scanners = NULL;
84
0
  length = size = 0;
85
0
  isSimple = clip->isSimple;
86
0
  prev = clip;
87
0
  if ((w = splashCeil(xMax)) <= 0) {
88
0
    w = 1;
89
0
  }
90
0
  buf = (Guchar *)gmalloc(w);
91
0
}
92
93
0
SplashClip::~SplashClip() {
94
0
  int i;
95
96
0
  for (i = 0; i < length; ++i) {
97
0
    delete scanners[i];
98
0
    delete paths[i];
99
0
  }
100
0
  gfree(paths);
101
0
  gfree(eo);
102
0
  gfree(scanners);
103
0
  gfree(buf);
104
0
}
105
106
0
void SplashClip::grow(int nPaths) {
107
0
  if (length + nPaths > size) {
108
0
    if (size == 0) {
109
0
      size = 32;
110
0
    }
111
0
    while (size < length + nPaths) {
112
0
      size *= 2;
113
0
    }
114
0
    paths = (SplashXPath **)greallocn(paths, size, sizeof(SplashXPath *));
115
0
    eo = (Guchar *)greallocn(eo, size, sizeof(Guchar));
116
0
    scanners = (SplashXPathScanner **)
117
0
                   greallocn(scanners, size, sizeof(SplashXPathScanner *));
118
0
  }
119
0
}
120
121
void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0,
122
0
           SplashCoord x1, SplashCoord y1) {
123
0
  int w, i;
124
125
0
  for (i = 0; i < length; ++i) {
126
0
    delete paths[i];
127
0
    delete scanners[i];
128
0
  }
129
0
  gfree(paths);
130
0
  gfree(eo);
131
0
  gfree(scanners);
132
0
  gfree(buf);
133
0
  paths = NULL;
134
0
  eo = NULL;
135
0
  scanners = NULL;
136
0
  length = size = 0;
137
0
  isSimple = gTrue;
138
0
  prev = NULL;
139
140
0
  if (x0 < x1) {
141
0
    xMin = x0;
142
0
    xMax = x1;
143
0
  } else {
144
0
    xMin = x1;
145
0
    xMax = x0;
146
0
  }
147
0
  if (y0 < y1) {
148
0
    yMin = y0;
149
0
    yMax = y1;
150
0
  } else {
151
0
    yMin = y1;
152
0
    yMax = y0;
153
0
  }
154
0
  intBoundsValid = gFalse;
155
0
  if ((w = splashCeil(xMax)) <= 0) {
156
0
    w = 1;
157
0
  }
158
0
  buf = (Guchar *)gmalloc(w);
159
0
}
160
161
SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0,
162
0
           SplashCoord x1, SplashCoord y1) {
163
0
  if (x0 < x1) {
164
0
    if (x0 > xMin) {
165
0
      xMin = x0;
166
0
      intBoundsValid = gFalse;
167
0
    }
168
0
    if (x1 < xMax) {
169
0
      xMax = x1;
170
0
      intBoundsValid = gFalse;
171
0
    }
172
0
  } else {
173
0
    if (x1 > xMin) {
174
0
      xMin = x1;
175
0
      intBoundsValid = gFalse;
176
0
    }
177
0
    if (x0 < xMax) {
178
0
      xMax = x0;
179
0
      intBoundsValid = gFalse;
180
0
    }
181
0
  }
182
0
  if (y0 < y1) {
183
0
    if (y0 > yMin) {
184
0
      yMin = y0;
185
0
      intBoundsValid = gFalse;
186
0
    }
187
0
    if (y1 < yMax) {
188
0
      yMax = y1;
189
0
      intBoundsValid = gFalse;
190
0
    }
191
0
  } else {
192
0
    if (y1 > yMin) {
193
0
      yMin = y1;
194
0
      intBoundsValid = gFalse;
195
0
    }
196
0
    if (y0 < yMax) {
197
0
      yMax = y0;
198
0
      intBoundsValid = gFalse;
199
0
    }
200
0
  }
201
0
  return splashOk;
202
0
}
203
204
SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix,
205
           SplashCoord flatness, GBool eoA,
206
           GBool enablePathSimplification,
207
0
           SplashStrokeAdjustMode strokeAdjust) {
208
0
  SplashXPath *xPath;
209
0
  SplashCoord t;
210
211
0
  xPath = new SplashXPath(path, matrix, flatness, gTrue,
212
0
        enablePathSimplification,
213
0
        strokeAdjust);
214
215
  // check for an empty path
216
0
  if (xPath->length == 0) {
217
0
    xMin = yMin = 1;
218
0
    xMax = yMax = 0;
219
0
    intBoundsValid = gFalse;
220
0
    delete xPath;
221
0
    return splashOk;
222
0
  }
223
224
  // check for a rectangle
225
0
  if (xPath->isRect) {
226
0
    clipToRect(xPath->rectX0, xPath->rectY0, xPath->rectX1, xPath->rectY1);
227
0
    delete xPath;
228
0
    return splashOk;
229
0
  }
230
231
0
  grow(1);
232
0
  paths[length] = xPath;
233
0
  eo[length] = (Guchar)eoA;
234
0
  if ((t = xPath->getXMin()) > xMin) {
235
0
    xMin = t;
236
0
  }
237
0
  if ((t = xPath->getYMin()) > yMin) {
238
0
    yMin = t;
239
0
  }
240
0
  if ((t = xPath->getXMax() + 1) < xMax) {
241
0
    xMax = t;
242
0
  }
243
0
  if ((t = xPath->getYMax() + 1) < yMax) {
244
0
    yMax = t;
245
0
  }
246
0
  intBoundsValid = gFalse;
247
0
  scanners[length] = new SplashXPathScanner(xPath, eoA, splashFloor(yMin),
248
0
              splashCeil(yMax) - 1);
249
0
  ++length;
250
0
  isSimple = gFalse;
251
252
0
  return splashOk;
253
0
}
254
255
SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin,
256
              int rectXMax, int rectYMax,
257
0
              SplashStrokeAdjustMode strokeAdjust) {
258
  // In general, this function tests the rectangle:
259
  //     x = [rectXMin, rectXMax + 1)    (note: coords are ints)
260
  //     y = [rectYMin, rectYMax + 1)
261
  // against the clipping region:
262
  //     x = [xMin, xMax)                (note: coords are fp)
263
  //     y = [yMin, yMax)
264
265
0
  if (strokeAdjust != splashStrokeAdjustOff && isSimple) {
266
    // special case for stroke adjustment with a simple clipping
267
    // rectangle -- the clipping region is:
268
    //     x = [xMinI, xMaxI + 1)
269
    //     y = [yMinI, yMaxI + 1)
270
0
    updateIntBounds(strokeAdjust);
271
0
    if (xMinI > xMaxI || yMinI > yMaxI) {
272
0
      return splashClipAllOutside;
273
0
    }
274
0
    if (rectXMax + 1 <= xMinI ||
275
0
  rectXMin >= xMaxI + 1 ||
276
0
  rectYMax + 1 <= yMinI ||
277
0
  rectYMin >= yMaxI + 1) {
278
0
      return splashClipAllOutside;
279
0
    }
280
0
    if (rectXMin >= xMinI &&
281
0
  rectXMax <= xMaxI &&
282
0
  rectYMin >= yMinI &&
283
0
  rectYMax <= yMaxI) {
284
0
      return splashClipAllInside;
285
0
    }
286
0
  } else {
287
0
    if (xMin >= xMax || yMin >= yMax) {
288
0
      return splashClipAllOutside;
289
0
    }
290
0
    if ((SplashCoord)(rectXMax + 1) <= xMin ||
291
0
  (SplashCoord)rectXMin >= xMax ||
292
0
  (SplashCoord)(rectYMax + 1) <= yMin ||
293
0
  (SplashCoord)rectYMin >= yMax) {
294
0
      return splashClipAllOutside;
295
0
    }
296
0
    if (isSimple &&
297
0
  (SplashCoord)rectXMin >= xMin &&
298
0
  (SplashCoord)(rectXMax + 1) <= xMax &&
299
0
  (SplashCoord)rectYMin >= yMin &&
300
0
  (SplashCoord)(rectYMax + 1) <= yMax) {
301
0
      return splashClipAllInside;
302
0
    }
303
0
  }
304
0
  return splashClipPartial;
305
0
}
306
307
void SplashClip::clipSpan(Guchar *line, int y, int x0, int x1,
308
0
        SplashStrokeAdjustMode strokeAdjust) {
309
0
  SplashClip *clip;
310
0
  SplashCoord d;
311
0
  int x0a, x1a, x0b, x1b, x, i;
312
313
0
  updateIntBounds(strokeAdjust);
314
315
  //--- clip to the integer rectangle
316
317
0
  if (y < yMinI || y > yMaxI ||
318
0
      x1 < xMinI || x0 > xMaxI) {
319
0
    memset(line + x0, 0, x1 - x0 + 1);
320
0
    return;
321
0
  }
322
323
0
  if (x0 > xMinI) {
324
0
    x0a = x0;
325
0
  } else {
326
0
    x0a = xMinI;
327
0
    memset(line + x0, 0, x0a - x0);
328
0
  }
329
330
0
  if (x1 < xMaxI) {
331
0
    x1a = x1;
332
0
  } else {
333
0
    x1a = xMaxI;
334
0
    memset(line + x1a + 1, 0, x1 - x1a);
335
0
  }
336
337
0
  if (x0a > x1a) {
338
0
    return;
339
0
  }
340
341
  //--- clip to the floating point rectangle
342
  //    (if stroke adjustment is disabled)
343
344
0
  if (strokeAdjust == splashStrokeAdjustOff) {
345
346
    // clip left edge (xMin)
347
0
    if (x0a == xMinI) {
348
0
      d = (SplashCoord)(xMinI + 1) - xMin;
349
0
      line[x0a] = (Guchar)(int)((SplashCoord)line[x0a] * d);
350
0
    }
351
352
    // clip right edge (xMax)
353
0
    if (x1a == xMaxI) {
354
0
      d = xMax - (SplashCoord)xMaxI;
355
0
      line[x1a] = (Guchar)(int)((SplashCoord)line[x1a] * d);
356
0
    }
357
358
    // clip top edge (yMin)
359
0
    if (y == yMinI) {
360
0
      d = (SplashCoord)(yMinI + 1) - yMin;
361
0
      for (x = x0a; x <= x1a; ++x) {
362
0
  line[x] = (Guchar)(int)((SplashCoord)line[x] * d);
363
0
      }
364
0
    }
365
366
    // clip bottom edge (yMax)
367
0
    if (y == yMaxI) {
368
0
      d = yMax - (SplashCoord)yMaxI;
369
0
      for (x = x0a; x <= x1a; ++x) {
370
0
  line[x] = (Guchar)(int)((SplashCoord)line[x] * d);
371
0
      }
372
0
    }
373
0
  }
374
375
0
  if (isSimple) {
376
0
    return;
377
0
  }
378
379
  //--- clip to the paths
380
381
0
  for (clip = this; clip; clip = clip->prev) {
382
0
    for (i = 0; i < clip->length; ++i) {
383
0
      clip->scanners[i]->getSpan(buf, y, x0a, x1a, &x0b, &x1b);
384
0
      if (x0a < x0b) {
385
0
  memset(line + x0a, 0, x0b - x0a);
386
0
      }
387
0
      for (x = x0b; x <= x1b; ++x) {
388
0
  line[x] = mul255(line[x], buf[x]);
389
0
      }
390
0
      if (x1b < x1a) {
391
0
  memset(line + x1b + 1, 0, x1a - x1b);
392
0
      }
393
0
    }
394
0
  }
395
0
}
396
397
GBool SplashClip::clipSpanBinary(Guchar *line, int y, int x0, int x1,
398
0
         SplashStrokeAdjustMode strokeAdjust) {
399
0
  SplashClip *clip;
400
0
  int x0a, x1a, x0b, x1b, x, i;
401
0
  Guchar any;
402
403
0
  updateIntBounds(strokeAdjust);
404
405
0
  if (y < yMinI || y > yMaxI ||
406
0
      x1 < xMinI || x0 > xMaxI) {
407
0
    if (x0 <= x1) {
408
0
      memset(line + x0, 0, x1 - x0 + 1);
409
0
    }
410
0
    return gFalse;
411
0
  }
412
413
0
  if (x0 > xMinI) {
414
0
    x0a = x0;
415
0
  } else {
416
0
    x0a = xMinI;
417
0
    memset(line + x0, 0, x0a - x0);
418
0
  }
419
420
0
  if (x1 < xMaxI) {
421
0
    x1a = x1;
422
0
  } else {
423
0
    x1a = xMaxI;
424
0
    memset(line + x1a + 1, 0, x1 - x1a);
425
0
  }
426
427
0
  if (x0a > x1a) {
428
0
    return gFalse;
429
0
  }
430
431
0
  if (isSimple) {
432
0
    for (x = x0a; x <= x1a; ++x) {
433
0
      if (line[x]) {
434
0
  return gTrue;
435
0
      }
436
0
    }
437
0
    return gFalse;
438
0
  }
439
440
0
  any = 0;
441
0
  for (clip = this; clip; clip = clip->prev) {
442
0
    for (i = 0; i < clip->length; ++i) {
443
0
      clip->scanners[i]->getSpanBinary(buf, y, x0a, x1a, &x0b, &x1b);
444
0
      if (x0a < x0b) {
445
0
  memset(line + x0a, 0, x0b - x0a);
446
0
      }
447
0
      for (x = x0b; x <= x1b; ++x) {
448
0
  line[x] &= buf[x];
449
0
  any |= line[x];
450
0
      }
451
0
      if (x1b < x1a) {
452
0
  memset(line + x1b + 1, 0, x1a - x1b);
453
0
      }
454
0
    }
455
0
  }
456
457
0
  return any != 0;
458
0
}
459
460
0
int SplashClip::getXMinI(SplashStrokeAdjustMode strokeAdjust) {
461
0
  updateIntBounds(strokeAdjust);
462
0
  return xMinI;
463
0
}
464
465
0
int SplashClip::getXMaxI(SplashStrokeAdjustMode strokeAdjust) {
466
0
  updateIntBounds(strokeAdjust);
467
0
  return xMaxI;
468
0
}
469
470
0
int SplashClip::getYMinI(SplashStrokeAdjustMode strokeAdjust) {
471
0
  updateIntBounds(strokeAdjust);
472
0
  return yMinI;
473
0
}
474
475
0
int SplashClip::getYMaxI(SplashStrokeAdjustMode strokeAdjust) {
476
0
  updateIntBounds(strokeAdjust);
477
0
  return yMaxI;
478
0
}
479
480
0
int SplashClip::getNumPaths() {
481
0
  SplashClip *clip;
482
0
  int n;
483
484
0
  n = 0;
485
0
  for (clip = this; clip; clip = clip->prev) {
486
0
    n += clip->length;
487
0
  }
488
0
  return n;
489
0
}
490
491
0
void SplashClip::updateIntBounds(SplashStrokeAdjustMode strokeAdjust) {
492
0
  if (intBoundsValid && strokeAdjust == intBoundsStrokeAdjust) {
493
0
    return;
494
0
  }
495
0
  if (strokeAdjust != splashStrokeAdjustOff && isSimple) {
496
0
    splashStrokeAdjust(xMin, xMax, &xMinI, &xMaxI, strokeAdjust);
497
0
    splashStrokeAdjust(yMin, yMax, &yMinI, &yMaxI, strokeAdjust);
498
0
  } else {
499
0
    xMinI = splashFloor(xMin);
500
0
    yMinI = splashFloor(yMin);
501
0
    xMaxI = splashCeil(xMax);
502
0
    yMaxI = splashCeil(yMax);
503
0
  }
504
0
  if (xMinI < hardXMin) {
505
0
    xMinI = hardXMin;
506
0
  }
507
0
  if (yMinI < hardYMin) {
508
0
    yMinI = hardYMin;
509
0
  }
510
0
  if (xMaxI > hardXMax) {
511
0
    xMaxI = hardXMax;
512
0
  }
513
0
  if (yMaxI > hardYMax) {
514
0
    yMaxI = hardYMax;
515
0
  }
516
  // the clipping code uses [xMinI, xMaxI] instead of [xMinI, xMaxI)
517
0
  --xMaxI;
518
0
  --yMaxI;
519
0
  intBoundsValid = gTrue;
520
0
  intBoundsStrokeAdjust = strokeAdjust;
521
0
}