Coverage Report

Created: 2025-07-07 10:01

/work/workdir/UnpackedTarball/cairo/src/cairo-traps.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 © 2002 Keith Packard
4
 * Copyright © 2007 Red Hat, Inc.
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it either under the terms of the GNU Lesser General Public
8
 * License version 2.1 as published by the Free Software Foundation
9
 * (the "LGPL") or, at your option, under the terms of the Mozilla
10
 * Public License Version 1.1 (the "MPL"). If you do not alter this
11
 * notice, a recipient may use your version of this file under either
12
 * the MPL or the LGPL.
13
 *
14
 * You should have received a copy of the LGPL along with this library
15
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17
 * You should have received a copy of the MPL along with this library
18
 * in the file COPYING-MPL-1.1
19
 *
20
 * The contents of this file are subject to the Mozilla Public License
21
 * Version 1.1 (the "License"); you may not use this file except in
22
 * compliance with the License. You may obtain a copy of the License at
23
 * http://www.mozilla.org/MPL/
24
 *
25
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27
 * the specific language governing rights and limitations.
28
 *
29
 * The Original Code is the cairo graphics library.
30
 *
31
 * The Initial Developer of the Original Code is Keith Packard
32
 *
33
 * Contributor(s):
34
 *  Keith R. Packard <keithp@keithp.com>
35
 *  Carl D. Worth <cworth@cworth.org>
36
 *
37
 * 2002-07-15: Converted from XRenderCompositeDoublePoly to #cairo_trap_t. Carl D. Worth
38
 */
39
40
#include "cairoint.h"
41
42
#include "cairo-box-inline.h"
43
#include "cairo-boxes-private.h"
44
#include "cairo-error-private.h"
45
#include "cairo-line-private.h"
46
#include "cairo-region-private.h"
47
#include "cairo-slope-private.h"
48
#include "cairo-traps-private.h"
49
#include "cairo-spans-private.h"
50
51
/* private functions */
52
53
void
54
_cairo_traps_init (cairo_traps_t *traps)
55
0
{
56
0
    VG (VALGRIND_MAKE_MEM_UNDEFINED (traps, sizeof (cairo_traps_t)));
57
58
0
    traps->status = CAIRO_STATUS_SUCCESS;
59
60
0
    traps->maybe_region = 1;
61
0
    traps->is_rectilinear = 0;
62
0
    traps->is_rectangular = 0;
63
64
0
    traps->num_traps = 0;
65
66
0
    traps->traps_size = ARRAY_LENGTH (traps->traps_embedded);
67
0
    traps->traps = traps->traps_embedded;
68
69
0
    traps->num_limits = 0;
70
0
    traps->has_intersections = FALSE;
71
0
}
72
73
void
74
_cairo_traps_limit (cairo_traps_t *traps,
75
        const cairo_box_t *limits,
76
        int      num_limits)
77
0
{
78
0
    int i;
79
80
0
    traps->limits = limits;
81
0
    traps->num_limits = num_limits;
82
83
0
    traps->bounds = limits[0];
84
0
    for (i = 1; i < num_limits; i++)
85
0
  _cairo_box_add_box (&traps->bounds, &limits[i]);
86
0
}
87
88
void
89
_cairo_traps_init_with_clip (cairo_traps_t *traps,
90
           const cairo_clip_t *clip)
91
0
{
92
0
    _cairo_traps_init (traps);
93
0
    if (clip)
94
0
  _cairo_traps_limit (traps, clip->boxes, clip->num_boxes);
95
0
}
96
97
void
98
_cairo_traps_clear (cairo_traps_t *traps)
99
0
{
100
0
    traps->status = CAIRO_STATUS_SUCCESS;
101
102
0
    traps->maybe_region = 1;
103
0
    traps->is_rectilinear = 0;
104
0
    traps->is_rectangular = 0;
105
106
0
    traps->num_traps = 0;
107
0
    traps->has_intersections = FALSE;
108
0
}
109
110
void
111
_cairo_traps_fini (cairo_traps_t *traps)
112
0
{
113
0
    if (traps->traps != traps->traps_embedded)
114
0
  free (traps->traps);
115
116
0
    VG (VALGRIND_MAKE_MEM_UNDEFINED (traps, sizeof (cairo_traps_t)));
117
0
}
118
119
/* make room for at least one more trap */
120
static cairo_bool_t
121
_cairo_traps_grow (cairo_traps_t *traps)
122
0
{
123
0
    cairo_trapezoid_t *new_traps;
124
0
    int new_size = 4 * traps->traps_size;
125
126
0
    if (CAIRO_INJECT_FAULT ()) {
127
0
  traps->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
128
0
  return FALSE;
129
0
    }
130
131
0
    if (traps->traps == traps->traps_embedded) {
132
0
  new_traps = _cairo_malloc_ab (new_size, sizeof (cairo_trapezoid_t));
133
0
  if (new_traps != NULL)
134
0
      memcpy (new_traps, traps->traps, sizeof (traps->traps_embedded));
135
0
    } else {
136
0
  new_traps = _cairo_realloc_ab (traps->traps,
137
0
                                 new_size, sizeof (cairo_trapezoid_t));
138
0
    }
139
140
0
    if (unlikely (new_traps == NULL)) {
141
0
  traps->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
142
0
  return FALSE;
143
0
    }
144
145
0
    traps->traps = new_traps;
146
0
    traps->traps_size = new_size;
147
0
    return TRUE;
148
0
}
149
150
void
151
_cairo_traps_add_trap (cairo_traps_t *traps,
152
           cairo_fixed_t top, cairo_fixed_t bottom,
153
           const cairo_line_t *left,
154
           const cairo_line_t *right)
155
0
{
156
0
    cairo_trapezoid_t *trap;
157
158
0
    assert (left->p1.y != left->p2.y);
159
0
    assert (right->p1.y != right->p2.y);
160
0
    assert (bottom > top);
161
162
0
    if (unlikely (traps->num_traps == traps->traps_size)) {
163
0
  if (unlikely (! _cairo_traps_grow (traps)))
164
0
      return;
165
0
    }
166
167
0
    trap = &traps->traps[traps->num_traps++];
168
0
    trap->top = top;
169
0
    trap->bottom = bottom;
170
0
    trap->left = *left;
171
0
    trap->right = *right;
172
0
}
173
174
static void
175
_cairo_traps_add_clipped_trap (cairo_traps_t *traps,
176
             cairo_fixed_t _top, cairo_fixed_t _bottom,
177
             const cairo_line_t *_left,
178
             const cairo_line_t *_right)
