Coverage Report

Created: 2025-09-04 06:50

/src/mupdf/source/fitz/draw-edgebuffer.c
Line
Count
Source (jump to first uncovered line)
1
// Copyright (C) 2004-2025 Artifex Software, Inc.
2
//
3
// This file is part of MuPDF.
4
//
5
// MuPDF is free software: you can redistribute it and/or modify it under the
6
// terms of the GNU Affero General Public License as published by the Free
7
// Software Foundation, either version 3 of the License, or (at your option)
8
// any later version.
9
//
10
// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
11
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12
// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
// details.
14
//
15
// You should have received a copy of the GNU Affero General Public License
16
// along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
17
//
18
// Alternative licensing terms are available from the licensor.
19
// For commercial licensing, see <https://www.artifex.com/> or contact
20
// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
21
// CA 94129, USA, for further information.
22
23
#include "mupdf/fitz.h"
24
#include "draw-imp.h"
25
26
#include <assert.h>
27
#include <stdlib.h>
28
#include <string.h>
29
#include <limits.h>
30
31
#undef DEBUG_SCAN_CONVERTER
32
33
/* Define ourselves a 'fixed' type for clarity */
34
typedef int fixed;
35
36
0
#define fixed_shift 8
37
0
#define float2fixed(x) ((int)((x)*(1<<fixed_shift)))
38
0
#define fixed2int(x) ((int)((x)>>fixed_shift))
39
0
#define fixed_half (1<<(fixed_shift-1))
40
0
#define fixed_1 (1<<fixed_shift)
41
0
#define int2fixed(x) ((x)<<fixed_shift)
42
43
enum
44
{
45
  DIRN_UNSET = -1,
46
  DIRN_UP = 0,
47
  DIRN_DOWN = 1
48
};
49
50
typedef struct
51
{
52
  fixed left;
53
  fixed right;
54
  fixed y;
55
  signed char d; /* 0 up (or horiz), 1 down, -1 uninited */
56
57
  /* unset == 1, iff the values in the above are unset */
58
  unsigned char unset;
59
  /* can_save == 1, iff we are eligible to 'save'. i.e. if we
60
   * have not yet output a cursor, and have not detected
61
   * any line segments completely out of range. */
62
  unsigned char can_save;
63
  unsigned char saved;
64
65
  fixed save_left;
66
  fixed save_right;
67
  int save_iy;
68
  int save_d;
69
}
70
cursor_t;
71
72
typedef struct fz_edgebuffer_s
73
{
74
  fz_rasterizer super;
75
  int app;
76
  int sorted;
77
  int n;
78
  int index_cap;
79
  int *index;
80
  int table_cap;
81
  int *table;
82
83
  /* cursor section, for use with any part of pixel mode */
84
  cursor_t cursor[3];
85
} fz_edgebuffer;
86
87
static fz_rasterizer_insert_fn fz_insert_edgebuffer_app;
88
static fz_rasterizer_insert_fn fz_insert_edgebuffer;
89
90
#ifdef DEBUG_SCAN_CONVERTER
91
int debugging_scan_converter = 1;
92
93
static void
94
fz_edgebuffer_print(fz_context *ctx, fz_output *out, fz_edgebuffer * edgebuffer)
95
{
96
  int i;
97
  int height = edgebuffer->super.clip.y1 - edgebuffer->super.clip.y0;
98
99
  fz_write_printf(ctx, out, "Edgebuffer %x\n", edgebuffer);
100
  fz_write_printf(ctx, out, "xmin=%x xmax=%x base=%x height=%x\n",
101
        edgebuffer->super.clip.x0, edgebuffer->super.clip.x1, edgebuffer->super.clip.y0, height);
102
  for (i=0; i < height; i++) {
103
    int  offset = edgebuffer->index[i];
104
    int *row = &edgebuffer->table[offset];
105
    int count = *row++;
106
    assert ((count & 1) == 0);
107
    fz_write_printf(ctx, out, "%x @ %x: %d =", i, offset, count);
108
    while (count-- > 0) {
109
      int v = *row++;
110
      fz_write_printf(ctx, out, " %x:%d", v&~1, v&1);
111
    }
112
    fz_write_printf(ctx, out, "\n");
113
  }
114
}
115
116
static void
117
fz_edgebuffer_print_app(fz_context *ctx, fz_output *out, fz_edgebuffer * edgebuffer)
118
{
119
  int i;
120
  int height = edgebuffer->super.clip.y1 - edgebuffer->super.clip.y0;
121
122
  fz_write_printf(ctx, out, "Edgebuffer %x\n", edgebuffer);
123
  fz_write_printf(ctx, out, "xmin=%x xmax=%x base=%x height=%x\n",
124
        edgebuffer->super.clip.x0, edgebuffer->super.clip.x1, edgebuffer->super.clip.y0, height);
125
  if (edgebuffer->table == NULL)
126
    return;
127
  for (i=0; i < height; i++) {
128
    int  offset = edgebuffer->index[i];
129
    int *row = &edgebuffer->table[offset];
130
    int count = *row++;
131
    int count0 = count;
132
    fz_write_printf(ctx, out, "%x @ %x: %d =", i, offset, count);
133
    while (count-- > 0) {
134
      int l = *row++;
135
      int r = *row++;
136
      fz_write_printf(ctx, out, " %x:%x", l, r);
137
    }
138
    assert((count0 & 1) == 0); (void)count0;
139
    fz_write_printf(ctx, out, "\n");
140
  }
141
}
142
#endif
143
144
static void fz_drop_edgebuffer(fz_context *ctx, fz_rasterizer *r)
145
0
{
146
0
  fz_edgebuffer *eb = (fz_edgebuffer *)r;
147
148
0
  if (eb)
149
0
  {
150
0
    fz_free(ctx, eb->index);
151
0
    fz_free(ctx, eb->table);
152
0
  }
153
0
  fz_free(ctx, eb);
154
0
}
155
156
static void index_edgebuffer_insert(fz_context *ctx, fz_rasterizer *ras, float fsx, float fsy, float fex, float fey, int rev)
157
0
{
158
0
  fz_edgebuffer *eb = (fz_edgebuffer *)ras;
159
0
  int iminy, imaxy;
160
0
  int height = eb->super.clip.y1 - eb->super.clip.y0;
161
162
0
  if (fsy == fey)
163
0
    return;
164
165
0
  if (fsx < fex)
166
0
  {
167
0
    if (fsx < eb->super.bbox.x0) eb->super.bbox.x0 = fsx;
168
0
    if (fex > eb->super.bbox.x1) eb->super.bbox.x1 = fex;
169
0
  }
170
0
  else
171
0
  {
172
0
    if (fsx > eb->super.bbox.x1) eb->super.bbox.x1 = fsx;
173
0
    if (fex < eb->super.bbox.x0) eb->super.bbox.x0 = fex;
174
0
  }
175
0
  if (fsy < fey)
176
0
  {
177
0
    if (fsy < eb->super.bbox.y0) eb->super.bbox.y0 = fsy;
178
0
    if (fey > eb->super.bbox.y1) eb->super.bbox.y1 = fey;
179
0
  }
180
0
  else
181
0
  {
182
0
    if (fey < eb->super.bbox.y0) eb->super.bbox.y0 = fey;
183
0
    if (fsy > eb->super.bbox.y1) eb->super.bbox.y1 = fsy;
184
0
  }
185
186
  /* To strictly match, this should be:
187
   * iminy = int2fixed(float2fixed(fsy))
188
   * imaxy = int2fixed(float2fixed(fsx))
189
   * but this is faster. It can round differently,
190
   * (on some machines at least) hence the iminy--; below.
191
   */
192
0
  iminy = (int)fsy;
193
0
  imaxy = (int)fey;
194
195
0
  if (iminy > imaxy)
196
0
  {
197
0
    int t;
198
0
    t = iminy; iminy = imaxy; imaxy = t;
199
0
  }
200
0
  imaxy++;
201
0
  iminy--;
202
203
0
  imaxy -= eb->super.clip.y0;
204
0
  if (imaxy < 0)
205
0
    return;
206
0
  iminy -= eb->super.clip.y0;
207
0
  if (iminy < 0)
208
0
    iminy = 0;
209
0
  else if (iminy > height)
210
0
    return;
211
0
  if (imaxy > height-1)
212
0
    imaxy = height-1;
213
#ifdef DEBUG_SCAN_CONVERTER
214
  if (debugging_scan_converter)
215
    fprintf(stderr, "%x->%x:%d\n", iminy, imaxy, eb->n);
216
#endif
217
0
  eb->index[iminy] += eb->n;
218
0
  eb->index[imaxy+1] -= eb->n;
219
0
}
220
221
static void fz_postindex_edgebuffer(fz_context *ctx, fz_rasterizer *r)
222
0
{
223
0
  fz_edgebuffer *eb = (fz_edgebuffer *)r;
224
0
  int height = eb->super.clip.y1 - eb->super.clip.y0 + 1;
225
0
  int n = eb->n;
226
0
  int total = 0;
227
0
  int delta = 0;
228
0
  int i;
229
230
0
  eb->super.fns.insert = (eb->app ? fz_insert_edgebuffer_app : fz_insert_edgebuffer);
231
232
0
  for (i = 0; i < height; i++)
233
0
  {
234
0
    delta += eb->index[i];
235
0
    eb->index[i] = total;
236
0
    total += 1 + delta*n;
237
0
  }
238
0
  assert(delta == 0);
239
240
0
  if (eb->table_cap < total)
241
0
  {
242
0
    eb->table = fz_realloc_array(ctx, eb->table, total, int);
243
0
    eb->table_cap = total;
244
0
  }
245
246
0
  for (i = 0; i < height; i++)
247
0
  {
248
0
    eb->table[eb->index[i]] = 0;
249
0
  }
250
0
}
251
252
static int fz_reset_edgebuffer(fz_context *ctx, fz_rasterizer *r)
253
0
{
254
0
  fz_edgebuffer *eb = (fz_edgebuffer *)r;
255
0
  int height = eb->super.clip.y1 - eb->super.clip.y0 + 1;
256
0
  int n;
257
258
0
  eb->sorted = 0;
259
260
0
  if (eb->index_cap < height)
261
0
  {
262
0
    eb->index = fz_realloc_array(ctx, eb->index, height, int);
263
0
    eb->index_cap = height;
264
0
  }
265
0
  memset(eb->index, 0, sizeof(int) * height);
266
267
0
  n = 1;
268
269
0
  if (eb->app)
270
0
  {
271
0
    n = 2;
272
0
    eb->cursor[0].saved = 0;
273
0
    eb->cursor[0].unset = 1;
274
0
    eb->cursor[0].can_save = 1;
275
0
    eb->cursor[0].d = DIRN_UNSET;
276
0
    eb->cursor[1].saved = 0;
277
0
    eb->cursor[1].unset = 1;
278
0
    eb->cursor[1].can_save = 1;
279
0
    eb->cursor[1].d = DIRN_UNSET;
280
0
    eb->cursor[2].saved = 0;
281
0
    eb->cursor[2].unset = 1;
282
0
    eb->cursor[2].can_save = 1;
283
0
    eb->cursor[2].d = DIRN_UNSET;
284
0
  }
285
286
0
  eb->n = n;
287
288
0
  eb->super.fns.insert = index_edgebuffer_insert;
289
0
  return 1;
290
0
}
291
292
static void mark_line(fz_context *ctx, fz_edgebuffer *eb, fixed sx, fixed sy, fixed ex, fixed ey)
293
0
{
294
0
  int base_y = eb->super.clip.y0;
295
0
  int height = eb->super.clip.y1 - eb->super.clip.y0;
296
0
  int *table = eb->table;
297
0
  int *index = eb->index;
298
0
  int delta;
299
0
  int iy, ih;
300
0
  fixed clip_sy, clip_ey;
301
0
  int dirn = DIRN_UP;
302
0
  int *row;
303
304
0
  if (fixed2int(sy + fixed_half-1) == fixed2int(ey + fixed_half-1))
305
0
    return;
306
0
  if (sy > ey) {
307
0
    int t;
308
0
    t = sy; sy = ey; ey = t;
309
0
    t = sx; sx = ex; ex = t;
310
0
    dirn = DIRN_DOWN;
311
0
  }
312
313
0
  if (fixed2int(sx) < eb->super.bbox.x0)
314
0
    eb->super.bbox.x0 = fixed2int(sx);
315
0
  if (fixed2int(sx + fixed_1 - 1) > eb->super.bbox.x1)
316
0
    eb->super.bbox.x1 = fixed2int(sx + fixed_1 - 1);
317
0
  if (fixed2int(ex) < eb->super.bbox.x0)
318
0
    eb->super.bbox.x0 = fixed2int(ex);
319
0
  if (fixed2int(ex + fixed_1 - 1) > eb->super.bbox.x1)
320
0
    eb->super.bbox.x1 = fixed2int(ex + fixed_1 - 1);
321
322
0
  if (fixed2int(sy) < eb->super.bbox.y0)
323
0
    eb->super.bbox.y0 = fixed2int(sy);
324
0
  if (fixed2int(ey + fixed_1 - 1) > eb->super.bbox.y1)
325
0
    eb->super.bbox.y1 = fixed2int(ey + fixed_1 - 1);
326
327
  /* Lines go from sy to ey, closed at the start, open at the end. */
328
  /* We clip them to a region to make them closed at both ends. */
329
  /* Thus the unset scanline marked (>= sy) is: */
330
0
  clip_sy = ((sy + fixed_half - 1) & ~(fixed_1-1)) | fixed_half;
331
  /* The last scanline marked (< ey) is: */
332
0
  clip_ey = ((ey - fixed_half - 1) & ~(fixed_1-1)) | fixed_half;
333
  /* Now allow for banding */
334
0
  if (clip_sy < int2fixed(base_y) + fixed_half)
335
0
    clip_sy = int2fixed(base_y) + fixed_half;
336
0
  if (ey <= clip_sy)
337
0
    return;
338
0
  if (clip_ey > int2fixed(base_y + height - 1) + fixed_half)
339
0
    clip_ey = int2fixed(base_y + height - 1) + fixed_half;
340
0
  if (sy > clip_ey)
341
0
    return;
342
0
  delta = clip_sy - sy;
343
0
  if (delta > 0)
344
0
  {
345
0
    int dx = ex - sx;
346
0
    int dy = ey - sy;
347
0
    int advance = (int)(((int64_t)dx * delta + (dy>>1)) / dy);
348
0
    sx += advance;
349
0
    sy += delta;
350
0
  }
351
0
  ex -= sx;
352
0
  ey -= sy;
353
0
  clip_ey -= clip_sy;
354
0
  delta = ey - clip_ey;
355
0
  if (delta > 0)
356
0
  {
357
0
    int advance = (int)(((int64_t)ex * delta + (ey>>1)) / ey);
358
0
    ex -= advance;
359
0
    ey -= delta;
360
0
  }
361
0
  ih = fixed2int(ey);
362
0
  assert(ih >= 0);
363
0
  iy = fixed2int(sy) - base_y;
364
#ifdef DEBUG_SCAN_CONVERTER
365
  if (debugging_scan_converter)
366
    fz_write_printf(ctx, fz_stderr(ctx), "  iy=%x ih=%x\n", iy, ih);
367
#endif
368
0
  assert(iy >= 0 && iy < height);
369
  /* We always cross at least one scanline */
370
0
  row = &table[index[iy]];
371
0
  *row = (*row)+1; /* Increment the count */
372
0
  row[*row] = (sx&~1) | dirn;
373
0
  if (ih == 0)
374
0
    return;
375
0
  if (ex >= 0) {
376
0
    int x_inc, n_inc, f;
377
378
    /* We want to change sx by ex in ih steps. So each step, we add
379
     * ex/ih to sx. That's x_inc + n_inc/ih.
380
     */
381
0
    x_inc = ex/ih;
382
0
    n_inc = ex-(x_inc*ih);
383
0
    f  = ih>>1;
384
0
    delta = ih;
385
0
    do {
386
0
      int count;
387
0
      iy++;
388
0
      sx += x_inc;
389
0
      f  -= n_inc;
390
0
      if (f < 0) {
391
0
        f += ih;
392
0
        sx++;
393
0
      }
394
0
      assert(iy >= 0 && iy < height);
395
0
      row = &table[index[iy]];
396
0
      count = *row = (*row)+1; /* Increment the count */
397
0
      row[count] = (sx&~1) | dirn;
398
0
    } while (--delta);
399
0
  } else {
400
0
    int x_dec, n_dec, f;
401
402
0
    ex = -ex;
403
    /* We want to change sx by ex in ih steps. So each step, we subtract
404
     * ex/ih from sx. That's x_dec + n_dec/ih.
405
     */
406
0
    x_dec = ex/ih;
407
0
    n_dec = ex-(x_dec*ih);
408
0
    f  = ih>>1;
409
0
    delta = ih;
410
0
    do {
411
0
      int count;
412
0
      iy++;
413
0
      sx -= x_dec;
414
0
      f  -= n_dec;
415
0
      if (f < 0) {
416
0
        f += ih;
417
0
        sx--;
418
0
      }
419
0
      assert(iy >= 0 && iy < height);
420
0
      row = &table[index[iy]];
421
0
      count = *row = (*row)+1; /* Increment the count */
422
0
      row[count] = (sx&~1) | dirn;
423
0
    } while (--delta);
424
0
  }
425
0
}
426
427
/* Allow for floats that are too large to safely convert to fixeds (ints),
428
 * by just clipping them at the end. */
