tor-browser

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

pixman-linear-gradient.c (7741B)


      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 <pixman-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 (pixman_iter_t                 *iter,
     93 	     const uint32_t                *mask,
     94 	     int                            Bpp,
     95 	     pixman_gradient_walker_write_t write_pixel,
     96 	     pixman_gradient_walker_fill_t  fill_pixel)
     97 {
     98    pixman_image_t *image  = iter->image;
     99    int             x      = iter->x;
    100    int             y      = iter->y;
    101    int             width  = iter->width;
    102    uint32_t *      buffer = iter->buffer;
    103 
    104    pixman_vector_t v, unit;
    105    pixman_fixed_32_32_t l;
    106    pixman_fixed_48_16_t dx, dy;
    107    gradient_t *gradient = (gradient_t *)image;
    108    linear_gradient_t *linear = (linear_gradient_t *)image;
    109    uint32_t *end = buffer + width * (Bpp / 4);
    110    pixman_gradient_walker_t walker;
    111 
    112    _pixman_gradient_walker_init (&walker, gradient, image->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 (image->common.transform)
    120    {
    121 if (!pixman_transform_point_3d (image->common.transform, &v))
    122     return iter->buffer;
    123 
    124 unit.vector[0] = image->common.transform->matrix[0][0];
    125 unit.vector[1] = image->common.transform->matrix[1][0];
    126 unit.vector[2] = image->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     fill_pixel (&walker, t, buffer, end);
    167 }
    168 else
    169 {
    170     int i;
    171 
    172     i = 0;
    173     while (buffer < end)
    174     {
    175 	if (!mask || *mask++)
    176 	{
    177 	    write_pixel (&walker, t + next_inc, buffer);
    178 	}
    179 	i++;
    180 	next_inc = inc * i;
    181 	buffer += (Bpp / 4);
    182     }
    183 }
    184    }
    185    else
    186    {
    187 /* projective transformation */
    188        double t;
    189 
    190 t = 0;
    191 
    192 while (buffer < end)
    193 {
    194     if (!mask || *mask++)
    195     {
    196         if (v.vector[2] != 0)
    197 	{
    198 	    double invden, v2;
    199 
    200 	    invden = pixman_fixed_1 * (double) pixman_fixed_1 /
    201 		(l * (double) v.vector[2]);
    202 	    v2 = v.vector[2] * (1. / pixman_fixed_1);
    203 	    t = ((dx * v.vector[0] + dy * v.vector[1]) -
    204 		 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
    205 	}
    206 
    207 	write_pixel (&walker, t, buffer);
    208     }
    209 
    210     buffer += (Bpp / 4);
    211 
    212     v.vector[0] += unit.vector[0];
    213     v.vector[1] += unit.vector[1];
    214     v.vector[2] += unit.vector[2];
    215 }
    216    }
    217 
    218    iter->y++;
    219 
    220    return iter->buffer;
    221 }
    222 
    223 static uint32_t *
    224 linear_get_scanline_narrow (pixman_iter_t  *iter,
    225 		    const uint32_t *mask)
    226 {
    227    return linear_get_scanline (iter, mask, 4,
    228 			_pixman_gradient_walker_write_narrow,
    229 			_pixman_gradient_walker_fill_narrow);
    230 }
    231 
    232 
    233 static uint32_t *
    234 linear_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
    235 {
    236    return linear_get_scanline (iter, NULL, 16,
    237 			_pixman_gradient_walker_write_wide,
    238 			_pixman_gradient_walker_fill_wide);
    239 }
    240 
    241 void
    242 _pixman_linear_gradient_iter_init (pixman_image_t *image, pixman_iter_t  *iter)
    243 {
    244    if (linear_gradient_is_horizontal (
    245     iter->image, iter->x, iter->y, iter->width, iter->height))
    246    {
    247 if (iter->iter_flags & ITER_NARROW)
    248     linear_get_scanline_narrow (iter, NULL);
    249 else
    250     linear_get_scanline_wide (iter, NULL);
    251 
    252 iter->get_scanline = _pixman_iter_get_scanline_noop;
    253    }
    254    else
    255    {
    256 if (iter->iter_flags & ITER_NARROW)
    257     iter->get_scanline = linear_get_scanline_narrow;
    258 else
    259     iter->get_scanline = linear_get_scanline_wide;
    260    }
    261 }
    262 
    263 PIXMAN_EXPORT pixman_image_t *
    264 pixman_image_create_linear_gradient (const pixman_point_fixed_t *  p1,
    265                                     const pixman_point_fixed_t *  p2,
    266                                     const pixman_gradient_stop_t *stops,
    267                                     int                           n_stops)
    268 {
    269    pixman_image_t *image;
    270    linear_gradient_t *linear;
    271 
    272    image = _pixman_image_allocate ();
    273 
    274    if (!image)
    275 return NULL;
    276 
    277    linear = &image->linear;
    278 
    279    if (!_pixman_init_gradient (&linear->common, stops, n_stops))
    280    {
    281 free (image);
    282 return NULL;
    283    }
    284 
    285    linear->p1 = *p1;
    286    linear->p2 = *p2;
    287 
    288    image->type = LINEAR;
    289 
    290    return image;
    291 }