179
0
{
180
    /* Note: With the goofy trapezoid specification, (where an
181
     * arbitrary two points on the lines can specified for the left
182
     * and right edges), these limit checks would not work in
183
     * general. For example, one can imagine a trapezoid entirely
184
     * within the limits, but with two points used to specify the left
185
     * edge entirely to the right of the limits.  Fortunately, for our
186
     * purposes, cairo will never generate such a crazy
187
     * trapezoid. Instead, cairo always uses for its points the
188
     * extreme positions of the edge that are visible on at least some
189
     * trapezoid. With this constraint, it's impossible for both
190
     * points to be outside the limits while the relevant edge is
191
     * entirely inside the limits.
192
     */
193
0
    if (traps->num_limits) {
194
0
  const cairo_box_t *b = &traps->bounds;
195
0
  cairo_fixed_t top = _top, bottom = _bottom;
196
0
  cairo_line_t left = *_left, right = *_right;
197
198
  /* Trivially reject if trapezoid is entirely to the right or
199
   * to the left of the limits. */
200
0
  if (left.p1.x >= b->p2.x && left.p2.x >= b->p2.x)
201
0
      return;
202
203
0
  if (right.p1.x <= b->p1.x && right.p2.x <= b->p1.x)
204
0
      return;
205
206
  /* And reject if the trapezoid is entirely above or below */
207
0
  if (top >= b->p2.y || bottom <= b->p1.y)
208
0
      return;
209
210
  /* Otherwise, clip the trapezoid to the limits. We only clip
211
   * where an edge is entirely outside the limits. If we wanted
212
   * to be more clever, we could handle cases where a trapezoid
213
   * edge intersects the edge of the limits, but that would
214
   * require slicing this trapezoid into multiple trapezoids,
215
   * and I'm not sure the effort would be worth it. */
216
0
  if (top < b->p1.y)
217
0
      top = b->p1.y;
218
219
0
  if (bottom > b->p2.y)
220
0
      bottom = b->p2.y;
221
222
0
  if (left.p1.x <= b->p1.x && left.p2.x <= b->p1.x)
223
0
      left.p1.x = left.p2.x = b->p1.x;
224
225
0
  if (right.p1.x >= b->p2.x && right.p2.x >= b->p2.x)
226
0
      right.p1.x = right.p2.x = b->p2.x;
227
228
  /* Trivial discards for empty trapezoids that are likely to
229
   * be produced by our tessellators (most notably convex_quad
230
   * when given a simple rectangle).
231
   */
232
0
  if (top >= bottom)
233
0
      return;
234
235
  /* cheap colinearity check */
236
0
  if (right.p1.x <= left.p1.x && right.p1.y == left.p1.y &&
237
0
      right.p2.x <= left.p2.x && right.p2.y == left.p2.y)
238
0
      return;
239
240
0
  _cairo_traps_add_trap (traps, top, bottom, &left, &right);
241
0
    } else
242
0
  _cairo_traps_add_trap (traps, _top, _bottom, _left, _right);
243
0
}
244
245
static int
246
_compare_point_fixed_by_y (const void *av, const void *bv)
247
0
{
248
0
    const cairo_point_t *a = av, *b = bv;
249
0
    int ret = a->y - b->y;
250
0
    if (ret == 0)
251
0
  ret = a->x - b->x;
252
0
    return ret;
253
0
}
254
255
void
256
_cairo_traps_tessellate_convex_quad (cairo_traps_t *traps,
257
             const cairo_point_t q[4])
