Coverage Report

Created: 2026-06-30 11:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/cairo/src/cairo-mono-scan-converter.c
Line
Count
Source
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
84.4k
#define I(x) _cairo_fixed_integer_round_down(x)
87
88
/* Compute the floored division (x*a)/b. Assumes / and % perform symmetric
89
 * division. */
90
static struct quorem
91
floored_muldivrem(int x, int a, int b)
92
2.11k
{
93
2.11k
    struct quorem qr;
94
2.11k
    long long xa = (long long)x*a;
95
2.11k
    qr.quo = xa/b;
96
2.11k
    qr.rem = xa%b;
97
2.11k
    if ((xa>=0) != (b>=0) && qr.rem) {
98
629
  qr.quo -= 1;
99
629
  qr.rem += b;
100
629
    }
101
2.11k
    return qr;
102
2.11k
}
103
104
static cairo_status_t
105
polygon_init (struct polygon *polygon, int ymin, int ymax)
106
2.61k
{
107
2.61k
    unsigned h = ymax - ymin + 1;
108
109
2.61k
    polygon->y_buckets = polygon->y_buckets_embedded;
110
2.61k
    if (h > ARRAY_LENGTH (polygon->y_buckets_embedded)) {
111
0
  polygon->y_buckets = _cairo_malloc_ab (h, sizeof (struct edge *));
112
0
  if (unlikely (NULL == polygon->y_buckets))
113
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
114
0
    }
115
2.61k
    memset (polygon->y_buckets, 0, h * sizeof (struct edge *));
116
2.61k
    polygon->y_buckets[h-1] = (void *)-1;
117
118
2.61k
    polygon->ymin = ymin;
119
2.61k
    polygon->ymax = ymax;
120
2.61k
    return CAIRO_STATUS_SUCCESS;
121
2.61k
}
122
123
static void
124
polygon_fini (struct polygon *polygon)
125
2.61k
{
126
2.61k
    if (polygon->y_buckets != polygon->y_buckets_embedded)
127
0
  free (polygon->y_buckets);
128
129
2.61k
    if (polygon->edges != polygon->edges_embedded)
130
41
  free (polygon->edges);
131
2.61k
}
132
133
static void
134
_polygon_insert_edge_into_its_y_bucket(struct polygon *polygon,
135
               struct edge *e,
136
               int y)
137
23.5k
{
138
23.5k
    struct edge **ptail = &polygon->y_buckets[y - polygon->ymin];
139
23.5k
    if (*ptail)
140
20.8k
  (*ptail)->prev = e;
141
23.5k
    e->next = *ptail;
142
23.5k
    e->prev = NULL;
143
23.5k
    *ptail = e;
144
23.5k
}
145
146
inline static void
147
polygon_add_edge (struct polygon *polygon,
148
      const cairo_edge_t *edge)
