Wed, 31 Dec 2014 06:09:35 +0100
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 |