void PixmanBitmap::FlipBlit(int x, int y, Bitmap* _src, Rect src_rect, bool horizontal, bool vertical) { if (!horizontal && !vertical) { Blit(x, y, _src, src_rect, 255); return; } PixmanBitmap* src = (PixmanBitmap*) _src; pixman_transform_t xform; pixman_transform_init_scale(&xform, pixman_int_to_fixed(horizontal ? -1 : 1), pixman_int_to_fixed(vertical ? -1 : 1)); pixman_transform_translate((pixman_transform_t*) NULL, &xform, pixman_int_to_fixed(horizontal ? src_rect.width : 0), pixman_int_to_fixed(vertical ? src_rect.height : 0)); pixman_image_set_transform(bitmap, &xform); pixman_image_composite32(PIXMAN_OP_SRC, src->bitmap, (pixman_image_t*) NULL, bitmap, src_rect.x, src_rect.y, 0, 0, x, y, src_rect.width, src_rect.height); pixman_transform_init_identity(&xform); pixman_image_set_transform(bitmap, &xform); RefreshCallback(); }
/* * Initialize one edge structure given a line, starting y value * and a pixel offset for the line */ PIXMAN_EXPORT void pixman_line_fixed_edge_init (pixman_edge_t * e, int n, pixman_fixed_t y, const pixman_line_fixed_t *line, int x_off, int y_off) { pixman_fixed_t x_off_fixed = pixman_int_to_fixed (x_off); pixman_fixed_t y_off_fixed = pixman_int_to_fixed (y_off); const pixman_point_fixed_t *top, *bot; if (line->p1.y <= line->p2.y) { top = &line->p1; bot = &line->p2; } else { top = &line->p2; bot = &line->p1; } pixman_edge_init (e, n, y, top->x + x_off_fixed, top->y + y_off_fixed, bot->x + x_off_fixed, bot->y + y_off_fixed); }
/* This function is copied verbatim from pixman.c. */ static pixman_bool_t compute_transformed_extents (pixman_transform_t *transform, const pixman_box32_t *extents, box_48_16_t *transformed) { pixman_fixed_48_16_t tx1, ty1, tx2, ty2; pixman_fixed_t x1, y1, x2, y2; int i; x1 = pixman_int_to_fixed (extents->x1) + pixman_fixed_1 / 2; y1 = pixman_int_to_fixed (extents->y1) + pixman_fixed_1 / 2; x2 = pixman_int_to_fixed (extents->x2) - pixman_fixed_1 / 2; y2 = pixman_int_to_fixed (extents->y2) - pixman_fixed_1 / 2; if (!transform) { transformed->x1 = x1; transformed->y1 = y1; transformed->x2 = x2; transformed->y2 = y2; return TRUE; } tx1 = ty1 = INT64_MAX; tx2 = ty2 = INT64_MIN; for (i = 0; i < 4; ++i) { pixman_fixed_48_16_t tx, ty; pixman_vector_t v; v.vector[0] = (i & 0x01)? x1 : x2; v.vector[1] = (i & 0x02)? y1 : y2; v.vector[2] = pixman_fixed_1; if (!pixman_transform_point (transform, &v)) return FALSE; tx = (pixman_fixed_48_16_t)v.vector[0]; ty = (pixman_fixed_48_16_t)v.vector[1]; if (tx < tx1) tx1 = tx; if (ty < ty1) ty1 = ty; if (tx > tx2) tx2 = tx; if (ty > ty2) ty2 = ty; } transformed->x1 = tx1; transformed->y1 = ty1; transformed->x2 = tx2; transformed->y2 = ty2; return TRUE; }
PIXMAN_EXPORT void pixman_add_traps (pixman_image_t * image, int16_t x_off, int16_t y_off, int ntrap, pixman_trap_t * traps) { int bpp; int width; int height; pixman_fixed_t x_off_fixed; pixman_fixed_t y_off_fixed; pixman_edge_t l, r; pixman_fixed_t t, b; _pixman_image_validate (image); width = image->bits.width; height = image->bits.height; bpp = PIXMAN_FORMAT_BPP (image->bits.format); x_off_fixed = pixman_int_to_fixed (x_off); y_off_fixed = pixman_int_to_fixed (y_off); while (ntrap--) { t = traps->top.y + y_off_fixed; if (t < 0) t = 0; t = pixman_sample_ceil_y (t, bpp); b = traps->bot.y + y_off_fixed; if (pixman_fixed_to_int (b) >= height) b = pixman_int_to_fixed (height) - 1; b = pixman_sample_floor_y (b, bpp); if (b >= t) { /* initialize edge walkers */ pixman_edge_init (&l, bpp, t, traps->top.l + x_off_fixed, traps->top.y + y_off_fixed, traps->bot.l + x_off_fixed, traps->bot.y + y_off_fixed); pixman_edge_init (&r, bpp, t, traps->top.r + x_off_fixed, traps->top.y + y_off_fixed, traps->bot.r + x_off_fixed, traps->bot.y + y_off_fixed); pixman_rasterize_edges (image, &l, &r, t, b); } traps++; } }
static void bench (const bench_info_t *bi, uint32_t max_n, uint32_t max_time, uint32_t *ret_n, uint32_t *ret_time, void (*func) (const pixman_composite_info_t *info)) { uint32_t n = 0; uint32_t t0; uint32_t t1; uint32_t x = 0; pixman_transform_t t; pixman_composite_info_t info; t = bi->transform; info.op = bi->op; info.src_image = bi->src_image; info.mask_image = bi->mask_image; info.dest_image = bi->dest_image; info.src_x = 0; info.src_y = 0; info.mask_x = 0; info.mask_y = 0; /* info.dest_x set below */ info.dest_y = 0; info.width = WIDTH; info.height = HEIGHT; t0 = gettimei (); do { if (++x >= 64) x = 0; info.dest_x = 63 - x; t.matrix[0][2] = pixman_int_to_fixed (bi->src_x + x); t.matrix[1][2] = pixman_int_to_fixed (bi->src_y); pixman_image_set_transform (bi->src_image, &t); if (bi->mask_image) pixman_image_set_transform (bi->mask_image, &t); func (&info); t1 = gettimei (); } while (++n < max_n && (t1 - t0) < max_time); if (ret_n) *ret_n = n; *ret_time = t1 - t0; }
static uint32_t * bits_image_fetch_affine_no_alpha (pixman_iter_t * iter, const uint32_t * mask) { pixman_image_t *image = iter->image; int offset = iter->x; int line = iter->y++; int width = iter->width; uint32_t * buffer = iter->buffer; pixman_fixed_t x, y; pixman_fixed_t ux, uy; pixman_vector_t v; int i; /* reference point is the center of the pixel */ v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; v.vector[2] = pixman_fixed_1; if (image->common.transform) { if (!pixman_transform_point_3d (image->common.transform, &v)) return iter->buffer; ux = image->common.transform->matrix[0][0]; uy = image->common.transform->matrix[1][0]; } else { ux = pixman_fixed_1; uy = 0; } x = v.vector[0]; y = v.vector[1]; for (i = 0; i < width; ++i) { if (!mask || mask[i]) { buffer[i] = bits_image_fetch_pixel_filtered ( &image->bits, x, y, fetch_pixel_no_alpha); } x += ux; y += uy; } return buffer; }
static void ssse3_bilinear_cover_iter_init (pixman_iter_t *iter, const pixman_iter_info_t *iter_info) { int width = iter->width; bilinear_info_t *info; pixman_vector_t v; /* Reference point is the center of the pixel */ v.vector[0] = pixman_int_to_fixed (iter->x) + pixman_fixed_1 / 2; v.vector[1] = pixman_int_to_fixed (iter->y) + pixman_fixed_1 / 2; v.vector[2] = pixman_fixed_1; if (!pixman_transform_point_3d (iter->image->common.transform, &v)) goto fail; info = malloc (sizeof (*info) + (2 * width - 1) * sizeof (uint64_t) + 64); if (!info) goto fail; info->x = v.vector[0] - pixman_fixed_1 / 2; info->y = v.vector[1] - pixman_fixed_1 / 2; #define ALIGN(addr) \ ((void *)((((uintptr_t)(addr)) + 15) & (~15))) /* It is safe to set the y coordinates to -1 initially * because COVER_CLIP_BILINEAR ensures that we will only * be asked to fetch lines in the [0, height) interval */ info->lines[0].y = -1; info->lines[0].buffer = ALIGN (&(info->data[0])); info->lines[1].y = -1; info->lines[1].buffer = ALIGN (info->lines[0].buffer + width); iter->get_scanline = ssse3_fetch_bilinear_cover; iter->fini = ssse3_bilinear_cover_iter_fini; iter->data = info; return; fail: /* Something went wrong, either a bad matrix or OOM; in such cases, * we don't guarantee any particular rendering. */ _pixman_log_error ( FUNC, "Allocation failure or bad matrix, skipping rendering\n"); iter->get_scanline = _pixman_iter_get_scanline_noop; iter->fini = NULL; }
PIXMAN_EXPORT void pixman_rasterize_trapezoid (pixman_image_t * image, const pixman_trapezoid_t *trap, int x_off, int y_off) { int bpp; int width; int height; pixman_fixed_t x_off_fixed; pixman_fixed_t y_off_fixed; pixman_edge_t l, r; pixman_fixed_t t, b; return_if_fail (image->type == BITS); _pixman_image_validate (image); if (!pixman_trapezoid_valid (trap)) return; width = image->bits.width; height = image->bits.height; bpp = PIXMAN_FORMAT_BPP (image->bits.format); x_off_fixed = pixman_int_to_fixed (x_off); y_off_fixed = pixman_int_to_fixed (y_off); t = trap->top + y_off_fixed; if (t < 0) t = 0; t = pixman_sample_ceil_y (t, bpp); b = trap->bottom + y_off_fixed; if (pixman_fixed_to_int (b) >= height) b = pixman_int_to_fixed (height) - 1; b = pixman_sample_floor_y (b, bpp); if (b >= t) { /* initialize edge walkers */ pixman_line_fixed_edge_init (&l, bpp, t, &trap->left, x_off, y_off); pixman_line_fixed_edge_init (&r, bpp, t, &trap->right, x_off, y_off); pixman_rasterize_edges (image, &l, &r, t, b); } }
/* Create the parameter list for a SEPARABLE_CONVOLUTION filter * with the given kernels and scale parameters */ PIXMAN_EXPORT pixman_fixed_t * pixman_filter_create_separable_convolution (int *n_values, pixman_fixed_t scale_x, pixman_fixed_t scale_y, pixman_kernel_t reconstruct_x, pixman_kernel_t reconstruct_y, pixman_kernel_t sample_x, pixman_kernel_t sample_y, int subsample_bits_x, int subsample_bits_y) { double sx = fabs (pixman_fixed_to_double (scale_x)); double sy = fabs (pixman_fixed_to_double (scale_y)); pixman_fixed_t *horz = NULL, *vert = NULL, *params = NULL; int subsample_x, subsample_y; int width, height; subsample_x = (1 << subsample_bits_x); subsample_y = (1 << subsample_bits_y); horz = create_1d_filter (&width, reconstruct_x, sample_x, sx, subsample_x); vert = create_1d_filter (&height, reconstruct_y, sample_y, sy, subsample_y); if (!horz || !vert) goto out; *n_values = 4 + width * subsample_x + height * subsample_y; params = malloc (*n_values * sizeof (pixman_fixed_t)); if (!params) goto out; params[0] = pixman_int_to_fixed (width); params[1] = pixman_int_to_fixed (height); params[2] = pixman_int_to_fixed (subsample_bits_x); params[3] = pixman_int_to_fixed (subsample_bits_y); memcpy (params + 4, horz, width * subsample_x * sizeof (pixman_fixed_t)); memcpy (params + 4 + width * subsample_x, vert, height * subsample_y * sizeof (pixman_fixed_t)); out: free (horz); free (vert); return params; }
PIXMAN_EXPORT pixman_image_t * pixman_image_create_conical_gradient (pixman_point_fixed_t * center, pixman_fixed_t angle, const pixman_gradient_stop_t *stops, int n_stops) { pixman_image_t *image = _pixman_image_allocate (); conical_gradient_t *conical; if (!image) return NULL; conical = &image->conical; if (!_pixman_init_gradient (&conical->common, stops, n_stops)) { free (image); return NULL; } angle = MOD (angle, pixman_int_to_fixed (360)); image->type = CONICAL; conical->center = *center; conical->angle = (pixman_fixed_to_double (angle) / 180.0) * M_PI; return image; }
void joy_filter_gaussian_set_radius(JoyFilter *self, gdouble radius) { g_return_if_fail(JOY_IS_FILTER_GAUSSIAN(self)); struct Private *priv = GET_PRIVATE(self); g_free(priv->kernel); gdouble fradius = fabs(radius) + 1.; gdouble sigma = sqrt(-(fradius * fradius) / (2. * log(1. / 255.))); const gdouble s2 = 2. * sigma * sigma; const gdouble s1 = 1. / (G_PI * s2); const gint size = 2 * radius + 1; gint n = size * size; gdouble kernel[n], sum; gint i, x, y; for (i = 0, sum = 0, x = -radius; x <= radius; ++x) { for (y = -radius; y <= radius; ++y, ++i) { const gdouble u = x * x; const gdouble v = y * y; kernel[i] = s1 * exp(-(u + v) / s2); sum += kernel[i]; } } priv->kernel = g_new(pixman_fixed_t, n + 2); priv->kernel[0] = priv->kernel[1] = pixman_int_to_fixed(size); for (i = 2; i < n; ++i) { priv->kernel[i] = pixman_double_to_fixed(kernel[i] / sum); } priv->n = n + 2; priv->radius = radius; }
static int pixman_renderer_read_pixels(struct weston_output *output, pixman_format_code_t format, void *pixels, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { struct pixman_output_state *po = get_output_state(output); pixman_transform_t transform; pixman_image_t *out_buf; if (!po->hw_buffer) { errno = ENODEV; return -1; } out_buf = pixman_image_create_bits(format, width, height, pixels, (PIXMAN_FORMAT_BPP(format) / 8) * width); /* Caller expects vflipped source image */ pixman_transform_init_translate(&transform, pixman_int_to_fixed (x), pixman_int_to_fixed (y - pixman_image_get_height (po->hw_buffer))); pixman_transform_scale(&transform, NULL, pixman_fixed_1, pixman_fixed_minus_1); pixman_image_set_transform(po->hw_buffer, &transform); pixman_image_composite32(PIXMAN_OP_SRC, po->hw_buffer, /* src */ NULL /* mask */, out_buf, /* dest */ 0, 0, /* src_x, src_y */ 0, 0, /* mask_x, mask_y */ 0, 0, /* dest_x, dest_y */ pixman_image_get_width (po->hw_buffer), /* width */ pixman_image_get_height (po->hw_buffer) /* height */); pixman_image_set_transform(po->hw_buffer, NULL); pixman_image_unref(out_buf); return 0; }
pixman_fixed_t* create_gaussian_blur_kernel (gint radius, gdouble sigma, gint* length) { const gdouble scale2 = 2.0f * sigma * sigma; const gdouble scale1 = 1.0f / (G_PI * scale2); const gint size = 2 * radius + 1; const gint n_params = size * size; pixman_fixed_t* params; gdouble* tmp; gdouble sum; gint x; gint y; gint i; tmp = g_newa (double, n_params); // caluclate gaussian kernel in floating point format for (i = 0, sum = 0, x = -radius; x <= radius; ++x) { for (y = -radius; y <= radius; ++y, ++i) { const gdouble u = x * x; const gdouble v = y * y; tmp[i] = scale1 * exp (-(u+v)/scale2); sum += tmp[i]; } } // normalize gaussian kernel and convert to fixed point format params = g_new (pixman_fixed_t, n_params + 2); params[0] = pixman_int_to_fixed (size); params[1] = pixman_int_to_fixed (size); for (i = 0; i < n_params; ++i) params[2 + i] = pixman_double_to_fixed (tmp[i] / sum); if (length) *length = n_params + 2; return params; }
void PixmanBitmap::TiledBlit(int ox, int oy, Rect src_rect, Bitmap* src, Rect dst_rect, int opacity) { if (opacity < 0) return; if (opacity > 255) opacity = 255; if (ox >= src_rect.width) ox %= src_rect.width; if (oy >= src_rect.height) ox %= src_rect.height; if (ox < 0) ox += src_rect.width * ((-ox + src_rect.width - 1) / src_rect.width); if (oy < 0) oy += src_rect.height * ((-oy + src_rect.height - 1) / src_rect.height); pixman_image_t* src_bm = GetSubimage(src, src_rect); pixman_image_t* mask; if (opacity < 255) { pixman_color_t tcolor = {0, 0, 0, opacity << 8}; mask = pixman_image_create_solid_fill(&tcolor); } else mask = (pixman_image_t*) NULL; pixman_image_set_repeat(src_bm, PIXMAN_REPEAT_NORMAL); pixman_transform_t xform; pixman_transform_init_translate(&xform, pixman_int_to_fixed(ox), pixman_int_to_fixed(oy)); pixman_image_set_transform(src_bm, &xform); pixman_image_composite32(PIXMAN_OP_OVER, src_bm, mask, bitmap, 0, 0, 0, 0, dst_rect.x, dst_rect.y, dst_rect.width, dst_rect.height); pixman_image_unref(src_bm); if (mask != NULL) pixman_image_unref(mask); RefreshCallback(); }
struct fp_img *fpi_im_resize(struct fp_img *img, unsigned int w_factor, unsigned int h_factor) { int new_width = img->width * w_factor; int new_height = img->height * h_factor; pixman_image_t *orig, *resized; pixman_transform_t transform; struct fp_img *newimg; orig = pixman_image_create_bits(PIXMAN_a8, img->width, img->height, (uint32_t *)img->data, img->width); resized = pixman_image_create_bits(PIXMAN_a8, new_width, new_height, NULL, new_width); pixman_transform_init_identity(&transform); pixman_transform_scale(NULL, &transform, pixman_int_to_fixed(w_factor), pixman_int_to_fixed(h_factor)); pixman_image_set_transform(orig, &transform); pixman_image_set_filter(orig, PIXMAN_FILTER_BILINEAR, NULL, 0); pixman_image_composite32(PIXMAN_OP_SRC, orig, /* src */ NULL, /* mask */ resized, /* dst */ 0, 0, /* src x y */ 0, 0, /* mask x y */ 0, 0, /* dst x y */ new_width, new_height /* width height */ ); newimg = fpi_img_new(new_width * new_height); newimg->width = new_width; newimg->height = new_height; newimg->flags = img->flags; memcpy(newimg->data, pixman_image_get_data(resized), new_width * new_height); pixman_image_unref(orig); pixman_image_unref(resized); return newimg; }
static void process_image_data(struct fp_img_dev *dev, char **output, int *output_height) { //pixman stuff taken from libfprint/pixman.c, adapted for my purposes. pixman_image_t *orig, *resized; pixman_transform_t transform; struct vfs0050_dev *vfs_dev = dev->priv; struct vfs0050_line *line, *calibration_line; char *buf = malloc(vfs_dev->scanbuf_idx); int lines = vfs_dev->scanbuf_idx / VFS0050_FRAME_SIZE; int i, x, sum, last_sum, diff; int new_height; //just grab one around middle, there should be 100 calibration_line = (struct vfs0050_line *) ((char *) vfs_dev->calbuf + (50 * VFS0050_FRAME_SIZE)); new_height = 0; for (i = 0; i < lines; i++) { line = (struct vfs0050_line *) ((char *) vfs_dev->scanbuf + (i * VFS0050_FRAME_SIZE)); if (!is_noise(line)) memcpy(buf + (new_height++ * VFS0050_IMG_WIDTH), line->row, VFS0050_IMG_WIDTH); else fp_dbg("removed noise at line: %d\n", i); } orig = pixman_image_create_bits(PIXMAN_a8, VFS0050_IMG_WIDTH, new_height, (uint32_t *) buf, VFS0050_IMG_WIDTH); new_height *= VFS0050_SCALE_FACTOR; //scale for resized image resized = pixman_image_create_bits(PIXMAN_a8, VFS0050_IMG_WIDTH, new_height, NULL, VFS0050_IMG_WIDTH); pixman_transform_init_identity(&transform); pixman_transform_scale(NULL, &transform, pixman_int_to_fixed(1), pixman_double_to_fixed(0.2)); pixman_image_set_transform(orig, &transform); pixman_image_set_filter(orig, PIXMAN_FILTER_BEST, NULL, 0); pixman_image_composite32(PIXMAN_OP_SRC, orig, NULL, resized, 0, 0, 0, 0, 0, 0, VFS0050_IMG_WIDTH, new_height ); memcpy(buf, pixman_image_get_data(resized), VFS0050_IMG_WIDTH * new_height); pixman_image_unref(orig); pixman_image_unref(resized); *output_height = new_height; *output = buf; }
bool mSDLSWInit(struct mSDLRenderer* renderer) { #if !SDL_VERSION_ATLEAST(2, 0, 0) #ifdef COLOR_16_BIT SDL_SetVideoMode(renderer->viewportWidth, renderer->viewportHeight, 16, SDL_DOUBLEBUF | SDL_HWSURFACE); #else SDL_SetVideoMode(renderer->viewportWidth, renderer->viewportHeight, 32, SDL_DOUBLEBUF | SDL_HWSURFACE); #endif #endif unsigned width, height; renderer->core->desiredVideoDimensions(renderer->core, &width, &height); #if SDL_VERSION_ATLEAST(2, 0, 0) renderer->window = SDL_CreateWindow(projectName, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, renderer->viewportWidth, renderer->viewportHeight, SDL_WINDOW_OPENGL | (SDL_WINDOW_FULLSCREEN_DESKTOP * renderer->player.fullscreen)); SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight); renderer->player.window = renderer->window; renderer->sdlRenderer = SDL_CreateRenderer(renderer->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); #ifdef COLOR_16_BIT #ifdef COLOR_5_6_5 renderer->sdlTex = SDL_CreateTexture(renderer->sdlRenderer, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STREAMING, width, height); #else renderer->sdlTex = SDL_CreateTexture(renderer->sdlRenderer, SDL_PIXELFORMAT_ABGR1555, SDL_TEXTUREACCESS_STREAMING, width, height); #endif #else renderer->sdlTex = SDL_CreateTexture(renderer->sdlRenderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, width, height); #endif int stride; SDL_LockTexture(renderer->sdlTex, 0, (void**) &renderer->outputBuffer, &stride); renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, stride / BYTES_PER_PIXEL); #else SDL_Surface* surface = SDL_GetVideoSurface(); SDL_LockSurface(surface); if (renderer->ratio == 1) { renderer->core->setVideoBuffer(renderer->core, surface->pixels, surface->pitch / BYTES_PER_PIXEL); } else { #ifdef USE_PIXMAN renderer->outputBuffer = malloc(width * height * BYTES_PER_PIXEL); renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, width); #ifdef COLOR_16_BIT #ifdef COLOR_5_6_5 pixman_format_code_t format = PIXMAN_r5g6b5; #else pixman_format_code_t format = PIXMAN_x1b5g5r5; #endif #else pixman_format_code_t format = PIXMAN_x8b8g8r8; #endif renderer->pix = pixman_image_create_bits(format, width, height, renderer->outputBuffer, width * BYTES_PER_PIXEL); renderer->screenpix = pixman_image_create_bits(format, renderer->viewportWidth, renderer->viewportHeight, surface->pixels, surface->pitch); pixman_transform_t transform; pixman_transform_init_identity(&transform); pixman_transform_scale(0, &transform, pixman_int_to_fixed(renderer->ratio), pixman_int_to_fixed(renderer->ratio)); pixman_image_set_transform(renderer->pix, &transform); pixman_image_set_filter(renderer->pix, PIXMAN_FILTER_NEAREST, 0, 0); #else return false; #endif } #endif return true; }
/* * We want to detect the case where we add the same value to a long * span of pixels. The triangles on the end are filled in while we * count how many sub-pixel scanlines contribute to the middle section. * * +--------------------------+ * fill_height =| \ / * +------------------+ * |================| * fill_start fill_end */ static void rasterize_edges_8 (pixman_image_t *image, pixman_edge_t * l, pixman_edge_t * r, pixman_fixed_t t, pixman_fixed_t b) { pixman_fixed_t y = t; uint32_t *line; int fill_start = -1, fill_end = -1; int fill_size = 0; uint32_t *buf = (image)->bits.bits; int stride = (image)->bits.rowstride; int width = (image)->bits.width; line = buf + pixman_fixed_to_int (y) * stride; for (;;) { uint8_t *ap = (uint8_t *) line; pixman_fixed_t lx, rx; int lxi, rxi; /* clip X */ lx = l->x; if (lx < 0) lx = 0; rx = r->x; if (pixman_fixed_to_int (rx) >= width) { /* Use the last pixel of the scanline, covered 100%. * We can't use the first pixel following the scanline, * because accessing it could result in a buffer overrun. */ rx = pixman_int_to_fixed (width) - 1; } /* Skip empty (or backwards) sections */ if (rx > lx) { int lxs, rxs; /* Find pixel bounds for span. */ lxi = pixman_fixed_to_int (lx); rxi = pixman_fixed_to_int (rx); /* Sample coverage for edge pixels */ lxs = RENDER_SAMPLES_X (lx, 8); rxs = RENDER_SAMPLES_X (rx, 8); /* Add coverage across row */ if (lxi == rxi) { WRITE (image, ap + lxi, clip255 (READ (image, ap + lxi) + rxs - lxs)); } else { WRITE (image, ap + lxi, clip255 (READ (image, ap + lxi) + N_X_FRAC (8) - lxs)); /* Move forward so that lxi/rxi is the pixel span */ lxi++; /* Don't bother trying to optimize the fill unless * the span is longer than 4 pixels. */ if (rxi - lxi > 4) { if (fill_start < 0) { fill_start = lxi; fill_end = rxi; fill_size++; } else { if (lxi >= fill_end || rxi < fill_start) { /* We're beyond what we saved, just fill it */ ADD_SATURATE_8 (ap + fill_start, fill_size * N_X_FRAC (8), fill_end - fill_start); fill_start = lxi; fill_end = rxi; fill_size = 1; } else { /* Update fill_start */ if (lxi > fill_start) { ADD_SATURATE_8 (ap + fill_start, fill_size * N_X_FRAC (8), lxi - fill_start); fill_start = lxi; } else if (lxi < fill_start) { ADD_SATURATE_8 (ap + lxi, N_X_FRAC (8), fill_start - lxi); } /* Update fill_end */ if (rxi < fill_end) { ADD_SATURATE_8 (ap + rxi, fill_size * N_X_FRAC (8), fill_end - rxi); fill_end = rxi; } else if (fill_end < rxi) { ADD_SATURATE_8 (ap + fill_end, N_X_FRAC (8), rxi - fill_end); } fill_size++; } } } else { ADD_SATURATE_8 (ap + lxi, N_X_FRAC (8), rxi - lxi); } WRITE (image, ap + rxi, clip255 (READ (image, ap + rxi) + rxs)); } } if (y == b) { /* We're done, make sure we clean up any remaining fill. */ if (fill_start != fill_end) { if (fill_size == N_Y_FRAC (8)) { MEMSET_WRAPPED (image, ap + fill_start, 0xff, fill_end - fill_start); } else { ADD_SATURATE_8 (ap + fill_start, fill_size * N_X_FRAC (8), fill_end - fill_start); } } break; } if (pixman_fixed_frac (y) != Y_FRAC_LAST (8)) { RENDER_EDGE_STEP_SMALL (l); RENDER_EDGE_STEP_SMALL (r); y += STEP_Y_SMALL (8); } else { RENDER_EDGE_STEP_BIG (l); RENDER_EDGE_STEP_BIG (r); y += STEP_Y_BIG (8); if (fill_start != fill_end) { if (fill_size == N_Y_FRAC (8)) { MEMSET_WRAPPED (image, ap + fill_start, 0xff, fill_end - fill_start); } else { ADD_SATURATE_8 (ap + fill_start, fill_size * N_X_FRAC (8), fill_end - fill_start); } fill_start = fill_end = -1; fill_size = 0; } line += stride; } } }
static uint32_t * conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) { pixman_image_t *image = iter->image; int x = iter->x; int y = iter->y; int width = iter->width; uint32_t *buffer = iter->buffer; gradient_t *gradient = (gradient_t *)image; conical_gradient_t *conical = (conical_gradient_t *)image; uint32_t *end = buffer + width; pixman_gradient_walker_t walker; pixman_bool_t affine = TRUE; double cx = 1.; double cy = 0.; double cz = 0.; double rx = x + 0.5; double ry = y + 0.5; double rz = 1.; _pixman_gradient_walker_init (&walker, gradient, image->common.repeat); if (image->common.transform) { pixman_vector_t v; /* reference point is the center of the pixel */ v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2; v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2; v.vector[2] = pixman_fixed_1; if (!pixman_transform_point_3d (image->common.transform, &v)) return iter->buffer; cx = image->common.transform->matrix[0][0] / 65536.; cy = image->common.transform->matrix[1][0] / 65536.; cz = image->common.transform->matrix[2][0] / 65536.; rx = v.vector[0] / 65536.; ry = v.vector[1] / 65536.; rz = v.vector[2] / 65536.; affine = image->common.transform->matrix[2][0] == 0 && v.vector[2] == pixman_fixed_1; } if (affine) { rx -= conical->center.x / 65536.; ry -= conical->center.y / 65536.; while (buffer < end) { if (!mask || *mask++) { double t = coordinates_to_parameter (rx, ry, conical->angle); *buffer = _pixman_gradient_walker_pixel ( &walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t)); } ++buffer; rx += cx; ry += cy; } } else { while (buffer < end) { double x, y; if (!mask || *mask++) { double t; if (rz != 0) { x = rx / rz; y = ry / rz; } else { x = y = 0.; } x -= conical->center.x / 65536.; y -= conical->center.y / 65536.; t = coordinates_to_parameter (x, y, conical->angle); *buffer = _pixman_gradient_walker_pixel ( &walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t)); } ++buffer; rx += cx; ry += cy; rz += cz; } } iter->y++; return iter->buffer; }
static uint32_t * linear_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) { pixman_image_t *image = iter->image; int x = iter->x; int y = iter->y; int width = iter->width; uint32_t * buffer = iter->buffer; pixman_vector_t v, unit; pixman_fixed_32_32_t l; pixman_fixed_48_16_t dx, dy; gradient_t *gradient = (gradient_t *)image; linear_gradient_t *linear = (linear_gradient_t *)image; uint32_t *end = buffer + width; pixman_gradient_walker_t walker; _pixman_gradient_walker_init (&walker, gradient, image->common.repeat); /* reference point is the center of the pixel */ v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2; v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2; v.vector[2] = pixman_fixed_1; if (image->common.transform) { if (!pixman_transform_point_3d (image->common.transform, &v)) return iter->buffer; unit.vector[0] = image->common.transform->matrix[0][0]; unit.vector[1] = image->common.transform->matrix[1][0]; unit.vector[2] = image->common.transform->matrix[2][0]; } else { unit.vector[0] = pixman_fixed_1; unit.vector[1] = 0; unit.vector[2] = 0; } dx = linear->p2.x - linear->p1.x; dy = linear->p2.y - linear->p1.y; l = dx * dx + dy * dy; if (l == 0 || unit.vector[2] == 0) { /* affine transformation only */ pixman_fixed_32_32_t t, next_inc; double inc; if (l == 0 || v.vector[2] == 0) { t = 0; inc = 0; } else { double invden, v2; invden = pixman_fixed_1 * (double) pixman_fixed_1 / (l * (double) v.vector[2]); v2 = v.vector[2] * (1. / pixman_fixed_1); t = ((dx * v.vector[0] + dy * v.vector[1]) - (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden; inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden; } next_inc = 0; if (((pixman_fixed_32_32_t )(inc * width)) == 0) { register uint32_t color; color = _pixman_gradient_walker_pixel (&walker, t); while (buffer < end) *buffer++ = color; } else { int i; i = 0; while (buffer < end) { if (!mask || *mask++) { *buffer = _pixman_gradient_walker_pixel (&walker, t + next_inc); } i++; next_inc = inc * i; buffer++; } } } else { /* projective transformation */ double t; t = 0; while (buffer < end) { if (!mask || *mask++) { if (v.vector[2] != 0) { double invden, v2; invden = pixman_fixed_1 * (double) pixman_fixed_1 / (l * (double) v.vector[2]); v2 = v.vector[2] * (1. / pixman_fixed_1); t = ((dx * v.vector[0] + dy * v.vector[1]) - (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden; } *buffer = _pixman_gradient_walker_pixel (&walker, t); } ++buffer; v.vector[0] += unit.vector[0]; v.vector[1] += unit.vector[1]; v.vector[2] += unit.vector[2]; } } iter->y++; return iter->buffer; }
static void set_image_properties(pixman_image_t * image, PicturePtr pict, Bool has_clip, int *xoff, int *yoff, Bool is_alpha_map) { pixman_repeat_t repeat; pixman_filter_t filter; if (pict->transform) { /* For source images, adjust the transform to account * for the drawable offset within the pixman image, * then set the offset to 0 as it will be used * to compute positions within the transformed image. */ if (!has_clip) { struct pixman_transform adjusted; adjusted = *pict->transform; pixman_transform_translate(&adjusted, NULL, pixman_int_to_fixed(*xoff), pixman_int_to_fixed(*yoff)); pixman_image_set_transform(image, &adjusted); *xoff = 0; *yoff = 0; } else pixman_image_set_transform(image, pict->transform); } switch (pict->repeatType) { default: case RepeatNone: repeat = PIXMAN_REPEAT_NONE; break; case RepeatPad: repeat = PIXMAN_REPEAT_PAD; break; case RepeatNormal: repeat = PIXMAN_REPEAT_NORMAL; break; case RepeatReflect: repeat = PIXMAN_REPEAT_REFLECT; break; } pixman_image_set_repeat(image, repeat); /* Fetch alpha map unless 'pict' is being used * as the alpha map for this operation */ if (pict->alphaMap && !is_alpha_map) { int alpha_xoff, alpha_yoff; pixman_image_t *alpha_map = image_from_pict_internal(pict->alphaMap, FALSE, &alpha_xoff, &alpha_yoff, TRUE); pixman_image_set_alpha_map(image, alpha_map, pict->alphaOrigin.x, pict->alphaOrigin.y); free_pixman_pict(pict->alphaMap, alpha_map); } pixman_image_set_component_alpha(image, pict->componentAlpha); switch (pict->filter) { default: case PictFilterNearest: case PictFilterFast: filter = PIXMAN_FILTER_NEAREST; break; case PictFilterBilinear: case PictFilterGood: filter = PIXMAN_FILTER_BILINEAR; break; case PictFilterConvolution: filter = PIXMAN_FILTER_CONVOLUTION; break; } if (pict->pDrawable) pixman_image_set_destroy_function(image, &image_destroy, pict->pDrawable); pixman_image_set_filter(image, filter, (pixman_fixed_t *) pict->filter_params, pict->filter_nparams); pixman_image_set_source_clipping(image, TRUE); }
void _pixman_general_radial_gradient_get_scanline_32 (pixman_image_t *image, int x, int y, int width, uint32_t * buffer, const uint32_t *mask, uint32_t mask_bits) { /* * In the radial gradient problem we are given two circles (c₁,r₁) and * (c₂,r₂) that define the gradient itself. Then, for any point p, we * must compute the value(s) of t within [0.0, 1.0] representing the * circle(s) that would color the point. * * There are potentially two values of t since the point p can be * colored by both sides of the circle, (which happens whenever one * circle is not entirely contained within the other). * * If we solve for a value of t that is outside of [0.0, 1.0] then we * use the extend mode (NONE, REPEAT, REFLECT, or PAD) to map to a * value within [0.0, 1.0]. * * Here is an illustration of the problem: * * p₂ * p • * • ╲ * · ╲r₂ * p₁ · ╲ * • θ╲ * ╲ ╌╌• * ╲r₁ · c₂ * θ╲ · * ╌╌• * c₁ * * Given (c₁,r₁), (c₂,r₂) and p, we must find an angle θ such that two * points p₁ and p₂ on the two circles are collinear with p. Then, the * desired value of t is the ratio of the length of p₁p to the length * of p₁p₂. * * So, we have six unknown values: (p₁x, p₁y), (p₂x, p₂y), θ and t. * We can also write six equations that constrain the problem: * * Point p₁ is a distance r₁ from c₁ at an angle of θ: * * 1. p₁x = c₁x + r₁·cos θ * 2. p₁y = c₁y + r₁·sin θ * * Point p₂ is a distance r₂ from c₂ at an angle of θ: * * 3. p₂x = c₂x + r2·cos θ * 4. p₂y = c₂y + r2·sin θ * * Point p lies at a fraction t along the line segment p₁p₂: * * 5. px = t·p₂x + (1-t)·p₁x * 6. py = t·p₂y + (1-t)·p₁y * * To solve, first subtitute 1-4 into 5 and 6: * * px = t·(c₂x + r₂·cos θ) + (1-t)·(c₁x + r₁·cos θ) * py = t·(c₂y + r₂·sin θ) + (1-t)·(c₁y + r₁·sin θ) * * Then solve each for cos θ and sin θ expressed as a function of t: * * cos θ = (-(c₂x - c₁x)·t + (px - c₁x)) / ((r₂-r₁)·t + r₁) * sin θ = (-(c₂y - c₁y)·t + (py - c₁y)) / ((r₂-r₁)·t + r₁) * * To simplify this a bit, we define new variables for several of the * common terms as shown below: * * p₂ * p • * • ╲ * · ┆ ╲r₂ * p₁ · ┆ ╲ * • pdy┆ ╲ * ╲ ┆ •c₂ * ╲r₁ ┆ · ┆ * ╲ ·┆ ┆cdy * •╌╌╌╌┴╌╌╌╌╌╌╌┘ * c₁ pdx cdx * * cdx = (c₂x - c₁x) * cdy = (c₂y - c₁y) * dr = r₂-r₁ * pdx = px - c₁x * pdy = py - c₁y * * Note that cdx, cdy, and dr do not depend on point p at all, so can * be pre-computed for the entire gradient. The simplifed equations * are now: * * cos θ = (-cdx·t + pdx) / (dr·t + r₁) * sin θ = (-cdy·t + pdy) / (dr·t + r₁) * * Finally, to get a single function of t and eliminate the last * unknown θ, we use the identity sin²θ + cos²θ = 1. First, square * each equation, (we knew a quadratic was coming since it must be * possible to obtain two solutions in some cases): * * cos²θ = (cdx²t² - 2·cdx·pdx·t + pdx²) / (dr²·t² + 2·r₁·dr·t + r₁²) * sin²θ = (cdy²t² - 2·cdy·pdy·t + pdy²) / (dr²·t² + 2·r₁·dr·t + r₁²) * * Then add both together, set the result equal to 1, and express as a * standard quadratic equation in t of the form At² + Bt + C = 0 * * (cdx² + cdy² - dr²)·t² - 2·(cdx·pdx + cdy·pdy + r₁·dr)·t + (pdx² + pdy² - r₁²) = 0 * * In other words: * * A = cdx² + cdy² - dr² * B = -2·(pdx·cdx + pdy·cdy + r₁·dr) * C = pdx² + pdy² - r₁² * * And again, notice that A does not depend on p, so can be * precomputed. From here we just use the quadratic formula to solve * for t: * * t = (-2·B ± ⎷(B² - 4·A·C)) / 2·A */ gradient_t *gradient = (gradient_t *)image; source_image_t *source = (source_image_t *)image; radial_gradient_t *radial = (radial_gradient_t *)image; uint32_t *end = buffer + width; pixman_gradient_walker_t walker; pixman_bool_t affine = TRUE; double cx = 1.; double cy = 0.; double cz = 0.; double rx = x + 0.5; double ry = y + 0.5; double rz = 1.; _pixman_gradient_walker_init (&walker, gradient, source->common.repeat); if (source->common.transform) { pixman_vector_t v; /* reference point is the center of the pixel */ v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2; v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2; v.vector[2] = pixman_fixed_1; if (!pixman_transform_point_3d (source->common.transform, &v)) return; cx = source->common.transform->matrix[0][0] / 65536.; cy = source->common.transform->matrix[1][0] / 65536.; cz = source->common.transform->matrix[2][0] / 65536.; rx = v.vector[0] / 65536.; ry = v.vector[1] / 65536.; rz = v.vector[2] / 65536.; affine = source->common.transform->matrix[2][0] == 0 && v.vector[2] == pixman_fixed_1; } if (affine) { /* When computing t over a scanline, we notice that some expressions * are constant so we can compute them just once. Given: * * t = (-2·B ± ⎷(B² - 4·A·C)) / 2·A * * where * * A = cdx² + cdy² - dr² [precomputed as radial->A] * B = -2·(pdx·cdx + pdy·cdy + r₁·dr) * C = pdx² + pdy² - r₁² * * Since we have an affine transformation, we know that (pdx, pdy) * increase linearly with each pixel, * * pdx = pdx₀ + n·cx, * pdy = pdy₀ + n·cy, * * we can then express B in terms of an linear increment along * the scanline: * * B = B₀ + n·cB, with * B₀ = -2·(pdx₀·cdx + pdy₀·cdy + r₁·dr) and * cB = -2·(cx·cdx + cy·cdy) * * Thus we can replace the full evaluation of B per-pixel (4 multiplies, * 2 additions) with a single addition. */ float r1 = radial->c1.radius / 65536.; float r1sq = r1 * r1; float pdx = rx - radial->c1.x / 65536.; float pdy = ry - radial->c1.y / 65536.; float A = radial->A; float invA = -65536. / (2. * A); float A4 = -4. * A; float B = -2. * (pdx*radial->cdx + pdy*radial->cdy + r1*radial->dr); float cB = -2. * (cx*radial->cdx + cy*radial->cdy); pixman_bool_t invert = A * radial->dr < 0; while (buffer < end) { if (!mask || *mask++ & mask_bits) { pixman_fixed_t t; double det = B * B + A4 * (pdx * pdx + pdy * pdy - r1sq); if (det <= 0.) t = (pixman_fixed_t) (B * invA); else if (invert) t = (pixman_fixed_t) ((B + sqrt (det)) * invA); else t = (pixman_fixed_t) ((B - sqrt (det)) * invA); *buffer = _pixman_gradient_walker_pixel (&walker, t); } ++buffer; pdx += cx; pdy += cy; B += cB; } } else { /* projective */ while (buffer < end) { if (!mask || *mask++ & mask_bits) { double pdx, pdy; double B, C; double det; double c1x = radial->c1.x / 65536.0; double c1y = radial->c1.y / 65536.0; double r1 = radial->c1.radius / 65536.0; pixman_fixed_48_16_t t; double x, y; if (rz != 0) { x = rx / rz; y = ry / rz; } else { x = y = 0.; } pdx = x - c1x; pdy = y - c1y; B = -2 * (pdx * radial->cdx + pdy * radial->cdy + r1 * radial->dr); C = (pdx * pdx + pdy * pdy - r1 * r1); det = (B * B) - (4 * radial->A * C); if (det < 0.0) det = 0.0; if (radial->A * radial->dr < 0) t = (pixman_fixed_48_16_t) ((-B - sqrt (det)) / (2.0 * radial->A) * 65536); else t = (pixman_fixed_48_16_t) ((-B + sqrt (det)) / (2.0 * radial->A) * 65536); *buffer = _pixman_gradient_walker_pixel (&walker, t); } ++buffer; rx += cx; ry += cy; rz += cz; } } }
int main (int argc, char **argv) { #define WIDTH 400 #define HEIGHT 200 uint32_t *alpha = malloc (WIDTH * HEIGHT * 4); uint32_t *dest = malloc (WIDTH * HEIGHT * 4); uint32_t *src = malloc (WIDTH * HEIGHT * 4); pixman_image_t *grad_img; pixman_image_t *alpha_img; pixman_image_t *dest_img; pixman_image_t *src_img; int i; pixman_gradient_stop_t stops[2] = { { pixman_int_to_fixed (0), { 0x0000, 0x0000, 0x0000, 0x0000 } }, { pixman_int_to_fixed (1), { 0xffff, 0x0000, 0x1111, 0xffff } } }; pixman_point_fixed_t p1 = { pixman_double_to_fixed (0), 0 }; pixman_point_fixed_t p2 = { pixman_double_to_fixed (WIDTH), pixman_int_to_fixed (0) }; #if 0 pixman_transform_t trans = { { { pixman_double_to_fixed (2), pixman_double_to_fixed (0.5), pixman_double_to_fixed (-100), }, { pixman_double_to_fixed (0), pixman_double_to_fixed (3), pixman_double_to_fixed (0), }, { pixman_double_to_fixed (0), pixman_double_to_fixed (0.000), pixman_double_to_fixed (1.0) } } }; #else pixman_transform_t trans = { { { pixman_fixed_1, 0, 0 }, { 0, pixman_fixed_1, 0 }, { 0, 0, pixman_fixed_1 } } }; #endif pixman_point_fixed_t c_inner; pixman_point_fixed_t c_outer; pixman_fixed_t r_inner; pixman_fixed_t r_outer; for (i = 0; i < WIDTH * HEIGHT; ++i) alpha[i] = 0x4f00004f; /* pale blue */ alpha_img = pixman_image_create_bits (PIXMAN_a8r8g8b8, WIDTH, HEIGHT, alpha, WIDTH * 4); for (i = 0; i < WIDTH * HEIGHT; ++i) dest[i] = 0xffffff00; /* yellow */ dest_img = pixman_image_create_bits (PIXMAN_a8r8g8b8, WIDTH, HEIGHT, dest, WIDTH * 4); for (i = 0; i < WIDTH * HEIGHT; ++i) src[i] = 0xffff0000; src_img = pixman_image_create_bits (PIXMAN_a8r8g8b8, WIDTH, HEIGHT, src, WIDTH * 4); c_inner.x = pixman_double_to_fixed (50.0); c_inner.y = pixman_double_to_fixed (50.0); c_outer.x = pixman_double_to_fixed (50.0); c_outer.y = pixman_double_to_fixed (50.0); r_inner = 0; r_outer = pixman_double_to_fixed (50.0); #if 0 grad_img = pixman_image_create_conical_gradient (&c_inner, r_inner, stops, 2); #endif #if 0 grad_img = pixman_image_create_conical_gradient (&c_inner, r_inner, stops, 2); grad_img = pixman_image_create_linear_gradient (&c_inner, &c_outer, r_inner, r_outer, stops, 2); #endif grad_img = pixman_image_create_linear_gradient (&p1, &p2, stops, 2); pixman_image_set_transform (grad_img, &trans); pixman_image_set_repeat (grad_img, PIXMAN_REPEAT_PAD); pixman_image_composite (PIXMAN_OP_OVER, grad_img, NULL, alpha_img, 0, 0, 0, 0, 0, 0, 10 * WIDTH, HEIGHT); pixman_image_set_alpha_map (src_img, alpha_img, 10, 10); pixman_image_composite (PIXMAN_OP_OVER, src_img, NULL, dest_img, 0, 0, 0, 0, 0, 0, 10 * WIDTH, HEIGHT); printf ("0, 0: %x\n", dest[0]); printf ("10, 10: %x\n", dest[10 * 10 + 10]); printf ("w, h: %x\n", dest[(HEIGHT - 1) * 100 + (WIDTH - 1)]); show_image (dest_img); pixman_image_unref (src_img); pixman_image_unref (grad_img); pixman_image_unref (alpha_img); free (dest); return 0; }
static force_inline void bits_image_fetch_nearest_affine (pixman_image_t * image, int offset, int line, int width, uint32_t * buffer, const uint32_t * mask, convert_pixel_t convert_pixel, pixman_format_code_t format, pixman_repeat_t repeat_mode) { pixman_fixed_t x, y; pixman_fixed_t ux, uy; pixman_vector_t v; bits_image_t *bits = &image->bits; int i; /* reference point is the center of the pixel */ v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; v.vector[2] = pixman_fixed_1; if (!pixman_transform_point_3d (image->common.transform, &v)) return; ux = image->common.transform->matrix[0][0]; uy = image->common.transform->matrix[1][0]; x = v.vector[0]; y = v.vector[1]; for (i = 0; i < width; ++i) { int width, height, x0, y0; const uint8_t *row; if (mask && !mask[i]) goto next; width = image->bits.width; height = image->bits.height; x0 = pixman_fixed_to_int (x - pixman_fixed_e); y0 = pixman_fixed_to_int (y - pixman_fixed_e); if (repeat_mode == PIXMAN_REPEAT_NONE && (y0 < 0 || y0 >= height || x0 < 0 || x0 >= width)) { buffer[i] = 0; } else { uint32_t mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; if (repeat_mode != PIXMAN_REPEAT_NONE) { repeat (repeat_mode, &x0, width); repeat (repeat_mode, &y0, height); } row = (uint8_t *)bits->bits + bits->rowstride * 4 * y0; buffer[i] = convert_pixel (row, x0) | mask; } next: x += ux; y += uy; } }
static force_inline void bits_image_fetch_bilinear_affine (pixman_image_t * image, int offset, int line, int width, uint32_t * buffer, const uint32_t * mask, convert_pixel_t convert_pixel, pixman_format_code_t format, pixman_repeat_t repeat_mode) { pixman_fixed_t x, y; pixman_fixed_t ux, uy; pixman_vector_t v; bits_image_t *bits = &image->bits; int i; /* reference point is the center of the pixel */ v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; v.vector[2] = pixman_fixed_1; if (!pixman_transform_point_3d (image->common.transform, &v)) return; ux = image->common.transform->matrix[0][0]; uy = image->common.transform->matrix[1][0]; x = v.vector[0]; y = v.vector[1]; for (i = 0; i < width; ++i) { int x1, y1, x2, y2; uint32_t tl, tr, bl, br; int32_t distx, disty; int width = image->bits.width; int height = image->bits.height; const uint8_t *row1; const uint8_t *row2; if (mask && !mask[i]) goto next; x1 = x - pixman_fixed_1 / 2; y1 = y - pixman_fixed_1 / 2; distx = pixman_fixed_to_bilinear_weight (x1); disty = pixman_fixed_to_bilinear_weight (y1); y1 = pixman_fixed_to_int (y1); y2 = y1 + 1; x1 = pixman_fixed_to_int (x1); x2 = x1 + 1; if (repeat_mode != PIXMAN_REPEAT_NONE) { uint32_t mask; mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; repeat (repeat_mode, &x1, width); repeat (repeat_mode, &y1, height); repeat (repeat_mode, &x2, width); repeat (repeat_mode, &y2, height); row1 = (uint8_t *)bits->bits + bits->rowstride * 4 * y1; row2 = (uint8_t *)bits->bits + bits->rowstride * 4 * y2; tl = convert_pixel (row1, x1) | mask; tr = convert_pixel (row1, x2) | mask; bl = convert_pixel (row2, x1) | mask; br = convert_pixel (row2, x2) | mask; } else { uint32_t mask1, mask2; int bpp; /* Note: PIXMAN_FORMAT_BPP() returns an unsigned value, * which means if you use it in expressions, those * expressions become unsigned themselves. Since * the variables below can be negative in some cases, * that will lead to crashes on 64 bit architectures. * * So this line makes sure bpp is signed */ bpp = PIXMAN_FORMAT_BPP (format); if (x1 >= width || x2 < 0 || y1 >= height || y2 < 0) { buffer[i] = 0; goto next; } if (y2 == 0) { row1 = zero; mask1 = 0; } else { row1 = (uint8_t *)bits->bits + bits->rowstride * 4 * y1; row1 += bpp / 8 * x1; mask1 = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; } if (y1 == height - 1) { row2 = zero; mask2 = 0; } else { row2 = (uint8_t *)bits->bits + bits->rowstride * 4 * y2; row2 += bpp / 8 * x1; mask2 = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; } if (x2 == 0) { tl = 0; bl = 0; } else { tl = convert_pixel (row1, 0) | mask1; bl = convert_pixel (row2, 0) | mask2; } if (x1 == width - 1) { tr = 0; br = 0; } else { tr = convert_pixel (row1, 1) | mask1; br = convert_pixel (row2, 1) | mask2; } } buffer[i] = bilinear_interpolation ( tl, tr, bl, br, distx, disty); next: x += ux; y += uy; } }
static uint32_t * bits_image_fetch_general (pixman_iter_t *iter, const uint32_t *mask) { pixman_image_t *image = iter->image; int offset = iter->x; int line = iter->y++; int width = iter->width; uint32_t * buffer = iter->buffer; pixman_fixed_t x, y, w; pixman_fixed_t ux, uy, uw; pixman_vector_t v; int i; /* reference point is the center of the pixel */ v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; v.vector[2] = pixman_fixed_1; if (image->common.transform) { if (!pixman_transform_point_3d (image->common.transform, &v)) return buffer; ux = image->common.transform->matrix[0][0]; uy = image->common.transform->matrix[1][0]; uw = image->common.transform->matrix[2][0]; } else { ux = pixman_fixed_1; uy = 0; uw = 0; } x = v.vector[0]; y = v.vector[1]; w = v.vector[2]; for (i = 0; i < width; ++i) { pixman_fixed_t x0, y0; if (!mask || mask[i]) { if (w != 0) { x0 = ((pixman_fixed_48_16_t)x << 16) / w; y0 = ((pixman_fixed_48_16_t)y << 16) / w; } else { x0 = 0; y0 = 0; } buffer[i] = bits_image_fetch_pixel_filtered ( &image->bits, x0, y0, fetch_pixel_general); } x += ux; y += uy; w += uw; } return buffer; }
int main (int argc, char **argv) { #define WIDTH 400 #define HEIGHT 200 uint32_t *dest = malloc (WIDTH * HEIGHT * 4); pixman_image_t *src_img; pixman_image_t *dest_img; int i, j, k, p; typedef struct { pixman_point_fixed_t p0; pixman_point_fixed_t p1; } point_pair_t; pixman_gradient_stop_t onestop[1] = { { pixman_int_to_fixed (1), { 0xffff, 0xeeee, 0xeeee, 0xeeee } }, }; pixman_gradient_stop_t subsetstops[2] = { { pixman_int_to_fixed (1), { 0xffff, 0xeeee, 0xeeee, 0xeeee } }, { pixman_int_to_fixed (1), { 0xffff, 0xeeee, 0xeeee, 0xeeee } }, }; pixman_gradient_stop_t stops01[2] = { { pixman_int_to_fixed (0), { 0xffff, 0xeeee, 0xeeee, 0xeeee } }, { pixman_int_to_fixed (1), { 0xffff, 0x1111, 0x1111, 0x1111 } } }; point_pair_t point_pairs [] = { { { pixman_double_to_fixed (0), 0 }, { pixman_double_to_fixed (WIDTH / 8.), pixman_int_to_fixed (0) } }, { { pixman_double_to_fixed (WIDTH / 2.0), pixman_double_to_fixed (HEIGHT / 2.0) }, { pixman_double_to_fixed (WIDTH / 2.0), pixman_double_to_fixed (HEIGHT / 2.0) } } }; pixman_transform_t transformations[] = { { { { pixman_double_to_fixed (2), pixman_double_to_fixed (0.5), pixman_double_to_fixed (-100), }, { pixman_double_to_fixed (0), pixman_double_to_fixed (3), pixman_double_to_fixed (0), }, { pixman_double_to_fixed (0), pixman_double_to_fixed (0.000), pixman_double_to_fixed (1.0) } } }, { { { pixman_double_to_fixed (1), pixman_double_to_fixed (0), pixman_double_to_fixed (0), }, { pixman_double_to_fixed (0), pixman_double_to_fixed (1), pixman_double_to_fixed (0), }, { pixman_double_to_fixed (0), pixman_double_to_fixed (0.000), pixman_double_to_fixed (1.0) } } }, { { { pixman_double_to_fixed (2), pixman_double_to_fixed (1), pixman_double_to_fixed (0), }, { pixman_double_to_fixed (1), pixman_double_to_fixed (1), pixman_double_to_fixed (0), }, { pixman_double_to_fixed (2), pixman_double_to_fixed (1.000), pixman_double_to_fixed (1.0) } } }, { { { pixman_double_to_fixed (2), pixman_double_to_fixed (1), pixman_double_to_fixed (0), }, { pixman_double_to_fixed (1), pixman_double_to_fixed (1), pixman_double_to_fixed (0), }, { pixman_double_to_fixed (0), pixman_double_to_fixed (0), pixman_double_to_fixed (0) } } }, { { { pixman_double_to_fixed (2), pixman_double_to_fixed (1), pixman_double_to_fixed (0), }, { pixman_double_to_fixed (1), pixman_double_to_fixed (1), pixman_double_to_fixed (0), }, { pixman_double_to_fixed (2), pixman_double_to_fixed (-1), pixman_double_to_fixed (0) } } }, { { { pixman_double_to_fixed (2), pixman_double_to_fixed (1), pixman_double_to_fixed (3), }, { pixman_double_to_fixed (1), pixman_double_to_fixed (1), pixman_double_to_fixed (0), }, { pixman_double_to_fixed (2), pixman_double_to_fixed (-1), pixman_double_to_fixed (0) } } }, }; pixman_fixed_t r_inner; pixman_fixed_t r_outer; enable_divbyzero_exceptions(); for (i = 0; i < WIDTH * HEIGHT; ++i) dest[i] = 0x4f00004f; /* pale blue */ dest_img = pixman_image_create_bits (PIXMAN_a8r8g8b8, WIDTH, HEIGHT, dest, WIDTH * 4); r_inner = 0; r_outer = pixman_double_to_fixed (50.0); for (i = 0; i < 3; ++i) { pixman_gradient_stop_t *stops; int num_stops; if (i == 0) { stops = onestop; num_stops = ARRAY_LENGTH (onestop); } else if (i == 1) { stops = subsetstops; num_stops = ARRAY_LENGTH (subsetstops); } else { stops = stops01; num_stops = ARRAY_LENGTH (stops01); } for (j = 0; j < 3; ++j) { for (p = 0; p < ARRAY_LENGTH (point_pairs); ++p) { point_pair_t *pair = &(point_pairs[p]); if (j == 0) src_img = pixman_image_create_conical_gradient (&(pair->p0), r_inner, stops, num_stops); else if (j == 1) src_img = pixman_image_create_radial_gradient (&(pair->p0), &(pair->p1), r_inner, r_outer, stops, num_stops); else src_img = pixman_image_create_linear_gradient (&(pair->p0), &(pair->p1), stops, num_stops); for (k = 0; k < ARRAY_LENGTH (transformations); ++k) { pixman_image_set_transform (src_img, &transformations[k]); pixman_image_set_repeat (src_img, PIXMAN_REPEAT_NONE); pixman_image_composite (PIXMAN_OP_OVER, src_img, NULL, dest_img, 0, 0, 0, 0, 0, 0, 10 * WIDTH, HEIGHT); } pixman_image_unref (src_img); } } } pixman_image_unref (dest_img); free (dest); return 0; }
static uint32_t * radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) { /* * Implementation of radial gradients following the PDF specification. * See section 8.7.4.5.4 Type 3 (Radial) Shadings of the PDF Reference * Manual (PDF 32000-1:2008 at the time of this writing). * * In the radial gradient problem we are given two circles (c₁,r₁) and * (c₂,r₂) that define the gradient itself. * * Mathematically the gradient can be defined as the family of circles * * ((1-t)·c₁ + t·(c₂), (1-t)·r₁ + t·r₂) * * excluding those circles whose radius would be < 0. When a point * belongs to more than one circle, the one with a bigger t is the only * one that contributes to its color. When a point does not belong * to any of the circles, it is transparent black, i.e. RGBA (0, 0, 0, 0). * Further limitations on the range of values for t are imposed when * the gradient is not repeated, namely t must belong to [0,1]. * * The graphical result is the same as drawing the valid (radius > 0) * circles with increasing t in [-inf, +inf] (or in [0,1] if the gradient * is not repeated) using SOURCE operator composition. * * It looks like a cone pointing towards the viewer if the ending circle * is smaller than the starting one, a cone pointing inside the page if * the starting circle is the smaller one and like a cylinder if they * have the same radius. * * What we actually do is, given the point whose color we are interested * in, compute the t values for that point, solving for t in: * * length((1-t)·c₁ + t·(c₂) - p) = (1-t)·r₁ + t·r₂ * * Let's rewrite it in a simpler way, by defining some auxiliary * variables: * * cd = c₂ - c₁ * pd = p - c₁ * dr = r₂ - r₁ * length(t·cd - pd) = r₁ + t·dr * * which actually means * * hypot(t·cdx - pdx, t·cdy - pdy) = r₁ + t·dr * * or * * ⎷((t·cdx - pdx)² + (t·cdy - pdy)²) = r₁ + t·dr. * * If we impose (as stated earlier) that r₁ + t·dr >= 0, it becomes: * * (t·cdx - pdx)² + (t·cdy - pdy)² = (r₁ + t·dr)² * * where we can actually expand the squares and solve for t: * * t²cdx² - 2t·cdx·pdx + pdx² + t²cdy² - 2t·cdy·pdy + pdy² = * = r₁² + 2·r₁·t·dr + t²·dr² * * (cdx² + cdy² - dr²)t² - 2(cdx·pdx + cdy·pdy + r₁·dr)t + * (pdx² + pdy² - r₁²) = 0 * * A = cdx² + cdy² - dr² * B = pdx·cdx + pdy·cdy + r₁·dr * C = pdx² + pdy² - r₁² * At² - 2Bt + C = 0 * * The solutions (unless the equation degenerates because of A = 0) are: * * t = (B ± ⎷(B² - A·C)) / A * * The solution we are going to prefer is the bigger one, unless the * radius associated to it is negative (or it falls outside the valid t * range). * * Additional observations (useful for optimizations): * A does not depend on p * * A < 0 <=> one of the two circles completely contains the other one * <=> for every p, the radiuses associated with the two t solutions * have opposite sign */ pixman_image_t *image = iter->image; int x = iter->x; int y = iter->y; int width = iter->width; uint32_t *buffer = iter->buffer; gradient_t *gradient = (gradient_t *)image; radial_gradient_t *radial = (radial_gradient_t *)image; uint32_t *end = buffer + width; pixman_gradient_walker_t walker; pixman_vector_t v, unit; /* reference point is the center of the pixel */ v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2; v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2; v.vector[2] = pixman_fixed_1; _pixman_gradient_walker_init (&walker, gradient, image->common.repeat); if (image->common.transform) { if (!pixman_transform_point_3d (image->common.transform, &v)) return iter->buffer; unit.vector[0] = image->common.transform->matrix[0][0]; unit.vector[1] = image->common.transform->matrix[1][0]; unit.vector[2] = image->common.transform->matrix[2][0]; } else { unit.vector[0] = pixman_fixed_1; unit.vector[1] = 0; unit.vector[2] = 0; } if (unit.vector[2] == 0 && v.vector[2] == pixman_fixed_1) { /* * Given: * * t = (B ± ⎷(B² - A·C)) / A * * where * * A = cdx² + cdy² - dr² * B = pdx·cdx + pdy·cdy + r₁·dr * C = pdx² + pdy² - r₁² * det = B² - A·C * * Since we have an affine transformation, we know that (pdx, pdy) * increase linearly with each pixel, * * pdx = pdx₀ + n·ux, * pdy = pdy₀ + n·uy, * * we can then express B, C and det through multiple differentiation. */ pixman_fixed_32_32_t b, db, c, dc, ddc; /* warning: this computation may overflow */ v.vector[0] -= radial->c1.x; v.vector[1] -= radial->c1.y; /* * B and C are computed and updated exactly. * If fdot was used instead of dot, in the worst case it would * lose 11 bits of precision in each of the multiplication and * summing up would zero out all the bit that were preserved, * thus making the result 0 instead of the correct one. * This would mean a worst case of unbound relative error or * about 2^10 absolute error */ b = dot (v.vector[0], v.vector[1], radial->c1.radius, radial->delta.x, radial->delta.y, radial->delta.radius); db = dot (unit.vector[0], unit.vector[1], 0, radial->delta.x, radial->delta.y, 0); c = dot (v.vector[0], v.vector[1], -((pixman_fixed_48_16_t) radial->c1.radius), v.vector[0], v.vector[1], radial->c1.radius); dc = dot (2 * (pixman_fixed_48_16_t) v.vector[0] + unit.vector[0], 2 * (pixman_fixed_48_16_t) v.vector[1] + unit.vector[1], 0, unit.vector[0], unit.vector[1], 0); ddc = 2 * dot (unit.vector[0], unit.vector[1], 0, unit.vector[0], unit.vector[1], 0); while (buffer < end) { if (!mask || *mask++) { *buffer = radial_compute_color (radial->a, b, c, radial->inva, radial->delta.radius, radial->mindr, &walker, image->common.repeat); } b += db; c += dc; dc += ddc; ++buffer; } } else { /* projective */ /* Warning: * error propagation guarantees are much looser than in the affine case */ while (buffer < end) { if (!mask || *mask++) { if (v.vector[2] != 0) { double pdx, pdy, invv2, b, c; invv2 = 1. * pixman_fixed_1 / v.vector[2]; pdx = v.vector[0] * invv2 - radial->c1.x; /* / pixman_fixed_1 */ pdy = v.vector[1] * invv2 - radial->c1.y; /* / pixman_fixed_1 */ b = fdot (pdx, pdy, radial->c1.radius, radial->delta.x, radial->delta.y, radial->delta.radius); /* / pixman_fixed_1 / pixman_fixed_1 */ c = fdot (pdx, pdy, -radial->c1.radius, pdx, pdy, radial->c1.radius); /* / pixman_fixed_1 / pixman_fixed_1 */ *buffer = radial_compute_color (radial->a, b, c, radial->inva, radial->delta.radius, radial->mindr, &walker, image->common.repeat); } else { *buffer = 0; } } ++buffer; v.vector[0] += unit.vector[0]; v.vector[1] += unit.vector[1]; v.vector[2] += unit.vector[2]; } } iter->y++; return iter->buffer; }
void _pixman_general_conical_gradient_get_scanline_32 (pixman_image_t *image, int x, int y, int width, uint32_t * buffer, const uint32_t *mask, uint32_t mask_bits) { source_image_t *source = (source_image_t *)image; gradient_t *gradient = (gradient_t *)source; conical_gradient_t *conical = (conical_gradient_t *)image; uint32_t *end = buffer + width; pixman_gradient_walker_t walker; pixman_bool_t affine = TRUE; double cx = 1.; double cy = 0.; double cz = 0.; double rx = x + 0.5; double ry = y + 0.5; double rz = 1.; double a = (conical->angle * M_PI) / (180. * 65536); _pixman_gradient_walker_init (&walker, gradient, source->common.repeat); if (source->common.transform) { pixman_vector_t v; /* reference point is the center of the pixel */ v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2; v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2; v.vector[2] = pixman_fixed_1; if (!pixman_transform_point_3d (source->common.transform, &v)) return; cx = source->common.transform->matrix[0][0] / 65536.; cy = source->common.transform->matrix[1][0] / 65536.; cz = source->common.transform->matrix[2][0] / 65536.; rx = v.vector[0] / 65536.; ry = v.vector[1] / 65536.; rz = v.vector[2] / 65536.; affine = source->common.transform->matrix[2][0] == 0 && v.vector[2] == pixman_fixed_1; } if (affine) { rx -= conical->center.x / 65536.; ry -= conical->center.y / 65536.; while (buffer < end) { double angle; if (!mask || *mask++ & mask_bits) { pixman_fixed_48_16_t t; angle = atan2 (ry, rx) + a; t = (pixman_fixed_48_16_t) (angle * (65536. / (2 * M_PI))); *buffer = _pixman_gradient_walker_pixel (&walker, t); } ++buffer; rx += cx; ry += cy; } } else { while (buffer < end) { double x, y; double angle; if (!mask || *mask++ & mask_bits) { pixman_fixed_48_16_t t; if (rz != 0) { x = rx / rz; y = ry / rz; } else { x = y = 0.; } x -= conical->center.x / 65536.; y -= conical->center.y / 65536.; angle = atan2 (y, x) + a; t = (pixman_fixed_48_16_t) (angle * (65536. / (2 * M_PI))); *buffer = _pixman_gradient_walker_pixel (&walker, t); } ++buffer; rx += cx; ry += cy; rz += cz; } } }
static uint32_t * bits_image_fetch_bilinear_no_repeat_8888 (pixman_iter_t *iter, const uint32_t *mask) { pixman_image_t * ima = iter->image; int offset = iter->x; int line = iter->y++; int width = iter->width; uint32_t * buffer = iter->buffer; bits_image_t *bits = &ima->bits; pixman_fixed_t x_top, x_bottom, x; pixman_fixed_t ux_top, ux_bottom, ux; pixman_vector_t v; uint32_t top_mask, bottom_mask; uint32_t *top_row; uint32_t *bottom_row; uint32_t *end; uint32_t zero[2] = { 0, 0 }; uint32_t one = 1; int y, y1, y2; int disty; int mask_inc; int w; /* reference point is the center of the pixel */ v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; v.vector[2] = pixman_fixed_1; if (!pixman_transform_point_3d (bits->common.transform, &v)) return iter->buffer; ux = ux_top = ux_bottom = bits->common.transform->matrix[0][0]; x = x_top = x_bottom = v.vector[0] - pixman_fixed_1/2; y = v.vector[1] - pixman_fixed_1/2; disty = pixman_fixed_to_bilinear_weight (y); /* Load the pointers to the first and second lines from the source * image that bilinear code must read. * * The main trick in this code is about the check if any line are * outside of the image; * * When I realize that a line (any one) is outside, I change * the pointer to a dummy area with zeros. Once I change this, I * must be sure the pointer will not change, so I set the * variables to each pointer increments inside the loop. */ y1 = pixman_fixed_to_int (y); y2 = y1 + 1; if (y1 < 0 || y1 >= bits->height) { top_row = zero; x_top = 0; ux_top = 0; } else { top_row = bits->bits + y1 * bits->rowstride; x_top = x; ux_top = ux; } if (y2 < 0 || y2 >= bits->height) { bottom_row = zero; x_bottom = 0; ux_bottom = 0; } else { bottom_row = bits->bits + y2 * bits->rowstride; x_bottom = x; ux_bottom = ux; } /* Instead of checking whether the operation uses the mast in * each loop iteration, verify this only once and prepare the * variables to make the code smaller inside the loop. */ if (!mask) { mask_inc = 0; mask = &one; } else { /* If have a mask, prepare the variables to check it */ mask_inc = 1; } /* If both are zero, then the whole thing is zero */ if (top_row == zero && bottom_row == zero) { memset (buffer, 0, width * sizeof (uint32_t)); return iter->buffer; } else if (bits->format == PIXMAN_x8r8g8b8) { if (top_row == zero) { top_mask = 0; bottom_mask = 0xff000000; } else if (bottom_row == zero) { top_mask = 0xff000000; bottom_mask = 0; } else { top_mask = 0xff000000; bottom_mask = 0xff000000; } } else { top_mask = 0; bottom_mask = 0; } end = buffer + width; /* Zero fill to the left of the image */ while (buffer < end && x < pixman_fixed_minus_1) { *buffer++ = 0; x += ux; x_top += ux_top; x_bottom += ux_bottom; mask += mask_inc; } /* Left edge */ while (buffer < end && x < 0) { uint32_t tr, br; int32_t distx; tr = top_row[pixman_fixed_to_int (x_top) + 1] | top_mask; br = bottom_row[pixman_fixed_to_int (x_bottom) + 1] | bottom_mask; distx = pixman_fixed_to_bilinear_weight (x); *buffer++ = bilinear_interpolation (0, tr, 0, br, distx, disty); x += ux; x_top += ux_top; x_bottom += ux_bottom; mask += mask_inc; } /* Main part */ w = pixman_int_to_fixed (bits->width - 1); while (buffer < end && x < w) { if (*mask) { uint32_t tl, tr, bl, br; int32_t distx; tl = top_row [pixman_fixed_to_int (x_top)] | top_mask; tr = top_row [pixman_fixed_to_int (x_top) + 1] | top_mask; bl = bottom_row [pixman_fixed_to_int (x_bottom)] | bottom_mask; br = bottom_row [pixman_fixed_to_int (x_bottom) + 1] | bottom_mask; distx = pixman_fixed_to_bilinear_weight (x); *buffer = bilinear_interpolation (tl, tr, bl, br, distx, disty); } buffer++; x += ux; x_top += ux_top; x_bottom += ux_bottom; mask += mask_inc; } /* Right Edge */ w = pixman_int_to_fixed (bits->width); while (buffer < end && x < w) { if (*mask) { uint32_t tl, bl; int32_t distx; tl = top_row [pixman_fixed_to_int (x_top)] | top_mask; bl = bottom_row [pixman_fixed_to_int (x_bottom)] | bottom_mask; distx = pixman_fixed_to_bilinear_weight (x); *buffer = bilinear_interpolation (tl, 0, bl, 0, distx, disty); } buffer++; x += ux; x_top += ux_top; x_bottom += ux_bottom; mask += mask_inc; } /* Zero fill to the left of the image */ while (buffer < end) *buffer++ = 0; return iter->buffer; }