tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pixman-gradient-walker.c (7746B)


      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 <pixman-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                              pixman_repeat_t		repeat)
     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->a_s       = 0.0f;
     41    walker->a_b       = 0.0f;
     42    walker->r_s       = 0.0f;
     43    walker->r_b       = 0.0f;
     44    walker->g_s       = 0.0f;
     45    walker->g_b       = 0.0f;
     46    walker->b_s       = 0.0f;
     47    walker->b_b       = 0.0f;
     48    walker->repeat    = repeat;
     49 
     50    walker->need_reset = TRUE;
     51 }
     52 
     53 static void
     54 gradient_walker_reset (pixman_gradient_walker_t *walker,
     55 	       pixman_fixed_48_16_t      pos)
     56 {
     57    int64_t x, left_x, right_x;
     58    pixman_color_t *left_c, *right_c;
     59    int n, count = walker->num_stops;
     60    pixman_gradient_stop_t *stops = walker->stops;
     61    float la, lr, lg, lb;
     62    float ra, rr, rg, rb;
     63    float lx, rx;
     64 
     65    if (walker->repeat == PIXMAN_REPEAT_NORMAL)
     66    {
     67 x = (int32_t)pos & 0xffff;
     68    }
     69    else if (walker->repeat == PIXMAN_REPEAT_REFLECT)
     70    {
     71 x = (int32_t)pos & 0xffff;
     72 if ((int32_t)pos & 0x10000)
     73     x = 0x10000 - x;
     74    }
     75    else
     76    {
     77 x = pos;
     78    }
     79    
     80    for (n = 0; n < count; n++)
     81    {
     82 if (x < stops[n].x)
     83     break;
     84    }
     85    
     86    left_x =  stops[n - 1].x;
     87    left_c = &stops[n - 1].color;
     88    
     89    right_x =  stops[n].x;
     90    right_c = &stops[n].color;
     91 
     92    if (walker->repeat == PIXMAN_REPEAT_NORMAL)
     93    {
     94 left_x  += (pos - x);
     95 right_x += (pos - x);
     96    }
     97    else if (walker->repeat == PIXMAN_REPEAT_REFLECT)
     98    {
     99 if ((int32_t)pos & 0x10000)
    100 {
    101     pixman_color_t  *tmp_c;
    102     int32_t tmp_x;
    103 
    104     tmp_x   = 0x10000 - right_x;
    105     right_x = 0x10000 - left_x;
    106     left_x  = tmp_x;
    107 
    108     tmp_c   = right_c;
    109     right_c = left_c;
    110     left_c  = tmp_c;
    111 
    112     x = 0x10000 - x;
    113 }
    114 left_x  += (pos - x);
    115 right_x += (pos - x);
    116    }
    117    else if (walker->repeat == PIXMAN_REPEAT_NONE)
    118    {
    119 if (n == 0)
    120     right_c = left_c;
    121 else if (n == count)
    122     left_c = right_c;
    123    }
    124 
    125    /* The alpha/red/green/blue channels are scaled to be in [0, 1].
    126     * This ensures that after premultiplication all channels will
    127     * be in the [0, 1] interval.
    128     */
    129    la = (left_c->alpha * (1.0f/257.0f));
    130    lr = (left_c->red * (1.0f/257.0f));
    131    lg = (left_c->green * (1.0f/257.0f));
    132    lb = (left_c->blue * (1.0f/257.0f));
    133 
    134    ra = (right_c->alpha * (1.0f/257.0f));
    135    rr = (right_c->red * (1.0f/257.0f));
    136    rg = (right_c->green * (1.0f/257.0f));
    137    rb = (right_c->blue * (1.0f/257.0f));
    138    
    139    lx = left_x * (1.0f/65536.0f);
    140    rx = right_x * (1.0f/65536.0f);
    141    
    142    if (FLOAT_IS_ZERO (rx - lx) || left_x == INT32_MIN || right_x == INT32_MAX)
    143    {
    144 walker->a_s = walker->r_s = walker->g_s = walker->b_s = 0.0f;
    145 walker->a_b = (la + ra) / 510.0f;
    146 walker->r_b = (lr + rr) / 510.0f;
    147 walker->g_b = (lg + rg) / 510.0f;
    148 walker->b_b = (lb + rb) / 510.0f;
    149    }
    150    else
    151    {
    152 float w_rec = 1.0f / (rx - lx);
    153 
    154 walker->a_b = (la * rx - ra * lx) * w_rec * (1.0f/255.0f);
    155 walker->r_b = (lr * rx - rr * lx) * w_rec * (1.0f/255.0f);
    156 walker->g_b = (lg * rx - rg * lx) * w_rec * (1.0f/255.0f);
    157 walker->b_b = (lb * rx - rb * lx) * w_rec * (1.0f/255.0f);
    158 
    159 walker->a_s = (ra - la) * w_rec * (1.0f/255.0f);
    160 walker->r_s = (rr - lr) * w_rec * (1.0f/255.0f);
    161 walker->g_s = (rg - lg) * w_rec * (1.0f/255.0f);
    162 walker->b_s = (rb - lb) * w_rec * (1.0f/255.0f);
    163    }
    164   
    165    walker->left_x = left_x;
    166    walker->right_x = right_x;
    167 
    168    walker->need_reset = FALSE;
    169 }
    170 
    171 static argb_t
    172 pixman_gradient_walker_pixel_float (pixman_gradient_walker_t *walker,
    173 			    pixman_fixed_48_16_t      x)
    174 {
    175    argb_t f;
    176    float y;
    177 
    178    if (walker->need_reset || x < walker->left_x || x >= walker->right_x)
    179 gradient_walker_reset (walker, x);
    180 
    181    y = x * (1.0f / 65536.0f);
    182 
    183    f.a = walker->a_s * y + walker->a_b;
    184    f.r = f.a * (walker->r_s * y + walker->r_b);
    185    f.g = f.a * (walker->g_s * y + walker->g_b);
    186    f.b = f.a * (walker->b_s * y + walker->b_b);
    187 
    188    return f;
    189 }
    190 
    191 static uint32_t
    192 pixman_gradient_walker_pixel_32 (pixman_gradient_walker_t *walker,
    193 			 pixman_fixed_48_16_t      x)
    194 {
    195    argb_t f;
    196    float y;
    197 
    198    if (walker->need_reset || x < walker->left_x || x >= walker->right_x)
    199 gradient_walker_reset (walker, x);
    200 
    201    y = x * (1.0f / 65536.0f);
    202 
    203    /* Instead of [0...1] for ARGB, we want [0...255],
    204     * multiply alpha with 255 and the color channels
    205     * also get multiplied by the alpha multiplier.
    206     *
    207     * We don't use pixman_contract_from_float because it causes a 2x
    208     * slowdown to do so, and the values are already normalized,
    209     * so we don't have to worry about values < 0.f or > 1.f
    210     */
    211    f.a = 255.f * (walker->a_s * y + walker->a_b);
    212    f.r = f.a * (walker->r_s * y + walker->r_b);
    213    f.g = f.a * (walker->g_s * y + walker->g_b);
    214    f.b = f.a * (walker->b_s * y + walker->b_b);
    215 
    216    return (((uint32_t)(f.a + .5f) << 24) & 0xff000000) |
    217           (((uint32_t)(f.r + .5f) << 16) & 0x00ff0000) |
    218           (((uint32_t)(f.g + .5f) <<  8) & 0x0000ff00) |
    219           (((uint32_t)(f.b + .5f) >>  0) & 0x000000ff);
    220 }
    221 
    222 void
    223 _pixman_gradient_walker_write_narrow (pixman_gradient_walker_t *walker,
    224 			      pixman_fixed_48_16_t      x,
    225 			      uint32_t                 *buffer)
    226 {
    227    *buffer = pixman_gradient_walker_pixel_32 (walker, x);
    228 }
    229 
    230 void
    231 _pixman_gradient_walker_write_wide (pixman_gradient_walker_t *walker,
    232 			    pixman_fixed_48_16_t      x,
    233 			    uint32_t                 *buffer)
    234 {
    235    *(argb_t *)buffer = pixman_gradient_walker_pixel_float (walker, x);
    236 }
    237 
    238 void
    239 _pixman_gradient_walker_fill_narrow (pixman_gradient_walker_t *walker,
    240 			     pixman_fixed_48_16_t      x,
    241 			     uint32_t                 *buffer,
    242 			     uint32_t                 *end)
    243 {
    244    register uint32_t color;
    245 
    246    color = pixman_gradient_walker_pixel_32 (walker, x);
    247    while (buffer < end)
    248 *buffer++ = color;
    249 }
    250 
    251 void
    252 _pixman_gradient_walker_fill_wide (pixman_gradient_walker_t *walker,
    253 			   pixman_fixed_48_16_t      x,
    254 			   uint32_t                 *buffer,
    255 			   uint32_t                 *end)
    256 {
    257    register argb_t color;
    258    argb_t *buffer_wide = (argb_t *)buffer;
    259    argb_t *end_wide    = (argb_t *)end;
    260 
    261    color = pixman_gradient_walker_pixel_float (walker, x);
    262    while (buffer_wide < end_wide)
    263 *buffer_wide++ = color;
    264 }