429
static fixed
430
safe_float2fixed(float f)
431
0
{
432
0
  if (f < (float)-0x00800000)
433
0
    return INT_MIN;
434
0
  else if (f >= (float)0x00800000)
435
0
    return INT_MAX;
436
0
  else
437
0
    return float2fixed(f);
438
0
}
439
440
static void fz_insert_edgebuffer(fz_context *ctx, fz_rasterizer *ras, float fsx, float fsy, float fex, float fey, int rev)
441
0
{
442
0
  fz_edgebuffer *eb = (fz_edgebuffer *)ras;
443
0
  fixed sx = safe_float2fixed(fsx);
444
0
  fixed sy = safe_float2fixed(fsy);
445
0
  fixed ex = safe_float2fixed(fex);
446
0
  fixed ey = safe_float2fixed(fey);
447
448
0
  mark_line(ctx, eb, sx, sy, ex, ey);
449
0
}
450
451
static inline void
452
cursor_output(fz_edgebuffer * FZ_RESTRICT eb, int rev, int iy)
453
0
{
454
0
  int *row;
455
0
  int count;
456
0
  int height = eb->super.clip.y1 - eb->super.clip.y0;
457
0
  cursor_t * FZ_RESTRICT cr = &eb->cursor[rev];
458
459
0
  rev &= 1; /* Edge label 0 is forwards, 1 and 2 are reverse */
460
461
0
  if (iy >= 0 && iy < height) {
462
0
    if (cr->can_save) {
463
      /* Save it for later in case we join up */
464
0
      cr->save_left = cr->left;
465
0
      cr->save_right = cr->right;
466
0
      cr->save_iy = iy;
467
0
      cr->save_d = cr->d;
468
0
      cr->saved = 1;
469
0
    } else {
470
      /* Enter it into the table */
471
0
      row = &eb->table[eb->index[iy]];
472
0
      if (cr->d == DIRN_UNSET)
473
0
      {
474
        /* Move 0 0; line 10 0; line 0 0; */
475
        /* FIXME */
476
0
      }
477
0
      else
478
0
      {
479
0
        *row = count = (*row)+1; /* Increment the count */
480
#ifdef DEBUG_SCAN_CONVERTER
481
        if (debugging_scan_converter)
482
          fprintf(stderr, "row: %x: %x->%x %c\n", iy, cr->left, cr->right, (cr->d^rev) == DIRN_UP ? '^' : (cr->d^rev) == DIRN_DOWN ? 'v' : '-');
483
#endif
484
0
        assert(count <= (eb->index[iy+1] - eb->index[iy] - 1)/2);
485
0
        row[2 * count - 1] = (cr->left&~1) | (cr->d ^ rev);
486
0
        row[2 * count] = cr->right;
487
0
      }
488
0
    }
489
0
  }
490
0
  cr->can_save = 0;
491
0
}
492
493
static inline void
494
cursor_output_inrange(fz_edgebuffer * FZ_RESTRICT eb, int rev, int iy)
495
0
{
496
0
  int *row;
497
0
  int count;
498
0
  cursor_t * FZ_RESTRICT cr = &eb->cursor[rev];
499
500
0
  rev &= 1; /* Edge label 0 is forwards, 1 and 2 are reverse */
501
502
0
  assert(iy >= 0 && iy < eb->super.clip.y1 - eb->super.clip.y0);
503
0
  if (cr->can_save) {
504
    /* Save it for later in case we join up */
505
0
    cr->save_left = cr->left;
506
0
    cr->save_right = cr->right;
507
0
    cr->save_iy = iy;
508
0
    cr->save_d = cr->d;
509
0
    cr->saved = 1;
510
0
  } else {
511
    /* Enter it into the table */
512
0
    assert(cr->d != DIRN_UNSET);
513
514
0
    row = &eb->table[eb->index[iy]];
515
0
    *row = count = (*row)+1; /* Increment the count */
516
#ifdef DEBUG_SCAN_CONVERTER
517
      if (debugging_scan_converter)
518
        printf("row= %x: %x->%x %c\n", iy, cr->left, cr->right, (cr->d^rev) == DIRN_UP ? '^' : (cr->d^rev) == DIRN_DOWN ? 'v' : '-');
519
#endif
520
0
    row[2 * count - 1] = (cr->left&~1) | (cr->d ^ rev);
521
0
    row[2 * count] = cr->right;
522
0
  }
523
0
  cr->can_save = 0;
524
0
}
525
526
/* Step the cursor in y, allowing for maybe crossing a scanline */
527
static inline void
528
cursor_step(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed dy, fixed x)
529
0
{
530
0
  cursor_t * FZ_RESTRICT cr = &eb->cursor[rev];
531
0
  int new_iy;
532
0
  int base = eb->super.clip.y0;
533
0
  int iy = fixed2int(cr->y) - base;
534
535
0
  cr->y += dy;
536
0
  new_iy = fixed2int(cr->y) - base;
537
0
  if (new_iy != iy) {
538
0
    cursor_output(eb, rev, iy);
539
0
    cr->left = x;
540
0
    cr->right = x;
541
0
  } else {
542
0
    if (x < cr->left)
543
0
      cr->left = x;
544
0
    if (x > cr->right)
545
0
      cr->right = x;
546
0
  }
547
0
}
548
549
/* Step the cursor in y, never by enough to cross a scanline. */
550
static inline void
551
cursor_never_step_vertical(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed dy, fixed x)
552
0
{
553
0
  cursor_t * FZ_RESTRICT cr = &eb->cursor[rev];
554
555
0
  assert(fixed2int(cr->y+dy) == fixed2int(cr->y));
556
557
0
  cr->y += dy;
558
0
}
559
560
/* Step the cursor in y, never by enough to cross a scanline,
561
 * knowing that we are moving left, and that the right edge
562
 * has already been accounted for. */
