static uint32_t color_stop_to_pixel(const cairo_gradient_stop_t *stop) { uint8_t a, r, g, b; a = stop->color.alpha_short >> 8; r = premultiply(stop->color.red, stop->color.alpha); g = premultiply(stop->color.green, stop->color.alpha); b = premultiply(stop->color.blue, stop->color.alpha); if (_cairo_is_little_endian ()) return a << 24 | r << 16 | g << 8 | b << 0; else return a << 0 | r << 8 | g << 16 | b << 24; }
static cairo_bool_t test_can_read_bgra (cairo_gl_flavor_t gl_flavor) { /* Desktop GL always supports BGRA formats. */ if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) return TRUE; assert (gl_flavor == CAIRO_GL_FLAVOR_ES); /* For OpenGL ES we have to look for the specific extension and BGRA only * matches cairo's integer packed bytes on little-endian machines. */ if (!_cairo_is_little_endian()) return FALSE; return _cairo_gl_has_extension ("EXT_read_format_bgra"); }
static cairo_status_t _cairo_gl_gradient_render (const cairo_gl_context_t *ctx, unsigned int n_stops, const cairo_gradient_stop_t *stops, void *bytes, int width) { pixman_image_t *gradient, *image; pixman_gradient_stop_t pixman_stops_stack[32]; pixman_gradient_stop_t *pixman_stops; pixman_point_fixed_t p1, p2; unsigned int i; pixman_format_code_t gradient_pixman_format; /* * Ensure that the order of the gradient's components in memory is BGRA. * This is done so that the gradient's pixel data is always suitable for * texture upload using format=GL_BGRA and type=GL_UNSIGNED_BYTE. */ if (_cairo_is_little_endian ()) gradient_pixman_format = PIXMAN_a8r8g8b8; else gradient_pixman_format = PIXMAN_b8g8r8a8; pixman_stops = pixman_stops_stack; if (unlikely (n_stops > ARRAY_LENGTH (pixman_stops_stack))) { pixman_stops = _cairo_malloc_ab (n_stops, sizeof (pixman_gradient_stop_t)); if (unlikely (pixman_stops == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } for (i = 0; i < n_stops; i++) { pixman_stops[i].x = _cairo_fixed_16_16_from_double (stops[i].offset); pixman_stops[i].color.red = stops[i].color.red_short; pixman_stops[i].color.green = stops[i].color.green_short; pixman_stops[i].color.blue = stops[i].color.blue_short; pixman_stops[i].color.alpha = stops[i].color.alpha_short; } p1.x = _cairo_fixed_16_16_from_double (0.5); p1.y = 0; p2.x = _cairo_fixed_16_16_from_double (width - 0.5); p2.y = 0; gradient = pixman_image_create_linear_gradient (&p1, &p2, pixman_stops, n_stops); if (pixman_stops != pixman_stops_stack) free (pixman_stops); if (unlikely (gradient == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); pixman_image_set_filter (gradient, PIXMAN_FILTER_BILINEAR, NULL, 0); pixman_image_set_repeat (gradient, PIXMAN_REPEAT_PAD); image = pixman_image_create_bits (gradient_pixman_format, width, 1, bytes, sizeof(uint32_t)*width); if (unlikely (image == NULL)) { pixman_image_unref (gradient); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } pixman_image_composite32 (PIXMAN_OP_SRC, gradient, NULL, image, 0, 0, 0, 0, 0, 0, width, 1); pixman_image_unref (gradient); pixman_image_unref (image); /* We need to fudge pixel 0 to hold the left-most color stop and not * the neareset stop to the zeroth pixel centre in order to correctly * populate the border color. For completeness, do both edges. */ ((uint32_t*)bytes)[0] = color_stop_to_pixel(&stops[0]); ((uint32_t*)bytes)[width-1] = color_stop_to_pixel(&stops[n_stops-1]); return CAIRO_STATUS_SUCCESS; }
static cairo_surface_t * _cairo_gl_surface_map_to_image (void *abstract_surface, const cairo_rectangle_int_t *extents) { cairo_gl_surface_t *surface = abstract_surface; cairo_image_surface_t *image; cairo_gl_context_t *ctx; GLenum format, type; pixman_format_code_t pixman_format; unsigned int cpp; cairo_bool_t invert; cairo_status_t status; /* Want to use a switch statement here but the compiler gets whiny. */ if (surface->base.content == CAIRO_CONTENT_COLOR_ALPHA) { format = GL_BGRA; pixman_format = PIXMAN_a8r8g8b8; type = GL_UNSIGNED_INT_8_8_8_8_REV; cpp = 4; } else if (surface->base.content == CAIRO_CONTENT_COLOR) { format = GL_BGRA; pixman_format = PIXMAN_x8r8g8b8; type = GL_UNSIGNED_INT_8_8_8_8_REV; cpp = 4; } else if (surface->base.content == CAIRO_CONTENT_ALPHA) { format = GL_ALPHA; pixman_format = PIXMAN_a8; type = GL_UNSIGNED_BYTE; cpp = 1; } else { ASSERT_NOT_REACHED; return NULL; } /* * GLES2 supports only RGBA, UNSIGNED_BYTE so use that. * We are also using this format for ALPHA as GLES2 does not * support GL_PACK_ROW_LENGTH anyway, and this makes sure that the * pixman image that is created has row_stride = row_width * bpp. */ if (_cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES) { format = GL_RGBA; if (! _cairo_is_little_endian ()) { if (surface->base.content == CAIRO_CONTENT_COLOR) pixman_format = PIXMAN_r8g8b8x8; else pixman_format = PIXMAN_r8g8b8a8; } else { if (surface->base.content == CAIRO_CONTENT_COLOR) pixman_format = PIXMAN_x8b8g8r8; else pixman_format = PIXMAN_a8b8g8r8; } type = GL_UNSIGNED_BYTE; cpp = 4; } image = (cairo_image_surface_t*) _cairo_image_surface_create_with_pixman_format (NULL, pixman_format, extents->width, extents->height, -1); if (unlikely (image->base.status)) return &image->base; if (surface->base.serial == 0) return &image->base; status = _cairo_gl_context_acquire (surface->base.device, &ctx); if (unlikely (status)) { cairo_surface_destroy (&image->base); return _cairo_surface_create_in_error (status); } cairo_surface_set_device_offset (&image->base, -extents->x, -extents->y); /* This is inefficient, as we'd rather just read the thing without making * it the destination. But then, this is the fallback path, so let's not * fall back instead. */ _cairo_gl_composite_flush (ctx); _cairo_gl_context_set_destination (ctx, surface); invert = ! _cairo_gl_surface_is_texture (surface) && ctx->has_mesa_pack_invert; glPixelStorei (GL_PACK_ALIGNMENT, 4); if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) glPixelStorei (GL_PACK_ROW_LENGTH, image->stride / cpp); if (invert) glPixelStorei (GL_PACK_INVERT_MESA, 1); glReadPixels (extents->x, extents->y, extents->width, extents->height, format, type, image->data); if (invert) glPixelStorei (GL_PACK_INVERT_MESA, 0); status = _cairo_gl_context_release (ctx, status); if (unlikely (status)) { cairo_surface_destroy (&image->base); image = (cairo_image_surface_t *) _cairo_surface_create_in_error (status); } return &image->base; }
static cairo_bool_t _cairo_gl_get_image_format_and_type_gles2 (pixman_format_code_t pixman_format, GLenum *internal_format, GLenum *format, GLenum *type, cairo_bool_t *has_alpha, cairo_bool_t *needs_swap) { cairo_bool_t is_little_endian = _cairo_is_little_endian (); *has_alpha = TRUE; switch ((int) pixman_format) { case PIXMAN_a8r8g8b8: *internal_format = GL_BGRA; *format = GL_BGRA; *type = GL_UNSIGNED_BYTE; *needs_swap = !is_little_endian; return TRUE; case PIXMAN_x8r8g8b8: *internal_format = GL_BGRA; *format = GL_BGRA; *type = GL_UNSIGNED_BYTE; *has_alpha = FALSE; *needs_swap = !is_little_endian; return TRUE; case PIXMAN_a8b8g8r8: *internal_format = GL_RGBA; *format = GL_RGBA; *type = GL_UNSIGNED_BYTE; *needs_swap = !is_little_endian; return TRUE; case PIXMAN_x8b8g8r8: *internal_format = GL_RGBA; *format = GL_RGBA; *type = GL_UNSIGNED_BYTE; *has_alpha = FALSE; *needs_swap = !is_little_endian; return TRUE; case PIXMAN_b8g8r8a8: *internal_format = GL_BGRA; *format = GL_BGRA; *type = GL_UNSIGNED_BYTE; *needs_swap = is_little_endian; return TRUE; case PIXMAN_b8g8r8x8: *internal_format = GL_BGRA; *format = GL_BGRA; *type = GL_UNSIGNED_BYTE; *has_alpha = FALSE; *needs_swap = is_little_endian; return TRUE; case PIXMAN_r8g8b8: *internal_format = GL_RGB; *format = GL_RGB; *type = GL_UNSIGNED_BYTE; *needs_swap = is_little_endian; return TRUE; case PIXMAN_b8g8r8: *internal_format = GL_RGB; *format = GL_RGB; *type = GL_UNSIGNED_BYTE; *needs_swap = !is_little_endian; return TRUE; case PIXMAN_r5g6b5: *internal_format = GL_RGB; *format = GL_RGB; *type = GL_UNSIGNED_SHORT_5_6_5; *needs_swap = FALSE; return TRUE; case PIXMAN_b5g6r5: *internal_format = GL_RGB; *format = GL_RGB; *type = GL_UNSIGNED_SHORT_5_6_5; *needs_swap = TRUE; return TRUE; case PIXMAN_a1b5g5r5: *internal_format = GL_RGBA; *format = GL_RGBA; *type = GL_UNSIGNED_SHORT_5_5_5_1; *needs_swap = TRUE; return TRUE; case PIXMAN_x1b5g5r5: *internal_format = GL_RGBA; *format = GL_RGBA; *type = GL_UNSIGNED_SHORT_5_5_5_1; *has_alpha = FALSE; *needs_swap = TRUE; return TRUE; case PIXMAN_a8: *internal_format = GL_ALPHA; *format = GL_ALPHA; *type = GL_UNSIGNED_BYTE; *needs_swap = FALSE; return TRUE; default: return FALSE; } }
static cairo_int_status_t traps_to_operand (void *_dst, const cairo_rectangle_int_t *extents, cairo_antialias_t antialias, cairo_traps_t *traps, cairo_gl_operand_t *operand, int dst_x, int dst_y) { pixman_format_code_t pixman_format; pixman_image_t *pixman_image; cairo_surface_t *image, *mask; cairo_surface_pattern_t pattern; cairo_status_t status; pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1; pixman_image = pixman_image_create_bits (pixman_format, extents->width, extents->height, NULL, 0); if (unlikely (pixman_image == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); _pixman_image_add_traps (pixman_image, extents->x, extents->y, traps); image = _cairo_image_surface_create_for_pixman_image (pixman_image, pixman_format); if (unlikely (image->status)) { pixman_image_unref (pixman_image); return image->status; } /* GLES2 only supports RGB/RGBA when uploading */ if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES) { cairo_surface_pattern_t pattern; cairo_surface_t *rgba_image; /* XXX perform this fixup inside _cairo_gl_draw_image() */ rgba_image = _cairo_image_surface_create_with_pixman_format (NULL, _cairo_is_little_endian () ? PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8, extents->width, extents->height, 0); if (unlikely (rgba_image->status)) return rgba_image->status; _cairo_pattern_init_for_surface (&pattern, image); status = _cairo_surface_paint (rgba_image, CAIRO_OPERATOR_SOURCE, &pattern.base, NULL); _cairo_pattern_fini (&pattern.base); cairo_surface_destroy (image); image = rgba_image; if (unlikely (status)) { cairo_surface_destroy (image); return status; } } mask = _cairo_surface_create_similar_scratch (_dst, CAIRO_CONTENT_COLOR_ALPHA, extents->width, extents->height); if (unlikely (mask->status)) { cairo_surface_destroy (image); return mask->status; } status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask, (cairo_image_surface_t *)image, 0, 0, extents->width, extents->height, 0, 0); cairo_surface_destroy (image); if (unlikely (status)) goto error; _cairo_pattern_init_for_surface (&pattern, mask); cairo_matrix_init_translate (&pattern.base.matrix, -extents->x+dst_x, -extents->y+dst_y); pattern.base.filter = CAIRO_FILTER_NEAREST; pattern.base.extend = CAIRO_EXTEND_NONE; status = _cairo_gl_operand_init (operand, &pattern.base, _dst, &_cairo_unbounded_rectangle, &_cairo_unbounded_rectangle); _cairo_pattern_fini (&pattern.base); if (unlikely (status)) goto error; operand->texture.owns_surface = mask; return CAIRO_STATUS_SUCCESS; error: cairo_surface_destroy (mask); return status; }