gfx/cairo/libpixman/src/pixman-linear-gradient.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
michael@0 2 /*
michael@0 3 * Copyright © 2000 SuSE, Inc.
michael@0 4 * Copyright © 2007 Red Hat, Inc.
michael@0 5 * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
michael@0 6 * 2005 Lars Knoll & Zack Rusin, Trolltech
michael@0 7 *
michael@0 8 * Permission to use, copy, modify, distribute, and sell this software and its
michael@0 9 * documentation for any purpose is hereby granted without fee, provided that
michael@0 10 * the above copyright notice appear in all copies and that both that
michael@0 11 * copyright notice and this permission notice appear in supporting
michael@0 12 * documentation, and that the name of Keith Packard not be used in
michael@0 13 * advertising or publicity pertaining to distribution of the software without
michael@0 14 * specific, written prior permission. Keith Packard makes no
michael@0 15 * representations about the suitability of this software for any purpose. It
michael@0 16 * is provided "as is" without express or implied warranty.
michael@0 17 *
michael@0 18 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
michael@0 19 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
michael@0 20 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
michael@0 21 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
michael@0 22 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
michael@0 23 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
michael@0 24 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
michael@0 25 * SOFTWARE.
michael@0 26 */
michael@0 27
michael@0 28 #ifdef HAVE_CONFIG_H
michael@0 29 #include <config.h>
michael@0 30 #endif
michael@0 31 #include <stdlib.h>
michael@0 32 #include "pixman-private.h"
michael@0 33
michael@0 34 #include "pixman-dither.h"
michael@0 35
michael@0 36 static pixman_bool_t
michael@0 37 linear_gradient_is_horizontal (pixman_image_t *image,
michael@0 38 int x,
michael@0 39 int y,
michael@0 40 int width,
michael@0 41 int height)
michael@0 42 {
michael@0 43 linear_gradient_t *linear = (linear_gradient_t *)image;
michael@0 44 pixman_vector_t v;
michael@0 45 pixman_fixed_32_32_t l;
michael@0 46 pixman_fixed_48_16_t dx, dy;
michael@0 47 double inc;
michael@0 48
michael@0 49 if (image->common.transform)
michael@0 50 {
michael@0 51 /* projective transformation */
michael@0 52 if (image->common.transform->matrix[2][0] != 0 ||
michael@0 53 image->common.transform->matrix[2][1] != 0 ||
michael@0 54 image->common.transform->matrix[2][2] == 0)
michael@0 55 {
michael@0 56 return FALSE;
michael@0 57 }
michael@0 58
michael@0 59 v.vector[0] = image->common.transform->matrix[0][1];
michael@0 60 v.vector[1] = image->common.transform->matrix[1][1];
michael@0 61 v.vector[2] = image->common.transform->matrix[2][2];
michael@0 62 }
michael@0 63 else
michael@0 64 {
michael@0 65 v.vector[0] = 0;
michael@0 66 v.vector[1] = pixman_fixed_1;
michael@0 67 v.vector[2] = pixman_fixed_1;
michael@0 68 }
michael@0 69
michael@0 70 dx = linear->p2.x - linear->p1.x;
michael@0 71 dy = linear->p2.y - linear->p1.y;
michael@0 72
michael@0 73 l = dx * dx + dy * dy;
michael@0 74
michael@0 75 if (l == 0)
michael@0 76 return FALSE;
michael@0 77
michael@0 78 /*
michael@0 79 * compute how much the input of the gradient walked changes
michael@0 80 * when moving vertically through the whole image
michael@0 81 */
michael@0 82 inc = height * (double) pixman_fixed_1 * pixman_fixed_1 *
michael@0 83 (dx * v.vector[0] + dy * v.vector[1]) /
michael@0 84 (v.vector[2] * (double) l);
michael@0 85
michael@0 86 /* check that casting to integer would result in 0 */
michael@0 87 if (-1 < inc && inc < 1)
michael@0 88 return TRUE;
michael@0 89
michael@0 90 return FALSE;
michael@0 91 }
michael@0 92
michael@0 93 static uint32_t *
michael@0 94 linear_get_scanline_narrow (pixman_iter_t *iter,
michael@0 95 const uint32_t *mask)
michael@0 96 {
michael@0 97 pixman_image_t *image = iter->image;
michael@0 98 int x = iter->x;
michael@0 99 int y = iter->y;
michael@0 100 int width = iter->width;
michael@0 101 uint32_t * buffer = iter->buffer;
michael@0 102
michael@0 103 pixman_vector_t v, unit;
michael@0 104 pixman_fixed_32_32_t l;
michael@0 105 pixman_fixed_48_16_t dx, dy;
michael@0 106 gradient_t *gradient = (gradient_t *)image;
michael@0 107 linear_gradient_t *linear = (linear_gradient_t *)image;
michael@0 108 uint32_t *end = buffer + width;
michael@0 109 pixman_gradient_walker_t walker;
michael@0 110
michael@0 111 _pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
michael@0 112
michael@0 113 /* reference point is the center of the pixel */
michael@0 114 v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
michael@0 115 v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
michael@0 116 v.vector[2] = pixman_fixed_1;
michael@0 117
michael@0 118 if (image->common.transform)
michael@0 119 {
michael@0 120 if (!pixman_transform_point_3d (image->common.transform, &v))
michael@0 121 return iter->buffer;
michael@0 122
michael@0 123 unit.vector[0] = image->common.transform->matrix[0][0];
michael@0 124 unit.vector[1] = image->common.transform->matrix[1][0];
michael@0 125 unit.vector[2] = image->common.transform->matrix[2][0];
michael@0 126 }
michael@0 127 else
michael@0 128 {
michael@0 129 unit.vector[0] = pixman_fixed_1;
michael@0 130 unit.vector[1] = 0;
michael@0 131 unit.vector[2] = 0;
michael@0 132 }
michael@0 133
michael@0 134 dx = linear->p2.x - linear->p1.x;
michael@0 135 dy = linear->p2.y - linear->p1.y;
michael@0 136
michael@0 137 l = dx * dx + dy * dy;
michael@0 138
michael@0 139 if (l == 0 || unit.vector[2] == 0)
michael@0 140 {
michael@0 141 /* affine transformation only */
michael@0 142 pixman_fixed_32_32_t t, next_inc;
michael@0 143 double inc;
michael@0 144
michael@0 145 if (l == 0 || v.vector[2] == 0)
michael@0 146 {
michael@0 147 t = 0;
michael@0 148 inc = 0;
michael@0 149 }
michael@0 150 else
michael@0 151 {
michael@0 152 double invden, v2;
michael@0 153
michael@0 154 invden = pixman_fixed_1 * (double) pixman_fixed_1 /
michael@0 155 (l * (double) v.vector[2]);
michael@0 156 v2 = v.vector[2] * (1. / pixman_fixed_1);
michael@0 157 t = ((dx * v.vector[0] + dy * v.vector[1]) -
michael@0 158 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
michael@0 159 inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden;
michael@0 160 }
michael@0 161 next_inc = 0;
michael@0 162
michael@0 163 if (((pixman_fixed_32_32_t )(inc * width)) == 0)
michael@0 164 {
michael@0 165 register uint32_t color;
michael@0 166
michael@0 167 color = _pixman_gradient_walker_pixel (&walker, t);
michael@0 168 while (buffer < end)
michael@0 169 *buffer++ = color;
michael@0 170 }
michael@0 171 else
michael@0 172 {
michael@0 173 int i;
michael@0 174
michael@0 175 i = 0;
michael@0 176 while (buffer < end)
michael@0 177 {
michael@0 178 if (!mask || *mask++)
michael@0 179 {
michael@0 180 *buffer = _pixman_gradient_walker_pixel (&walker,
michael@0 181 t + next_inc);
michael@0 182 }
michael@0 183 i++;
michael@0 184 next_inc = inc * i;
michael@0 185 buffer++;
michael@0 186 }
michael@0 187 }
michael@0 188 }
michael@0 189 else
michael@0 190 {
michael@0 191 /* projective transformation */
michael@0 192 double t;
michael@0 193
michael@0 194 t = 0;
michael@0 195
michael@0 196 while (buffer < end)
michael@0 197 {
michael@0 198 if (!mask || *mask++)
michael@0 199 {
michael@0 200 if (v.vector[2] != 0)
michael@0 201 {
michael@0 202 double invden, v2;
michael@0 203
michael@0 204 invden = pixman_fixed_1 * (double) pixman_fixed_1 /
michael@0 205 (l * (double) v.vector[2]);
michael@0 206 v2 = v.vector[2] * (1. / pixman_fixed_1);
michael@0 207 t = ((dx * v.vector[0] + dy * v.vector[1]) -
michael@0 208 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
michael@0 209 }
michael@0 210
michael@0 211 *buffer = _pixman_gradient_walker_pixel (&walker, t);
michael@0 212 }
michael@0 213
michael@0 214 ++buffer;
michael@0 215
michael@0 216 v.vector[0] += unit.vector[0];
michael@0 217 v.vector[1] += unit.vector[1];
michael@0 218 v.vector[2] += unit.vector[2];
michael@0 219 }
michael@0 220 }
michael@0 221
michael@0 222 iter->y++;
michael@0 223
michael@0 224 return iter->buffer;
michael@0 225 }
michael@0 226
michael@0 227 static uint32_t *
michael@0 228 linear_get_scanline_16 (pixman_iter_t *iter,
michael@0 229 const uint32_t *mask)
michael@0 230 {
michael@0 231 pixman_image_t *image = iter->image;
michael@0 232 int x = iter->x;
michael@0 233 int y = iter->y;
michael@0 234 int width = iter->width;
michael@0 235 uint16_t * buffer = (uint16_t*)iter->buffer;
michael@0 236 pixman_bool_t toggle = ((x ^ y) & 1);
michael@0 237
michael@0 238 pixman_vector_t v, unit;
michael@0 239 pixman_fixed_32_32_t l;
michael@0 240 pixman_fixed_48_16_t dx, dy;
michael@0 241 gradient_t *gradient = (gradient_t *)image;
michael@0 242 linear_gradient_t *linear = (linear_gradient_t *)image;
michael@0 243 uint16_t *end = buffer + width;
michael@0 244 pixman_gradient_walker_t walker;
michael@0 245
michael@0 246 _pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
michael@0 247
michael@0 248 /* reference point is the center of the pixel */
michael@0 249 v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
michael@0 250 v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
michael@0 251 v.vector[2] = pixman_fixed_1;
michael@0 252
michael@0 253 if (image->common.transform)
michael@0 254 {
michael@0 255 if (!pixman_transform_point_3d (image->common.transform, &v))
michael@0 256 return iter->buffer;
michael@0 257
michael@0 258 unit.vector[0] = image->common.transform->matrix[0][0];
michael@0 259 unit.vector[1] = image->common.transform->matrix[1][0];
michael@0 260 unit.vector[2] = image->common.transform->matrix[2][0];
michael@0 261 }
michael@0 262 else
michael@0 263 {
michael@0 264 unit.vector[0] = pixman_fixed_1;
michael@0 265 unit.vector[1] = 0;
michael@0 266 unit.vector[2] = 0;
michael@0 267 }
michael@0 268
michael@0 269 dx = linear->p2.x - linear->p1.x;
michael@0 270 dy = linear->p2.y - linear->p1.y;
michael@0 271
michael@0 272 l = dx * dx + dy * dy;
michael@0 273
michael@0 274 if (l == 0 || unit.vector[2] == 0)
michael@0 275 {
michael@0 276 /* affine transformation only */
michael@0 277 pixman_fixed_32_32_t t, next_inc;
michael@0 278 double inc;
michael@0 279
michael@0 280 if (l == 0 || v.vector[2] == 0)
michael@0 281 {
michael@0 282 t = 0;
michael@0 283 inc = 0;
michael@0 284 }
michael@0 285 else
michael@0 286 {
michael@0 287 double invden, v2;
michael@0 288
michael@0 289 invden = pixman_fixed_1 * (double) pixman_fixed_1 /
michael@0 290 (l * (double) v.vector[2]);
michael@0 291 v2 = v.vector[2] * (1. / pixman_fixed_1);
michael@0 292 t = ((dx * v.vector[0] + dy * v.vector[1]) -
michael@0 293 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
michael@0 294 inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden;
michael@0 295 }
michael@0 296 next_inc = 0;
michael@0 297
michael@0 298 if (((pixman_fixed_32_32_t )(inc * width)) == 0)
michael@0 299 {
michael@0 300 register uint32_t color;
michael@0 301 uint16_t dither_diff;
michael@0 302 uint16_t color16;
michael@0 303 uint16_t color16b;
michael@0 304
michael@0 305 color = _pixman_gradient_walker_pixel (&walker, t);
michael@0 306 color16 = dither_8888_to_0565(color, toggle);
michael@0 307 color16b = dither_8888_to_0565(color, toggle^1);
michael@0 308 // compute the difference
michael@0 309 dither_diff = color16 ^ color16b;
michael@0 310 while (buffer < end) {
michael@0 311 *buffer++ = color16;
michael@0 312 // use dither_diff to toggle between color16 and color16b
michael@0 313 color16 ^= dither_diff;
michael@0 314 toggle ^= 1;
michael@0 315 }
michael@0 316 }
michael@0 317 else
michael@0 318 {
michael@0 319 int i;
michael@0 320
michael@0 321 i = 0;
michael@0 322 while (buffer < end)
michael@0 323 {
michael@0 324 if (!mask || *mask++)
michael@0 325 {
michael@0 326 *buffer = dither_8888_to_0565(_pixman_gradient_walker_pixel (&walker,
michael@0 327 t + next_inc),
michael@0 328 toggle);
michael@0 329 }
michael@0 330 toggle ^= 1;
michael@0 331 i++;
michael@0 332 next_inc = inc * i;
michael@0 333 buffer++;
michael@0 334 }
michael@0 335 }
michael@0 336 }
michael@0 337 else
michael@0 338 {
michael@0 339 /* projective transformation */
michael@0 340 double t;
michael@0 341
michael@0 342 t = 0;
michael@0 343
michael@0 344 while (buffer < end)
michael@0 345 {
michael@0 346 if (!mask || *mask++)
michael@0 347 {
michael@0 348 if (v.vector[2] != 0)
michael@0 349 {
michael@0 350 double invden, v2;
michael@0 351
michael@0 352 invden = pixman_fixed_1 * (double) pixman_fixed_1 /
michael@0 353 (l * (double) v.vector[2]);
michael@0 354 v2 = v.vector[2] * (1. / pixman_fixed_1);
michael@0 355 t = ((dx * v.vector[0] + dy * v.vector[1]) -
michael@0 356 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
michael@0 357 }
michael@0 358
michael@0 359 *buffer = dither_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t),
michael@0 360 toggle);
michael@0 361 }
michael@0 362 toggle ^= 1;
michael@0 363
michael@0 364 ++buffer;
michael@0 365
michael@0 366 v.vector[0] += unit.vector[0];
michael@0 367 v.vector[1] += unit.vector[1];
michael@0 368 v.vector[2] += unit.vector[2];
michael@0 369 }
michael@0 370 }
michael@0 371
michael@0 372 iter->y++;
michael@0 373
michael@0 374 return iter->buffer;
michael@0 375 }
michael@0 376
michael@0 377 static uint32_t *
michael@0 378 linear_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
michael@0 379 {
michael@0 380 uint32_t *buffer = linear_get_scanline_narrow (iter, NULL);
michael@0 381
michael@0 382 pixman_expand_to_float (
michael@0 383 (argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
michael@0 384
michael@0 385 return buffer;
michael@0 386 }
michael@0 387
michael@0 388 void
michael@0 389 _pixman_linear_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter)
michael@0 390 {
michael@0 391 // XXX: we can't use this optimization when dithering
michael@0 392 if (0 && linear_gradient_is_horizontal (
michael@0 393 iter->image, iter->x, iter->y, iter->width, iter->height))
michael@0 394 {
michael@0 395 if (iter->iter_flags & ITER_16)
michael@0 396 linear_get_scanline_16 (iter, NULL);
michael@0 397 else if (iter->iter_flags & ITER_NARROW)
michael@0 398 linear_get_scanline_narrow (iter, NULL);
michael@0 399 else
michael@0 400 linear_get_scanline_wide (iter, NULL);
michael@0 401
michael@0 402 iter->get_scanline = _pixman_iter_get_scanline_noop;
michael@0 403 }
michael@0 404 else
michael@0 405 {
michael@0 406 if (iter->iter_flags & ITER_16)
michael@0 407 iter->get_scanline = linear_get_scanline_16;
michael@0 408 else if (iter->iter_flags & ITER_NARROW)
michael@0 409 iter->get_scanline = linear_get_scanline_narrow;
michael@0 410 else
michael@0 411 iter->get_scanline = linear_get_scanline_wide;
michael@0 412 }
michael@0 413 }
michael@0 414
michael@0 415 PIXMAN_EXPORT pixman_image_t *
michael@0 416 pixman_image_create_linear_gradient (const pixman_point_fixed_t * p1,
michael@0 417 const pixman_point_fixed_t * p2,
michael@0 418 const pixman_gradient_stop_t *stops,
michael@0 419 int n_stops)
michael@0 420 {
michael@0 421 pixman_image_t *image;
michael@0 422 linear_gradient_t *linear;
michael@0 423
michael@0 424 image = _pixman_image_allocate ();
michael@0 425
michael@0 426 if (!image)
michael@0 427 return NULL;
michael@0 428
michael@0 429 linear = &image->linear;
michael@0 430
michael@0 431 if (!_pixman_init_gradient (&linear->common, stops, n_stops))
michael@0 432 {
michael@0 433 free (image);
michael@0 434 return NULL;
michael@0 435 }
michael@0 436
michael@0 437 linear->p1 = *p1;
michael@0 438 linear->p2 = *p2;
michael@0 439
michael@0 440 image->type = LINEAR;
michael@0 441
michael@0 442 return image;
michael@0 443 }
michael@0 444

mercurial