563
static inline void
564
cursor_never_step_left(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed dy, fixed x)
565
0
{
566
0
  cursor_t * FZ_RESTRICT cr = &eb->cursor[rev];
567
568
0
  assert(fixed2int(cr->y+dy) == fixed2int(cr->y));
569
570
0
  if (x < cr->left)
571
0
    cr->left = x;
572
0
  cr->y += dy;
573
0
}
574
575
/* Step the cursor in y, never by enough to cross a scanline,
576
 * knowing that we are moving right, and that the left edge
577
 * has already been accounted for. */
578
static inline void
579
cursor_never_step_right(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed dy, fixed x)
580
0
{
581
0
  cursor_t * FZ_RESTRICT cr = &eb->cursor[rev];
582
583
0
  assert(fixed2int(cr->y+dy) == fixed2int(cr->y));
584
585
0
  if (x > cr->right)
586
0
    cr->right = x;
587
0
  cr->y += dy;
588
0
}
589
590
/* Step the cursor in y, always by enough to cross a scanline. */
591
static inline void
592
cursor_always_step(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed dy, fixed x)
593
0
{
594
0
  cursor_t * FZ_RESTRICT cr = &eb->cursor[rev];
595
0
  int base = eb->super.clip.y0;
596
0
  int iy = fixed2int(cr->y) - base;
597
598
0
  cursor_output(eb, rev, iy);
599
0
  cr->y += dy;
600
0
  cr->left = x;
601
0
  cr->right = x;
602
0
}
603
604
/* Step the cursor in y, always by enough to cross a scanline, as
605
 * part of a vertical line, knowing that we are moving from a
606
 * position guaranteed to be in the valid y range. */
607
static inline void
608
cursor_always_step_inrange_vertical(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed dy, fixed x)
609
0
{
610
0
  cursor_t * FZ_RESTRICT cr = &eb->cursor[rev];
611
0
  int base = eb->super.clip.y0;
612
0
  int iy = fixed2int(cr->y) - base;
613
614
0
  cursor_output(eb, rev, iy);
615
0
  cr->y += dy;
616
0
}
617
618
/* Step the cursor in y, always by enough to cross a scanline, as
619
 * part of a left moving line, knowing that we are moving from a
620
 * position guaranteed to be in the valid y range. */
621
static inline void
622
cursor_always_inrange_step_left(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed dy, fixed x)
623
0
{
624
0
  cursor_t * FZ_RESTRICT cr = &eb->cursor[rev];
625
0
  int base = eb->super.clip.y0;
626
0
  int iy = fixed2int(cr->y) - base;
627
628
0
  cr->y += dy;
629
0
  cursor_output_inrange(eb, rev, iy);
630
0
  cr->right = x;
631
0
}
632
633
/* Step the cursor in y, always by enough to cross a scanline, as
634
 * part of a right moving line, knowing that we are moving from a
635
 * position guaranteed to be in the valid y range. */