149
28.0k
{
150
28.0k
    struct edge *e;
151
28.0k
    cairo_fixed_t dx;
152
28.0k
    cairo_fixed_t dy;
153
28.0k
    int y, ytop, ybot;
154
28.0k
    int ymin = polygon->ymin;
155
28.0k
    int ymax = polygon->ymax;
156
157
28.0k
    y = I(edge->top);
158
28.0k
    ytop = MAX(y, ymin);
159
160
28.0k
    y = I(edge->bottom);
161
28.0k
    ybot = MIN(y, ymax);
162
163
28.0k
    if (ybot <= ytop)
164
4.49k
  return;
165
166
23.5k
    e = polygon->edges + polygon->num_edges++;
167
23.5k
    e->height_left = ybot - ytop;
168
23.5k
    e->dir = edge->dir;
169
170
23.5k
    dx = edge->line.p2.x - edge->line.p1.x;
171
23.5k
    dy = edge->line.p2.y - edge->line.p1.y;
172
173
23.5k
    if (dx == 0) {
174
22.4k
  e->vertical = TRUE;
175
22.4k
  e->x.quo = edge->line.p1.x;
176
22.4k
  e->x.rem = 0;
177
22.4k
  e->dxdy.quo = 0;
178
22.4k
  e->dxdy.rem = 0;
179
22.4k
  e->dy = 0;
180
22.4k
    } else {
181
1.05k
  e->vertical = FALSE;
182
1.05k
  e->dxdy = floored_muldivrem (dx, CAIRO_FIXED_ONE, dy);
183
1.05k
  e->dy = dy;
184
185
1.05k
  e->x = floored_muldivrem (ytop * CAIRO_FIXED_ONE + CAIRO_FIXED_FRAC_MASK/2 - edge->line.p1.y,
186
1.05k
          dx, dy);
187
1.05k
  e->x.quo += edge->line.p1.x;
188
1.05k
    }
189
23.5k
    e->x.rem -= dy;
190
191
23.5k
    _polygon_insert_edge_into_its_y_bucket (polygon, e, ytop);
192
23.5k
}
193
194
static struct edge *
195
merge_sorted_edges (struct edge *head_a, struct edge *head_b)
196
11.7k
{
197
11.7k
    struct edge *head, **next, *prev;
198
11.7k
    int32_t x;
199
200
11.7k
    prev = head_a->prev;
201
11.7k
    next = &head;
202
11.7k
    if (head_a->x.quo <= head_b->x.quo) {
203
7.39k
  head = head_a;
204
7.39k
    } else {
205
4.36k
  head = head_b;
206
4.36k
  head_b->prev = prev;
207
4.36k
  goto start_with_b;
208
4.36k
    }
209
210
10.4k
    do {
211
10.4k
  x = head_b->x.quo;
212
58.0k
  while (head_a != NULL && head_a->x.quo <= x) {
213
47.5k
      prev = head_a;
214
47.5k
      next = &head_a->next;
215
47.5k
      head_a = head_a->next;
216
47.5k
  }
217
218
10.4k
  head_b->prev = prev;
219
10.4k
  *next = head_b;
220
10.4k
  if (head_a == NULL)
221
4.39k
      return head;
222
223
10.4k
start_with_b:
224
10.4k
  x = head_a->x.quo;
225
73.7k
  while (head_b != NULL && head_b->x.quo <= x) {
226
63.2k
      prev = head_b;
227
63.2k
      next = &head_b->next;
228
63.2k
      head_b = head_b->next;
229
63.2k
  }
230
231
10.4k
  head_a->prev = prev;
232
10.4k
  *next = head_a;
233
10.4k
  if (head_b == NULL)
234
7.35k
      return head;
235
10.4k
    } while (1);
236
7.39k
}
237
238
static struct edge *
239
sort_edges (struct edge *list,
240
      unsigned int level,
241
      struct edge **head_out)
