Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright © 2000 SuSE, Inc.
  3.  * Copyright © 2007 Red Hat, Inc.
  4.  * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
  5.  *             2005 Lars Knoll & Zack Rusin, Trolltech
  6.  *
  7.  * Permission to use, copy, modify, distribute, and sell this software and its
  8.  * documentation for any purpose is hereby granted without fee, provided that
  9.  * the above copyright notice appear in all copies and that both that
  10.  * copyright notice and this permission notice appear in supporting
  11.  * documentation, and that the name of Keith Packard not be used in
  12.  * advertising or publicity pertaining to distribution of the software without
  13.  * specific, written prior permission.  Keith Packard makes no
  14.  * representations about the suitability of this software for any purpose.  It
  15.  * is provided "as is" without express or implied warranty.
  16.  *
  17.  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
  18.  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  19.  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
  20.  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  21.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  22.  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  23.  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  24.  * SOFTWARE.
  25.  */
  26.  
  27. #ifdef HAVE_CONFIG_H
  28. #include <config.h>
  29. #endif
  30.  
  31. #include <stdlib.h>
  32. #include <math.h>
  33. #include "pixman-private.h"
  34.  
  35. static force_inline double
  36. coordinates_to_parameter (double x, double y, double angle)
  37. {
  38.     double t;
  39.  
  40.     t = atan2 (y, x) + angle;
  41.  
  42.     while (t < 0)
  43.         t += 2 * M_PI;
  44.  
  45.     while (t >= 2 * M_PI)
  46.         t -= 2 * M_PI;
  47.  
  48.     return 1 - t * (1 / (2 * M_PI)); /* Scale t to [0, 1] and
  49.                                       * make rotation CCW
  50.                                       */
  51. }
  52.  
  53. static uint32_t *
  54. conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
  55. {
  56.     pixman_image_t *image = iter->image;
  57.     int x = iter->x;
  58.     int y = iter->y;
  59.     int width = iter->width;
  60.     uint32_t *buffer = iter->buffer;
  61.  
  62.     gradient_t *gradient = (gradient_t *)image;
  63.     conical_gradient_t *conical = (conical_gradient_t *)image;
  64.     uint32_t       *end = buffer + width;
  65.     pixman_gradient_walker_t walker;
  66.     pixman_bool_t affine = TRUE;
  67.     double cx = 1.;
  68.     double cy = 0.;
  69.     double cz = 0.;
  70.     double rx = x + 0.5;
  71.     double ry = y + 0.5;
  72.     double rz = 1.;
  73.  
  74.     _pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
  75.  
  76.     if (image->common.transform)
  77.     {
  78.         pixman_vector_t v;
  79.  
  80.         /* reference point is the center of the pixel */
  81.         v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
  82.         v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
  83.         v.vector[2] = pixman_fixed_1;
  84.  
  85.         if (!pixman_transform_point_3d (image->common.transform, &v))
  86.             return iter->buffer;
  87.  
  88.         cx = image->common.transform->matrix[0][0] / 65536.;
  89.         cy = image->common.transform->matrix[1][0] / 65536.;
  90.         cz = image->common.transform->matrix[2][0] / 65536.;
  91.  
  92.         rx = v.vector[0] / 65536.;
  93.         ry = v.vector[1] / 65536.;
  94.         rz = v.vector[2] / 65536.;
  95.  
  96.         affine =
  97.             image->common.transform->matrix[2][0] == 0 &&
  98.             v.vector[2] == pixman_fixed_1;
  99.     }
  100.  
  101.     if (affine)
  102.     {
  103.         rx -= conical->center.x / 65536.;
  104.         ry -= conical->center.y / 65536.;
  105.  
  106.         while (buffer < end)
  107.         {
  108.             if (!mask || *mask++)
  109.             {
  110.                 double t = coordinates_to_parameter (rx, ry, conical->angle);
  111.  
  112.                 *buffer = _pixman_gradient_walker_pixel (
  113.                     &walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t));
  114.             }
  115.  
  116.             ++buffer;
  117.  
  118.             rx += cx;
  119.             ry += cy;
  120.         }
  121.     }
  122.     else
  123.     {
  124.         while (buffer < end)
  125.         {
  126.             double x, y;
  127.  
  128.             if (!mask || *mask++)
  129.             {
  130.                 double t;
  131.  
  132.                 if (rz != 0)
  133.                 {
  134.                     x = rx / rz;
  135.                     y = ry / rz;
  136.                 }
  137.                 else
  138.                 {
  139.                     x = y = 0.;
  140.                 }
  141.  
  142.                 x -= conical->center.x / 65536.;
  143.                 y -= conical->center.y / 65536.;
  144.  
  145.                 t = coordinates_to_parameter (x, y, conical->angle);
  146.  
  147.                 *buffer = _pixman_gradient_walker_pixel (
  148.                     &walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t));
  149.             }
  150.  
  151.             ++buffer;
  152.  
  153.             rx += cx;
  154.             ry += cy;
  155.             rz += cz;
  156.         }
  157.     }
  158.  
  159.     iter->y++;
  160.     return iter->buffer;
  161. }
  162.  
  163. static uint32_t *
  164. conical_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
  165. {
  166.     uint32_t *buffer = conical_get_scanline_narrow (iter, NULL);
  167.  
  168.     pixman_expand_to_float (
  169.         (argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
  170.  
  171.     return buffer;
  172. }
  173.  
  174. void
  175. _pixman_conical_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter)
  176. {
  177.     if (iter->iter_flags & ITER_NARROW)
  178.         iter->get_scanline = conical_get_scanline_narrow;
  179.     else
  180.         iter->get_scanline = conical_get_scanline_wide;
  181. }
  182.  
  183. PIXMAN_EXPORT pixman_image_t *
  184. pixman_image_create_conical_gradient (const pixman_point_fixed_t *  center,
  185.                                       pixman_fixed_t                angle,
  186.                                       const pixman_gradient_stop_t *stops,
  187.                                       int                           n_stops)
  188. {
  189.     pixman_image_t *image = _pixman_image_allocate ();
  190.     conical_gradient_t *conical;
  191.  
  192.     if (!image)
  193.         return NULL;
  194.  
  195.     conical = &image->conical;
  196.  
  197.     if (!_pixman_init_gradient (&conical->common, stops, n_stops))
  198.     {
  199.         free (image);
  200.         return NULL;
  201.     }
  202.  
  203.     angle = MOD (angle, pixman_int_to_fixed (360));
  204.  
  205.     image->type = CONICAL;
  206.  
  207.     conical->center = *center;
  208.     conical->angle = (pixman_fixed_to_double (angle) / 180.0) * M_PI;
  209.  
  210.     return image;
  211. }
  212.  
  213.