Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | 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 source_image_class_t
  35. linear_gradient_classify (pixman_image_t *image,
  36.                           int             x,
  37.                           int             y,
  38.                           int             width,
  39.                           int             height)
  40. {
  41.     source_image_t *source = (source_image_t *)image;
  42.     linear_gradient_t *linear = (linear_gradient_t *)image;
  43.     pixman_vector_t v;
  44.     pixman_fixed_32_32_t l;
  45.     pixman_fixed_48_16_t dx, dy;
  46.     double inc;
  47.     source_image_class_t class;
  48.  
  49.     class = SOURCE_IMAGE_CLASS_UNKNOWN;
  50.  
  51.     if (source->common.transform)
  52.     {
  53.         /* projective transformation */
  54.         if (source->common.transform->matrix[2][0] != 0 ||
  55.             source->common.transform->matrix[2][1] != 0 ||
  56.             source->common.transform->matrix[2][2] == 0)
  57.         {
  58.             return class;
  59.         }
  60.  
  61.         v.vector[0] = source->common.transform->matrix[0][1];
  62.         v.vector[1] = source->common.transform->matrix[1][1];
  63.         v.vector[2] = source->common.transform->matrix[2][2];
  64.     }
  65.     else
  66.     {
  67.         v.vector[0] = 0;
  68.         v.vector[1] = pixman_fixed_1;
  69.         v.vector[2] = pixman_fixed_1;
  70.     }
  71.  
  72.     dx = linear->p2.x - linear->p1.x;
  73.     dy = linear->p2.y - linear->p1.y;
  74.  
  75.     l = dx * dx + dy * dy;
  76.  
  77.     if (l == 0)
  78.         return class;  
  79.  
  80.     /*
  81.      * compute how much the input of the gradient walked changes
  82.      * when moving vertically through the whole image
  83.      */
  84.     inc = height * (double) pixman_fixed_1 * pixman_fixed_1 *
  85.         (dx * v.vector[0] + dy * v.vector[1]) /
  86.         (v.vector[2] * (double) l);
  87.  
  88.     /* check that casting to integer would result in 0 */
  89.     if (-1 < inc && inc < 1)
  90.         class = SOURCE_IMAGE_CLASS_HORIZONTAL;
  91.  
  92.     return class;
  93. }
  94.  
  95. static void
  96. linear_gradient_get_scanline_32 (pixman_image_t *image,
  97.                                  int             x,
  98.                                  int             y,
  99.                                  int             width,
  100.                                  uint32_t *      buffer,
  101.                                  const uint32_t *mask)
  102. {
  103.     pixman_vector_t v, unit;
  104.     pixman_fixed_32_32_t l;
  105.     pixman_fixed_48_16_t dx, dy;
  106.     gradient_t *gradient = (gradient_t *)image;
  107.     source_image_t *source = (source_image_t *)image;
  108.     linear_gradient_t *linear = (linear_gradient_t *)image;
  109.     uint32_t *end = buffer + width;
  110.     pixman_gradient_walker_t walker;
  111.  
  112.     _pixman_gradient_walker_init (&walker, gradient, source->common.repeat);
  113.  
  114.     /* reference point is the center of the pixel */
  115.     v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
  116.     v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
  117.     v.vector[2] = pixman_fixed_1;
  118.  
  119.     if (source->common.transform)
  120.     {
  121.         if (!pixman_transform_point_3d (source->common.transform, &v))
  122.             return;
  123.        
  124.         unit.vector[0] = source->common.transform->matrix[0][0];
  125.         unit.vector[1] = source->common.transform->matrix[1][0];
  126.         unit.vector[2] = source->common.transform->matrix[2][0];
  127.     }
  128.     else
  129.     {
  130.         unit.vector[0] = pixman_fixed_1;
  131.         unit.vector[1] = 0;
  132.         unit.vector[2] = 0;
  133.     }
  134.  
  135.     dx = linear->p2.x - linear->p1.x;
  136.     dy = linear->p2.y - linear->p1.y;
  137.  
  138.     l = dx * dx + dy * dy;
  139.  
  140.     if (l == 0 || unit.vector[2] == 0)
  141.     {
  142.         /* affine transformation only */
  143.         pixman_fixed_32_32_t t, next_inc;
  144.         double inc;
  145.  
  146.         if (l == 0 || v.vector[2] == 0)
  147.         {
  148.             t = 0;
  149.             inc = 0;
  150.         }
  151.         else
  152.         {
  153.             double invden, v2;
  154.  
  155.             invden = pixman_fixed_1 * (double) pixman_fixed_1 /
  156.                 (l * (double) v.vector[2]);
  157.             v2 = v.vector[2] * (1. / pixman_fixed_1);
  158.             t = ((dx * v.vector[0] + dy * v.vector[1]) -
  159.                  (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
  160.             inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden;
  161.         }
  162.         next_inc = 0;
  163.  
  164.         if (((pixman_fixed_32_32_t )(inc * width)) == 0)
  165.         {
  166.             register uint32_t color;
  167.  
  168.             color = _pixman_gradient_walker_pixel (&walker, t);
  169.             while (buffer < end)
  170.                 *buffer++ = color;
  171.         }
  172.         else
  173.         {
  174.             int i;
  175.  
  176.             i = 0;
  177.             while (buffer < end)
  178.             {
  179.                 if (!mask || *mask++)
  180.                 {
  181.                     *buffer = _pixman_gradient_walker_pixel (&walker,
  182.                                                              t + next_inc);
  183.                 }
  184.                 i++;
  185.                 next_inc = inc * i;
  186.                 buffer++;
  187.             }
  188.         }
  189.     }
  190.     else
  191.     {
  192.         /* projective transformation */
  193.         double t;
  194.  
  195.         t = 0;
  196.  
  197.         while (buffer < end)
  198.         {
  199.             if (!mask || *mask++)
  200.             {
  201.                 if (v.vector[2] != 0)
  202.                 {
  203.                     double invden, v2;
  204.  
  205.                     invden = pixman_fixed_1 * (double) pixman_fixed_1 /
  206.                         (l * (double) v.vector[2]);
  207.                     v2 = v.vector[2] * (1. / pixman_fixed_1);
  208.                     t = ((dx * v.vector[0] + dy * v.vector[1]) -
  209.                          (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
  210.                 }
  211.  
  212.                 *buffer = _pixman_gradient_walker_pixel (&walker, t);
  213.             }
  214.  
  215.             ++buffer;
  216.  
  217.             v.vector[0] += unit.vector[0];
  218.             v.vector[1] += unit.vector[1];
  219.             v.vector[2] += unit.vector[2];
  220.         }
  221.     }
  222. }
  223.  
  224. static void
  225. linear_gradient_property_changed (pixman_image_t *image)
  226. {
  227.     image->common.get_scanline_32 = linear_gradient_get_scanline_32;
  228.     image->common.get_scanline_64 = _pixman_image_get_scanline_generic_64;
  229. }
  230.  
  231. PIXMAN_EXPORT pixman_image_t *
  232. pixman_image_create_linear_gradient (pixman_point_fixed_t *        p1,
  233.                                      pixman_point_fixed_t *        p2,
  234.                                      const pixman_gradient_stop_t *stops,
  235.                                      int                           n_stops)
  236. {
  237.     pixman_image_t *image;
  238.     linear_gradient_t *linear;
  239.  
  240.     image = _pixman_image_allocate ();
  241.  
  242.     if (!image)
  243.         return NULL;
  244.  
  245.     linear = &image->linear;
  246.  
  247.     if (!_pixman_init_gradient (&linear->common, stops, n_stops))
  248.     {
  249.         free (image);
  250.         return NULL;
  251.     }
  252.  
  253.     linear->p1 = *p1;
  254.     linear->p2 = *p2;
  255.  
  256.     image->type = LINEAR;
  257.     image->common.classify = linear_gradient_classify;
  258.     image->common.property_changed = linear_gradient_property_changed;
  259.  
  260.     return image;
  261. }
  262.  
  263.