242
11.7k
{
243
11.7k
    struct edge *head_other, *remaining;
244
11.7k
    unsigned int i;
245
246
11.7k
    head_other = list->next;
247
248
11.7k
    if (head_other == NULL) {
249
0
  *head_out = list;
250
0
  return NULL;
251
0
    }
252
253
11.7k
    remaining = head_other->next;
254
11.7k
    if (list->x.quo <= head_other->x.quo) {
255
7.35k
  *head_out = list;
256
7.35k
  head_other->next = NULL;
257
7.35k
    } else {
258
4.40k
  *head_out = head_other;
259
4.40k
  head_other->prev = list->prev;
260
4.40k
  head_other->next = list;
261
4.40k
  list->prev = head_other;
262
4.40k
  list->next = NULL;
263
4.40k
    }
264
265
20.8k
    for (i = 0; i < level && remaining; i++) {
266
9.13k
  remaining = sort_edges (remaining, i, &head_other);
267
9.13k
  *head_out = merge_sorted_edges (*head_out, head_other);
268
9.13k
    }
269
270
11.7k
    return remaining;
271
11.7k
}
272
273
static struct edge *
274
merge_unsorted_edges (struct edge *head, struct edge *unsorted)
275
2.61k
{
276
2.61k
    sort_edges (unsorted, UINT_MAX, &unsorted);
277
2.61k
    return merge_sorted_edges (head, unsorted);
278
2.61k
}
279
280
inline static void
281
active_list_merge_edges (struct mono_scan_converter *c, struct edge *edges)
282
2.61k
{
283
2.61k
    struct edge *e;
284
285
16.7k
    for (e = edges; c->is_vertical && e; e = e->next)
286
14.1k
  c->is_vertical = e->vertical;
287
288
2.61k
    c->head.next = merge_unsorted_edges (c->head.next, edges);
289
2.61k
}
290
291
inline static void
292
add_span (struct mono_scan_converter *c, int x1, int x2)
293
2.61k
{
294
2.61k
    int n;
295
296
2.61k
    if (x1 < c->xmin)
297
0
  x1 = c->xmin;
298
2.61k
    if (x2 > c->xmax)
299
1
  x2 = c->xmax;
300
2.61k
    if (x2 <= x1)
301
52
  return;
302
303
2.56k
    n = c->num_spans++;
304
2.56k
    c->spans[n].x = x1;
305
2.56k
    c->spans[n].coverage = 255;
306
307
2.56k
    n = c->num_spans++;
308
2.56k
    c->spans[n].x = x2;
309
2.56k
    c->spans[n].coverage = 0;
310
2.56k
}
311
312
inline static void
313
row (struct mono_scan_converter *c, unsigned int mask)
314
2.61k
{
315
2.61k
    struct edge *edge = c->head.next;
316
2.61k
    int xstart = INT_MIN, prev_x = INT_MIN;
317
2.61k
    int winding = 0;
318
319
2.61k
    c->num_spans = 0;
320
26.1k
    while (&c->tail != edge) {
321
23.5k
  struct edge *next = edge->next;
322
23.5k
  int xend = I(edge->x.quo);
323
324
23.5k
  if (--edge->height_left) {
325
0
      if (!edge->vertical) {
326
0
    edge->x.quo += edge->dxdy.quo;
327
0
    edge->x.rem += edge->dxdy.rem;
328
0
    if (edge->x.rem >= 0) {
329
0
        ++edge->x.quo;
330
0
        edge->x.rem -= edge->dy;
331
0
    }
332
0
      }
333
334
0
      if (edge->x.quo < prev_x) {
335
0
    struct edge *pos = edge->prev;
336
0
    pos->next = next;
337
0
    next->prev = pos;
338
0
    do {
339
0
        pos = pos->prev;
340
0
    } while (edge->x.quo < pos->x.quo);
341
0
    pos->next->prev = edge;
342
0
    edge->next = pos->next;
343
0
    edge->prev = pos;
344
0
    pos->next = edge;
345
0
      } else
346
0
    prev_x = edge->x.quo;
347
23.5k
  } else {
348
23.5k
      edge->prev->next = next;
349
23.5k
      next->prev = edge->prev;
350
23.5k
  }
351
352
23.5k
  winding += edge->dir;
353
23.5k
  if ((winding & mask) == 0) {
354
4.95k
      if (I(next->x.quo) > xend + 1) {
355
2.61k
    add_span (c, xstart, xend);
356
2.61k
    xstart = INT_MIN;
357
2.61k
      }
358
18.5k
  } else if (xstart == INT_MIN)
359
2.61k
      xstart = xend;
360
361
23.5k
  edge = next;
362
23.5k
    }
363
2.61k
}
364
365
static cairo_status_t
366
_mono_scan_converter_init(struct mono_scan_converter *c,
367
        int xmin, int ymin,
368
        int xmax, int ymax)
