Home | History | Annotate | Download | only in pixman
      1 /*
      2  * Copyright  2000 SuSE, Inc.
      3  * Copyright  2007 Red Hat, Inc.
      4  * Copyright  2000 Keith Packard, member of The XFree86 Project, Inc.
      5  *             2005 Lars Knoll & Zack Rusin, Trolltech
      6  *
      7  * Permission to use, copy, modify, distribute, and sell this software and its
      8  * documentation for any purpose is hereby granted without fee, provided that
      9  * the above copyright notice appear in all copies and that both that
     10  * copyright notice and this permission notice appear in supporting
     11  * documentation, and that the name of Keith Packard not be used in
     12  * advertising or publicity pertaining to distribution of the software without
     13  * specific, written prior permission.  Keith Packard makes no
     14  * representations about the suitability of this software for any purpose.  It
     15  * is provided "as is" without express or implied warranty.
     16  *
     17  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
     18  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
     19  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
     20  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     21  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
     22  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     23  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     24  * SOFTWARE.
     25  */
     26 
     27 #ifdef HAVE_CONFIG_H
     28 #include <config.h>
     29 #endif
     30 
     31 #include <stdlib.h>
     32 #include <math.h>
     33 #include "pixman-private.h"
     34 
     35 static force_inline double
     36 coordinates_to_parameter (double x, double y, double angle)
     37 {
     38     double t;
     39 
     40     t = atan2 (y, x) + angle;
     41 
     42     while (t < 0)
     43 	t += 2 * M_PI;
     44 
     45     while (t >= 2 * M_PI)
     46 	t -= 2 * M_PI;
     47 
     48     return 1 - t * (1 / (2 * M_PI)); /* Scale t to [0, 1] and
     49 				      * make rotation CCW
     50 				      */
     51 }
     52 
     53 static uint32_t *
     54 conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
     55 {
     56     pixman_image_t *image = iter->image;
     57     int x = iter->x;
     58     int y = iter->y;
     59     int width = iter->width;
     60     uint32_t *buffer = iter->buffer;
     61 
     62     gradient_t *gradient = (gradient_t *)image;
     63     conical_gradient_t *conical = (conical_gradient_t *)image;
     64     uint32_t       *end = buffer + width;
     65     pixman_gradient_walker_t walker;
     66     pixman_bool_t affine = TRUE;
     67     double cx = 1.;
     68     double cy = 0.;
     69     double cz = 0.;
     70     double rx = x + 0.5;
     71     double ry = y + 0.5;
     72     double rz = 1.;
     73 
     74     _pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
     75 
     76     if (image->common.transform)
     77     {
     78 	pixman_vector_t v;
     79 
     80 	/* reference point is the center of the pixel */
     81 	v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
     82 	v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
     83 	v.vector[2] = pixman_fixed_1;
     84 
     85 	if (!pixman_transform_point_3d (image->common.transform, &v))
     86 	    return iter->buffer;
     87 
     88 	cx = image->common.transform->matrix[0][0] / 65536.;
     89 	cy = image->common.transform->matrix[1][0] / 65536.;
     90 	cz = image->common.transform->matrix[2][0] / 65536.;
     91 
     92 	rx = v.vector[0] / 65536.;
     93 	ry = v.vector[1] / 65536.;
     94 	rz = v.vector[2] / 65536.;
     95 
     96 	affine =
     97 	    image->common.transform->matrix[2][0] == 0 &&
     98 	    v.vector[2] == pixman_fixed_1;
     99     }
    100 
    101     if (affine)
    102     {
    103 	rx -= conical->center.x / 65536.;
    104 	ry -= conical->center.y / 65536.;
    105 
    106 	while (buffer < end)
    107 	{
    108 	    if (!mask || *mask++)
    109 	    {
    110 		double t = coordinates_to_parameter (rx, ry, conical->angle);
    111 
    112 		*buffer = _pixman_gradient_walker_pixel (
    113 		    &walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t));
    114 	    }
    115 
    116 	    ++buffer;
    117 
    118 	    rx += cx;
    119 	    ry += cy;
    120 	}
    121     }
    122     else
    123     {
    124 	while (buffer < end)
    125 	{
    126 	    double x, y;
    127 
    128 	    if (!mask || *mask++)
    129 	    {
    130 		double t;
    131 
    132 		if (rz != 0)
    133 		{
    134 		    x = rx / rz;
    135 		    y = ry / rz;
    136 		}
    137 		else
    138 		{
    139 		    x = y = 0.;
    140 		}
    141 
    142 		x -= conical->center.x / 65536.;
    143 		y -= conical->center.y / 65536.;
    144 
    145 		t = coordinates_to_parameter (x, y, conical->angle);
    146 
    147 		*buffer = _pixman_gradient_walker_pixel (
    148 		    &walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t));
    149 	    }
    150 
    151 	    ++buffer;
    152 
    153 	    rx += cx;
    154 	    ry += cy;
    155 	    rz += cz;
    156 	}
    157     }
    158 
    159     iter->y++;
    160     return iter->buffer;
    161 }
    162 
    163 static uint32_t *
    164 conical_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
    165 {
    166     uint32_t *buffer = conical_get_scanline_narrow (iter, NULL);
    167 
    168     pixman_expand_to_float (
    169 	(argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
    170 
    171     return buffer;
    172 }
    173 
    174 void
    175 _pixman_conical_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter)
    176 {
    177     if (iter->iter_flags & ITER_NARROW)
    178 	iter->get_scanline = conical_get_scanline_narrow;
    179     else
    180 	iter->get_scanline = conical_get_scanline_wide;
    181 }
    182 
    183 PIXMAN_EXPORT pixman_image_t *
    184 pixman_image_create_conical_gradient (const pixman_point_fixed_t *  center,
    185                                       pixman_fixed_t                angle,
    186                                       const pixman_gradient_stop_t *stops,
    187                                       int                           n_stops)
    188 {
    189     pixman_image_t *image = _pixman_image_allocate ();
    190     conical_gradient_t *conical;
    191 
    192     if (!image)
    193 	return NULL;
    194 
    195     conical = &image->conical;
    196 
    197     if (!_pixman_init_gradient (&conical->common, stops, n_stops))
    198     {
    199 	free (image);
    200 	return NULL;
    201     }
    202 
    203     angle = MOD (angle, pixman_int_to_fixed (360));
    204 
    205     image->type = CONICAL;
    206 
    207     conical->center = *center;
    208     conical->angle = (pixman_fixed_to_double (angle) / 180.0) * M_PI;
    209 
    210     return image;
    211 }
    212 
    213