Coverage Report

Created: 2025-07-07 10:01

/work/workdir/UnpackedTarball/cairo/src/cairo-mono-scan-converter.c
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2
/*
3
 * Copyright (c) 2011  Intel Corporation
4
 *
5
 * Permission is hereby granted, free of charge, to any person
6
 * obtaining a copy of this software and associated documentation
7
 * files (the "Software"), to deal in the Software without
8
 * restriction, including without limitation the rights to use,
9
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the
11
 * Software is furnished to do so, subject to the following
12
 * conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be
15
 * included in all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
 * OTHER DEALINGS IN THE SOFTWARE.
25
 */
26
#include "cairoint.h"
27
#include "cairo-spans-private.h"
28
#include "cairo-error-private.h"
29
30
#include <stdlib.h>
31
#include <string.h>
32
#include <limits.h>
33
34
struct quorem {
35
    int32_t quo;
36
    int32_t rem;
37
};
38
39
struct edge {
40
    struct edge *next, *prev;
41
42
    int32_t height_left;
43
    int32_t dir;
44
    int32_t vertical;
45
46
    int32_t dy;
47
    struct quorem x;
48
    struct quorem dxdy;
49
};
50
51
/* A collection of sorted and vertically clipped edges of the polygon.
52
 * Edges are moved from the polygon to an active list while scan
53
 * converting. */
54
struct polygon {
55
    /* The vertical clip extents. */
56
    int32_t ymin, ymax;
57
58
    int num_edges;
59
    struct edge *edges;
60
61
    /* Array of edges all starting in the same bucket.  An edge is put
62
     * into bucket EDGE_BUCKET_INDEX(edge->ytop, polygon->ymin) when
63
     * it is added to the polygon. */
64
    struct edge **y_buckets;
65
66
    struct edge *y_buckets_embedded[64];
67
    struct edge edges_embedded[32];
68
};
69
70
struct mono_scan_converter {
71
    struct polygon polygon[1];
72
73
    /* Leftmost edge on the current scan line. */
74
    struct edge head, tail;
75
    int is_vertical;
76
77
    cairo_half_open_span_t *spans;
78
    cairo_half_open_span_t spans_embedded[64];
79
    int num_spans;
80
81
    /* Clip box. */
82
    int32_t xmin, xmax;
83
    int32_t ymin, ymax;
84
};
85
86
978k
#define I(x) _cairo_fixed_integer_round_down(x)
87
88
/* Compute the floored division a/b. Assumes / and % perform symmetric
89
 * division. */
90
inline static struct quorem
91
floored_divrem(int a, int b)
92
0
{
93
0
    struct quorem qr;
94
0
    qr.quo = a/b;
95
0
    qr.rem = a%b;
96
0
    if ((a^b)<0 && qr.rem) {
97
0
  qr.quo -= 1;
98
0
  qr.rem += b;
99
0
    }
100
0
    return qr;
101
0
}
102
103
/* Compute the floored division (x*a)/b. Assumes / and % perform symmetric
104
 * division. */
105
static struct quorem
106
floored_muldivrem(int x, int a, int b)
107
23.9k
{
108
23.9k
    struct quorem qr;
109
23.9k
    long long xa = (long long)x*a;
110
23.9k
    qr.quo = xa/b;
111
23.9k
    qr.rem = xa%b;
112
23.9k
    if ((xa>=0) != (b>=0) && qr.rem) {
113
6.20k
  qr.quo -= 1;
114
6.20k
  qr.rem += b;
115
6.20k
    }
116
23.9k
    return qr;
117
23.9k
}
118
119
static cairo_status_t
120
polygon_init (struct polygon *polygon, int ymin, int ymax)
121
20.3k
{
122
20.3k
    unsigned h = ymax - ymin + 1;
123
124
20.3k
    polygon->y_buckets = polygon->y_buckets_embedded;
125
20.3k
    if (h > ARRAY_LENGTH (polygon->y_buckets_embedded)) {
126
0
  polygon->y_buckets = _cairo_malloc_ab (h, sizeof (struct edge *));
127
0
  if (unlikely (NULL == polygon->y_buckets))
128
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
129
0
    }
130
20.3k
    memset (polygon->y_buckets, 0, h * sizeof (struct edge *));
131
20.3k
    polygon->y_buckets[h-1] = (void *)-1;
132
133
20.3k
    polygon->ymin = ymin;
134
20.3k
    polygon->ymax = ymax;
135
20.3k
    return CAIRO_STATUS_SUCCESS;
136
20.3k
}
137
138
static void
139
polygon_fini (struct polygon *polygon)
140
20.3k
{
141
20.3k
    if (polygon->y_buckets != polygon->y_buckets_embedded)
142
0
  free (polygon->y_buckets);
143
144
20.3k
    if (polygon->edges != polygon->edges_embedded)
145
600
  free (polygon->edges);
146
20.3k
}
147
148
static void
149
_polygon_insert_edge_into_its_y_bucket(struct polygon *polygon,
150
               struct edge *e,
151
               int y)