369
2.61k
{
370
2.61k
    cairo_status_t status;
371
2.61k
    int max_num_spans;
372
373
2.61k
    status = polygon_init (c->polygon, ymin, ymax);
374
2.61k
    if  (unlikely (status))
375
0
  return status;
376
377
2.61k
    max_num_spans = xmax - xmin + 1;
378
2.61k
    if (max_num_spans > ARRAY_LENGTH(c->spans_embedded)) {
379
0
  c->spans = _cairo_malloc_ab (max_num_spans,
380
0
             sizeof (cairo_half_open_span_t));
381
0
  if (unlikely (c->spans == NULL)) {
382
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
383
0
  }
384
0
    } else
385
2.61k
  c->spans = c->spans_embedded;
386
387
2.61k
    c->xmin = xmin;
388
2.61k
    c->xmax = xmax;
389
2.61k
    c->ymin = ymin;
390
2.61k
    c->ymax = ymax;
391
392
2.61k
    c->head.vertical = 1;
393
2.61k
    c->head.height_left = INT_MAX;
394
2.61k
    c->head.x.quo = _cairo_fixed_from_int (_cairo_fixed_integer_part (INT_MIN));
395
2.61k
    c->head.prev = NULL;
396
2.61k
    c->head.next = &c->tail;
397
2.61k
    c->tail.prev = &c->head;
398
2.61k
    c->tail.next = NULL;
399
2.61k
    c->tail.x.quo = _cairo_fixed_from_int (_cairo_fixed_integer_part (INT_MAX));
400
2.61k
    c->tail.height_left = INT_MAX;
401
2.61k
    c->tail.vertical = 1;
402
403
2.61k
    c->is_vertical = 1;
404
2.61k
    return CAIRO_STATUS_SUCCESS;
405
2.61k
}
406
407
static void
408
_mono_scan_converter_fini(struct mono_scan_converter *self)
409
2.61k
{
410
2.61k
    if (self->spans != self->spans_embedded)
411
0
  free (self->spans);
412
413
2.61k
    polygon_fini(self->polygon);
414
2.61k
}
415
416
static cairo_status_t
417
mono_scan_converter_allocate_edges(struct mono_scan_converter *c,
418
           int num_edges)
419
420
2.61k
{
421
2.61k
    c->polygon->num_edges = 0;
422
2.61k
    c->polygon->edges = c->polygon->edges_embedded;
423
2.61k
    if (num_edges > ARRAY_LENGTH (c->polygon->edges_embedded)) {
424
41
  c->polygon->edges = _cairo_malloc_ab (num_edges, sizeof (struct edge));
425
41
  if (unlikely (c->polygon->edges == NULL))
426
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
427
41
    }
428
429
2.61k
    return CAIRO_STATUS_SUCCESS;
430
2.61k
}
431
432
static void
433
mono_scan_converter_add_edge (struct mono_scan_converter *c,
434
            const cairo_edge_t *edge)
435
28.0k
{
436
28.0k
    polygon_add_edge (c->polygon, edge);
437
28.0k
}
438
439
static void
440
step_edges (struct mono_scan_converter *c, int count)
441
0
{
442
0
    struct edge *edge;
443
444
0
    for (edge = c->head.next; edge != &c->tail; edge = edge->next) {
445
0
  edge->height_left -= count;
446
0
  if (! edge->height_left) {
447
0
      edge->prev->next = edge->next;
448
0
      edge->next->prev = edge->prev;
449
0
  }
450
0
    }
451
0
}
452
453
static cairo_status_t
454
mono_scan_converter_render(struct mono_scan_converter *c,
455
         unsigned int winding_mask,
456
         cairo_span_renderer_t *renderer)
