From ad18ef5db99eb38075e6e49246b097a8ba727ab8 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 15 Apr 2015 23:57:39 +0100 Subject: [PATCH] Update RISC OS frontend to use bitmap operation table --- riscos/bitmap.c | 318 +++++++++++++++++++++++---------------------- riscos/bitmap.h | 17 ++- riscos/gui.c | 2 + riscos/plotters.c | 4 +- riscos/save.c | 6 +- riscos/save_draw.c | 2 +- riscos/thumbnail.c | 16 +-- riscos/window.c | 6 +- 8 files changed, 199 insertions(+), 172 deletions(-) diff --git a/riscos/bitmap.c b/riscos/bitmap.c index 2c700ec7d..c232f20bd 100644 --- a/riscos/bitmap.c +++ b/riscos/bitmap.c @@ -30,22 +30,24 @@ #include #include #include -#include "oslib/osfile.h" -#include "oslib/osfind.h" -#include "oslib/osgbpb.h" -#include "oslib/osspriteop.h" -#include "oslib/wimp.h" -#include "content/content.h" -#include "image/bitmap.h" -#include "riscos/bitmap.h" -#include "riscos/image.h" +#include +#include +#include +#include +#include + #include "utils/nsoption.h" -#include "riscos/palettes.h" -#include "riscos/content-handlers/sprite.h" -#include "riscos/tinct.h" #include "utils/filename.h" #include "utils/log.h" #include "utils/utils.h" +#include "content/content.h" +#include "image/bitmap.h" + +#include "riscos/image.h" +#include "riscos/palettes.h" +#include "riscos/content-handlers/sprite.h" +#include "riscos/tinct.h" +#include "riscos/bitmap.h" /** Colour in the overlay sprite that allows the bitmap to show through */ #define OVERLAY_INDEX 0xfe @@ -109,8 +111,7 @@ static bool bitmap_initialise(struct bitmap *bitmap) * \param state the state to create the bitmap in. * \return an opaque struct bitmap, or NULL on memory exhaustion */ - -void *bitmap_create(int width, int height, unsigned int state) +void *riscos_bitmap_create(int width, int height, unsigned int state) { struct bitmap *bitmap; @@ -129,91 +130,30 @@ void *bitmap_create(int width, int height, unsigned int state) /** - * Overlay a sprite onto the given bitmap + * Return a pointer to the pixel data in a bitmap. * - * \param bitmap bitmap object - * \param s 8bpp sprite to be overlayed onto bitmap + * The pixel data is packed as BITMAP_FORMAT, possibly with padding at the end + * of rows. The width of a row in bytes is given by bitmap_get_rowstride(). + * + * \param vbitmap a bitmap, as returned by bitmap_create() + * \return pointer to the pixel buffer */ - -void bitmap_overlay_sprite(struct bitmap *bitmap, const osspriteop_header *s) +unsigned char *riscos_bitmap_get_buffer(void *vbitmap) { - const os_colour *palette; - const byte *sp, *mp; - bool masked = false; - bool alpha = false; - os_error *error; - int dp_offset; - int sp_offset; - unsigned *dp; - int x, y; - int w, h; + struct bitmap *bitmap = (struct bitmap *) vbitmap; + assert(bitmap); - assert(sprite_bpp(s) == 8); - - if ((unsigned)s->mode & 0x80000000U) - alpha = true; - - error = xosspriteop_read_sprite_info(osspriteop_PTR, - (osspriteop_area *)0x100, - (osspriteop_id)s, - &w, &h, NULL, NULL); - if (error) { - LOG(("xosspriteop_read_sprite_info: 0x%x:%s", - error->errnum, error->errmess)); - return; - } - sp_offset = ((s->width + 1) * 4) - w; - - if (w > bitmap->width) - w = bitmap->width; - if (h > bitmap->height) - h = bitmap->height; - - dp_offset = bitmap_get_rowstride(bitmap) / 4; - - dp = (void*)bitmap_get_buffer(bitmap); - if (!dp) - return; - sp = (byte*)s + s->image; - mp = (byte*)s + s->mask; - - sp += s->left_bit / 8; - mp += s->left_bit / 8; - - if (s->image > (int)sizeof(*s)) - palette = (os_colour*)(s + 1); - else - palette = default_palette8; - - if (s->mask != s->image) { - masked = true; - bitmap_set_opaque(bitmap, false); + /* dynamically create the buffer */ + if (bitmap->sprite_area == NULL) { + if (!bitmap_initialise(bitmap)) + return NULL; } - /* (partially-)transparent pixels in the overlayed sprite retain - * their transparency in the output bitmap; opaque sprite pixels - * are also propagated to the bitmap, except those which are the - * OVERLAY_INDEX colour which allow the original bitmap contents to - * show through */ - for (y = 0; y < h; y++) { - unsigned *sdp = dp; - for(x = 0; x < w; x++) { - os_colour d = ((unsigned)palette[(*sp) << 1]) >> 8; - if (*sp++ == OVERLAY_INDEX) - d = *dp; - if (masked) { - if (alpha) - d |= ((*mp << 24) ^ 0xff000000U); - else if (*mp) - d |= 0xff000000U; - } - *dp++ = d; - mp++; - } - dp = sdp + dp_offset; - sp += sp_offset; - mp += sp_offset; - } + /* image data area should exist */ + if (bitmap->sprite_area) + return ((unsigned char *) (bitmap->sprite_area)) + 16 + 44; + + return NULL; } @@ -223,7 +163,7 @@ void bitmap_overlay_sprite(struct bitmap *bitmap, const osspriteop_header *s) * \param vbitmap a bitmap, as returned by bitmap_create() * \param opaque whether the bitmap should be plotted opaque */ -void bitmap_set_opaque(void *vbitmap, bool opaque) +static void bitmap_set_opaque(void *vbitmap, bool opaque) { struct bitmap *bitmap = (struct bitmap *) vbitmap; assert(bitmap); @@ -235,13 +175,26 @@ void bitmap_set_opaque(void *vbitmap, bool opaque) } +/** + * Find the width of a pixel row in bytes. + * + * \param vbitmap a bitmap, as returned by bitmap_create() + * \return width of a pixel row in the bitmap + */ +size_t riscos_bitmap_get_rowstride(void *vbitmap) +{ + struct bitmap *bitmap = (struct bitmap *) vbitmap; + return bitmap->width * 4; +} + + /** * Tests whether a bitmap has an opaque alpha channel * * \param vbitmap a bitmap, as returned by bitmap_create() * \return whether the bitmap is opaque */ -bool bitmap_test_opaque(void *vbitmap) +static bool bitmap_test_opaque(void *vbitmap) { struct bitmap *bitmap = (struct bitmap *) vbitmap; unsigned char *sprite; @@ -251,11 +204,11 @@ bool bitmap_test_opaque(void *vbitmap) assert(bitmap); - sprite = bitmap_get_buffer(bitmap); + sprite = riscos_bitmap_get_buffer(bitmap); if (!sprite) return false; - width = bitmap_get_rowstride(bitmap); + width = riscos_bitmap_get_rowstride(bitmap); sprite_header = (osspriteop_header *) (bitmap->sprite_area + 1); @@ -289,7 +242,7 @@ bool bitmap_test_opaque(void *vbitmap) * * \param vbitmap a bitmap, as returned by bitmap_create() */ -bool bitmap_get_opaque(void *vbitmap) +bool riscos_bitmap_get_opaque(void *vbitmap) { struct bitmap *bitmap = (struct bitmap *) vbitmap; assert(bitmap); @@ -297,56 +250,12 @@ bool bitmap_get_opaque(void *vbitmap) } -/** - * Return a pointer to the pixel data in a bitmap. - * - * The pixel data is packed as BITMAP_FORMAT, possibly with padding at the end - * of rows. The width of a row in bytes is given by bitmap_get_rowstride(). - * - * \param vbitmap a bitmap, as returned by bitmap_create() - * \return pointer to the pixel buffer - */ - -unsigned char *bitmap_get_buffer(void *vbitmap) -{ - struct bitmap *bitmap = (struct bitmap *) vbitmap; - assert(bitmap); - - /* dynamically create the buffer */ - if (bitmap->sprite_area == NULL) { - if (!bitmap_initialise(bitmap)) - return NULL; - } - - /* image data area should exist */ - if (bitmap->sprite_area) - return ((unsigned char *) (bitmap->sprite_area)) + 16 + 44; - - return NULL; -} - - -/** - * Find the width of a pixel row in bytes. - * - * \param vbitmap a bitmap, as returned by bitmap_create() - * \return width of a pixel row in the bitmap - */ - -size_t bitmap_get_rowstride(void *vbitmap) -{ - struct bitmap *bitmap = (struct bitmap *) vbitmap; - return bitmap->width * 4; -} - - /** * Free a bitmap. * * \param vbitmap a bitmap, as returned by bitmap_create() */ - -void bitmap_destroy(void *vbitmap) +void riscos_bitmap_destroy(void *vbitmap) { struct bitmap *bitmap = (struct bitmap *) vbitmap; @@ -369,18 +278,18 @@ void bitmap_destroy(void *vbitmap) * \param flags modify the behaviour of the save * \return true on success, false on error and error reported */ - -bool bitmap_save(void *vbitmap, const char *path, unsigned flags) +bool riscos_bitmap_save(void *vbitmap, const char *path, unsigned flags) { struct bitmap *bitmap = (struct bitmap *) vbitmap; os_error *error; - if (!bitmap->sprite_area) - bitmap_get_buffer(bitmap); + if (!bitmap->sprite_area) { + riscos_bitmap_get_buffer(bitmap); + } if (!bitmap->sprite_area) return false; - if (bitmap_get_opaque(bitmap)) { + if (riscos_bitmap_get_opaque(bitmap)) { error = xosspriteop_save_sprite_file(osspriteop_USER_AREA, (bitmap->sprite_area), path); if (error) { @@ -539,20 +448,21 @@ bool bitmap_save(void *vbitmap, const char *path, unsigned flags) * * \param vbitmap a bitmap, as returned by bitmap_create() */ -void bitmap_modified(void *vbitmap) { +void riscos_bitmap_modified(void *vbitmap) +{ struct bitmap *bitmap = (struct bitmap *) vbitmap; bitmap->state |= BITMAP_MODIFIED; } -int bitmap_get_width(void *vbitmap) +int riscos_bitmap_get_width(void *vbitmap) { struct bitmap *bitmap = (struct bitmap *) vbitmap; return bitmap->width; } -int bitmap_get_height(void *vbitmap) +int riscos_bitmap_get_height(void *vbitmap) { struct bitmap *bitmap = (struct bitmap *) vbitmap; return bitmap->height; @@ -565,11 +475,113 @@ int bitmap_get_height(void *vbitmap) * \param vbitmap a bitmap, as returned by bitmap_create() * \return bytes per pixel */ - -size_t bitmap_get_bpp(void *vbitmap) +static size_t bitmap_get_bpp(void *vbitmap) { struct bitmap *bitmap = (struct bitmap *)vbitmap; assert(bitmap); return 4; } +/** + * Overlay a sprite onto the given bitmap + * + * \param bitmap bitmap object + * \param s 8bpp sprite to be overlayed onto bitmap + */ +void riscos_bitmap_overlay_sprite(struct bitmap *bitmap, const osspriteop_header *s) +{ + const os_colour *palette; + const byte *sp, *mp; + bool masked = false; + bool alpha = false; + os_error *error; + int dp_offset; + int sp_offset; + unsigned *dp; + int x, y; + int w, h; + + assert(sprite_bpp(s) == 8); + + if ((unsigned)s->mode & 0x80000000U) + alpha = true; + + error = xosspriteop_read_sprite_info(osspriteop_PTR, + (osspriteop_area *)0x100, + (osspriteop_id)s, + &w, &h, NULL, NULL); + if (error) { + LOG(("xosspriteop_read_sprite_info: 0x%x:%s", + error->errnum, error->errmess)); + return; + } + sp_offset = ((s->width + 1) * 4) - w; + + if (w > bitmap->width) + w = bitmap->width; + if (h > bitmap->height) + h = bitmap->height; + + dp_offset = riscos_bitmap_get_rowstride(bitmap) / 4; + + dp = (void*)riscos_bitmap_get_buffer(bitmap); + if (!dp) + return; + sp = (byte*)s + s->image; + mp = (byte*)s + s->mask; + + sp += s->left_bit / 8; + mp += s->left_bit / 8; + + if (s->image > (int)sizeof(*s)) + palette = (os_colour*)(s + 1); + else + palette = default_palette8; + + if (s->mask != s->image) { + masked = true; + bitmap_set_opaque(bitmap, false); + } + + /* (partially-)transparent pixels in the overlayed sprite retain + * their transparency in the output bitmap; opaque sprite pixels + * are also propagated to the bitmap, except those which are the + * OVERLAY_INDEX colour which allow the original bitmap contents to + * show through */ + for (y = 0; y < h; y++) { + unsigned *sdp = dp; + for(x = 0; x < w; x++) { + os_colour d = ((unsigned)palette[(*sp) << 1]) >> 8; + if (*sp++ == OVERLAY_INDEX) + d = *dp; + if (masked) { + if (alpha) + d |= ((*mp << 24) ^ 0xff000000U); + else if (*mp) + d |= 0xff000000U; + } + *dp++ = d; + mp++; + } + dp = sdp + dp_offset; + sp += sp_offset; + mp += sp_offset; + } +} + +static struct gui_bitmap_table bitmap_table = { + .create = riscos_bitmap_create, + .destroy = riscos_bitmap_destroy, + .set_opaque = bitmap_set_opaque, + .get_opaque = riscos_bitmap_get_opaque, + .test_opaque = bitmap_test_opaque, + .get_buffer = riscos_bitmap_get_buffer, + .get_rowstride = riscos_bitmap_get_rowstride, + .get_width = riscos_bitmap_get_width, + .get_height = riscos_bitmap_get_height, + .get_bpp = bitmap_get_bpp, + .save = riscos_bitmap_save, + .modified = riscos_bitmap_modified, +}; + +struct gui_bitmap_table *riscos_bitmap_table = &bitmap_table; diff --git a/riscos/bitmap.h b/riscos/bitmap.h index 1b7d1b9a9..1ae50fd71 100644 --- a/riscos/bitmap.h +++ b/riscos/bitmap.h @@ -19,11 +19,15 @@ #ifndef _NETSURF_RISCOS_BITMAP_H_ #define _NETSURF_RISCOS_BITMAP_H_ +/** bitmap operations table */ +struct gui_bitmap_table *riscos_bitmap_table; + #include #include "oslib/osspriteop.h" #include "image/bitmap.h" -#define BITMAP_SAVE_FULL_ALPHA (1 << 0) /** save with full alpha channel (if not opaque) */ +/** save with full alpha channel (if not opaque) */ +#define BITMAP_SAVE_FULL_ALPHA (1 << 0) struct osspriteop_area; @@ -36,6 +40,15 @@ struct bitmap { osspriteop_area *sprite_area; /** Uncompressed data, or NULL */ }; -void bitmap_overlay_sprite(struct bitmap *bitmap, const osspriteop_header *s); +void riscos_bitmap_overlay_sprite(struct bitmap *bitmap, const osspriteop_header *s); +void riscos_bitmap_destroy(void *vbitmap); +void *riscos_bitmap_create(int width, int height, unsigned int state); +unsigned char *riscos_bitmap_get_buffer(void *vbitmap); +void riscos_bitmap_modified(void *vbitmap); +int riscos_bitmap_get_width(void *vbitmap); +int riscos_bitmap_get_height(void *vbitmap); +size_t riscos_bitmap_get_rowstride(void *vbitmap); +bool riscos_bitmap_get_opaque(void *vbitmap); +bool riscos_bitmap_save(void *vbitmap, const char *path, unsigned flags); #endif diff --git a/riscos/gui.c b/riscos/gui.c index 3fd113c93..6a861c295 100644 --- a/riscos/gui.c +++ b/riscos/gui.c @@ -58,6 +58,7 @@ #include "content/backing_store.h" #include "riscos/gui.h" +#include "riscos/bitmap.h" #include "riscos/wimputils.h" #include "riscos/hotlist.h" #include "riscos/buffer.h" @@ -2446,6 +2447,7 @@ int main(int argc, char** argv) .utf8 = riscos_utf8_table, .search = riscos_search_table, .llcache = filesystem_llcache_table, + .bitmap = riscos_bitmap_table, }; ret = netsurf_register(&riscos_table); diff --git a/riscos/plotters.c b/riscos/plotters.c index d35d1f0c6..e23242e74 100644 --- a/riscos/plotters.c +++ b/riscos/plotters.c @@ -519,7 +519,7 @@ bool ro_plot_bitmap(int x, int y, int width, int height, { const uint8_t *buffer; - buffer = bitmap_get_buffer(bitmap); + buffer = riscos_bitmap_get_buffer(bitmap); if (!buffer) { LOG(("bitmap_get_buffer failed")); return false; @@ -534,6 +534,6 @@ bool ro_plot_bitmap(int x, int y, int width, int height, bg, flags & BITMAPF_REPEAT_X, flags & BITMAPF_REPEAT_Y, flags & BITMAPF_REPEAT_X || flags & BITMAPF_REPEAT_Y, - bitmap_get_opaque(bitmap) ? IMAGE_PLOT_TINCT_OPAQUE : + riscos_bitmap_get_opaque(bitmap) ? IMAGE_PLOT_TINCT_OPAQUE : IMAGE_PLOT_TINCT_ALPHA); } diff --git a/riscos/save.c b/riscos/save.c index 7b6023963..6b27db470 100644 --- a/riscos/save.c +++ b/riscos/save.c @@ -1144,7 +1144,7 @@ bool ro_gui_save_object_native(hlcache_handle *h, char *path) { unsigned flags = (os_version == 0xA9) ? BITMAP_SAVE_FULL_ALPHA : 0; - bitmap_save(content_get_bitmap(h), path, flags); + riscos_bitmap_save(content_get_bitmap(h), path, flags); } break; case osfile_TYPE_DRAW: @@ -1370,14 +1370,14 @@ bool ro_gui_save_create_thumbnail(hlcache_handle *h, const char *name) struct bitmap *bitmap; osspriteop_area *area; - bitmap = bitmap_create(34, 34, BITMAP_NEW | BITMAP_OPAQUE | BITMAP_CLEAR_MEMORY); + bitmap = riscos_bitmap_create(34, 34, BITMAP_NEW | BITMAP_OPAQUE | BITMAP_CLEAR_MEMORY); if (!bitmap) { LOG(("Thumbnail initialisation failed.")); return false; } thumbnail_create(h, bitmap); area = thumbnail_convert_8bpp(bitmap); - bitmap_destroy(bitmap); + riscos_bitmap_destroy(bitmap); if (!area) { LOG(("Thumbnail conversion failed.")); return false; diff --git a/riscos/save_draw.c b/riscos/save_draw.c index fe14071ee..bf81bca10 100644 --- a/riscos/save_draw.c +++ b/riscos/save_draw.c @@ -400,7 +400,7 @@ bool ro_save_draw_bitmap(int x, int y, int width, int height, pencil_code code; const uint8_t *buffer; - buffer = bitmap_get_buffer(bitmap); + buffer = riscos_bitmap_get_buffer(bitmap); if (!buffer) { warn_user("NoMemory", 0); return false; diff --git a/riscos/thumbnail.c b/riscos/thumbnail.c index 6613b0e6a..ee21747f5 100644 --- a/riscos/thumbnail.c +++ b/riscos/thumbnail.c @@ -108,7 +108,7 @@ bool thumbnail_create(hlcache_handle *content, struct bitmap *bitmap) return false; sprite_header = (osspriteop_header *)(sprite_area + 1); } else { - const uint8_t *pixbufp = bitmap_get_buffer(bitmap); + const uint8_t *pixbufp = riscos_bitmap_get_buffer(bitmap); if (!pixbufp || !bitmap->sprite_area) return false; sprite_area = bitmap->sprite_area; @@ -137,7 +137,7 @@ bool thumbnail_create(hlcache_handle *content, struct bitmap *bitmap) /* if we changed to 8bpp then go back to 32bpp */ if (thumbnail_32bpp_available != 1) { - const uint8_t *pixbufp = bitmap_get_buffer(bitmap); + const uint8_t *pixbufp = riscos_bitmap_get_buffer(bitmap); _kernel_oserror *error; if (!pixbufp || !bitmap->sprite_area) { @@ -152,7 +152,7 @@ bool thumbnail_create(hlcache_handle *content, struct bitmap *bitmap) return false; } - bitmap_modified(bitmap); + riscos_bitmap_modified(bitmap); return true; } @@ -190,13 +190,13 @@ osspriteop_area *thumbnail_convert_8bpp(struct bitmap *bitmap) if (sprite_header->image != sprite_header->mask) { /* build the sprite mask from the alpha channel */ - void *buf = bitmap_get_buffer(bitmap); + void *buf = riscos_bitmap_get_buffer(bitmap); unsigned *dp = (unsigned *) buf; if (!dp) return sprite_area; - int w = bitmap_get_width(bitmap); - int h = bitmap_get_height(bitmap); - int dp_offset = bitmap_get_rowstride(bitmap) / 4 - w; + int w = riscos_bitmap_get_width(bitmap); + int h = riscos_bitmap_get_height(bitmap); + int dp_offset = riscos_bitmap_get_rowstride(bitmap) / 4 - w; int mp_offset = ((sprite_header->width + 1) * 4) - w; byte *mp = (byte*)sprite_header + sprite_header->mask; bool alpha = ((unsigned)sprite_header->mode & 0x80000000U) != 0; @@ -228,7 +228,7 @@ osspriteop_area *thumbnail_convert_8bpp(struct bitmap *bitmap) osspriteop_area *thumbnail_create_8bpp(struct bitmap *bitmap) { unsigned image_size = ((bitmap->width + 3) & ~3) * bitmap->height; - bool opaque = bitmap_get_opaque(bitmap); + bool opaque = riscos_bitmap_get_opaque(bitmap); osspriteop_header *sprite_header = NULL; osspriteop_area *sprite_area = NULL; unsigned area_size; diff --git a/riscos/window.c b/riscos/window.c index fae756646..4f281b919 100644 --- a/riscos/window.c +++ b/riscos/window.c @@ -3411,7 +3411,7 @@ void ro_gui_window_iconise(struct gui_window *g, } /* create the thumbnail sprite */ - bitmap = bitmap_create(width, height, BITMAP_NEW | BITMAP_OPAQUE | + bitmap = riscos_bitmap_create(width, height, BITMAP_NEW | BITMAP_OPAQUE | BITMAP_CLEAR_MEMORY); if (!bitmap) { LOG(("Thumbnail initialisation failed.")); @@ -3419,10 +3419,10 @@ void ro_gui_window_iconise(struct gui_window *g, } thumbnail_create(h, bitmap); if (overlay) { - bitmap_overlay_sprite(bitmap, overlay); + riscos_bitmap_overlay_sprite(bitmap, overlay); } area = thumbnail_convert_8bpp(bitmap); - bitmap_destroy(bitmap); + riscos_bitmap_destroy(bitmap); if (!area) { LOG(("Thumbnail conversion failed.")); return;