152
267k
{
153
267k
    struct edge **ptail = &polygon->y_buckets[y - polygon->ymin];
154
267k
    if (*ptail)
155
247k
  (*ptail)->prev = e;
156
267k
    e->next = *ptail;
157
267k
    e->prev = NULL;
158
267k
    *ptail = e;
159
267k
}
160
161
inline static void
162
polygon_add_edge (struct polygon *polygon,
163
      const cairo_edge_t *edge)
164
320k
{
165
320k
    struct edge *e;
166
320k
    cairo_fixed_t dx;
167
320k
    cairo_fixed_t dy;
168
320k
    int y, ytop, ybot;
169
320k
    int ymin = polygon->ymin;
170
320k
    int ymax = polygon->ymax;
171
172
320k
    y = I(edge->top);
173
320k
    ytop = MAX(y, ymin);
174
175
320k
    y = I(edge->bottom);
176
320k
    ybot = MIN(y, ymax);
177
178
320k
    if (ybot <= ytop)
179
52.9k
  return;
180
181
267k
    e = polygon->edges + polygon->num_edges++;
182
267k
    e->height_left = ybot - ytop;
183
267k
    e->dir = edge->dir;
184
185
267k
    dx = edge->line.p2.x - edge->line.p1.x;
186
267k
    dy = edge->line.p2.y - edge->line.p1.y;
187
188
267k
    if (dx == 0) {
189
255k
  e->vertical = TRUE;
190
255k
  e->x.quo = edge->line.p1.x;
191
255k
  e->x.rem = 0;
192
255k
  e->dxdy.quo = 0;
193
255k
  e->dxdy.rem = 0;
194
255k
  e->dy = 0;
195
255k
    } else {
196
11.9k
  e->vertical = FALSE;
197
11.9k
  e->dxdy = floored_muldivrem (dx, CAIRO_FIXED_ONE, dy);
198
11.9k
  e->dy = dy;
199
200
11.9k
  e->x = floored_muldivrem (ytop * CAIRO_FIXED_ONE + CAIRO_FIXED_FRAC_MASK/2 - edge->line.p1.y,
201
11.9k
          dx, dy);
202
11.9k
  e->x.quo += edge->line.p1.x;
203
11.9k
    }
204
267k
    e->x.rem -= dy;
205
206
267k
    _polygon_insert_edge_into_its_y_bucket (polygon, e, ytop);
207
267k
}
208
209
static struct edge *
210
merge_sorted_edges (struct edge *head_a, struct edge *head_b)
211
133k
{
212
133k
    struct edge *head, **next, *prev;
213
133k
    int32_t x;
214
215
133k
    prev = head_a->prev;
216
133k
    next = &head;
217
133k
    if (head_a->x.quo <= head_b->x.quo) {
218
94.6k
  head = head_a;
219
94.6k
    } else {
220
39.1k
  head = head_b;
221
39.1k
  head_b->prev = prev;
222
39.1k
  goto start_with_b;
223
39.1k
    }
224
225
120k
    do {
226
120k
  x = head_b->x.quo;
227
797k
  while (head_a != NULL && head_a->x.quo <= x) {
228
676k
      prev = head_a;
229
676k
      next = &head_a->next;
230
676k
      head_a = head_a->next;
231
676k
  }
232
233
120k
  head_b->prev = prev;
234
120k
  *next = head_b;
235
120k
  if (head_a == NULL)
236
51.8k
      return head;
237
238
107k
start_with_b:
239
107k
  x = head_a->x.quo;
240
979k
  while (head_b != NULL && head_b->x.quo <= x) {
241
871k
      prev = head_b;
242
871k
      next = &head_b->next;
243
871k
      head_b = head_b->next;
244
871k
  }
245
246
107k
  head_a->prev = prev;
247
107k
  *next = head_a;
248
107k
  if (head_b == NULL)
249
81.8k
      return head;
250
107k
    } while (1);
251
94.6k
}
252
253
static struct edge *
254
sort_edges (struct edge *list,
255
      unsigned int level,
256
      struct edge **head_out)
