gfx/cairo/libpixman/src/pixman-image.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /*
michael@0 2 * Copyright © 2000 SuSE, Inc.
michael@0 3 * Copyright © 2007 Red Hat, Inc.
michael@0 4 *
michael@0 5 * Permission to use, copy, modify, distribute, and sell this software and its
michael@0 6 * documentation for any purpose is hereby granted without fee, provided that
michael@0 7 * the above copyright notice appear in all copies and that both that
michael@0 8 * copyright notice and this permission notice appear in supporting
michael@0 9 * documentation, and that the name of SuSE not be used in advertising or
michael@0 10 * publicity pertaining to distribution of the software without specific,
michael@0 11 * written prior permission. SuSE makes no representations about the
michael@0 12 * suitability of this software for any purpose. It is provided "as is"
michael@0 13 * without express or implied warranty.
michael@0 14 *
michael@0 15 * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
michael@0 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
michael@0 17 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
michael@0 18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
michael@0 19 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
michael@0 20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
michael@0 21 */
michael@0 22
michael@0 23 #ifdef HAVE_CONFIG_H
michael@0 24 #include <config.h>
michael@0 25 #endif
michael@0 26
michael@0 27 #include <stdlib.h>
michael@0 28 #include <stdio.h>
michael@0 29 #include <string.h>
michael@0 30 #include <assert.h>
michael@0 31
michael@0 32 #include "pixman-private.h"
michael@0 33
michael@0 34 static const pixman_color_t transparent_black = { 0, 0, 0, 0 };
michael@0 35
michael@0 36 static void
michael@0 37 gradient_property_changed (pixman_image_t *image)
michael@0 38 {
michael@0 39 gradient_t *gradient = &image->gradient;
michael@0 40 int n = gradient->n_stops;
michael@0 41 pixman_gradient_stop_t *stops = gradient->stops;
michael@0 42 pixman_gradient_stop_t *begin = &(gradient->stops[-1]);
michael@0 43 pixman_gradient_stop_t *end = &(gradient->stops[n]);
michael@0 44
michael@0 45 switch (gradient->common.repeat)
michael@0 46 {
michael@0 47 default:
michael@0 48 case PIXMAN_REPEAT_NONE:
michael@0 49 begin->x = INT32_MIN;
michael@0 50 begin->color = transparent_black;
michael@0 51 end->x = INT32_MAX;
michael@0 52 end->color = transparent_black;
michael@0 53 break;
michael@0 54
michael@0 55 case PIXMAN_REPEAT_NORMAL:
michael@0 56 begin->x = stops[n - 1].x - pixman_fixed_1;
michael@0 57 begin->color = stops[n - 1].color;
michael@0 58 end->x = stops[0].x + pixman_fixed_1;
michael@0 59 end->color = stops[0].color;
michael@0 60 break;
michael@0 61
michael@0 62 case PIXMAN_REPEAT_REFLECT:
michael@0 63 begin->x = - stops[0].x;
michael@0 64 begin->color = stops[0].color;
michael@0 65 end->x = pixman_int_to_fixed (2) - stops[n - 1].x;
michael@0 66 end->color = stops[n - 1].color;
michael@0 67 break;
michael@0 68
michael@0 69 case PIXMAN_REPEAT_PAD:
michael@0 70 begin->x = INT32_MIN;
michael@0 71 begin->color = stops[0].color;
michael@0 72 end->x = INT32_MAX;
michael@0 73 end->color = stops[n - 1].color;
michael@0 74 break;
michael@0 75 }
michael@0 76 }
michael@0 77
michael@0 78 pixman_bool_t
michael@0 79 _pixman_init_gradient (gradient_t * gradient,
michael@0 80 const pixman_gradient_stop_t *stops,
michael@0 81 int n_stops)
michael@0 82 {
michael@0 83 return_val_if_fail (n_stops > 0, FALSE);
michael@0 84
michael@0 85 /* We allocate two extra stops, one before the beginning of the stop list,
michael@0 86 * and one after the end. These stops are initialized to whatever color
michael@0 87 * would be used for positions outside the range of the stop list.
michael@0 88 *
michael@0 89 * This saves a bit of computation in the gradient walker.
michael@0 90 *
michael@0 91 * The pointer we store in the gradient_t struct still points to the
michael@0 92 * first user-supplied struct, so when freeing, we will have to
michael@0 93 * subtract one.
michael@0 94 */
michael@0 95 gradient->stops =
michael@0 96 pixman_malloc_ab (n_stops + 2, sizeof (pixman_gradient_stop_t));
michael@0 97 if (!gradient->stops)
michael@0 98 return FALSE;
michael@0 99
michael@0 100 gradient->stops += 1;
michael@0 101 memcpy (gradient->stops, stops, n_stops * sizeof (pixman_gradient_stop_t));
michael@0 102 gradient->n_stops = n_stops;
michael@0 103
michael@0 104 gradient->common.property_changed = gradient_property_changed;
michael@0 105
michael@0 106 return TRUE;
michael@0 107 }
michael@0 108
michael@0 109 void
michael@0 110 _pixman_image_init (pixman_image_t *image)
michael@0 111 {
michael@0 112 image_common_t *common = &image->common;
michael@0 113
michael@0 114 pixman_region32_init (&common->clip_region);
michael@0 115
michael@0 116 common->alpha_count = 0;
michael@0 117 common->have_clip_region = FALSE;
michael@0 118 common->clip_sources = FALSE;
michael@0 119 common->transform = NULL;
michael@0 120 common->repeat = PIXMAN_REPEAT_NONE;
michael@0 121 common->filter = PIXMAN_FILTER_NEAREST;
michael@0 122 common->filter_params = NULL;
michael@0 123 common->n_filter_params = 0;
michael@0 124 common->alpha_map = NULL;
michael@0 125 common->component_alpha = FALSE;
michael@0 126 common->ref_count = 1;
michael@0 127 common->property_changed = NULL;
michael@0 128 common->client_clip = FALSE;
michael@0 129 common->destroy_func = NULL;
michael@0 130 common->destroy_data = NULL;
michael@0 131 common->dirty = TRUE;
michael@0 132 }
michael@0 133
michael@0 134 pixman_bool_t
michael@0 135 _pixman_image_fini (pixman_image_t *image)
michael@0 136 {
michael@0 137 image_common_t *common = (image_common_t *)image;
michael@0 138
michael@0 139 common->ref_count--;
michael@0 140
michael@0 141 if (common->ref_count == 0)
michael@0 142 {
michael@0 143 if (image->common.destroy_func)
michael@0 144 image->common.destroy_func (image, image->common.destroy_data);
michael@0 145
michael@0 146 pixman_region32_fini (&common->clip_region);
michael@0 147
michael@0 148 free (common->transform);
michael@0 149 free (common->filter_params);
michael@0 150
michael@0 151 if (common->alpha_map)
michael@0 152 pixman_image_unref ((pixman_image_t *)common->alpha_map);
michael@0 153
michael@0 154 if (image->type == LINEAR ||
michael@0 155 image->type == RADIAL ||
michael@0 156 image->type == CONICAL)
michael@0 157 {
michael@0 158 if (image->gradient.stops)
michael@0 159 {
michael@0 160 /* See _pixman_init_gradient() for an explanation of the - 1 */
michael@0 161 free (image->gradient.stops - 1);
michael@0 162 }
michael@0 163
michael@0 164 /* This will trigger if someone adds a property_changed
michael@0 165 * method to the linear/radial/conical gradient overwriting
michael@0 166 * the general one.
michael@0 167 */
michael@0 168 assert (
michael@0 169 image->common.property_changed == gradient_property_changed);
michael@0 170 }
michael@0 171
michael@0 172 if (image->type == BITS && image->bits.free_me)
michael@0 173 free (image->bits.free_me);
michael@0 174
michael@0 175 return TRUE;
michael@0 176 }
michael@0 177
michael@0 178 return FALSE;
michael@0 179 }
michael@0 180
michael@0 181 pixman_image_t *
michael@0 182 _pixman_image_allocate (void)
michael@0 183 {
michael@0 184 pixman_image_t *image = malloc (sizeof (pixman_image_t));
michael@0 185
michael@0 186 if (image)
michael@0 187 _pixman_image_init (image);
michael@0 188
michael@0 189 return image;
michael@0 190 }
michael@0 191
michael@0 192 static void
michael@0 193 image_property_changed (pixman_image_t *image)
michael@0 194 {
michael@0 195 image->common.dirty = TRUE;
michael@0 196 }
michael@0 197
michael@0 198 /* Ref Counting */
michael@0 199 PIXMAN_EXPORT pixman_image_t *
michael@0 200 pixman_image_ref (pixman_image_t *image)
michael@0 201 {
michael@0 202 image->common.ref_count++;
michael@0 203
michael@0 204 return image;
michael@0 205 }
michael@0 206
michael@0 207 /* returns TRUE when the image is freed */
michael@0 208 PIXMAN_EXPORT pixman_bool_t
michael@0 209 pixman_image_unref (pixman_image_t *image)
michael@0 210 {
michael@0 211 if (_pixman_image_fini (image))
michael@0 212 {
michael@0 213 free (image);
michael@0 214 return TRUE;
michael@0 215 }
michael@0 216
michael@0 217 return FALSE;
michael@0 218 }
michael@0 219
michael@0 220 PIXMAN_EXPORT void
michael@0 221 pixman_image_set_destroy_function (pixman_image_t * image,
michael@0 222 pixman_image_destroy_func_t func,
michael@0 223 void * data)
michael@0 224 {
michael@0 225 image->common.destroy_func = func;
michael@0 226 image->common.destroy_data = data;
michael@0 227 }
michael@0 228
michael@0 229 PIXMAN_EXPORT void *
michael@0 230 pixman_image_get_destroy_data (pixman_image_t *image)
michael@0 231 {
michael@0 232 return image->common.destroy_data;
michael@0 233 }
michael@0 234
michael@0 235 void
michael@0 236 _pixman_image_reset_clip_region (pixman_image_t *image)
michael@0 237 {
michael@0 238 image->common.have_clip_region = FALSE;
michael@0 239 }
michael@0 240
michael@0 241 /* Executive Summary: This function is a no-op that only exists
michael@0 242 * for historical reasons.
michael@0 243 *
michael@0 244 * There used to be a bug in the X server where it would rely on
michael@0 245 * out-of-bounds accesses when it was asked to composite with a
michael@0 246 * window as the source. It would create a pixman image pointing
michael@0 247 * to some bogus position in memory, but then set a clip region
michael@0 248 * to the position where the actual bits were.
michael@0 249 *
michael@0 250 * Due to a bug in old versions of pixman, where it would not clip
michael@0 251 * against the image bounds when a clip region was set, this would
michael@0 252 * actually work. So when the pixman bug was fixed, a workaround was
michael@0 253 * added to allow certain out-of-bound accesses. This function disabled
michael@0 254 * those workarounds.
michael@0 255 *
michael@0 256 * Since 0.21.2, pixman doesn't do these workarounds anymore, so now
michael@0 257 * this function is a no-op.
michael@0 258 */
michael@0 259 PIXMAN_EXPORT void
michael@0 260 pixman_disable_out_of_bounds_workaround (void)
michael@0 261 {
michael@0 262 }
michael@0 263
michael@0 264 static void
michael@0 265 compute_image_info (pixman_image_t *image)
michael@0 266 {
michael@0 267 pixman_format_code_t code;
michael@0 268 uint32_t flags = 0;
michael@0 269
michael@0 270 /* Transform */
michael@0 271 if (!image->common.transform)
michael@0 272 {
michael@0 273 flags |= (FAST_PATH_ID_TRANSFORM |
michael@0 274 FAST_PATH_X_UNIT_POSITIVE |
michael@0 275 FAST_PATH_Y_UNIT_ZERO |
michael@0 276 FAST_PATH_AFFINE_TRANSFORM);
michael@0 277 }
michael@0 278 else
michael@0 279 {
michael@0 280 flags |= FAST_PATH_HAS_TRANSFORM;
michael@0 281
michael@0 282 if (image->common.transform->matrix[2][0] == 0 &&
michael@0 283 image->common.transform->matrix[2][1] == 0 &&
michael@0 284 image->common.transform->matrix[2][2] == pixman_fixed_1)
michael@0 285 {
michael@0 286 flags |= FAST_PATH_AFFINE_TRANSFORM;
michael@0 287
michael@0 288 if (image->common.transform->matrix[0][1] == 0 &&
michael@0 289 image->common.transform->matrix[1][0] == 0)
michael@0 290 {
michael@0 291 if (image->common.transform->matrix[0][0] == -pixman_fixed_1 &&
michael@0 292 image->common.transform->matrix[1][1] == -pixman_fixed_1)
michael@0 293 {
michael@0 294 flags |= FAST_PATH_ROTATE_180_TRANSFORM;
michael@0 295 }
michael@0 296 flags |= FAST_PATH_SCALE_TRANSFORM;
michael@0 297 }
michael@0 298 else if (image->common.transform->matrix[0][0] == 0 &&
michael@0 299 image->common.transform->matrix[1][1] == 0)
michael@0 300 {
michael@0 301 pixman_fixed_t m01 = image->common.transform->matrix[0][1];
michael@0 302 pixman_fixed_t m10 = image->common.transform->matrix[1][0];
michael@0 303
michael@0 304 if (m01 == -pixman_fixed_1 && m10 == pixman_fixed_1)
michael@0 305 flags |= FAST_PATH_ROTATE_90_TRANSFORM;
michael@0 306 else if (m01 == pixman_fixed_1 && m10 == -pixman_fixed_1)
michael@0 307 flags |= FAST_PATH_ROTATE_270_TRANSFORM;
michael@0 308 }
michael@0 309 }
michael@0 310
michael@0 311 if (image->common.transform->matrix[0][0] > 0)
michael@0 312 flags |= FAST_PATH_X_UNIT_POSITIVE;
michael@0 313
michael@0 314 if (image->common.transform->matrix[1][0] == 0)
michael@0 315 flags |= FAST_PATH_Y_UNIT_ZERO;
michael@0 316 }
michael@0 317
michael@0 318 /* Filter */
michael@0 319 switch (image->common.filter)
michael@0 320 {
michael@0 321 case PIXMAN_FILTER_NEAREST:
michael@0 322 case PIXMAN_FILTER_FAST:
michael@0 323 flags |= (FAST_PATH_NEAREST_FILTER | FAST_PATH_NO_CONVOLUTION_FILTER);
michael@0 324 break;
michael@0 325
michael@0 326 case PIXMAN_FILTER_BILINEAR:
michael@0 327 case PIXMAN_FILTER_GOOD:
michael@0 328 case PIXMAN_FILTER_BEST:
michael@0 329 flags |= (FAST_PATH_BILINEAR_FILTER | FAST_PATH_NO_CONVOLUTION_FILTER);
michael@0 330
michael@0 331 /* Here we have a chance to optimize BILINEAR filter to NEAREST if
michael@0 332 * they are equivalent for the currently used transformation matrix.
michael@0 333 */
michael@0 334 if (flags & FAST_PATH_ID_TRANSFORM)
michael@0 335 {
michael@0 336 flags |= FAST_PATH_NEAREST_FILTER;
michael@0 337 }
michael@0 338 else if (
michael@0 339 /* affine and integer translation components in matrix ... */
michael@0 340 ((flags & FAST_PATH_AFFINE_TRANSFORM) &&
michael@0 341 !pixman_fixed_frac (image->common.transform->matrix[0][2] |
michael@0 342 image->common.transform->matrix[1][2])) &&
michael@0 343 (
michael@0 344 /* ... combined with a simple rotation */
michael@0 345 (flags & (FAST_PATH_ROTATE_90_TRANSFORM |
michael@0 346 FAST_PATH_ROTATE_180_TRANSFORM |
michael@0 347 FAST_PATH_ROTATE_270_TRANSFORM)) ||
michael@0 348 /* ... or combined with a simple non-rotated translation */
michael@0 349 (image->common.transform->matrix[0][0] == pixman_fixed_1 &&
michael@0 350 image->common.transform->matrix[1][1] == pixman_fixed_1 &&
michael@0 351 image->common.transform->matrix[0][1] == 0 &&
michael@0 352 image->common.transform->matrix[1][0] == 0)
michael@0 353 )
michael@0 354 )
michael@0 355 {
michael@0 356 /* FIXME: there are some affine-test failures, showing that
michael@0 357 * handling of BILINEAR and NEAREST filter is not quite
michael@0 358 * equivalent when getting close to 32K for the translation
michael@0 359 * components of the matrix. That's likely some bug, but for
michael@0 360 * now just skip BILINEAR->NEAREST optimization in this case.
michael@0 361 */
michael@0 362 pixman_fixed_t magic_limit = pixman_int_to_fixed (30000);
michael@0 363 if (image->common.transform->matrix[0][2] <= magic_limit &&
michael@0 364 image->common.transform->matrix[1][2] <= magic_limit &&
michael@0 365 image->common.transform->matrix[0][2] >= -magic_limit &&
michael@0 366 image->common.transform->matrix[1][2] >= -magic_limit)
michael@0 367 {
michael@0 368 flags |= FAST_PATH_NEAREST_FILTER;
michael@0 369 }
michael@0 370 }
michael@0 371 break;
michael@0 372
michael@0 373 case PIXMAN_FILTER_CONVOLUTION:
michael@0 374 break;
michael@0 375
michael@0 376 case PIXMAN_FILTER_SEPARABLE_CONVOLUTION:
michael@0 377 flags |= FAST_PATH_SEPARABLE_CONVOLUTION_FILTER;
michael@0 378 break;
michael@0 379
michael@0 380 default:
michael@0 381 flags |= FAST_PATH_NO_CONVOLUTION_FILTER;
michael@0 382 break;
michael@0 383 }
michael@0 384
michael@0 385 /* Repeat mode */
michael@0 386 switch (image->common.repeat)
michael@0 387 {
michael@0 388 case PIXMAN_REPEAT_NONE:
michael@0 389 flags |=
michael@0 390 FAST_PATH_NO_REFLECT_REPEAT |
michael@0 391 FAST_PATH_NO_PAD_REPEAT |
michael@0 392 FAST_PATH_NO_NORMAL_REPEAT;
michael@0 393 break;
michael@0 394
michael@0 395 case PIXMAN_REPEAT_REFLECT:
michael@0 396 flags |=
michael@0 397 FAST_PATH_NO_PAD_REPEAT |
michael@0 398 FAST_PATH_NO_NONE_REPEAT |
michael@0 399 FAST_PATH_NO_NORMAL_REPEAT;
michael@0 400 break;
michael@0 401
michael@0 402 case PIXMAN_REPEAT_PAD:
michael@0 403 flags |=
michael@0 404 FAST_PATH_NO_REFLECT_REPEAT |
michael@0 405 FAST_PATH_NO_NONE_REPEAT |
michael@0 406 FAST_PATH_NO_NORMAL_REPEAT;
michael@0 407 break;
michael@0 408
michael@0 409 default:
michael@0 410 flags |=
michael@0 411 FAST_PATH_NO_REFLECT_REPEAT |
michael@0 412 FAST_PATH_NO_PAD_REPEAT |
michael@0 413 FAST_PATH_NO_NONE_REPEAT;
michael@0 414 break;
michael@0 415 }
michael@0 416
michael@0 417 /* Component alpha */
michael@0 418 if (image->common.component_alpha)
michael@0 419 flags |= FAST_PATH_COMPONENT_ALPHA;
michael@0 420 else
michael@0 421 flags |= FAST_PATH_UNIFIED_ALPHA;
michael@0 422
michael@0 423 flags |= (FAST_PATH_NO_ACCESSORS | FAST_PATH_NARROW_FORMAT);
michael@0 424
michael@0 425 /* Type specific checks */
michael@0 426 switch (image->type)
michael@0 427 {
michael@0 428 case SOLID:
michael@0 429 code = PIXMAN_solid;
michael@0 430
michael@0 431 if (image->solid.color.alpha == 0xffff)
michael@0 432 flags |= FAST_PATH_IS_OPAQUE;
michael@0 433 break;
michael@0 434
michael@0 435 case BITS:
michael@0 436 if (image->bits.width == 1 &&
michael@0 437 image->bits.height == 1 &&
michael@0 438 image->common.repeat != PIXMAN_REPEAT_NONE)
michael@0 439 {
michael@0 440 code = PIXMAN_solid;
michael@0 441 }
michael@0 442 else
michael@0 443 {
michael@0 444 code = image->bits.format;
michael@0 445 flags |= FAST_PATH_BITS_IMAGE;
michael@0 446 }
michael@0 447
michael@0 448 if (!PIXMAN_FORMAT_A (image->bits.format) &&
michael@0 449 PIXMAN_FORMAT_TYPE (image->bits.format) != PIXMAN_TYPE_GRAY &&
michael@0 450 PIXMAN_FORMAT_TYPE (image->bits.format) != PIXMAN_TYPE_COLOR)
michael@0 451 {
michael@0 452 flags |= FAST_PATH_SAMPLES_OPAQUE;
michael@0 453
michael@0 454 if (image->common.repeat != PIXMAN_REPEAT_NONE)
michael@0 455 flags |= FAST_PATH_IS_OPAQUE;
michael@0 456 }
michael@0 457
michael@0 458 if (image->bits.read_func || image->bits.write_func)
michael@0 459 flags &= ~FAST_PATH_NO_ACCESSORS;
michael@0 460
michael@0 461 if (PIXMAN_FORMAT_IS_WIDE (image->bits.format))
michael@0 462 flags &= ~FAST_PATH_NARROW_FORMAT;
michael@0 463
michael@0 464 if (image->bits.format == PIXMAN_r5g6b5)
michael@0 465 flags |= FAST_PATH_16_FORMAT;
michael@0 466
michael@0 467 break;
michael@0 468
michael@0 469 case RADIAL:
michael@0 470 code = PIXMAN_unknown;
michael@0 471
michael@0 472 /*
michael@0 473 * As explained in pixman-radial-gradient.c, every point of
michael@0 474 * the plane has a valid associated radius (and thus will be
michael@0 475 * colored) if and only if a is negative (i.e. one of the two
michael@0 476 * circles contains the other one).
michael@0 477 */
michael@0 478
michael@0 479 if (image->radial.a >= 0)
michael@0 480 break;
michael@0 481
michael@0 482 /* Fall through */
michael@0 483
michael@0 484 case CONICAL:
michael@0 485 case LINEAR:
michael@0 486 code = PIXMAN_unknown;
michael@0 487
michael@0 488 if (image->common.repeat != PIXMAN_REPEAT_NONE)
michael@0 489 {
michael@0 490 int i;
michael@0 491
michael@0 492 flags |= FAST_PATH_IS_OPAQUE;
michael@0 493 for (i = 0; i < image->gradient.n_stops; ++i)
michael@0 494 {
michael@0 495 if (image->gradient.stops[i].color.alpha != 0xffff)
michael@0 496 {
michael@0 497 flags &= ~FAST_PATH_IS_OPAQUE;
michael@0 498 break;
michael@0 499 }
michael@0 500 }
michael@0 501 }
michael@0 502 break;
michael@0 503
michael@0 504 default:
michael@0 505 code = PIXMAN_unknown;
michael@0 506 break;
michael@0 507 }
michael@0 508
michael@0 509 /* Alpha map */
michael@0 510 if (!image->common.alpha_map)
michael@0 511 {
michael@0 512 flags |= FAST_PATH_NO_ALPHA_MAP;
michael@0 513 }
michael@0 514 else
michael@0 515 {
michael@0 516 if (PIXMAN_FORMAT_IS_WIDE (image->common.alpha_map->format))
michael@0 517 flags &= ~FAST_PATH_NARROW_FORMAT;
michael@0 518 }
michael@0 519
michael@0 520 /* Both alpha maps and convolution filters can introduce
michael@0 521 * non-opaqueness in otherwise opaque images. Also
michael@0 522 * an image with component alpha turned on is only opaque
michael@0 523 * if all channels are opaque, so we simply turn it off
michael@0 524 * unconditionally for those images.
michael@0 525 */
michael@0 526 if (image->common.alpha_map ||
michael@0 527 image->common.filter == PIXMAN_FILTER_CONVOLUTION ||
michael@0 528 image->common.filter == PIXMAN_FILTER_SEPARABLE_CONVOLUTION ||
michael@0 529 image->common.component_alpha)
michael@0 530 {
michael@0 531 flags &= ~(FAST_PATH_IS_OPAQUE | FAST_PATH_SAMPLES_OPAQUE);
michael@0 532 }
michael@0 533
michael@0 534 image->common.flags = flags;
michael@0 535 image->common.extended_format_code = code;
michael@0 536 }
michael@0 537
michael@0 538 void
michael@0 539 _pixman_image_validate (pixman_image_t *image)
michael@0 540 {
michael@0 541 if (image->common.dirty)
michael@0 542 {
michael@0 543 compute_image_info (image);
michael@0 544
michael@0 545 /* It is important that property_changed is
michael@0 546 * called *after* compute_image_info() because
michael@0 547 * property_changed() can make use of the flags
michael@0 548 * to set up accessors etc.
michael@0 549 */
michael@0 550 if (image->common.property_changed)
michael@0 551 image->common.property_changed (image);
michael@0 552
michael@0 553 image->common.dirty = FALSE;
michael@0 554 }
michael@0 555
michael@0 556 if (image->common.alpha_map)
michael@0 557 _pixman_image_validate ((pixman_image_t *)image->common.alpha_map);
michael@0 558 }
michael@0 559
michael@0 560 PIXMAN_EXPORT pixman_bool_t
michael@0 561 pixman_image_set_clip_region32 (pixman_image_t * image,
michael@0 562 pixman_region32_t *region)
michael@0 563 {
michael@0 564 image_common_t *common = (image_common_t *)image;
michael@0 565 pixman_bool_t result;
michael@0 566
michael@0 567 if (region)
michael@0 568 {
michael@0 569 if ((result = pixman_region32_copy (&common->clip_region, region)))
michael@0 570 image->common.have_clip_region = TRUE;
michael@0 571 }
michael@0 572 else
michael@0 573 {
michael@0 574 _pixman_image_reset_clip_region (image);
michael@0 575
michael@0 576 result = TRUE;
michael@0 577 }
michael@0 578
michael@0 579 image_property_changed (image);
michael@0 580
michael@0 581 return result;
michael@0 582 }
michael@0 583
michael@0 584 PIXMAN_EXPORT pixman_bool_t
michael@0 585 pixman_image_set_clip_region (pixman_image_t * image,
michael@0 586 pixman_region16_t *region)
michael@0 587 {
michael@0 588 image_common_t *common = (image_common_t *)image;
michael@0 589 pixman_bool_t result;
michael@0 590
michael@0 591 if (region)
michael@0 592 {
michael@0 593 if ((result = pixman_region32_copy_from_region16 (&common->clip_region, region)))
michael@0 594 image->common.have_clip_region = TRUE;
michael@0 595 }
michael@0 596 else
michael@0 597 {
michael@0 598 _pixman_image_reset_clip_region (image);
michael@0 599
michael@0 600 result = TRUE;
michael@0 601 }
michael@0 602
michael@0 603 image_property_changed (image);
michael@0 604
michael@0 605 return result;
michael@0 606 }
michael@0 607
michael@0 608 PIXMAN_EXPORT void
michael@0 609 pixman_image_set_has_client_clip (pixman_image_t *image,
michael@0 610 pixman_bool_t client_clip)
michael@0 611 {
michael@0 612 image->common.client_clip = client_clip;
michael@0 613 }
michael@0 614
michael@0 615 PIXMAN_EXPORT pixman_bool_t
michael@0 616 pixman_image_set_transform (pixman_image_t * image,
michael@0 617 const pixman_transform_t *transform)
michael@0 618 {
michael@0 619 static const pixman_transform_t id =
michael@0 620 {
michael@0 621 { { pixman_fixed_1, 0, 0 },
michael@0 622 { 0, pixman_fixed_1, 0 },
michael@0 623 { 0, 0, pixman_fixed_1 } }
michael@0 624 };
michael@0 625
michael@0 626 image_common_t *common = (image_common_t *)image;
michael@0 627 pixman_bool_t result;
michael@0 628
michael@0 629 if (common->transform == transform)
michael@0 630 return TRUE;
michael@0 631
michael@0 632 if (!transform || memcmp (&id, transform, sizeof (pixman_transform_t)) == 0)
michael@0 633 {
michael@0 634 free (common->transform);
michael@0 635 common->transform = NULL;
michael@0 636 result = TRUE;
michael@0 637
michael@0 638 goto out;
michael@0 639 }
michael@0 640
michael@0 641 if (common->transform &&
michael@0 642 memcmp (common->transform, transform, sizeof (pixman_transform_t)) == 0)
michael@0 643 {
michael@0 644 return TRUE;
michael@0 645 }
michael@0 646
michael@0 647 if (common->transform == NULL)
michael@0 648 common->transform = malloc (sizeof (pixman_transform_t));
michael@0 649
michael@0 650 if (common->transform == NULL)
michael@0 651 {
michael@0 652 result = FALSE;
michael@0 653
michael@0 654 goto out;
michael@0 655 }
michael@0 656
michael@0 657 memcpy (common->transform, transform, sizeof(pixman_transform_t));
michael@0 658
michael@0 659 result = TRUE;
michael@0 660
michael@0 661 out:
michael@0 662 image_property_changed (image);
michael@0 663
michael@0 664 return result;
michael@0 665 }
michael@0 666
michael@0 667 PIXMAN_EXPORT void
michael@0 668 pixman_image_set_repeat (pixman_image_t *image,
michael@0 669 pixman_repeat_t repeat)
michael@0 670 {
michael@0 671 if (image->common.repeat == repeat)
michael@0 672 return;
michael@0 673
michael@0 674 image->common.repeat = repeat;
michael@0 675
michael@0 676 image_property_changed (image);
michael@0 677 }
michael@0 678
michael@0 679 PIXMAN_EXPORT pixman_bool_t
michael@0 680 pixman_image_set_filter (pixman_image_t * image,
michael@0 681 pixman_filter_t filter,
michael@0 682 const pixman_fixed_t *params,
michael@0 683 int n_params)
michael@0 684 {
michael@0 685 image_common_t *common = (image_common_t *)image;
michael@0 686 pixman_fixed_t *new_params;
michael@0 687
michael@0 688 if (params == common->filter_params && filter == common->filter)
michael@0 689 return TRUE;
michael@0 690
michael@0 691 if (filter == PIXMAN_FILTER_SEPARABLE_CONVOLUTION)
michael@0 692 {
michael@0 693 int width = pixman_fixed_to_int (params[0]);
michael@0 694 int height = pixman_fixed_to_int (params[1]);
michael@0 695 int x_phase_bits = pixman_fixed_to_int (params[2]);
michael@0 696 int y_phase_bits = pixman_fixed_to_int (params[3]);
michael@0 697 int n_x_phases = (1 << x_phase_bits);
michael@0 698 int n_y_phases = (1 << y_phase_bits);
michael@0 699
michael@0 700 return_val_if_fail (
michael@0 701 n_params == 4 + n_x_phases * width + n_y_phases * height, FALSE);
michael@0 702 }
michael@0 703
michael@0 704 new_params = NULL;
michael@0 705 if (params)
michael@0 706 {
michael@0 707 new_params = pixman_malloc_ab (n_params, sizeof (pixman_fixed_t));
michael@0 708 if (!new_params)
michael@0 709 return FALSE;
michael@0 710
michael@0 711 memcpy (new_params,
michael@0 712 params, n_params * sizeof (pixman_fixed_t));
michael@0 713 }
michael@0 714
michael@0 715 common->filter = filter;
michael@0 716
michael@0 717 if (common->filter_params)
michael@0 718 free (common->filter_params);
michael@0 719
michael@0 720 common->filter_params = new_params;
michael@0 721 common->n_filter_params = n_params;
michael@0 722
michael@0 723 image_property_changed (image);
michael@0 724 return TRUE;
michael@0 725 }
michael@0 726
michael@0 727 PIXMAN_EXPORT void
michael@0 728 pixman_image_set_source_clipping (pixman_image_t *image,
michael@0 729 pixman_bool_t clip_sources)
michael@0 730 {
michael@0 731 if (image->common.clip_sources == clip_sources)
michael@0 732 return;
michael@0 733
michael@0 734 image->common.clip_sources = clip_sources;
michael@0 735
michael@0 736 image_property_changed (image);
michael@0 737 }
michael@0 738
michael@0 739 /* Unlike all the other property setters, this function does not
michael@0 740 * copy the content of indexed. Doing this copying is simply
michael@0 741 * way, way too expensive.
michael@0 742 */
michael@0 743 PIXMAN_EXPORT void
michael@0 744 pixman_image_set_indexed (pixman_image_t * image,
michael@0 745 const pixman_indexed_t *indexed)
michael@0 746 {
michael@0 747 bits_image_t *bits = (bits_image_t *)image;
michael@0 748
michael@0 749 if (bits->indexed == indexed)
michael@0 750 return;
michael@0 751
michael@0 752 bits->indexed = indexed;
michael@0 753
michael@0 754 image_property_changed (image);
michael@0 755 }
michael@0 756
michael@0 757 PIXMAN_EXPORT void
michael@0 758 pixman_image_set_alpha_map (pixman_image_t *image,
michael@0 759 pixman_image_t *alpha_map,
michael@0 760 int16_t x,
michael@0 761 int16_t y)
michael@0 762 {
michael@0 763 image_common_t *common = (image_common_t *)image;
michael@0 764
michael@0 765 return_if_fail (!alpha_map || alpha_map->type == BITS);
michael@0 766
michael@0 767 if (alpha_map && common->alpha_count > 0)
michael@0 768 {
michael@0 769 /* If this image is being used as an alpha map itself,
michael@0 770 * then you can't give it an alpha map of its own.
michael@0 771 */
michael@0 772 return;
michael@0 773 }
michael@0 774
michael@0 775 if (alpha_map && alpha_map->common.alpha_map)
michael@0 776 {
michael@0 777 /* If the image has an alpha map of its own,
michael@0 778 * then it can't be used as an alpha map itself
michael@0 779 */
michael@0 780 return;
michael@0 781 }
michael@0 782
michael@0 783 if (common->alpha_map != (bits_image_t *)alpha_map)
michael@0 784 {
michael@0 785 if (common->alpha_map)
michael@0 786 {
michael@0 787 common->alpha_map->common.alpha_count--;
michael@0 788
michael@0 789 pixman_image_unref ((pixman_image_t *)common->alpha_map);
michael@0 790 }
michael@0 791
michael@0 792 if (alpha_map)
michael@0 793 {
michael@0 794 common->alpha_map = (bits_image_t *)pixman_image_ref (alpha_map);
michael@0 795
michael@0 796 common->alpha_map->common.alpha_count++;
michael@0 797 }
michael@0 798 else
michael@0 799 {
michael@0 800 common->alpha_map = NULL;
michael@0 801 }
michael@0 802 }
michael@0 803
michael@0 804 common->alpha_origin_x = x;
michael@0 805 common->alpha_origin_y = y;
michael@0 806
michael@0 807 image_property_changed (image);
michael@0 808 }
michael@0 809
michael@0 810 PIXMAN_EXPORT void
michael@0 811 pixman_image_set_component_alpha (pixman_image_t *image,
michael@0 812 pixman_bool_t component_alpha)
michael@0 813 {
michael@0 814 if (image->common.component_alpha == component_alpha)
michael@0 815 return;
michael@0 816
michael@0 817 image->common.component_alpha = component_alpha;
michael@0 818
michael@0 819 image_property_changed (image);
michael@0 820 }
michael@0 821
michael@0 822 PIXMAN_EXPORT pixman_bool_t
michael@0 823 pixman_image_get_component_alpha (pixman_image_t *image)
michael@0 824 {
michael@0 825 return image->common.component_alpha;
michael@0 826 }
michael@0 827
michael@0 828 PIXMAN_EXPORT void
michael@0 829 pixman_image_set_accessors (pixman_image_t * image,
michael@0 830 pixman_read_memory_func_t read_func,
michael@0 831 pixman_write_memory_func_t write_func)
michael@0 832 {
michael@0 833 return_if_fail (image != NULL);
michael@0 834
michael@0 835 if (image->type == BITS)
michael@0 836 {
michael@0 837 image->bits.read_func = read_func;
michael@0 838 image->bits.write_func = write_func;
michael@0 839
michael@0 840 image_property_changed (image);
michael@0 841 }
michael@0 842 }
michael@0 843
michael@0 844 PIXMAN_EXPORT uint32_t *
michael@0 845 pixman_image_get_data (pixman_image_t *image)
michael@0 846 {
michael@0 847 if (image->type == BITS)
michael@0 848 return image->bits.bits;
michael@0 849
michael@0 850 return NULL;
michael@0 851 }
michael@0 852
michael@0 853 PIXMAN_EXPORT int
michael@0 854 pixman_image_get_width (pixman_image_t *image)
michael@0 855 {
michael@0 856 if (image->type == BITS)
michael@0 857 return image->bits.width;
michael@0 858
michael@0 859 return 0;
michael@0 860 }
michael@0 861
michael@0 862 PIXMAN_EXPORT int
michael@0 863 pixman_image_get_height (pixman_image_t *image)
michael@0 864 {
michael@0 865 if (image->type == BITS)
michael@0 866 return image->bits.height;
michael@0 867
michael@0 868 return 0;
michael@0 869 }
michael@0 870
michael@0 871 PIXMAN_EXPORT int
michael@0 872 pixman_image_get_stride (pixman_image_t *image)
michael@0 873 {
michael@0 874 if (image->type == BITS)
michael@0 875 return image->bits.rowstride * (int) sizeof (uint32_t);
michael@0 876
michael@0 877 return 0;
michael@0 878 }
michael@0 879
michael@0 880 PIXMAN_EXPORT int
michael@0 881 pixman_image_get_depth (pixman_image_t *image)
michael@0 882 {
michael@0 883 if (image->type == BITS)
michael@0 884 return PIXMAN_FORMAT_DEPTH (image->bits.format);
michael@0 885
michael@0 886 return 0;
michael@0 887 }
michael@0 888
michael@0 889 PIXMAN_EXPORT pixman_format_code_t
michael@0 890 pixman_image_get_format (pixman_image_t *image)
michael@0 891 {
michael@0 892 if (image->type == BITS)
michael@0 893 return image->bits.format;
michael@0 894
michael@0 895 return PIXMAN_null;
michael@0 896 }
michael@0 897
michael@0 898 uint32_t
michael@0 899 _pixman_image_get_solid (pixman_implementation_t *imp,
michael@0 900 pixman_image_t * image,
michael@0 901 pixman_format_code_t format)
michael@0 902 {
michael@0 903 uint32_t result;
michael@0 904
michael@0 905 if (image->type == SOLID)
michael@0 906 {
michael@0 907 result = image->solid.color_32;
michael@0 908 }
michael@0 909 else if (image->type == BITS)
michael@0 910 {
michael@0 911 if (image->bits.format == PIXMAN_a8r8g8b8)
michael@0 912 result = image->bits.bits[0];
michael@0 913 else if (image->bits.format == PIXMAN_x8r8g8b8)
michael@0 914 result = image->bits.bits[0] | 0xff000000;
michael@0 915 else if (image->bits.format == PIXMAN_a8)
michael@0 916 result = (*(uint8_t *)image->bits.bits) << 24;
michael@0 917 else
michael@0 918 goto otherwise;
michael@0 919 }
michael@0 920 else
michael@0 921 {
michael@0 922 pixman_iter_t iter;
michael@0 923
michael@0 924 otherwise:
michael@0 925 _pixman_implementation_src_iter_init (
michael@0 926 imp, &iter, image, 0, 0, 1, 1,
michael@0 927 (uint8_t *)&result,
michael@0 928 ITER_NARROW, image->common.flags);
michael@0 929
michael@0 930 result = *iter.get_scanline (&iter, NULL);
michael@0 931 }
michael@0 932
michael@0 933 /* If necessary, convert RGB <--> BGR. */
michael@0 934 if (PIXMAN_FORMAT_TYPE (format) != PIXMAN_TYPE_ARGB
michael@0 935 && PIXMAN_FORMAT_TYPE (format) != PIXMAN_TYPE_ARGB_SRGB)
michael@0 936 {
michael@0 937 result = (((result & 0xff000000) >> 0) |
michael@0 938 ((result & 0x00ff0000) >> 16) |
michael@0 939 ((result & 0x0000ff00) >> 0) |
michael@0 940 ((result & 0x000000ff) << 16));
michael@0 941 }
michael@0 942
michael@0 943 return result;
michael@0 944 }

mercurial