636
static inline void
637
cursor_always_inrange_step_right(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed dy, fixed x)
638
0
{
639
0
  cursor_t * FZ_RESTRICT cr = &eb->cursor[rev];
640
0
  int base = eb->super.clip.y0;
641
0
  int iy = fixed2int(cr->y) - base;
642
643
0
  cr->y += dy;
644
0
  cursor_output_inrange(eb, rev, iy);
645
0
  cr->left = x;
646
0
}
647
648
static inline void cursor_init(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed y, fixed x)
649
0
{
650
0
  cursor_t * FZ_RESTRICT cr = &eb->cursor[rev];
651
652
0
  assert(y >= int2fixed(eb->super.clip.y0) && y <= int2fixed(eb->super.clip.y1));
653
654
0
  cr->y = y;
655
0
  cr->left = x;
656
0
  cr->right = x;
657
0
  cr->d = DIRN_UNSET;
658
0
}
659
660
static inline void cursor_left_merge(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed x)
661
0
{
662
0
  cursor_t * FZ_RESTRICT cr = &eb->cursor[rev];
663
664
0
  if (x < cr->left)
665
0
    cr->left = x;
666
0
}
667
668
static inline void cursor_left(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed x)
669
0
{
670
0
  cursor_t * FZ_RESTRICT cr = &eb->cursor[rev];
671
672
0
  cr->left = x;
673
0
}
674
675
static inline void cursor_right_merge(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed x)
676
0
{
677
0
  cursor_t * FZ_RESTRICT cr = &eb->cursor[rev];
678
679
0
  if (x > cr->right)
680
0
    cr->right = x;
681
0
}
682
683
static inline void cursor_right(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed x)
684
0
{
685
0
  cursor_t * FZ_RESTRICT cr = &eb->cursor[rev];
686
687
0
  cr->right = x;
688
0
}
689
690
static inline void cursor_down(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed x)
691
0
{
692
0
  cursor_t * FZ_RESTRICT cr = &eb->cursor[rev];
693
0
  int base = eb->super.clip.y0;
694
695
0
  if (cr->d == DIRN_UP)
696
0
  {
697
0
    cursor_output(eb, rev, fixed2int(cr->y) - base);
698
0
    cr->left = x;
699
0
    cr->right = x;
700
0
  }
701
0
  cr->d = DIRN_DOWN;
702
0
}
703
704
static inline void cursor_up(fz_edgebuffer * FZ_RESTRICT eb, int rev, fixed x)
705
0
{
706
0
  cursor_t * FZ_RESTRICT cr = &eb->cursor[rev];
707
0
  int base = eb->super.clip.y0;
708
709
0
  if (cr->d == DIRN_DOWN)
710
0
  {
711
0
    cursor_output(eb, rev, fixed2int(cr->y) - base);
712
0
    cr->left = x;
713
0
    cr->right = x;
714
0
  }
715
0
  cr->d = DIRN_UP;
716
0
}
717
718
static inline int dirns_match(int d0, int d1)
719
0
{
720
0
  return d0 == d1 || d0 == DIRN_UNSET || d1 == DIRN_UNSET;
721
0
}
722
723
static inline int dirn_flip(int d)
724
0
{
725
0
  return d < 0 ? d : d^1;
726
0
}
727
728
static inline int dirns_merge(int d0, int d1)
729
0
{
730
0
  if (d0 == DIRN_UNSET)
731
0
    return d1;
732
0
  assert(dirns_match(d0, d1));
733
0
  return d0;
734
0
}
735
736
static void
737
cursor_flush(fz_edgebuffer * FZ_RESTRICT eb)
738
0
{
739
0
  int base = eb->super.clip.y0;
740
0
  int iy0, iy1, iy2;
741
0
  cursor_t * FZ_RESTRICT cr0 = &eb->cursor[0];
742
0
  cursor_t * FZ_RESTRICT cr1 = &eb->cursor[1];
743
0
  cursor_t * FZ_RESTRICT cr2 = &eb->cursor[2];
744
745
0
  if (cr0->unset)
746
0
  {
747
0
    assert(cr1->unset && cr2->unset);
748
0
    return;
749
0
  }
750
751
0
  iy0 = fixed2int(cr0->y) - base;
752
0
  iy1 = fixed2int(cr1->y) - base;
753
0
  if (!cr2->unset)
754
0
  {
755
0
    assert(!cr1->unset);
756
0
    iy2 = fixed2int(cr2->y) - base;
757
    /* Try to merge the end of cursor 0 with the end of cursor 1 */
758
0
    if (iy0 == iy1 && dirns_match(cr0->d, dirn_flip(cr1->d)))
759
0
    {
760
      /* Succeeded! Just one to output. */
761
0
      cr0->d = dirns_merge(cr0->d, dirn_flip(cr1->d));
762
0
      if (cr0->left > cr1->left)
763
0
        cr0->left = cr1->left;
764
0
      if (cr0->right < cr1->right)
765
0
        cr0->right = cr1->right;
766
0
      cr1->unset = 1; /* Stop us outputting cursor 1 later */
767
0
    }
768
769
    /* Try to merge the end of cursor 2 with the start of cursor 0 */
770
0
    if (cr0->saved)
771
0
    {
772
0
      if (cr0->save_iy == iy2 && dirns_match(cr0->save_d, cr2->d))
773
0
      {
774
0
        cr0->save_d = dirns_merge(cr0->save_d, cr2->d);
775
0
        if (cr0->save_left > cr2->left)
776
0
          cr0->save_left = cr2->left;
777
0
        if (cr0->save_right > cr2->right)
778
0
          cr0->save_right = cr2->right;
779
0
        cr2->unset = 1; /* Stop us outputting cursor 2 later */
780
0
      }
781
0
    }
782
0
    else
783
0
    {
784
      /* Maybe cursor 0 never moved from the original pixel */
785
0
      if (iy0 == iy2 && dirns_match(cr0->d, cr2->d))
786
0
      {
787
0
        cr0->d = dirns_merge(cr0->d, cr2->d);
788
0
        if (cr0->left > cr2->left)
789
0
          cr0->left = cr2->left;
790
0
        if (cr0->right > cr2->right)
791
0
          cr0->right = cr2->right;
792
0
        cr2->unset = 1; /* Stop us outputting cursor 2 later */
793
0
      }
794
0
    }
795
796
    /* Try to merge the start of cursor 2 with the start of cursor 1 */
797
0
    if (cr1->saved)
798
0
    {
799
0
      if (cr2->saved)
800
0
      {
801
0
        if (cr2->save_iy == cr1->save_iy && dirns_match(cr2->save_d, dirn_flip(cr1->save_d)))
802
0
        {
803
0
          cr2->save_d = dirns_merge(cr2->save_d, dirn_flip(cr1->save_d));
804
0
          if (cr2->save_left > cr1->save_left)
805
0
            cr2->save_left = cr1->save_left;
806
0
          if (cr2->save_right > cr1->save_right)
807
0
            cr2->save_right = cr1->save_right;
808
0
          cr1->saved = 0; /* Don't output cr1->saved again later */
809
0
        }
810
0
      }
811
0
      else if (!cr2->unset)
812
0
      {
813
        /* Maybe cursor 2 never moved from the original pixel */
814
0
        if (iy2 == cr1->save_iy && dirns_match(cr2->d, dirn_flip(cr1->save_d)))
815
0
        {
816
0
          cr2->d = dirns_merge(cr2->d, dirn_flip(cr1->save_d));
817
0
          if (cr2->left > cr1->save_left)
818
0
            cr2->left = cr1->save_left;
819
0
          if (cr2->right > cr1->save_right)
820
0
            cr2->right = cr1->save_right;
821
0
          cr1->saved = 0; /* Don't output cr1->saved again later */
822
0
        }
823
0
      }
824
0
    }
825
0
    else if (!cr1->unset)
826
0
    {
827
      /* Cursor 1 might not have moved from the original pixel, hence nothing saved */
828
0
      if (cr2->saved)
829
0
      {
830
0
        if (cr2->save_iy == iy1 && dirns_match(cr2->save_d, dirn_flip(cr1->d)))
831
0
        {
832
0
          cr2->save_d = dirns_merge(cr2->save_d, dirn_flip(cr1->d));
833
0
          if (cr2->save_left > cr1->left)
834
0
            cr2->save_left = cr1->left;
835
0
          if (cr2->save_right > cr1->right)
836
0
            cr2->save_right = cr1->right;
837
0
          cr1->unset = 1; /* Stop us outputting cursor 1 later */
838
0
        }
839
0
      }
840
0
      else if (!cr2->unset)
841
0
      {
842
        /* Maybe cursor 2 never moved from the original pixel */
843
0
        if (iy2 == iy1 && dirns_match(cr2->d, dirn_flip(cr1->d)))
844
0
        {
845
0
          cr2->d = dirns_merge(cr2->d, dirn_flip(cr1->d));
846
0
          if (cr2->left > cr1->left)
847
0
            cr2->left = cr1->left;
848
0
          if (cr2->right > cr1->right)
849
0
            cr2->right = cr1->right;
850
0
          cr1->unset = 1; /* Stop us outputting cursor 1 later */
851
0
        }
852
0
      }
853
0
    }
854
0
    else
855
0
    {
856
      /* Cursor 1 might not have moved from the original pixel, hence nothing saved,
857
       * AND we might have merged it with cursor 0 already! */
858
0
      if (cr2->saved)
859
0
      {
860
0
        if (iy0 == cr2->save_iy && dirns_match(cr0->d, cr2->save_d))
861
0
        {
862
0
          cr0->d = dirns_merge(cr0->d, cr2->save_d);
863
0
          if (cr0->left > cr2->save_left)
864
0
            cr0->left = cr2->save_left;
865
0
          if (cr0->right > cr2->save_right)
866
0
            cr0->right = cr2->save_right;
867
0
          cr2->saved = 0; /* Stop us outputting saved cursor 2 later */
868
0
        }
869
0
      }
870
0
      else if (!cr2->unset)
871
0
      {
872
        /* Maybe cursor 2 never moved from the original pixel */
873
0
        if (iy0 == iy2 && dirns_match(cr0->d, cr2->d))
874
0
        {
875
0
          cr0->d = dirns_merge(cr0->d, cr2->d);
876
0
          if (cr0->left > cr2->left)
877
0
            cr0->left = cr2->left;
878
0
          if (cr0->right > cr2->right)
879
0
            cr0->right = cr2->right;
880
0
          cr2->unset = 1; /* Stop us outputting cursor 2 later */
881
0
        }
882
0
      }
883
0
    }
884
0
  }
885
0
  else
886
0
  {
887
0
    iy2 = 0;
888
889
    /* Try to merge the end of cursor 0 with the start of cursor 0 */
890
0
    if (cr0->saved)
891
0
    {
892
0
      if (iy0 == cr0->save_iy && dirns_match(cr0->d, cr0->save_d))
893
0
      {
894
0
        cr0->d = dirns_merge(cr0->d, cr0->save_d);
895
0
        if (cr0->left > cr0->save_left)
896
0
          cr0->left = cr0->save_left;
897
0
        if (cr0->right > cr0->save_right)
898
0
          cr0->right = cr0->save_right;
899
0
        cr0->saved = 0; /* Stop us outputting saved cursor 0 later */
900
0
      }
901
0
    }
902
903
0
    if (!cr1->unset)
904
0
    {
905
      /* Try to merge the end of cursor 1 with the start of cursor 1 */
906
0
      if (cr1->saved)
907
0
      {
908
0
        if (iy1 == cr1->save_iy && dirns_match(cr1->d, cr1->save_d))
909
0
        {
910
0
          cr1->d = dirns_merge(cr1->d, cr1->save_d);
911
0
          if (cr1->left > cr1->save_left)
912
0
            cr1->left = cr1->save_left;
913
0
          if (cr1->right > cr1->save_right)
914
0
            cr1->right = cr1->save_right;
915
0
          cr1->saved = 0; /* Stop us outputting saved cursor 1 later */
916
0
        }
917
0
      }
918
0
    }
919
0
  }
920
921
0
  if (!cr0->unset)
922
0
    cursor_output(eb, 0, iy0);
923
0
  if (cr0->saved)
924
0
  {
925
0
    cr0->left = cr0->save_left;
926
0
    cr0->right = cr0->save_right;
927
0
    cr0->d = cr0->save_d;
928
0
    cursor_output(eb, 0, cr0->save_iy);
929
0
  }
930
0
  if (!cr1->unset)
931
0
    cursor_output(eb, 1, iy1);
932
0
  if (cr1->saved)
933
0
  {
934
0
    cr1->left = cr1->save_left;
935
0
    cr1->right = cr1->save_right;
936
0
    cr1->d = cr1->save_d;
937
0
    cursor_output(eb, 1, cr1->save_iy);
938
0
  }
939
0
  if (!cr2->unset)
940
0
    cursor_output(eb, 2, iy2);
941
0
  if (cr2->saved)
942
0
  {
943
0
    cr2->left = cr2->save_left;
944
0
    cr2->right = cr2->save_right;
945
0
    cr2->d = cr2->save_d;
946
0
    cursor_output(eb, 2, cr2->save_iy);
947
0
  }
948
0
}
949
950
static void do_mark_line_app(fz_context *ctx, fz_edgebuffer *eb, fixed sx, fixed sy, fixed ex, fixed ey, int rev)
951
0
{
952
0
  int base_y = eb->super.clip.y0;
953
0
  int height = eb->super.clip.y1 - eb->super.clip.y0;
954
0
  int isy, iey;
955
0
  fixed y_steps;
956
0
  fixed save_sy = sy;
957
0
  fixed save_ex = ex;
958
0
  fixed save_ey = ey;
959
0
  int truncated;
960
0
  cursor_t * FZ_RESTRICT cr = &eb->cursor[rev];
961
962
0
  if (cr->unset)
963
0
    cr->y = sy, cr->left = sx, cr->right = sx, cr->unset = 0;
964
965
  /* Floating point inaccuracies can cause these not *quite* to be true. */
966
0
  assert(cr->y == sy && cr->left <= sx && cr->right >= sx && cr->d >= DIRN_UNSET && cr->d <= DIRN_DOWN);
967
0
  sy = cr->y;
968
0
  if (cr->left > sx)
969
0
    sx = cr->left;
970
0
  else if (cr->right < sx)
971
0
    sx = cr->right;
972
973
0
  if (sx == ex && sy == ey)
974
0
    return;
975
976
0
  isy = fixed2int(sy) - base_y;
977
0
  iey = fixed2int(ey) - base_y;
978
#ifdef DEBUG_SCAN_CONVERTER
979
  if (debugging_scan_converter)
980
    fz_write_printf(ctx, fz_stderr(ctx), "Marking line (app) from %x,%x to %x,%x (%x,%x) %d\n", sx, sy, ex, ey, isy, iey, rev);
981
#endif
982
983
0
  if (isy < iey) {
984
    /* Rising line */
985
0
    if (iey < 0 || isy >= height) {
986
      /* All line is outside. */
987
0
      cr->y = ey;
988
0
      cr->left = ex;
989
0
      cr->right = ex;
990
0
      cr->can_save = 0;
991
0
      return;
992
0
    }
993
0
    if (isy < 0) {
994
      /* Move sy up */
995
0
      int y = ey - sy;
996
0
      int new_sy = int2fixed(base_y);
997
0
      int dy = new_sy - sy;
998
0
      sx += (int)((((int64_t)(ex-sx))*dy + y/2)/y);
999
0
      sy = new_sy;
1000
0
      cursor_init(eb, rev, sy, sx);
1001
0
      isy = 0;
1002
0
    }
1003
0
    truncated = iey > height;
1004
0
    if (truncated) {
1005
      /* Move ey down */
1006
0
      int y = ey - sy;
1007
0
      int new_ey = int2fixed(base_y + height);
1008
0
      int dy = ey - new_ey;
1009
0
      save_ex = ex;
1010
0
      save_ey = ey;
1011
0
      ex -= (int)((((int64_t)(ex-sx))*dy + y/2)/y);
1012
0
      ey = new_ey;
1013
0
      iey = height;
1014
0
    }
1015
0
  } else {
1016
    /* Falling line */
1017
0
    if (isy < 0 || iey >= height) {
1018
      /* All line is outside. */
1019
0
      cr->y = ey;
1020
0
      cr->left = ex;
1021
0
      cr->right = ex;
1022
0
      cr->can_save = 0;
1023
0
      return;
1024
0
    }
1025
0
    truncated = iey < 0;
1026
0
    if (truncated) {
1027
      /* Move ey up */
1028
0
      int y = ey - sy;
1029
0
      int new_ey = int2fixed(base_y);
1030
0
      int dy = ey - new_ey;
1031
0
      ex -= (int)((((int64_t)(ex-sx))*dy + y/2)/y);
1032
0
      ey = new_ey;
1033
0
      iey = 0;
1034
0
    }
1035
0
    if (isy >= height) {
1036
      /* Move sy down */
1037
0
      int y = ey - sy;
1038
0
      if (y) {
1039
0
        int new_sy = int2fixed(base_y + height);
1040
0
        int dy = new_sy - sy;
1041
0
        sx += (int)((((int64_t)(ex-sx))*dy + y/2)/y);
1042
0
        sy = new_sy;
1043
0
        cursor_init(eb, rev, sy, sx);
1044
0
        isy = height;
1045
0
      }
1046
0
    }
1047
0
  }
1048
1049
0
  assert(cr->left <= sx);
1050
0
  assert(cr->right >= sx);
1051
0
  assert(cr->y == sy);
1052
1053
  /* A note: The code below used to be of the form:
1054
   *   if (isy == iey)   ... deal with horizontal lines
1055
   *   else if (ey > sy) {
1056
   *   fixed y_steps = ey - sy;
1057
   *    ... deal with rising lines ...
1058
   *   } else {
1059
   *   fixed y_steps = ey - sy;
1060
   *   ... deal with falling lines
1061
   *   }
1062
   * but that lead to problems, for instance, an example seen
1063
   * has sx=2aa8e, sy=8aee7, ex=7ffc1686, ey=8003e97a.
1064
   * Thus isy=84f, iey=ff80038a. We can see that ey < sy, but
1065
   * sy - ey < 0!
1066
   * We therefore rejig our code so that the choice between
1067
   * cases is done based on the sign of y_steps rather than
1068
   * the relative size of ey and sy.
1069
   */
1070
1071
  /* First, deal with lines that don't change scanline.
1072
   * This accommodates horizontal lines. */
1073
0
  if (isy == iey) {
1074
0
    if (save_sy == save_ey) {
1075
      /* Horizontal line. Don't change cr->d, don't flush. */
1076
0
    } else if (save_sy > save_ey) {
1077
      /* Falling line, flush if previous was rising */
1078
0
      cursor_down(eb, rev, sx);
1079
0
    } else {
1080
      /* Rising line, flush if previous was falling */
1081
0
      cursor_up(eb, rev, sx);
1082
0
    }
1083
0
    if (sx <= ex) {
1084
0
      cursor_left_merge(eb, rev, sx);
1085
0
      cursor_right_merge(eb, rev, ex);
1086
0
    } else {
1087
0
      cursor_left_merge(eb, rev, ex);
1088
0
      cursor_right_merge(eb, rev, sx);
1089
0
    }
1090
0
    cr->y = ey;
1091
0
    if (sy > save_ey)
1092
0
      goto endFalling;
1093
0
  } else if ((y_steps = ey - sy) > 0) {
1094
    /* We want to change from sy to ey, which are guaranteed to be on
1095
     * different scanlines. We do this in 3 phases.
1096
     * Phase 1 gets us from sy to the next scanline boundary.
1097
     * Phase 2 gets us all the way to the last scanline boundary.
1098
     * Phase 3 gets us from the last scanline boundary to ey.
1099
     */
1100
    /* We want to change from sy to ey, which are guaranteed to be on
1101
     * different scanlines. We do this in 3 phases.
1102
     * Phase 1 gets us from sy to the next scanline boundary. (We may exit after phase 1).
1103
     * Phase 2 gets us all the way to the last scanline boundary. (This may be a null operation)
1104
     * Phase 3 gets us from the last scanline boundary to ey. (We are guaranteed to have output the cursor at least once before phase 3).
1105
     */
1106
0
    int phase1_y_steps = (-sy) & (fixed_1 - 1);
1107
0
    int phase3_y_steps = ey & (fixed_1 - 1);
1108
1109
0
    cursor_up(eb, rev, sx);
1110
1111
0
    if (sx == ex) {
1112
      /* Vertical line. (Rising) */
1113
1114
      /* Phase 1: */
1115
0
      cursor_left_merge(eb, rev, sx);
1116
0
      cursor_right_merge(eb, rev, sx);
1117
0
      if (phase1_y_steps) {
1118
        /* If phase 1 will move us into a new scanline, then we must
1119
         * flush it before we move. */
1120
0
        cursor_step(eb, rev, phase1_y_steps, sx);
1121
0
        sy += phase1_y_steps;
1122
0
        y_steps -= phase1_y_steps;
1123
0
        if (y_steps == 0)
1124
0
          goto end;
1125
0
      }
1126
1127
      /* Phase 3: precalculation */
1128
0
      y_steps -= phase3_y_steps;
1129
1130
      /* Phase 2: */
1131
0
      y_steps = fixed2int(y_steps);
1132
0
      assert(y_steps >= 0);
1133
0
      if (y_steps > 0) {
1134
0
        cursor_always_step(eb, rev, fixed_1, sx);
1135
0
        y_steps--;
1136
0
        while (y_steps) {
1137
0
          cursor_always_step_inrange_vertical(eb, rev, fixed_1, sx);
1138
0
          y_steps--;
1139
0
        }
1140
0
      }
1141
1142
      /* Phase 3 */
1143
0
      assert(cr->left == sx && cr->right == sx);
1144
0
      cr->y += phase3_y_steps;
1145
0
    } else if (sx < ex) {
1146
      /* Lines increasing in x. (Rightwards, rising) */
1147
0
      int phase1_x_steps, phase3_x_steps;
1148
0
      fixed x_steps = ex - sx;
1149
1150
      /* Phase 1: */
1151
0
      cursor_left_merge(eb, rev, sx);
1152
0
      if (phase1_y_steps) {
1153
0
        phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps);
1154
0
        sx += phase1_x_steps;
1155
0
        cursor_right_merge(eb, rev, sx);
1156
0
        x_steps -= phase1_x_steps;
1157
0
        cursor_step(eb, rev, phase1_y_steps, sx);
1158
0
        sy += phase1_y_steps;
1159
0
        y_steps -= phase1_y_steps;
1160
0
        if (y_steps == 0)
1161
0
          goto end;
1162
0
      }
1163
1164
      /* Phase 3: precalculation */
1165
0
      phase3_x_steps = (int)(((int64_t)x_steps * phase3_y_steps + y_steps/2) / y_steps);
1166
0
      x_steps -= phase3_x_steps;
1167
0
      y_steps -= phase3_y_steps;
1168
0
      assert((y_steps & (fixed_1 - 1)) == 0);
1169
1170
      /* Phase 2: */
1171
0
      y_steps = fixed2int(y_steps);
1172
0
      assert(y_steps >= 0);
1173
0
      if (y_steps) {
1174
        /* We want to change sx by x_steps in y_steps steps.
1175
         * So each step, we add x_steps/y_steps to sx. That's x_inc + n_inc/y_steps. */
1176
0
        int x_inc = x_steps/y_steps;
1177
0
        int n_inc = x_steps - (x_inc * y_steps);
1178
0
        int f = y_steps/2;
1179
0
        int d = y_steps;
1180
1181
        /* Special casing the unset iteration, allows us to simplify
1182
         * the following loop. */
1183
0
        sx += x_inc;
1184
0
        f -= n_inc;
1185
0
        if (f < 0)
1186
0
          f += d, sx++;
1187
0
        cursor_right_merge(eb, rev, sx);
1188
0
        cursor_always_step(eb, rev, fixed_1, sx);
1189
0
        y_steps--;
1190
1191
0
        while (y_steps) {
1192
0
          sx += x_inc;
1193
0
          f -= n_inc;
1194
0
          if (f < 0)
1195
0
            f += d, sx++;
1196
0
          cursor_right(eb, rev, sx);
1197
0
          cursor_always_inrange_step_right(eb, rev, fixed_1, sx);
1198
0
          y_steps--;
1199
0
        };
1200
0
      }
1201
1202
      /* Phase 3 */
1203
0
      assert(cr->left <= ex && cr->right >= sx);
1204
0
      cursor_right(eb, rev, ex);
1205
0
      cr->y += phase3_y_steps;
1206
0
    } else {
1207
      /* Lines decreasing in x. (Leftwards, rising) */
1208
0
      int phase1_x_steps, phase3_x_steps;
1209
0
      fixed x_steps = sx - ex;
1210
1211
      /* Phase 1: */
1212
0
      cursor_right_merge(eb, rev, sx);
1213
0
      if (phase1_y_steps) {
1214
0
        phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps);
1215
0
        x_steps -= phase1_x_steps;
1216
0
        sx -= phase1_x_steps;
1217
0
        cursor_left_merge(eb, rev, sx);
1218
0
        cursor_step(eb, rev, phase1_y_steps, sx);
1219
0
        sy += phase1_y_steps;
1220
0
        y_steps -= phase1_y_steps;
1221
0
        if (y_steps == 0)
1222
0
          goto end;
1223
0
      }
1224
1225
      /* Phase 3: precalculation */
1226
0
      phase3_x_steps = (int)(((int64_t)x_steps * phase3_y_steps + y_steps/2) / y_steps);
1227
0
      x_steps -= phase3_x_steps;
1228
0
      y_steps -= phase3_y_steps;
1229
0
      assert((y_steps & (fixed_1 - 1)) == 0);
1230
1231
      /* Phase 2: */
1232
0
      y_steps = fixed2int(y_steps);
1233
0
      assert(y_steps >= 0);
1234
0
      if (y_steps) {
1235
        /* We want to change sx by x_steps in y_steps steps.
1236
         * So each step, we sub x_steps/y_steps from sx. That's x_inc + n_inc/ey. */
1237
0
        int x_inc = x_steps/y_steps;
1238
0
        int n_inc = x_steps - (x_inc * y_steps);
1239
0
        int f = y_steps/2;
1240
0
        int d = y_steps;
1241
1242
        /* Special casing the unset iteration, allows us to simplify
1243
         * the following loop. */
1244
0
        sx -= x_inc;
1245
0
        f -= n_inc;
1246
0
        if (f < 0)
1247
0
          f += d, sx--;
1248
0
        cursor_left_merge(eb, rev, sx);
1249
0
        cursor_always_step(eb, rev, fixed_1, sx);
1250
0
        y_steps--;
1251
1252
0
        while (y_steps) {
1253
0
          sx -= x_inc;
1254
0
          f -= n_inc;
1255
0
          if (f < 0)
1256
0
            f += d, sx--;
1257
0
          cursor_left(eb, rev, sx);
1258
0
          cursor_always_inrange_step_left(eb, rev, fixed_1, sx);
1259
0
          y_steps--;
1260
0
        }
1261
0
      }
1262
1263
      /* Phase 3 */
1264
0
      assert(cr->right >= ex && cr->left <= sx);
1265
0
      cursor_left(eb, rev, ex);
1266
0
      cr->y += phase3_y_steps;
1267
0
    }