257
133k
{
258
133k
    struct edge *head_other, *remaining;
259
133k
    unsigned int i;
260
261
133k
    head_other = list->next;
262
263
133k
    if (head_other == NULL) {
264
0
  *head_out = list;
265
0
  return NULL;
266
0
    }
267
268
133k
    remaining = head_other->next;
269
133k
    if (list->x.quo <= head_other->x.quo) {
270
96.9k
  *head_out = list;
271
96.9k
  head_other->next = NULL;
272
96.9k
    } else {
273
36.7k
  *head_out = head_other;
274
36.7k
  head_other->prev = list->prev;
275
36.7k
  head_other->next = list;
276
36.7k
  list->prev = head_other;
277
36.7k
  list->next = NULL;
278
36.7k
    }
279
280
247k
    for (i = 0; i < level && remaining; i++) {
281
113k
  remaining = sort_edges (remaining, i, &head_other);
282
113k
  *head_out = merge_sorted_edges (*head_out, head_other);
283
113k
    }
284
285
133k
    return remaining;
286
133k
}
287
288
static struct edge *
289
merge_unsorted_edges (struct edge *head, struct edge *unsorted)
290
20.3k
{
291
20.3k
    sort_edges (unsorted, UINT_MAX, &unsorted);
292
20.3k
    return merge_sorted_edges (head, unsorted);
293
20.3k
}
294
295
inline static void
296
active_list_merge_edges (struct mono_scan_converter *c, struct edge *edges)
297
20.3k
{
298
20.3k
    struct edge *e;
299
300
145k
    for (e = edges; c->is_vertical && e; e = e->next)
301
125k
  c->is_vertical = e->vertical;
302
303
20.3k
    c->head.next = merge_unsorted_edges (c->head.next, edges);
304
20.3k
}
305
306
inline static void
307
add_span (struct mono_scan_converter *c, int x1, int x2)
308
20.3k
{
309
20.3k
    int n;
310
311
20.3k
    if (x1 < c->xmin)
312
0
  x1 = c->xmin;
313
20.3k
    if (x2 > c->xmax)
314
6
  x2 = c->xmax;
315
20.3k
    if (x2 <= x1)
316
830
  return;
317
318
19.4k
    n = c->num_spans++;
319
19.4k
    c->spans[n].x = x1;
320
19.4k
    c->spans[n].coverage = 255;
321
322
19.4k
    n = c->num_spans++;
323
19.4k
    c->spans[n].x = x2;
324
19.4k
    c->spans[n].coverage = 0;
325
19.4k
}
326
327
inline static void
328
row (struct mono_scan_converter *c, unsigned int mask)
329
20.3k
{
330
20.3k
    struct edge *edge = c->head.next;
331
20.3k
    int xstart = INT_MIN, prev_x = INT_MIN;
332
20.3k
    int winding = 0;
333
334
20.3k
    c->num_spans = 0;
335
287k
    while (&c->tail != edge) {
336
267k
  struct edge *next = edge->next;
337
267k
  int xend = I(edge->x.quo);
338
339
267k
  if (--edge->height_left) {
340
0
      if (!edge->vertical) {
341
0
    edge->x.quo += edge->dxdy.quo;
342
0
    edge->x.rem += edge->dxdy.rem;
343
0
    if (edge->x.rem >= 0) {
344
0
        ++edge->x.quo;
345
0
        edge->x.rem -= edge->dy;
346
0
    }
347
0
      }
348
349
0
      if (edge->x.quo < prev_x) {
350
0
    struct edge *pos = edge->prev;
351
0
    pos->next = next;
352
0
    next->prev = pos;
353
0
    do {
354
0
        pos = pos->prev;
355
0
    } while (edge->x.quo < pos->x.quo);
356
0
    pos->next->prev = edge;
357
0
    edge->next = pos->next;
358
0
    edge->prev = pos;
359
0
    pos->next = edge;
360
0
      } else
361
0
    prev_x = edge->x.quo;
362
267k
  } else {
363
267k
      edge->prev->next = next;
364
267k
      next->prev = edge->prev;
365
267k
  }
366
367
267k
  winding += edge->dir;
368
267k
  if ((winding & mask) == 0) {
369
70.6k
      if (I(next->x.quo) > xend + 1) {
370
20.3k
    add_span (c, xstart, xend);
371
20.3k
    xstart = INT_MIN;
372
20.3k
      }
373
196k
  } else if (xstart == INT_MIN)
374
20.3k
      xstart = xend;
375
376
267k
  edge = next;
377
267k
    }
378
20.3k
}
379
380
inline static void dec (struct edge *e, int h)
381
0
{
382
0
    e->height_left -= h;
383
0
    if (e->height_left == 0) {
384
0
  e->prev->next = e->next;
385
0
  e->next->prev = e->prev;
386
0
    }
387
0
}
388
389
static cairo_status_t
390
_mono_scan_converter_init(struct mono_scan_converter *c,
391
        int xmin, int ymin,
392
        int xmax, int ymax)
