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