Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
  2. /*
  3.  * Copyright © 2000 SuSE, Inc.
  4.  * Copyright © 2007 Red Hat, Inc.
  5.  * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
  6.  *             2005 Lars Knoll & Zack Rusin, Trolltech
  7.  *
  8.  * Permission to use, copy, modify, distribute, and sell this software and its
  9.  * documentation for any purpose is hereby granted without fee, provided that
  10.  * the above copyright notice appear in all copies and that both that
  11.  * copyright notice and this permission notice appear in supporting
  12.  * documentation, and that the name of Keith Packard not be used in
  13.  * advertising or publicity pertaining to distribution of the software without
  14.  * specific, written prior permission.  Keith Packard makes no
  15.  * representations about the suitability of this software for any purpose.  It
  16.  * is provided "as is" without express or implied warranty.
  17.  *
  18.  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
  19.  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  20.  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
  21.  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  22.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  23.  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  24.  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  25.  * SOFTWARE.
  26.  */
  27.  
  28. #ifdef HAVE_CONFIG_H
  29. #include <config.h>
  30. #endif
  31. #include <stdlib.h>
  32. #include "pixman-private.h"
  33.  
  34. static pixman_bool_t
  35. linear_gradient_is_horizontal (pixman_image_t *image,
  36.                                int             x,
  37.                                int             y,
  38.                                int             width,
  39.                                int             height)
  40. {
  41.     linear_gradient_t *linear = (linear_gradient_t *)image;
  42.     pixman_vector_t v;
  43.     pixman_fixed_32_32_t l;
  44.     pixman_fixed_48_16_t dx, dy;
  45.     double inc;
  46.  
  47.     if (image->common.transform)
  48.     {
  49.         /* projective transformation */
  50.         if (image->common.transform->matrix[2][0] != 0 ||
  51.             image->common.transform->matrix[2][1] != 0 ||
  52.             image->common.transform->matrix[2][2] == 0)
  53.         {
  54.             return FALSE;
  55.         }
  56.  
  57.         v.vector[0] = image->common.transform->matrix[0][1];
  58.         v.vector[1] = image->common.transform->matrix[1][1];
  59.         v.vector[2] = image->common.transform->matrix[2][2];
  60.     }
  61.     else
  62.     {
  63.         v.vector[0] = 0;
  64.         v.vector[1] = pixman_fixed_1;
  65.         v.vector[2] = pixman_fixed_1;
  66.     }
  67.  
  68.     dx = linear->p2.x - linear->p1.x;
  69.     dy = linear->p2.y - linear->p1.y;
  70.  
  71.     l = dx * dx + dy * dy;
  72.  
  73.     if (l == 0)
  74.         return FALSE;
  75.  
  76.     /*
  77.      * compute how much the input of the gradient walked changes
  78.      * when moving vertically through the whole image
  79.      */
  80.     inc = height * (double) pixman_fixed_1 * pixman_fixed_1 *
  81.         (dx * v.vector[0] + dy * v.vector[1]) /
  82.         (v.vector[2] * (double) l);
  83.  
  84.     /* check that casting to integer would result in 0 */
  85.     if (-1 < inc && inc < 1)
  86.         return TRUE;
  87.  
  88.     return FALSE;
  89. }
  90.  
  91. static uint32_t *
  92. linear_get_scanline_narrow (pixman_iter_t  *iter,
  93.                             const uint32_t *mask)
  94. {
  95.     pixman_image_t *image  = iter->image;
  96.     int             x      = iter->x;
  97.     int             y      = iter->y;
  98.     int             width  = iter->width;
  99.     uint32_t *      buffer = iter->buffer;
  100.  
  101.     pixman_vector_t v, unit;
  102.     pixman_fixed_32_32_t l;
  103.     pixman_fixed_48_16_t dx, dy;
  104.     gradient_t *gradient = (gradient_t *)image;
  105.     linear_gradient_t *linear = (linear_gradient_t *)image;
  106.     uint32_t *end = buffer + width;
  107.     pixman_gradient_walker_t walker;
  108.  
  109.     _pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
  110.  
  111.     /* reference point is the center of the pixel */
  112.     v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
  113.     v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
  114.     v.vector[2] = pixman_fixed_1;
  115.  
  116.     if (image->common.transform)
  117.     {
  118.         if (!pixman_transform_point_3d (image->common.transform, &v))
  119.             return iter->buffer;
  120.  
  121.         unit.vector[0] = image->common.transform->matrix[0][0];
  122.         unit.vector[1] = image->common.transform->matrix[1][0];
  123.         unit.vector[2] = image->common.transform->matrix[2][0];
  124.     }
  125.     else
  126.     {
  127.         unit.vector[0] = pixman_fixed_1;
  128.         unit.vector[1] = 0;
  129.         unit.vector[2] = 0;
  130.     }
  131.  
  132.     dx = linear->p2.x - linear->p1.x;
  133.     dy = linear->p2.y - linear->p1.y;
  134.  
  135.     l = dx * dx + dy * dy;
  136.  
  137.     if (l == 0 || unit.vector[2] == 0)
  138.     {
  139.         /* affine transformation only */
  140.         pixman_fixed_32_32_t t, next_inc;
  141.         double inc;
  142.  
  143.         if (l == 0 || v.vector[2] == 0)
  144.         {
  145.             t = 0;
  146.             inc = 0;
  147.         }
  148.         else
  149.         {
  150.             double invden, v2;
  151.  
  152.             invden = pixman_fixed_1 * (double) pixman_fixed_1 /
  153.                 (l * (double) v.vector[2]);
  154.             v2 = v.vector[2] * (1. / pixman_fixed_1);
  155.             t = ((dx * v.vector[0] + dy * v.vector[1]) -
  156.                  (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
  157.             inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden;
  158.         }
  159.         next_inc = 0;
  160.  
  161.         if (((pixman_fixed_32_32_t )(inc * width)) == 0)
  162.         {
  163.             register uint32_t color;
  164.  
  165.             color = _pixman_gradient_walker_pixel (&walker, t);
  166.             while (buffer < end)
  167.                 *buffer++ = color;
  168.         }
  169.         else
  170.         {
  171.             int i;
  172.  
  173.             i = 0;
  174.             while (buffer < end)
  175.             {
  176.                 if (!mask || *mask++)
  177.                 {
  178.                     *buffer = _pixman_gradient_walker_pixel (&walker,
  179.                                                              t + next_inc);
  180.                 }
  181.                 i++;
  182.                 next_inc = inc * i;
  183.                 buffer++;
  184.             }
  185.         }
  186.     }
  187.     else
  188.     {
  189.         /* projective transformation */
  190.         double t;
  191.  
  192.         t = 0;
  193.  
  194.         while (buffer < end)
  195.         {
  196.             if (!mask || *mask++)
  197.             {
  198.                 if (v.vector[2] != 0)
  199.                 {
  200.                     double invden, v2;
  201.  
  202.                     invden = pixman_fixed_1 * (double) pixman_fixed_1 /
  203.                         (l * (double) v.vector[2]);
  204.                     v2 = v.vector[2] * (1. / pixman_fixed_1);
  205.                     t = ((dx * v.vector[0] + dy * v.vector[1]) -
  206.                          (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
  207.                 }
  208.  
  209.                 *buffer = _pixman_gradient_walker_pixel (&walker, t);
  210.             }
  211.  
  212.             ++buffer;
  213.  
  214.             v.vector[0] += unit.vector[0];
  215.             v.vector[1] += unit.vector[1];
  216.             v.vector[2] += unit.vector[2];
  217.         }
  218.     }
  219.  
  220.     iter->y++;
  221.  
  222.     return iter->buffer;
  223. }
  224.  
  225. static uint32_t *
  226. linear_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
  227. {
  228.     uint32_t *buffer = linear_get_scanline_narrow (iter, NULL);
  229.  
  230.     pixman_expand_to_float (
  231.         (argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
  232.  
  233.     return buffer;
  234. }
  235.  
  236. void
  237. _pixman_linear_gradient_iter_init (pixman_image_t *image, pixman_iter_t  *iter)
  238. {
  239.     if (linear_gradient_is_horizontal (
  240.             iter->image, iter->x, iter->y, iter->width, iter->height))
  241.     {
  242.         if (iter->iter_flags & ITER_NARROW)
  243.             linear_get_scanline_narrow (iter, NULL);
  244.         else
  245.             linear_get_scanline_wide (iter, NULL);
  246.  
  247.         iter->get_scanline = _pixman_iter_get_scanline_noop;
  248.     }
  249.     else
  250.     {
  251.         if (iter->iter_flags & ITER_NARROW)
  252.             iter->get_scanline = linear_get_scanline_narrow;
  253.         else
  254.             iter->get_scanline = linear_get_scanline_wide;
  255.     }
  256. }
  257.  
  258. PIXMAN_EXPORT pixman_image_t *
  259. pixman_image_create_linear_gradient (const pixman_point_fixed_t *  p1,
  260.                                      const pixman_point_fixed_t *  p2,
  261.                                      const pixman_gradient_stop_t *stops,
  262.                                      int                           n_stops)
  263. {
  264.     pixman_image_t *image;
  265.     linear_gradient_t *linear;
  266.  
  267.     image = _pixman_image_allocate ();
  268.  
  269.     if (!image)
  270.         return NULL;
  271.  
  272.     linear = &image->linear;
  273.  
  274.     if (!_pixman_init_gradient (&linear->common, stops, n_stops))
  275.     {
  276.         free (image);
  277.         return NULL;
  278.     }
  279.  
  280.     linear->p1 = *p1;
  281.     linear->p2 = *p2;
  282.  
  283.     image->type = LINEAR;
  284.  
  285.     return image;
  286. }
  287.  
  288.