393
20.3k
{
394
20.3k
    cairo_status_t status;
395
20.3k
    int max_num_spans;
396
397
20.3k
    status = polygon_init (c->polygon, ymin, ymax);
398
20.3k
    if  (unlikely (status))
399
0
  return status;
400
401
20.3k
    max_num_spans = xmax - xmin + 1;
402
20.3k
    if (max_num_spans > ARRAY_LENGTH(c->spans_embedded)) {
403
0
  c->spans = _cairo_malloc_ab (max_num_spans,
404
0
             sizeof (cairo_half_open_span_t));
405
0
  if (unlikely (c->spans == NULL)) {
406
0
      polygon_fini (c->polygon);
407
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
408
0
  }
409
0
    } else
410
20.3k
  c->spans = c->spans_embedded;
411
412
20.3k
    c->xmin = xmin;
413
20.3k
    c->xmax = xmax;
414
20.3k
    c->ymin = ymin;
415
20.3k
    c->ymax = ymax;
416
417
20.3k
    c->head.vertical = 1;
418
20.3k
    c->head.height_left = INT_MAX;
419
20.3k
    c->head.x.quo = _cairo_fixed_from_int (_cairo_fixed_integer_part (INT_MIN));
420
20.3k
    c->head.prev = NULL;
421
20.3k
    c->head.next = &c->tail;
422
20.3k
    c->tail.prev = &c->head;
423
20.3k
    c->tail.next = NULL;
424
20.3k
    c->tail.x.quo = _cairo_fixed_from_int (_cairo_fixed_integer_part (INT_MAX));
425
20.3k
    c->tail.height_left = INT_MAX;
426
20.3k
    c->tail.vertical = 1;
427
428
20.3k
    c->is_vertical = 1;
429
20.3k
    return CAIRO_STATUS_SUCCESS;
430
20.3k
}
431
432
static void
433
_mono_scan_converter_fini(struct mono_scan_converter *self)
434
20.3k
{
435
20.3k
    if (self->spans != self->spans_embedded)
436
0
  free (self->spans);
437
438
20.3k
    polygon_fini(self->polygon);
439
20.3k
}
440
441
static cairo_status_t
442
mono_scan_converter_allocate_edges(struct mono_scan_converter *c,
443
           int num_edges)
444
445
20.3k
{
446
20.3k
    c->polygon->num_edges = 0;
447
20.3k
    c->polygon->edges = c->polygon->edges_embedded;
448
20.3k
    if (num_edges > ARRAY_LENGTH (c->polygon->edges_embedded)) {
449
600
  c->polygon->edges = _cairo_malloc_ab (num_edges, sizeof (struct edge));
450
600
  if (unlikely (c->polygon->edges == NULL))
451
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
452
600
    }
453
454
20.3k
    return CAIRO_STATUS_SUCCESS;
455
20.3k
}
456
457
static void
458
mono_scan_converter_add_edge (struct mono_scan_converter *c,
459
            const cairo_edge_t *edge)
460
320k
{
461
320k
    polygon_add_edge (c->polygon, edge);
462
320k
}
463
464
static void
465
step_edges (struct mono_scan_converter *c, int count)
466
0
{
467
0
    struct edge *edge;
468
469
0
    for (edge = c->head.next; edge != &c->tail; edge = edge->next) {
470
0
  edge->height_left -= count;
471
0
  if (! edge->height_left) {
472
0
      edge->prev->next = edge->next;
473
0
      edge->next->prev = edge->prev;
474
0
  }
475
0
    }
476
0
}
477
478
static cairo_status_t
479
mono_scan_converter_render(struct mono_scan_converter *c,
480
         unsigned int winding_mask,
481
         cairo_span_renderer_t *renderer)