457
2.61k
{
458
2.61k
    struct polygon *polygon = c->polygon;
459
2.61k
    int i, j, h = c->ymax - c->ymin;
460
2.61k
    cairo_status_t status;
461
462
5.23k
    for (i = 0; i < h; i = j) {
463
2.61k
  j = i + 1;
464
465
2.61k
  if (polygon->y_buckets[i])
466
2.61k
      active_list_merge_edges (c, polygon->y_buckets[i]);
467
468
2.61k
  if (c->is_vertical) {
469
2.19k
      int min_height;
470
2.19k
      struct edge *e;
471
472
2.19k
      e = c->head.next;
473
2.19k
      min_height = e->height_left;
474
15.0k
      while (e != &c->tail) {
475
12.8k
    if (e->height_left < min_height)
476
0
        min_height = e->height_left;
477
12.8k
    e = e->next;
478
12.8k
      }
479
480
2.19k
      while (--min_height >= 1 && polygon->y_buckets[j] == NULL)
481
0
    j++;
482
2.19k
      if (j != i + 1)
483
0
    step_edges (c, j - (i + 1));
484
2.19k
  }
485
486
2.61k
  row (c, winding_mask);
487
2.61k
  if (c->num_spans) {
488
2.56k
      status = renderer->render_rows (renderer, c->ymin+i, j-i,
489
2.56k
              c->spans, c->num_spans);
490
2.56k
      if (unlikely (status))
491
0
    return status;
492
2.56k
  }
493
494
  /* XXX recompute after dropping edges? */
495
2.61k
  if (c->head.next == &c->tail)
496
2.61k
      c->is_vertical = 1;
497
2.61k
    }
498
499
2.61k
    return CAIRO_STATUS_SUCCESS;
500
2.61k
}
501
502
struct _cairo_mono_scan_converter {
503
    cairo_scan_converter_t base;
504
505
    struct mono_scan_converter converter[1];
506
    cairo_fill_rule_t fill_rule;
507
};
508
509
typedef struct _cairo_mono_scan_converter cairo_mono_scan_converter_t;
510
511
static void
512
_cairo_mono_scan_converter_destroy (void *converter)
513
2.61k
{
514
2.61k
    cairo_mono_scan_converter_t *self = converter;
515
2.61k
    _mono_scan_converter_fini (self->converter);
516
2.61k
    free(self);
517
2.61k
}
518
519
cairo_status_t
520
_cairo_mono_scan_converter_add_polygon (void    *converter,
521
               const cairo_polygon_t *polygon)
522
2.61k
{
523
2.61k
    cairo_mono_scan_converter_t *self = converter;
524
2.61k
    cairo_status_t status;
525
2.61k
    int i;
526
527
#if 0
528
    FILE *file = fopen ("polygon.txt", "w");
529
    _cairo_debug_print_polygon (file, polygon);
530
    fclose (file);
531
#endif
532
533
2.61k
    status = mono_scan_converter_allocate_edges (self->converter,
534
2.61k
             polygon->num_edges);
535
2.61k
    if (unlikely (status))
536
0
  return status;
537
538
30.6k
    for (i = 0; i < polygon->num_edges; i++)
539
28.0k
   mono_scan_converter_add_edge (self->converter, &polygon->edges[i]);
540
541
2.61k
    return CAIRO_STATUS_SUCCESS;
542
2.61k
}
543
544
static cairo_status_t
545
_cairo_mono_scan_converter_generate (void     *converter,
546
            cairo_span_renderer_t *renderer)
547
2.61k
{
548
2.61k
    cairo_mono_scan_converter_t *self = converter;
549
550
2.61k
    return mono_scan_converter_render (self->converter,
551
2.61k
               self->fill_rule == CAIRO_FILL_RULE_WINDING ? ~0 : 1,
552
2.61k
               renderer);
553
2.61k
}
554
555
cairo_scan_converter_t *
556
_cairo_mono_scan_converter_create (int      xmin,
557
          int     ymin,
558
          int     xmax,
559
          int     ymax,
560
          cairo_fill_rule_t fill_rule)
561
2.61k
{
562
2.61k
    cairo_mono_scan_converter_t *self;
563
2.61k
    cairo_status_t status;
564
565
2.61k
    self = _cairo_calloc (sizeof(struct _cairo_mono_scan_converter));
566
2.61k
    if (unlikely (self == NULL)) {
567
0
  status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
568
0
  goto bail_nomem;
569
0
    }
570
571
2.61k
    self->base.destroy = _cairo_mono_scan_converter_destroy;
572
2.61k
    self->base.generate = _cairo_mono_scan_converter_generate;
573
574
2.61k
    status = _mono_scan_converter_init (self->converter,
575
2.61k
          xmin, ymin, xmax, ymax);
576
2.61k
    if (unlikely (status))
577
0
  goto bail;
578
579
2.61k
    self->fill_rule = fill_rule;
580
581
2.61k
    return &self->base;
582
583
0
 bail:
584
0
    self->base.destroy(&self->base);
585
0
 bail_nomem:
586
0
    return _cairo_scan_converter_create_in_error (status);
587
0
}