258
0
{
259
0
    int a, b, c, d;
260
0
    int i;
261
0
    cairo_slope_t ab, ad;
262
0
    cairo_bool_t b_left_of_d;
263
0
    cairo_line_t left;
264
0
    cairo_line_t right;
265
266
    /* Choose a as a point with minimal y */
267
0
    a = 0;
268
0
    for (i = 1; i < 4; i++)
269
0
  if (_compare_point_fixed_by_y (&q[i], &q[a]) < 0)
270
0
      a = i;
271
272
    /* b and d are adjacent to a, while c is opposite */
273
0
    b = (a + 1) % 4;
274
0
    c = (a + 2) % 4;
275
0
    d = (a + 3) % 4;
276
277
    /* Choose between b and d so that b.y is less than d.y */
278
0
    if (_compare_point_fixed_by_y (&q[d], &q[b]) < 0) {
279
0
  b = (a + 3) % 4;
280
0
  d = (a + 1) % 4;
281
0
    }
282
283
    /* Without freedom left to choose anything else, we have four
284
     * cases to tessellate.
285
     *
286
     * First, we have to determine the Y-axis sort of the four
287
     * vertices, (either abcd or abdc). After that we need to determine
288
     * which edges will be "left" and which will be "right" in the
289
     * resulting trapezoids. This can be determined by computing a
290
     * slope comparison of ab and ad to determine if b is left of d or
291
     * not.
292
     *
293
     * Note that "left of" here is in the sense of which edges should
294
     * be the left vs. right edges of the trapezoid. In particular, b
295
     * left of d does *not* mean that b.x is less than d.x.
296
     *
297
     * This should hopefully be made clear in the lame ASCII art
298
     * below. Since the same slope comparison is used in all cases, we
299
     * compute it before testing for the Y-value sort. */
300
301
    /* Note: If a == b then the ab slope doesn't give us any
302
     * information. In that case, we can replace it with the ac (or
303
     * equivalenly the bc) slope which gives us exactly the same
304
     * information we need. At worst the names of the identifiers ab
305
     * and b_left_of_d are inaccurate in this case, (would be ac, and
306
     * c_left_of_d). */
307
0
    if (q[a].x == q[b].x && q[a].y == q[b].y)
308
0
  _cairo_slope_init (&ab, &q[a], &q[c]);
309
0
    else
310
0
  _cairo_slope_init (&ab, &q[a], &q[b]);
311
312
0
    _cairo_slope_init (&ad, &q[a], &q[d]);
313
314
0
    b_left_of_d = _cairo_slope_compare (&ab, &ad) > 0;
315
316
0
    if (q[c].y <= q[d].y) {
317
0
  if (b_left_of_d) {
318
      /* Y-sort is abcd and b is left of d, (slope(ab) > slope (ad))
319
       *
320
       *                      top bot left right
321
       *        _a  a  a
322
       *      / /  /|  |\      a.y b.y  ab   ad
323
       *     b /  b |  b \
324
       *    / /   | |   \ \    b.y c.y  bc   ad
325
       *   c /    c |    c \
326
       *  | /      \|     \ \  c.y d.y  cd   ad
327
       *  d         d       d
328
       */
329
0
      left.p1  = q[a]; left.p2  = q[b];
330
0
      right.p1 = q[a]; right.p2 = q[d];
331
0
      _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
332
0
      left.p1  = q[b]; left.p2  = q[c];
333
0
      _cairo_traps_add_clipped_trap (traps, q[b].y, q[c].y, &left, &right);
334
0
      left.p1  = q[c]; left.p2  = q[d];
335
0
      _cairo_traps_add_clipped_trap (traps, q[c].y, q[d].y, &left, &right);
336
0
  } else {
337
      /* Y-sort is abcd and b is right of d, (slope(ab) <= slope (ad))
338
       *
339
       *       a  a  a_
340
       *      /|  |\  \ \     a.y b.y  ad  ab
341
       *     / b  | b  \ b
342
       *    / /   | |   \ \   b.y c.y  ad  bc
343
       *   / c    | c    \ c
344
       *  / /     |/      \ | c.y d.y  ad  cd
345
       *  d       d         d
346
       */
347
0
      left.p1  = q[a]; left.p2  = q[d];
348
0
      right.p1 = q[a]; right.p2 = q[b];
349
0
      _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
350
0
      right.p1 = q[b]; right.p2 = q[c];
351
0
      _cairo_traps_add_clipped_trap (traps, q[b].y, q[c].y, &left, &right);
352
0
      right.p1 = q[c]; right.p2 = q[d];
353
0
      _cairo_traps_add_clipped_trap (traps, q[c].y, q[d].y, &left, &right);
354
0
  }
355
0
    } else {
356
0
  if (b_left_of_d) {
357
      /* Y-sort is abdc and b is left of d, (slope (ab) > slope (ad))
358
       *
359
       *        a   a     a
360
       *       //  / \    |\     a.y b.y  ab  ad
361
       *     /b/  b   \   b \
362
       *    / /    \   \   \ \   b.y d.y  bc  ad
363
       *   /d/      \   d   \ d
364
       *  //         \ /     \|  d.y c.y  bc  dc
365
       *  c           c       c
366
       */
367
0
      left.p1  = q[a]; left.p2  = q[b];
368
0
      right.p1 = q[a]; right.p2 = q[d];
369
0
      _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
370
0
      left.p1  = q[b]; left.p2  = q[c];
371
0
      _cairo_traps_add_clipped_trap (traps, q[b].y, q[d].y, &left, &right);
372
0
      right.p1 = q[d]; right.p2 = q[c];
373
0
      _cairo_traps_add_clipped_trap (traps, q[d].y, q[c].y, &left, &right);
374
0
  } else {
375
      /* Y-sort is abdc and b is right of d, (slope (ab) <= slope (ad))
376
       *
377
       *      a     a   a
378
       *     /|    / \  \\       a.y b.y  ad  ab
379
       *    / b   /   b  \b\
380
       *   / /   /   /    \ \    b.y d.y  ad  bc
381
       *  d /   d   /  \d\
382
       *  |/     \ /         \\  d.y c.y  dc  bc
383
       *  c       c    c
384
       */
385
0
      left.p1  = q[a]; left.p2  = q[d];
386
0
      right.p1 = q[a]; right.p2 = q[b];
387
0
      _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
388
0
      right.p1 = q[b]; right.p2 = q[c];
389
0
      _cairo_traps_add_clipped_trap (traps, q[b].y, q[d].y, &left, &right);
390
0
      left.p1  = q[d]; left.p2  = q[c];
391
0
      _cairo_traps_add_clipped_trap (traps, q[d].y, q[c].y, &left, &right);
392
0
  }
393
0
    }
394
0
}
395
396
static void add_tri (cairo_traps_t *traps,
397
         int y1, int y2,
398
         const cairo_line_t *left,
399
         const cairo_line_t *right)
400
0
{
401
0
    if (y2 < y1) {
402
0
  int tmp = y1;
403
0
  y1 = y2;
404
0
  y2 = tmp;
405
0
    }
406
407
0
    if (_cairo_lines_compare_at_y (left, right, y1) > 0) {
408
0
  const cairo_line_t *tmp = left;
409
0
  left = right;
410
0
  right = tmp;
411
0
    }
412
413
0
    _cairo_traps_add_clipped_trap (traps, y1, y2, left, right);
414
0
}
415
416
void
417
_cairo_traps_tessellate_triangle_with_edges (cairo_traps_t *traps,
418
               const cairo_point_t t[3],
419
               const cairo_point_t edges[4])
