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 35static force_inline double 36coordinates_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 53static uint32_t * 54conical_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 163static uint32_t * 164conical_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 174void 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 183PIXMAN_EXPORT pixman_image_t * 184pixman_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