1268
0
  } else {
1269
    /* So lines decreasing in y. */
1270
    /* We want to change from sy to ey, which are guaranteed to be on
1271
     * different scanlines. We do this in 3 phases.
1272
     * Phase 1 gets us from sy to the next scanline boundary. This never causes an output.
1273
     * Phase 2 gets us all the way to the last scanline boundary. This is guaranteed to cause an output.
1274
     * Phase 3 gets us from the last scanline boundary to ey. We are guaranteed to have outputted by now.
1275
     */
1276
0
    int phase1_y_steps = sy & (fixed_1 - 1);
1277
0
    int phase3_y_steps = (-ey) & (fixed_1 - 1);
1278
1279
0
    y_steps = -y_steps;
1280
    /* Cope with the awkward 0x80000000 case. */
1281
0
    if (y_steps < 0)
1282
0
    {
1283
0
      int mx, my;
1284
0
      mx = sx + ((ex-sx)>>1);
1285
0
      my = sy + ((ey-sy)>>1);
1286
0
      do_mark_line_app(ctx, eb, sx, sy, mx, my, rev);
1287
0
      do_mark_line_app(ctx, eb, mx, my, ex, ey, rev);
1288
0
      return;
1289
0
    }
1290
1291
0
    cursor_down(eb, rev, sx);
1292
1293
0
    if (sx == ex) {
1294
      /* Vertical line. (Falling) */
1295
1296
      /* Phase 1: */
1297
0
      cursor_left_merge(eb, rev, sx);
1298
0
      cursor_right_merge(eb, rev, sx);
1299
0
      if (phase1_y_steps) {
1300
        /* Phase 1 in a falling line never moves us into a new scanline. */
1301
0
        cursor_never_step_vertical(eb, rev, -phase1_y_steps, sx);
1302
0
        sy -= phase1_y_steps;
1303
0
        y_steps -= phase1_y_steps;
1304
0
        if (y_steps == 0)
1305
0
          goto endFalling;
1306
0
      }
1307
1308
      /* Phase 3: precalculation */
1309
0
      y_steps -= phase3_y_steps;
1310
0
      assert((y_steps & (fixed_1 - 1)) == 0);
1311
1312
      /* Phase 2: */
1313
0
      y_steps = fixed2int(y_steps);
1314
0
      assert(y_steps >= 0);
1315
0
      if (y_steps) {
1316
0
        cursor_always_step(eb, rev, -fixed_1, sx);
1317
0
        y_steps--;
1318
0
        while (y_steps) {
1319
0
          cursor_always_step_inrange_vertical(eb, rev, -fixed_1, sx);
1320
0
          y_steps--;
1321
0
        }
1322
0
      }
1323
1324
      /* Phase 3 */
1325
0
      if (phase3_y_steps > 0) {
1326
0
        cursor_step(eb, rev, -phase3_y_steps, sx);
1327
0
        assert(cr->left == sx && cr->right == sx);
1328
0
      }
1329
0
    } else if (sx < ex) {
1330
      /* Lines increasing in x. (Rightwards, falling) */
1331
0
      int phase1_x_steps, phase3_x_steps;
1332
0
      fixed x_steps = ex - sx;
1333
1334
      /* Phase 1: */
1335
0
      cursor_left_merge(eb, rev, sx);
1336
0
      if (phase1_y_steps) {
1337
0
        phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps);
1338
0
        x_steps -= phase1_x_steps;
1339
0
        sx += phase1_x_steps;
1340
        /* Phase 1 in a falling line never moves us into a new scanline. */
1341
0
        cursor_never_step_right(eb, rev, -phase1_y_steps, sx);
1342
0
        sy -= phase1_y_steps;
1343
0
        y_steps -= phase1_y_steps;
1344
0
        if (y_steps == 0)
1345
0
          goto endFalling;
1346
0
      } else
1347
0
        cursor_right_merge(eb, rev, sx);
1348
1349
      /* Phase 3: precalculation */
1350
0
      phase3_x_steps = (int)(((int64_t)x_steps * phase3_y_steps + y_steps/2) / y_steps);
1351
0
      x_steps -= phase3_x_steps;
1352
0
      y_steps -= phase3_y_steps;
1353
0
      assert((y_steps & (fixed_1 - 1)) == 0);
1354
1355
      /* Phase 2: */
1356
0
      y_steps = fixed2int(y_steps);
1357
0
      assert(y_steps >= 0);
1358
0
      if (y_steps) {
1359
        /* We want to change sx by x_steps in y_steps steps.
1360
         * So each step, we add x_steps/y_steps to sx. That's x_inc + n_inc/ey. */
1361
0
        int x_inc = x_steps/y_steps;
1362
0
        int n_inc = x_steps - (x_inc * y_steps);
1363
0
        int f = y_steps/2;
1364
0
        int d = y_steps;
1365
1366
0
        cursor_always_step(eb, rev, -fixed_1, sx);
1367
0
        sx += x_inc;
1368
0
        f -= n_inc;
1369
0
        if (f < 0)
1370
0
          f += d, sx++;
1371
0
        cursor_right(eb, rev, sx);
1372
0
        y_steps--;
1373
1374
0
        while (y_steps) {
1375
0
          cursor_always_inrange_step_right(eb, rev, -fixed_1, sx);
1376
0
          sx += x_inc;
1377
0
          f -= n_inc;
1378
0
          if (f < 0)
1379
0
            f += d, sx++;
1380
0
          cursor_right(eb, rev, sx);
1381
0
          y_steps--;
1382
0
        }
1383
0
      }
1384
1385
      /* Phase 3 */
1386
0
      if (phase3_y_steps > 0) {
1387
0
        cursor_step(eb, rev, -phase3_y_steps, sx);
1388
0
        cursor_right(eb, rev, ex);
1389
0
        assert(cr->left == sx && cr->right == ex);
1390
0
      }
1391
0
    } else {
1392
      /* Lines decreasing in x. (Falling) */
1393
0
      int phase1_x_steps, phase3_x_steps;
1394
0
      fixed x_steps = sx - ex;
1395
1396
      /* Phase 1: */
1397
0
      cursor_right_merge(eb, rev, sx);
1398
0
      if (phase1_y_steps) {
1399
0
        phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps);
1400
0
        x_steps -= phase1_x_steps;
1401
0
        sx -= phase1_x_steps;
1402
        /* Phase 1 in a falling line never moves us into a new scanline. */
1403
0
        cursor_never_step_left(eb, rev, -phase1_y_steps, sx);
1404
0
        sy -= phase1_y_steps;
1405
0
        y_steps -= phase1_y_steps;
1406
0
        if (y_steps == 0)
1407
0
          goto endFalling;
1408
0
      } else