420
0
{
421
0
    cairo_line_t lines[3];
422
423
0
    if (edges[0].y <= edges[1].y) {
424
0
      lines[0].p1 = edges[0];
425
0
      lines[0].p2 = edges[1];
426
0
    } else {
427
0
      lines[0].p1 = edges[1];
428
0
      lines[0].p2 = edges[0];
429
0
    }
430
431
0
    if (edges[2].y <= edges[3].y) {
432
0
      lines[1].p1 = edges[2];
433
0
      lines[1].p2 = edges[3];
434
0
    } else {
435
0
      lines[1].p1 = edges[3];
436
0
      lines[1].p2 = edges[2];
437
0
    }
438
439
0
    if (t[1].y == t[2].y) {
440
0
  add_tri (traps, t[0].y, t[1].y, &lines[0], &lines[1]);
441
0
  return;
442
0
    }
443
444
0
    if (t[1].y <= t[2].y) {
445
0
      lines[2].p1 = t[1];
446
0
      lines[2].p2 = t[2];
447
0
    } else {
448
0
      lines[2].p1 = t[2];
449
0
      lines[2].p2 = t[1];
450
0
    }
451
452
0
    if (((t[1].y - t[0].y) < 0) ^ ((t[2].y - t[0].y) < 0)) {
453
0
  add_tri (traps, t[0].y, t[1].y, &lines[0], &lines[2]);
454
0
  add_tri (traps, t[0].y, t[2].y, &lines[1], &lines[2]);
455
0
    } else if (abs(t[1].y - t[0].y) < abs(t[2].y - t[0].y)) {
456
0
  add_tri (traps, t[0].y, t[1].y, &lines[0], &lines[1]);
457
0
  add_tri (traps, t[1].y, t[2].y, &lines[2], &lines[1]);
458
0
    } else {
459
0
  add_tri (traps, t[0].y, t[2].y, &lines[1], &lines[0]);
460
0
  add_tri (traps, t[1].y, t[2].y, &lines[2], &lines[0]);
461
0
    }
462
0
}
463
464
/**
465
 * _cairo_traps_init_boxes:
466
 * @traps: a #cairo_traps_t
467
 * @box: an array box that will each be converted to a single trapezoid
468
 *       to store in @traps.
469
 *
470
 * Initializes a #cairo_traps_t to contain an array of rectangular
471
 * trapezoids.
472
 **/
473
cairo_status_t
474
_cairo_traps_init_boxes (cairo_traps_t      *traps,
475
             const cairo_boxes_t *boxes)
476
0
{
477
0
    cairo_trapezoid_t *trap;
478
0
    const struct _cairo_boxes_chunk *chunk;
479
480
0
    _cairo_traps_init (traps);
481
482
0
    while (traps->traps_size < boxes->num_boxes) {
483
0
  if (unlikely (! _cairo_traps_grow (traps))) {
484
0
      _cairo_traps_fini (traps);
485
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
486
0
  }
487
0
    }
488
489
0
    traps->num_traps = boxes->num_boxes;
490
0
    traps->is_rectilinear = TRUE;
491
0
    traps->is_rectangular = TRUE;
492
0
    traps->maybe_region = boxes->is_pixel_aligned;
493
494
0
    trap = &traps->traps[0];
495
0
    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
496
0
  const cairo_box_t *box;
497
0
  int i;
498
499
0
  box = chunk->base;
500
0
  for (i = 0; i < chunk->count; i++) {
501
0
      trap->top    = box->p1.y;
502
0
      trap->bottom = box->p2.y;
503
504
0
      trap->left.p1   = box->p1;
505
0
      trap->left.p2.x = box->p1.x;
506
0
      trap->left.p2.y = box->p2.y;
507
508
0
      trap->right.p1.x = box->p2.x;
509
0
      trap->right.p1.y = box->p1.y;
510
0
      trap->right.p2   = box->p2;
511
512
0
      box++, trap++;
513
0
  }
514
0
    }
515
516
0
    return CAIRO_STATUS_SUCCESS;
517
0
}
518
519
cairo_status_t
520
_cairo_traps_tessellate_rectangle (cairo_traps_t *traps,
521
           const cairo_point_t *top_left,
522
           const cairo_point_t *bottom_right)
523
0
{
524
0
    cairo_line_t left;
525
0
    cairo_line_t right;
526
0
    cairo_fixed_t top, bottom;
527
528
0
    if (top_left->y == bottom_right->y)
529
0
  return CAIRO_STATUS_SUCCESS;
530
531
0
    if (top_left->x == bottom_right->x)
532
0
  return CAIRO_STATUS_SUCCESS;
533
534
0
     left.p1.x =  left.p2.x = top_left->x;
535
0
     left.p1.y = right.p1.y = top_left->y;
536
0
    right.p1.x = right.p2.x = bottom_right->x;
537
0
     left.p2.y = right.p2.y = bottom_right->y;
538
539
0
     top = top_left->y;
540
0
     bottom = bottom_right->y;
541
542
0
    if (traps->num_limits) {
543
0
  cairo_bool_t reversed;
544
0
  int n;
545
546
0
  if (top >= traps->bounds.p2.y || bottom <= traps->bounds.p1.y)
547
0
      return CAIRO_STATUS_SUCCESS;
548
549
  /* support counter-clockwise winding for rectangular tessellation */
550
0
  reversed = top_left->x > bottom_right->x;
551
0
  if (reversed) {
552
0
      right.p1.x = right.p2.x = top_left->x;
553
0
      left.p1.x = left.p2.x = bottom_right->x;
554
0
  }
555
556
0
  if (left.p1.x >= traps->bounds.p2.x || right.p1.x <= traps->bounds.p1.x)
557
0
      return CAIRO_STATUS_SUCCESS;
558
559
0
  for (n = 0; n < traps->num_limits; n++) {
560
0
      const cairo_box_t *limits = &traps->limits[n];
561
0
      cairo_line_t _left, _right;
562
0
      cairo_fixed_t _top, _bottom;
563
564
0
      if (top >= limits->p2.y)
565
0
    continue;
566
0
      if (bottom <= limits->p1.y)
567
0
    continue;
568
569
      /* Trivially reject if trapezoid is entirely to the right or
570
       * to the left of the limits. */
571
0
      if (left.p1.x >= limits->p2.x)
572
0
    continue;
573
0
      if (right.p1.x <= limits->p1.x)
574
0
    continue;
575
576
      /* Otherwise, clip the trapezoid to the limits. */
577
0
      _top = top;
578
0
      if (_top < limits->p1.y)
579
0
    _top = limits->p1.y;
580
581
0
      _bottom = bottom;
582
0
      if (_bottom > limits->p2.y)
583
0
    _bottom = limits->p2.y;
584
585
0
      if (_bottom <= _top)
586
0
    continue;
587
588
0
      _left = left;
589
0
      if (_left.p1.x < limits->p1.x) {
590
0
    _left.p1.x = limits->p1.x;
591
0
    _left.p1.y = limits->p1.y;
592
0
    _left.p2.x = limits->p1.x;
593
0
    _left.p2.y = limits->p2.y;
594
0
      }
595
596
0
      _right = right;
597
0
      if (_right.p1.x > limits->p2.x) {
598
0
    _right.p1.x = limits->p2.x;
599
0
    _right.p1.y = limits->p1.y;
600
0
    _right.p2.x = limits->p2.x;
601
0
    _right.p2.y = limits->p2.y;
602
0
      }
603
604
0
      if (left.p1.x >= right.p1.x)
605
0
    continue;
606
607
0
      if (reversed)
608
0
    _cairo_traps_add_trap (traps, _top, _bottom, &_right, &_left);
609
0
      else
610
0
    _cairo_traps_add_trap (traps, _top, _bottom, &_left, &_right);
611
0
  }
612
0
    } else {
613
0
  _cairo_traps_add_trap (traps, top, bottom, &left, &right);
614
0
    }
615
616
0
    return traps->status;
617
0
}
618
619
void
620
_cairo_traps_translate (cairo_traps_t *traps, int x, int y)
621
0
{
622
0
    cairo_fixed_t xoff, yoff;
623
0
    cairo_trapezoid_t *t;
624
0
    int i;
625
626
    /* Ugh. The cairo_composite/(Render) interface doesn't allow
627
       an offset for the trapezoids. Need to manually shift all
628
       the coordinates to align with the offset origin of the
629
       intermediate surface. */
630
631
0
    xoff = _cairo_fixed_from_int (x);
632
0
    yoff = _cairo_fixed_from_int (y);
633
634
0
    for (i = 0, t = traps->traps; i < traps->num_traps; i++, t++) {
635
0
  t->top += yoff;
636
0
  t->bottom += yoff;
637
0
  t->left.p1.x += xoff;
638
0
  t->left.p1.y += yoff;
639
0
  t->left.p2.x += xoff;
640
0
  t->left.p2.y += yoff;
641
0
  t->right.p1.x += xoff;
642
0
  t->right.p1.y += yoff;
643
0
  t->right.p2.x += xoff;
644
0
  t->right.p2.y += yoff;
645
0
    }
646
0
}
647
648
void
649
_cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps,
650
                                            cairo_trapezoid_t *src_traps,