482
20.3k
{
483
20.3k
    struct polygon *polygon = c->polygon;
484
20.3k
    int i, j, h = c->ymax - c->ymin;
485
20.3k
    cairo_status_t status;
486
487
40.6k
    for (i = 0; i < h; i = j) {
488
20.3k
  j = i + 1;
489
490
20.3k
  if (polygon->y_buckets[i])
491
20.3k
      active_list_merge_edges (c, polygon->y_buckets[i]);
492
493
20.3k
  if (c->is_vertical) {
494
18.4k
      int min_height;
495
18.4k
      struct edge *e;
496
497
18.4k
      e = c->head.next;
498
18.4k
      min_height = e->height_left;
499
123k
      while (e != &c->tail) {
500
104k
    if (e->height_left < min_height)
501
0
        min_height = e->height_left;
502
104k
    e = e->next;
503
104k
      }
504
505
18.4k
      while (--min_height >= 1 && polygon->y_buckets[j] == NULL)
506
0
    j++;
507
18.4k
      if (j != i + 1)
508
0
    step_edges (c, j - (i + 1));
509
18.4k
  }
510
511
20.3k
  row (c, winding_mask);
512
20.3k
  if (c->num_spans) {
513
19.4k
      status = renderer->render_rows (renderer, c->ymin+i, j-i,
514
19.4k
              c->spans, c->num_spans);
515
19.4k
      if (unlikely (status))
516
0
    return status;
517
19.4k
  }
518
519
  /* XXX recompute after dropping edges? */
520
20.3k
  if (c->head.next == &c->tail)
521
20.3k
      c->is_vertical = 1;
522
20.3k
    }
523
524
20.3k
    return CAIRO_STATUS_SUCCESS;
525
20.3k
}
526
527
struct _cairo_mono_scan_converter {
528
    cairo_scan_converter_t base;
529
530
    struct mono_scan_converter converter[1];
531
    cairo_fill_rule_t fill_rule;
532
};
533
534
typedef struct _cairo_mono_scan_converter cairo_mono_scan_converter_t;
535
536
static void
537
_cairo_mono_scan_converter_destroy (void *converter)
538
20.3k
{
539
20.3k
    cairo_mono_scan_converter_t *self = converter;
540
20.3k
    _mono_scan_converter_fini (self->converter);
541
20.3k
    free(self);
542
20.3k
}
543
544
cairo_status_t
545
_cairo_mono_scan_converter_add_polygon (void    *converter,
546
               const cairo_polygon_t *polygon)
547
20.3k
{
548
20.3k
    cairo_mono_scan_converter_t *self = converter;
549
20.3k
    cairo_status_t status;
550
20.3k
    int i;
551
552
#if 0
553
    FILE *file = fopen ("polygon.txt", "w");
554
    _cairo_debug_print_polygon (file, polygon);
555
    fclose (file);
556
#endif
557
558
20.3k
    status = mono_scan_converter_allocate_edges (self->converter,
559
20.3k
             polygon->num_edges);
560
20.3k
    if (unlikely (status))
561
0
  return status;
562
563
340k
    for (i = 0; i < polygon->num_edges; i++)
564
320k
   mono_scan_converter_add_edge (self->converter, &polygon->edges[i]);
565
566
20.3k
    return CAIRO_STATUS_SUCCESS;
567
20.3k
}
568
569
static cairo_status_t
570
_cairo_mono_scan_converter_generate (void     *converter,
571
            cairo_span_renderer_t *renderer)
572
20.3k
{
573
20.3k
    cairo_mono_scan_converter_t *self = converter;
574
575
20.3k
    return mono_scan_converter_render (self->converter,
576
20.3k
               self->fill_rule == CAIRO_FILL_RULE_WINDING ? ~0 : 1,
577
20.3k
               renderer);
578
20.3k
}
579
580
cairo_scan_converter_t *
581
_cairo_mono_scan_converter_create (int      xmin,
582
          int     ymin,
583
          int     xmax,
584
          int     ymax,
585
          cairo_fill_rule_t fill_rule)
586
20.3k
{
587
20.3k
    cairo_mono_scan_converter_t *self;
588
20.3k
    cairo_status_t status;
589
590
20.3k
    self = _cairo_malloc (sizeof(struct _cairo_mono_scan_converter));
591
20.3k
    if (unlikely (self == NULL)) {
592
0
  status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
593
0
  goto bail_nomem;
594
0
    }
595
596
20.3k
    self->base.destroy = _cairo_mono_scan_converter_destroy;
597
20.3k
    self->base.generate = _cairo_mono_scan_converter_generate;
598
599
20.3k
    status = _mono_scan_converter_init (self->converter,
600
20.3k
          xmin, ymin, xmax, ymax);
601
20.3k
    if (unlikely (status))
602
0
  goto bail;
603
604
20.3k
    self->fill_rule = fill_rule;
605
606
20.3k
    return &self->base;
607
608
0
 bail:
609
0
    self->base.destroy(&self->base);
610
0
 bail_nomem:
611
0
    return _cairo_scan_converter_create_in_error (status);
612
0
}