1409
0
        cursor_left_merge(eb, rev, sx);
1410
1411
      /* Phase 3: precalculation */
1412
0
      phase3_x_steps = (int)(((int64_t)x_steps * phase3_y_steps + y_steps/2) / y_steps);
1413
0
      x_steps -= phase3_x_steps;
1414
0
      y_steps -= phase3_y_steps;
1415
0
      assert((y_steps & (fixed_1 - 1)) == 0);
1416
1417
      /* Phase 2: */
1418
0
      y_steps = fixed2int(y_steps);
1419
0
      assert(y_steps >= 0);
1420
0
      if (y_steps) {
1421
        /* We want to change sx by x_steps in y_steps steps.
1422
         * So each step, we sub x_steps/y_steps from sx. That's x_inc + n_inc/ey. */
1423
0
        int x_inc = x_steps/y_steps;
1424
0
        int n_inc = x_steps - (x_inc * y_steps);
1425
0
        int f = y_steps/2;
1426
0
        int d = y_steps;
1427
1428
0
        cursor_always_step(eb, rev, -fixed_1, sx);
1429
0
        sx -= x_inc;
1430
0
        f -= n_inc;
1431
0
        if (f < 0)
1432
0
          f += d, sx--;
1433
0
        cursor_left(eb, rev, sx);
1434
0
        y_steps--;
1435
1436
0
        while (y_steps) {
1437
0
          cursor_always_inrange_step_left(eb, rev, -fixed_1, sx);
1438
0
          sx -= x_inc;
1439
0
          f -= n_inc;
1440
0
          if (f < 0)
1441
0
            f += d, sx--;
1442
0
          cursor_left(eb, rev, sx);
1443
0
          y_steps--;
1444
0
        }
1445
0
      }