651
                                            int num_traps,
652
                                            double tx, double ty,
653
                                            double sx, double sy)
654
0
{
655
0
    int i;
656
0
    cairo_fixed_t xoff = _cairo_fixed_from_double (tx);
657
0
    cairo_fixed_t yoff = _cairo_fixed_from_double (ty);
658
659
0
    if (sx == 1.0 && sy == 1.0) {
660
0
        for (i = 0; i < num_traps; i++) {
661
0
            offset_traps[i].top = src_traps[i].top + yoff;
662
0
            offset_traps[i].bottom = src_traps[i].bottom + yoff;
663
0
            offset_traps[i].left.p1.x = src_traps[i].left.p1.x + xoff;
664
0
            offset_traps[i].left.p1.y = src_traps[i].left.p1.y + yoff;
665
0
            offset_traps[i].left.p2.x = src_traps[i].left.p2.x + xoff;
666
0
            offset_traps[i].left.p2.y = src_traps[i].left.p2.y + yoff;
667
0
            offset_traps[i].right.p1.x = src_traps[i].right.p1.x + xoff;
668
0
            offset_traps[i].right.p1.y = src_traps[i].right.p1.y + yoff;
669
0
            offset_traps[i].right.p2.x = src_traps[i].right.p2.x + xoff;
670
0
            offset_traps[i].right.p2.y = src_traps[i].right.p2.y + yoff;
671
0
        }
672
0
    } else {
673
0
        cairo_fixed_t xsc = _cairo_fixed_from_double (sx);
674
0
        cairo_fixed_t ysc = _cairo_fixed_from_double (sy);
675
676
0
        for (i = 0; i < num_traps; i++) {
677
0
            offset_traps[i].top = _cairo_fixed_mul (src_traps[i].top + yoff, ysc);
678
0
            offset_traps[i].bottom = _cairo_fixed_mul (src_traps[i].bottom + yoff, ysc);
679
0
            offset_traps[i].left.p1.x = _cairo_fixed_mul (src_traps[i].left.p1.x + xoff, xsc);
680
0
            offset_traps[i].left.p1.y = _cairo_fixed_mul (src_traps[i].left.p1.y + yoff, ysc);
681
0
            offset_traps[i].left.p2.x = _cairo_fixed_mul (src_traps[i].left.p2.x + xoff, xsc);
682
0
            offset_traps[i].left.p2.y = _cairo_fixed_mul (src_traps[i].left.p2.y + yoff, ysc);
683
0
            offset_traps[i].right.p1.x = _cairo_fixed_mul (src_traps[i].right.p1.x + xoff, xsc);
684
0
            offset_traps[i].right.p1.y = _cairo_fixed_mul (src_traps[i].right.p1.y + yoff, ysc);
685
0
            offset_traps[i].right.p2.x = _cairo_fixed_mul (src_traps[i].right.p2.x + xoff, xsc);
686
0
            offset_traps[i].right.p2.y = _cairo_fixed_mul (src_traps[i].right.p2.y + yoff, ysc);
687
0
        }
688
0
    }
689
0
}
690
691
static cairo_bool_t
692
_cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt)
693
0
{
694
0
    cairo_slope_t slope_left, slope_pt, slope_right;
695
696
0
    if (t->top > pt->y)
697
0
  return FALSE;
698
0
    if (t->bottom < pt->y)
699
0
  return FALSE;
700
701
0
    _cairo_slope_init (&slope_left, &t->left.p1, &t->left.p2);
702
0
    _cairo_slope_init (&slope_pt, &t->left.p1, pt);
703
704
0
    if (_cairo_slope_compare (&slope_left, &slope_pt) < 0)
705
0
  return FALSE;
706
707
0
    _cairo_slope_init (&slope_right, &t->right.p1, &t->right.p2);
708
0
    _cairo_slope_init (&slope_pt, &t->right.p1, pt);
709
710
0
    if (_cairo_slope_compare (&slope_pt, &slope_right) < 0)
711
0
  return FALSE;
712
713
0
    return TRUE;
714
0
}
715
716
cairo_bool_t
717
_cairo_traps_contain (const cairo_traps_t *traps,
718
          double x, double y)
