diff options
Diffstat (limited to 'src/wld/pixman.c')
-rw-r--r-- | src/wld/pixman.c | 620 |
1 files changed, 289 insertions, 331 deletions
diff --git a/src/wld/pixman.c b/src/wld/pixman.c index 50a10ec..4f46119 100644 --- a/src/wld/pixman.c +++ b/src/wld/pixman.c @@ -24,427 +24,385 @@ #include "wld/pixman.h" #include "wld/wld-private.h" -#define PIXMAN_COLOR(c) { \ - .alpha = ((c >> 24) & 0xff) * 0x101, \ - .red = ((c >> 16) & 0xff) * 0x101, \ - .green = ((c >> 8) & 0xff) * 0x101, \ - .blue = ((c >> 0) & 0xff) * 0x101, \ -} - -struct pixman_renderer -{ - struct wld_renderer base; - pixman_image_t * target; - pixman_glyph_cache_t * glyph_cache; +#define PIXMAN_COLOR(c) \ + { \ + .alpha = ((c >> 24) & 0xff) * 0x101, .red = ((c >> 16) & 0xff) * 0x101, \ + .green = ((c >> 8) & 0xff) * 0x101, .blue = ((c >> 0) & 0xff) * 0x101, \ + } + +struct pixman_renderer { + struct wld_renderer base; + pixman_image_t *target; + pixman_glyph_cache_t *glyph_cache; }; -struct pixman_buffer -{ - struct buffer base; - pixman_image_t * image; +struct pixman_buffer { + struct buffer base; + pixman_image_t *image; }; -struct pixman_map -{ - struct wld_exporter exporter; - struct wld_destructor destructor; - pixman_image_t * image; +struct pixman_map { + struct wld_exporter exporter; + struct wld_destructor destructor; + pixman_image_t *image; }; #include "interface/context.h" #define RENDERER_IMPLEMENTS_REGION -#include "interface/renderer.h" #include "interface/buffer.h" +#include "interface/renderer.h" IMPL(pixman_renderer, wld_renderer) IMPL(pixman_buffer, wld_buffer) -static struct wld_context context = { .impl = &wld_context_impl }; +static struct wld_context context = {.impl = &wld_context_impl}; EXPORT -struct wld_context * wld_pixman_context = &context; +struct wld_context *wld_pixman_context = &context; -struct wld_renderer * context_create_renderer(struct wld_context * context) -{ - struct pixman_renderer * renderer; +struct wld_renderer *context_create_renderer(struct wld_context *context) { + struct pixman_renderer *renderer; - if (!(renderer = malloc(sizeof *renderer))) - goto error0; + if (!(renderer = malloc(sizeof *renderer))) + goto error0; - if (!(renderer->glyph_cache = pixman_glyph_cache_create())) - goto error1; + if (!(renderer->glyph_cache = pixman_glyph_cache_create())) + goto error1; - renderer_initialize(&renderer->base, &wld_renderer_impl); - renderer->target = NULL; + renderer_initialize(&renderer->base, &wld_renderer_impl); + renderer->target = NULL; - return &renderer->base; + return &renderer->base; - error1: - free(renderer); - error0: - return NULL; +error1: + free(renderer); +error0: + return NULL; } -static struct buffer * new_buffer(pixman_image_t * image) -{ - struct pixman_buffer * buffer; +static struct buffer *new_buffer(pixman_image_t *image) { + struct pixman_buffer *buffer; - if (!(buffer = malloc(sizeof *buffer))) - return NULL; + if (!(buffer = malloc(sizeof *buffer))) + return NULL; - buffer_initialize(&buffer->base, &wld_buffer_impl, - pixman_image_get_width(image), - pixman_image_get_height(image), - format_pixman_to_wld(pixman_image_get_format(image)), - pixman_image_get_stride(image)); - buffer->base.base.map = pixman_image_get_data(image); - buffer->image = image; + buffer_initialize(&buffer->base, &wld_buffer_impl, + pixman_image_get_width(image), + pixman_image_get_height(image), + format_pixman_to_wld(pixman_image_get_format(image)), + pixman_image_get_stride(image)); + buffer->base.base.map = pixman_image_get_data(image); + buffer->image = image; - return &buffer->base; + return &buffer->base; } -struct buffer * context_create_buffer(struct wld_context * context, - uint32_t width, uint32_t height, - uint32_t format, uint32_t flags) -{ - struct buffer * buffer; - pixman_image_t * image; +struct buffer *context_create_buffer(struct wld_context *context, + uint32_t width, uint32_t height, + uint32_t format, uint32_t flags) { + struct buffer *buffer; + pixman_image_t *image; - image = pixman_image_create_bits(format_wld_to_pixman(format), - width, height, NULL, 0); + image = pixman_image_create_bits(format_wld_to_pixman(format), width, height, + NULL, 0); - if (!image) - goto error0; + if (!image) + goto error0; - if (!(buffer = new_buffer(image))) - goto error1; + if (!(buffer = new_buffer(image))) + goto error1; - return buffer; + return buffer; - error1: - pixman_image_unref(image); - error0: - return NULL; +error1: + pixman_image_unref(image); +error0: + return NULL; } -struct buffer * context_import_buffer(struct wld_context * context, - uint32_t type, union wld_object object, - uint32_t width, uint32_t height, - uint32_t format, uint32_t pitch) -{ - struct buffer * buffer; - pixman_image_t * image; - - switch (type) - { - case WLD_OBJECT_DATA: - image = pixman_image_create_bits(format_wld_to_pixman(format), - width, height, object.ptr, pitch); - break; - default: image = NULL; - } - - if (!image) - goto error0; - - if (!(buffer = new_buffer(image))) - goto error1; - - return buffer; - - error1: - pixman_image_unref(image); - error0: - return NULL; - +struct buffer *context_import_buffer(struct wld_context *context, uint32_t type, + union wld_object object, uint32_t width, + uint32_t height, uint32_t format, + uint32_t pitch) { + struct buffer *buffer; + pixman_image_t *image; + + switch (type) { + case WLD_OBJECT_DATA: + image = pixman_image_create_bits(format_wld_to_pixman(format), width, + height, object.ptr, pitch); + break; + default: + image = NULL; + } + + if (!image) + goto error0; + + if (!(buffer = new_buffer(image))) + goto error1; + + return buffer; + +error1: + pixman_image_unref(image); +error0: + return NULL; } -void context_destroy(struct wld_context * context) -{ -} +void context_destroy(struct wld_context *context) {} -uint32_t renderer_capabilities(struct wld_renderer * renderer, - struct buffer * buffer) -{ - /* The pixman renderer can read and write to any buffer using it's map - * implementation. */ - return WLD_CAPABILITY_READ | WLD_CAPABILITY_WRITE; +uint32_t renderer_capabilities(struct wld_renderer *renderer, + struct buffer *buffer) { + /* The pixman renderer can read and write to any buffer using it's map + * implementation. */ + return WLD_CAPABILITY_READ | WLD_CAPABILITY_WRITE; } -static void destroy_image(pixman_image_t * image, void * data) -{ - struct buffer * buffer = data; +static void destroy_image(pixman_image_t *image, void *data) { + struct buffer *buffer = data; - wld_unmap(&buffer->base); + wld_unmap(&buffer->base); } -bool map_export(struct wld_exporter * exporter, struct wld_buffer * buffer, - uint32_t type, union wld_object * object) -{ - struct pixman_map * map - = CONTAINER_OF(exporter, struct pixman_map, exporter); - - switch (type) - { - case WLD_PIXMAN_OBJECT_IMAGE: - object->ptr = pixman_image_ref(map->image); - return true; - default: - return false; - } +bool map_export(struct wld_exporter *exporter, struct wld_buffer *buffer, + uint32_t type, union wld_object *object) { + struct pixman_map *map = CONTAINER_OF(exporter, struct pixman_map, exporter); + + switch (type) { + case WLD_PIXMAN_OBJECT_IMAGE: + object->ptr = pixman_image_ref(map->image); + return true; + default: + return false; + } } -void map_destroy(struct wld_destructor * destructor) -{ - struct pixman_map * map - = CONTAINER_OF(destructor, struct pixman_map, destructor); +void map_destroy(struct wld_destructor *destructor) { + struct pixman_map *map = + CONTAINER_OF(destructor, struct pixman_map, destructor); - pixman_image_unref(map->image); - free(map); + pixman_image_unref(map->image); + free(map); } -static pixman_image_t * pixman_image(struct buffer * buffer) -{ - if (buffer->base.impl == &wld_buffer_impl) - return pixman_image_ref(pixman_buffer(&buffer->base)->image); +static pixman_image_t *pixman_image(struct buffer *buffer) { + if (buffer->base.impl == &wld_buffer_impl) + return pixman_image_ref(pixman_buffer(&buffer->base)->image); - union wld_object object; + union wld_object object; - if (wld_export(&buffer->base, WLD_PIXMAN_OBJECT_IMAGE, &object)) - return object.ptr; + if (wld_export(&buffer->base, WLD_PIXMAN_OBJECT_IMAGE, &object)) + return object.ptr; - struct pixman_map * map; - pixman_image_t * image; + struct pixman_map *map; + pixman_image_t *image; - if (!wld_map(&buffer->base)) - goto error0; + if (!wld_map(&buffer->base)) + goto error0; - image = pixman_image_create_bits(format_wld_to_pixman(buffer->base.format), - buffer->base.width, buffer->base.height, - buffer->base.map, buffer->base.pitch); + image = pixman_image_create_bits(format_wld_to_pixman(buffer->base.format), + buffer->base.width, buffer->base.height, + buffer->base.map, buffer->base.pitch); - if (!image) - goto error1; + if (!image) + goto error1; - if (!(map = malloc(sizeof *map))) - goto error2; + if (!(map = malloc(sizeof *map))) + goto error2; - map->image = image; - map->exporter.export = &map_export; - wld_buffer_add_exporter(&buffer->base, &map->exporter); - map->destructor.destroy = &map_destroy; - wld_buffer_add_destructor(&buffer->base, &map->destructor); - pixman_image_set_destroy_function(image, &destroy_image, buffer); + map->image = image; + map->exporter.export = &map_export; + wld_buffer_add_exporter(&buffer->base, &map->exporter); + map->destructor.destroy = &map_destroy; + wld_buffer_add_destructor(&buffer->base, &map->destructor); + pixman_image_set_destroy_function(image, &destroy_image, buffer); - return pixman_image_ref(image); + return pixman_image_ref(image); - error2: - pixman_image_unref(image); - error1: - wld_unmap(&buffer->base); - error0: - return NULL; +error2: + pixman_image_unref(image); +error1: + wld_unmap(&buffer->base); +error0: + return NULL; } -bool renderer_set_target(struct wld_renderer * base, struct buffer * buffer) -{ - struct pixman_renderer * renderer = pixman_renderer(base); +bool renderer_set_target(struct wld_renderer *base, struct buffer *buffer) { + struct pixman_renderer *renderer = pixman_renderer(base); - if (renderer->target) - pixman_image_unref(renderer->target); + if (renderer->target) + pixman_image_unref(renderer->target); - if (buffer) - return (renderer->target = pixman_image(buffer)); + if (buffer) + return (renderer->target = pixman_image(buffer)); - renderer->target = NULL; - return true; + renderer->target = NULL; + return true; } -void renderer_fill_rectangle(struct wld_renderer * base, uint32_t color, - int32_t x, int32_t y, - uint32_t width, uint32_t height) -{ - struct pixman_renderer * renderer = pixman_renderer(base); - pixman_color_t pixman_color = PIXMAN_COLOR(color); - pixman_box32_t box = { x, y, x + width, y + height }; +void renderer_fill_rectangle(struct wld_renderer *base, uint32_t color, + int32_t x, int32_t y, uint32_t width, + uint32_t height) { + struct pixman_renderer *renderer = pixman_renderer(base); + pixman_color_t pixman_color = PIXMAN_COLOR(color); + pixman_box32_t box = {x, y, x + width, y + height}; - pixman_image_fill_boxes(PIXMAN_OP_SRC, renderer->target, - &pixman_color, 1, &box); + pixman_image_fill_boxes(PIXMAN_OP_SRC, renderer->target, &pixman_color, 1, + &box); } -void renderer_fill_region(struct wld_renderer * base, uint32_t color, - pixman_region32_t * region) -{ - struct pixman_renderer * renderer = pixman_renderer(base); - pixman_color_t pixman_color = PIXMAN_COLOR(color); - pixman_box32_t * boxes; - int num_boxes; - - boxes = pixman_region32_rectangles(region, &num_boxes); - pixman_image_fill_boxes(PIXMAN_OP_SRC, renderer->target, - &pixman_color, num_boxes, boxes); +void renderer_fill_region(struct wld_renderer *base, uint32_t color, + pixman_region32_t *region) { + struct pixman_renderer *renderer = pixman_renderer(base); + pixman_color_t pixman_color = PIXMAN_COLOR(color); + pixman_box32_t *boxes; + int num_boxes; + + boxes = pixman_region32_rectangles(region, &num_boxes); + pixman_image_fill_boxes(PIXMAN_OP_SRC, renderer->target, &pixman_color, + num_boxes, boxes); } -void renderer_copy_rectangle(struct wld_renderer * base, struct buffer * buffer, - int32_t dst_x, int32_t dst_y, - int32_t src_x, int32_t src_y, - uint32_t width, uint32_t height) -{ - struct pixman_renderer * renderer = pixman_renderer(base); - pixman_image_t * src = pixman_image(buffer), * dst = renderer->target; +void renderer_copy_rectangle(struct wld_renderer *base, struct buffer *buffer, + int32_t dst_x, int32_t dst_y, int32_t src_x, + int32_t src_y, uint32_t width, uint32_t height) { + struct pixman_renderer *renderer = pixman_renderer(base); + pixman_image_t *src = pixman_image(buffer), *dst = renderer->target; - if (!src) return; + if (!src) + return; - pixman_image_composite32(PIXMAN_OP_SRC, src, NULL, dst, - src_x, src_y, 0, 0, dst_x, dst_y, width, height); + pixman_image_composite32(PIXMAN_OP_SRC, src, NULL, dst, src_x, src_y, 0, 0, + dst_x, dst_y, width, height); } -void renderer_copy_region(struct wld_renderer * base, struct buffer * buffer, +void renderer_copy_region(struct wld_renderer *base, struct buffer *buffer, int32_t dst_x, int32_t dst_y, - pixman_region32_t * region) -{ - struct pixman_renderer * renderer = pixman_renderer(base); - pixman_image_t * src = pixman_image(buffer), * dst = renderer->target; - - if (!src) return; - - pixman_image_set_clip_region32(src, region); - pixman_image_composite32(PIXMAN_OP_SRC, src, NULL, dst, - region->extents.x1, region->extents.y1, 0, 0, - region->extents.x1 + dst_x, - region->extents.y1 + dst_y, - region->extents.x2 - region->extents.x1, - region->extents.y2 - region->extents.y1); - pixman_image_set_clip_region32(src, NULL); + pixman_region32_t *region) { + struct pixman_renderer *renderer = pixman_renderer(base); + pixman_image_t *src = pixman_image(buffer), *dst = renderer->target; + + if (!src) + return; + + pixman_image_set_clip_region32(src, region); + pixman_image_composite32(PIXMAN_OP_SRC, src, NULL, dst, region->extents.x1, + region->extents.y1, 0, 0, region->extents.x1 + dst_x, + region->extents.y1 + dst_y, + region->extents.x2 - region->extents.x1, + region->extents.y2 - region->extents.y1); + pixman_image_set_clip_region32(src, NULL); } -static inline uint8_t reverse(uint8_t byte) -{ - byte = ((byte << 1) & 0xaa) | ((byte >> 1) & 0x55); - byte = ((byte << 2) & 0xcc) | ((byte >> 2) & 0x33); - byte = ((byte << 4) & 0xf0) | ((byte >> 4) & 0x0f); +static inline uint8_t reverse(uint8_t byte) { + byte = ((byte << 1) & 0xaa) | ((byte >> 1) & 0x55); + byte = ((byte << 2) & 0xcc) | ((byte >> 2) & 0x33); + byte = ((byte << 4) & 0xf0) | ((byte >> 4) & 0x0f); - return byte; + return byte; } -void renderer_draw_text(struct wld_renderer * base, - struct font * font, uint32_t color, - int32_t x, int32_t y, const char * text, - uint32_t length, struct wld_extents * extents) -{ - struct pixman_renderer * renderer = pixman_renderer(base); - int ret; - uint32_t c; - struct glyph * glyph; - FT_UInt glyph_index; - pixman_glyph_t glyphs[length == -1 ? (length = strlen(text)) : length]; - uint32_t index = 0, origin_x = 0; - pixman_color_t pixman_color = PIXMAN_COLOR(color); - pixman_image_t * solid; - - solid = pixman_image_create_solid_fill(&pixman_color); - - while ((ret = FcUtf8ToUcs4((FcChar8 *) text, &c, length)) > 0 && c != '\0') - { - text += ret; - length -= ret; - glyph_index = FT_Get_Char_Index(font->face, c); - - if (!font_ensure_glyph(font, glyph_index)) - continue; - - glyph = font->glyphs[glyph_index]; - - glyphs[index].x = origin_x; - glyphs[index].y = 0; - glyphs[index].glyph = pixman_glyph_cache_lookup(renderer->glyph_cache, - font, glyph); - - /* If we don't have the glyph in our cache, do some conversions to make - * pixman happy, and then insert it. */ - if (!glyphs[index].glyph) - { - uint8_t * src, * dst; - uint32_t row, byte_index, bytes_per_row, pitch; - pixman_image_t * image; - FT_Bitmap * bitmap; - - bitmap = &glyph->bitmap; - image = pixman_image_create_bits - (PIXMAN_a1, bitmap->width, bitmap->rows, NULL, bitmap->pitch); - - if (!image) - goto advance; - - pitch = pixman_image_get_stride(image); - bytes_per_row = (bitmap->width + 7) / 8; - src = bitmap->buffer; - dst = (uint8_t *) pixman_image_get_data(image); - - for (row = 0; row < bitmap->rows; ++row) - { - /* Pixman's A1 format expects the bits in the opposite order - * that Freetype gives us. Sigh... */ - for (byte_index = 0; byte_index < bytes_per_row; ++byte_index) - dst[byte_index] = reverse(src[byte_index]); - - dst += pitch; - src += bitmap->pitch; - } - - /* Insert the glyph into the cache. */ - pixman_glyph_cache_freeze(renderer->glyph_cache); - glyphs[index].glyph = pixman_glyph_cache_insert - (renderer->glyph_cache, font, glyph, - -glyph->x, -glyph->y, image); - pixman_glyph_cache_thaw(renderer->glyph_cache); - - /* The glyph cache copies the contents of the glyph bitmap. */ - pixman_image_unref(image); - } - - ++index; - - advance: - origin_x += glyph->advance; +void renderer_draw_text(struct wld_renderer *base, struct font *font, + uint32_t color, int32_t x, int32_t y, const char *text, + uint32_t length, struct wld_extents *extents) { + struct pixman_renderer *renderer = pixman_renderer(base); + int ret; + uint32_t c; + struct glyph *glyph; + FT_UInt glyph_index; + pixman_glyph_t glyphs[length == -1 ? (length = strlen(text)) : length]; + uint32_t index = 0, origin_x = 0; + pixman_color_t pixman_color = PIXMAN_COLOR(color); + pixman_image_t *solid; + + solid = pixman_image_create_solid_fill(&pixman_color); + + while ((ret = FcUtf8ToUcs4((FcChar8 *)text, &c, length)) > 0 && c != '\0') { + text += ret; + length -= ret; + glyph_index = FT_Get_Char_Index(font->face, c); + + if (!font_ensure_glyph(font, glyph_index)) + continue; + + glyph = font->glyphs[glyph_index]; + + glyphs[index].x = origin_x; + glyphs[index].y = 0; + glyphs[index].glyph = + pixman_glyph_cache_lookup(renderer->glyph_cache, font, glyph); + + /* If we don't have the glyph in our cache, do some conversions to make + * pixman happy, and then insert it. */ + if (!glyphs[index].glyph) { + uint8_t *src, *dst; + uint32_t row, byte_index, bytes_per_row, pitch; + pixman_image_t *image; + FT_Bitmap *bitmap; + + bitmap = &glyph->bitmap; + image = pixman_image_create_bits(PIXMAN_a1, bitmap->width, bitmap->rows, + NULL, bitmap->pitch); + + if (!image) + goto advance; + + pitch = pixman_image_get_stride(image); + bytes_per_row = (bitmap->width + 7) / 8; + src = bitmap->buffer; + dst = (uint8_t *)pixman_image_get_data(image); + + for (row = 0; row < bitmap->rows; ++row) { + /* Pixman's A1 format expects the bits in the opposite order + * that Freetype gives us. Sigh... */ + for (byte_index = 0; byte_index < bytes_per_row; ++byte_index) + dst[byte_index] = reverse(src[byte_index]); + + dst += pitch; + src += bitmap->pitch; + } + + /* Insert the glyph into the cache. */ + pixman_glyph_cache_freeze(renderer->glyph_cache); + glyphs[index].glyph = pixman_glyph_cache_insert( + renderer->glyph_cache, font, glyph, -glyph->x, -glyph->y, image); + pixman_glyph_cache_thaw(renderer->glyph_cache); + + /* The glyph cache copies the contents of the glyph bitmap. */ + pixman_image_unref(image); } - pixman_composite_glyphs_no_mask(PIXMAN_OP_OVER, solid, renderer->target, - 0, 0, x, y, renderer->glyph_cache, - index, glyphs); + ++index; - pixman_image_unref(solid); + advance: + origin_x += glyph->advance; + } - if (extents) - extents->advance = origin_x; -} + pixman_composite_glyphs_no_mask(PIXMAN_OP_OVER, solid, renderer->target, 0, 0, + x, y, renderer->glyph_cache, index, glyphs); -void renderer_flush(struct wld_renderer * renderer) -{ + pixman_image_unref(solid); + + if (extents) + extents->advance = origin_x; } -void renderer_destroy(struct wld_renderer * base) -{ - struct pixman_renderer * renderer = pixman_renderer(base); +void renderer_flush(struct wld_renderer *renderer) {} - pixman_glyph_cache_destroy(renderer->glyph_cache); - free(renderer); -} +void renderer_destroy(struct wld_renderer *base) { + struct pixman_renderer *renderer = pixman_renderer(base); -bool buffer_map(struct buffer * buffer) -{ - return true; + pixman_glyph_cache_destroy(renderer->glyph_cache); + free(renderer); } -bool buffer_unmap(struct buffer * buffer) -{ - return true; -} +bool buffer_map(struct buffer *buffer) { return true; } -void buffer_destroy(struct buffer * base) -{ - struct pixman_buffer * buffer = pixman_buffer(&base->base); +bool buffer_unmap(struct buffer *buffer) { return true; } - pixman_image_unref(buffer->image); - free(buffer); -} +void buffer_destroy(struct buffer *base) { + struct pixman_buffer *buffer = pixman_buffer(&base->base); + pixman_image_unref(buffer->image); + free(buffer); +} |