Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  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-boxes-private.h"
  43. #include "cairo-error-private.h"
  44. #include "cairo-region-private.h"
  45. #include "cairo-slope-private.h"
  46.  
  47. /* private functions */
  48.  
  49. void
  50. _cairo_traps_init (cairo_traps_t *traps)
  51. {
  52.     VG (VALGRIND_MAKE_MEM_UNDEFINED (traps, sizeof (cairo_traps_t)));
  53.  
  54.     traps->status = CAIRO_STATUS_SUCCESS;
  55.  
  56.     traps->maybe_region = 1;
  57.     traps->is_rectilinear = 0;
  58.     traps->is_rectangular = 0;
  59.  
  60.     traps->num_traps = 0;
  61.  
  62.     traps->traps_size = ARRAY_LENGTH (traps->traps_embedded);
  63.     traps->traps = traps->traps_embedded;
  64.  
  65.     traps->num_limits = 0;
  66.     traps->has_intersections = FALSE;
  67. }
  68.  
  69. void
  70. _cairo_traps_limit (cairo_traps_t       *traps,
  71.                     const cairo_box_t   *limits,
  72.                     int                  num_limits)
  73. {
  74.     traps->limits = limits;
  75.     traps->num_limits = num_limits;
  76. }
  77.  
  78. void
  79. _cairo_traps_clear (cairo_traps_t *traps)
  80. {
  81.     traps->status = CAIRO_STATUS_SUCCESS;
  82.  
  83.     traps->maybe_region = 1;
  84.     traps->is_rectilinear = 0;
  85.     traps->is_rectangular = 0;
  86.  
  87.     traps->num_traps = 0;
  88.     traps->has_intersections = FALSE;
  89. }
  90.  
  91. void
  92. _cairo_traps_fini (cairo_traps_t *traps)
  93. {
  94.     if (traps->traps != traps->traps_embedded)
  95.         free (traps->traps);
  96.  
  97.     VG (VALGRIND_MAKE_MEM_NOACCESS (traps, sizeof (cairo_traps_t)));
  98. }
  99.  
  100. /* make room for at least one more trap */
  101. static cairo_bool_t
  102. _cairo_traps_grow (cairo_traps_t *traps)
  103. {
  104.     cairo_trapezoid_t *new_traps;
  105.     int new_size = 4 * traps->traps_size;
  106.  
  107.     if (CAIRO_INJECT_FAULT ()) {
  108.         traps->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  109.         return FALSE;
  110.     }
  111.  
  112.     if (traps->traps == traps->traps_embedded) {
  113.         new_traps = _cairo_malloc_ab (new_size, sizeof (cairo_trapezoid_t));
  114.         if (new_traps != NULL)
  115.             memcpy (new_traps, traps->traps, sizeof (traps->traps_embedded));
  116.     } else {
  117.         new_traps = _cairo_realloc_ab (traps->traps,
  118.                                        new_size, sizeof (cairo_trapezoid_t));
  119.     }
  120.  
  121.     if (unlikely (new_traps == NULL)) {
  122.         traps->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  123.         return FALSE;
  124.     }
  125.  
  126.     traps->traps = new_traps;
  127.     traps->traps_size = new_size;
  128.     return TRUE;
  129. }
  130.  
  131. void
  132. _cairo_traps_add_trap (cairo_traps_t *traps,
  133.                        cairo_fixed_t top, cairo_fixed_t bottom,
  134.                        cairo_line_t *left, cairo_line_t *right)
  135. {
  136.     cairo_trapezoid_t *trap;
  137.  
  138.     if (unlikely (traps->num_traps == traps->traps_size)) {
  139.         if (unlikely (! _cairo_traps_grow (traps)))
  140.             return;
  141.     }
  142.  
  143.     trap = &traps->traps[traps->num_traps++];
  144.     trap->top = top;
  145.     trap->bottom = bottom;
  146.     trap->left = *left;
  147.     trap->right = *right;
  148. }
  149.  
  150. /**
  151.  * _cairo_traps_init_box:
  152.  * @traps: a #cairo_traps_t
  153.  * @box: an array box that will each be converted to a single trapezoid
  154.  *       to store in @traps.
  155.  *
  156.  * Initializes a #cairo_traps_t to contain an array of rectangular
  157.  * trapezoids.
  158.  **/
  159. cairo_status_t
  160. _cairo_traps_init_boxes (cairo_traps_t      *traps,
  161.                          const cairo_boxes_t *boxes)
  162. {
  163.     cairo_trapezoid_t *trap;
  164.     const struct _cairo_boxes_chunk *chunk;
  165.  
  166.     _cairo_traps_init (traps);
  167.  
  168.     while (traps->traps_size < boxes->num_boxes) {
  169.         if (unlikely (! _cairo_traps_grow (traps))) {
  170.             _cairo_traps_fini (traps);
  171.             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  172.         }
  173.     }
  174.  
  175.     traps->num_traps = boxes->num_boxes;
  176.     traps->is_rectilinear = TRUE;
  177.     traps->is_rectangular = TRUE;
  178.     traps->maybe_region = boxes->is_pixel_aligned;
  179.  
  180.     trap = &traps->traps[0];
  181.     for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
  182.         const cairo_box_t *box;
  183.         int i;
  184.  
  185.         box = chunk->base;
  186.         for (i = 0; i < chunk->count; i++) {
  187.             trap->top    = box->p1.y;
  188.             trap->bottom = box->p2.y;
  189.  
  190.             trap->left.p1   = box->p1;
  191.             trap->left.p2.x = box->p1.x;
  192.             trap->left.p2.y = box->p2.y;
  193.  
  194.             trap->right.p1.x = box->p2.x;
  195.             trap->right.p1.y = box->p1.y;
  196.             trap->right.p2   = box->p2;
  197.  
  198.             box++, trap++;
  199.         }
  200.     }
  201.  
  202.     return CAIRO_STATUS_SUCCESS;
  203. }
  204.  
  205. cairo_status_t
  206. _cairo_traps_tessellate_rectangle (cairo_traps_t *traps,
  207.                                    const cairo_point_t *top_left,
  208.                                    const cairo_point_t *bottom_right)
  209. {
  210.     cairo_line_t left;
  211.     cairo_line_t right;
  212.     cairo_fixed_t top, bottom;
  213.  
  214.     if (top_left->y == bottom_right->y)
  215.         return CAIRO_STATUS_SUCCESS;
  216.  
  217.     if (top_left->x == bottom_right->x)
  218.         return CAIRO_STATUS_SUCCESS;
  219.  
  220.      left.p1.x =  left.p2.x = top_left->x;
  221.      left.p1.y = right.p1.y = top_left->y;
  222.     right.p1.x = right.p2.x = bottom_right->x;
  223.      left.p2.y = right.p2.y = bottom_right->y;
  224.  
  225.      top = top_left->y;
  226.      bottom = bottom_right->y;
  227.  
  228.     if (traps->num_limits) {
  229.         cairo_bool_t reversed;
  230.         int n;
  231.  
  232.         /* support counter-clockwise winding for rectangular tessellation */
  233.         reversed = top_left->x > bottom_right->x;
  234.         if (reversed) {
  235.             right.p1.x = right.p2.x = top_left->x;
  236.             left.p1.x = left.p2.x = bottom_right->x;
  237.         }
  238.  
  239.         for (n = 0; n < traps->num_limits; n++) {
  240.             const cairo_box_t *limits = &traps->limits[n];
  241.             cairo_line_t _left, _right;
  242.             cairo_fixed_t _top, _bottom;
  243.  
  244.             if (top >= limits->p2.y)
  245.                 continue;
  246.             if (bottom <= limits->p1.y)
  247.                 continue;
  248.  
  249.             /* Trivially reject if trapezoid is entirely to the right or
  250.              * to the left of the limits. */
  251.             if (left.p1.x >= limits->p2.x)
  252.                 continue;
  253.             if (right.p1.x <= limits->p1.x)
  254.                 continue;
  255.  
  256.             /* Otherwise, clip the trapezoid to the limits. */
  257.             _top = top;
  258.             if (_top < limits->p1.y)
  259.                 _top = limits->p1.y;
  260.  
  261.             _bottom = bottom;
  262.             if (_bottom > limits->p2.y)
  263.                 _bottom = limits->p2.y;
  264.  
  265.             if (_bottom <= _top)
  266.                 continue;
  267.  
  268.             _left = left;
  269.             if (_left.p1.x < limits->p1.x) {
  270.                 _left.p1.x = limits->p1.x;
  271.                 _left.p1.y = limits->p1.y;
  272.                 _left.p2.x = limits->p1.x;
  273.                 _left.p2.y = limits->p2.y;
  274.             }
  275.  
  276.             _right = right;
  277.             if (_right.p1.x > limits->p2.x) {
  278.                 _right.p1.x = limits->p2.x;
  279.                 _right.p1.y = limits->p1.y;
  280.                 _right.p2.x = limits->p2.x;
  281.                 _right.p2.y = limits->p2.y;
  282.             }
  283.  
  284.             if (left.p1.x >= right.p1.x)
  285.                 continue;
  286.  
  287.             if (reversed)
  288.                 _cairo_traps_add_trap (traps, _top, _bottom, &_right, &_left);
  289.             else
  290.                 _cairo_traps_add_trap (traps, _top, _bottom, &_left, &_right);
  291.         }
  292.     } else {
  293.         _cairo_traps_add_trap (traps, top, bottom, &left, &right);
  294.     }
  295.  
  296.     return traps->status;
  297. }
  298.  
  299. void
  300. _cairo_traps_translate (cairo_traps_t *traps, int x, int y)
  301. {
  302.     cairo_fixed_t xoff, yoff;
  303.     cairo_trapezoid_t *t;
  304.     int i;
  305.  
  306.     /* Ugh. The cairo_composite/(Render) interface doesn't allow
  307.        an offset for the trapezoids. Need to manually shift all
  308.        the coordinates to align with the offset origin of the
  309.        intermediate surface. */
  310.  
  311.     xoff = _cairo_fixed_from_int (x);
  312.     yoff = _cairo_fixed_from_int (y);
  313.  
  314.     for (i = 0, t = traps->traps; i < traps->num_traps; i++, t++) {
  315.         t->top += yoff;
  316.         t->bottom += yoff;
  317.         t->left.p1.x += xoff;
  318.         t->left.p1.y += yoff;
  319.         t->left.p2.x += xoff;
  320.         t->left.p2.y += yoff;
  321.         t->right.p1.x += xoff;
  322.         t->right.p1.y += yoff;
  323.         t->right.p2.x += xoff;
  324.         t->right.p2.y += yoff;
  325.     }
  326. }
  327.  
  328. void
  329. _cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps,
  330.                                             cairo_trapezoid_t *src_traps,
  331.                                             int num_traps,
  332.                                             double tx, double ty,
  333.                                             double sx, double sy)
  334. {
  335.     int i;
  336.     cairo_fixed_t xoff = _cairo_fixed_from_double (tx);
  337.     cairo_fixed_t yoff = _cairo_fixed_from_double (ty);
  338.  
  339.     if (sx == 1.0 && sy == 1.0) {
  340.         for (i = 0; i < num_traps; i++) {
  341.             offset_traps[i].top = src_traps[i].top + yoff;
  342.             offset_traps[i].bottom = src_traps[i].bottom + yoff;
  343.             offset_traps[i].left.p1.x = src_traps[i].left.p1.x + xoff;
  344.             offset_traps[i].left.p1.y = src_traps[i].left.p1.y + yoff;
  345.             offset_traps[i].left.p2.x = src_traps[i].left.p2.x + xoff;
  346.             offset_traps[i].left.p2.y = src_traps[i].left.p2.y + yoff;
  347.             offset_traps[i].right.p1.x = src_traps[i].right.p1.x + xoff;
  348.             offset_traps[i].right.p1.y = src_traps[i].right.p1.y + yoff;
  349.             offset_traps[i].right.p2.x = src_traps[i].right.p2.x + xoff;
  350.             offset_traps[i].right.p2.y = src_traps[i].right.p2.y + yoff;
  351.         }
  352.     } else {
  353.         cairo_fixed_t xsc = _cairo_fixed_from_double (sx);
  354.         cairo_fixed_t ysc = _cairo_fixed_from_double (sy);
  355.  
  356.         for (i = 0; i < num_traps; i++) {
  357.             offset_traps[i].top = _cairo_fixed_mul (src_traps[i].top + yoff, ysc);
  358.             offset_traps[i].bottom = _cairo_fixed_mul (src_traps[i].bottom + yoff, ysc);
  359.             offset_traps[i].left.p1.x = _cairo_fixed_mul (src_traps[i].left.p1.x + xoff, xsc);
  360.             offset_traps[i].left.p1.y = _cairo_fixed_mul (src_traps[i].left.p1.y + yoff, ysc);
  361.             offset_traps[i].left.p2.x = _cairo_fixed_mul (src_traps[i].left.p2.x + xoff, xsc);
  362.             offset_traps[i].left.p2.y = _cairo_fixed_mul (src_traps[i].left.p2.y + yoff, ysc);
  363.             offset_traps[i].right.p1.x = _cairo_fixed_mul (src_traps[i].right.p1.x + xoff, xsc);
  364.             offset_traps[i].right.p1.y = _cairo_fixed_mul (src_traps[i].right.p1.y + yoff, ysc);
  365.             offset_traps[i].right.p2.x = _cairo_fixed_mul (src_traps[i].right.p2.x + xoff, xsc);
  366.             offset_traps[i].right.p2.y = _cairo_fixed_mul (src_traps[i].right.p2.y + yoff, ysc);
  367.         }
  368.     }
  369. }
  370.  
  371. static cairo_bool_t
  372. _cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt)
  373. {
  374.     cairo_slope_t slope_left, slope_pt, slope_right;
  375.  
  376.     if (t->top > pt->y)
  377.         return FALSE;
  378.     if (t->bottom < pt->y)
  379.         return FALSE;
  380.  
  381.     _cairo_slope_init (&slope_left, &t->left.p1, &t->left.p2);
  382.     _cairo_slope_init (&slope_pt, &t->left.p1, pt);
  383.  
  384.     if (_cairo_slope_compare (&slope_left, &slope_pt) < 0)
  385.         return FALSE;
  386.  
  387.     _cairo_slope_init (&slope_right, &t->right.p1, &t->right.p2);
  388.     _cairo_slope_init (&slope_pt, &t->right.p1, pt);
  389.  
  390.     if (_cairo_slope_compare (&slope_pt, &slope_right) < 0)
  391.         return FALSE;
  392.  
  393.     return TRUE;
  394. }
  395.  
  396. cairo_bool_t
  397. _cairo_traps_contain (const cairo_traps_t *traps,
  398.                       double x, double y)
  399. {
  400.     int i;
  401.     cairo_point_t point;
  402.  
  403.     point.x = _cairo_fixed_from_double (x);
  404.     point.y = _cairo_fixed_from_double (y);
  405.  
  406.     for (i = 0; i < traps->num_traps; i++) {
  407.         if (_cairo_trap_contains (&traps->traps[i], &point))
  408.             return TRUE;
  409.     }
  410.  
  411.     return FALSE;
  412. }
  413.  
  414. static cairo_fixed_t
  415. _line_compute_intersection_x_for_y (const cairo_line_t *line,
  416.                                     cairo_fixed_t y)
  417. {
  418.     return _cairo_edge_compute_intersection_x_for_y (&line->p1, &line->p2, y);
  419. }
  420.  
  421. void
  422. _cairo_traps_extents (const cairo_traps_t *traps,
  423.                       cairo_box_t *extents)
  424. {
  425.     int i;
  426.  
  427.     if (traps->num_traps == 0) {
  428.         extents->p1.x = extents->p1.y = 0;
  429.         extents->p2.x = extents->p2.y = 0;
  430.         return;
  431.     }
  432.  
  433.     extents->p1.x = extents->p1.y = INT32_MAX;
  434.     extents->p2.x = extents->p2.y = INT32_MIN;
  435.  
  436.     for (i = 0; i < traps->num_traps; i++) {
  437.         const cairo_trapezoid_t *trap =  &traps->traps[i];
  438.  
  439.         if (trap->top < extents->p1.y)
  440.             extents->p1.y = trap->top;
  441.         if (trap->bottom > extents->p2.y)
  442.             extents->p2.y = trap->bottom;
  443.  
  444.         if (trap->left.p1.x < extents->p1.x) {
  445.             cairo_fixed_t x = trap->left.p1.x;
  446.             if (trap->top != trap->left.p1.y) {
  447.                 x = _line_compute_intersection_x_for_y (&trap->left,
  448.                                                         trap->top);
  449.                 if (x < extents->p1.x)
  450.                     extents->p1.x = x;
  451.             } else
  452.                 extents->p1.x = x;
  453.         }
  454.         if (trap->left.p2.x < extents->p1.x) {
  455.             cairo_fixed_t x = trap->left.p2.x;
  456.             if (trap->bottom != trap->left.p2.y) {
  457.                 x = _line_compute_intersection_x_for_y (&trap->left,
  458.                                                         trap->bottom);
  459.                 if (x < extents->p1.x)
  460.                     extents->p1.x = x;
  461.             } else
  462.                 extents->p1.x = x;
  463.         }
  464.  
  465.         if (trap->right.p1.x > extents->p2.x) {
  466.             cairo_fixed_t x = trap->right.p1.x;
  467.             if (trap->top != trap->right.p1.y) {
  468.                 x = _line_compute_intersection_x_for_y (&trap->right,
  469.                                                         trap->top);
  470.                 if (x > extents->p2.x)
  471.                     extents->p2.x = x;
  472.             } else
  473.                 extents->p2.x = x;
  474.         }
  475.         if (trap->right.p2.x > extents->p2.x) {
  476.             cairo_fixed_t x = trap->right.p2.x;
  477.             if (trap->bottom != trap->right.p2.y) {
  478.                 x = _line_compute_intersection_x_for_y (&trap->right,
  479.                                                         trap->bottom);
  480.                 if (x > extents->p2.x)
  481.                     extents->p2.x = x;
  482.             } else
  483.                 extents->p2.x = x;
  484.         }
  485.     }
  486. }
  487.  
  488.  
  489. /**
  490.  * _cairo_traps_extract_region:
  491.  * @traps: a #cairo_traps_t
  492.  * @region: a #cairo_region_t
  493.  *
  494.  * Determines if a set of trapezoids are exactly representable as a
  495.  * cairo region.  If so, the passed-in region is initialized to
  496.  * the area representing the given traps.  It should be finalized
  497.  * with cairo_region_fini().  If not, %CAIRO_INT_STATUS_UNSUPPORTED
  498.  * is returned.
  499.  *
  500.  * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED
  501.  * or %CAIRO_STATUS_NO_MEMORY
  502.  **/
  503. cairo_int_status_t
  504. _cairo_traps_extract_region (cairo_traps_t   *traps,
  505.                              cairo_region_t **region)
  506. {
  507.     cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
  508.     cairo_rectangle_int_t *rects = stack_rects;
  509.     cairo_int_status_t status;
  510.     int i, rect_count;
  511.  
  512.     /* we only treat this a hint... */
  513.     if (! traps->maybe_region)
  514.         return CAIRO_INT_STATUS_UNSUPPORTED;
  515.  
  516.     for (i = 0; i < traps->num_traps; i++) {
  517.         if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x   ||
  518.             traps->traps[i].right.p1.x != traps->traps[i].right.p2.x ||
  519.             ! _cairo_fixed_is_integer (traps->traps[i].top)          ||
  520.             ! _cairo_fixed_is_integer (traps->traps[i].bottom)       ||
  521.             ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x)    ||
  522.             ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
  523.         {
  524.             traps->maybe_region = FALSE;
  525.             return CAIRO_INT_STATUS_UNSUPPORTED;
  526.         }
  527.     }
  528.  
  529.     if (traps->num_traps > ARRAY_LENGTH (stack_rects)) {
  530.         rects = _cairo_malloc_ab (traps->num_traps, sizeof (cairo_rectangle_int_t));
  531.  
  532.         if (unlikely (rects == NULL))
  533.             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  534.     }
  535.  
  536.     rect_count = 0;
  537.     for (i = 0; i < traps->num_traps; i++) {
  538.         int x1 = _cairo_fixed_integer_part (traps->traps[i].left.p1.x);
  539.         int y1 = _cairo_fixed_integer_part (traps->traps[i].top);
  540.         int x2 = _cairo_fixed_integer_part (traps->traps[i].right.p1.x);
  541.         int y2 = _cairo_fixed_integer_part (traps->traps[i].bottom);
  542.  
  543.         rects[rect_count].x = x1;
  544.         rects[rect_count].y = y1;
  545.         rects[rect_count].width = x2 - x1;
  546.         rects[rect_count].height = y2 - y1;
  547.  
  548.         rect_count++;
  549.     }
  550.  
  551.     *region = cairo_region_create_rectangles (rects, rect_count);
  552.     status = (*region)->status;
  553.  
  554.     if (rects != stack_rects)
  555.         free (rects);
  556.  
  557.     return status;
  558. }
  559.  
  560. /* moves trap points such that they become the actual corners of the trapezoid */
  561. static void
  562. _sanitize_trap (cairo_trapezoid_t *t)
  563. {
  564.     cairo_trapezoid_t s = *t;
  565.  
  566. #define FIX(lr, tb, p) \
  567.     if (t->lr.p.y != t->tb) { \
  568.         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); \
  569.         t->lr.p.y = s.tb; \
  570.     }
  571.     FIX (left,  top,    p1);
  572.     FIX (left,  bottom, p2);
  573.     FIX (right, top,    p1);
  574.     FIX (right, bottom, p2);
  575. }
  576.  
  577. cairo_private cairo_status_t
  578. _cairo_traps_path (const cairo_traps_t *traps,
  579.                    cairo_path_fixed_t  *path)
  580. {
  581.     int i;
  582.  
  583.     for (i = 0; i < traps->num_traps; i++) {
  584.         cairo_status_t status;
  585.         cairo_trapezoid_t trap = traps->traps[i];
  586.  
  587.         if (trap.top == trap.bottom)
  588.             continue;
  589.  
  590.         _sanitize_trap (&trap);
  591.  
  592.         status = _cairo_path_fixed_move_to (path, trap.left.p1.x, trap.top);
  593.         if (unlikely (status)) return status;
  594.         status = _cairo_path_fixed_line_to (path, trap.right.p1.x, trap.top);
  595.         if (unlikely (status)) return status;
  596.         status = _cairo_path_fixed_line_to (path, trap.right.p2.x, trap.bottom);
  597.         if (unlikely (status)) return status;
  598.         status = _cairo_path_fixed_line_to (path, trap.left.p2.x, trap.bottom);
  599.         if (unlikely (status)) return status;
  600.         status = _cairo_path_fixed_close_path (path);
  601.         if (unlikely (status)) return status;
  602.     }
  603.  
  604.     return CAIRO_STATUS_SUCCESS;
  605. }
  606.