pixman-utils.c revision 27693ee9
1/* 2 * Copyright © 2000 SuSE, Inc. 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that 7 * copyright notice and this permission notice appear in supporting 8 * documentation, and that the name of SuSE not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. SuSE makes no representations about the 11 * suitability of this software for any purpose. It is provided "as is" 12 * without express or implied warranty. 13 * 14 * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE 16 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 18 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 19 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 * 21 * Author: Keith Packard, SuSE, Inc. 22 */ 23 24#ifdef HAVE_CONFIG_H 25#include <config.h> 26#endif 27 28#include <stdlib.h> 29 30#include "pixman-private.h" 31#include "pixman-mmx.h" 32 33PIXMAN_EXPORT pixman_bool_t 34pixman_transform_point_3d (pixman_transform_t *transform, 35 pixman_vector_t *vector) 36{ 37 pixman_vector_t result; 38 int i, j; 39 pixman_fixed_32_32_t partial; 40 pixman_fixed_48_16_t v; 41 42 for (j = 0; j < 3; j++) 43 { 44 v = 0; 45 for (i = 0; i < 3; i++) 46 { 47 partial = ((pixman_fixed_48_16_t) transform->matrix[j][i] * 48 (pixman_fixed_48_16_t) vector->vector[i]); 49 v += partial >> 16; 50 } 51 52 if (v > pixman_max_fixed_48_16 || v < pixman_min_fixed_48_16) 53 return FALSE; 54 55 result.vector[j] = (pixman_fixed_48_16_t) v; 56 } 57 58 if (!result.vector[2]) 59 return FALSE; 60 61 *vector = result; 62 return TRUE; 63} 64 65PIXMAN_EXPORT pixman_bool_t 66pixman_blt (uint32_t *src_bits, 67 uint32_t *dst_bits, 68 int src_stride, 69 int dst_stride, 70 int src_bpp, 71 int dst_bpp, 72 int src_x, int src_y, 73 int dst_x, int dst_y, 74 int width, int height) 75{ 76#ifdef USE_MMX 77 if (pixman_have_mmx()) 78 { 79 return pixman_blt_mmx (src_bits, dst_bits, src_stride, dst_stride, src_bpp, dst_bpp, 80 src_x, src_y, dst_x, dst_y, width, height); 81 } 82 else 83#endif 84 return FALSE; 85} 86 87static void 88pixman_fill8 (uint32_t *bits, 89 int stride, 90 int x, 91 int y, 92 int width, 93 int height, 94 uint32_t xor) 95{ 96 int byte_stride = stride * (int) sizeof (uint32_t); 97 uint8_t *dst = (uint8_t *) bits; 98 uint8_t v = xor & 0xff; 99 int i; 100 101 dst = dst + y * byte_stride + x; 102 103 while (height--) 104 { 105 for (i = 0; i < width; ++i) 106 dst[i] = v; 107 108 dst += byte_stride; 109 } 110} 111 112static void 113pixman_fill16 (uint32_t *bits, 114 int stride, 115 int x, 116 int y, 117 int width, 118 int height, 119 uint32_t xor) 120{ 121 int short_stride = (stride * (int) sizeof (uint32_t)) / (int) sizeof (uint16_t); 122 uint16_t *dst = (uint16_t *)bits; 123 uint16_t v = xor & 0xffff; 124 int i; 125 126 dst = dst + y * short_stride + x; 127 128 while (height--) 129 { 130 for (i = 0; i < width; ++i) 131 dst[i] = v; 132 133 dst += short_stride; 134 } 135} 136 137static void 138pixman_fill32 (uint32_t *bits, 139 int stride, 140 int x, 141 int y, 142 int width, 143 int height, 144 uint32_t xor) 145{ 146 int i; 147 148 bits = bits + y * stride + x; 149 150 while (height--) 151 { 152 for (i = 0; i < width; ++i) 153 bits[i] = xor; 154 155 bits += stride; 156 } 157} 158 159PIXMAN_EXPORT pixman_bool_t 160pixman_fill (uint32_t *bits, 161 int stride, 162 int bpp, 163 int x, 164 int y, 165 int width, 166 int height, 167 uint32_t xor) 168{ 169#if 0 170 printf ("filling: %d %d %d %d (stride: %d, bpp: %d) pixel: %x\n", 171 x, y, width, height, stride, bpp, xor); 172#endif 173 174#ifdef USE_MMX 175 if (!pixman_have_mmx() || !pixman_fill_mmx (bits, stride, bpp, x, y, width, height, xor)) 176#endif 177 { 178 switch (bpp) 179 { 180 case 8: 181 pixman_fill8 (bits, stride, x, y, width, height, xor); 182 break; 183 184 case 16: 185 pixman_fill16 (bits, stride, x, y, width, height, xor); 186 break; 187 188 case 32: 189 pixman_fill32 (bits, stride, x, y, width, height, xor); 190 break; 191 192 default: 193 return FALSE; 194 break; 195 } 196 } 197 198 return TRUE; 199} 200 201 202/* 203 * Compute the smallest value no less than y which is on a 204 * grid row 205 */ 206 207PIXMAN_EXPORT pixman_fixed_t 208pixman_sample_ceil_y (pixman_fixed_t y, int n) 209{ 210 pixman_fixed_t f = pixman_fixed_frac(y); 211 pixman_fixed_t i = pixman_fixed_floor(y); 212 213 f = ((f + Y_FRAC_FIRST(n)) / STEP_Y_SMALL(n)) * STEP_Y_SMALL(n) + Y_FRAC_FIRST(n); 214 if (f > Y_FRAC_LAST(n)) 215 { 216 f = Y_FRAC_FIRST(n); 217 i += pixman_fixed_1; 218 } 219 return (i | f); 220} 221 222#define _div(a,b) ((a) >= 0 ? (a) / (b) : -((-(a) + (b) - 1) / (b))) 223 224/* 225 * Compute the largest value no greater than y which is on a 226 * grid row 227 */ 228PIXMAN_EXPORT pixman_fixed_t 229pixman_sample_floor_y (pixman_fixed_t y, int n) 230{ 231 pixman_fixed_t f = pixman_fixed_frac(y); 232 pixman_fixed_t i = pixman_fixed_floor (y); 233 234 f = _div(f - Y_FRAC_FIRST(n), STEP_Y_SMALL(n)) * STEP_Y_SMALL(n) + Y_FRAC_FIRST(n); 235 if (f < Y_FRAC_FIRST(n)) 236 { 237 f = Y_FRAC_LAST(n); 238 i -= pixman_fixed_1; 239 } 240 return (i | f); 241} 242 243/* 244 * Step an edge by any amount (including negative values) 245 */ 246PIXMAN_EXPORT void 247pixman_edge_step (pixman_edge_t *e, int n) 248{ 249 pixman_fixed_48_16_t ne; 250 251 e->x += n * e->stepx; 252 253 ne = e->e + n * (pixman_fixed_48_16_t) e->dx; 254 255 if (n >= 0) 256 { 257 if (ne > 0) 258 { 259 int nx = (ne + e->dy - 1) / e->dy; 260 e->e = ne - nx * (pixman_fixed_48_16_t) e->dy; 261 e->x += nx * e->signdx; 262 } 263 } 264 else 265 { 266 if (ne <= -e->dy) 267 { 268 int nx = (-ne) / e->dy; 269 e->e = ne + nx * (pixman_fixed_48_16_t) e->dy; 270 e->x -= nx * e->signdx; 271 } 272 } 273} 274 275/* 276 * A private routine to initialize the multi-step 277 * elements of an edge structure 278 */ 279static void 280_pixman_edge_tMultiInit (pixman_edge_t *e, int n, pixman_fixed_t *stepx_p, pixman_fixed_t *dx_p) 281{ 282 pixman_fixed_t stepx; 283 pixman_fixed_48_16_t ne; 284 285 ne = n * (pixman_fixed_48_16_t) e->dx; 286 stepx = n * e->stepx; 287 if (ne > 0) 288 { 289 int nx = ne / e->dy; 290 ne -= nx * e->dy; 291 stepx += nx * e->signdx; 292 } 293 *dx_p = ne; 294 *stepx_p = stepx; 295} 296 297/* 298 * Initialize one edge structure given the line endpoints and a 299 * starting y value 300 */ 301PIXMAN_EXPORT void 302pixman_edge_init (pixman_edge_t *e, 303 int n, 304 pixman_fixed_t y_start, 305 pixman_fixed_t x_top, 306 pixman_fixed_t y_top, 307 pixman_fixed_t x_bot, 308 pixman_fixed_t y_bot) 309{ 310 pixman_fixed_t dx, dy; 311 312 e->x = x_top; 313 e->e = 0; 314 dx = x_bot - x_top; 315 dy = y_bot - y_top; 316 e->dy = dy; 317 e->dx = 0; 318 if (dy) 319 { 320 if (dx >= 0) 321 { 322 e->signdx = 1; 323 e->stepx = dx / dy; 324 e->dx = dx % dy; 325 e->e = -dy; 326 } 327 else 328 { 329 e->signdx = -1; 330 e->stepx = -(-dx / dy); 331 e->dx = -dx % dy; 332 e->e = 0; 333 } 334 335 _pixman_edge_tMultiInit (e, STEP_Y_SMALL(n), &e->stepx_small, &e->dx_small); 336 _pixman_edge_tMultiInit (e, STEP_Y_BIG(n), &e->stepx_big, &e->dx_big); 337 } 338 pixman_edge_step (e, y_start - y_top); 339} 340 341/* 342 * Initialize one edge structure given a line, starting y value 343 * and a pixel offset for the line 344 */ 345PIXMAN_EXPORT void 346pixman_line_fixed_edge_init (pixman_edge_t *e, 347 int n, 348 pixman_fixed_t y, 349 const pixman_line_fixed_t *line, 350 int x_off, 351 int y_off) 352{ 353 pixman_fixed_t x_off_fixed = pixman_int_to_fixed(x_off); 354 pixman_fixed_t y_off_fixed = pixman_int_to_fixed(y_off); 355 const pixman_point_fixed_t *top, *bot; 356 357 if (line->p1.y <= line->p2.y) 358 { 359 top = &line->p1; 360 bot = &line->p2; 361 } 362 else 363 { 364 top = &line->p2; 365 bot = &line->p1; 366 } 367 pixman_edge_init (e, n, y, 368 top->x + x_off_fixed, 369 top->y + y_off_fixed, 370 bot->x + x_off_fixed, 371 bot->y + y_off_fixed); 372} 373 374pixman_bool_t 375pixman_multiply_overflows_int (unsigned int a, 376 unsigned int b) 377{ 378 return a >= INT32_MAX / b; 379} 380 381pixman_bool_t 382pixman_addition_overflows_int (unsigned int a, 383 unsigned int b) 384{ 385 return a > INT32_MAX - b; 386} 387 388void * 389pixman_malloc_ab(unsigned int a, 390 unsigned int b) 391{ 392 if (a >= INT32_MAX / b) 393 return NULL; 394 395 return malloc (a * b); 396} 397 398void * 399pixman_malloc_abc (unsigned int a, 400 unsigned int b, 401 unsigned int c) 402{ 403 if (a >= INT32_MAX / b) 404 return NULL; 405 else if (a * b >= INT32_MAX / c) 406 return NULL; 407 else 408 return malloc (a * b * c); 409} 410 411 412/** 413 * pixman_version: 414 * 415 * Returns the version of the pixman library encoded in a single 416 * integer as per %PIXMAN_VERSION_ENCODE. The encoding ensures that 417 * later versions compare greater than earlier versions. 418 * 419 * A run-time comparison to check that pixman's version is greater than 420 * or equal to version X.Y.Z could be performed as follows: 421 * 422 * <informalexample><programlisting> 423 * if (pixman_version() >= PIXMAN_VERSION_ENCODE(X,Y,Z)) {...} 424 * </programlisting></informalexample> 425 * 426 * See also pixman_version_string() as well as the compile-time 427 * equivalents %PIXMAN_VERSION and %PIXMAN_VERSION_STRING. 428 * 429 * Return value: the encoded version. 430 **/ 431PIXMAN_EXPORT int 432pixman_version (void) 433{ 434 return PIXMAN_VERSION; 435} 436 437/** 438 * pixman_version_string: 439 * 440 * Returns the version of the pixman library as a human-readable string 441 * of the form "X.Y.Z". 442 * 443 * See also pixman_version() as well as the compile-time equivalents 444 * %PIXMAN_VERSION_STRING and %PIXMAN_VERSION. 445 * 446 * Return value: a string containing the version. 447 **/ 448PIXMAN_EXPORT const char* 449pixman_version_string (void) 450{ 451 return PIXMAN_VERSION_STRING; 452} 453 454/** 455 * pixman_format_supported_destination: 456 * @format: A pixman_format_code_t format 457 * 458 * Return value: whether the provided format code is a supported 459 * format for a pixman surface used as a destination in 460 * rendering. 461 * 462 * Currently, all pixman_format_code_t values are supported 463 * except for the YUV formats. 464 **/ 465PIXMAN_EXPORT pixman_bool_t 466pixman_format_supported_destination (pixman_format_code_t format) 467{ 468 switch (format) { 469 /* 32 bpp formats */ 470 case PIXMAN_a2b10g10r10: 471 case PIXMAN_x2b10g10r10: 472 case PIXMAN_a8r8g8b8: 473 case PIXMAN_x8r8g8b8: 474 case PIXMAN_a8b8g8r8: 475 case PIXMAN_x8b8g8r8: 476 case PIXMAN_r8g8b8: 477 case PIXMAN_b8g8r8: 478 case PIXMAN_r5g6b5: 479 case PIXMAN_b5g6r5: 480 /* 16 bpp formats */ 481 case PIXMAN_a1r5g5b5: 482 case PIXMAN_x1r5g5b5: 483 case PIXMAN_a1b5g5r5: 484 case PIXMAN_x1b5g5r5: 485 case PIXMAN_a4r4g4b4: 486 case PIXMAN_x4r4g4b4: 487 case PIXMAN_a4b4g4r4: 488 case PIXMAN_x4b4g4r4: 489 /* 8bpp formats */ 490 case PIXMAN_a8: 491 case PIXMAN_r3g3b2: 492 case PIXMAN_b2g3r3: 493 case PIXMAN_a2r2g2b2: 494 case PIXMAN_a2b2g2r2: 495 case PIXMAN_c8: 496 case PIXMAN_g8: 497 case PIXMAN_x4a4: 498 /* Collides with PIXMAN_c8 499 case PIXMAN_x4c4: 500 */ 501 /* Collides with PIXMAN_g8 502 case PIXMAN_x4g4: 503 */ 504 /* 4bpp formats */ 505 case PIXMAN_a4: 506 case PIXMAN_r1g2b1: 507 case PIXMAN_b1g2r1: 508 case PIXMAN_a1r1g1b1: 509 case PIXMAN_a1b1g1r1: 510 case PIXMAN_c4: 511 case PIXMAN_g4: 512 /* 1bpp formats */ 513 case PIXMAN_a1: 514 case PIXMAN_g1: 515 return TRUE; 516 517 /* YUV formats */ 518 case PIXMAN_yuy2: 519 case PIXMAN_yv12: 520 default: 521 return FALSE; 522 } 523} 524 525/** 526 * pixman_format_supported_source: 527 * @format: A pixman_format_code_t format 528 * 529 * Return value: whether the provided format code is a supported 530 * format for a pixman surface used as a source in 531 * rendering. 532 * 533 * Currently, all pixman_format_code_t values are supported. 534 **/ 535PIXMAN_EXPORT pixman_bool_t 536pixman_format_supported_source (pixman_format_code_t format) 537{ 538 switch (format) { 539 /* 32 bpp formats */ 540 case PIXMAN_a2b10g10r10: 541 case PIXMAN_x2b10g10r10: 542 case PIXMAN_a8r8g8b8: 543 case PIXMAN_x8r8g8b8: 544 case PIXMAN_a8b8g8r8: 545 case PIXMAN_x8b8g8r8: 546 case PIXMAN_r8g8b8: 547 case PIXMAN_b8g8r8: 548 case PIXMAN_r5g6b5: 549 case PIXMAN_b5g6r5: 550 /* 16 bpp formats */ 551 case PIXMAN_a1r5g5b5: 552 case PIXMAN_x1r5g5b5: 553 case PIXMAN_a1b5g5r5: 554 case PIXMAN_x1b5g5r5: 555 case PIXMAN_a4r4g4b4: 556 case PIXMAN_x4r4g4b4: 557 case PIXMAN_a4b4g4r4: 558 case PIXMAN_x4b4g4r4: 559 /* 8bpp formats */ 560 case PIXMAN_a8: 561 case PIXMAN_r3g3b2: 562 case PIXMAN_b2g3r3: 563 case PIXMAN_a2r2g2b2: 564 case PIXMAN_a2b2g2r2: 565 case PIXMAN_c8: 566 case PIXMAN_g8: 567 case PIXMAN_x4a4: 568 /* Collides with PIXMAN_c8 569 case PIXMAN_x4c4: 570 */ 571 /* Collides with PIXMAN_g8 572 case PIXMAN_x4g4: 573 */ 574 /* 4bpp formats */ 575 case PIXMAN_a4: 576 case PIXMAN_r1g2b1: 577 case PIXMAN_b1g2r1: 578 case PIXMAN_a1r1g1b1: 579 case PIXMAN_a1b1g1r1: 580 case PIXMAN_c4: 581 case PIXMAN_g4: 582 /* 1bpp formats */ 583 case PIXMAN_a1: 584 case PIXMAN_g1: 585 /* YUV formats */ 586 case PIXMAN_yuy2: 587 case PIXMAN_yv12: 588 return TRUE; 589 590 default: 591 return FALSE; 592 } 593} 594