719
0
{
720
0
    int i;
721
0
    cairo_point_t point;
722
723
0
    point.x = _cairo_fixed_from_double (x);
724
0
    point.y = _cairo_fixed_from_double (y);
725
726
0
    for (i = 0; i < traps->num_traps; i++) {
727
0
  if (_cairo_trap_contains (&traps->traps[i], &point))
728
0
      return TRUE;
729
0
    }
730
731
0
    return FALSE;
732
0
}
733
734
static cairo_fixed_t
735
_line_compute_intersection_x_for_y (const cairo_line_t *line,
736
            cairo_fixed_t y)
737
0
{
738
0
    return _cairo_edge_compute_intersection_x_for_y (&line->p1, &line->p2, y);
739
0
}
740
741
void
742
_cairo_traps_extents (const cairo_traps_t *traps,
743
          cairo_box_t *extents)
744
0
{
745
0
    int i;
746
747
0
    if (traps->num_traps == 0) {
748
0
  extents->p1.x = extents->p1.y = 0;
749
0
  extents->p2.x = extents->p2.y = 0;
750
0
  return;
751
0
    }
752
753
0
    extents->p1.x = extents->p1.y = INT32_MAX;
754
0
    extents->p2.x = extents->p2.y = INT32_MIN;
755
756
0
    for (i = 0; i < traps->num_traps; i++) {
757
0
  const cairo_trapezoid_t *trap =  &traps->traps[i];
758
759
0
  if (trap->top < extents->p1.y)
760
0
      extents->p1.y = trap->top;
761
0
  if (trap->bottom > extents->p2.y)
762
0
      extents->p2.y = trap->bottom;
763
764
0
  if (trap->left.p1.x < extents->p1.x) {
765
0
      cairo_fixed_t x = trap->left.p1.x;
766
0
      if (trap->top != trap->left.p1.y) {
767
0
    x = _line_compute_intersection_x_for_y (&trap->left,
768
0
              trap->top);
769
0
    if (x < extents->p1.x)
770
0
        extents->p1.x = x;
771
0
      } else
772
0
    extents->p1.x = x;
773
0
  }
774
0
  if (trap->left.p2.x < extents->p1.x) {
775
0
      cairo_fixed_t x = trap->left.p2.x;
776
0
      if (trap->bottom != trap->left.p2.y) {
777
0
    x = _line_compute_intersection_x_for_y (&trap->left,
778
0
              trap->bottom);
779
0
    if (x < extents->p1.x)
780
0
        extents->p1.x = x;
781
0
      } else
782
0
    extents->p1.x = x;
783
0
  }
784
785
0
  if (trap->right.p1.x > extents->p2.x) {
786
0
      cairo_fixed_t x = trap->right.p1.x;
787
0
      if (trap->top != trap->right.p1.y) {
788
0
    x = _line_compute_intersection_x_for_y (&trap->right,
789
0
              trap->top);
790
0
    if (x > extents->p2.x)
791
0
        extents->p2.x = x;
792
0
      } else
793
0
    extents->p2.x = x;
794
0
  }
795
0
  if (trap->right.p2.x > extents->p2.x) {
796
0
      cairo_fixed_t x = trap->right.p2.x;
797
0
      if (trap->bottom != trap->right.p2.y) {
798
0
    x = _line_compute_intersection_x_for_y (&trap->right,
799
0
              trap->bottom);
800
0
    if (x > extents->p2.x)
801
0
        extents->p2.x = x;
802
0
      } else
803
0
    extents->p2.x = x;
804
0
  }
805
0
    }
806
0
}
807
808
static cairo_bool_t
809
_mono_edge_is_vertical (const cairo_line_t *line)
810
0
{
811
0
    return _cairo_fixed_integer_round_down (line->p1.x) == _cairo_fixed_integer_round_down (line->p2.x);
812
0
}
813
814
static cairo_bool_t
815
_traps_are_pixel_aligned (cairo_traps_t *traps,
816
        cairo_antialias_t antialias)
817
0
{
818
0
    int i;
819
820
0
    if (antialias == CAIRO_ANTIALIAS_NONE) {
821
0
  for (i = 0; i < traps->num_traps; i++) {
822
0
      if (! _mono_edge_is_vertical (&traps->traps[i].left)   ||
823
0
    ! _mono_edge_is_vertical (&traps->traps[i].right))
824
0
      {
825
0
    traps->maybe_region = FALSE;
826
0
    return FALSE;
827
0
      }
828
0
  }
829
0
    } else {
830
0
  for (i = 0; i < traps->num_traps; i++) {
831
0
      if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x   ||
832
0
    traps->traps[i].right.p1.x != traps->traps[i].right.p2.x ||
833
0
    ! _cairo_fixed_is_integer (traps->traps[i].top)          ||
834
0
    ! _cairo_fixed_is_integer (traps->traps[i].bottom)       ||
835
0
    ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x)    ||
836
0
    ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
837
0
      {
838
0
    traps->maybe_region = FALSE;
839
0
    return FALSE;
840
0
      }
841
0
  }
842
0
    }
843
844
0
    return TRUE;
845
0
}
846
847
/**
848
 * _cairo_traps_extract_region:
849
 * @traps: a #cairo_traps_t
850
 * @region: a #cairo_region_t
851
 *
852
 * Determines if a set of trapezoids are exactly representable as a
853
 * cairo region.  If so, the passed-in region is initialized to
854
 * the area representing the given traps.  It should be finalized
855
 * with cairo_region_fini().  If not, %CAIRO_INT_STATUS_UNSUPPORTED
856
 * is returned.
857
 *
858
 * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED
859
 * or %CAIRO_STATUS_NO_MEMORY
860
 **/
861
cairo_int_status_t
862
_cairo_traps_extract_region (cairo_traps_t   *traps,
863
           cairo_antialias_t antialias,
864
           cairo_region_t **region)
