Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  *
  3.  * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
  4.  *             2005 Lars Knoll & Zack Rusin, Trolltech
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and its
  7.  * documentation for any purpose is hereby granted without fee, provided that
  8.  * the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation, and that the name of Keith Packard not be used in
  11.  * advertising or publicity pertaining to distribution of the software without
  12.  * specific, written prior permission.  Keith Packard makes no
  13.  * representations about the suitability of this software for any purpose.  It
  14.  * is provided "as is" without express or implied warranty.
  15.  *
  16.  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
  17.  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  18.  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
  19.  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  20.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  21.  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  22.  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  23.  * SOFTWARE.
  24.  */
  25.  
  26. #ifdef HAVE_CONFIG_H
  27. #include <config.h>
  28. #endif
  29. #include "pixman-private.h"
  30.  
  31. void
  32. _pixman_gradient_walker_init (pixman_gradient_walker_t *walker,
  33.                               gradient_t *              gradient,
  34.                               unsigned int              spread)
  35. {
  36.     walker->num_stops = gradient->n_stops;
  37.     walker->stops     = gradient->stops;
  38.     walker->left_x    = 0;
  39.     walker->right_x   = 0x10000;
  40.     walker->stepper   = 0;
  41.     walker->left_ag   = 0;
  42.     walker->left_rb   = 0;
  43.     walker->right_ag  = 0;
  44.     walker->right_rb  = 0;
  45.     walker->spread    = spread;
  46.  
  47.     walker->need_reset = TRUE;
  48. }
  49.  
  50. void
  51. _pixman_gradient_walker_reset (pixman_gradient_walker_t *walker,
  52.                                pixman_fixed_32_32_t      pos)
  53. {
  54.     int32_t x, left_x, right_x;
  55.     pixman_color_t          *left_c, *right_c;
  56.     int n, count = walker->num_stops;
  57.     pixman_gradient_stop_t *      stops = walker->stops;
  58.  
  59.     static const pixman_color_t transparent_black = { 0, 0, 0, 0 };
  60.  
  61.     switch (walker->spread)
  62.     {
  63.     case PIXMAN_REPEAT_NORMAL:
  64.         x = (int32_t)pos & 0xFFFF;
  65.         for (n = 0; n < count; n++)
  66.             if (x < stops[n].x)
  67.                 break;
  68.         if (n == 0)
  69.         {
  70.             left_x =  stops[count - 1].x - 0x10000;
  71.             left_c = &stops[count - 1].color;
  72.         }
  73.         else
  74.         {
  75.             left_x =  stops[n - 1].x;
  76.             left_c = &stops[n - 1].color;
  77.         }
  78.  
  79.         if (n == count)
  80.         {
  81.             right_x =  stops[0].x + 0x10000;
  82.             right_c = &stops[0].color;
  83.         }
  84.         else
  85.         {
  86.             right_x =  stops[n].x;
  87.             right_c = &stops[n].color;
  88.         }
  89.         left_x  += (pos - x);
  90.         right_x += (pos - x);
  91.         break;
  92.  
  93.     case PIXMAN_REPEAT_PAD:
  94.         for (n = 0; n < count; n++)
  95.             if (pos < stops[n].x)
  96.                 break;
  97.  
  98.         if (n == 0)
  99.         {
  100.             left_x =  INT32_MIN;
  101.             left_c = &stops[0].color;
  102.         }
  103.         else
  104.         {
  105.             left_x =  stops[n - 1].x;
  106.             left_c = &stops[n - 1].color;
  107.         }
  108.  
  109.         if (n == count)
  110.         {
  111.             right_x =  INT32_MAX;
  112.             right_c = &stops[n - 1].color;
  113.         }
  114.         else
  115.         {
  116.             right_x =  stops[n].x;
  117.             right_c = &stops[n].color;
  118.         }
  119.         break;
  120.  
  121.     case PIXMAN_REPEAT_REFLECT:
  122.         x = (int32_t)pos & 0xFFFF;
  123.         if ((int32_t)pos & 0x10000)
  124.             x = 0x10000 - x;
  125.         for (n = 0; n < count; n++)
  126.             if (x < stops[n].x)
  127.                 break;
  128.  
  129.         if (n == 0)
  130.         {
  131.             left_x =  -stops[0].x;
  132.             left_c = &stops[0].color;
  133.         }
  134.         else
  135.         {
  136.             left_x =  stops[n - 1].x;
  137.             left_c = &stops[n - 1].color;
  138.         }
  139.  
  140.         if (n == count)
  141.         {
  142.             right_x = 0x20000 - stops[n - 1].x;
  143.             right_c = &stops[n - 1].color;
  144.         }
  145.         else
  146.         {
  147.             right_x =  stops[n].x;
  148.             right_c = &stops[n].color;
  149.         }
  150.  
  151.         if ((int32_t)pos & 0x10000)
  152.         {
  153.             pixman_color_t  *tmp_c;
  154.             int32_t tmp_x;
  155.  
  156.             tmp_x   = 0x10000 - right_x;
  157.             right_x = 0x10000 - left_x;
  158.             left_x  = tmp_x;
  159.  
  160.             tmp_c   = right_c;
  161.             right_c = left_c;
  162.             left_c  = tmp_c;
  163.  
  164.             x = 0x10000 - x;
  165.         }
  166.         left_x  += (pos - x);
  167.         right_x += (pos - x);
  168.         break;
  169.  
  170.     default:  /* REPEAT_NONE */
  171.         for (n = 0; n < count; n++)
  172.             if (pos < stops[n].x)
  173.                 break;
  174.  
  175.         if (n == 0)
  176.         {
  177.             left_x  =  INT32_MIN;
  178.             right_x =  stops[0].x;
  179.             left_c  = right_c = (pixman_color_t*) &transparent_black;
  180.         }
  181.         else if (n == count)
  182.         {
  183.             left_x  = stops[n - 1].x;
  184.             right_x = INT32_MAX;
  185.             left_c  = right_c = (pixman_color_t*) &transparent_black;
  186.         }
  187.         else
  188.         {
  189.             left_x  =  stops[n - 1].x;
  190.             right_x =  stops[n].x;
  191.             left_c  = &stops[n - 1].color;
  192.             right_c = &stops[n].color;
  193.         }
  194.     }
  195.  
  196.     walker->left_x   = left_x;
  197.     walker->right_x  = right_x;
  198.     walker->left_ag  = ((left_c->alpha >> 8) << 16)   | (left_c->green >> 8);
  199.     walker->left_rb  = ((left_c->red & 0xff00) << 8)  | (left_c->blue >> 8);
  200.     walker->right_ag = ((right_c->alpha >> 8) << 16)  | (right_c->green >> 8);
  201.     walker->right_rb = ((right_c->red & 0xff00) << 8) | (right_c->blue >> 8);
  202.  
  203.     if (walker->left_x == walker->right_x                ||
  204.         ( walker->left_ag == walker->right_ag &&
  205.           walker->left_rb == walker->right_rb )   )
  206.     {
  207.         walker->stepper = 0;
  208.     }
  209.     else
  210.     {
  211.         int32_t width = right_x - left_x;
  212.         walker->stepper = ((1 << 24) + width / 2) / width;
  213.     }
  214.  
  215.     walker->need_reset = FALSE;
  216. }
  217.  
  218. #define  PIXMAN_GRADIENT_WALKER_NEED_RESET(w, x)                         \
  219.     ( (w)->need_reset || (x) < (w)->left_x || (x) >= (w)->right_x)
  220.  
  221.  
  222. /* the following assumes that PIXMAN_GRADIENT_WALKER_NEED_RESET(w,x) is FALSE */
  223. uint32_t
  224. _pixman_gradient_walker_pixel (pixman_gradient_walker_t *walker,
  225.                                pixman_fixed_32_32_t      x)
  226. {
  227.     int dist, idist;
  228.     uint32_t t1, t2, a, color;
  229.  
  230.     if (PIXMAN_GRADIENT_WALKER_NEED_RESET (walker, x))
  231.         _pixman_gradient_walker_reset (walker, x);
  232.  
  233.     dist  = ((int)(x - walker->left_x) * walker->stepper) >> 16;
  234.     idist = 256 - dist;
  235.  
  236.     /* combined INTERPOLATE and premultiply */
  237.     t1 = walker->left_rb * idist + walker->right_rb * dist;
  238.     t1 = (t1 >> 8) & 0xff00ff;
  239.  
  240.     t2  = walker->left_ag * idist + walker->right_ag * dist;
  241.     t2 &= 0xff00ff00;
  242.  
  243.     color = t2 & 0xff000000;
  244.     a     = t2 >> 24;
  245.  
  246.     t1  = t1 * a + 0x800080;
  247.     t1  = (t1 + ((t1 >> 8) & 0xff00ff)) >> 8;
  248.  
  249.     t2  = (t2 >> 8) * a + 0x800080;
  250.     t2  = (t2 + ((t2 >> 8) & 0xff00ff));
  251.  
  252.     return (color | (t1 & 0xff00ff) | (t2 & 0xff00));
  253. }
  254.  
  255.