pixman-conical-gradient.c (5662B)
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 <pixman-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 (pixman_iter_t *iter, 55 const uint32_t *mask, 56 int Bpp, 57 pixman_gradient_walker_write_t write_pixel) 58 { 59 pixman_image_t *image = iter->image; 60 int x = iter->x; 61 int y = iter->y; 62 int width = iter->width; 63 uint32_t *buffer = iter->buffer; 64 65 gradient_t *gradient = (gradient_t *)image; 66 conical_gradient_t *conical = (conical_gradient_t *)image; 67 uint32_t *end = buffer + width * (Bpp / 4); 68 pixman_gradient_walker_t walker; 69 pixman_bool_t affine = TRUE; 70 double cx = 1.; 71 double cy = 0.; 72 double cz = 0.; 73 double rx = x + 0.5; 74 double ry = y + 0.5; 75 double rz = 1.; 76 77 _pixman_gradient_walker_init (&walker, gradient, image->common.repeat); 78 79 if (image->common.transform) 80 { 81 pixman_vector_t v; 82 83 /* reference point is the center of the pixel */ 84 v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2; 85 v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2; 86 v.vector[2] = pixman_fixed_1; 87 88 if (!pixman_transform_point_3d (image->common.transform, &v)) 89 return iter->buffer; 90 91 cx = image->common.transform->matrix[0][0] / 65536.; 92 cy = image->common.transform->matrix[1][0] / 65536.; 93 cz = image->common.transform->matrix[2][0] / 65536.; 94 95 rx = v.vector[0] / 65536.; 96 ry = v.vector[1] / 65536.; 97 rz = v.vector[2] / 65536.; 98 99 affine = 100 image->common.transform->matrix[2][0] == 0 && 101 v.vector[2] == pixman_fixed_1; 102 } 103 104 if (affine) 105 { 106 rx -= conical->center.x / 65536.; 107 ry -= conical->center.y / 65536.; 108 109 while (buffer < end) 110 { 111 if (!mask || *mask++) 112 { 113 double t = coordinates_to_parameter (rx, ry, conical->angle); 114 115 write_pixel (&walker, 116 (pixman_fixed_48_16_t)pixman_double_to_fixed (t), 117 buffer); 118 } 119 120 buffer += (Bpp / 4); 121 122 rx += cx; 123 ry += cy; 124 } 125 } 126 else 127 { 128 while (buffer < end) 129 { 130 double x, y; 131 132 if (!mask || *mask++) 133 { 134 double t; 135 136 if (rz != 0) 137 { 138 x = rx / rz; 139 y = ry / rz; 140 } 141 else 142 { 143 x = y = 0.; 144 } 145 146 x -= conical->center.x / 65536.; 147 y -= conical->center.y / 65536.; 148 149 t = coordinates_to_parameter (x, y, conical->angle); 150 151 write_pixel (&walker, 152 (pixman_fixed_48_16_t)pixman_double_to_fixed (t), 153 buffer); 154 } 155 156 buffer += (Bpp / 4); 157 158 rx += cx; 159 ry += cy; 160 rz += cz; 161 } 162 } 163 164 iter->y++; 165 return iter->buffer; 166 } 167 168 static uint32_t * 169 conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) 170 { 171 return conical_get_scanline (iter, mask, 4, 172 _pixman_gradient_walker_write_narrow); 173 } 174 175 static uint32_t * 176 conical_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) 177 { 178 return conical_get_scanline (iter, NULL, 16, 179 _pixman_gradient_walker_write_wide); 180 } 181 182 void 183 _pixman_conical_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter) 184 { 185 if (iter->iter_flags & ITER_NARROW) 186 iter->get_scanline = conical_get_scanline_narrow; 187 else 188 iter->get_scanline = conical_get_scanline_wide; 189 } 190 191 PIXMAN_EXPORT pixman_image_t * 192 pixman_image_create_conical_gradient (const pixman_point_fixed_t * center, 193 pixman_fixed_t angle, 194 const pixman_gradient_stop_t *stops, 195 int n_stops) 196 { 197 pixman_image_t *image = _pixman_image_allocate (); 198 conical_gradient_t *conical; 199 200 if (!image) 201 return NULL; 202 203 conical = &image->conical; 204 205 if (!_pixman_init_gradient (&conical->common, stops, n_stops)) 206 { 207 free (image); 208 return NULL; 209 } 210 211 angle = MOD (angle, pixman_int_to_fixed (360)); 212 213 image->type = CONICAL; 214 215 conical->center = *center; 216 conical->angle = (pixman_fixed_to_double (angle) / 180.0) * M_PI; 217 218 return image; 219 }