865
0
{
866
0
    cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
867
0
    cairo_rectangle_int_t *rects = stack_rects;
868
0
    cairo_int_status_t status;
869
0
    int i, rect_count;
870
871
    /* we only treat this a hint... */
872
0
    if (antialias != CAIRO_ANTIALIAS_NONE && ! traps->maybe_region)
873
0
  return CAIRO_INT_STATUS_UNSUPPORTED;
874
875
0
    if (! _traps_are_pixel_aligned (traps, antialias)) {
876
0
  traps->maybe_region = FALSE;
877
0
  return CAIRO_INT_STATUS_UNSUPPORTED;
878
0
    }
879
880
0
    if (traps->num_traps > ARRAY_LENGTH (stack_rects)) {
881
0
  rects = _cairo_malloc_ab (traps->num_traps, sizeof (cairo_rectangle_int_t));
882
883
0
  if (unlikely (rects == NULL))
884
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
885
0
    }
886
887
0
    rect_count = 0;
888
0
    for (i = 0; i < traps->num_traps; i++) {
889
0
  int x1, y1, x2, y2;
890
891
0
  if (antialias == CAIRO_ANTIALIAS_NONE) {
892
0
      x1 = _cairo_fixed_integer_round_down (traps->traps[i].left.p1.x);
893
0
      y1 = _cairo_fixed_integer_round_down (traps->traps[i].top);
894
0
      x2 = _cairo_fixed_integer_round_down (traps->traps[i].right.p1.x);
895
0
      y2 = _cairo_fixed_integer_round_down (traps->traps[i].bottom);
896
0
  } else {
897
0
      x1 = _cairo_fixed_integer_part (traps->traps[i].left.p1.x);
898
0
      y1 = _cairo_fixed_integer_part (traps->traps[i].top);
899
0
      x2 = _cairo_fixed_integer_part (traps->traps[i].right.p1.x);
900
0
      y2 = _cairo_fixed_integer_part (traps->traps[i].bottom);
901
0
  }
902
903
0
  if (x2 > x1 && y2 > y1) {
904
0
      rects[rect_count].x = x1;
905
0
      rects[rect_count].y = y1;
906
0
      rects[rect_count].width  = x2 - x1;
907
0
      rects[rect_count].height = y2 - y1;
908
0
      rect_count++;
909
0
  }
910
0
    }
911
912
913
0
    *region = cairo_region_create_rectangles (rects, rect_count);
914
0
    status = (*region)->status;
915
916
0
    if (rects != stack_rects)
917
0
  free (rects);
918
919
0
    return status;
920
0
}
921
922
cairo_bool_t
923
_cairo_traps_to_boxes (cairo_traps_t *traps,
924
           cairo_antialias_t antialias,
925
           cairo_boxes_t *boxes)
926
0
{
927
0
    int i;
928
929
0
    for (i = 0; i < traps->num_traps; i++) {
930
0
  if (traps->traps[i].left.p1.x  != traps->traps[i].left.p2.x ||
931
0
      traps->traps[i].right.p1.x != traps->traps[i].right.p2.x)
932
0
      return FALSE;
933
0
    }
934
935
0
    _cairo_boxes_init (boxes);
936
937
0
    boxes->num_boxes    = traps->num_traps;
938
0
    boxes->chunks.base  = (cairo_box_t *) traps->traps;
939
0
    boxes->chunks.count = traps->num_traps;
940
0
    boxes->chunks.size  = traps->num_traps;
941
942
0
    if (antialias != CAIRO_ANTIALIAS_NONE) {
943
0
  for (i = 0; i < traps->num_traps; i++) {
944
      /* Note the traps and boxes alias so we need to take the local copies first. */
945
0
      cairo_fixed_t x1 = traps->traps[i].left.p1.x;
946
0
      cairo_fixed_t x2 = traps->traps[i].right.p1.x;
947
0
      cairo_fixed_t y1 = traps->traps[i].top;
948
0
      cairo_fixed_t y2 = traps->traps[i].bottom;
949
950
0
      boxes->chunks.base[i].p1.x = x1;
951
0
      boxes->chunks.base[i].p1.y = y1;
952
0
      boxes->chunks.base[i].p2.x = x2;
953
0
      boxes->chunks.base[i].p2.y = y2;
954
955
0
      if (boxes->is_pixel_aligned) {
956
0
    boxes->is_pixel_aligned =
957
0
        _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
958
0
        _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
959
0
      }
960
0
  }
961
0
    } else {
962
0
  boxes->is_pixel_aligned = TRUE;
963
964
0
  for (i = 0; i < traps->num_traps; i++) {
965
      /* Note the traps and boxes alias so we need to take the local copies first. */
966
0
      cairo_fixed_t x1 = traps->traps[i].left.p1.x;
967
0
      cairo_fixed_t x2 = traps->traps[i].right.p1.x;
968
0
      cairo_fixed_t y1 = traps->traps[i].top;
969
0
      cairo_fixed_t y2 = traps->traps[i].bottom;
970
971
      /* round down here to match Pixman's behavior when using traps. */
972
0
      boxes->chunks.base[i].p1.x = _cairo_fixed_round_down (x1);
973
0
      boxes->chunks.base[i].p1.y = _cairo_fixed_round_down (y1);
974
0
      boxes->chunks.base[i].p2.x = _cairo_fixed_round_down (x2);
975
0
      boxes->chunks.base[i].p2.y = _cairo_fixed_round_down (y2);
976
0
  }
977
0
    }
978
979
0
    return TRUE;
980
0
}
981
982
/* moves trap points such that they become the actual corners of the trapezoid */
983
static void
984
_sanitize_trap (cairo_trapezoid_t *t)
985
0
{
986
0
    cairo_trapezoid_t s = *t;
987
988
0
#define FIX(lr, tb, p) \
989
0
    if (t->lr.p.y != t->tb) { \
990
0
        t->lr.p.x = s.lr.p2.x + _cairo_fixed_mul_div_floor (s.lr.p1.x - s.lr.p2.x, s.tb - s.lr.p2.y, s.lr.p1.y - s.lr.p2.y); \
991
0
        t->lr.p.y = s.tb; \
992
0
    }
993
0
    FIX (left,  top,    p1);
994
0
    FIX (left,  bottom, p2);
995
0
    FIX (right, top,    p1);
996
0
    FIX (right, bottom, p2);
997
0
}
998
999
cairo_private cairo_status_t
1000
_cairo_traps_path (const cairo_traps_t *traps,
1001
       cairo_path_fixed_t  *path)
