Thu, 22 Jan 2015 13:21:57 +0100
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 Keith Packard, member of The XFree86 Project, Inc. |
michael@0 | 3 | * 2005 Lars Knoll & Zack Rusin, Trolltech |
michael@0 | 4 | * 2008 Aaron Plattner, NVIDIA Corporation |
michael@0 | 5 | * Copyright © 2000 SuSE, Inc. |
michael@0 | 6 | * Copyright © 2007, 2009 Red Hat, Inc. |
michael@0 | 7 | * Copyright © 2008 André Tupinambá <andrelrt@gmail.com> |
michael@0 | 8 | * |
michael@0 | 9 | * Permission to use, copy, modify, distribute, and sell this software and its |
michael@0 | 10 | * documentation for any purpose is hereby granted without fee, provided that |
michael@0 | 11 | * the above copyright notice appear in all copies and that both that |
michael@0 | 12 | * copyright notice and this permission notice appear in supporting |
michael@0 | 13 | * documentation, and that the name of Keith Packard not be used in |
michael@0 | 14 | * advertising or publicity pertaining to distribution of the software without |
michael@0 | 15 | * specific, written prior permission. Keith Packard makes no |
michael@0 | 16 | * representations about the suitability of this software for any purpose. It |
michael@0 | 17 | * is provided "as is" without express or implied warranty. |
michael@0 | 18 | * |
michael@0 | 19 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS |
michael@0 | 20 | * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND |
michael@0 | 21 | * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY |
michael@0 | 22 | * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
michael@0 | 23 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN |
michael@0 | 24 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING |
michael@0 | 25 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
michael@0 | 26 | * SOFTWARE. |
michael@0 | 27 | */ |
michael@0 | 28 | |
michael@0 | 29 | #ifdef HAVE_CONFIG_H |
michael@0 | 30 | #include <config.h> |
michael@0 | 31 | #endif |
michael@0 | 32 | #include <stdio.h> |
michael@0 | 33 | #include <stdlib.h> |
michael@0 | 34 | #include <string.h> |
michael@0 | 35 | #include "pixman-private.h" |
michael@0 | 36 | #include "pixman-combine32.h" |
michael@0 | 37 | #include "pixman-inlines.h" |
michael@0 | 38 | |
michael@0 | 39 | static uint32_t * |
michael@0 | 40 | _pixman_image_get_scanline_generic_float (pixman_iter_t * iter, |
michael@0 | 41 | const uint32_t *mask) |
michael@0 | 42 | { |
michael@0 | 43 | pixman_iter_get_scanline_t fetch_32 = iter->data; |
michael@0 | 44 | uint32_t *buffer = iter->buffer; |
michael@0 | 45 | |
michael@0 | 46 | fetch_32 (iter, NULL); |
michael@0 | 47 | |
michael@0 | 48 | pixman_expand_to_float ((argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width); |
michael@0 | 49 | |
michael@0 | 50 | return iter->buffer; |
michael@0 | 51 | } |
michael@0 | 52 | |
michael@0 | 53 | /* Fetch functions */ |
michael@0 | 54 | |
michael@0 | 55 | static force_inline uint32_t |
michael@0 | 56 | fetch_pixel_no_alpha (bits_image_t *image, |
michael@0 | 57 | int x, int y, pixman_bool_t check_bounds) |
michael@0 | 58 | { |
michael@0 | 59 | if (check_bounds && |
michael@0 | 60 | (x < 0 || x >= image->width || y < 0 || y >= image->height)) |
michael@0 | 61 | { |
michael@0 | 62 | return 0; |
michael@0 | 63 | } |
michael@0 | 64 | |
michael@0 | 65 | return image->fetch_pixel_32 (image, x, y); |
michael@0 | 66 | } |
michael@0 | 67 | |
michael@0 | 68 | typedef uint32_t (* get_pixel_t) (bits_image_t *image, |
michael@0 | 69 | int x, int y, pixman_bool_t check_bounds); |
michael@0 | 70 | |
michael@0 | 71 | static force_inline uint32_t |
michael@0 | 72 | bits_image_fetch_pixel_nearest (bits_image_t *image, |
michael@0 | 73 | pixman_fixed_t x, |
michael@0 | 74 | pixman_fixed_t y, |
michael@0 | 75 | get_pixel_t get_pixel) |
michael@0 | 76 | { |
michael@0 | 77 | int x0 = pixman_fixed_to_int (x - pixman_fixed_e); |
michael@0 | 78 | int y0 = pixman_fixed_to_int (y - pixman_fixed_e); |
michael@0 | 79 | |
michael@0 | 80 | if (image->common.repeat != PIXMAN_REPEAT_NONE) |
michael@0 | 81 | { |
michael@0 | 82 | repeat (image->common.repeat, &x0, image->width); |
michael@0 | 83 | repeat (image->common.repeat, &y0, image->height); |
michael@0 | 84 | |
michael@0 | 85 | return get_pixel (image, x0, y0, FALSE); |
michael@0 | 86 | } |
michael@0 | 87 | else |
michael@0 | 88 | { |
michael@0 | 89 | return get_pixel (image, x0, y0, TRUE); |
michael@0 | 90 | } |
michael@0 | 91 | } |
michael@0 | 92 | |
michael@0 | 93 | static force_inline uint32_t |
michael@0 | 94 | bits_image_fetch_pixel_bilinear (bits_image_t *image, |
michael@0 | 95 | pixman_fixed_t x, |
michael@0 | 96 | pixman_fixed_t y, |
michael@0 | 97 | get_pixel_t get_pixel) |
michael@0 | 98 | { |
michael@0 | 99 | pixman_repeat_t repeat_mode = image->common.repeat; |
michael@0 | 100 | int width = image->width; |
michael@0 | 101 | int height = image->height; |
michael@0 | 102 | int x1, y1, x2, y2; |
michael@0 | 103 | uint32_t tl, tr, bl, br; |
michael@0 | 104 | int32_t distx, disty; |
michael@0 | 105 | |
michael@0 | 106 | x1 = x - pixman_fixed_1 / 2; |
michael@0 | 107 | y1 = y - pixman_fixed_1 / 2; |
michael@0 | 108 | |
michael@0 | 109 | distx = pixman_fixed_to_bilinear_weight (x1); |
michael@0 | 110 | disty = pixman_fixed_to_bilinear_weight (y1); |
michael@0 | 111 | |
michael@0 | 112 | x1 = pixman_fixed_to_int (x1); |
michael@0 | 113 | y1 = pixman_fixed_to_int (y1); |
michael@0 | 114 | x2 = x1 + 1; |
michael@0 | 115 | y2 = y1 + 1; |
michael@0 | 116 | |
michael@0 | 117 | if (repeat_mode != PIXMAN_REPEAT_NONE) |
michael@0 | 118 | { |
michael@0 | 119 | repeat (repeat_mode, &x1, width); |
michael@0 | 120 | repeat (repeat_mode, &y1, height); |
michael@0 | 121 | repeat (repeat_mode, &x2, width); |
michael@0 | 122 | repeat (repeat_mode, &y2, height); |
michael@0 | 123 | |
michael@0 | 124 | tl = get_pixel (image, x1, y1, FALSE); |
michael@0 | 125 | bl = get_pixel (image, x1, y2, FALSE); |
michael@0 | 126 | tr = get_pixel (image, x2, y1, FALSE); |
michael@0 | 127 | br = get_pixel (image, x2, y2, FALSE); |
michael@0 | 128 | } |
michael@0 | 129 | else |
michael@0 | 130 | { |
michael@0 | 131 | tl = get_pixel (image, x1, y1, TRUE); |
michael@0 | 132 | tr = get_pixel (image, x2, y1, TRUE); |
michael@0 | 133 | bl = get_pixel (image, x1, y2, TRUE); |
michael@0 | 134 | br = get_pixel (image, x2, y2, TRUE); |
michael@0 | 135 | } |
michael@0 | 136 | |
michael@0 | 137 | return bilinear_interpolation (tl, tr, bl, br, distx, disty); |
michael@0 | 138 | } |
michael@0 | 139 | |
michael@0 | 140 | static uint32_t * |
michael@0 | 141 | bits_image_fetch_bilinear_no_repeat_8888 (pixman_iter_t *iter, |
michael@0 | 142 | const uint32_t *mask) |
michael@0 | 143 | { |
michael@0 | 144 | |
michael@0 | 145 | pixman_image_t * ima = iter->image; |
michael@0 | 146 | int offset = iter->x; |
michael@0 | 147 | int line = iter->y++; |
michael@0 | 148 | int width = iter->width; |
michael@0 | 149 | uint32_t * buffer = iter->buffer; |
michael@0 | 150 | |
michael@0 | 151 | bits_image_t *bits = &ima->bits; |
michael@0 | 152 | pixman_fixed_t x_top, x_bottom, x; |
michael@0 | 153 | pixman_fixed_t ux_top, ux_bottom, ux; |
michael@0 | 154 | pixman_vector_t v; |
michael@0 | 155 | uint32_t top_mask, bottom_mask; |
michael@0 | 156 | uint32_t *top_row; |
michael@0 | 157 | uint32_t *bottom_row; |
michael@0 | 158 | uint32_t *end; |
michael@0 | 159 | uint32_t zero[2] = { 0, 0 }; |
michael@0 | 160 | uint32_t one = 1; |
michael@0 | 161 | int y, y1, y2; |
michael@0 | 162 | int disty; |
michael@0 | 163 | int mask_inc; |
michael@0 | 164 | int w; |
michael@0 | 165 | |
michael@0 | 166 | /* reference point is the center of the pixel */ |
michael@0 | 167 | v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; |
michael@0 | 168 | v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; |
michael@0 | 169 | v.vector[2] = pixman_fixed_1; |
michael@0 | 170 | |
michael@0 | 171 | if (!pixman_transform_point_3d (bits->common.transform, &v)) |
michael@0 | 172 | return iter->buffer; |
michael@0 | 173 | |
michael@0 | 174 | ux = ux_top = ux_bottom = bits->common.transform->matrix[0][0]; |
michael@0 | 175 | x = x_top = x_bottom = v.vector[0] - pixman_fixed_1/2; |
michael@0 | 176 | |
michael@0 | 177 | y = v.vector[1] - pixman_fixed_1/2; |
michael@0 | 178 | disty = pixman_fixed_to_bilinear_weight (y); |
michael@0 | 179 | |
michael@0 | 180 | /* Load the pointers to the first and second lines from the source |
michael@0 | 181 | * image that bilinear code must read. |
michael@0 | 182 | * |
michael@0 | 183 | * The main trick in this code is about the check if any line are |
michael@0 | 184 | * outside of the image; |
michael@0 | 185 | * |
michael@0 | 186 | * When I realize that a line (any one) is outside, I change |
michael@0 | 187 | * the pointer to a dummy area with zeros. Once I change this, I |
michael@0 | 188 | * must be sure the pointer will not change, so I set the |
michael@0 | 189 | * variables to each pointer increments inside the loop. |
michael@0 | 190 | */ |
michael@0 | 191 | y1 = pixman_fixed_to_int (y); |
michael@0 | 192 | y2 = y1 + 1; |
michael@0 | 193 | |
michael@0 | 194 | if (y1 < 0 || y1 >= bits->height) |
michael@0 | 195 | { |
michael@0 | 196 | top_row = zero; |
michael@0 | 197 | x_top = 0; |
michael@0 | 198 | ux_top = 0; |
michael@0 | 199 | } |
michael@0 | 200 | else |
michael@0 | 201 | { |
michael@0 | 202 | top_row = bits->bits + y1 * bits->rowstride; |
michael@0 | 203 | x_top = x; |
michael@0 | 204 | ux_top = ux; |
michael@0 | 205 | } |
michael@0 | 206 | |
michael@0 | 207 | if (y2 < 0 || y2 >= bits->height) |
michael@0 | 208 | { |
michael@0 | 209 | bottom_row = zero; |
michael@0 | 210 | x_bottom = 0; |
michael@0 | 211 | ux_bottom = 0; |
michael@0 | 212 | } |
michael@0 | 213 | else |
michael@0 | 214 | { |
michael@0 | 215 | bottom_row = bits->bits + y2 * bits->rowstride; |
michael@0 | 216 | x_bottom = x; |
michael@0 | 217 | ux_bottom = ux; |
michael@0 | 218 | } |
michael@0 | 219 | |
michael@0 | 220 | /* Instead of checking whether the operation uses the mast in |
michael@0 | 221 | * each loop iteration, verify this only once and prepare the |
michael@0 | 222 | * variables to make the code smaller inside the loop. |
michael@0 | 223 | */ |
michael@0 | 224 | if (!mask) |
michael@0 | 225 | { |
michael@0 | 226 | mask_inc = 0; |
michael@0 | 227 | mask = &one; |
michael@0 | 228 | } |
michael@0 | 229 | else |
michael@0 | 230 | { |
michael@0 | 231 | /* If have a mask, prepare the variables to check it */ |
michael@0 | 232 | mask_inc = 1; |
michael@0 | 233 | } |
michael@0 | 234 | |
michael@0 | 235 | /* If both are zero, then the whole thing is zero */ |
michael@0 | 236 | if (top_row == zero && bottom_row == zero) |
michael@0 | 237 | { |
michael@0 | 238 | memset (buffer, 0, width * sizeof (uint32_t)); |
michael@0 | 239 | return iter->buffer; |
michael@0 | 240 | } |
michael@0 | 241 | else if (bits->format == PIXMAN_x8r8g8b8) |
michael@0 | 242 | { |
michael@0 | 243 | if (top_row == zero) |
michael@0 | 244 | { |
michael@0 | 245 | top_mask = 0; |
michael@0 | 246 | bottom_mask = 0xff000000; |
michael@0 | 247 | } |
michael@0 | 248 | else if (bottom_row == zero) |
michael@0 | 249 | { |
michael@0 | 250 | top_mask = 0xff000000; |
michael@0 | 251 | bottom_mask = 0; |
michael@0 | 252 | } |
michael@0 | 253 | else |
michael@0 | 254 | { |
michael@0 | 255 | top_mask = 0xff000000; |
michael@0 | 256 | bottom_mask = 0xff000000; |
michael@0 | 257 | } |
michael@0 | 258 | } |
michael@0 | 259 | else |
michael@0 | 260 | { |
michael@0 | 261 | top_mask = 0; |
michael@0 | 262 | bottom_mask = 0; |
michael@0 | 263 | } |
michael@0 | 264 | |
michael@0 | 265 | end = buffer + width; |
michael@0 | 266 | |
michael@0 | 267 | /* Zero fill to the left of the image */ |
michael@0 | 268 | while (buffer < end && x < pixman_fixed_minus_1) |
michael@0 | 269 | { |
michael@0 | 270 | *buffer++ = 0; |
michael@0 | 271 | x += ux; |
michael@0 | 272 | x_top += ux_top; |
michael@0 | 273 | x_bottom += ux_bottom; |
michael@0 | 274 | mask += mask_inc; |
michael@0 | 275 | } |
michael@0 | 276 | |
michael@0 | 277 | /* Left edge |
michael@0 | 278 | */ |
michael@0 | 279 | while (buffer < end && x < 0) |
michael@0 | 280 | { |
michael@0 | 281 | uint32_t tr, br; |
michael@0 | 282 | int32_t distx; |
michael@0 | 283 | |
michael@0 | 284 | tr = top_row[pixman_fixed_to_int (x_top) + 1] | top_mask; |
michael@0 | 285 | br = bottom_row[pixman_fixed_to_int (x_bottom) + 1] | bottom_mask; |
michael@0 | 286 | |
michael@0 | 287 | distx = pixman_fixed_to_bilinear_weight (x); |
michael@0 | 288 | |
michael@0 | 289 | *buffer++ = bilinear_interpolation (0, tr, 0, br, distx, disty); |
michael@0 | 290 | |
michael@0 | 291 | x += ux; |
michael@0 | 292 | x_top += ux_top; |
michael@0 | 293 | x_bottom += ux_bottom; |
michael@0 | 294 | mask += mask_inc; |
michael@0 | 295 | } |
michael@0 | 296 | |
michael@0 | 297 | /* Main part */ |
michael@0 | 298 | w = pixman_int_to_fixed (bits->width - 1); |
michael@0 | 299 | |
michael@0 | 300 | while (buffer < end && x < w) |
michael@0 | 301 | { |
michael@0 | 302 | if (*mask) |
michael@0 | 303 | { |
michael@0 | 304 | uint32_t tl, tr, bl, br; |
michael@0 | 305 | int32_t distx; |
michael@0 | 306 | |
michael@0 | 307 | tl = top_row [pixman_fixed_to_int (x_top)] | top_mask; |
michael@0 | 308 | tr = top_row [pixman_fixed_to_int (x_top) + 1] | top_mask; |
michael@0 | 309 | bl = bottom_row [pixman_fixed_to_int (x_bottom)] | bottom_mask; |
michael@0 | 310 | br = bottom_row [pixman_fixed_to_int (x_bottom) + 1] | bottom_mask; |
michael@0 | 311 | |
michael@0 | 312 | distx = pixman_fixed_to_bilinear_weight (x); |
michael@0 | 313 | |
michael@0 | 314 | *buffer = bilinear_interpolation (tl, tr, bl, br, distx, disty); |
michael@0 | 315 | } |
michael@0 | 316 | |
michael@0 | 317 | buffer++; |
michael@0 | 318 | x += ux; |
michael@0 | 319 | x_top += ux_top; |
michael@0 | 320 | x_bottom += ux_bottom; |
michael@0 | 321 | mask += mask_inc; |
michael@0 | 322 | } |
michael@0 | 323 | |
michael@0 | 324 | /* Right Edge */ |
michael@0 | 325 | w = pixman_int_to_fixed (bits->width); |
michael@0 | 326 | while (buffer < end && x < w) |
michael@0 | 327 | { |
michael@0 | 328 | if (*mask) |
michael@0 | 329 | { |
michael@0 | 330 | uint32_t tl, bl; |
michael@0 | 331 | int32_t distx; |
michael@0 | 332 | |
michael@0 | 333 | tl = top_row [pixman_fixed_to_int (x_top)] | top_mask; |
michael@0 | 334 | bl = bottom_row [pixman_fixed_to_int (x_bottom)] | bottom_mask; |
michael@0 | 335 | |
michael@0 | 336 | distx = pixman_fixed_to_bilinear_weight (x); |
michael@0 | 337 | |
michael@0 | 338 | *buffer = bilinear_interpolation (tl, 0, bl, 0, distx, disty); |
michael@0 | 339 | } |
michael@0 | 340 | |
michael@0 | 341 | buffer++; |
michael@0 | 342 | x += ux; |
michael@0 | 343 | x_top += ux_top; |
michael@0 | 344 | x_bottom += ux_bottom; |
michael@0 | 345 | mask += mask_inc; |
michael@0 | 346 | } |
michael@0 | 347 | |
michael@0 | 348 | /* Zero fill to the left of the image */ |
michael@0 | 349 | while (buffer < end) |
michael@0 | 350 | *buffer++ = 0; |
michael@0 | 351 | |
michael@0 | 352 | return iter->buffer; |
michael@0 | 353 | } |
michael@0 | 354 | |
michael@0 | 355 | static force_inline uint32_t |
michael@0 | 356 | bits_image_fetch_pixel_convolution (bits_image_t *image, |
michael@0 | 357 | pixman_fixed_t x, |
michael@0 | 358 | pixman_fixed_t y, |
michael@0 | 359 | get_pixel_t get_pixel) |
michael@0 | 360 | { |
michael@0 | 361 | pixman_fixed_t *params = image->common.filter_params; |
michael@0 | 362 | int x_off = (params[0] - pixman_fixed_1) >> 1; |
michael@0 | 363 | int y_off = (params[1] - pixman_fixed_1) >> 1; |
michael@0 | 364 | int32_t cwidth = pixman_fixed_to_int (params[0]); |
michael@0 | 365 | int32_t cheight = pixman_fixed_to_int (params[1]); |
michael@0 | 366 | int32_t i, j, x1, x2, y1, y2; |
michael@0 | 367 | pixman_repeat_t repeat_mode = image->common.repeat; |
michael@0 | 368 | int width = image->width; |
michael@0 | 369 | int height = image->height; |
michael@0 | 370 | int srtot, sgtot, sbtot, satot; |
michael@0 | 371 | |
michael@0 | 372 | params += 2; |
michael@0 | 373 | |
michael@0 | 374 | x1 = pixman_fixed_to_int (x - pixman_fixed_e - x_off); |
michael@0 | 375 | y1 = pixman_fixed_to_int (y - pixman_fixed_e - y_off); |
michael@0 | 376 | x2 = x1 + cwidth; |
michael@0 | 377 | y2 = y1 + cheight; |
michael@0 | 378 | |
michael@0 | 379 | srtot = sgtot = sbtot = satot = 0; |
michael@0 | 380 | |
michael@0 | 381 | for (i = y1; i < y2; ++i) |
michael@0 | 382 | { |
michael@0 | 383 | for (j = x1; j < x2; ++j) |
michael@0 | 384 | { |
michael@0 | 385 | int rx = j; |
michael@0 | 386 | int ry = i; |
michael@0 | 387 | |
michael@0 | 388 | pixman_fixed_t f = *params; |
michael@0 | 389 | |
michael@0 | 390 | if (f) |
michael@0 | 391 | { |
michael@0 | 392 | uint32_t pixel; |
michael@0 | 393 | |
michael@0 | 394 | if (repeat_mode != PIXMAN_REPEAT_NONE) |
michael@0 | 395 | { |
michael@0 | 396 | repeat (repeat_mode, &rx, width); |
michael@0 | 397 | repeat (repeat_mode, &ry, height); |
michael@0 | 398 | |
michael@0 | 399 | pixel = get_pixel (image, rx, ry, FALSE); |
michael@0 | 400 | } |
michael@0 | 401 | else |
michael@0 | 402 | { |
michael@0 | 403 | pixel = get_pixel (image, rx, ry, TRUE); |
michael@0 | 404 | } |
michael@0 | 405 | |
michael@0 | 406 | srtot += (int)RED_8 (pixel) * f; |
michael@0 | 407 | sgtot += (int)GREEN_8 (pixel) * f; |
michael@0 | 408 | sbtot += (int)BLUE_8 (pixel) * f; |
michael@0 | 409 | satot += (int)ALPHA_8 (pixel) * f; |
michael@0 | 410 | } |
michael@0 | 411 | |
michael@0 | 412 | params++; |
michael@0 | 413 | } |
michael@0 | 414 | } |
michael@0 | 415 | |
michael@0 | 416 | satot = (satot + 0x8000) >> 16; |
michael@0 | 417 | srtot = (srtot + 0x8000) >> 16; |
michael@0 | 418 | sgtot = (sgtot + 0x8000) >> 16; |
michael@0 | 419 | sbtot = (sbtot + 0x8000) >> 16; |
michael@0 | 420 | |
michael@0 | 421 | satot = CLIP (satot, 0, 0xff); |
michael@0 | 422 | srtot = CLIP (srtot, 0, 0xff); |
michael@0 | 423 | sgtot = CLIP (sgtot, 0, 0xff); |
michael@0 | 424 | sbtot = CLIP (sbtot, 0, 0xff); |
michael@0 | 425 | |
michael@0 | 426 | return ((satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot)); |
michael@0 | 427 | } |
michael@0 | 428 | |
michael@0 | 429 | static uint32_t |
michael@0 | 430 | bits_image_fetch_pixel_separable_convolution (bits_image_t *image, |
michael@0 | 431 | pixman_fixed_t x, |
michael@0 | 432 | pixman_fixed_t y, |
michael@0 | 433 | get_pixel_t get_pixel) |
michael@0 | 434 | { |
michael@0 | 435 | pixman_fixed_t *params = image->common.filter_params; |
michael@0 | 436 | pixman_repeat_t repeat_mode = image->common.repeat; |
michael@0 | 437 | int width = image->width; |
michael@0 | 438 | int height = image->height; |
michael@0 | 439 | int cwidth = pixman_fixed_to_int (params[0]); |
michael@0 | 440 | int cheight = pixman_fixed_to_int (params[1]); |
michael@0 | 441 | int x_phase_bits = pixman_fixed_to_int (params[2]); |
michael@0 | 442 | int y_phase_bits = pixman_fixed_to_int (params[3]); |
michael@0 | 443 | int x_phase_shift = 16 - x_phase_bits; |
michael@0 | 444 | int y_phase_shift = 16 - y_phase_bits; |
michael@0 | 445 | int x_off = ((cwidth << 16) - pixman_fixed_1) >> 1; |
michael@0 | 446 | int y_off = ((cheight << 16) - pixman_fixed_1) >> 1; |
michael@0 | 447 | pixman_fixed_t *y_params; |
michael@0 | 448 | int srtot, sgtot, sbtot, satot; |
michael@0 | 449 | int32_t x1, x2, y1, y2; |
michael@0 | 450 | int32_t px, py; |
michael@0 | 451 | int i, j; |
michael@0 | 452 | |
michael@0 | 453 | /* Round x and y to the middle of the closest phase before continuing. This |
michael@0 | 454 | * ensures that the convolution matrix is aligned right, since it was |
michael@0 | 455 | * positioned relative to a particular phase (and not relative to whatever |
michael@0 | 456 | * exact fraction we happen to get here). |
michael@0 | 457 | */ |
michael@0 | 458 | x = ((x >> x_phase_shift) << x_phase_shift) + ((1 << x_phase_shift) >> 1); |
michael@0 | 459 | y = ((y >> y_phase_shift) << y_phase_shift) + ((1 << y_phase_shift) >> 1); |
michael@0 | 460 | |
michael@0 | 461 | px = (x & 0xffff) >> x_phase_shift; |
michael@0 | 462 | py = (y & 0xffff) >> y_phase_shift; |
michael@0 | 463 | |
michael@0 | 464 | y_params = params + 4 + (1 << x_phase_bits) * cwidth + py * cheight; |
michael@0 | 465 | |
michael@0 | 466 | x1 = pixman_fixed_to_int (x - pixman_fixed_e - x_off); |
michael@0 | 467 | y1 = pixman_fixed_to_int (y - pixman_fixed_e - y_off); |
michael@0 | 468 | x2 = x1 + cwidth; |
michael@0 | 469 | y2 = y1 + cheight; |
michael@0 | 470 | |
michael@0 | 471 | srtot = sgtot = sbtot = satot = 0; |
michael@0 | 472 | |
michael@0 | 473 | for (i = y1; i < y2; ++i) |
michael@0 | 474 | { |
michael@0 | 475 | pixman_fixed_48_16_t fy = *y_params++; |
michael@0 | 476 | pixman_fixed_t *x_params = params + 4 + px * cwidth; |
michael@0 | 477 | |
michael@0 | 478 | if (fy) |
michael@0 | 479 | { |
michael@0 | 480 | for (j = x1; j < x2; ++j) |
michael@0 | 481 | { |
michael@0 | 482 | pixman_fixed_t fx = *x_params++; |
michael@0 | 483 | int rx = j; |
michael@0 | 484 | int ry = i; |
michael@0 | 485 | |
michael@0 | 486 | if (fx) |
michael@0 | 487 | { |
michael@0 | 488 | pixman_fixed_t f; |
michael@0 | 489 | uint32_t pixel; |
michael@0 | 490 | |
michael@0 | 491 | if (repeat_mode != PIXMAN_REPEAT_NONE) |
michael@0 | 492 | { |
michael@0 | 493 | repeat (repeat_mode, &rx, width); |
michael@0 | 494 | repeat (repeat_mode, &ry, height); |
michael@0 | 495 | |
michael@0 | 496 | pixel = get_pixel (image, rx, ry, FALSE); |
michael@0 | 497 | } |
michael@0 | 498 | else |
michael@0 | 499 | { |
michael@0 | 500 | pixel = get_pixel (image, rx, ry, TRUE); |
michael@0 | 501 | } |
michael@0 | 502 | |
michael@0 | 503 | f = (fy * fx + 0x8000) >> 16; |
michael@0 | 504 | |
michael@0 | 505 | srtot += (int)RED_8 (pixel) * f; |
michael@0 | 506 | sgtot += (int)GREEN_8 (pixel) * f; |
michael@0 | 507 | sbtot += (int)BLUE_8 (pixel) * f; |
michael@0 | 508 | satot += (int)ALPHA_8 (pixel) * f; |
michael@0 | 509 | } |
michael@0 | 510 | } |
michael@0 | 511 | } |
michael@0 | 512 | } |
michael@0 | 513 | |
michael@0 | 514 | satot = (satot + 0x8000) >> 16; |
michael@0 | 515 | srtot = (srtot + 0x8000) >> 16; |
michael@0 | 516 | sgtot = (sgtot + 0x8000) >> 16; |
michael@0 | 517 | sbtot = (sbtot + 0x8000) >> 16; |
michael@0 | 518 | |
michael@0 | 519 | satot = CLIP (satot, 0, 0xff); |
michael@0 | 520 | srtot = CLIP (srtot, 0, 0xff); |
michael@0 | 521 | sgtot = CLIP (sgtot, 0, 0xff); |
michael@0 | 522 | sbtot = CLIP (sbtot, 0, 0xff); |
michael@0 | 523 | |
michael@0 | 524 | return ((satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot)); |
michael@0 | 525 | } |
michael@0 | 526 | |
michael@0 | 527 | static force_inline uint32_t |
michael@0 | 528 | bits_image_fetch_pixel_filtered (bits_image_t *image, |
michael@0 | 529 | pixman_fixed_t x, |
michael@0 | 530 | pixman_fixed_t y, |
michael@0 | 531 | get_pixel_t get_pixel) |
michael@0 | 532 | { |
michael@0 | 533 | switch (image->common.filter) |
michael@0 | 534 | { |
michael@0 | 535 | case PIXMAN_FILTER_NEAREST: |
michael@0 | 536 | case PIXMAN_FILTER_FAST: |
michael@0 | 537 | return bits_image_fetch_pixel_nearest (image, x, y, get_pixel); |
michael@0 | 538 | break; |
michael@0 | 539 | |
michael@0 | 540 | case PIXMAN_FILTER_BILINEAR: |
michael@0 | 541 | case PIXMAN_FILTER_GOOD: |
michael@0 | 542 | case PIXMAN_FILTER_BEST: |
michael@0 | 543 | return bits_image_fetch_pixel_bilinear (image, x, y, get_pixel); |
michael@0 | 544 | break; |
michael@0 | 545 | |
michael@0 | 546 | case PIXMAN_FILTER_CONVOLUTION: |
michael@0 | 547 | return bits_image_fetch_pixel_convolution (image, x, y, get_pixel); |
michael@0 | 548 | break; |
michael@0 | 549 | |
michael@0 | 550 | case PIXMAN_FILTER_SEPARABLE_CONVOLUTION: |
michael@0 | 551 | return bits_image_fetch_pixel_separable_convolution (image, x, y, get_pixel); |
michael@0 | 552 | break; |
michael@0 | 553 | |
michael@0 | 554 | default: |
michael@0 | 555 | break; |
michael@0 | 556 | } |
michael@0 | 557 | |
michael@0 | 558 | return 0; |
michael@0 | 559 | } |
michael@0 | 560 | |
michael@0 | 561 | static uint32_t * |
michael@0 | 562 | bits_image_fetch_affine_no_alpha (pixman_iter_t * iter, |
michael@0 | 563 | const uint32_t * mask) |
michael@0 | 564 | { |
michael@0 | 565 | pixman_image_t *image = iter->image; |
michael@0 | 566 | int offset = iter->x; |
michael@0 | 567 | int line = iter->y++; |
michael@0 | 568 | int width = iter->width; |
michael@0 | 569 | uint32_t * buffer = iter->buffer; |
michael@0 | 570 | |
michael@0 | 571 | pixman_fixed_t x, y; |
michael@0 | 572 | pixman_fixed_t ux, uy; |
michael@0 | 573 | pixman_vector_t v; |
michael@0 | 574 | int i; |
michael@0 | 575 | |
michael@0 | 576 | /* reference point is the center of the pixel */ |
michael@0 | 577 | v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; |
michael@0 | 578 | v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; |
michael@0 | 579 | v.vector[2] = pixman_fixed_1; |
michael@0 | 580 | |
michael@0 | 581 | if (image->common.transform) |
michael@0 | 582 | { |
michael@0 | 583 | if (!pixman_transform_point_3d (image->common.transform, &v)) |
michael@0 | 584 | return iter->buffer; |
michael@0 | 585 | |
michael@0 | 586 | ux = image->common.transform->matrix[0][0]; |
michael@0 | 587 | uy = image->common.transform->matrix[1][0]; |
michael@0 | 588 | } |
michael@0 | 589 | else |
michael@0 | 590 | { |
michael@0 | 591 | ux = pixman_fixed_1; |
michael@0 | 592 | uy = 0; |
michael@0 | 593 | } |
michael@0 | 594 | |
michael@0 | 595 | x = v.vector[0]; |
michael@0 | 596 | y = v.vector[1]; |
michael@0 | 597 | |
michael@0 | 598 | for (i = 0; i < width; ++i) |
michael@0 | 599 | { |
michael@0 | 600 | if (!mask || mask[i]) |
michael@0 | 601 | { |
michael@0 | 602 | buffer[i] = bits_image_fetch_pixel_filtered ( |
michael@0 | 603 | &image->bits, x, y, fetch_pixel_no_alpha); |
michael@0 | 604 | } |
michael@0 | 605 | |
michael@0 | 606 | x += ux; |
michael@0 | 607 | y += uy; |
michael@0 | 608 | } |
michael@0 | 609 | |
michael@0 | 610 | return buffer; |
michael@0 | 611 | } |
michael@0 | 612 | |
michael@0 | 613 | /* General fetcher */ |
michael@0 | 614 | static force_inline uint32_t |
michael@0 | 615 | fetch_pixel_general (bits_image_t *image, int x, int y, pixman_bool_t check_bounds) |
michael@0 | 616 | { |
michael@0 | 617 | uint32_t pixel; |
michael@0 | 618 | |
michael@0 | 619 | if (check_bounds && |
michael@0 | 620 | (x < 0 || x >= image->width || y < 0 || y >= image->height)) |
michael@0 | 621 | { |
michael@0 | 622 | return 0; |
michael@0 | 623 | } |
michael@0 | 624 | |
michael@0 | 625 | pixel = image->fetch_pixel_32 (image, x, y); |
michael@0 | 626 | |
michael@0 | 627 | if (image->common.alpha_map) |
michael@0 | 628 | { |
michael@0 | 629 | uint32_t pixel_a; |
michael@0 | 630 | |
michael@0 | 631 | x -= image->common.alpha_origin_x; |
michael@0 | 632 | y -= image->common.alpha_origin_y; |
michael@0 | 633 | |
michael@0 | 634 | if (x < 0 || x >= image->common.alpha_map->width || |
michael@0 | 635 | y < 0 || y >= image->common.alpha_map->height) |
michael@0 | 636 | { |
michael@0 | 637 | pixel_a = 0; |
michael@0 | 638 | } |
michael@0 | 639 | else |
michael@0 | 640 | { |
michael@0 | 641 | pixel_a = image->common.alpha_map->fetch_pixel_32 ( |
michael@0 | 642 | image->common.alpha_map, x, y); |
michael@0 | 643 | |
michael@0 | 644 | pixel_a = ALPHA_8 (pixel_a); |
michael@0 | 645 | } |
michael@0 | 646 | |
michael@0 | 647 | pixel &= 0x00ffffff; |
michael@0 | 648 | pixel |= (pixel_a << 24); |
michael@0 | 649 | } |
michael@0 | 650 | |
michael@0 | 651 | return pixel; |
michael@0 | 652 | } |
michael@0 | 653 | |
michael@0 | 654 | static uint32_t * |
michael@0 | 655 | bits_image_fetch_general (pixman_iter_t *iter, |
michael@0 | 656 | const uint32_t *mask) |
michael@0 | 657 | { |
michael@0 | 658 | pixman_image_t *image = iter->image; |
michael@0 | 659 | int offset = iter->x; |
michael@0 | 660 | int line = iter->y++; |
michael@0 | 661 | int width = iter->width; |
michael@0 | 662 | uint32_t * buffer = iter->buffer; |
michael@0 | 663 | |
michael@0 | 664 | pixman_fixed_t x, y, w; |
michael@0 | 665 | pixman_fixed_t ux, uy, uw; |
michael@0 | 666 | pixman_vector_t v; |
michael@0 | 667 | int i; |
michael@0 | 668 | |
michael@0 | 669 | /* reference point is the center of the pixel */ |
michael@0 | 670 | v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; |
michael@0 | 671 | v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; |
michael@0 | 672 | v.vector[2] = pixman_fixed_1; |
michael@0 | 673 | |
michael@0 | 674 | if (image->common.transform) |
michael@0 | 675 | { |
michael@0 | 676 | if (!pixman_transform_point_3d (image->common.transform, &v)) |
michael@0 | 677 | return buffer; |
michael@0 | 678 | |
michael@0 | 679 | ux = image->common.transform->matrix[0][0]; |
michael@0 | 680 | uy = image->common.transform->matrix[1][0]; |
michael@0 | 681 | uw = image->common.transform->matrix[2][0]; |
michael@0 | 682 | } |
michael@0 | 683 | else |
michael@0 | 684 | { |
michael@0 | 685 | ux = pixman_fixed_1; |
michael@0 | 686 | uy = 0; |
michael@0 | 687 | uw = 0; |
michael@0 | 688 | } |
michael@0 | 689 | |
michael@0 | 690 | x = v.vector[0]; |
michael@0 | 691 | y = v.vector[1]; |
michael@0 | 692 | w = v.vector[2]; |
michael@0 | 693 | |
michael@0 | 694 | for (i = 0; i < width; ++i) |
michael@0 | 695 | { |
michael@0 | 696 | pixman_fixed_t x0, y0; |
michael@0 | 697 | |
michael@0 | 698 | if (!mask || mask[i]) |
michael@0 | 699 | { |
michael@0 | 700 | if (w != 0) |
michael@0 | 701 | { |
michael@0 | 702 | x0 = ((pixman_fixed_48_16_t)x << 16) / w; |
michael@0 | 703 | y0 = ((pixman_fixed_48_16_t)y << 16) / w; |
michael@0 | 704 | } |
michael@0 | 705 | else |
michael@0 | 706 | { |
michael@0 | 707 | x0 = 0; |
michael@0 | 708 | y0 = 0; |
michael@0 | 709 | } |
michael@0 | 710 | |
michael@0 | 711 | buffer[i] = bits_image_fetch_pixel_filtered ( |
michael@0 | 712 | &image->bits, x0, y0, fetch_pixel_general); |
michael@0 | 713 | } |
michael@0 | 714 | |
michael@0 | 715 | x += ux; |
michael@0 | 716 | y += uy; |
michael@0 | 717 | w += uw; |
michael@0 | 718 | } |
michael@0 | 719 | |
michael@0 | 720 | return buffer; |
michael@0 | 721 | } |
michael@0 | 722 | |
michael@0 | 723 | typedef uint32_t (* convert_pixel_t) (const uint8_t *row, int x); |
michael@0 | 724 | |
michael@0 | 725 | static force_inline void |
michael@0 | 726 | bits_image_fetch_separable_convolution_affine (pixman_image_t * image, |
michael@0 | 727 | int offset, |
michael@0 | 728 | int line, |
michael@0 | 729 | int width, |
michael@0 | 730 | uint32_t * buffer, |
michael@0 | 731 | const uint32_t * mask, |
michael@0 | 732 | |
michael@0 | 733 | convert_pixel_t convert_pixel, |
michael@0 | 734 | pixman_format_code_t format, |
michael@0 | 735 | pixman_repeat_t repeat_mode) |
michael@0 | 736 | { |
michael@0 | 737 | bits_image_t *bits = &image->bits; |
michael@0 | 738 | pixman_fixed_t *params = image->common.filter_params; |
michael@0 | 739 | int cwidth = pixman_fixed_to_int (params[0]); |
michael@0 | 740 | int cheight = pixman_fixed_to_int (params[1]); |
michael@0 | 741 | int x_off = ((cwidth << 16) - pixman_fixed_1) >> 1; |
michael@0 | 742 | int y_off = ((cheight << 16) - pixman_fixed_1) >> 1; |
michael@0 | 743 | int x_phase_bits = pixman_fixed_to_int (params[2]); |
michael@0 | 744 | int y_phase_bits = pixman_fixed_to_int (params[3]); |
michael@0 | 745 | int x_phase_shift = 16 - x_phase_bits; |
michael@0 | 746 | int y_phase_shift = 16 - y_phase_bits; |
michael@0 | 747 | pixman_fixed_t vx, vy; |
michael@0 | 748 | pixman_fixed_t ux, uy; |
michael@0 | 749 | pixman_vector_t v; |
michael@0 | 750 | int k; |
michael@0 | 751 | |
michael@0 | 752 | /* reference point is the center of the pixel */ |
michael@0 | 753 | v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; |
michael@0 | 754 | v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; |
michael@0 | 755 | v.vector[2] = pixman_fixed_1; |
michael@0 | 756 | |
michael@0 | 757 | if (!pixman_transform_point_3d (image->common.transform, &v)) |
michael@0 | 758 | return; |
michael@0 | 759 | |
michael@0 | 760 | ux = image->common.transform->matrix[0][0]; |
michael@0 | 761 | uy = image->common.transform->matrix[1][0]; |
michael@0 | 762 | |
michael@0 | 763 | vx = v.vector[0]; |
michael@0 | 764 | vy = v.vector[1]; |
michael@0 | 765 | |
michael@0 | 766 | for (k = 0; k < width; ++k) |
michael@0 | 767 | { |
michael@0 | 768 | pixman_fixed_t *y_params; |
michael@0 | 769 | int satot, srtot, sgtot, sbtot; |
michael@0 | 770 | pixman_fixed_t x, y; |
michael@0 | 771 | int32_t x1, x2, y1, y2; |
michael@0 | 772 | int32_t px, py; |
michael@0 | 773 | int i, j; |
michael@0 | 774 | |
michael@0 | 775 | if (mask && !mask[k]) |
michael@0 | 776 | goto next; |
michael@0 | 777 | |
michael@0 | 778 | /* Round x and y to the middle of the closest phase before continuing. This |
michael@0 | 779 | * ensures that the convolution matrix is aligned right, since it was |
michael@0 | 780 | * positioned relative to a particular phase (and not relative to whatever |
michael@0 | 781 | * exact fraction we happen to get here). |
michael@0 | 782 | */ |
michael@0 | 783 | x = ((vx >> x_phase_shift) << x_phase_shift) + ((1 << x_phase_shift) >> 1); |
michael@0 | 784 | y = ((vy >> y_phase_shift) << y_phase_shift) + ((1 << y_phase_shift) >> 1); |
michael@0 | 785 | |
michael@0 | 786 | px = (x & 0xffff) >> x_phase_shift; |
michael@0 | 787 | py = (y & 0xffff) >> y_phase_shift; |
michael@0 | 788 | |
michael@0 | 789 | x1 = pixman_fixed_to_int (x - pixman_fixed_e - x_off); |
michael@0 | 790 | y1 = pixman_fixed_to_int (y - pixman_fixed_e - y_off); |
michael@0 | 791 | x2 = x1 + cwidth; |
michael@0 | 792 | y2 = y1 + cheight; |
michael@0 | 793 | |
michael@0 | 794 | satot = srtot = sgtot = sbtot = 0; |
michael@0 | 795 | |
michael@0 | 796 | y_params = params + 4 + (1 << x_phase_bits) * cwidth + py * cheight; |
michael@0 | 797 | |
michael@0 | 798 | for (i = y1; i < y2; ++i) |
michael@0 | 799 | { |
michael@0 | 800 | pixman_fixed_t fy = *y_params++; |
michael@0 | 801 | |
michael@0 | 802 | if (fy) |
michael@0 | 803 | { |
michael@0 | 804 | pixman_fixed_t *x_params = params + 4 + px * cwidth; |
michael@0 | 805 | |
michael@0 | 806 | for (j = x1; j < x2; ++j) |
michael@0 | 807 | { |
michael@0 | 808 | pixman_fixed_t fx = *x_params++; |
michael@0 | 809 | int rx = j; |
michael@0 | 810 | int ry = i; |
michael@0 | 811 | |
michael@0 | 812 | if (fx) |
michael@0 | 813 | { |
michael@0 | 814 | pixman_fixed_t f; |
michael@0 | 815 | uint32_t pixel, mask; |
michael@0 | 816 | uint8_t *row; |
michael@0 | 817 | |
michael@0 | 818 | mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; |
michael@0 | 819 | |
michael@0 | 820 | if (repeat_mode != PIXMAN_REPEAT_NONE) |
michael@0 | 821 | { |
michael@0 | 822 | repeat (repeat_mode, &rx, bits->width); |
michael@0 | 823 | repeat (repeat_mode, &ry, bits->height); |
michael@0 | 824 | |
michael@0 | 825 | row = (uint8_t *)bits->bits + bits->rowstride * 4 * ry; |
michael@0 | 826 | pixel = convert_pixel (row, rx) | mask; |
michael@0 | 827 | } |
michael@0 | 828 | else |
michael@0 | 829 | { |
michael@0 | 830 | if (rx < 0 || ry < 0 || rx >= bits->width || ry >= bits->height) |
michael@0 | 831 | { |
michael@0 | 832 | pixel = 0; |
michael@0 | 833 | } |
michael@0 | 834 | else |
michael@0 | 835 | { |
michael@0 | 836 | row = (uint8_t *)bits->bits + bits->rowstride * 4 * ry; |
michael@0 | 837 | pixel = convert_pixel (row, rx) | mask; |
michael@0 | 838 | } |
michael@0 | 839 | } |
michael@0 | 840 | |
michael@0 | 841 | f = ((pixman_fixed_32_32_t)fx * fy + 0x8000) >> 16; |
michael@0 | 842 | srtot += (int)RED_8 (pixel) * f; |
michael@0 | 843 | sgtot += (int)GREEN_8 (pixel) * f; |
michael@0 | 844 | sbtot += (int)BLUE_8 (pixel) * f; |
michael@0 | 845 | satot += (int)ALPHA_8 (pixel) * f; |
michael@0 | 846 | } |
michael@0 | 847 | } |
michael@0 | 848 | } |
michael@0 | 849 | } |
michael@0 | 850 | |
michael@0 | 851 | satot = (satot + 0x8000) >> 16; |
michael@0 | 852 | srtot = (srtot + 0x8000) >> 16; |
michael@0 | 853 | sgtot = (sgtot + 0x8000) >> 16; |
michael@0 | 854 | sbtot = (sbtot + 0x8000) >> 16; |
michael@0 | 855 | |
michael@0 | 856 | satot = CLIP (satot, 0, 0xff); |
michael@0 | 857 | srtot = CLIP (srtot, 0, 0xff); |
michael@0 | 858 | sgtot = CLIP (sgtot, 0, 0xff); |
michael@0 | 859 | sbtot = CLIP (sbtot, 0, 0xff); |
michael@0 | 860 | |
michael@0 | 861 | buffer[k] = (satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot << 0); |
michael@0 | 862 | |
michael@0 | 863 | next: |
michael@0 | 864 | vx += ux; |
michael@0 | 865 | vy += uy; |
michael@0 | 866 | } |
michael@0 | 867 | } |
michael@0 | 868 | |
michael@0 | 869 | static const uint8_t zero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; |
michael@0 | 870 | |
michael@0 | 871 | static force_inline void |
michael@0 | 872 | bits_image_fetch_bilinear_affine (pixman_image_t * image, |
michael@0 | 873 | int offset, |
michael@0 | 874 | int line, |
michael@0 | 875 | int width, |
michael@0 | 876 | uint32_t * buffer, |
michael@0 | 877 | const uint32_t * mask, |
michael@0 | 878 | |
michael@0 | 879 | convert_pixel_t convert_pixel, |
michael@0 | 880 | pixman_format_code_t format, |
michael@0 | 881 | pixman_repeat_t repeat_mode) |
michael@0 | 882 | { |
michael@0 | 883 | pixman_fixed_t x, y; |
michael@0 | 884 | pixman_fixed_t ux, uy; |
michael@0 | 885 | pixman_vector_t v; |
michael@0 | 886 | bits_image_t *bits = &image->bits; |
michael@0 | 887 | int i; |
michael@0 | 888 | |
michael@0 | 889 | /* reference point is the center of the pixel */ |
michael@0 | 890 | v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; |
michael@0 | 891 | v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; |
michael@0 | 892 | v.vector[2] = pixman_fixed_1; |
michael@0 | 893 | |
michael@0 | 894 | if (!pixman_transform_point_3d (image->common.transform, &v)) |
michael@0 | 895 | return; |
michael@0 | 896 | |
michael@0 | 897 | ux = image->common.transform->matrix[0][0]; |
michael@0 | 898 | uy = image->common.transform->matrix[1][0]; |
michael@0 | 899 | |
michael@0 | 900 | x = v.vector[0]; |
michael@0 | 901 | y = v.vector[1]; |
michael@0 | 902 | |
michael@0 | 903 | for (i = 0; i < width; ++i) |
michael@0 | 904 | { |
michael@0 | 905 | int x1, y1, x2, y2; |
michael@0 | 906 | uint32_t tl, tr, bl, br; |
michael@0 | 907 | int32_t distx, disty; |
michael@0 | 908 | int width = image->bits.width; |
michael@0 | 909 | int height = image->bits.height; |
michael@0 | 910 | const uint8_t *row1; |
michael@0 | 911 | const uint8_t *row2; |
michael@0 | 912 | |
michael@0 | 913 | if (mask && !mask[i]) |
michael@0 | 914 | goto next; |
michael@0 | 915 | |
michael@0 | 916 | x1 = x - pixman_fixed_1 / 2; |
michael@0 | 917 | y1 = y - pixman_fixed_1 / 2; |
michael@0 | 918 | |
michael@0 | 919 | distx = pixman_fixed_to_bilinear_weight (x1); |
michael@0 | 920 | disty = pixman_fixed_to_bilinear_weight (y1); |
michael@0 | 921 | |
michael@0 | 922 | y1 = pixman_fixed_to_int (y1); |
michael@0 | 923 | y2 = y1 + 1; |
michael@0 | 924 | x1 = pixman_fixed_to_int (x1); |
michael@0 | 925 | x2 = x1 + 1; |
michael@0 | 926 | |
michael@0 | 927 | if (repeat_mode != PIXMAN_REPEAT_NONE) |
michael@0 | 928 | { |
michael@0 | 929 | uint32_t mask; |
michael@0 | 930 | |
michael@0 | 931 | mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; |
michael@0 | 932 | |
michael@0 | 933 | repeat (repeat_mode, &x1, width); |
michael@0 | 934 | repeat (repeat_mode, &y1, height); |
michael@0 | 935 | repeat (repeat_mode, &x2, width); |
michael@0 | 936 | repeat (repeat_mode, &y2, height); |
michael@0 | 937 | |
michael@0 | 938 | row1 = (uint8_t *)bits->bits + bits->rowstride * 4 * y1; |
michael@0 | 939 | row2 = (uint8_t *)bits->bits + bits->rowstride * 4 * y2; |
michael@0 | 940 | |
michael@0 | 941 | tl = convert_pixel (row1, x1) | mask; |
michael@0 | 942 | tr = convert_pixel (row1, x2) | mask; |
michael@0 | 943 | bl = convert_pixel (row2, x1) | mask; |
michael@0 | 944 | br = convert_pixel (row2, x2) | mask; |
michael@0 | 945 | } |
michael@0 | 946 | else |
michael@0 | 947 | { |
michael@0 | 948 | uint32_t mask1, mask2; |
michael@0 | 949 | int bpp; |
michael@0 | 950 | |
michael@0 | 951 | /* Note: PIXMAN_FORMAT_BPP() returns an unsigned value, |
michael@0 | 952 | * which means if you use it in expressions, those |
michael@0 | 953 | * expressions become unsigned themselves. Since |
michael@0 | 954 | * the variables below can be negative in some cases, |
michael@0 | 955 | * that will lead to crashes on 64 bit architectures. |
michael@0 | 956 | * |
michael@0 | 957 | * So this line makes sure bpp is signed |
michael@0 | 958 | */ |
michael@0 | 959 | bpp = PIXMAN_FORMAT_BPP (format); |
michael@0 | 960 | |
michael@0 | 961 | if (x1 >= width || x2 < 0 || y1 >= height || y2 < 0) |
michael@0 | 962 | { |
michael@0 | 963 | buffer[i] = 0; |
michael@0 | 964 | goto next; |
michael@0 | 965 | } |
michael@0 | 966 | |
michael@0 | 967 | if (y2 == 0) |
michael@0 | 968 | { |
michael@0 | 969 | row1 = zero; |
michael@0 | 970 | mask1 = 0; |
michael@0 | 971 | } |
michael@0 | 972 | else |
michael@0 | 973 | { |
michael@0 | 974 | row1 = (uint8_t *)bits->bits + bits->rowstride * 4 * y1; |
michael@0 | 975 | row1 += bpp / 8 * x1; |
michael@0 | 976 | |
michael@0 | 977 | mask1 = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; |
michael@0 | 978 | } |
michael@0 | 979 | |
michael@0 | 980 | if (y1 == height - 1) |
michael@0 | 981 | { |
michael@0 | 982 | row2 = zero; |
michael@0 | 983 | mask2 = 0; |
michael@0 | 984 | } |
michael@0 | 985 | else |
michael@0 | 986 | { |
michael@0 | 987 | row2 = (uint8_t *)bits->bits + bits->rowstride * 4 * y2; |
michael@0 | 988 | row2 += bpp / 8 * x1; |
michael@0 | 989 | |
michael@0 | 990 | mask2 = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; |
michael@0 | 991 | } |
michael@0 | 992 | |
michael@0 | 993 | if (x2 == 0) |
michael@0 | 994 | { |
michael@0 | 995 | tl = 0; |
michael@0 | 996 | bl = 0; |
michael@0 | 997 | } |
michael@0 | 998 | else |
michael@0 | 999 | { |
michael@0 | 1000 | tl = convert_pixel (row1, 0) | mask1; |
michael@0 | 1001 | bl = convert_pixel (row2, 0) | mask2; |
michael@0 | 1002 | } |
michael@0 | 1003 | |
michael@0 | 1004 | if (x1 == width - 1) |
michael@0 | 1005 | { |
michael@0 | 1006 | tr = 0; |
michael@0 | 1007 | br = 0; |
michael@0 | 1008 | } |
michael@0 | 1009 | else |
michael@0 | 1010 | { |
michael@0 | 1011 | tr = convert_pixel (row1, 1) | mask1; |
michael@0 | 1012 | br = convert_pixel (row2, 1) | mask2; |
michael@0 | 1013 | } |
michael@0 | 1014 | } |
michael@0 | 1015 | |
michael@0 | 1016 | buffer[i] = bilinear_interpolation ( |
michael@0 | 1017 | tl, tr, bl, br, distx, disty); |
michael@0 | 1018 | |
michael@0 | 1019 | next: |
michael@0 | 1020 | x += ux; |
michael@0 | 1021 | y += uy; |
michael@0 | 1022 | } |
michael@0 | 1023 | } |
michael@0 | 1024 | |
michael@0 | 1025 | static force_inline void |
michael@0 | 1026 | bits_image_fetch_nearest_affine (pixman_image_t * image, |
michael@0 | 1027 | int offset, |
michael@0 | 1028 | int line, |
michael@0 | 1029 | int width, |
michael@0 | 1030 | uint32_t * buffer, |
michael@0 | 1031 | const uint32_t * mask, |
michael@0 | 1032 | |
michael@0 | 1033 | convert_pixel_t convert_pixel, |
michael@0 | 1034 | pixman_format_code_t format, |
michael@0 | 1035 | pixman_repeat_t repeat_mode) |
michael@0 | 1036 | { |
michael@0 | 1037 | pixman_fixed_t x, y; |
michael@0 | 1038 | pixman_fixed_t ux, uy; |
michael@0 | 1039 | pixman_vector_t v; |
michael@0 | 1040 | bits_image_t *bits = &image->bits; |
michael@0 | 1041 | int i; |
michael@0 | 1042 | |
michael@0 | 1043 | /* reference point is the center of the pixel */ |
michael@0 | 1044 | v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; |
michael@0 | 1045 | v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; |
michael@0 | 1046 | v.vector[2] = pixman_fixed_1; |
michael@0 | 1047 | |
michael@0 | 1048 | if (!pixman_transform_point_3d (image->common.transform, &v)) |
michael@0 | 1049 | return; |
michael@0 | 1050 | |
michael@0 | 1051 | ux = image->common.transform->matrix[0][0]; |
michael@0 | 1052 | uy = image->common.transform->matrix[1][0]; |
michael@0 | 1053 | |
michael@0 | 1054 | x = v.vector[0]; |
michael@0 | 1055 | y = v.vector[1]; |
michael@0 | 1056 | |
michael@0 | 1057 | for (i = 0; i < width; ++i) |
michael@0 | 1058 | { |
michael@0 | 1059 | int width, height, x0, y0; |
michael@0 | 1060 | const uint8_t *row; |
michael@0 | 1061 | |
michael@0 | 1062 | if (mask && !mask[i]) |
michael@0 | 1063 | goto next; |
michael@0 | 1064 | |
michael@0 | 1065 | width = image->bits.width; |
michael@0 | 1066 | height = image->bits.height; |
michael@0 | 1067 | x0 = pixman_fixed_to_int (x - pixman_fixed_e); |
michael@0 | 1068 | y0 = pixman_fixed_to_int (y - pixman_fixed_e); |
michael@0 | 1069 | |
michael@0 | 1070 | if (repeat_mode == PIXMAN_REPEAT_NONE && |
michael@0 | 1071 | (y0 < 0 || y0 >= height || x0 < 0 || x0 >= width)) |
michael@0 | 1072 | { |
michael@0 | 1073 | buffer[i] = 0; |
michael@0 | 1074 | } |
michael@0 | 1075 | else |
michael@0 | 1076 | { |
michael@0 | 1077 | uint32_t mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; |
michael@0 | 1078 | |
michael@0 | 1079 | if (repeat_mode != PIXMAN_REPEAT_NONE) |
michael@0 | 1080 | { |
michael@0 | 1081 | repeat (repeat_mode, &x0, width); |
michael@0 | 1082 | repeat (repeat_mode, &y0, height); |
michael@0 | 1083 | } |
michael@0 | 1084 | |
michael@0 | 1085 | row = (uint8_t *)bits->bits + bits->rowstride * 4 * y0; |
michael@0 | 1086 | |
michael@0 | 1087 | buffer[i] = convert_pixel (row, x0) | mask; |
michael@0 | 1088 | } |
michael@0 | 1089 | |
michael@0 | 1090 | next: |
michael@0 | 1091 | x += ux; |
michael@0 | 1092 | y += uy; |
michael@0 | 1093 | } |
michael@0 | 1094 | } |
michael@0 | 1095 | |
michael@0 | 1096 | static force_inline uint32_t |
michael@0 | 1097 | convert_a8r8g8b8 (const uint8_t *row, int x) |
michael@0 | 1098 | { |
michael@0 | 1099 | return *(((uint32_t *)row) + x); |
michael@0 | 1100 | } |
michael@0 | 1101 | |
michael@0 | 1102 | static force_inline uint32_t |
michael@0 | 1103 | convert_x8r8g8b8 (const uint8_t *row, int x) |
michael@0 | 1104 | { |
michael@0 | 1105 | return *(((uint32_t *)row) + x); |
michael@0 | 1106 | } |
michael@0 | 1107 | |
michael@0 | 1108 | static force_inline uint32_t |
michael@0 | 1109 | convert_a8 (const uint8_t *row, int x) |
michael@0 | 1110 | { |
michael@0 | 1111 | return *(row + x) << 24; |
michael@0 | 1112 | } |
michael@0 | 1113 | |
michael@0 | 1114 | static force_inline uint32_t |
michael@0 | 1115 | convert_r5g6b5 (const uint8_t *row, int x) |
michael@0 | 1116 | { |
michael@0 | 1117 | return convert_0565_to_0888 (*((uint16_t *)row + x)); |
michael@0 | 1118 | } |
michael@0 | 1119 | |
michael@0 | 1120 | #define MAKE_SEPARABLE_CONVOLUTION_FETCHER(name, format, repeat_mode) \ |
michael@0 | 1121 | static uint32_t * \ |
michael@0 | 1122 | bits_image_fetch_separable_convolution_affine_ ## name (pixman_iter_t *iter, \ |
michael@0 | 1123 | const uint32_t * mask) \ |
michael@0 | 1124 | { \ |
michael@0 | 1125 | bits_image_fetch_separable_convolution_affine ( \ |
michael@0 | 1126 | iter->image, \ |
michael@0 | 1127 | iter->x, iter->y++, \ |
michael@0 | 1128 | iter->width, \ |
michael@0 | 1129 | iter->buffer, mask, \ |
michael@0 | 1130 | convert_ ## format, \ |
michael@0 | 1131 | PIXMAN_ ## format, \ |
michael@0 | 1132 | repeat_mode); \ |
michael@0 | 1133 | \ |
michael@0 | 1134 | return iter->buffer; \ |
michael@0 | 1135 | } |
michael@0 | 1136 | |
michael@0 | 1137 | #define MAKE_BILINEAR_FETCHER(name, format, repeat_mode) \ |
michael@0 | 1138 | static uint32_t * \ |
michael@0 | 1139 | bits_image_fetch_bilinear_affine_ ## name (pixman_iter_t *iter, \ |
michael@0 | 1140 | const uint32_t * mask) \ |
michael@0 | 1141 | { \ |
michael@0 | 1142 | bits_image_fetch_bilinear_affine (iter->image, \ |
michael@0 | 1143 | iter->x, iter->y++, \ |
michael@0 | 1144 | iter->width, \ |
michael@0 | 1145 | iter->buffer, mask, \ |
michael@0 | 1146 | convert_ ## format, \ |
michael@0 | 1147 | PIXMAN_ ## format, \ |
michael@0 | 1148 | repeat_mode); \ |
michael@0 | 1149 | return iter->buffer; \ |
michael@0 | 1150 | } |
michael@0 | 1151 | |
michael@0 | 1152 | #define MAKE_NEAREST_FETCHER(name, format, repeat_mode) \ |
michael@0 | 1153 | static uint32_t * \ |
michael@0 | 1154 | bits_image_fetch_nearest_affine_ ## name (pixman_iter_t *iter, \ |
michael@0 | 1155 | const uint32_t * mask) \ |
michael@0 | 1156 | { \ |
michael@0 | 1157 | bits_image_fetch_nearest_affine (iter->image, \ |
michael@0 | 1158 | iter->x, iter->y++, \ |
michael@0 | 1159 | iter->width, \ |
michael@0 | 1160 | iter->buffer, mask, \ |
michael@0 | 1161 | convert_ ## format, \ |
michael@0 | 1162 | PIXMAN_ ## format, \ |
michael@0 | 1163 | repeat_mode); \ |
michael@0 | 1164 | return iter->buffer; \ |
michael@0 | 1165 | } |
michael@0 | 1166 | |
michael@0 | 1167 | #define MAKE_FETCHERS(name, format, repeat_mode) \ |
michael@0 | 1168 | MAKE_NEAREST_FETCHER (name, format, repeat_mode) \ |
michael@0 | 1169 | MAKE_BILINEAR_FETCHER (name, format, repeat_mode) \ |
michael@0 | 1170 | MAKE_SEPARABLE_CONVOLUTION_FETCHER (name, format, repeat_mode) |
michael@0 | 1171 | |
michael@0 | 1172 | MAKE_FETCHERS (pad_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_PAD) |
michael@0 | 1173 | MAKE_FETCHERS (none_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_NONE) |
michael@0 | 1174 | MAKE_FETCHERS (reflect_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_REFLECT) |
michael@0 | 1175 | MAKE_FETCHERS (normal_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_NORMAL) |
michael@0 | 1176 | MAKE_FETCHERS (pad_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_PAD) |
michael@0 | 1177 | MAKE_FETCHERS (none_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_NONE) |
michael@0 | 1178 | MAKE_FETCHERS (reflect_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_REFLECT) |
michael@0 | 1179 | MAKE_FETCHERS (normal_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_NORMAL) |
michael@0 | 1180 | MAKE_FETCHERS (pad_a8, a8, PIXMAN_REPEAT_PAD) |
michael@0 | 1181 | MAKE_FETCHERS (none_a8, a8, PIXMAN_REPEAT_NONE) |
michael@0 | 1182 | MAKE_FETCHERS (reflect_a8, a8, PIXMAN_REPEAT_REFLECT) |
michael@0 | 1183 | MAKE_FETCHERS (normal_a8, a8, PIXMAN_REPEAT_NORMAL) |
michael@0 | 1184 | MAKE_FETCHERS (pad_r5g6b5, r5g6b5, PIXMAN_REPEAT_PAD) |
michael@0 | 1185 | MAKE_FETCHERS (none_r5g6b5, r5g6b5, PIXMAN_REPEAT_NONE) |
michael@0 | 1186 | MAKE_FETCHERS (reflect_r5g6b5, r5g6b5, PIXMAN_REPEAT_REFLECT) |
michael@0 | 1187 | MAKE_FETCHERS (normal_r5g6b5, r5g6b5, PIXMAN_REPEAT_NORMAL) |
michael@0 | 1188 | |
michael@0 | 1189 | static void |
michael@0 | 1190 | replicate_pixel_32 (bits_image_t * bits, |
michael@0 | 1191 | int x, |
michael@0 | 1192 | int y, |
michael@0 | 1193 | int width, |
michael@0 | 1194 | uint32_t * buffer) |
michael@0 | 1195 | { |
michael@0 | 1196 | uint32_t color; |
michael@0 | 1197 | uint32_t *end; |
michael@0 | 1198 | |
michael@0 | 1199 | color = bits->fetch_pixel_32 (bits, x, y); |
michael@0 | 1200 | |
michael@0 | 1201 | end = buffer + width; |
michael@0 | 1202 | while (buffer < end) |
michael@0 | 1203 | *(buffer++) = color; |
michael@0 | 1204 | } |
michael@0 | 1205 | |
michael@0 | 1206 | static void |
michael@0 | 1207 | replicate_pixel_float (bits_image_t * bits, |
michael@0 | 1208 | int x, |
michael@0 | 1209 | int y, |
michael@0 | 1210 | int width, |
michael@0 | 1211 | uint32_t * b) |
michael@0 | 1212 | { |
michael@0 | 1213 | argb_t color; |
michael@0 | 1214 | argb_t *buffer = (argb_t *)b; |
michael@0 | 1215 | argb_t *end; |
michael@0 | 1216 | |
michael@0 | 1217 | color = bits->fetch_pixel_float (bits, x, y); |
michael@0 | 1218 | |
michael@0 | 1219 | end = buffer + width; |
michael@0 | 1220 | while (buffer < end) |
michael@0 | 1221 | *(buffer++) = color; |
michael@0 | 1222 | } |
michael@0 | 1223 | |
michael@0 | 1224 | static void |
michael@0 | 1225 | bits_image_fetch_untransformed_repeat_none (bits_image_t *image, |
michael@0 | 1226 | pixman_bool_t wide, |
michael@0 | 1227 | int x, |
michael@0 | 1228 | int y, |
michael@0 | 1229 | int width, |
michael@0 | 1230 | uint32_t * buffer) |
michael@0 | 1231 | { |
michael@0 | 1232 | uint32_t w; |
michael@0 | 1233 | |
michael@0 | 1234 | if (y < 0 || y >= image->height) |
michael@0 | 1235 | { |
michael@0 | 1236 | memset (buffer, 0, width * (wide? sizeof (argb_t) : 4)); |
michael@0 | 1237 | return; |
michael@0 | 1238 | } |
michael@0 | 1239 | |
michael@0 | 1240 | if (x < 0) |
michael@0 | 1241 | { |
michael@0 | 1242 | w = MIN (width, -x); |
michael@0 | 1243 | |
michael@0 | 1244 | memset (buffer, 0, w * (wide ? sizeof (argb_t) : 4)); |
michael@0 | 1245 | |
michael@0 | 1246 | width -= w; |
michael@0 | 1247 | buffer += w * (wide? 4 : 1); |
michael@0 | 1248 | x += w; |
michael@0 | 1249 | } |
michael@0 | 1250 | |
michael@0 | 1251 | if (x < image->width) |
michael@0 | 1252 | { |
michael@0 | 1253 | w = MIN (width, image->width - x); |
michael@0 | 1254 | |
michael@0 | 1255 | if (wide) |
michael@0 | 1256 | image->fetch_scanline_float ((pixman_image_t *)image, x, y, w, buffer, NULL); |
michael@0 | 1257 | else |
michael@0 | 1258 | image->fetch_scanline_32 ((pixman_image_t *)image, x, y, w, buffer, NULL); |
michael@0 | 1259 | |
michael@0 | 1260 | width -= w; |
michael@0 | 1261 | buffer += w * (wide? 4 : 1); |
michael@0 | 1262 | x += w; |
michael@0 | 1263 | } |
michael@0 | 1264 | |
michael@0 | 1265 | memset (buffer, 0, width * (wide ? sizeof (argb_t) : 4)); |
michael@0 | 1266 | } |
michael@0 | 1267 | |
michael@0 | 1268 | static void |
michael@0 | 1269 | bits_image_fetch_untransformed_repeat_normal (bits_image_t *image, |
michael@0 | 1270 | pixman_bool_t wide, |
michael@0 | 1271 | int x, |
michael@0 | 1272 | int y, |
michael@0 | 1273 | int width, |
michael@0 | 1274 | uint32_t * buffer) |
michael@0 | 1275 | { |
michael@0 | 1276 | uint32_t w; |
michael@0 | 1277 | |
michael@0 | 1278 | while (y < 0) |
michael@0 | 1279 | y += image->height; |
michael@0 | 1280 | |
michael@0 | 1281 | while (y >= image->height) |
michael@0 | 1282 | y -= image->height; |
michael@0 | 1283 | |
michael@0 | 1284 | if (image->width == 1) |
michael@0 | 1285 | { |
michael@0 | 1286 | if (wide) |
michael@0 | 1287 | replicate_pixel_float (image, 0, y, width, buffer); |
michael@0 | 1288 | else |
michael@0 | 1289 | replicate_pixel_32 (image, 0, y, width, buffer); |
michael@0 | 1290 | |
michael@0 | 1291 | return; |
michael@0 | 1292 | } |
michael@0 | 1293 | |
michael@0 | 1294 | while (width) |
michael@0 | 1295 | { |
michael@0 | 1296 | while (x < 0) |
michael@0 | 1297 | x += image->width; |
michael@0 | 1298 | while (x >= image->width) |
michael@0 | 1299 | x -= image->width; |
michael@0 | 1300 | |
michael@0 | 1301 | w = MIN (width, image->width - x); |
michael@0 | 1302 | |
michael@0 | 1303 | if (wide) |
michael@0 | 1304 | image->fetch_scanline_float ((pixman_image_t *)image, x, y, w, buffer, NULL); |
michael@0 | 1305 | else |
michael@0 | 1306 | image->fetch_scanline_32 ((pixman_image_t *)image, x, y, w, buffer, NULL); |
michael@0 | 1307 | |
michael@0 | 1308 | buffer += w * (wide? 4 : 1); |
michael@0 | 1309 | x += w; |
michael@0 | 1310 | width -= w; |
michael@0 | 1311 | } |
michael@0 | 1312 | } |
michael@0 | 1313 | |
michael@0 | 1314 | static uint32_t * |
michael@0 | 1315 | bits_image_fetch_untransformed_32 (pixman_iter_t * iter, |
michael@0 | 1316 | const uint32_t *mask) |
michael@0 | 1317 | { |
michael@0 | 1318 | pixman_image_t *image = iter->image; |
michael@0 | 1319 | int x = iter->x; |
michael@0 | 1320 | int y = iter->y; |
michael@0 | 1321 | int width = iter->width; |
michael@0 | 1322 | uint32_t * buffer = iter->buffer; |
michael@0 | 1323 | |
michael@0 | 1324 | if (image->common.repeat == PIXMAN_REPEAT_NONE) |
michael@0 | 1325 | { |
michael@0 | 1326 | bits_image_fetch_untransformed_repeat_none ( |
michael@0 | 1327 | &image->bits, FALSE, x, y, width, buffer); |
michael@0 | 1328 | } |
michael@0 | 1329 | else |
michael@0 | 1330 | { |
michael@0 | 1331 | bits_image_fetch_untransformed_repeat_normal ( |
michael@0 | 1332 | &image->bits, FALSE, x, y, width, buffer); |
michael@0 | 1333 | } |
michael@0 | 1334 | |
michael@0 | 1335 | iter->y++; |
michael@0 | 1336 | return buffer; |
michael@0 | 1337 | } |
michael@0 | 1338 | |
michael@0 | 1339 | static uint32_t * |
michael@0 | 1340 | bits_image_fetch_untransformed_float (pixman_iter_t * iter, |
michael@0 | 1341 | const uint32_t *mask) |
michael@0 | 1342 | { |
michael@0 | 1343 | pixman_image_t *image = iter->image; |
michael@0 | 1344 | int x = iter->x; |
michael@0 | 1345 | int y = iter->y; |
michael@0 | 1346 | int width = iter->width; |
michael@0 | 1347 | uint32_t * buffer = iter->buffer; |
michael@0 | 1348 | |
michael@0 | 1349 | if (image->common.repeat == PIXMAN_REPEAT_NONE) |
michael@0 | 1350 | { |
michael@0 | 1351 | bits_image_fetch_untransformed_repeat_none ( |
michael@0 | 1352 | &image->bits, TRUE, x, y, width, buffer); |
michael@0 | 1353 | } |
michael@0 | 1354 | else |
michael@0 | 1355 | { |
michael@0 | 1356 | bits_image_fetch_untransformed_repeat_normal ( |
michael@0 | 1357 | &image->bits, TRUE, x, y, width, buffer); |
michael@0 | 1358 | } |
michael@0 | 1359 | |
michael@0 | 1360 | iter->y++; |
michael@0 | 1361 | return buffer; |
michael@0 | 1362 | } |
michael@0 | 1363 | |
michael@0 | 1364 | typedef struct |
michael@0 | 1365 | { |
michael@0 | 1366 | pixman_format_code_t format; |
michael@0 | 1367 | uint32_t flags; |
michael@0 | 1368 | pixman_iter_get_scanline_t get_scanline_32; |
michael@0 | 1369 | pixman_iter_get_scanline_t get_scanline_float; |
michael@0 | 1370 | } fetcher_info_t; |
michael@0 | 1371 | |
michael@0 | 1372 | static const fetcher_info_t fetcher_info[] = |
michael@0 | 1373 | { |
michael@0 | 1374 | { PIXMAN_any, |
michael@0 | 1375 | (FAST_PATH_NO_ALPHA_MAP | |
michael@0 | 1376 | FAST_PATH_ID_TRANSFORM | |
michael@0 | 1377 | FAST_PATH_NO_CONVOLUTION_FILTER | |
michael@0 | 1378 | FAST_PATH_NO_PAD_REPEAT | |
michael@0 | 1379 | FAST_PATH_NO_REFLECT_REPEAT), |
michael@0 | 1380 | bits_image_fetch_untransformed_32, |
michael@0 | 1381 | bits_image_fetch_untransformed_float |
michael@0 | 1382 | }, |
michael@0 | 1383 | |
michael@0 | 1384 | #define FAST_BILINEAR_FLAGS \ |
michael@0 | 1385 | (FAST_PATH_NO_ALPHA_MAP | \ |
michael@0 | 1386 | FAST_PATH_NO_ACCESSORS | \ |
michael@0 | 1387 | FAST_PATH_HAS_TRANSFORM | \ |
michael@0 | 1388 | FAST_PATH_AFFINE_TRANSFORM | \ |
michael@0 | 1389 | FAST_PATH_X_UNIT_POSITIVE | \ |
michael@0 | 1390 | FAST_PATH_Y_UNIT_ZERO | \ |
michael@0 | 1391 | FAST_PATH_NONE_REPEAT | \ |
michael@0 | 1392 | FAST_PATH_BILINEAR_FILTER) |
michael@0 | 1393 | |
michael@0 | 1394 | { PIXMAN_a8r8g8b8, |
michael@0 | 1395 | FAST_BILINEAR_FLAGS, |
michael@0 | 1396 | bits_image_fetch_bilinear_no_repeat_8888, |
michael@0 | 1397 | _pixman_image_get_scanline_generic_float |
michael@0 | 1398 | }, |
michael@0 | 1399 | |
michael@0 | 1400 | { PIXMAN_x8r8g8b8, |
michael@0 | 1401 | FAST_BILINEAR_FLAGS, |
michael@0 | 1402 | bits_image_fetch_bilinear_no_repeat_8888, |
michael@0 | 1403 | _pixman_image_get_scanline_generic_float |
michael@0 | 1404 | }, |
michael@0 | 1405 | |
michael@0 | 1406 | #define GENERAL_BILINEAR_FLAGS \ |
michael@0 | 1407 | (FAST_PATH_NO_ALPHA_MAP | \ |
michael@0 | 1408 | FAST_PATH_NO_ACCESSORS | \ |
michael@0 | 1409 | FAST_PATH_HAS_TRANSFORM | \ |
michael@0 | 1410 | FAST_PATH_AFFINE_TRANSFORM | \ |
michael@0 | 1411 | FAST_PATH_BILINEAR_FILTER) |
michael@0 | 1412 | |
michael@0 | 1413 | #define GENERAL_NEAREST_FLAGS \ |
michael@0 | 1414 | (FAST_PATH_NO_ALPHA_MAP | \ |
michael@0 | 1415 | FAST_PATH_NO_ACCESSORS | \ |
michael@0 | 1416 | FAST_PATH_HAS_TRANSFORM | \ |
michael@0 | 1417 | FAST_PATH_AFFINE_TRANSFORM | \ |
michael@0 | 1418 | FAST_PATH_NEAREST_FILTER) |
michael@0 | 1419 | |
michael@0 | 1420 | #define GENERAL_SEPARABLE_CONVOLUTION_FLAGS \ |
michael@0 | 1421 | (FAST_PATH_NO_ALPHA_MAP | \ |
michael@0 | 1422 | FAST_PATH_NO_ACCESSORS | \ |
michael@0 | 1423 | FAST_PATH_HAS_TRANSFORM | \ |
michael@0 | 1424 | FAST_PATH_AFFINE_TRANSFORM | \ |
michael@0 | 1425 | FAST_PATH_SEPARABLE_CONVOLUTION_FILTER) |
michael@0 | 1426 | |
michael@0 | 1427 | #define SEPARABLE_CONVOLUTION_AFFINE_FAST_PATH(name, format, repeat) \ |
michael@0 | 1428 | { PIXMAN_ ## format, \ |
michael@0 | 1429 | GENERAL_SEPARABLE_CONVOLUTION_FLAGS | FAST_PATH_ ## repeat ## _REPEAT, \ |
michael@0 | 1430 | bits_image_fetch_separable_convolution_affine_ ## name, \ |
michael@0 | 1431 | _pixman_image_get_scanline_generic_float \ |
michael@0 | 1432 | }, |
michael@0 | 1433 | |
michael@0 | 1434 | #define BILINEAR_AFFINE_FAST_PATH(name, format, repeat) \ |
michael@0 | 1435 | { PIXMAN_ ## format, \ |
michael@0 | 1436 | GENERAL_BILINEAR_FLAGS | FAST_PATH_ ## repeat ## _REPEAT, \ |
michael@0 | 1437 | bits_image_fetch_bilinear_affine_ ## name, \ |
michael@0 | 1438 | _pixman_image_get_scanline_generic_float \ |
michael@0 | 1439 | }, |
michael@0 | 1440 | |
michael@0 | 1441 | #define NEAREST_AFFINE_FAST_PATH(name, format, repeat) \ |
michael@0 | 1442 | { PIXMAN_ ## format, \ |
michael@0 | 1443 | GENERAL_NEAREST_FLAGS | FAST_PATH_ ## repeat ## _REPEAT, \ |
michael@0 | 1444 | bits_image_fetch_nearest_affine_ ## name, \ |
michael@0 | 1445 | _pixman_image_get_scanline_generic_float \ |
michael@0 | 1446 | }, |
michael@0 | 1447 | |
michael@0 | 1448 | #define AFFINE_FAST_PATHS(name, format, repeat) \ |
michael@0 | 1449 | SEPARABLE_CONVOLUTION_AFFINE_FAST_PATH(name, format, repeat) \ |
michael@0 | 1450 | BILINEAR_AFFINE_FAST_PATH(name, format, repeat) \ |
michael@0 | 1451 | NEAREST_AFFINE_FAST_PATH(name, format, repeat) |
michael@0 | 1452 | |
michael@0 | 1453 | AFFINE_FAST_PATHS (pad_a8r8g8b8, a8r8g8b8, PAD) |
michael@0 | 1454 | AFFINE_FAST_PATHS (none_a8r8g8b8, a8r8g8b8, NONE) |
michael@0 | 1455 | AFFINE_FAST_PATHS (reflect_a8r8g8b8, a8r8g8b8, REFLECT) |
michael@0 | 1456 | AFFINE_FAST_PATHS (normal_a8r8g8b8, a8r8g8b8, NORMAL) |
michael@0 | 1457 | AFFINE_FAST_PATHS (pad_x8r8g8b8, x8r8g8b8, PAD) |
michael@0 | 1458 | AFFINE_FAST_PATHS (none_x8r8g8b8, x8r8g8b8, NONE) |
michael@0 | 1459 | AFFINE_FAST_PATHS (reflect_x8r8g8b8, x8r8g8b8, REFLECT) |
michael@0 | 1460 | AFFINE_FAST_PATHS (normal_x8r8g8b8, x8r8g8b8, NORMAL) |
michael@0 | 1461 | AFFINE_FAST_PATHS (pad_a8, a8, PAD) |
michael@0 | 1462 | AFFINE_FAST_PATHS (none_a8, a8, NONE) |
michael@0 | 1463 | AFFINE_FAST_PATHS (reflect_a8, a8, REFLECT) |
michael@0 | 1464 | AFFINE_FAST_PATHS (normal_a8, a8, NORMAL) |
michael@0 | 1465 | AFFINE_FAST_PATHS (pad_r5g6b5, r5g6b5, PAD) |
michael@0 | 1466 | AFFINE_FAST_PATHS (none_r5g6b5, r5g6b5, NONE) |
michael@0 | 1467 | AFFINE_FAST_PATHS (reflect_r5g6b5, r5g6b5, REFLECT) |
michael@0 | 1468 | AFFINE_FAST_PATHS (normal_r5g6b5, r5g6b5, NORMAL) |
michael@0 | 1469 | |
michael@0 | 1470 | /* Affine, no alpha */ |
michael@0 | 1471 | { PIXMAN_any, |
michael@0 | 1472 | (FAST_PATH_NO_ALPHA_MAP | FAST_PATH_HAS_TRANSFORM | FAST_PATH_AFFINE_TRANSFORM), |
michael@0 | 1473 | bits_image_fetch_affine_no_alpha, |
michael@0 | 1474 | _pixman_image_get_scanline_generic_float |
michael@0 | 1475 | }, |
michael@0 | 1476 | |
michael@0 | 1477 | /* General */ |
michael@0 | 1478 | { PIXMAN_any, |
michael@0 | 1479 | 0, |
michael@0 | 1480 | bits_image_fetch_general, |
michael@0 | 1481 | _pixman_image_get_scanline_generic_float |
michael@0 | 1482 | }, |
michael@0 | 1483 | |
michael@0 | 1484 | { PIXMAN_null }, |
michael@0 | 1485 | }; |
michael@0 | 1486 | |
michael@0 | 1487 | static void |
michael@0 | 1488 | bits_image_property_changed (pixman_image_t *image) |
michael@0 | 1489 | { |
michael@0 | 1490 | _pixman_bits_image_setup_accessors (&image->bits); |
michael@0 | 1491 | } |
michael@0 | 1492 | |
michael@0 | 1493 | void |
michael@0 | 1494 | _pixman_bits_image_src_iter_init (pixman_image_t *image, pixman_iter_t *iter) |
michael@0 | 1495 | { |
michael@0 | 1496 | pixman_format_code_t format = image->common.extended_format_code; |
michael@0 | 1497 | uint32_t flags = image->common.flags; |
michael@0 | 1498 | const fetcher_info_t *info; |
michael@0 | 1499 | |
michael@0 | 1500 | for (info = fetcher_info; info->format != PIXMAN_null; ++info) |
michael@0 | 1501 | { |
michael@0 | 1502 | if ((info->format == format || info->format == PIXMAN_any) && |
michael@0 | 1503 | (info->flags & flags) == info->flags) |
michael@0 | 1504 | { |
michael@0 | 1505 | if (iter->iter_flags & ITER_NARROW) |
michael@0 | 1506 | { |
michael@0 | 1507 | iter->get_scanline = info->get_scanline_32; |
michael@0 | 1508 | } |
michael@0 | 1509 | else |
michael@0 | 1510 | { |
michael@0 | 1511 | iter->data = info->get_scanline_32; |
michael@0 | 1512 | iter->get_scanline = info->get_scanline_float; |
michael@0 | 1513 | } |
michael@0 | 1514 | return; |
michael@0 | 1515 | } |
michael@0 | 1516 | } |
michael@0 | 1517 | |
michael@0 | 1518 | /* Just in case we somehow didn't find a scanline function */ |
michael@0 | 1519 | iter->get_scanline = _pixman_iter_get_scanline_noop; |
michael@0 | 1520 | } |
michael@0 | 1521 | |
michael@0 | 1522 | static uint32_t * |
michael@0 | 1523 | dest_get_scanline_16 (pixman_iter_t *iter, const uint32_t *mask) |
michael@0 | 1524 | { |
michael@0 | 1525 | pixman_image_t *image = iter->image; |
michael@0 | 1526 | int x = iter->x; |
michael@0 | 1527 | int y = iter->y; |
michael@0 | 1528 | int width = iter->width; |
michael@0 | 1529 | uint32_t * buffer = iter->buffer; |
michael@0 | 1530 | |
michael@0 | 1531 | image->bits.fetch_scanline_16 (image, x, y, width, buffer, mask); |
michael@0 | 1532 | |
michael@0 | 1533 | return iter->buffer; |
michael@0 | 1534 | } |
michael@0 | 1535 | |
michael@0 | 1536 | static uint32_t * |
michael@0 | 1537 | dest_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) |
michael@0 | 1538 | { |
michael@0 | 1539 | pixman_image_t *image = iter->image; |
michael@0 | 1540 | int x = iter->x; |
michael@0 | 1541 | int y = iter->y; |
michael@0 | 1542 | int width = iter->width; |
michael@0 | 1543 | uint32_t * buffer = iter->buffer; |
michael@0 | 1544 | |
michael@0 | 1545 | image->bits.fetch_scanline_32 (image, x, y, width, buffer, mask); |
michael@0 | 1546 | if (image->common.alpha_map) |
michael@0 | 1547 | { |
michael@0 | 1548 | uint32_t *alpha; |
michael@0 | 1549 | |
michael@0 | 1550 | if ((alpha = malloc (width * sizeof (uint32_t)))) |
michael@0 | 1551 | { |
michael@0 | 1552 | int i; |
michael@0 | 1553 | |
michael@0 | 1554 | x -= image->common.alpha_origin_x; |
michael@0 | 1555 | y -= image->common.alpha_origin_y; |
michael@0 | 1556 | |
michael@0 | 1557 | image->common.alpha_map->fetch_scanline_32 ( |
michael@0 | 1558 | (pixman_image_t *)image->common.alpha_map, |
michael@0 | 1559 | x, y, width, alpha, mask); |
michael@0 | 1560 | |
michael@0 | 1561 | for (i = 0; i < width; ++i) |
michael@0 | 1562 | { |
michael@0 | 1563 | buffer[i] &= ~0xff000000; |
michael@0 | 1564 | buffer[i] |= (alpha[i] & 0xff000000); |
michael@0 | 1565 | } |
michael@0 | 1566 | |
michael@0 | 1567 | free (alpha); |
michael@0 | 1568 | } |
michael@0 | 1569 | } |
michael@0 | 1570 | |
michael@0 | 1571 | return iter->buffer; |
michael@0 | 1572 | } |
michael@0 | 1573 | |
michael@0 | 1574 | static uint32_t * |
michael@0 | 1575 | dest_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) |
michael@0 | 1576 | { |
michael@0 | 1577 | bits_image_t * image = &iter->image->bits; |
michael@0 | 1578 | int x = iter->x; |
michael@0 | 1579 | int y = iter->y; |
michael@0 | 1580 | int width = iter->width; |
michael@0 | 1581 | argb_t * buffer = (argb_t *)iter->buffer; |
michael@0 | 1582 | |
michael@0 | 1583 | image->fetch_scanline_float ( |
michael@0 | 1584 | (pixman_image_t *)image, x, y, width, (uint32_t *)buffer, mask); |
michael@0 | 1585 | if (image->common.alpha_map) |
michael@0 | 1586 | { |
michael@0 | 1587 | argb_t *alpha; |
michael@0 | 1588 | |
michael@0 | 1589 | if ((alpha = malloc (width * sizeof (argb_t)))) |
michael@0 | 1590 | { |
michael@0 | 1591 | int i; |
michael@0 | 1592 | |
michael@0 | 1593 | x -= image->common.alpha_origin_x; |
michael@0 | 1594 | y -= image->common.alpha_origin_y; |
michael@0 | 1595 | |
michael@0 | 1596 | image->common.alpha_map->fetch_scanline_float ( |
michael@0 | 1597 | (pixman_image_t *)image->common.alpha_map, |
michael@0 | 1598 | x, y, width, (uint32_t *)alpha, mask); |
michael@0 | 1599 | |
michael@0 | 1600 | for (i = 0; i < width; ++i) |
michael@0 | 1601 | buffer[i].a = alpha[i].a; |
michael@0 | 1602 | |
michael@0 | 1603 | free (alpha); |
michael@0 | 1604 | } |
michael@0 | 1605 | } |
michael@0 | 1606 | |
michael@0 | 1607 | return iter->buffer; |
michael@0 | 1608 | } |
michael@0 | 1609 | |
michael@0 | 1610 | static void |
michael@0 | 1611 | dest_write_back_16 (pixman_iter_t *iter) |
michael@0 | 1612 | { |
michael@0 | 1613 | bits_image_t * image = &iter->image->bits; |
michael@0 | 1614 | int x = iter->x; |
michael@0 | 1615 | int y = iter->y; |
michael@0 | 1616 | int width = iter->width; |
michael@0 | 1617 | const uint32_t *buffer = iter->buffer; |
michael@0 | 1618 | |
michael@0 | 1619 | image->store_scanline_16 (image, x, y, width, buffer); |
michael@0 | 1620 | |
michael@0 | 1621 | iter->y++; |
michael@0 | 1622 | } |
michael@0 | 1623 | |
michael@0 | 1624 | static void |
michael@0 | 1625 | dest_write_back_narrow (pixman_iter_t *iter) |
michael@0 | 1626 | { |
michael@0 | 1627 | bits_image_t * image = &iter->image->bits; |
michael@0 | 1628 | int x = iter->x; |
michael@0 | 1629 | int y = iter->y; |
michael@0 | 1630 | int width = iter->width; |
michael@0 | 1631 | const uint32_t *buffer = iter->buffer; |
michael@0 | 1632 | |
michael@0 | 1633 | image->store_scanline_32 (image, x, y, width, buffer); |
michael@0 | 1634 | |
michael@0 | 1635 | if (image->common.alpha_map) |
michael@0 | 1636 | { |
michael@0 | 1637 | x -= image->common.alpha_origin_x; |
michael@0 | 1638 | y -= image->common.alpha_origin_y; |
michael@0 | 1639 | |
michael@0 | 1640 | image->common.alpha_map->store_scanline_32 ( |
michael@0 | 1641 | image->common.alpha_map, x, y, width, buffer); |
michael@0 | 1642 | } |
michael@0 | 1643 | |
michael@0 | 1644 | iter->y++; |
michael@0 | 1645 | } |
michael@0 | 1646 | |
michael@0 | 1647 | static void |
michael@0 | 1648 | dest_write_back_wide (pixman_iter_t *iter) |
michael@0 | 1649 | { |
michael@0 | 1650 | bits_image_t * image = &iter->image->bits; |
michael@0 | 1651 | int x = iter->x; |
michael@0 | 1652 | int y = iter->y; |
michael@0 | 1653 | int width = iter->width; |
michael@0 | 1654 | const uint32_t *buffer = iter->buffer; |
michael@0 | 1655 | |
michael@0 | 1656 | image->store_scanline_float (image, x, y, width, buffer); |
michael@0 | 1657 | |
michael@0 | 1658 | if (image->common.alpha_map) |
michael@0 | 1659 | { |
michael@0 | 1660 | x -= image->common.alpha_origin_x; |
michael@0 | 1661 | y -= image->common.alpha_origin_y; |
michael@0 | 1662 | |
michael@0 | 1663 | image->common.alpha_map->store_scanline_float ( |
michael@0 | 1664 | image->common.alpha_map, x, y, width, buffer); |
michael@0 | 1665 | } |
michael@0 | 1666 | |
michael@0 | 1667 | iter->y++; |
michael@0 | 1668 | } |
michael@0 | 1669 | |
michael@0 | 1670 | void |
michael@0 | 1671 | _pixman_bits_image_dest_iter_init (pixman_image_t *image, pixman_iter_t *iter) |
michael@0 | 1672 | { |
michael@0 | 1673 | if (iter->iter_flags & ITER_16) |
michael@0 | 1674 | { |
michael@0 | 1675 | if ((iter->iter_flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) == |
michael@0 | 1676 | (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) |
michael@0 | 1677 | { |
michael@0 | 1678 | iter->get_scanline = _pixman_iter_get_scanline_noop; |
michael@0 | 1679 | } |
michael@0 | 1680 | else |
michael@0 | 1681 | { |
michael@0 | 1682 | iter->get_scanline = dest_get_scanline_16; |
michael@0 | 1683 | } |
michael@0 | 1684 | iter->write_back = dest_write_back_16; |
michael@0 | 1685 | } |
michael@0 | 1686 | else if (iter->iter_flags & ITER_NARROW) |
michael@0 | 1687 | { |
michael@0 | 1688 | if ((iter->iter_flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) == |
michael@0 | 1689 | (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) |
michael@0 | 1690 | { |
michael@0 | 1691 | iter->get_scanline = _pixman_iter_get_scanline_noop; |
michael@0 | 1692 | } |
michael@0 | 1693 | else |
michael@0 | 1694 | { |
michael@0 | 1695 | iter->get_scanline = dest_get_scanline_narrow; |
michael@0 | 1696 | } |
michael@0 | 1697 | |
michael@0 | 1698 | iter->write_back = dest_write_back_narrow; |
michael@0 | 1699 | } |
michael@0 | 1700 | else |
michael@0 | 1701 | { |
michael@0 | 1702 | iter->get_scanline = dest_get_scanline_wide; |
michael@0 | 1703 | iter->write_back = dest_write_back_wide; |
michael@0 | 1704 | } |
michael@0 | 1705 | } |
michael@0 | 1706 | |
michael@0 | 1707 | static uint32_t * |
michael@0 | 1708 | create_bits (pixman_format_code_t format, |
michael@0 | 1709 | int width, |
michael@0 | 1710 | int height, |
michael@0 | 1711 | int * rowstride_bytes, |
michael@0 | 1712 | pixman_bool_t clear) |
michael@0 | 1713 | { |
michael@0 | 1714 | int stride; |
michael@0 | 1715 | size_t buf_size; |
michael@0 | 1716 | int bpp; |
michael@0 | 1717 | |
michael@0 | 1718 | /* what follows is a long-winded way, avoiding any possibility of integer |
michael@0 | 1719 | * overflows, of saying: |
michael@0 | 1720 | * stride = ((width * bpp + 0x1f) >> 5) * sizeof (uint32_t); |
michael@0 | 1721 | */ |
michael@0 | 1722 | |
michael@0 | 1723 | bpp = PIXMAN_FORMAT_BPP (format); |
michael@0 | 1724 | if (_pixman_multiply_overflows_int (width, bpp)) |
michael@0 | 1725 | return NULL; |
michael@0 | 1726 | |
michael@0 | 1727 | stride = width * bpp; |
michael@0 | 1728 | if (_pixman_addition_overflows_int (stride, 0x1f)) |
michael@0 | 1729 | return NULL; |
michael@0 | 1730 | |
michael@0 | 1731 | stride += 0x1f; |
michael@0 | 1732 | stride >>= 5; |
michael@0 | 1733 | |
michael@0 | 1734 | stride *= sizeof (uint32_t); |
michael@0 | 1735 | |
michael@0 | 1736 | if (_pixman_multiply_overflows_size (height, stride)) |
michael@0 | 1737 | return NULL; |
michael@0 | 1738 | |
michael@0 | 1739 | buf_size = height * stride; |
michael@0 | 1740 | |
michael@0 | 1741 | if (rowstride_bytes) |
michael@0 | 1742 | *rowstride_bytes = stride; |
michael@0 | 1743 | |
michael@0 | 1744 | if (clear) |
michael@0 | 1745 | return calloc (buf_size, 1); |
michael@0 | 1746 | else |
michael@0 | 1747 | return malloc (buf_size); |
michael@0 | 1748 | } |
michael@0 | 1749 | |
michael@0 | 1750 | pixman_bool_t |
michael@0 | 1751 | _pixman_bits_image_init (pixman_image_t * image, |
michael@0 | 1752 | pixman_format_code_t format, |
michael@0 | 1753 | int width, |
michael@0 | 1754 | int height, |
michael@0 | 1755 | uint32_t * bits, |
michael@0 | 1756 | int rowstride, |
michael@0 | 1757 | pixman_bool_t clear) |
michael@0 | 1758 | { |
michael@0 | 1759 | uint32_t *free_me = NULL; |
michael@0 | 1760 | |
michael@0 | 1761 | if (!bits && width && height) |
michael@0 | 1762 | { |
michael@0 | 1763 | int rowstride_bytes; |
michael@0 | 1764 | |
michael@0 | 1765 | free_me = bits = create_bits (format, width, height, &rowstride_bytes, clear); |
michael@0 | 1766 | |
michael@0 | 1767 | if (!bits) |
michael@0 | 1768 | return FALSE; |
michael@0 | 1769 | |
michael@0 | 1770 | rowstride = rowstride_bytes / (int) sizeof (uint32_t); |
michael@0 | 1771 | } |
michael@0 | 1772 | |
michael@0 | 1773 | _pixman_image_init (image); |
michael@0 | 1774 | |
michael@0 | 1775 | image->type = BITS; |
michael@0 | 1776 | image->bits.format = format; |
michael@0 | 1777 | image->bits.width = width; |
michael@0 | 1778 | image->bits.height = height; |
michael@0 | 1779 | image->bits.bits = bits; |
michael@0 | 1780 | image->bits.free_me = free_me; |
michael@0 | 1781 | image->bits.read_func = NULL; |
michael@0 | 1782 | image->bits.write_func = NULL; |
michael@0 | 1783 | image->bits.rowstride = rowstride; |
michael@0 | 1784 | image->bits.indexed = NULL; |
michael@0 | 1785 | |
michael@0 | 1786 | image->common.property_changed = bits_image_property_changed; |
michael@0 | 1787 | |
michael@0 | 1788 | _pixman_image_reset_clip_region (image); |
michael@0 | 1789 | |
michael@0 | 1790 | return TRUE; |
michael@0 | 1791 | } |
michael@0 | 1792 | |
michael@0 | 1793 | static pixman_image_t * |
michael@0 | 1794 | create_bits_image_internal (pixman_format_code_t format, |
michael@0 | 1795 | int width, |
michael@0 | 1796 | int height, |
michael@0 | 1797 | uint32_t * bits, |
michael@0 | 1798 | int rowstride_bytes, |
michael@0 | 1799 | pixman_bool_t clear) |
michael@0 | 1800 | { |
michael@0 | 1801 | pixman_image_t *image; |
michael@0 | 1802 | |
michael@0 | 1803 | /* must be a whole number of uint32_t's |
michael@0 | 1804 | */ |
michael@0 | 1805 | return_val_if_fail ( |
michael@0 | 1806 | bits == NULL || (rowstride_bytes % sizeof (uint32_t)) == 0, NULL); |
michael@0 | 1807 | |
michael@0 | 1808 | return_val_if_fail (PIXMAN_FORMAT_BPP (format) >= PIXMAN_FORMAT_DEPTH (format), NULL); |
michael@0 | 1809 | |
michael@0 | 1810 | image = _pixman_image_allocate (); |
michael@0 | 1811 | |
michael@0 | 1812 | if (!image) |
michael@0 | 1813 | return NULL; |
michael@0 | 1814 | |
michael@0 | 1815 | if (!_pixman_bits_image_init (image, format, width, height, bits, |
michael@0 | 1816 | rowstride_bytes / (int) sizeof (uint32_t), |
michael@0 | 1817 | clear)) |
michael@0 | 1818 | { |
michael@0 | 1819 | free (image); |
michael@0 | 1820 | return NULL; |
michael@0 | 1821 | } |
michael@0 | 1822 | |
michael@0 | 1823 | return image; |
michael@0 | 1824 | } |
michael@0 | 1825 | |
michael@0 | 1826 | /* If bits is NULL, a buffer will be allocated and initialized to 0 */ |
michael@0 | 1827 | PIXMAN_EXPORT pixman_image_t * |
michael@0 | 1828 | pixman_image_create_bits (pixman_format_code_t format, |
michael@0 | 1829 | int width, |
michael@0 | 1830 | int height, |
michael@0 | 1831 | uint32_t * bits, |
michael@0 | 1832 | int rowstride_bytes) |
michael@0 | 1833 | { |
michael@0 | 1834 | return create_bits_image_internal ( |
michael@0 | 1835 | format, width, height, bits, rowstride_bytes, TRUE); |
michael@0 | 1836 | } |
michael@0 | 1837 | |
michael@0 | 1838 | |
michael@0 | 1839 | /* If bits is NULL, a buffer will be allocated and _not_ initialized */ |
michael@0 | 1840 | PIXMAN_EXPORT pixman_image_t * |
michael@0 | 1841 | pixman_image_create_bits_no_clear (pixman_format_code_t format, |
michael@0 | 1842 | int width, |
michael@0 | 1843 | int height, |
michael@0 | 1844 | uint32_t * bits, |
michael@0 | 1845 | int rowstride_bytes) |
michael@0 | 1846 | { |
michael@0 | 1847 | return create_bits_image_internal ( |
michael@0 | 1848 | format, width, height, bits, rowstride_bytes, FALSE); |
michael@0 | 1849 | } |