1446
1447
      /* Phase 3 */
1448
0
      if (phase3_y_steps > 0) {
1449
0
        cursor_step(eb, rev, -phase3_y_steps, sx);
1450
0
        cursor_left(eb, rev, ex);
1451
0
        assert(cr->left == ex && cr->right == sx);
1452
0
      }
1453
0
    }
1454
0
endFalling:
1455
0
    if (truncated)
1456
0
      cursor_output(eb, rev, fixed2int(cr->y) - base_y);
1457
0
  }
1458
1459
0
end:
1460
0
  if (truncated) {
1461
0
    cr->left = save_ex;
1462
0
    cr->right = save_ex;
1463
0
    cr->y = save_ey;
1464
0
  }
1465
0
}
1466
1467
static void mark_line_app(fz_context *ctx, fz_edgebuffer *eb, fixed sx, fixed sy, fixed ex, fixed ey, int rev)
1468
0
{
1469
0
  if (rev == 1)
1470
0
  {
1471
0
    fixed t;
1472
0
    t = sx, sx = ex, ex = t;
1473
0
    t = sy, sy = ey, ey = t;
1474
0
  }
1475
0
  do_mark_line_app(ctx, eb, sx, sy, ex, ey, rev);
1476
0
}
1477
1478
static void fz_insert_edgebuffer_app(fz_context *ctx, fz_rasterizer *ras, float fsx, float fsy, float fex, float fey, int rev)
1479
0
{
1480
0
  fz_edgebuffer *eb = (fz_edgebuffer *)ras;
1481
0
  fixed sx = safe_float2fixed(fsx);
1482
0
  fixed sy = safe_float2fixed(fsy);
1483
0
  fixed ex = safe_float2fixed(fex);
1484
0
  fixed ey = safe_float2fixed(fey);
1485
1486
0
  if (fsx < fex)
1487
0
  {
1488
0
    if (fsx < eb->super.bbox.x0) eb->super.bbox.x0 = fsx;
1489
0
    if (fex > eb->super.bbox.x1) eb->super.bbox.x1 = fex;
1490
0
  }
1491
0
  else
1492
0
  {
1493
0
    if (fsx > eb->super.bbox.x1) eb->super.bbox.x1 = fsx;
1494
0
    if (fex < eb->super.bbox.x0) eb->super.bbox.x0 = fex;
1495
0
  }
1496
0
  if (fsy < fey)
1497
0
  {
1498
0
    if (fsy < eb->super.bbox.y0) eb->super.bbox.y0 = fsy;
1499
0
    if (fey > eb->super.bbox.y1) eb->super.bbox.y1 = fey;
1500
0
  }
1501
0
  else
1502
0
  {
1503
0
    if (fey < eb->super.bbox.y0) eb->super.bbox.y0 = fey;
1504
0
    if (fsy > eb->super.bbox.y1) eb->super.bbox.y1 = fsy;
1505
0
  }
1506
1507
0
  mark_line_app(ctx, eb, sx, sy, ex, ey, rev);
1508
0
}
1509
1510
static int intcmp(const void *a, const void *b)
1511
0
{
1512
0
  return *((int*)a) - *((int *)b);
1513
0
}
1514
1515
static void fz_convert_edgebuffer(fz_context *ctx, fz_rasterizer *ras, int eofill, const fz_irect *clip, fz_pixmap *pix, unsigned char *color, fz_overprint *eop)
1516
0
{
1517
0
  fz_edgebuffer *eb = (fz_edgebuffer *)ras;
1518
0
  int scanlines = ras->clip.y1 - ras->clip.y0;
1519
0
  int i, n, a, pl, pr;
1520
0
  int *table = eb->table;
1521
0
  int *index = eb->index;
1522
0
  uint8_t *out;
1523
0
  fz_solid_color_painter_t *fn;
1524
1525
0
  fn = fz_get_solid_color_painter(pix->n, color, pix->alpha, eop);
1526
0
  assert(fn);
1527
0
  if (fn == NULL)
1528
0
    return;
1529
1530
#ifdef DEBUG_SCAN_CONVERTER
1531
  if (debugging_scan_converter)
1532
  {
1533
    fz_output *err = fz_stderr(ctx);
1534
    fz_write_printf(ctx, err, "Before sort:\n");
1535
    fz_edgebuffer_print(ctx, err, eb);
1536
  }
1537
#endif
1538
1539
0
  if (!eb->sorted)
1540
0
  {
1541
0
    eb->sorted = 1;
1542
0
    for (i = 0; i < scanlines; i++)
1543
0
    {
1544
0
      int *row = &table[index[i]];
1545
0
      int rowlen = *row++;
1546
1547
      /* Bubblesort short runs, qsort longer ones. */
1548
      /* FIXME: Check "6" below */
1549
0
      if (rowlen <= 6) {
1550
0
        int j, k;
1551
0
        for (j = 0; j < rowlen-1; j++)
1552
0
        {
1553
0
          int t = row[j];
1554
0
          for (k = j+1; k < rowlen; k++)
1555
0
          {
1556
0
            int s = row[k];
1557
0
            if (t > s)
1558
0
              row[k] = t, t = row[j] = s;
1559
0
          }
1560
0
        }
1561
0
      } else
1562
0
        qsort(row, rowlen, sizeof(int), intcmp);
1563
0
    }
1564
1565
#ifdef DEBUG_SCAN_CONVERTER
1566
    if (debugging_scan_converter)
1567
    {
1568
      fz_output *err = fz_stderr(ctx);
1569
      fz_write_printf(ctx, err, "Before filter: %s\n", eofill ? "EO" : "NZ");
1570
      fz_edgebuffer_print(ctx, err, eb);
1571
    }
1572
#endif
1573
1574
0
    for (i=0; i < scanlines; i++) {
1575
0
      int *row = &table[index[i]];
1576
0
      int *rowstart = row;
1577
0
      int rowlen = *row++;
1578
0
      int *rowout = row;
1579
1580
0
      while (rowlen > 0)
1581
0
      {
1582
0
        int left, right;
1583
1584
0
        if (eofill) {
1585
          /* Even Odd */
1586
0
          left  = (*row++)&~1;
1587
0
          right = (*row++)&~1;
1588
0
          rowlen -= 2;
1589
0
        } else {
1590
          /* Non-Zero */
1591
0
          int w;
1592
1593
0
          left = *row++;
1594
0
          w = ((left&1)-1) | (left&1);
1595
0
          rowlen--;
1596
0
          do {
1597
0
            right  = *row++;
1598
0
            rowlen--;
1599
0
            w += ((right&1)-1) | (right&1);
1600
0
          } while (w != 0);
1601
0
          left &= ~1;
1602
0
          right &= ~1;
1603
0
        }
1604
1605
0
        if (right > left) {
1606
0
          *rowout++ = left;
1607
0
          *rowout++ = right;
1608
0
        }
1609
0
      }
1610
0
      *rowstart = (rowout-rowstart)-1;
1611
0
    }
1612
0
  }
1613
1614
#ifdef DEBUG_SCAN_CONVERTER
1615
  if (debugging_scan_converter)
1616
  {
1617
    fz_output *err = fz_stderr(ctx);
1618
    fz_write_printf(ctx, err, "Before render:\n");
1619
    fz_edgebuffer_print(ctx, err, eb);
1620
  }
1621
#endif
1622
1623
0
  n = pix->n;
1624
0
  a = pix->alpha;
1625
0
  pl = fz_maxi(ras->clip.x0, pix->x);
1626
0
  pr = fz_mini(ras->clip.x1, pix->x + pix->w);
1627
0
  pr -= pl;
1628
0
  out = pix->samples + pix->stride * fz_maxi(ras->clip.y0 - pix->y, 0) + fz_maxi(ras->clip.x0 - pix->x, 0) * n;
1629
0
  if (scanlines > pix->y + pix->h - ras->clip.y0)
1630
0
    scanlines = pix->y + pix->h - ras->clip.y0;
1631
0
  for (i = fz_maxi(pix->y - ras->clip.y0, 0); i < scanlines; i++) {
1632
0
    int *row = &table[index[i]];
1633
0
    int  rowlen = *row++;
1634
1635
0
    while (rowlen > 0) {
1636
0
      int left, right;
1637
1638
0
      left  = *row++;
1639
0
      right = *row++;
1640
0
      rowlen -= 2;
1641
0
      left  = fixed2int(left + fixed_half) - pl;
1642
0
      right = fixed2int(right + fixed_half) - pl;
1643
1644
0
      if (right <= 0)
1645
0
        continue;
1646
0
      if (left >= pr)
1647
0
        continue;
1648
0
      if (right > pr)
1649
0
        right = pr;
1650
0
      if (left < 0)
1651
0
        left = 0;
1652
0
      right -= left;
1653
0
      if (right > 0) {
1654
0
        (*fn)(out + left*n, n, right, color, a, eop);
1655
0
      }
1656
0
    }
1657
0
    out += pix->stride;
1658
0
  }
1659
0
}
1660
1661
static int edgecmp(const void *a, const void *b)
1662
0
{
1663
0
  int left  = ((int*)a)[0];
1664
0
  int right = ((int*)b)[0];
1665
0
  left -= right;
1666
0
  if (left)
1667
0
    return left;
1668
0
  return ((int*)a)[1] - ((int*)b)[1];
1669
0
}
1670
1671
static void fz_convert_edgebuffer_app(fz_context *ctx, fz_rasterizer *ras, int eofill, const fz_irect *clip, fz_pixmap *pix, unsigned char *color, fz_overprint *eop)
1672
0
{
1673
0
  fz_edgebuffer *eb = (fz_edgebuffer *)ras;
1674
0
  int scanlines = ras->clip.y1 - ras->clip.y0;
1675
0
  int i, n, a, pl, pr;
1676
0
  int *table = eb->table;
1677
0
  int *index = eb->index;
1678
0
  uint8_t *out;
1679
0
  fz_solid_color_painter_t *fn;
1680
1681
0
  fn = fz_get_solid_color_painter(pix->n, color, pix->alpha, eop);
1682
0
  assert(fn);
1683
0
  if (fn == NULL)
1684
0
    return;
1685
1686
#ifdef DEBUG_SCAN_CONVERTER
1687
  if (debugging_scan_converter)
1688
  {
1689
    fz_output *err = fz_stderr(ctx);
1690
    fz_write_printf(ctx, err, "Before sort:\n");
1691
    fz_edgebuffer_print_app(ctx, err, eb);
1692
  }
1693
#endif
1694
1695
0
  if (!eb->sorted)
1696
0
  {
1697
0
    eb->sorted = 1;
1698
0
    for (i = 0; i < scanlines; i++)
1699
0
    {
1700
0
      int *row = &table[index[i]];
1701
0
      int rowlen = *row++;
1702
1703
      /* Bubblesort short runs, qsort longer ones. */
1704
      /* FIXME: Check "6" below */
1705
0
      if (rowlen <= 6) {
1706
0
        int j, k;
1707
0
        for (j = 0; j < rowlen-1; j++) {
1708
0
          int * FZ_RESTRICT t = &row[j<<1];
1709
0
          for (k = j+1; k < rowlen; k++) {
1710
0
            int * FZ_RESTRICT s = &row[k<<1];
1711
0
            int tmp;
1712
0
            if (t[0] < s[0])
1713
0
              continue;
1714
0
            if (t[0] > s[0])
1715
0
              tmp = t[0], t[0] = s[0], s[0] = tmp;
1716
0
            else if (t[0] <= s[1])
1717
0
              continue;
1718
0
            tmp = t[1]; t[1] = s[1]; s[1] = tmp;
1719
0
          }
1720
0
        }
1721
0
      } else
1722
0
        qsort(row, rowlen, 2*sizeof(int), edgecmp);
1723
0
    }
1724
1725
#ifdef DEBUG_SCAN_CONVERTER
1726
    if (debugging_scan_converter)
1727
    {
1728
      fz_output *err = fz_stderr(ctx);
1729
      fz_write_printf(ctx, err, "Before filter: %s\n", eofill ? "EO" : "NZ");
1730
      fz_edgebuffer_print_app(ctx, err, eb);
1731
    }
1732
#endif
1733
1734
0
    for (i=0; i < scanlines; i++) {
1735
0
      int *row = &table[index[i]];
1736
0
      int rowlen = *row++;
1737
0
      int *rowstart = row;
1738
0
      int *rowout = row;
1739
0
      int  ll, lr, rl, rr, wind, marked_to;
1740
1741
      /* Avoid double setting pixels, by keeping where we have marked to. */
1742
0
      marked_to = int2fixed(clip->x0);
1743
0
      while (rowlen > 0) {
1744
0
        if (eofill) {
1745
          /* Even Odd */
1746
0
          ll = (*row++)&~1;
1747
0
          lr = *row;
1748
0
          row += 2;
1749
0
          rowlen-=2;
1750
1751
          /* We will fill solidly from ll to at least lr, possibly further */
1752
0
          assert(rowlen >= 0);
1753
0
          rr = (*row++);
1754
0
          if (rr > lr)
1755
0
            lr = rr;
1756
0
        } else {
1757
          /* Non-Zero */
1758
0
          int w;
1759
1760
0
          ll = *row++;
1761
0
          lr = *row++;
1762
0
          wind = -(ll&1) | 1;
1763
0
          ll &= ~1;
1764
0
          rowlen--;
1765
1766
0
          assert(rowlen > 0);
1767
0
          do {
1768
0
            rl = *row++;
1769
0
            rr = *row++;
1770
0
            w = -(rl&1) | 1;
1771
            /* rl &= ~1; */
1772
0
            rowlen--;
1773
0
            if (rr > lr)
1774
0
              lr = rr;
1775
0
            wind += w;
1776
0
            if (wind == 0)
1777
0
              break;
1778
0
          } while (rowlen > 0);
1779
0
        }
1780
1781
0
        if (marked_to >= lr)
1782
0
          continue;
1783
1784
0
        if (marked_to >= ll) {
1785
0
          if (rowout == rowstart)
1786
0
            ll = marked_to;
1787
0
          else {
1788
0
            rowout -= 2;
1789
0
            ll = *rowout;
1790
0
          }
1791
0
        }
1792
1793
0
        if (lr > ll) {
1794
0
          *rowout++ = ll;
1795
0
          *rowout++ = lr;
1796
0
          marked_to = lr;
1797
0
        }
1798
0
      }
1799
0
      rowstart[-1] = rowout-rowstart;
1800
0
    }
1801
0
  }
1802
1803
#ifdef DEBUG_SCAN_CONVERTER
1804
  if (debugging_scan_converter)
1805
  {
1806
    fz_output *err = fz_stderr(ctx);
1807
    fz_write_printf(ctx, err, "Before render:\n");
1808
    fz_edgebuffer_print_app(ctx, err, eb);
1809
  }
1810
#endif
1811
1812
0
  n = pix->n;
1813
0
  a = pix->alpha;
1814
0
  pl = clip->x0;
1815
0
  pr = clip->x1 - pl;
1816
0
  out = pix->samples + pix->stride * (clip->y0 - pix->y) + (clip->x0 - pix->x) * n;
1817
0
  if (scanlines > clip->y1 - ras->clip.y0)
1818
0
    scanlines = clip->y1 - ras->clip.y0;
1819
1820
0
  i = (clip->y0 - ras->clip.y0);
1821
0
  if (i < 0)
1822
0
    return;
1823
0
  for (; i < scanlines; i++) {
1824
0
    int *row = &table[index[i]];
1825
0
    int  rowlen = *row++;
1826
1827
0
    while (rowlen > 0) {
1828
0
      int left, right;
1829
1830
0
      left  = *row++;
1831
0
      right = *row++;
1832
0
      rowlen -= 2;
1833
0
      left  = fixed2int(left + fixed_half) - pl;
1834
0
      right = fixed2int(right + fixed_half) - pl;
1835
1836
0
      if (right <= 0)
1837
0
        continue;
1838
0
      if (left >= pr)
1839
0
        break;
1840
0
      if (right > pr)
1841
0
        right = pr;
1842
0
      if (left < 0)
1843
0
        left = 0;
1844
0
      right -= left;
1845
0
      if (right > 0) {
1846
0
        (*fn)(out + left*n, n, right, color, a, eop);
1847
0
      }
1848
0
    }
1849
0
    out += pix->stride;
1850
0
  }
1851
0
}
1852
1853
static void fz_gap_edgebuffer(fz_context *ctx, fz_rasterizer *ras)
1854
0
{
1855
0
  fz_edgebuffer *eb = (fz_edgebuffer *)ras;
1856
1857
0
  if (eb->app)
1858
0
  {
1859
#ifdef DEBUG_SCAN_CONVERTER
1860
    if (0 && debugging_scan_converter)
1861
    {
1862
      fz_output *err = fz_stderr(ctx);
1863
      fz_write_printf(ctx, fz_stderr(ctx), "Pen up move.\n");
1864
      fz_write_printf(ctx, err, "Before flush:\n");
1865
      fz_edgebuffer_print_app(ctx, err, eb);
1866
    }
1867
#endif
1868
0
    cursor_flush(eb);
1869
0
    eb->cursor[0].saved = 0;
1870
0
    eb->cursor[0].unset = 1;
1871
0
    eb->cursor[0].can_save = 1;
1872
0
    eb->cursor[0].d = DIRN_UNSET;
1873
0
    eb->cursor[1].saved = 0;
1874
0
    eb->cursor[1].unset = 1;
1875
0
    eb->cursor[1].can_save = 1;
1876
0
    eb->cursor[1].d = DIRN_UNSET;
1877
0
    eb->cursor[2].saved = 0;
1878
0
    eb->cursor[2].unset = 1;
1879
0
    eb->cursor[2].can_save = 1;
1880
0
    eb->cursor[2].d = DIRN_UNSET;
1881
0
  }
1882
0
}
1883
1884
static int fz_is_rect_edgebuffer(fz_context *ctx, fz_rasterizer *r)
1885
0
{
1886
0
  return 0;
1887
0
}
1888
1889
static const fz_rasterizer_fns edgebuffer_app =
1890
{
1891
  fz_drop_edgebuffer,
1892
  fz_reset_edgebuffer,
1893
  fz_postindex_edgebuffer,
1894
  fz_insert_edgebuffer_app,
1895
  NULL,
1896
  fz_gap_edgebuffer,
1897
  fz_convert_edgebuffer_app,
1898
  fz_is_rect_edgebuffer,
1899
  1 /* Reusable */
1900
};
1901
1902
static const fz_rasterizer_fns edgebuffer_cop =
1903
{
1904
  fz_drop_edgebuffer,
1905
  fz_reset_edgebuffer,
1906
  fz_postindex_edgebuffer,
1907
  fz_insert_edgebuffer,
1908
  NULL,
1909
  NULL, /* gap */
1910
  fz_convert_edgebuffer,
1911
  fz_is_rect_edgebuffer,
1912
  1 /* Reusable */
1913
};
1914
1915
fz_rasterizer *
1916
fz_new_edgebuffer(fz_context *ctx, fz_edgebuffer_rule rule)
1917
0
{
1918
0
  fz_edgebuffer *eb;
1919
0
  eb = fz_new_derived_rasterizer(ctx, fz_edgebuffer, rule == FZ_EDGEBUFFER_ANY_PART_OF_PIXEL ? &edgebuffer_app : &edgebuffer_cop);
1920
0
  eb->app = rule == FZ_EDGEBUFFER_ANY_PART_OF_PIXEL;
1921
0
  return &eb->super;
1922
0
}