michael@0: /* michael@0: * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. michael@0: * 2005 Lars Knoll & Zack Rusin, Trolltech michael@0: * 2008 Aaron Plattner, NVIDIA Corporation michael@0: * Copyright © 2000 SuSE, Inc. michael@0: * Copyright © 2007, 2009 Red Hat, Inc. michael@0: * Copyright © 2008 André Tupinambá michael@0: * michael@0: * Permission to use, copy, modify, distribute, and sell this software and its michael@0: * documentation for any purpose is hereby granted without fee, provided that michael@0: * the above copyright notice appear in all copies and that both that michael@0: * copyright notice and this permission notice appear in supporting michael@0: * documentation, and that the name of Keith Packard not be used in michael@0: * advertising or publicity pertaining to distribution of the software without michael@0: * specific, written prior permission. Keith Packard makes no michael@0: * representations about the suitability of this software for any purpose. It michael@0: * is provided "as is" without express or implied warranty. michael@0: * michael@0: * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS michael@0: * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND michael@0: * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY michael@0: * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES michael@0: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN michael@0: * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING michael@0: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS michael@0: * SOFTWARE. michael@0: */ michael@0: michael@0: #ifdef HAVE_CONFIG_H michael@0: #include michael@0: #endif michael@0: #include michael@0: #include michael@0: #include michael@0: #include "pixman-private.h" michael@0: #include "pixman-combine32.h" michael@0: #include "pixman-inlines.h" michael@0: michael@0: static uint32_t * michael@0: _pixman_image_get_scanline_generic_float (pixman_iter_t * iter, michael@0: const uint32_t *mask) michael@0: { michael@0: pixman_iter_get_scanline_t fetch_32 = iter->data; michael@0: uint32_t *buffer = iter->buffer; michael@0: michael@0: fetch_32 (iter, NULL); michael@0: michael@0: pixman_expand_to_float ((argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width); michael@0: michael@0: return iter->buffer; michael@0: } michael@0: michael@0: /* Fetch functions */ michael@0: michael@0: static force_inline uint32_t michael@0: fetch_pixel_no_alpha (bits_image_t *image, michael@0: int x, int y, pixman_bool_t check_bounds) michael@0: { michael@0: if (check_bounds && michael@0: (x < 0 || x >= image->width || y < 0 || y >= image->height)) michael@0: { michael@0: return 0; michael@0: } michael@0: michael@0: return image->fetch_pixel_32 (image, x, y); michael@0: } michael@0: michael@0: typedef uint32_t (* get_pixel_t) (bits_image_t *image, michael@0: int x, int y, pixman_bool_t check_bounds); michael@0: michael@0: static force_inline uint32_t michael@0: bits_image_fetch_pixel_nearest (bits_image_t *image, michael@0: pixman_fixed_t x, michael@0: pixman_fixed_t y, michael@0: get_pixel_t get_pixel) michael@0: { michael@0: int x0 = pixman_fixed_to_int (x - pixman_fixed_e); michael@0: int y0 = pixman_fixed_to_int (y - pixman_fixed_e); michael@0: michael@0: if (image->common.repeat != PIXMAN_REPEAT_NONE) michael@0: { michael@0: repeat (image->common.repeat, &x0, image->width); michael@0: repeat (image->common.repeat, &y0, image->height); michael@0: michael@0: return get_pixel (image, x0, y0, FALSE); michael@0: } michael@0: else michael@0: { michael@0: return get_pixel (image, x0, y0, TRUE); michael@0: } michael@0: } michael@0: michael@0: static force_inline uint32_t michael@0: bits_image_fetch_pixel_bilinear (bits_image_t *image, michael@0: pixman_fixed_t x, michael@0: pixman_fixed_t y, michael@0: get_pixel_t get_pixel) michael@0: { michael@0: pixman_repeat_t repeat_mode = image->common.repeat; michael@0: int width = image->width; michael@0: int height = image->height; michael@0: int x1, y1, x2, y2; michael@0: uint32_t tl, tr, bl, br; michael@0: int32_t distx, disty; michael@0: michael@0: x1 = x - pixman_fixed_1 / 2; michael@0: y1 = y - pixman_fixed_1 / 2; michael@0: michael@0: distx = pixman_fixed_to_bilinear_weight (x1); michael@0: disty = pixman_fixed_to_bilinear_weight (y1); michael@0: michael@0: x1 = pixman_fixed_to_int (x1); michael@0: y1 = pixman_fixed_to_int (y1); michael@0: x2 = x1 + 1; michael@0: y2 = y1 + 1; michael@0: michael@0: if (repeat_mode != PIXMAN_REPEAT_NONE) michael@0: { michael@0: repeat (repeat_mode, &x1, width); michael@0: repeat (repeat_mode, &y1, height); michael@0: repeat (repeat_mode, &x2, width); michael@0: repeat (repeat_mode, &y2, height); michael@0: michael@0: tl = get_pixel (image, x1, y1, FALSE); michael@0: bl = get_pixel (image, x1, y2, FALSE); michael@0: tr = get_pixel (image, x2, y1, FALSE); michael@0: br = get_pixel (image, x2, y2, FALSE); michael@0: } michael@0: else michael@0: { michael@0: tl = get_pixel (image, x1, y1, TRUE); michael@0: tr = get_pixel (image, x2, y1, TRUE); michael@0: bl = get_pixel (image, x1, y2, TRUE); michael@0: br = get_pixel (image, x2, y2, TRUE); michael@0: } michael@0: michael@0: return bilinear_interpolation (tl, tr, bl, br, distx, disty); michael@0: } michael@0: michael@0: static uint32_t * michael@0: bits_image_fetch_bilinear_no_repeat_8888 (pixman_iter_t *iter, michael@0: const uint32_t *mask) michael@0: { michael@0: michael@0: pixman_image_t * ima = iter->image; michael@0: int offset = iter->x; michael@0: int line = iter->y++; michael@0: int width = iter->width; michael@0: uint32_t * buffer = iter->buffer; michael@0: michael@0: bits_image_t *bits = &ima->bits; michael@0: pixman_fixed_t x_top, x_bottom, x; michael@0: pixman_fixed_t ux_top, ux_bottom, ux; michael@0: pixman_vector_t v; michael@0: uint32_t top_mask, bottom_mask; michael@0: uint32_t *top_row; michael@0: uint32_t *bottom_row; michael@0: uint32_t *end; michael@0: uint32_t zero[2] = { 0, 0 }; michael@0: uint32_t one = 1; michael@0: int y, y1, y2; michael@0: int disty; michael@0: int mask_inc; michael@0: int w; michael@0: michael@0: /* reference point is the center of the pixel */ michael@0: v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; michael@0: v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; michael@0: v.vector[2] = pixman_fixed_1; michael@0: michael@0: if (!pixman_transform_point_3d (bits->common.transform, &v)) michael@0: return iter->buffer; michael@0: michael@0: ux = ux_top = ux_bottom = bits->common.transform->matrix[0][0]; michael@0: x = x_top = x_bottom = v.vector[0] - pixman_fixed_1/2; michael@0: michael@0: y = v.vector[1] - pixman_fixed_1/2; michael@0: disty = pixman_fixed_to_bilinear_weight (y); michael@0: michael@0: /* Load the pointers to the first and second lines from the source michael@0: * image that bilinear code must read. michael@0: * michael@0: * The main trick in this code is about the check if any line are michael@0: * outside of the image; michael@0: * michael@0: * When I realize that a line (any one) is outside, I change michael@0: * the pointer to a dummy area with zeros. Once I change this, I michael@0: * must be sure the pointer will not change, so I set the michael@0: * variables to each pointer increments inside the loop. michael@0: */ michael@0: y1 = pixman_fixed_to_int (y); michael@0: y2 = y1 + 1; michael@0: michael@0: if (y1 < 0 || y1 >= bits->height) michael@0: { michael@0: top_row = zero; michael@0: x_top = 0; michael@0: ux_top = 0; michael@0: } michael@0: else michael@0: { michael@0: top_row = bits->bits + y1 * bits->rowstride; michael@0: x_top = x; michael@0: ux_top = ux; michael@0: } michael@0: michael@0: if (y2 < 0 || y2 >= bits->height) michael@0: { michael@0: bottom_row = zero; michael@0: x_bottom = 0; michael@0: ux_bottom = 0; michael@0: } michael@0: else michael@0: { michael@0: bottom_row = bits->bits + y2 * bits->rowstride; michael@0: x_bottom = x; michael@0: ux_bottom = ux; michael@0: } michael@0: michael@0: /* Instead of checking whether the operation uses the mast in michael@0: * each loop iteration, verify this only once and prepare the michael@0: * variables to make the code smaller inside the loop. michael@0: */ michael@0: if (!mask) michael@0: { michael@0: mask_inc = 0; michael@0: mask = &one; michael@0: } michael@0: else michael@0: { michael@0: /* If have a mask, prepare the variables to check it */ michael@0: mask_inc = 1; michael@0: } michael@0: michael@0: /* If both are zero, then the whole thing is zero */ michael@0: if (top_row == zero && bottom_row == zero) michael@0: { michael@0: memset (buffer, 0, width * sizeof (uint32_t)); michael@0: return iter->buffer; michael@0: } michael@0: else if (bits->format == PIXMAN_x8r8g8b8) michael@0: { michael@0: if (top_row == zero) michael@0: { michael@0: top_mask = 0; michael@0: bottom_mask = 0xff000000; michael@0: } michael@0: else if (bottom_row == zero) michael@0: { michael@0: top_mask = 0xff000000; michael@0: bottom_mask = 0; michael@0: } michael@0: else michael@0: { michael@0: top_mask = 0xff000000; michael@0: bottom_mask = 0xff000000; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: top_mask = 0; michael@0: bottom_mask = 0; michael@0: } michael@0: michael@0: end = buffer + width; michael@0: michael@0: /* Zero fill to the left of the image */ michael@0: while (buffer < end && x < pixman_fixed_minus_1) michael@0: { michael@0: *buffer++ = 0; michael@0: x += ux; michael@0: x_top += ux_top; michael@0: x_bottom += ux_bottom; michael@0: mask += mask_inc; michael@0: } michael@0: michael@0: /* Left edge michael@0: */ michael@0: while (buffer < end && x < 0) michael@0: { michael@0: uint32_t tr, br; michael@0: int32_t distx; michael@0: michael@0: tr = top_row[pixman_fixed_to_int (x_top) + 1] | top_mask; michael@0: br = bottom_row[pixman_fixed_to_int (x_bottom) + 1] | bottom_mask; michael@0: michael@0: distx = pixman_fixed_to_bilinear_weight (x); michael@0: michael@0: *buffer++ = bilinear_interpolation (0, tr, 0, br, distx, disty); michael@0: michael@0: x += ux; michael@0: x_top += ux_top; michael@0: x_bottom += ux_bottom; michael@0: mask += mask_inc; michael@0: } michael@0: michael@0: /* Main part */ michael@0: w = pixman_int_to_fixed (bits->width - 1); michael@0: michael@0: while (buffer < end && x < w) michael@0: { michael@0: if (*mask) michael@0: { michael@0: uint32_t tl, tr, bl, br; michael@0: int32_t distx; michael@0: michael@0: tl = top_row [pixman_fixed_to_int (x_top)] | top_mask; michael@0: tr = top_row [pixman_fixed_to_int (x_top) + 1] | top_mask; michael@0: bl = bottom_row [pixman_fixed_to_int (x_bottom)] | bottom_mask; michael@0: br = bottom_row [pixman_fixed_to_int (x_bottom) + 1] | bottom_mask; michael@0: michael@0: distx = pixman_fixed_to_bilinear_weight (x); michael@0: michael@0: *buffer = bilinear_interpolation (tl, tr, bl, br, distx, disty); michael@0: } michael@0: michael@0: buffer++; michael@0: x += ux; michael@0: x_top += ux_top; michael@0: x_bottom += ux_bottom; michael@0: mask += mask_inc; michael@0: } michael@0: michael@0: /* Right Edge */ michael@0: w = pixman_int_to_fixed (bits->width); michael@0: while (buffer < end && x < w) michael@0: { michael@0: if (*mask) michael@0: { michael@0: uint32_t tl, bl; michael@0: int32_t distx; michael@0: michael@0: tl = top_row [pixman_fixed_to_int (x_top)] | top_mask; michael@0: bl = bottom_row [pixman_fixed_to_int (x_bottom)] | bottom_mask; michael@0: michael@0: distx = pixman_fixed_to_bilinear_weight (x); michael@0: michael@0: *buffer = bilinear_interpolation (tl, 0, bl, 0, distx, disty); michael@0: } michael@0: michael@0: buffer++; michael@0: x += ux; michael@0: x_top += ux_top; michael@0: x_bottom += ux_bottom; michael@0: mask += mask_inc; michael@0: } michael@0: michael@0: /* Zero fill to the left of the image */ michael@0: while (buffer < end) michael@0: *buffer++ = 0; michael@0: michael@0: return iter->buffer; michael@0: } michael@0: michael@0: static force_inline uint32_t michael@0: bits_image_fetch_pixel_convolution (bits_image_t *image, michael@0: pixman_fixed_t x, michael@0: pixman_fixed_t y, michael@0: get_pixel_t get_pixel) michael@0: { michael@0: pixman_fixed_t *params = image->common.filter_params; michael@0: int x_off = (params[0] - pixman_fixed_1) >> 1; michael@0: int y_off = (params[1] - pixman_fixed_1) >> 1; michael@0: int32_t cwidth = pixman_fixed_to_int (params[0]); michael@0: int32_t cheight = pixman_fixed_to_int (params[1]); michael@0: int32_t i, j, x1, x2, y1, y2; michael@0: pixman_repeat_t repeat_mode = image->common.repeat; michael@0: int width = image->width; michael@0: int height = image->height; michael@0: int srtot, sgtot, sbtot, satot; michael@0: michael@0: params += 2; michael@0: michael@0: x1 = pixman_fixed_to_int (x - pixman_fixed_e - x_off); michael@0: y1 = pixman_fixed_to_int (y - pixman_fixed_e - y_off); michael@0: x2 = x1 + cwidth; michael@0: y2 = y1 + cheight; michael@0: michael@0: srtot = sgtot = sbtot = satot = 0; michael@0: michael@0: for (i = y1; i < y2; ++i) michael@0: { michael@0: for (j = x1; j < x2; ++j) michael@0: { michael@0: int rx = j; michael@0: int ry = i; michael@0: michael@0: pixman_fixed_t f = *params; michael@0: michael@0: if (f) michael@0: { michael@0: uint32_t pixel; michael@0: michael@0: if (repeat_mode != PIXMAN_REPEAT_NONE) michael@0: { michael@0: repeat (repeat_mode, &rx, width); michael@0: repeat (repeat_mode, &ry, height); michael@0: michael@0: pixel = get_pixel (image, rx, ry, FALSE); michael@0: } michael@0: else michael@0: { michael@0: pixel = get_pixel (image, rx, ry, TRUE); michael@0: } michael@0: michael@0: srtot += (int)RED_8 (pixel) * f; michael@0: sgtot += (int)GREEN_8 (pixel) * f; michael@0: sbtot += (int)BLUE_8 (pixel) * f; michael@0: satot += (int)ALPHA_8 (pixel) * f; michael@0: } michael@0: michael@0: params++; michael@0: } michael@0: } michael@0: michael@0: satot = (satot + 0x8000) >> 16; michael@0: srtot = (srtot + 0x8000) >> 16; michael@0: sgtot = (sgtot + 0x8000) >> 16; michael@0: sbtot = (sbtot + 0x8000) >> 16; michael@0: michael@0: satot = CLIP (satot, 0, 0xff); michael@0: srtot = CLIP (srtot, 0, 0xff); michael@0: sgtot = CLIP (sgtot, 0, 0xff); michael@0: sbtot = CLIP (sbtot, 0, 0xff); michael@0: michael@0: return ((satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot)); michael@0: } michael@0: michael@0: static uint32_t michael@0: bits_image_fetch_pixel_separable_convolution (bits_image_t *image, michael@0: pixman_fixed_t x, michael@0: pixman_fixed_t y, michael@0: get_pixel_t get_pixel) michael@0: { michael@0: pixman_fixed_t *params = image->common.filter_params; michael@0: pixman_repeat_t repeat_mode = image->common.repeat; michael@0: int width = image->width; michael@0: int height = image->height; michael@0: int cwidth = pixman_fixed_to_int (params[0]); michael@0: int cheight = pixman_fixed_to_int (params[1]); michael@0: int x_phase_bits = pixman_fixed_to_int (params[2]); michael@0: int y_phase_bits = pixman_fixed_to_int (params[3]); michael@0: int x_phase_shift = 16 - x_phase_bits; michael@0: int y_phase_shift = 16 - y_phase_bits; michael@0: int x_off = ((cwidth << 16) - pixman_fixed_1) >> 1; michael@0: int y_off = ((cheight << 16) - pixman_fixed_1) >> 1; michael@0: pixman_fixed_t *y_params; michael@0: int srtot, sgtot, sbtot, satot; michael@0: int32_t x1, x2, y1, y2; michael@0: int32_t px, py; michael@0: int i, j; michael@0: michael@0: /* Round x and y to the middle of the closest phase before continuing. This michael@0: * ensures that the convolution matrix is aligned right, since it was michael@0: * positioned relative to a particular phase (and not relative to whatever michael@0: * exact fraction we happen to get here). michael@0: */ michael@0: x = ((x >> x_phase_shift) << x_phase_shift) + ((1 << x_phase_shift) >> 1); michael@0: y = ((y >> y_phase_shift) << y_phase_shift) + ((1 << y_phase_shift) >> 1); michael@0: michael@0: px = (x & 0xffff) >> x_phase_shift; michael@0: py = (y & 0xffff) >> y_phase_shift; michael@0: michael@0: y_params = params + 4 + (1 << x_phase_bits) * cwidth + py * cheight; michael@0: michael@0: x1 = pixman_fixed_to_int (x - pixman_fixed_e - x_off); michael@0: y1 = pixman_fixed_to_int (y - pixman_fixed_e - y_off); michael@0: x2 = x1 + cwidth; michael@0: y2 = y1 + cheight; michael@0: michael@0: srtot = sgtot = sbtot = satot = 0; michael@0: michael@0: for (i = y1; i < y2; ++i) michael@0: { michael@0: pixman_fixed_48_16_t fy = *y_params++; michael@0: pixman_fixed_t *x_params = params + 4 + px * cwidth; michael@0: michael@0: if (fy) michael@0: { michael@0: for (j = x1; j < x2; ++j) michael@0: { michael@0: pixman_fixed_t fx = *x_params++; michael@0: int rx = j; michael@0: int ry = i; michael@0: michael@0: if (fx) michael@0: { michael@0: pixman_fixed_t f; michael@0: uint32_t pixel; michael@0: michael@0: if (repeat_mode != PIXMAN_REPEAT_NONE) michael@0: { michael@0: repeat (repeat_mode, &rx, width); michael@0: repeat (repeat_mode, &ry, height); michael@0: michael@0: pixel = get_pixel (image, rx, ry, FALSE); michael@0: } michael@0: else michael@0: { michael@0: pixel = get_pixel (image, rx, ry, TRUE); michael@0: } michael@0: michael@0: f = (fy * fx + 0x8000) >> 16; michael@0: michael@0: srtot += (int)RED_8 (pixel) * f; michael@0: sgtot += (int)GREEN_8 (pixel) * f; michael@0: sbtot += (int)BLUE_8 (pixel) * f; michael@0: satot += (int)ALPHA_8 (pixel) * f; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: satot = (satot + 0x8000) >> 16; michael@0: srtot = (srtot + 0x8000) >> 16; michael@0: sgtot = (sgtot + 0x8000) >> 16; michael@0: sbtot = (sbtot + 0x8000) >> 16; michael@0: michael@0: satot = CLIP (satot, 0, 0xff); michael@0: srtot = CLIP (srtot, 0, 0xff); michael@0: sgtot = CLIP (sgtot, 0, 0xff); michael@0: sbtot = CLIP (sbtot, 0, 0xff); michael@0: michael@0: return ((satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot)); michael@0: } michael@0: michael@0: static force_inline uint32_t michael@0: bits_image_fetch_pixel_filtered (bits_image_t *image, michael@0: pixman_fixed_t x, michael@0: pixman_fixed_t y, michael@0: get_pixel_t get_pixel) michael@0: { michael@0: switch (image->common.filter) michael@0: { michael@0: case PIXMAN_FILTER_NEAREST: michael@0: case PIXMAN_FILTER_FAST: michael@0: return bits_image_fetch_pixel_nearest (image, x, y, get_pixel); michael@0: break; michael@0: michael@0: case PIXMAN_FILTER_BILINEAR: michael@0: case PIXMAN_FILTER_GOOD: michael@0: case PIXMAN_FILTER_BEST: michael@0: return bits_image_fetch_pixel_bilinear (image, x, y, get_pixel); michael@0: break; michael@0: michael@0: case PIXMAN_FILTER_CONVOLUTION: michael@0: return bits_image_fetch_pixel_convolution (image, x, y, get_pixel); michael@0: break; michael@0: michael@0: case PIXMAN_FILTER_SEPARABLE_CONVOLUTION: michael@0: return bits_image_fetch_pixel_separable_convolution (image, x, y, get_pixel); michael@0: break; michael@0: michael@0: default: michael@0: break; michael@0: } michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: static uint32_t * michael@0: bits_image_fetch_affine_no_alpha (pixman_iter_t * iter, michael@0: const uint32_t * mask) michael@0: { michael@0: pixman_image_t *image = iter->image; michael@0: int offset = iter->x; michael@0: int line = iter->y++; michael@0: int width = iter->width; michael@0: uint32_t * buffer = iter->buffer; michael@0: michael@0: pixman_fixed_t x, y; michael@0: pixman_fixed_t ux, uy; michael@0: pixman_vector_t v; michael@0: int i; michael@0: michael@0: /* reference point is the center of the pixel */ michael@0: v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; michael@0: v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; michael@0: v.vector[2] = pixman_fixed_1; michael@0: michael@0: if (image->common.transform) michael@0: { michael@0: if (!pixman_transform_point_3d (image->common.transform, &v)) michael@0: return iter->buffer; michael@0: michael@0: ux = image->common.transform->matrix[0][0]; michael@0: uy = image->common.transform->matrix[1][0]; michael@0: } michael@0: else michael@0: { michael@0: ux = pixman_fixed_1; michael@0: uy = 0; michael@0: } michael@0: michael@0: x = v.vector[0]; michael@0: y = v.vector[1]; michael@0: michael@0: for (i = 0; i < width; ++i) michael@0: { michael@0: if (!mask || mask[i]) michael@0: { michael@0: buffer[i] = bits_image_fetch_pixel_filtered ( michael@0: &image->bits, x, y, fetch_pixel_no_alpha); michael@0: } michael@0: michael@0: x += ux; michael@0: y += uy; michael@0: } michael@0: michael@0: return buffer; michael@0: } michael@0: michael@0: /* General fetcher */ michael@0: static force_inline uint32_t michael@0: fetch_pixel_general (bits_image_t *image, int x, int y, pixman_bool_t check_bounds) michael@0: { michael@0: uint32_t pixel; michael@0: michael@0: if (check_bounds && michael@0: (x < 0 || x >= image->width || y < 0 || y >= image->height)) michael@0: { michael@0: return 0; michael@0: } michael@0: michael@0: pixel = image->fetch_pixel_32 (image, x, y); michael@0: michael@0: if (image->common.alpha_map) michael@0: { michael@0: uint32_t pixel_a; michael@0: michael@0: x -= image->common.alpha_origin_x; michael@0: y -= image->common.alpha_origin_y; michael@0: michael@0: if (x < 0 || x >= image->common.alpha_map->width || michael@0: y < 0 || y >= image->common.alpha_map->height) michael@0: { michael@0: pixel_a = 0; michael@0: } michael@0: else michael@0: { michael@0: pixel_a = image->common.alpha_map->fetch_pixel_32 ( michael@0: image->common.alpha_map, x, y); michael@0: michael@0: pixel_a = ALPHA_8 (pixel_a); michael@0: } michael@0: michael@0: pixel &= 0x00ffffff; michael@0: pixel |= (pixel_a << 24); michael@0: } michael@0: michael@0: return pixel; michael@0: } michael@0: michael@0: static uint32_t * michael@0: bits_image_fetch_general (pixman_iter_t *iter, michael@0: const uint32_t *mask) michael@0: { michael@0: pixman_image_t *image = iter->image; michael@0: int offset = iter->x; michael@0: int line = iter->y++; michael@0: int width = iter->width; michael@0: uint32_t * buffer = iter->buffer; michael@0: michael@0: pixman_fixed_t x, y, w; michael@0: pixman_fixed_t ux, uy, uw; michael@0: pixman_vector_t v; michael@0: int i; michael@0: michael@0: /* reference point is the center of the pixel */ michael@0: v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; michael@0: v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; michael@0: v.vector[2] = pixman_fixed_1; michael@0: michael@0: if (image->common.transform) michael@0: { michael@0: if (!pixman_transform_point_3d (image->common.transform, &v)) michael@0: return buffer; michael@0: michael@0: ux = image->common.transform->matrix[0][0]; michael@0: uy = image->common.transform->matrix[1][0]; michael@0: uw = image->common.transform->matrix[2][0]; michael@0: } michael@0: else michael@0: { michael@0: ux = pixman_fixed_1; michael@0: uy = 0; michael@0: uw = 0; michael@0: } michael@0: michael@0: x = v.vector[0]; michael@0: y = v.vector[1]; michael@0: w = v.vector[2]; michael@0: michael@0: for (i = 0; i < width; ++i) michael@0: { michael@0: pixman_fixed_t x0, y0; michael@0: michael@0: if (!mask || mask[i]) michael@0: { michael@0: if (w != 0) michael@0: { michael@0: x0 = ((pixman_fixed_48_16_t)x << 16) / w; michael@0: y0 = ((pixman_fixed_48_16_t)y << 16) / w; michael@0: } michael@0: else michael@0: { michael@0: x0 = 0; michael@0: y0 = 0; michael@0: } michael@0: michael@0: buffer[i] = bits_image_fetch_pixel_filtered ( michael@0: &image->bits, x0, y0, fetch_pixel_general); michael@0: } michael@0: michael@0: x += ux; michael@0: y += uy; michael@0: w += uw; michael@0: } michael@0: michael@0: return buffer; michael@0: } michael@0: michael@0: typedef uint32_t (* convert_pixel_t) (const uint8_t *row, int x); michael@0: michael@0: static force_inline void michael@0: bits_image_fetch_separable_convolution_affine (pixman_image_t * image, michael@0: int offset, michael@0: int line, michael@0: int width, michael@0: uint32_t * buffer, michael@0: const uint32_t * mask, michael@0: michael@0: convert_pixel_t convert_pixel, michael@0: pixman_format_code_t format, michael@0: pixman_repeat_t repeat_mode) michael@0: { michael@0: bits_image_t *bits = &image->bits; michael@0: pixman_fixed_t *params = image->common.filter_params; michael@0: int cwidth = pixman_fixed_to_int (params[0]); michael@0: int cheight = pixman_fixed_to_int (params[1]); michael@0: int x_off = ((cwidth << 16) - pixman_fixed_1) >> 1; michael@0: int y_off = ((cheight << 16) - pixman_fixed_1) >> 1; michael@0: int x_phase_bits = pixman_fixed_to_int (params[2]); michael@0: int y_phase_bits = pixman_fixed_to_int (params[3]); michael@0: int x_phase_shift = 16 - x_phase_bits; michael@0: int y_phase_shift = 16 - y_phase_bits; michael@0: pixman_fixed_t vx, vy; michael@0: pixman_fixed_t ux, uy; michael@0: pixman_vector_t v; michael@0: int k; michael@0: michael@0: /* reference point is the center of the pixel */ michael@0: v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; michael@0: v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; michael@0: v.vector[2] = pixman_fixed_1; michael@0: michael@0: if (!pixman_transform_point_3d (image->common.transform, &v)) michael@0: return; michael@0: michael@0: ux = image->common.transform->matrix[0][0]; michael@0: uy = image->common.transform->matrix[1][0]; michael@0: michael@0: vx = v.vector[0]; michael@0: vy = v.vector[1]; michael@0: michael@0: for (k = 0; k < width; ++k) michael@0: { michael@0: pixman_fixed_t *y_params; michael@0: int satot, srtot, sgtot, sbtot; michael@0: pixman_fixed_t x, y; michael@0: int32_t x1, x2, y1, y2; michael@0: int32_t px, py; michael@0: int i, j; michael@0: michael@0: if (mask && !mask[k]) michael@0: goto next; michael@0: michael@0: /* Round x and y to the middle of the closest phase before continuing. This michael@0: * ensures that the convolution matrix is aligned right, since it was michael@0: * positioned relative to a particular phase (and not relative to whatever michael@0: * exact fraction we happen to get here). michael@0: */ michael@0: x = ((vx >> x_phase_shift) << x_phase_shift) + ((1 << x_phase_shift) >> 1); michael@0: y = ((vy >> y_phase_shift) << y_phase_shift) + ((1 << y_phase_shift) >> 1); michael@0: michael@0: px = (x & 0xffff) >> x_phase_shift; michael@0: py = (y & 0xffff) >> y_phase_shift; michael@0: michael@0: x1 = pixman_fixed_to_int (x - pixman_fixed_e - x_off); michael@0: y1 = pixman_fixed_to_int (y - pixman_fixed_e - y_off); michael@0: x2 = x1 + cwidth; michael@0: y2 = y1 + cheight; michael@0: michael@0: satot = srtot = sgtot = sbtot = 0; michael@0: michael@0: y_params = params + 4 + (1 << x_phase_bits) * cwidth + py * cheight; michael@0: michael@0: for (i = y1; i < y2; ++i) michael@0: { michael@0: pixman_fixed_t fy = *y_params++; michael@0: michael@0: if (fy) michael@0: { michael@0: pixman_fixed_t *x_params = params + 4 + px * cwidth; michael@0: michael@0: for (j = x1; j < x2; ++j) michael@0: { michael@0: pixman_fixed_t fx = *x_params++; michael@0: int rx = j; michael@0: int ry = i; michael@0: michael@0: if (fx) michael@0: { michael@0: pixman_fixed_t f; michael@0: uint32_t pixel, mask; michael@0: uint8_t *row; michael@0: michael@0: mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; michael@0: michael@0: if (repeat_mode != PIXMAN_REPEAT_NONE) michael@0: { michael@0: repeat (repeat_mode, &rx, bits->width); michael@0: repeat (repeat_mode, &ry, bits->height); michael@0: michael@0: row = (uint8_t *)bits->bits + bits->rowstride * 4 * ry; michael@0: pixel = convert_pixel (row, rx) | mask; michael@0: } michael@0: else michael@0: { michael@0: if (rx < 0 || ry < 0 || rx >= bits->width || ry >= bits->height) michael@0: { michael@0: pixel = 0; michael@0: } michael@0: else michael@0: { michael@0: row = (uint8_t *)bits->bits + bits->rowstride * 4 * ry; michael@0: pixel = convert_pixel (row, rx) | mask; michael@0: } michael@0: } michael@0: michael@0: f = ((pixman_fixed_32_32_t)fx * fy + 0x8000) >> 16; michael@0: srtot += (int)RED_8 (pixel) * f; michael@0: sgtot += (int)GREEN_8 (pixel) * f; michael@0: sbtot += (int)BLUE_8 (pixel) * f; michael@0: satot += (int)ALPHA_8 (pixel) * f; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: satot = (satot + 0x8000) >> 16; michael@0: srtot = (srtot + 0x8000) >> 16; michael@0: sgtot = (sgtot + 0x8000) >> 16; michael@0: sbtot = (sbtot + 0x8000) >> 16; michael@0: michael@0: satot = CLIP (satot, 0, 0xff); michael@0: srtot = CLIP (srtot, 0, 0xff); michael@0: sgtot = CLIP (sgtot, 0, 0xff); michael@0: sbtot = CLIP (sbtot, 0, 0xff); michael@0: michael@0: buffer[k] = (satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot << 0); michael@0: michael@0: next: michael@0: vx += ux; michael@0: vy += uy; michael@0: } michael@0: } michael@0: michael@0: static const uint8_t zero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; michael@0: michael@0: static force_inline void michael@0: bits_image_fetch_bilinear_affine (pixman_image_t * image, michael@0: int offset, michael@0: int line, michael@0: int width, michael@0: uint32_t * buffer, michael@0: const uint32_t * mask, michael@0: michael@0: convert_pixel_t convert_pixel, michael@0: pixman_format_code_t format, michael@0: pixman_repeat_t repeat_mode) michael@0: { michael@0: pixman_fixed_t x, y; michael@0: pixman_fixed_t ux, uy; michael@0: pixman_vector_t v; michael@0: bits_image_t *bits = &image->bits; michael@0: int i; michael@0: michael@0: /* reference point is the center of the pixel */ michael@0: v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; michael@0: v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; michael@0: v.vector[2] = pixman_fixed_1; michael@0: michael@0: if (!pixman_transform_point_3d (image->common.transform, &v)) michael@0: return; michael@0: michael@0: ux = image->common.transform->matrix[0][0]; michael@0: uy = image->common.transform->matrix[1][0]; michael@0: michael@0: x = v.vector[0]; michael@0: y = v.vector[1]; michael@0: michael@0: for (i = 0; i < width; ++i) michael@0: { michael@0: int x1, y1, x2, y2; michael@0: uint32_t tl, tr, bl, br; michael@0: int32_t distx, disty; michael@0: int width = image->bits.width; michael@0: int height = image->bits.height; michael@0: const uint8_t *row1; michael@0: const uint8_t *row2; michael@0: michael@0: if (mask && !mask[i]) michael@0: goto next; michael@0: michael@0: x1 = x - pixman_fixed_1 / 2; michael@0: y1 = y - pixman_fixed_1 / 2; michael@0: michael@0: distx = pixman_fixed_to_bilinear_weight (x1); michael@0: disty = pixman_fixed_to_bilinear_weight (y1); michael@0: michael@0: y1 = pixman_fixed_to_int (y1); michael@0: y2 = y1 + 1; michael@0: x1 = pixman_fixed_to_int (x1); michael@0: x2 = x1 + 1; michael@0: michael@0: if (repeat_mode != PIXMAN_REPEAT_NONE) michael@0: { michael@0: uint32_t mask; michael@0: michael@0: mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; michael@0: michael@0: repeat (repeat_mode, &x1, width); michael@0: repeat (repeat_mode, &y1, height); michael@0: repeat (repeat_mode, &x2, width); michael@0: repeat (repeat_mode, &y2, height); michael@0: michael@0: row1 = (uint8_t *)bits->bits + bits->rowstride * 4 * y1; michael@0: row2 = (uint8_t *)bits->bits + bits->rowstride * 4 * y2; michael@0: michael@0: tl = convert_pixel (row1, x1) | mask; michael@0: tr = convert_pixel (row1, x2) | mask; michael@0: bl = convert_pixel (row2, x1) | mask; michael@0: br = convert_pixel (row2, x2) | mask; michael@0: } michael@0: else michael@0: { michael@0: uint32_t mask1, mask2; michael@0: int bpp; michael@0: michael@0: /* Note: PIXMAN_FORMAT_BPP() returns an unsigned value, michael@0: * which means if you use it in expressions, those michael@0: * expressions become unsigned themselves. Since michael@0: * the variables below can be negative in some cases, michael@0: * that will lead to crashes on 64 bit architectures. michael@0: * michael@0: * So this line makes sure bpp is signed michael@0: */ michael@0: bpp = PIXMAN_FORMAT_BPP (format); michael@0: michael@0: if (x1 >= width || x2 < 0 || y1 >= height || y2 < 0) michael@0: { michael@0: buffer[i] = 0; michael@0: goto next; michael@0: } michael@0: michael@0: if (y2 == 0) michael@0: { michael@0: row1 = zero; michael@0: mask1 = 0; michael@0: } michael@0: else michael@0: { michael@0: row1 = (uint8_t *)bits->bits + bits->rowstride * 4 * y1; michael@0: row1 += bpp / 8 * x1; michael@0: michael@0: mask1 = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; michael@0: } michael@0: michael@0: if (y1 == height - 1) michael@0: { michael@0: row2 = zero; michael@0: mask2 = 0; michael@0: } michael@0: else michael@0: { michael@0: row2 = (uint8_t *)bits->bits + bits->rowstride * 4 * y2; michael@0: row2 += bpp / 8 * x1; michael@0: michael@0: mask2 = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; michael@0: } michael@0: michael@0: if (x2 == 0) michael@0: { michael@0: tl = 0; michael@0: bl = 0; michael@0: } michael@0: else michael@0: { michael@0: tl = convert_pixel (row1, 0) | mask1; michael@0: bl = convert_pixel (row2, 0) | mask2; michael@0: } michael@0: michael@0: if (x1 == width - 1) michael@0: { michael@0: tr = 0; michael@0: br = 0; michael@0: } michael@0: else michael@0: { michael@0: tr = convert_pixel (row1, 1) | mask1; michael@0: br = convert_pixel (row2, 1) | mask2; michael@0: } michael@0: } michael@0: michael@0: buffer[i] = bilinear_interpolation ( michael@0: tl, tr, bl, br, distx, disty); michael@0: michael@0: next: michael@0: x += ux; michael@0: y += uy; michael@0: } michael@0: } michael@0: michael@0: static force_inline void michael@0: bits_image_fetch_nearest_affine (pixman_image_t * image, michael@0: int offset, michael@0: int line, michael@0: int width, michael@0: uint32_t * buffer, michael@0: const uint32_t * mask, michael@0: michael@0: convert_pixel_t convert_pixel, michael@0: pixman_format_code_t format, michael@0: pixman_repeat_t repeat_mode) michael@0: { michael@0: pixman_fixed_t x, y; michael@0: pixman_fixed_t ux, uy; michael@0: pixman_vector_t v; michael@0: bits_image_t *bits = &image->bits; michael@0: int i; michael@0: michael@0: /* reference point is the center of the pixel */ michael@0: v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; michael@0: v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; michael@0: v.vector[2] = pixman_fixed_1; michael@0: michael@0: if (!pixman_transform_point_3d (image->common.transform, &v)) michael@0: return; michael@0: michael@0: ux = image->common.transform->matrix[0][0]; michael@0: uy = image->common.transform->matrix[1][0]; michael@0: michael@0: x = v.vector[0]; michael@0: y = v.vector[1]; michael@0: michael@0: for (i = 0; i < width; ++i) michael@0: { michael@0: int width, height, x0, y0; michael@0: const uint8_t *row; michael@0: michael@0: if (mask && !mask[i]) michael@0: goto next; michael@0: michael@0: width = image->bits.width; michael@0: height = image->bits.height; michael@0: x0 = pixman_fixed_to_int (x - pixman_fixed_e); michael@0: y0 = pixman_fixed_to_int (y - pixman_fixed_e); michael@0: michael@0: if (repeat_mode == PIXMAN_REPEAT_NONE && michael@0: (y0 < 0 || y0 >= height || x0 < 0 || x0 >= width)) michael@0: { michael@0: buffer[i] = 0; michael@0: } michael@0: else michael@0: { michael@0: uint32_t mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; michael@0: michael@0: if (repeat_mode != PIXMAN_REPEAT_NONE) michael@0: { michael@0: repeat (repeat_mode, &x0, width); michael@0: repeat (repeat_mode, &y0, height); michael@0: } michael@0: michael@0: row = (uint8_t *)bits->bits + bits->rowstride * 4 * y0; michael@0: michael@0: buffer[i] = convert_pixel (row, x0) | mask; michael@0: } michael@0: michael@0: next: michael@0: x += ux; michael@0: y += uy; michael@0: } michael@0: } michael@0: michael@0: static force_inline uint32_t michael@0: convert_a8r8g8b8 (const uint8_t *row, int x) michael@0: { michael@0: return *(((uint32_t *)row) + x); michael@0: } michael@0: michael@0: static force_inline uint32_t michael@0: convert_x8r8g8b8 (const uint8_t *row, int x) michael@0: { michael@0: return *(((uint32_t *)row) + x); michael@0: } michael@0: michael@0: static force_inline uint32_t michael@0: convert_a8 (const uint8_t *row, int x) michael@0: { michael@0: return *(row + x) << 24; michael@0: } michael@0: michael@0: static force_inline uint32_t michael@0: convert_r5g6b5 (const uint8_t *row, int x) michael@0: { michael@0: return convert_0565_to_0888 (*((uint16_t *)row + x)); michael@0: } michael@0: michael@0: #define MAKE_SEPARABLE_CONVOLUTION_FETCHER(name, format, repeat_mode) \ michael@0: static uint32_t * \ michael@0: bits_image_fetch_separable_convolution_affine_ ## name (pixman_iter_t *iter, \ michael@0: const uint32_t * mask) \ michael@0: { \ michael@0: bits_image_fetch_separable_convolution_affine ( \ michael@0: iter->image, \ michael@0: iter->x, iter->y++, \ michael@0: iter->width, \ michael@0: iter->buffer, mask, \ michael@0: convert_ ## format, \ michael@0: PIXMAN_ ## format, \ michael@0: repeat_mode); \ michael@0: \ michael@0: return iter->buffer; \ michael@0: } michael@0: michael@0: #define MAKE_BILINEAR_FETCHER(name, format, repeat_mode) \ michael@0: static uint32_t * \ michael@0: bits_image_fetch_bilinear_affine_ ## name (pixman_iter_t *iter, \ michael@0: const uint32_t * mask) \ michael@0: { \ michael@0: bits_image_fetch_bilinear_affine (iter->image, \ michael@0: iter->x, iter->y++, \ michael@0: iter->width, \ michael@0: iter->buffer, mask, \ michael@0: convert_ ## format, \ michael@0: PIXMAN_ ## format, \ michael@0: repeat_mode); \ michael@0: return iter->buffer; \ michael@0: } michael@0: michael@0: #define MAKE_NEAREST_FETCHER(name, format, repeat_mode) \ michael@0: static uint32_t * \ michael@0: bits_image_fetch_nearest_affine_ ## name (pixman_iter_t *iter, \ michael@0: const uint32_t * mask) \ michael@0: { \ michael@0: bits_image_fetch_nearest_affine (iter->image, \ michael@0: iter->x, iter->y++, \ michael@0: iter->width, \ michael@0: iter->buffer, mask, \ michael@0: convert_ ## format, \ michael@0: PIXMAN_ ## format, \ michael@0: repeat_mode); \ michael@0: return iter->buffer; \ michael@0: } michael@0: michael@0: #define MAKE_FETCHERS(name, format, repeat_mode) \ michael@0: MAKE_NEAREST_FETCHER (name, format, repeat_mode) \ michael@0: MAKE_BILINEAR_FETCHER (name, format, repeat_mode) \ michael@0: MAKE_SEPARABLE_CONVOLUTION_FETCHER (name, format, repeat_mode) michael@0: michael@0: MAKE_FETCHERS (pad_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_PAD) michael@0: MAKE_FETCHERS (none_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_NONE) michael@0: MAKE_FETCHERS (reflect_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_REFLECT) michael@0: MAKE_FETCHERS (normal_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_NORMAL) michael@0: MAKE_FETCHERS (pad_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_PAD) michael@0: MAKE_FETCHERS (none_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_NONE) michael@0: MAKE_FETCHERS (reflect_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_REFLECT) michael@0: MAKE_FETCHERS (normal_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_NORMAL) michael@0: MAKE_FETCHERS (pad_a8, a8, PIXMAN_REPEAT_PAD) michael@0: MAKE_FETCHERS (none_a8, a8, PIXMAN_REPEAT_NONE) michael@0: MAKE_FETCHERS (reflect_a8, a8, PIXMAN_REPEAT_REFLECT) michael@0: MAKE_FETCHERS (normal_a8, a8, PIXMAN_REPEAT_NORMAL) michael@0: MAKE_FETCHERS (pad_r5g6b5, r5g6b5, PIXMAN_REPEAT_PAD) michael@0: MAKE_FETCHERS (none_r5g6b5, r5g6b5, PIXMAN_REPEAT_NONE) michael@0: MAKE_FETCHERS (reflect_r5g6b5, r5g6b5, PIXMAN_REPEAT_REFLECT) michael@0: MAKE_FETCHERS (normal_r5g6b5, r5g6b5, PIXMAN_REPEAT_NORMAL) michael@0: michael@0: static void michael@0: replicate_pixel_32 (bits_image_t * bits, michael@0: int x, michael@0: int y, michael@0: int width, michael@0: uint32_t * buffer) michael@0: { michael@0: uint32_t color; michael@0: uint32_t *end; michael@0: michael@0: color = bits->fetch_pixel_32 (bits, x, y); michael@0: michael@0: end = buffer + width; michael@0: while (buffer < end) michael@0: *(buffer++) = color; michael@0: } michael@0: michael@0: static void michael@0: replicate_pixel_float (bits_image_t * bits, michael@0: int x, michael@0: int y, michael@0: int width, michael@0: uint32_t * b) michael@0: { michael@0: argb_t color; michael@0: argb_t *buffer = (argb_t *)b; michael@0: argb_t *end; michael@0: michael@0: color = bits->fetch_pixel_float (bits, x, y); michael@0: michael@0: end = buffer + width; michael@0: while (buffer < end) michael@0: *(buffer++) = color; michael@0: } michael@0: michael@0: static void michael@0: bits_image_fetch_untransformed_repeat_none (bits_image_t *image, michael@0: pixman_bool_t wide, michael@0: int x, michael@0: int y, michael@0: int width, michael@0: uint32_t * buffer) michael@0: { michael@0: uint32_t w; michael@0: michael@0: if (y < 0 || y >= image->height) michael@0: { michael@0: memset (buffer, 0, width * (wide? sizeof (argb_t) : 4)); michael@0: return; michael@0: } michael@0: michael@0: if (x < 0) michael@0: { michael@0: w = MIN (width, -x); michael@0: michael@0: memset (buffer, 0, w * (wide ? sizeof (argb_t) : 4)); michael@0: michael@0: width -= w; michael@0: buffer += w * (wide? 4 : 1); michael@0: x += w; michael@0: } michael@0: michael@0: if (x < image->width) michael@0: { michael@0: w = MIN (width, image->width - x); michael@0: michael@0: if (wide) michael@0: image->fetch_scanline_float ((pixman_image_t *)image, x, y, w, buffer, NULL); michael@0: else michael@0: image->fetch_scanline_32 ((pixman_image_t *)image, x, y, w, buffer, NULL); michael@0: michael@0: width -= w; michael@0: buffer += w * (wide? 4 : 1); michael@0: x += w; michael@0: } michael@0: michael@0: memset (buffer, 0, width * (wide ? sizeof (argb_t) : 4)); michael@0: } michael@0: michael@0: static void michael@0: bits_image_fetch_untransformed_repeat_normal (bits_image_t *image, michael@0: pixman_bool_t wide, michael@0: int x, michael@0: int y, michael@0: int width, michael@0: uint32_t * buffer) michael@0: { michael@0: uint32_t w; michael@0: michael@0: while (y < 0) michael@0: y += image->height; michael@0: michael@0: while (y >= image->height) michael@0: y -= image->height; michael@0: michael@0: if (image->width == 1) michael@0: { michael@0: if (wide) michael@0: replicate_pixel_float (image, 0, y, width, buffer); michael@0: else michael@0: replicate_pixel_32 (image, 0, y, width, buffer); michael@0: michael@0: return; michael@0: } michael@0: michael@0: while (width) michael@0: { michael@0: while (x < 0) michael@0: x += image->width; michael@0: while (x >= image->width) michael@0: x -= image->width; michael@0: michael@0: w = MIN (width, image->width - x); michael@0: michael@0: if (wide) michael@0: image->fetch_scanline_float ((pixman_image_t *)image, x, y, w, buffer, NULL); michael@0: else michael@0: image->fetch_scanline_32 ((pixman_image_t *)image, x, y, w, buffer, NULL); michael@0: michael@0: buffer += w * (wide? 4 : 1); michael@0: x += w; michael@0: width -= w; michael@0: } michael@0: } michael@0: michael@0: static uint32_t * michael@0: bits_image_fetch_untransformed_32 (pixman_iter_t * iter, michael@0: const uint32_t *mask) michael@0: { michael@0: pixman_image_t *image = iter->image; michael@0: int x = iter->x; michael@0: int y = iter->y; michael@0: int width = iter->width; michael@0: uint32_t * buffer = iter->buffer; michael@0: michael@0: if (image->common.repeat == PIXMAN_REPEAT_NONE) michael@0: { michael@0: bits_image_fetch_untransformed_repeat_none ( michael@0: &image->bits, FALSE, x, y, width, buffer); michael@0: } michael@0: else michael@0: { michael@0: bits_image_fetch_untransformed_repeat_normal ( michael@0: &image->bits, FALSE, x, y, width, buffer); michael@0: } michael@0: michael@0: iter->y++; michael@0: return buffer; michael@0: } michael@0: michael@0: static uint32_t * michael@0: bits_image_fetch_untransformed_float (pixman_iter_t * iter, michael@0: const uint32_t *mask) michael@0: { michael@0: pixman_image_t *image = iter->image; michael@0: int x = iter->x; michael@0: int y = iter->y; michael@0: int width = iter->width; michael@0: uint32_t * buffer = iter->buffer; michael@0: michael@0: if (image->common.repeat == PIXMAN_REPEAT_NONE) michael@0: { michael@0: bits_image_fetch_untransformed_repeat_none ( michael@0: &image->bits, TRUE, x, y, width, buffer); michael@0: } michael@0: else michael@0: { michael@0: bits_image_fetch_untransformed_repeat_normal ( michael@0: &image->bits, TRUE, x, y, width, buffer); michael@0: } michael@0: michael@0: iter->y++; michael@0: return buffer; michael@0: } michael@0: michael@0: typedef struct michael@0: { michael@0: pixman_format_code_t format; michael@0: uint32_t flags; michael@0: pixman_iter_get_scanline_t get_scanline_32; michael@0: pixman_iter_get_scanline_t get_scanline_float; michael@0: } fetcher_info_t; michael@0: michael@0: static const fetcher_info_t fetcher_info[] = michael@0: { michael@0: { PIXMAN_any, michael@0: (FAST_PATH_NO_ALPHA_MAP | michael@0: FAST_PATH_ID_TRANSFORM | michael@0: FAST_PATH_NO_CONVOLUTION_FILTER | michael@0: FAST_PATH_NO_PAD_REPEAT | michael@0: FAST_PATH_NO_REFLECT_REPEAT), michael@0: bits_image_fetch_untransformed_32, michael@0: bits_image_fetch_untransformed_float michael@0: }, michael@0: michael@0: #define FAST_BILINEAR_FLAGS \ michael@0: (FAST_PATH_NO_ALPHA_MAP | \ michael@0: FAST_PATH_NO_ACCESSORS | \ michael@0: FAST_PATH_HAS_TRANSFORM | \ michael@0: FAST_PATH_AFFINE_TRANSFORM | \ michael@0: FAST_PATH_X_UNIT_POSITIVE | \ michael@0: FAST_PATH_Y_UNIT_ZERO | \ michael@0: FAST_PATH_NONE_REPEAT | \ michael@0: FAST_PATH_BILINEAR_FILTER) michael@0: michael@0: { PIXMAN_a8r8g8b8, michael@0: FAST_BILINEAR_FLAGS, michael@0: bits_image_fetch_bilinear_no_repeat_8888, michael@0: _pixman_image_get_scanline_generic_float michael@0: }, michael@0: michael@0: { PIXMAN_x8r8g8b8, michael@0: FAST_BILINEAR_FLAGS, michael@0: bits_image_fetch_bilinear_no_repeat_8888, michael@0: _pixman_image_get_scanline_generic_float michael@0: }, michael@0: michael@0: #define GENERAL_BILINEAR_FLAGS \ michael@0: (FAST_PATH_NO_ALPHA_MAP | \ michael@0: FAST_PATH_NO_ACCESSORS | \ michael@0: FAST_PATH_HAS_TRANSFORM | \ michael@0: FAST_PATH_AFFINE_TRANSFORM | \ michael@0: FAST_PATH_BILINEAR_FILTER) michael@0: michael@0: #define GENERAL_NEAREST_FLAGS \ michael@0: (FAST_PATH_NO_ALPHA_MAP | \ michael@0: FAST_PATH_NO_ACCESSORS | \ michael@0: FAST_PATH_HAS_TRANSFORM | \ michael@0: FAST_PATH_AFFINE_TRANSFORM | \ michael@0: FAST_PATH_NEAREST_FILTER) michael@0: michael@0: #define GENERAL_SEPARABLE_CONVOLUTION_FLAGS \ michael@0: (FAST_PATH_NO_ALPHA_MAP | \ michael@0: FAST_PATH_NO_ACCESSORS | \ michael@0: FAST_PATH_HAS_TRANSFORM | \ michael@0: FAST_PATH_AFFINE_TRANSFORM | \ michael@0: FAST_PATH_SEPARABLE_CONVOLUTION_FILTER) michael@0: michael@0: #define SEPARABLE_CONVOLUTION_AFFINE_FAST_PATH(name, format, repeat) \ michael@0: { PIXMAN_ ## format, \ michael@0: GENERAL_SEPARABLE_CONVOLUTION_FLAGS | FAST_PATH_ ## repeat ## _REPEAT, \ michael@0: bits_image_fetch_separable_convolution_affine_ ## name, \ michael@0: _pixman_image_get_scanline_generic_float \ michael@0: }, michael@0: michael@0: #define BILINEAR_AFFINE_FAST_PATH(name, format, repeat) \ michael@0: { PIXMAN_ ## format, \ michael@0: GENERAL_BILINEAR_FLAGS | FAST_PATH_ ## repeat ## _REPEAT, \ michael@0: bits_image_fetch_bilinear_affine_ ## name, \ michael@0: _pixman_image_get_scanline_generic_float \ michael@0: }, michael@0: michael@0: #define NEAREST_AFFINE_FAST_PATH(name, format, repeat) \ michael@0: { PIXMAN_ ## format, \ michael@0: GENERAL_NEAREST_FLAGS | FAST_PATH_ ## repeat ## _REPEAT, \ michael@0: bits_image_fetch_nearest_affine_ ## name, \ michael@0: _pixman_image_get_scanline_generic_float \ michael@0: }, michael@0: michael@0: #define AFFINE_FAST_PATHS(name, format, repeat) \ michael@0: SEPARABLE_CONVOLUTION_AFFINE_FAST_PATH(name, format, repeat) \ michael@0: BILINEAR_AFFINE_FAST_PATH(name, format, repeat) \ michael@0: NEAREST_AFFINE_FAST_PATH(name, format, repeat) michael@0: michael@0: AFFINE_FAST_PATHS (pad_a8r8g8b8, a8r8g8b8, PAD) michael@0: AFFINE_FAST_PATHS (none_a8r8g8b8, a8r8g8b8, NONE) michael@0: AFFINE_FAST_PATHS (reflect_a8r8g8b8, a8r8g8b8, REFLECT) michael@0: AFFINE_FAST_PATHS (normal_a8r8g8b8, a8r8g8b8, NORMAL) michael@0: AFFINE_FAST_PATHS (pad_x8r8g8b8, x8r8g8b8, PAD) michael@0: AFFINE_FAST_PATHS (none_x8r8g8b8, x8r8g8b8, NONE) michael@0: AFFINE_FAST_PATHS (reflect_x8r8g8b8, x8r8g8b8, REFLECT) michael@0: AFFINE_FAST_PATHS (normal_x8r8g8b8, x8r8g8b8, NORMAL) michael@0: AFFINE_FAST_PATHS (pad_a8, a8, PAD) michael@0: AFFINE_FAST_PATHS (none_a8, a8, NONE) michael@0: AFFINE_FAST_PATHS (reflect_a8, a8, REFLECT) michael@0: AFFINE_FAST_PATHS (normal_a8, a8, NORMAL) michael@0: AFFINE_FAST_PATHS (pad_r5g6b5, r5g6b5, PAD) michael@0: AFFINE_FAST_PATHS (none_r5g6b5, r5g6b5, NONE) michael@0: AFFINE_FAST_PATHS (reflect_r5g6b5, r5g6b5, REFLECT) michael@0: AFFINE_FAST_PATHS (normal_r5g6b5, r5g6b5, NORMAL) michael@0: michael@0: /* Affine, no alpha */ michael@0: { PIXMAN_any, michael@0: (FAST_PATH_NO_ALPHA_MAP | FAST_PATH_HAS_TRANSFORM | FAST_PATH_AFFINE_TRANSFORM), michael@0: bits_image_fetch_affine_no_alpha, michael@0: _pixman_image_get_scanline_generic_float michael@0: }, michael@0: michael@0: /* General */ michael@0: { PIXMAN_any, michael@0: 0, michael@0: bits_image_fetch_general, michael@0: _pixman_image_get_scanline_generic_float michael@0: }, michael@0: michael@0: { PIXMAN_null }, michael@0: }; michael@0: michael@0: static void michael@0: bits_image_property_changed (pixman_image_t *image) michael@0: { michael@0: _pixman_bits_image_setup_accessors (&image->bits); michael@0: } michael@0: michael@0: void michael@0: _pixman_bits_image_src_iter_init (pixman_image_t *image, pixman_iter_t *iter) michael@0: { michael@0: pixman_format_code_t format = image->common.extended_format_code; michael@0: uint32_t flags = image->common.flags; michael@0: const fetcher_info_t *info; michael@0: michael@0: for (info = fetcher_info; info->format != PIXMAN_null; ++info) michael@0: { michael@0: if ((info->format == format || info->format == PIXMAN_any) && michael@0: (info->flags & flags) == info->flags) michael@0: { michael@0: if (iter->iter_flags & ITER_NARROW) michael@0: { michael@0: iter->get_scanline = info->get_scanline_32; michael@0: } michael@0: else michael@0: { michael@0: iter->data = info->get_scanline_32; michael@0: iter->get_scanline = info->get_scanline_float; michael@0: } michael@0: return; michael@0: } michael@0: } michael@0: michael@0: /* Just in case we somehow didn't find a scanline function */ michael@0: iter->get_scanline = _pixman_iter_get_scanline_noop; michael@0: } michael@0: michael@0: static uint32_t * michael@0: dest_get_scanline_16 (pixman_iter_t *iter, const uint32_t *mask) michael@0: { michael@0: pixman_image_t *image = iter->image; michael@0: int x = iter->x; michael@0: int y = iter->y; michael@0: int width = iter->width; michael@0: uint32_t * buffer = iter->buffer; michael@0: michael@0: image->bits.fetch_scanline_16 (image, x, y, width, buffer, mask); michael@0: michael@0: return iter->buffer; michael@0: } michael@0: michael@0: static uint32_t * michael@0: dest_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) michael@0: { michael@0: pixman_image_t *image = iter->image; michael@0: int x = iter->x; michael@0: int y = iter->y; michael@0: int width = iter->width; michael@0: uint32_t * buffer = iter->buffer; michael@0: michael@0: image->bits.fetch_scanline_32 (image, x, y, width, buffer, mask); michael@0: if (image->common.alpha_map) michael@0: { michael@0: uint32_t *alpha; michael@0: michael@0: if ((alpha = malloc (width * sizeof (uint32_t)))) michael@0: { michael@0: int i; michael@0: michael@0: x -= image->common.alpha_origin_x; michael@0: y -= image->common.alpha_origin_y; michael@0: michael@0: image->common.alpha_map->fetch_scanline_32 ( michael@0: (pixman_image_t *)image->common.alpha_map, michael@0: x, y, width, alpha, mask); michael@0: michael@0: for (i = 0; i < width; ++i) michael@0: { michael@0: buffer[i] &= ~0xff000000; michael@0: buffer[i] |= (alpha[i] & 0xff000000); michael@0: } michael@0: michael@0: free (alpha); michael@0: } michael@0: } michael@0: michael@0: return iter->buffer; michael@0: } michael@0: michael@0: static uint32_t * michael@0: dest_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) michael@0: { michael@0: bits_image_t * image = &iter->image->bits; michael@0: int x = iter->x; michael@0: int y = iter->y; michael@0: int width = iter->width; michael@0: argb_t * buffer = (argb_t *)iter->buffer; michael@0: michael@0: image->fetch_scanline_float ( michael@0: (pixman_image_t *)image, x, y, width, (uint32_t *)buffer, mask); michael@0: if (image->common.alpha_map) michael@0: { michael@0: argb_t *alpha; michael@0: michael@0: if ((alpha = malloc (width * sizeof (argb_t)))) michael@0: { michael@0: int i; michael@0: michael@0: x -= image->common.alpha_origin_x; michael@0: y -= image->common.alpha_origin_y; michael@0: michael@0: image->common.alpha_map->fetch_scanline_float ( michael@0: (pixman_image_t *)image->common.alpha_map, michael@0: x, y, width, (uint32_t *)alpha, mask); michael@0: michael@0: for (i = 0; i < width; ++i) michael@0: buffer[i].a = alpha[i].a; michael@0: michael@0: free (alpha); michael@0: } michael@0: } michael@0: michael@0: return iter->buffer; michael@0: } michael@0: michael@0: static void michael@0: dest_write_back_16 (pixman_iter_t *iter) michael@0: { michael@0: bits_image_t * image = &iter->image->bits; michael@0: int x = iter->x; michael@0: int y = iter->y; michael@0: int width = iter->width; michael@0: const uint32_t *buffer = iter->buffer; michael@0: michael@0: image->store_scanline_16 (image, x, y, width, buffer); michael@0: michael@0: iter->y++; michael@0: } michael@0: michael@0: static void michael@0: dest_write_back_narrow (pixman_iter_t *iter) michael@0: { michael@0: bits_image_t * image = &iter->image->bits; michael@0: int x = iter->x; michael@0: int y = iter->y; michael@0: int width = iter->width; michael@0: const uint32_t *buffer = iter->buffer; michael@0: michael@0: image->store_scanline_32 (image, x, y, width, buffer); michael@0: michael@0: if (image->common.alpha_map) michael@0: { michael@0: x -= image->common.alpha_origin_x; michael@0: y -= image->common.alpha_origin_y; michael@0: michael@0: image->common.alpha_map->store_scanline_32 ( michael@0: image->common.alpha_map, x, y, width, buffer); michael@0: } michael@0: michael@0: iter->y++; michael@0: } michael@0: michael@0: static void michael@0: dest_write_back_wide (pixman_iter_t *iter) michael@0: { michael@0: bits_image_t * image = &iter->image->bits; michael@0: int x = iter->x; michael@0: int y = iter->y; michael@0: int width = iter->width; michael@0: const uint32_t *buffer = iter->buffer; michael@0: michael@0: image->store_scanline_float (image, x, y, width, buffer); michael@0: michael@0: if (image->common.alpha_map) michael@0: { michael@0: x -= image->common.alpha_origin_x; michael@0: y -= image->common.alpha_origin_y; michael@0: michael@0: image->common.alpha_map->store_scanline_float ( michael@0: image->common.alpha_map, x, y, width, buffer); michael@0: } michael@0: michael@0: iter->y++; michael@0: } michael@0: michael@0: void michael@0: _pixman_bits_image_dest_iter_init (pixman_image_t *image, pixman_iter_t *iter) michael@0: { michael@0: if (iter->iter_flags & ITER_16) michael@0: { michael@0: if ((iter->iter_flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) == michael@0: (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) michael@0: { michael@0: iter->get_scanline = _pixman_iter_get_scanline_noop; michael@0: } michael@0: else michael@0: { michael@0: iter->get_scanline = dest_get_scanline_16; michael@0: } michael@0: iter->write_back = dest_write_back_16; michael@0: } michael@0: else if (iter->iter_flags & ITER_NARROW) michael@0: { michael@0: if ((iter->iter_flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) == michael@0: (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) michael@0: { michael@0: iter->get_scanline = _pixman_iter_get_scanline_noop; michael@0: } michael@0: else michael@0: { michael@0: iter->get_scanline = dest_get_scanline_narrow; michael@0: } michael@0: michael@0: iter->write_back = dest_write_back_narrow; michael@0: } michael@0: else michael@0: { michael@0: iter->get_scanline = dest_get_scanline_wide; michael@0: iter->write_back = dest_write_back_wide; michael@0: } michael@0: } michael@0: michael@0: static uint32_t * michael@0: create_bits (pixman_format_code_t format, michael@0: int width, michael@0: int height, michael@0: int * rowstride_bytes, michael@0: pixman_bool_t clear) michael@0: { michael@0: int stride; michael@0: size_t buf_size; michael@0: int bpp; michael@0: michael@0: /* what follows is a long-winded way, avoiding any possibility of integer michael@0: * overflows, of saying: michael@0: * stride = ((width * bpp + 0x1f) >> 5) * sizeof (uint32_t); michael@0: */ michael@0: michael@0: bpp = PIXMAN_FORMAT_BPP (format); michael@0: if (_pixman_multiply_overflows_int (width, bpp)) michael@0: return NULL; michael@0: michael@0: stride = width * bpp; michael@0: if (_pixman_addition_overflows_int (stride, 0x1f)) michael@0: return NULL; michael@0: michael@0: stride += 0x1f; michael@0: stride >>= 5; michael@0: michael@0: stride *= sizeof (uint32_t); michael@0: michael@0: if (_pixman_multiply_overflows_size (height, stride)) michael@0: return NULL; michael@0: michael@0: buf_size = height * stride; michael@0: michael@0: if (rowstride_bytes) michael@0: *rowstride_bytes = stride; michael@0: michael@0: if (clear) michael@0: return calloc (buf_size, 1); michael@0: else michael@0: return malloc (buf_size); michael@0: } michael@0: michael@0: pixman_bool_t michael@0: _pixman_bits_image_init (pixman_image_t * image, michael@0: pixman_format_code_t format, michael@0: int width, michael@0: int height, michael@0: uint32_t * bits, michael@0: int rowstride, michael@0: pixman_bool_t clear) michael@0: { michael@0: uint32_t *free_me = NULL; michael@0: michael@0: if (!bits && width && height) michael@0: { michael@0: int rowstride_bytes; michael@0: michael@0: free_me = bits = create_bits (format, width, height, &rowstride_bytes, clear); michael@0: michael@0: if (!bits) michael@0: return FALSE; michael@0: michael@0: rowstride = rowstride_bytes / (int) sizeof (uint32_t); michael@0: } michael@0: michael@0: _pixman_image_init (image); michael@0: michael@0: image->type = BITS; michael@0: image->bits.format = format; michael@0: image->bits.width = width; michael@0: image->bits.height = height; michael@0: image->bits.bits = bits; michael@0: image->bits.free_me = free_me; michael@0: image->bits.read_func = NULL; michael@0: image->bits.write_func = NULL; michael@0: image->bits.rowstride = rowstride; michael@0: image->bits.indexed = NULL; michael@0: michael@0: image->common.property_changed = bits_image_property_changed; michael@0: michael@0: _pixman_image_reset_clip_region (image); michael@0: michael@0: return TRUE; michael@0: } michael@0: michael@0: static pixman_image_t * michael@0: create_bits_image_internal (pixman_format_code_t format, michael@0: int width, michael@0: int height, michael@0: uint32_t * bits, michael@0: int rowstride_bytes, michael@0: pixman_bool_t clear) michael@0: { michael@0: pixman_image_t *image; michael@0: michael@0: /* must be a whole number of uint32_t's michael@0: */ michael@0: return_val_if_fail ( michael@0: bits == NULL || (rowstride_bytes % sizeof (uint32_t)) == 0, NULL); michael@0: michael@0: return_val_if_fail (PIXMAN_FORMAT_BPP (format) >= PIXMAN_FORMAT_DEPTH (format), NULL); michael@0: michael@0: image = _pixman_image_allocate (); michael@0: michael@0: if (!image) michael@0: return NULL; michael@0: michael@0: if (!_pixman_bits_image_init (image, format, width, height, bits, michael@0: rowstride_bytes / (int) sizeof (uint32_t), michael@0: clear)) michael@0: { michael@0: free (image); michael@0: return NULL; michael@0: } michael@0: michael@0: return image; michael@0: } michael@0: michael@0: /* If bits is NULL, a buffer will be allocated and initialized to 0 */ michael@0: PIXMAN_EXPORT pixman_image_t * michael@0: pixman_image_create_bits (pixman_format_code_t format, michael@0: int width, michael@0: int height, michael@0: uint32_t * bits, michael@0: int rowstride_bytes) michael@0: { michael@0: return create_bits_image_internal ( michael@0: format, width, height, bits, rowstride_bytes, TRUE); michael@0: } michael@0: michael@0: michael@0: /* If bits is NULL, a buffer will be allocated and _not_ initialized */ michael@0: PIXMAN_EXPORT pixman_image_t * michael@0: pixman_image_create_bits_no_clear (pixman_format_code_t format, michael@0: int width, michael@0: int height, michael@0: uint32_t * bits, michael@0: int rowstride_bytes) michael@0: { michael@0: return create_bits_image_internal ( michael@0: format, width, height, bits, rowstride_bytes, FALSE); michael@0: }