Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /* cairo - a vector graphics library with display and print output
  2.  *
  3.  * Copyright © 2002 University of Southern California
  4.  *
  5.  * This library is free software; you can redistribute it and/or
  6.  * modify it either under the terms of the GNU Lesser General Public
  7.  * License version 2.1 as published by the Free Software Foundation
  8.  * (the "LGPL") or, at your option, under the terms of the Mozilla
  9.  * Public License Version 1.1 (the "MPL"). If you do not alter this
  10.  * notice, a recipient may use your version of this file under either
  11.  * the MPL or the LGPL.
  12.  *
  13.  * You should have received a copy of the LGPL along with this library
  14.  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
  15.  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
  16.  * You should have received a copy of the MPL along with this library
  17.  * in the file COPYING-MPL-1.1
  18.  *
  19.  * The contents of this file are subject to the Mozilla Public License
  20.  * Version 1.1 (the "License"); you may not use this file except in
  21.  * compliance with the License. You may obtain a copy of the License at
  22.  * http://www.mozilla.org/MPL/
  23.  *
  24.  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
  25.  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
  26.  * the specific language governing rights and limitations.
  27.  *
  28.  * The Original Code is the cairo graphics library.
  29.  *
  30.  * The Initial Developer of the Original Code is University of Southern
  31.  * California.
  32.  *
  33.  * Contributor(s):
  34.  *      Carl D. Worth <cworth@cworth.org>
  35.  */
  36.  
  37. #include "cairoint.h"
  38. #include "cairo-boxes-private.h"
  39. #include "cairo-error-private.h"
  40. #include "cairo-path-fixed-private.h"
  41. #include "cairo-region-private.h"
  42.  
  43. typedef struct cairo_filler {
  44.     double tolerance;
  45.     cairo_polygon_t *polygon;
  46. } cairo_filler_t;
  47.  
  48. static void
  49. _cairo_filler_init (cairo_filler_t *filler,
  50.                     double tolerance,
  51.                     cairo_polygon_t *polygon)
  52. {
  53.     filler->tolerance = tolerance;
  54.     filler->polygon = polygon;
  55. }
  56.  
  57. static void
  58. _cairo_filler_fini (cairo_filler_t *filler)
  59. {
  60. }
  61.  
  62. static cairo_status_t
  63. _cairo_filler_move_to (void *closure,
  64.                        const cairo_point_t *point)
  65. {
  66.     cairo_filler_t *filler = closure;
  67.     cairo_polygon_t *polygon = filler->polygon;
  68.  
  69.     return _cairo_polygon_close (polygon) ||
  70.            _cairo_polygon_move_to (polygon, point);
  71. }
  72.  
  73. static cairo_status_t
  74. _cairo_filler_line_to (void *closure,
  75.                        const cairo_point_t *point)
  76. {
  77.     cairo_filler_t *filler = closure;
  78.     return _cairo_polygon_line_to (filler->polygon, point);
  79. }
  80.  
  81. static cairo_status_t
  82. _cairo_filler_curve_to (void *closure,
  83.                         const cairo_point_t *b,
  84.                         const cairo_point_t *c,
  85.                         const cairo_point_t *d)
  86. {
  87.     cairo_filler_t *filler = closure;
  88.     cairo_spline_t spline;
  89.  
  90.     if (! _cairo_spline_init (&spline,
  91.                               _cairo_filler_line_to, filler,
  92.                               &filler->polygon->current_point, b, c, d))
  93.     {
  94.         return _cairo_filler_line_to (closure, d);
  95.     }
  96.  
  97.     return _cairo_spline_decompose (&spline, filler->tolerance);
  98. }
  99.  
  100. static cairo_status_t
  101. _cairo_filler_close_path (void *closure)
  102. {
  103.     cairo_filler_t *filler = closure;
  104.     return _cairo_polygon_close (filler->polygon);
  105. }
  106.  
  107. cairo_status_t
  108. _cairo_path_fixed_fill_to_polygon (const cairo_path_fixed_t *path,
  109.                                    double tolerance,
  110.                                    cairo_polygon_t *polygon)
  111. {
  112.     cairo_filler_t filler;
  113.     cairo_status_t status;
  114.  
  115.     _cairo_filler_init (&filler, tolerance, polygon);
  116.  
  117.     status = _cairo_path_fixed_interpret (path,
  118.                                           CAIRO_DIRECTION_FORWARD,
  119.                                           _cairo_filler_move_to,
  120.                                           _cairo_filler_line_to,
  121.                                           _cairo_filler_curve_to,
  122.                                           _cairo_filler_close_path,
  123.                                           &filler);
  124.     if (unlikely (status))
  125.         return status;
  126.  
  127.     status = _cairo_polygon_close (polygon);
  128.     _cairo_filler_fini (&filler);
  129.  
  130.     return status;
  131. }
  132.  
  133. cairo_status_t
  134. _cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
  135.                                  cairo_fill_rule_t fill_rule,
  136.                                  double tolerance,
  137.                                  cairo_traps_t *traps)
  138. {
  139.     cairo_polygon_t polygon;
  140.     cairo_status_t status;
  141.  
  142.     if (path->is_empty_fill)
  143.         return CAIRO_STATUS_SUCCESS;
  144.  
  145.     _cairo_polygon_init (&polygon);
  146.     if (traps->num_limits)
  147.         _cairo_polygon_limit (&polygon, traps->limits, traps->num_limits);
  148.  
  149.     status = _cairo_path_fixed_fill_to_polygon (path,
  150.                                                 tolerance,
  151.                                                 &polygon);
  152.     if (unlikely (status || polygon.num_edges == 0))
  153.         goto CLEANUP;
  154.  
  155.     if (path->is_rectilinear) {
  156.         status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (traps,
  157.                                                                         &polygon,
  158.                                                                         fill_rule);
  159.     } else {
  160.         status = _cairo_bentley_ottmann_tessellate_polygon (traps,
  161.                                                             &polygon,
  162.                                                             fill_rule);
  163.     }
  164.  
  165.   CLEANUP:
  166.     _cairo_polygon_fini (&polygon);
  167.     return status;
  168. }
  169.  
  170. static cairo_region_t *
  171. _cairo_path_fixed_fill_rectilinear_tessellate_to_region (const cairo_path_fixed_t       *path,
  172.                                                          cairo_fill_rule_t       fill_rule,
  173.                                                          const cairo_rectangle_int_t *extents)
  174. {
  175.     cairo_box_t box;
  176.     cairo_polygon_t polygon;
  177.     cairo_traps_t traps;
  178.     cairo_status_t status;
  179.     cairo_region_t *region;
  180.  
  181.     /* first try to bypass fill-to-polygon */
  182.     _cairo_traps_init (&traps);
  183.     status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
  184.                                                           fill_rule,
  185.                                                           &traps);
  186.     if (_cairo_status_is_error (status))
  187.         goto CLEANUP_TRAPS;
  188.  
  189.     if (status == CAIRO_STATUS_SUCCESS) {
  190.         status = _cairo_traps_extract_region (&traps, &region);
  191.         goto CLEANUP_TRAPS;
  192.     }
  193.  
  194.     /* path is not rectangular, try extracting clipped rectilinear edges */
  195.     _cairo_polygon_init (&polygon);
  196.     if (extents != NULL) {
  197.         _cairo_box_from_rectangle (&box, extents);
  198.         _cairo_polygon_limit (&polygon, &box, 1);
  199.     }
  200.  
  201.     /* tolerance will be ignored as the path is rectilinear */
  202.     status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon);
  203.     if (unlikely (status))
  204.         goto CLEANUP_POLYGON;
  205.  
  206.     if (polygon.num_edges == 0) {
  207.         region = cairo_region_create ();
  208.     } else {
  209.         status =
  210.             _cairo_bentley_ottmann_tessellate_rectilinear_polygon (&traps,
  211.                                                                    &polygon,
  212.                                                                    fill_rule);
  213.         if (likely (status == CAIRO_STATUS_SUCCESS))
  214.             status = _cairo_traps_extract_region (&traps, &region);
  215.     }
  216.  
  217.   CLEANUP_POLYGON:
  218.     _cairo_polygon_fini (&polygon);
  219.  
  220.   CLEANUP_TRAPS:
  221.     _cairo_traps_fini (&traps);
  222.  
  223.     if (unlikely (status))
  224.         region = _cairo_region_create_in_error (status);
  225.  
  226.     return region;
  227. }
  228.  
  229. /* This special-case filler supports only a path that describes a
  230.  * device-axis aligned rectangle. It exists to avoid the overhead of
  231.  * the general tessellator when drawing very common rectangles.
  232.  *
  233.  * If the path described anything but a device-axis aligned rectangle,
  234.  * this function will abort.
  235.  */
  236. cairo_region_t *
  237. _cairo_path_fixed_fill_rectilinear_to_region (const cairo_path_fixed_t  *path,
  238.                                               cairo_fill_rule_t  fill_rule,
  239.                                               const cairo_rectangle_int_t *extents)
  240. {
  241.     cairo_rectangle_int_t rectangle_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
  242.     cairo_box_t box;
  243.     cairo_region_t *region = NULL;
  244.  
  245.     assert (path->maybe_fill_region);
  246.     assert (! path->is_empty_fill);
  247.  
  248.     if (_cairo_path_fixed_is_box (path, &box)) {
  249.         rectangle_stack[0].x = _cairo_fixed_integer_part (box.p1.x);
  250.         rectangle_stack[0].y = _cairo_fixed_integer_part (box.p1.y);
  251.         rectangle_stack[0].width = _cairo_fixed_integer_part (box.p2.x) -
  252.                                     rectangle_stack[0].x;
  253.         rectangle_stack[0].height = _cairo_fixed_integer_part (box.p2.y) -
  254.                                     rectangle_stack[0].y;
  255.         if (! _cairo_rectangle_intersect (&rectangle_stack[0], extents))
  256.             region = cairo_region_create ();
  257.         else
  258.             region = cairo_region_create_rectangle (&rectangle_stack[0]);
  259.     } else if (fill_rule == CAIRO_FILL_RULE_WINDING) {
  260.         cairo_rectangle_int_t *rects = rectangle_stack;
  261.         cairo_path_fixed_iter_t iter;
  262.         int last_cw = -1;
  263.         int size = ARRAY_LENGTH (rectangle_stack);
  264.         int count = 0;
  265.  
  266.         /* Support a series of rectangles as can be expected to describe a
  267.          * GdkRegion clip region during exposes.
  268.          */
  269.         _cairo_path_fixed_iter_init (&iter, path);
  270.         while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
  271.             int cw = 0;
  272.  
  273.             if (box.p1.x > box.p2.x) {
  274.                 cairo_fixed_t t;
  275.  
  276.                 t = box.p1.x;
  277.                 box.p1.x = box.p2.x;
  278.                 box.p2.x = t;
  279.  
  280.                 cw = ! cw;
  281.             }
  282.  
  283.             if (box.p1.y > box.p2.y) {
  284.                 cairo_fixed_t t;
  285.  
  286.                 t = box.p1.y;
  287.                 box.p1.y = box.p2.y;
  288.                 box.p2.y = t;
  289.  
  290.                 cw = ! cw;
  291.             }
  292.  
  293.             if (last_cw < 0)
  294.                 last_cw = cw;
  295.             else if (last_cw != cw)
  296.                 goto TESSELLATE;
  297.  
  298.             if (count == size) {
  299.                 cairo_rectangle_int_t *new_rects;
  300.  
  301.                 size *= 4;
  302.                 if (rects == rectangle_stack) {
  303.                     new_rects = _cairo_malloc_ab (size,
  304.                                                   sizeof (cairo_rectangle_int_t));
  305.                     if (unlikely (new_rects == NULL)) {
  306.                         /* XXX _cairo_region_nil */
  307.                         break;
  308.                     }
  309.                     memcpy (new_rects, rects, sizeof (rectangle_stack));
  310.                 } else {
  311.                     new_rects = _cairo_realloc_ab (rects, size,
  312.                                                    sizeof (cairo_rectangle_int_t));
  313.                     if (unlikely (new_rects == NULL)) {
  314.                         /* XXX _cairo_region_nil */
  315.                         break;
  316.                     }
  317.                 }
  318.                 rects = new_rects;
  319.             }
  320.  
  321.             rects[count].x = _cairo_fixed_integer_part (box.p1.x);
  322.             rects[count].y = _cairo_fixed_integer_part (box.p1.y);
  323.             rects[count].width = _cairo_fixed_integer_part (box.p2.x) - rects[count].x;
  324.             rects[count].height = _cairo_fixed_integer_part (box.p2.y) - rects[count].y;
  325.             if (_cairo_rectangle_intersect (&rects[count], extents))
  326.                 count++;
  327.         }
  328.  
  329.         if (_cairo_path_fixed_iter_at_end (&iter))
  330.             region = cairo_region_create_rectangles (rects, count);
  331.  
  332. TESSELLATE:
  333.         if (rects != rectangle_stack)
  334.             free (rects);
  335.     }
  336.  
  337.     if (region == NULL) {
  338.         /* Hmm, complex polygon */
  339.         region = _cairo_path_fixed_fill_rectilinear_tessellate_to_region (path,
  340.                                                                           fill_rule,
  341.                                                                           extents);
  342.  
  343.  
  344.     }
  345.  
  346.     return region;
  347. }
  348.  
  349. cairo_int_status_t
  350. _cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path,
  351.                                              cairo_fill_rule_t fill_rule,
  352.                                              cairo_traps_t *traps)
  353. {
  354.     cairo_box_t box;
  355.     cairo_status_t status;
  356.  
  357.     traps->is_rectilinear = TRUE;
  358.     traps->is_rectangular = TRUE;
  359.  
  360.     if (_cairo_path_fixed_is_box (path, &box)) {
  361.         return _cairo_traps_tessellate_rectangle (traps, &box.p1, &box.p2);
  362.     } else {
  363.         cairo_path_fixed_iter_t iter;
  364.  
  365.         _cairo_path_fixed_iter_init (&iter, path);
  366.         while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
  367.             if (box.p1.y > box.p2.y) {
  368.                 cairo_fixed_t t;
  369.  
  370.                 t = box.p1.y;
  371.                 box.p1.y = box.p2.y;
  372.                 box.p2.y = t;
  373.  
  374.                 t = box.p1.x;
  375.                 box.p1.x = box.p2.x;
  376.                 box.p2.x = t;
  377.             }
  378.  
  379.             status = _cairo_traps_tessellate_rectangle (traps,
  380.                                                         &box.p1, &box.p2);
  381.             if (unlikely (status)) {
  382.                 _cairo_traps_clear (traps);
  383.                 return status;
  384.             }
  385.         }
  386.  
  387.         if (_cairo_path_fixed_iter_at_end (&iter))
  388.             return _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, fill_rule);
  389.  
  390.         _cairo_traps_clear (traps);
  391.         return CAIRO_INT_STATUS_UNSUPPORTED;
  392.     }
  393. }
  394.  
  395. static cairo_status_t
  396. _cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (const cairo_path_fixed_t *path,
  397.                                                         cairo_fill_rule_t fill_rule,
  398.                                                         cairo_boxes_t *boxes)
  399. {
  400.     cairo_polygon_t polygon;
  401.     cairo_status_t status;
  402.  
  403.     _cairo_polygon_init (&polygon);
  404.     if (boxes->num_limits) {
  405.         _cairo_polygon_limit (&polygon, boxes->limits, boxes->num_limits);
  406.         boxes->num_limits = 0;
  407.     }
  408.  
  409.     /* tolerance will be ignored as the path is rectilinear */
  410.     status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon);
  411.     if (likely (status == CAIRO_STATUS_SUCCESS)) {
  412.         status =
  413.             _cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (&polygon,
  414.                                                                             fill_rule,
  415.                                                                             boxes);
  416.     }
  417.  
  418.     _cairo_polygon_fini (&polygon);
  419.  
  420.     return status;
  421. }
  422.  
  423. cairo_status_t
  424. _cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path,
  425.                                              cairo_fill_rule_t fill_rule,
  426.                                              cairo_boxes_t *boxes)
  427. {
  428.     cairo_path_fixed_iter_t iter;
  429.     cairo_status_t status;
  430.     cairo_box_t box;
  431.  
  432.     if (_cairo_path_fixed_is_box (path, &box))
  433.         return _cairo_boxes_add (boxes, &box);
  434.  
  435.     _cairo_path_fixed_iter_init (&iter, path);
  436.     while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
  437.         if (box.p1.y == box.p2.y || box.p1.x == box.p2.x)
  438.             continue;
  439.  
  440.         if (box.p1.y > box.p2.y) {
  441.             cairo_fixed_t t;
  442.  
  443.             t = box.p1.y;
  444.             box.p1.y = box.p2.y;
  445.             box.p2.y = t;
  446.  
  447.             t = box.p1.x;
  448.             box.p1.x = box.p2.x;
  449.             box.p2.x = t;
  450.         }
  451.  
  452.         status = _cairo_boxes_add (boxes, &box);
  453.         if (unlikely (status))
  454.             return status;
  455.     }
  456.  
  457.     if (_cairo_path_fixed_iter_at_end (&iter))
  458.         return _cairo_bentley_ottmann_tessellate_boxes (boxes, fill_rule, boxes);
  459.  
  460.     /* path is not rectangular, try extracting clipped rectilinear edges */
  461.     _cairo_boxes_clear (boxes);
  462.     return _cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (path,
  463.                                                                    fill_rule,
  464.                                                                    boxes);
  465. }
  466.