Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright © 2004 Carl Worth
  3.  * Copyright © 2006 Red Hat, Inc.
  4.  * Copyright © 2008 Chris Wilson
  5.  * Copyright © 2011 Intel Corporation
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it either under the terms of the GNU Lesser General Public
  9.  * License version 2.1 as published by the Free Software Foundation
  10.  * (the "LGPL") or, at your option, under the terms of the Mozilla
  11.  * Public License Version 1.1 (the "MPL"). If you do not alter this
  12.  * notice, a recipient may use your version of this file under either
  13.  * the MPL or the LGPL.
  14.  *
  15.  * You should have received a copy of the LGPL along with this library
  16.  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
  17.  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
  18.  * You should have received a copy of the MPL along with this library
  19.  * in the file COPYING-MPL-1.1
  20.  *
  21.  * The contents of this file are subject to the Mozilla Public License
  22.  * Version 1.1 (the "License"); you may not use this file except in
  23.  * compliance with the License. You may obtain a copy of the License at
  24.  * http://www.mozilla.org/MPL/
  25.  *
  26.  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
  27.  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
  28.  * the specific language governing rights and limitations.
  29.  *
  30.  * The Original Code is the cairo graphics library.
  31.  *
  32.  * The Initial Developer of the Original Code is Carl Worth
  33.  *
  34.  * Contributor(s):
  35.  *      Carl D. Worth <cworth@cworth.org>
  36.  *      Chris Wilson <chris@chris-wilson.co.uk>
  37.  */
  38.  
  39. typedef unsigned long long uint64_t;
  40.  
  41. #include "cairoint.h"
  42.  
  43. #include "cairo-error-private.h"
  44. #include "cairo-freelist-private.h"
  45. #include "cairo-combsort-inline.h"
  46. #include "cairo-contour-inline.h"
  47. #include "cairo-contour-private.h"
  48.  
  49. void
  50. _cairo_contour_init (cairo_contour_t *contour,
  51.                      int direction)
  52. {
  53.     contour->direction = direction;
  54.     contour->chain.points = contour->embedded_points;
  55.     contour->chain.next = NULL;
  56.     contour->chain.num_points = 0;
  57.     contour->chain.size_points = ARRAY_LENGTH (contour->embedded_points);
  58.     contour->tail = &contour->chain;
  59. }
  60.  
  61. cairo_int_status_t
  62. __cairo_contour_add_point (cairo_contour_t *contour,
  63.                           const cairo_point_t *point)
  64. {
  65.     cairo_contour_chain_t *tail = contour->tail;
  66.     cairo_contour_chain_t *next;
  67.  
  68.     assert (tail->next == NULL);
  69.  
  70.     next = _cairo_malloc_ab_plus_c (tail->size_points*2,
  71.                                     sizeof (cairo_point_t),
  72.                                     sizeof (cairo_contour_chain_t));
  73.     if (unlikely (next == NULL))
  74.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  75.  
  76.     next->size_points = tail->size_points*2;
  77.     next->num_points = 1;
  78.     next->points = (cairo_point_t *)(next+1);
  79.     next->next = NULL;
  80.     tail->next = next;
  81.     contour->tail = next;
  82.  
  83.     next->points[0] = *point;
  84.     return CAIRO_INT_STATUS_SUCCESS;
  85. }
  86.  
  87. static void
  88. first_inc (cairo_contour_t *contour,
  89.            cairo_point_t **p,
  90.            cairo_contour_chain_t **chain)
  91. {
  92.     if (*p == (*chain)->points + (*chain)->num_points) {
  93.         assert ((*chain)->next);
  94.         *chain = (*chain)->next;
  95.         *p = &(*chain)->points[0];
  96.     } else
  97.         ++*p;
  98. }
  99.  
  100. static void
  101. last_dec (cairo_contour_t *contour,
  102.           cairo_point_t **p,
  103.           cairo_contour_chain_t **chain)
  104. {
  105.     if (*p == (*chain)->points) {
  106.         cairo_contour_chain_t *prev;
  107.         assert (*chain != &contour->chain);
  108.         for (prev = &contour->chain; prev->next != *chain; prev = prev->next)
  109.             ;
  110.         *chain = prev;
  111.         *p = &(*chain)->points[(*chain)->num_points-1];
  112.     } else
  113.         --*p;
  114. }
  115.  
  116. void
  117. _cairo_contour_reverse (cairo_contour_t *contour)
  118. {
  119.     cairo_contour_chain_t *first_chain, *last_chain;
  120.     cairo_point_t *first, *last;
  121.  
  122.     contour->direction = -contour->direction;
  123.  
  124.     if (contour->chain.num_points <= 1)
  125.         return;
  126.  
  127.     first_chain = &contour->chain;
  128.     last_chain = contour->tail;
  129.  
  130.     first = &first_chain->points[0];
  131.     last = &last_chain->points[last_chain->num_points-1];
  132.  
  133.     while (first != last) {
  134.         cairo_point_t p;
  135.  
  136.         p = *first;
  137.         *first = *last;
  138.         *last = p;
  139.  
  140.         first_inc (contour, &first, &first_chain);
  141.         last_dec (contour, &last, &last_chain);
  142.     }
  143. }
  144.  
  145. cairo_int_status_t
  146. _cairo_contour_add (cairo_contour_t *dst,
  147.                     const cairo_contour_t *src)
  148. {
  149.     const cairo_contour_chain_t *chain;
  150.     cairo_int_status_t status;
  151.     int i;
  152.  
  153.     for (chain = &src->chain; chain; chain = chain->next) {
  154.         for (i = 0; i < chain->num_points; i++) {
  155.             status = _cairo_contour_add_point (dst, &chain->points[i]);
  156.             if (unlikely (status))
  157.                 return status;
  158.         }
  159.     }
  160.  
  161.     return CAIRO_INT_STATUS_SUCCESS;
  162. }
  163.  
  164. static inline cairo_bool_t
  165. iter_next (cairo_contour_iter_t *iter)
  166. {
  167.     if (iter->point == &iter->chain->points[iter->chain->size_points-1]) {
  168.         iter->chain = iter->chain->next;
  169.         if (iter->chain == NULL)
  170.             return FALSE;
  171.  
  172.         iter->point = &iter->chain->points[0];
  173.         return TRUE;
  174.     } else {
  175.         iter->point++;
  176.         return TRUE;
  177.     }
  178. }
  179.  
  180. static cairo_bool_t
  181. iter_equal (const cairo_contour_iter_t *i1,
  182.             const cairo_contour_iter_t *i2)
  183. {
  184.     return i1->chain == i2->chain && i1->point == i2->point;
  185. }
  186.  
  187. static void
  188. iter_init (cairo_contour_iter_t *iter, cairo_contour_t *contour)
  189. {
  190.     iter->chain = &contour->chain;
  191.     iter->point = &contour->chain.points[0];
  192. }
  193.  
  194. static void
  195. iter_init_last (cairo_contour_iter_t *iter, cairo_contour_t *contour)
  196. {
  197.     iter->chain = contour->tail;
  198.     iter->point = &contour->tail->points[contour->tail->num_points-1];
  199. }
  200.  
  201. static const cairo_contour_chain_t *prev_const_chain(const cairo_contour_t *contour,
  202.                                                      const cairo_contour_chain_t *chain)
  203. {
  204.     const cairo_contour_chain_t *prev;
  205.  
  206.     if (chain == &contour->chain)
  207.         return NULL;
  208.  
  209.     for (prev = &contour->chain; prev->next != chain; prev = prev->next)
  210.         ;
  211.  
  212.     return prev;
  213. }
  214.  
  215. cairo_int_status_t
  216. _cairo_contour_add_reversed (cairo_contour_t *dst,
  217.                              const cairo_contour_t *src)
  218. {
  219.     const cairo_contour_chain_t *last;
  220.     cairo_int_status_t status;
  221.     int i;
  222.  
  223.     if (src->chain.num_points == 0)
  224.         return CAIRO_INT_STATUS_SUCCESS;
  225.  
  226.     for (last = src->tail; last; last = prev_const_chain (src, last)) {
  227.         for (i = last->num_points-1; i >= 0; i--) {
  228.             status = _cairo_contour_add_point (dst, &last->points[i]);
  229.             if (unlikely (status))
  230.                 return status;
  231.         }
  232.     }
  233.  
  234.     return CAIRO_INT_STATUS_SUCCESS;
  235. }
  236.  
  237. static cairo_uint64_t
  238. point_distance_sq (const cairo_point_t *p1,
  239.                    const cairo_point_t *p2)
  240. {
  241.     int32_t dx = p1->x - p2->x;
  242.     int32_t dy = p1->y - p2->y;
  243.     return _cairo_int64_add(_cairo_int32x32_64_mul (dx, dx), _cairo_int32x32_64_mul (dy, dy));
  244. }
  245.  
  246. #define DELETED(p) ((p)->x == INT_MIN && (p)->y == INT_MAX)
  247. #define MARK_DELETED(p) ((p)->x = INT_MIN, (p)->y = INT_MAX)
  248.  
  249. static cairo_bool_t
  250. _cairo_contour_simplify_chain (cairo_contour_t *contour, const double tolerance,
  251.                                const cairo_contour_iter_t *first,
  252.                                const cairo_contour_iter_t *last)
  253. {
  254.     cairo_contour_iter_t iter, furthest;
  255.     uint64_t max_error;
  256.     int x0, y0;
  257.     int nx, ny;
  258.     int count;
  259.  
  260.     iter = *first;
  261.     iter_next (&iter);
  262.     if (iter_equal (&iter, last))
  263.         return FALSE;
  264.  
  265.     x0 = first->point->x;
  266.     y0 = first->point->y;
  267.     nx = last->point->y - y0;
  268.     ny = x0 - last->point->x;
  269.  
  270.     count = 0;
  271.     max_error = 0;
  272.     do {
  273.         cairo_point_t *p = iter.point;
  274.         if (! DELETED(p)) {
  275.             uint64_t d = (uint64_t)nx * (x0 - p->x) + (uint64_t)ny * (y0 - p->y);
  276.             if (d * d > max_error) {
  277.                 max_error = d * d;
  278.                 furthest = iter;
  279.             }
  280.             count++;
  281.         }
  282.         iter_next (&iter);
  283.     } while (! iter_equal (&iter, last));
  284.     if (count == 0)
  285.         return FALSE;
  286.  
  287.     if (max_error > tolerance * ((uint64_t)nx * nx + (uint64_t)ny * ny)) {
  288.         cairo_bool_t simplified;
  289.  
  290.         simplified = FALSE;
  291.         simplified |= _cairo_contour_simplify_chain (contour, tolerance,
  292.                                                      first, &furthest);
  293.         simplified |= _cairo_contour_simplify_chain (contour, tolerance,
  294.                                                      &furthest, last);
  295.         return simplified;
  296.     } else {
  297.         iter = *first;
  298.         iter_next (&iter);
  299.         do {
  300.             MARK_DELETED (iter.point);
  301.             iter_next (&iter);
  302.         } while (! iter_equal (&iter, last));
  303.  
  304.         return TRUE;
  305.     }
  306. }
  307.  
  308. void
  309. _cairo_contour_simplify (cairo_contour_t *contour, double tolerance)
  310. {
  311.     cairo_contour_chain_t *chain;
  312.     cairo_point_t *last = NULL;
  313.     cairo_contour_iter_t iter, furthest;
  314.     cairo_bool_t simplified;
  315.     uint64_t max = 0;
  316.     int i;
  317.  
  318.     if (contour->chain.num_points <= 2)
  319.         return;
  320.  
  321.     tolerance = tolerance * CAIRO_FIXED_ONE;
  322.     tolerance *= tolerance;
  323.  
  324.     /* stage 1: vertex reduction */
  325.     for (chain = &contour->chain; chain; chain = chain->next) {
  326.         for (i = 0; i < chain->num_points; i++) {
  327.             if (last == NULL ||
  328.         _cairo_uint64_to_double(point_distance_sq (last, &chain->points[i])) > tolerance) {
  329.                 last = &chain->points[i];
  330.             } else {
  331.                 MARK_DELETED (&chain->points[i]);
  332.             }
  333.         }
  334.     }
  335.  
  336.     /* stage2: polygon simplification using Douglas-Peucker */
  337.     simplified = FALSE;
  338.     do {
  339.         last = &contour->chain.points[0];
  340.         iter_init (&furthest, contour);
  341.         max = 0;
  342.         for (chain = &contour->chain; chain; chain = chain->next) {
  343.             for (i = 0; i < chain->num_points; i++) {
  344.                 uint64_t d;
  345.  
  346.                 if (DELETED (&chain->points[i]))
  347.                     continue;
  348.  
  349.                 d = point_distance_sq (last, &chain->points[i]);
  350.                 if (d > max) {
  351.                     furthest.chain = chain;
  352.                     furthest.point = &chain->points[i];
  353.                     max = d;
  354.                 }
  355.             }
  356.         }
  357.         assert (max);
  358.  
  359.         simplified = FALSE;
  360.         iter_init (&iter, contour);
  361.         simplified |= _cairo_contour_simplify_chain (contour, tolerance,
  362.                                                      &iter, &furthest);
  363.  
  364.         iter_init_last (&iter, contour);
  365.         if (! iter_equal (&furthest, &iter))
  366.             simplified |= _cairo_contour_simplify_chain (contour, tolerance,
  367.                                                          &furthest, &iter);
  368.     } while (simplified);
  369.  
  370.     iter_init (&iter, contour);
  371.     for (chain = &contour->chain; chain; chain = chain->next) {
  372.         int num_points = chain->num_points;
  373.         chain->num_points = 0;
  374.         for (i = 0; i < num_points; i++) {
  375.             if (! DELETED(&chain->points[i])) {
  376.                 if (iter.point != &chain->points[i])
  377.                     *iter.point = chain->points[i];
  378.                 iter.chain->num_points++;
  379.                 iter_next (&iter);
  380.             }
  381.         }
  382.     }
  383.  
  384.     if (iter.chain) {
  385.         cairo_contour_chain_t *next;
  386.  
  387.         for (chain = iter.chain->next; chain; chain = next) {
  388.             next = chain->next;
  389.             free (chain);
  390.         }
  391.  
  392.         iter.chain->next = NULL;
  393.         contour->tail = iter.chain;
  394.     }
  395. }
  396.  
  397. void
  398. _cairo_contour_reset (cairo_contour_t *contour)
  399. {
  400.     _cairo_contour_fini (contour);
  401.     _cairo_contour_init (contour, contour->direction);
  402. }
  403.  
  404. void
  405. _cairo_contour_fini (cairo_contour_t *contour)
  406. {
  407.     cairo_contour_chain_t *chain, *next;
  408.  
  409.     for (chain = contour->chain.next; chain; chain = next) {
  410.         next = chain->next;
  411.         free (chain);
  412.     }
  413. }
  414.  
  415. void
  416. _cairo_debug_print_contour (FILE *file, cairo_contour_t *contour)
  417. {
  418.     cairo_contour_chain_t *chain;
  419.     int num_points, size_points;
  420.     int i;
  421.  
  422.     num_points = 0;
  423.     size_points = 0;
  424.     for (chain = &contour->chain; chain; chain = chain->next) {
  425.         num_points += chain->num_points;
  426.         size_points += chain->size_points;
  427.     }
  428.  
  429.     fprintf (file, "contour: direction=%d, num_points=%d / %d\n",
  430.              contour->direction, num_points, size_points);
  431.  
  432.     num_points = 0;
  433.     for (chain = &contour->chain; chain; chain = chain->next) {
  434.         for (i = 0; i < chain->num_points; i++) {
  435.             fprintf (file, "  [%d] = (%f, %f)\n",
  436.                      num_points++,
  437.                      _cairo_fixed_to_double (chain->points[i].x),
  438.                      _cairo_fixed_to_double (chain->points[i].y));
  439.         }
  440.     }
  441. }
  442.  
  443. void
  444. __cairo_contour_remove_last_chain (cairo_contour_t *contour)
  445. {
  446.     cairo_contour_chain_t *chain;
  447.  
  448.     if (contour->tail == &contour->chain)
  449.         return;
  450.  
  451.     for (chain = &contour->chain; chain->next != contour->tail; chain = chain->next)
  452.         ;
  453.     free (contour->tail);
  454.     contour->tail = chain;
  455.     chain->next = NULL;
  456. }
  457.