1002
0
{
1003
0
    int i;
1004
1005
0
    for (i = 0; i < traps->num_traps; i++) {
1006
0
  cairo_status_t status;
1007
0
  cairo_trapezoid_t trap = traps->traps[i];
1008
1009
0
  if (trap.top == trap.bottom)
1010
0
      continue;
1011
1012
0
  _sanitize_trap (&trap);
1013
1014
0
  status = _cairo_path_fixed_move_to (path, trap.left.p1.x, trap.top);
1015
0
  if (unlikely (status)) return status;
1016
0
  status = _cairo_path_fixed_line_to (path, trap.right.p1.x, trap.top);
1017
0
  if (unlikely (status)) return status;
1018
0
  status = _cairo_path_fixed_line_to (path, trap.right.p2.x, trap.bottom);
1019
0
  if (unlikely (status)) return status;
1020
0
  status = _cairo_path_fixed_line_to (path, trap.left.p2.x, trap.bottom);
1021
0
  if (unlikely (status)) return status;
1022
0
  status = _cairo_path_fixed_close_path (path);
1023
0
  if (unlikely (status)) return status;
1024
0
    }
1025
1026
0
    return CAIRO_STATUS_SUCCESS;
1027
0
}
1028
1029
void
1030
_cairo_debug_print_traps (FILE *file, const cairo_traps_t *traps)
1031
0
{
1032
0
    cairo_box_t extents;
1033
0
    int n;
1034
1035
#if 0
1036
    if (traps->has_limits) {
1037
  printf ("%s: limits=(%d, %d, %d, %d)\n",
1038
    filename,
1039
    traps->limits.p1.x, traps->limits.p1.y,
1040
    traps->limits.p2.x, traps->limits.p2.y);
1041
    }
1042
#endif
1043
1044
0
    _cairo_traps_extents (traps, &extents);
1045
0
    fprintf (file, "extents=(%d, %d, %d, %d)\n",
1046
0
       extents.p1.x, extents.p1.y,
1047
0
       extents.p2.x, extents.p2.y);
1048
1049
0
    for (n = 0; n < traps->num_traps; n++) {
1050
0
  fprintf (file, "%d %d L:(%d, %d), (%d, %d) R:(%d, %d), (%d, %d)\n",
1051
0
     traps->traps[n].top,
1052
0
     traps->traps[n].bottom,
1053
0
     traps->traps[n].left.p1.x,
1054
0
     traps->traps[n].left.p1.y,
1055
0
     traps->traps[n].left.p2.x,
1056
0
     traps->traps[n].left.p2.y,
1057
0
     traps->traps[n].right.p1.x,
1058
0
     traps->traps[n].right.p1.y,
1059
0
     traps->traps[n].right.p2.x,
1060
0
     traps->traps[n].right.p2.y);
1061
0
    }
1062
0
}
1063
1064
struct cairo_trap_renderer {
1065
    cairo_span_renderer_t base;
1066
    cairo_traps_t *traps;
1067
};
1068
1069
static cairo_status_t
1070
span_to_traps (void *abstract_renderer, int y, int h,
1071
         const cairo_half_open_span_t *spans, unsigned num_spans)
1072
0
{
1073
0
    struct cairo_trap_renderer *r = abstract_renderer;
1074
0
    cairo_fixed_t top, bot;
1075
1076
0
    if (num_spans == 0)
1077
0
  return CAIRO_STATUS_SUCCESS;
1078
1079
0
    top = _cairo_fixed_from_int (y);
1080
0
    bot = _cairo_fixed_from_int (y + h);
1081
0
    do {
1082
0
  if (spans[0].coverage) {
1083
0
      cairo_fixed_t x0 = _cairo_fixed_from_int(spans[0].x);
1084
0
      cairo_fixed_t x1 = _cairo_fixed_from_int(spans[1].x);
1085
0
      cairo_line_t left = { { x0, top }, { x0, bot } },
1086
0
       right = { { x1, top }, { x1, bot } };
1087
0
      _cairo_traps_add_trap (r->traps, top, bot, &left, &right);
1088
0
  }
1089
0
  spans++;
1090
0
    } while (--num_spans > 1);
1091
1092
0
    return CAIRO_STATUS_SUCCESS;
1093
0
}
1094
1095
cairo_int_status_t
1096
_cairo_rasterise_polygon_to_traps (cairo_polygon_t      *polygon,
1097
           cairo_fill_rule_t       fill_rule,
1098
           cairo_antialias_t       antialias,
1099
           cairo_traps_t *traps)
1100
0
{
1101
0
    struct cairo_trap_renderer renderer;
1102
0
    cairo_scan_converter_t *converter;
1103
0
    cairo_int_status_t status;
1104
0
    cairo_rectangle_int_t r;
1105
1106
0
    TRACE ((stderr, "%s: fill_rule=%d, antialias=%d\n",
1107
0
      __FUNCTION__, fill_rule, antialias));
1108
0
    assert(antialias == CAIRO_ANTIALIAS_NONE);
1109
1110
0
    renderer.traps = traps;
1111
0
    renderer.base.render_rows = span_to_traps;
1112
1113
0
    _cairo_box_round_to_rectangle (&polygon->extents, &r);
1114
0
    converter = _cairo_mono_scan_converter_create (r.x, r.y,
1115
0
               r.x + r.width,
1116
0
               r.y + r.height,
1117
0
               fill_rule);
1118
0
    status = _cairo_mono_scan_converter_add_polygon (converter, polygon);
1119
0
    if (likely (status == CAIRO_INT_STATUS_SUCCESS))
1120
0
  status = converter->generate (converter, &renderer.base);
1121
0
    converter->destroy (converter);
1122
0
    return status;
1123
0
}