1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/cairo/libpixman/src/pixman-linear-gradient.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,444 @@ 1.4 +/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */ 1.5 +/* 1.6 + * Copyright © 2000 SuSE, Inc. 1.7 + * Copyright © 2007 Red Hat, Inc. 1.8 + * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. 1.9 + * 2005 Lars Knoll & Zack Rusin, Trolltech 1.10 + * 1.11 + * Permission to use, copy, modify, distribute, and sell this software and its 1.12 + * documentation for any purpose is hereby granted without fee, provided that 1.13 + * the above copyright notice appear in all copies and that both that 1.14 + * copyright notice and this permission notice appear in supporting 1.15 + * documentation, and that the name of Keith Packard not be used in 1.16 + * advertising or publicity pertaining to distribution of the software without 1.17 + * specific, written prior permission. Keith Packard makes no 1.18 + * representations about the suitability of this software for any purpose. It 1.19 + * is provided "as is" without express or implied warranty. 1.20 + * 1.21 + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS 1.22 + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 1.23 + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 1.24 + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1.25 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 1.26 + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 1.27 + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 1.28 + * SOFTWARE. 1.29 + */ 1.30 + 1.31 +#ifdef HAVE_CONFIG_H 1.32 +#include <config.h> 1.33 +#endif 1.34 +#include <stdlib.h> 1.35 +#include "pixman-private.h" 1.36 + 1.37 +#include "pixman-dither.h" 1.38 + 1.39 +static pixman_bool_t 1.40 +linear_gradient_is_horizontal (pixman_image_t *image, 1.41 + int x, 1.42 + int y, 1.43 + int width, 1.44 + int height) 1.45 +{ 1.46 + linear_gradient_t *linear = (linear_gradient_t *)image; 1.47 + pixman_vector_t v; 1.48 + pixman_fixed_32_32_t l; 1.49 + pixman_fixed_48_16_t dx, dy; 1.50 + double inc; 1.51 + 1.52 + if (image->common.transform) 1.53 + { 1.54 + /* projective transformation */ 1.55 + if (image->common.transform->matrix[2][0] != 0 || 1.56 + image->common.transform->matrix[2][1] != 0 || 1.57 + image->common.transform->matrix[2][2] == 0) 1.58 + { 1.59 + return FALSE; 1.60 + } 1.61 + 1.62 + v.vector[0] = image->common.transform->matrix[0][1]; 1.63 + v.vector[1] = image->common.transform->matrix[1][1]; 1.64 + v.vector[2] = image->common.transform->matrix[2][2]; 1.65 + } 1.66 + else 1.67 + { 1.68 + v.vector[0] = 0; 1.69 + v.vector[1] = pixman_fixed_1; 1.70 + v.vector[2] = pixman_fixed_1; 1.71 + } 1.72 + 1.73 + dx = linear->p2.x - linear->p1.x; 1.74 + dy = linear->p2.y - linear->p1.y; 1.75 + 1.76 + l = dx * dx + dy * dy; 1.77 + 1.78 + if (l == 0) 1.79 + return FALSE; 1.80 + 1.81 + /* 1.82 + * compute how much the input of the gradient walked changes 1.83 + * when moving vertically through the whole image 1.84 + */ 1.85 + inc = height * (double) pixman_fixed_1 * pixman_fixed_1 * 1.86 + (dx * v.vector[0] + dy * v.vector[1]) / 1.87 + (v.vector[2] * (double) l); 1.88 + 1.89 + /* check that casting to integer would result in 0 */ 1.90 + if (-1 < inc && inc < 1) 1.91 + return TRUE; 1.92 + 1.93 + return FALSE; 1.94 +} 1.95 + 1.96 +static uint32_t * 1.97 +linear_get_scanline_narrow (pixman_iter_t *iter, 1.98 + const uint32_t *mask) 1.99 +{ 1.100 + pixman_image_t *image = iter->image; 1.101 + int x = iter->x; 1.102 + int y = iter->y; 1.103 + int width = iter->width; 1.104 + uint32_t * buffer = iter->buffer; 1.105 + 1.106 + pixman_vector_t v, unit; 1.107 + pixman_fixed_32_32_t l; 1.108 + pixman_fixed_48_16_t dx, dy; 1.109 + gradient_t *gradient = (gradient_t *)image; 1.110 + linear_gradient_t *linear = (linear_gradient_t *)image; 1.111 + uint32_t *end = buffer + width; 1.112 + pixman_gradient_walker_t walker; 1.113 + 1.114 + _pixman_gradient_walker_init (&walker, gradient, image->common.repeat); 1.115 + 1.116 + /* reference point is the center of the pixel */ 1.117 + v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2; 1.118 + v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2; 1.119 + v.vector[2] = pixman_fixed_1; 1.120 + 1.121 + if (image->common.transform) 1.122 + { 1.123 + if (!pixman_transform_point_3d (image->common.transform, &v)) 1.124 + return iter->buffer; 1.125 + 1.126 + unit.vector[0] = image->common.transform->matrix[0][0]; 1.127 + unit.vector[1] = image->common.transform->matrix[1][0]; 1.128 + unit.vector[2] = image->common.transform->matrix[2][0]; 1.129 + } 1.130 + else 1.131 + { 1.132 + unit.vector[0] = pixman_fixed_1; 1.133 + unit.vector[1] = 0; 1.134 + unit.vector[2] = 0; 1.135 + } 1.136 + 1.137 + dx = linear->p2.x - linear->p1.x; 1.138 + dy = linear->p2.y - linear->p1.y; 1.139 + 1.140 + l = dx * dx + dy * dy; 1.141 + 1.142 + if (l == 0 || unit.vector[2] == 0) 1.143 + { 1.144 + /* affine transformation only */ 1.145 + pixman_fixed_32_32_t t, next_inc; 1.146 + double inc; 1.147 + 1.148 + if (l == 0 || v.vector[2] == 0) 1.149 + { 1.150 + t = 0; 1.151 + inc = 0; 1.152 + } 1.153 + else 1.154 + { 1.155 + double invden, v2; 1.156 + 1.157 + invden = pixman_fixed_1 * (double) pixman_fixed_1 / 1.158 + (l * (double) v.vector[2]); 1.159 + v2 = v.vector[2] * (1. / pixman_fixed_1); 1.160 + t = ((dx * v.vector[0] + dy * v.vector[1]) - 1.161 + (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden; 1.162 + inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden; 1.163 + } 1.164 + next_inc = 0; 1.165 + 1.166 + if (((pixman_fixed_32_32_t )(inc * width)) == 0) 1.167 + { 1.168 + register uint32_t color; 1.169 + 1.170 + color = _pixman_gradient_walker_pixel (&walker, t); 1.171 + while (buffer < end) 1.172 + *buffer++ = color; 1.173 + } 1.174 + else 1.175 + { 1.176 + int i; 1.177 + 1.178 + i = 0; 1.179 + while (buffer < end) 1.180 + { 1.181 + if (!mask || *mask++) 1.182 + { 1.183 + *buffer = _pixman_gradient_walker_pixel (&walker, 1.184 + t + next_inc); 1.185 + } 1.186 + i++; 1.187 + next_inc = inc * i; 1.188 + buffer++; 1.189 + } 1.190 + } 1.191 + } 1.192 + else 1.193 + { 1.194 + /* projective transformation */ 1.195 + double t; 1.196 + 1.197 + t = 0; 1.198 + 1.199 + while (buffer < end) 1.200 + { 1.201 + if (!mask || *mask++) 1.202 + { 1.203 + if (v.vector[2] != 0) 1.204 + { 1.205 + double invden, v2; 1.206 + 1.207 + invden = pixman_fixed_1 * (double) pixman_fixed_1 / 1.208 + (l * (double) v.vector[2]); 1.209 + v2 = v.vector[2] * (1. / pixman_fixed_1); 1.210 + t = ((dx * v.vector[0] + dy * v.vector[1]) - 1.211 + (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden; 1.212 + } 1.213 + 1.214 + *buffer = _pixman_gradient_walker_pixel (&walker, t); 1.215 + } 1.216 + 1.217 + ++buffer; 1.218 + 1.219 + v.vector[0] += unit.vector[0]; 1.220 + v.vector[1] += unit.vector[1]; 1.221 + v.vector[2] += unit.vector[2]; 1.222 + } 1.223 + } 1.224 + 1.225 + iter->y++; 1.226 + 1.227 + return iter->buffer; 1.228 +} 1.229 + 1.230 +static uint32_t * 1.231 +linear_get_scanline_16 (pixman_iter_t *iter, 1.232 + const uint32_t *mask) 1.233 +{ 1.234 + pixman_image_t *image = iter->image; 1.235 + int x = iter->x; 1.236 + int y = iter->y; 1.237 + int width = iter->width; 1.238 + uint16_t * buffer = (uint16_t*)iter->buffer; 1.239 + pixman_bool_t toggle = ((x ^ y) & 1); 1.240 + 1.241 + pixman_vector_t v, unit; 1.242 + pixman_fixed_32_32_t l; 1.243 + pixman_fixed_48_16_t dx, dy; 1.244 + gradient_t *gradient = (gradient_t *)image; 1.245 + linear_gradient_t *linear = (linear_gradient_t *)image; 1.246 + uint16_t *end = buffer + width; 1.247 + pixman_gradient_walker_t walker; 1.248 + 1.249 + _pixman_gradient_walker_init (&walker, gradient, image->common.repeat); 1.250 + 1.251 + /* reference point is the center of the pixel */ 1.252 + v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2; 1.253 + v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2; 1.254 + v.vector[2] = pixman_fixed_1; 1.255 + 1.256 + if (image->common.transform) 1.257 + { 1.258 + if (!pixman_transform_point_3d (image->common.transform, &v)) 1.259 + return iter->buffer; 1.260 + 1.261 + unit.vector[0] = image->common.transform->matrix[0][0]; 1.262 + unit.vector[1] = image->common.transform->matrix[1][0]; 1.263 + unit.vector[2] = image->common.transform->matrix[2][0]; 1.264 + } 1.265 + else 1.266 + { 1.267 + unit.vector[0] = pixman_fixed_1; 1.268 + unit.vector[1] = 0; 1.269 + unit.vector[2] = 0; 1.270 + } 1.271 + 1.272 + dx = linear->p2.x - linear->p1.x; 1.273 + dy = linear->p2.y - linear->p1.y; 1.274 + 1.275 + l = dx * dx + dy * dy; 1.276 + 1.277 + if (l == 0 || unit.vector[2] == 0) 1.278 + { 1.279 + /* affine transformation only */ 1.280 + pixman_fixed_32_32_t t, next_inc; 1.281 + double inc; 1.282 + 1.283 + if (l == 0 || v.vector[2] == 0) 1.284 + { 1.285 + t = 0; 1.286 + inc = 0; 1.287 + } 1.288 + else 1.289 + { 1.290 + double invden, v2; 1.291 + 1.292 + invden = pixman_fixed_1 * (double) pixman_fixed_1 / 1.293 + (l * (double) v.vector[2]); 1.294 + v2 = v.vector[2] * (1. / pixman_fixed_1); 1.295 + t = ((dx * v.vector[0] + dy * v.vector[1]) - 1.296 + (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden; 1.297 + inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden; 1.298 + } 1.299 + next_inc = 0; 1.300 + 1.301 + if (((pixman_fixed_32_32_t )(inc * width)) == 0) 1.302 + { 1.303 + register uint32_t color; 1.304 + uint16_t dither_diff; 1.305 + uint16_t color16; 1.306 + uint16_t color16b; 1.307 + 1.308 + color = _pixman_gradient_walker_pixel (&walker, t); 1.309 + color16 = dither_8888_to_0565(color, toggle); 1.310 + color16b = dither_8888_to_0565(color, toggle^1); 1.311 + // compute the difference 1.312 + dither_diff = color16 ^ color16b; 1.313 + while (buffer < end) { 1.314 + *buffer++ = color16; 1.315 + // use dither_diff to toggle between color16 and color16b 1.316 + color16 ^= dither_diff; 1.317 + toggle ^= 1; 1.318 + } 1.319 + } 1.320 + else 1.321 + { 1.322 + int i; 1.323 + 1.324 + i = 0; 1.325 + while (buffer < end) 1.326 + { 1.327 + if (!mask || *mask++) 1.328 + { 1.329 + *buffer = dither_8888_to_0565(_pixman_gradient_walker_pixel (&walker, 1.330 + t + next_inc), 1.331 + toggle); 1.332 + } 1.333 + toggle ^= 1; 1.334 + i++; 1.335 + next_inc = inc * i; 1.336 + buffer++; 1.337 + } 1.338 + } 1.339 + } 1.340 + else 1.341 + { 1.342 + /* projective transformation */ 1.343 + double t; 1.344 + 1.345 + t = 0; 1.346 + 1.347 + while (buffer < end) 1.348 + { 1.349 + if (!mask || *mask++) 1.350 + { 1.351 + if (v.vector[2] != 0) 1.352 + { 1.353 + double invden, v2; 1.354 + 1.355 + invden = pixman_fixed_1 * (double) pixman_fixed_1 / 1.356 + (l * (double) v.vector[2]); 1.357 + v2 = v.vector[2] * (1. / pixman_fixed_1); 1.358 + t = ((dx * v.vector[0] + dy * v.vector[1]) - 1.359 + (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden; 1.360 + } 1.361 + 1.362 + *buffer = dither_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t), 1.363 + toggle); 1.364 + } 1.365 + toggle ^= 1; 1.366 + 1.367 + ++buffer; 1.368 + 1.369 + v.vector[0] += unit.vector[0]; 1.370 + v.vector[1] += unit.vector[1]; 1.371 + v.vector[2] += unit.vector[2]; 1.372 + } 1.373 + } 1.374 + 1.375 + iter->y++; 1.376 + 1.377 + return iter->buffer; 1.378 +} 1.379 + 1.380 +static uint32_t * 1.381 +linear_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) 1.382 +{ 1.383 + uint32_t *buffer = linear_get_scanline_narrow (iter, NULL); 1.384 + 1.385 + pixman_expand_to_float ( 1.386 + (argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width); 1.387 + 1.388 + return buffer; 1.389 +} 1.390 + 1.391 +void 1.392 +_pixman_linear_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter) 1.393 +{ 1.394 + // XXX: we can't use this optimization when dithering 1.395 + if (0 && linear_gradient_is_horizontal ( 1.396 + iter->image, iter->x, iter->y, iter->width, iter->height)) 1.397 + { 1.398 + if (iter->iter_flags & ITER_16) 1.399 + linear_get_scanline_16 (iter, NULL); 1.400 + else if (iter->iter_flags & ITER_NARROW) 1.401 + linear_get_scanline_narrow (iter, NULL); 1.402 + else 1.403 + linear_get_scanline_wide (iter, NULL); 1.404 + 1.405 + iter->get_scanline = _pixman_iter_get_scanline_noop; 1.406 + } 1.407 + else 1.408 + { 1.409 + if (iter->iter_flags & ITER_16) 1.410 + iter->get_scanline = linear_get_scanline_16; 1.411 + else if (iter->iter_flags & ITER_NARROW) 1.412 + iter->get_scanline = linear_get_scanline_narrow; 1.413 + else 1.414 + iter->get_scanline = linear_get_scanline_wide; 1.415 + } 1.416 +} 1.417 + 1.418 +PIXMAN_EXPORT pixman_image_t * 1.419 +pixman_image_create_linear_gradient (const pixman_point_fixed_t * p1, 1.420 + const pixman_point_fixed_t * p2, 1.421 + const pixman_gradient_stop_t *stops, 1.422 + int n_stops) 1.423 +{ 1.424 + pixman_image_t *image; 1.425 + linear_gradient_t *linear; 1.426 + 1.427 + image = _pixman_image_allocate (); 1.428 + 1.429 + if (!image) 1.430 + return NULL; 1.431 + 1.432 + linear = &image->linear; 1.433 + 1.434 + if (!_pixman_init_gradient (&linear->common, stops, n_stops)) 1.435 + { 1.436 + free (image); 1.437 + return NULL; 1.438 + } 1.439 + 1.440 + linear->p1 = *p1; 1.441 + linear->p2 = *p2; 1.442 + 1.443 + image->type = LINEAR; 1.444 + 1.445 + return image; 1.446 +} 1.447 +