diff options
Diffstat (limited to 'frontends/riscos/bitmap.c')
-rw-r--r-- | frontends/riscos/bitmap.c | 876 |
1 files changed, 876 insertions, 0 deletions
diff --git a/frontends/riscos/bitmap.c b/frontends/riscos/bitmap.c new file mode 100644 index 000000000..cc4be590c --- /dev/null +++ b/frontends/riscos/bitmap.c @@ -0,0 +1,876 @@ +/* + * Copyright 2004 James Bursa <bursa@users.sourceforge.net> + * Copyright 2005 Richard Wilson <info@tinct.net> + * Copyright 2008 Adrian Lees <adrianl@users.sourceforge.net> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * \file + * RISC OS implementation of bitmap operations. + * + * This implements the interface given by image/bitmap.h using RISC OS + * sprites. + */ + +#include <assert.h> +#include <stdbool.h> +#include <string.h> +#include <swis.h> +#include <rufl.h> +#include <unixlib/local.h> +#include <oslib/colourtrans.h> +#include <oslib/osfile.h> +#include <oslib/osfind.h> +#include <oslib/osgbpb.h> +#include <oslib/osspriteop.h> +#include <oslib/wimp.h> + +#include "utils/nsoption.h" +#include "utils/filename.h" +#include "utils/log.h" +#include "utils/messages.h" +#include "desktop/plotters.h" +#include "content/content.h" +#include "image/bitmap.h" + +#include "riscos/gui.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 + +/** Size of buffer used when constructing mask data to be saved */ +#define SAVE_CHUNK_SIZE 4096 + +/** + * Whether we can use 32bpp sprites + */ +static int thumbnail_32bpp_available = -1; + +/** + * Sprite output context saving + */ +struct thumbnail_save_area { + osspriteop_save_area *save_area; + int context1; + int context2; + int context3; +}; + +/** + * Initialise a bitmaps sprite area. + * + * \param bitmap the bitmap to initialise + * \return true if bitmap initialised else false. + */ + +static bool bitmap_initialise(struct bitmap *bitmap) +{ + unsigned int area_size; + osspriteop_area *sprite_area; + osspriteop_header *sprite; + + assert(!bitmap->sprite_area); + + area_size = 16 + 44 + bitmap->width * bitmap->height * 4; + if (bitmap->state & BITMAP_CLEAR_MEMORY) + bitmap->sprite_area = calloc(1, area_size); + else + bitmap->sprite_area = malloc(area_size); + + if (!bitmap->sprite_area) + return false; + + /* area control block */ + sprite_area = bitmap->sprite_area; + sprite_area->size = area_size; + sprite_area->sprite_count = 1; + sprite_area->first = 16; + sprite_area->used = area_size; + + /* sprite control block */ + sprite = (osspriteop_header *) (sprite_area + 1); + sprite->size = area_size - 16; + memset(sprite->name, 0x00, 12); + strncpy(sprite->name, "bitmap", 12); + sprite->width = bitmap->width - 1; + sprite->height = bitmap->height - 1; + sprite->left_bit = 0; + sprite->right_bit = 31; + sprite->image = sprite->mask = 44; + sprite->mode = tinct_SPRITE_MODE; + + return true; +} + + +/* exported interface documented in riscos/bitmap.h */ +void *riscos_bitmap_create(int width, int height, unsigned int state) +{ + struct bitmap *bitmap; + + if (width == 0 || height == 0) + return NULL; + + bitmap = calloc(1, sizeof(struct bitmap)); + if (!bitmap) + return NULL; + bitmap->width = width; + bitmap->height = height; + bitmap->state = state; + + return bitmap; +} + + +/* exported interface documented in riscos/bitmap.h */ +unsigned char *riscos_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; +} + + +/** + * Sets whether a bitmap should be plotted opaque + * + * \param vbitmap a bitmap, as returned by bitmap_create() + * \param opaque whether the bitmap should be plotted opaque + */ +static void bitmap_set_opaque(void *vbitmap, bool opaque) +{ + struct bitmap *bitmap = (struct bitmap *) vbitmap; + assert(bitmap); + + if (opaque) + bitmap->state |= BITMAP_OPAQUE; + else + bitmap->state &= ~BITMAP_OPAQUE; +} + + +/** + * Find the width of a pixel row in bytes. + * + * \param vbitmap A bitmap, as returned by riscos_bitmap_create() + * \return width of a pixel row in the bitmap + */ +static size_t 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 + */ +static bool bitmap_test_opaque(void *vbitmap) +{ + struct bitmap *bitmap = (struct bitmap *) vbitmap; + unsigned char *sprite; + unsigned int width, height, size; + osspriteop_header *sprite_header; + unsigned *p, *ep; + + assert(bitmap); + + sprite = riscos_bitmap_get_buffer(bitmap); + if (!sprite) + return false; + + width = bitmap_get_rowstride(bitmap); + + sprite_header = (osspriteop_header *) (bitmap->sprite_area + 1); + + height = (sprite_header->height + 1); + + size = width * height; + + p = (void *) sprite; + + ep = (void *) (sprite + (size & ~31)); + while (p < ep) { + /* \todo prefetch(p, 128)? */ + if (((p[0] & p[1] & p[2] & p[3] & p[4] & p[5] & p[6] & p[7]) + & 0xff000000U) != 0xff000000U) + return false; + p += 8; + } + + ep = (void *) (sprite + size); + while (p < ep) { + if ((*p & 0xff000000U) != 0xff000000U) return false; + p++; + } + + return true; +} + + +/* exported interface documented in riscos/bitmap.h */ +bool riscos_bitmap_get_opaque(void *vbitmap) +{ + struct bitmap *bitmap = (struct bitmap *) vbitmap; + assert(bitmap); + return (bitmap->state & BITMAP_OPAQUE); +} + + +/* exported interface documented in riscos/bitmap.h */ +void riscos_bitmap_destroy(void *vbitmap) +{ + struct bitmap *bitmap = (struct bitmap *) vbitmap; + + assert(bitmap); + + /* destroy bitmap */ + if (bitmap->sprite_area) { + free(bitmap->sprite_area); + } + + free(bitmap); +} + + +/* exported interface documented in riscos/bitmap.h */ +bool riscos_bitmap_save(void *vbitmap, const char *path, unsigned flags) +{ + struct bitmap *bitmap = (struct bitmap *) vbitmap; + os_error *error; + + if (bitmap == NULL) { + ro_warn_user("SaveError", messages_get("SprIsNull")); + return false; + } + + if (!bitmap->sprite_area) { + riscos_bitmap_get_buffer(bitmap); + } + if (!bitmap->sprite_area) + return false; + + if (riscos_bitmap_get_opaque(bitmap)) { + error = xosspriteop_save_sprite_file(osspriteop_USER_AREA, + (bitmap->sprite_area), path); + if (error) { + LOG("xosspriteop_save_sprite_file: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("SaveError", error->errmess); + return false; + } + return true; + } else { + /* to make the saved sprite useful we must convert from 'Tinct' + * format to either a bi-level mask or a Select-style full + * alpha channel */ + osspriteop_area *area = bitmap->sprite_area; + osspriteop_header *hdr = (void *) ((char *) area + area->first); + unsigned width = hdr->width + 1, height = hdr->height + 1; + unsigned image_size = height * width * 4; + unsigned char *chunk_buf; + unsigned *p, *elp, *eip; + unsigned mask_size; + size_t chunk_pix; + struct { + osspriteop_area area; + osspriteop_header hdr; + } file_hdr; + os_fw fw; + + /* we only support 32bpp sprites */ + if ((((unsigned)hdr->mode >> 27)&15) != 6) { + assert(!"Unsupported sprite format in bitmap_save"); + return false; + } + + chunk_buf = malloc(SAVE_CHUNK_SIZE); + if (!chunk_buf) { + ro_warn_user("NoMemory", NULL); + return false; + } + + file_hdr.area = *area; + file_hdr.hdr = *hdr; + + if (flags & BITMAP_SAVE_FULL_ALPHA) { + mask_size = ((width + 3) & ~3) * height; + chunk_pix = SAVE_CHUNK_SIZE; + file_hdr.hdr.mode = (os_mode)((unsigned)file_hdr.hdr.mode + | (1U<<31)); + } else { + mask_size = (((width + 31) & ~31)/8) * height; + chunk_pix = SAVE_CHUNK_SIZE<<3; + file_hdr.hdr.mode = (os_mode)((unsigned)file_hdr.hdr.mode + & ~(1U<<31)); + } + + file_hdr.area.sprite_count = 1; + file_hdr.area.first = sizeof(file_hdr.area); + file_hdr.area.used = sizeof(file_hdr) + image_size + mask_size; + + file_hdr.hdr.image = sizeof(file_hdr.hdr); + file_hdr.hdr.mask = file_hdr.hdr.image + image_size; + file_hdr.hdr.size = file_hdr.hdr.mask + mask_size; + + error = xosfind_openoutw(0, path, NULL, &fw); + if (error) { + LOG("xosfind_openoutw: 0x%x: %s", error->errnum, error->errmess); + free(chunk_buf); + ro_warn_user("SaveError", error->errmess); + return false; + } + + p = (void *) ((char *) hdr + hdr->image); + + /* write out the area header, sprite header and image data */ + error = xosgbpb_writew(fw, (byte*)&file_hdr + 4, + sizeof(file_hdr)-4, NULL); + if (!error) + error = xosgbpb_writew(fw, (byte*)p, image_size, NULL); + if (error) { + LOG("xosgbpb_writew: 0x%x: %s", error->errnum, error->errmess); + free(chunk_buf); + xosfind_closew(fw); + ro_warn_user("SaveError", error->errmess); + return false; + } + + /* then write out the mask data in chunks */ + eip = p + (width * height); /* end of image */ + elp = p + width; /* end of line */ + + while (p < eip) { + unsigned char *dp = chunk_buf; + unsigned *ep = p + chunk_pix; + if (ep > elp) ep = elp; + + if (flags & BITMAP_SAVE_FULL_ALPHA) { + while (p < ep) { + *dp++ = ((unsigned char*)p)[3]; + p++; + } + } + else { + unsigned char mb = 0; + int msh = 0; + while (p < ep) { + if (((unsigned char*)p)[3]) mb |= (1 << msh); + if (++msh >= 8) { + *dp++ = mb; + msh = 0; + mb = 0; + } + p++; + } + if (msh > 0) *dp++ = mb; + } + + if (p >= elp) { /* end of line yet? */ + /* align to word boundary */ + while ((int)dp & 3) *dp++ = 0; + /* advance end of line pointer */ + elp += width; + } + error = xosgbpb_writew(fw, (byte*)chunk_buf, dp-chunk_buf, NULL); + if (error) { + LOG("xosgbpb_writew: 0x%x: %s", error->errnum, error->errmess); + free(chunk_buf); + xosfind_closew(fw); + ro_warn_user("SaveError", error->errmess); + return false; + } + } + + error = xosfind_closew(fw); + if (error) { + LOG("xosfind_closew: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("SaveError", error->errmess); + } + + error = xosfile_set_type(path, osfile_TYPE_SPRITE); + if (error) { + LOG("xosfile_set_type: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("SaveError", error->errmess); + } + + free(chunk_buf); + return true; + } +} + + +/** + * The bitmap image has changed, so flush any persistent cache. + * + * \param vbitmap a bitmap, as returned by bitmap_create() + */ +static void bitmap_modified(void *vbitmap) +{ + struct bitmap *bitmap = (struct bitmap *) vbitmap; + bitmap->state |= BITMAP_MODIFIED; +} + + +/** + * Get the width of a bitmap. + * + * \param vbitmap A bitmap, as returned by bitmap_create() + * \return The bitmaps width in pixels. + */ +static int bitmap_get_width(void *vbitmap) +{ + struct bitmap *bitmap = (struct bitmap *) vbitmap; + return bitmap->width; +} + + +/** + * Get the height of a bitmap. + * + * \param vbitmap A bitmap, as returned by bitmap_create() + * \return The bitmaps height in pixels. + */ +static int bitmap_get_height(void *vbitmap) +{ + struct bitmap *bitmap = (struct bitmap *) vbitmap; + return bitmap->height; +} + + +/** + * Find the bytes per pixel of a bitmap + * + * \param vbitmap a bitmap, as returned by bitmap_create() + * \return bytes per pixel + */ +static size_t bitmap_get_bpp(void *vbitmap) +{ + struct bitmap *bitmap = (struct bitmap *)vbitmap; + assert(bitmap); + return 4; +} + + +/* exported interface documented in riscos/bitmap.h */ +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 = 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; + } +} + + +/** + * Creates an 8bpp canvas. + * + * \param bitmap the bitmap to clone the size of + * \return a sprite area containing an 8bpp sprite + */ +static osspriteop_area *thumbnail_create_8bpp(struct bitmap *bitmap) +{ + unsigned image_size = ((bitmap->width + 3) & ~3) * bitmap->height; + bool opaque = riscos_bitmap_get_opaque(bitmap); + osspriteop_header *sprite_header = NULL; + osspriteop_area *sprite_area = NULL; + unsigned area_size; + + /* clone the sprite */ + area_size = sizeof(osspriteop_area) + + sizeof(osspriteop_header) + + image_size + + 2048; + + if (!opaque) area_size += image_size; + + sprite_area = (osspriteop_area *)malloc(area_size); + if (!sprite_area) { + LOG("no memory for malloc()"); + return NULL; + } + sprite_area->size = area_size; + sprite_area->sprite_count = 1; + sprite_area->first = 16; + sprite_area->used = area_size; + sprite_header = (osspriteop_header *)(sprite_area + 1); + sprite_header->size = area_size - sizeof(osspriteop_area); + memset(sprite_header->name, 0x00, 12); + strcpy(sprite_header->name, "bitmap"); + sprite_header->left_bit = 0; + sprite_header->height = bitmap->height - 1; + sprite_header->mode = os_MODE8BPP90X90; + sprite_header->right_bit = ((bitmap->width << 3) - 1) & 31; + sprite_header->width = ((bitmap->width + 3) >> 2) - 1; + sprite_header->image = sizeof(osspriteop_header) + 2048; + sprite_header->mask = sizeof(osspriteop_header) + 2048; + if (!opaque) sprite_header->mask += image_size; + + /* create the palette. we don't read the necessary size like + * we really should as we know it's going to have 256 entries + * of 8 bytes = 2048. */ + xcolourtrans_read_palette((osspriteop_area *)os_MODE8BPP90X90, + (osspriteop_id)0, + (os_palette *)(sprite_header + 1), 2048, + (colourtrans_palette_flags)(1 << 1), 0); + return sprite_area; +} + + +/** + * Switches output to the specified sprite and returns the previous context. + */ +static struct thumbnail_save_area* +thumbnail_switch_output(osspriteop_area *sprite_area, + osspriteop_header *sprite_header) +{ + struct thumbnail_save_area *save_area; + int size; + + /* create a save area */ + save_area = calloc(sizeof(struct thumbnail_save_area), 1); + if (save_area == NULL) return NULL; + + /* allocate OS_SpriteOp save area */ + if (xosspriteop_read_save_area_size(osspriteop_PTR, sprite_area, + (osspriteop_id)sprite_header, &size)) { + free(save_area); + return NULL; + } + + /* create the save area */ + save_area->save_area = malloc((unsigned)size); + if (save_area->save_area == NULL) { + free(save_area); + return NULL; + } + save_area->save_area->a[0] = 0; + + /* switch output to sprite */ + if (xosspriteop_switch_output_to_sprite(osspriteop_PTR, sprite_area, + (osspriteop_id)sprite_header, save_area->save_area, + 0, &save_area->context1, &save_area->context2, + &save_area->context3)) { + free(save_area->save_area); + free(save_area); + return NULL; + } + return save_area; +} + + +/** + * Restores output to the specified context, and destroys it. + */ +static void thumbnail_restore_output(struct thumbnail_save_area *save_area) +{ + /* we don't care if we err, as there's nothing we can do about it */ + xosspriteop_switch_output_to_sprite(osspriteop_PTR, + (osspriteop_area *)save_area->context1, + (osspriteop_id)save_area->context2, + (osspriteop_save_area *)save_area->context3, + 0, 0, 0, 0); + free(save_area->save_area); + free(save_area); +} + + +/** + * Convert a bitmap to 8bpp. + * + * \param bitmap the bitmap to convert + * \return a sprite area containing an 8bpp sprite + */ +osspriteop_area *riscos_bitmap_convert_8bpp(struct bitmap *bitmap) +{ + struct thumbnail_save_area *save_area; + osspriteop_area *sprite_area = NULL; + osspriteop_header *sprite_header = NULL; + + sprite_area = thumbnail_create_8bpp(bitmap); + if (!sprite_area) + return NULL; + sprite_header = (osspriteop_header *)(sprite_area + 1); + + + /* switch output and redraw */ + save_area = thumbnail_switch_output(sprite_area, sprite_header); + if (save_area == NULL) { + if (thumbnail_32bpp_available != 1) + free(sprite_area); + return false; + } + _swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7), + (osspriteop_header *)(bitmap->sprite_area + 1), + 0, 0, + tinct_ERROR_DIFFUSE); + thumbnail_restore_output(save_area); + + if (sprite_header->image != sprite_header->mask) { + /* build the sprite mask from the alpha channel */ + 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 mp_offset = ((sprite_header->width + 1) * 4) - w; + byte *mp = (byte*)sprite_header + sprite_header->mask; + bool alpha = ((unsigned)sprite_header->mode & 0x80000000U) != 0; + + while (h-- > 0) { + int x = 0; + for(x = 0; x < w; x++) { + unsigned d = *dp++; + if (alpha) + *mp++ = (d >> 24) ^ 0xff; + else + *mp++ = (d < 0xff000000U) ? 0 : 0xff; + } + dp += dp_offset; + mp += mp_offset; + } + } + + return sprite_area; +} + + + + +/** + * Check to see whether 32bpp sprites are available. + * + * Rather than using Wimp_ReadSysInfo we test if 32bpp sprites are available + * in case the user has a 3rd party patch to enable them. + */ +static void thumbnail_test(void) +{ + unsigned int area_size; + osspriteop_area *sprite_area; + + /* try to create a 1x1 32bpp sprite */ + area_size = sizeof(osspriteop_area) + + sizeof(osspriteop_header) + sizeof(int); + if ((sprite_area = (osspriteop_area *)malloc(area_size)) == NULL) { + LOG("Insufficient memory to perform sprite test."); + return; + } + sprite_area->size = area_size + 1; + sprite_area->sprite_count = 0; + sprite_area->first = 16; + sprite_area->used = 16; + if (xosspriteop_create_sprite(osspriteop_NAME, sprite_area, + "test", false, 1, 1, (os_mode)tinct_SPRITE_MODE)) + thumbnail_32bpp_available = 0; + else + thumbnail_32bpp_available = 1; + free(sprite_area); +} + + +/* exported interface documented in riscos/bitmap.h */ +nserror riscos_bitmap_render(struct bitmap *bitmap, + struct hlcache_handle *content) +{ + struct thumbnail_save_area *save_area; + osspriteop_area *sprite_area = NULL; + osspriteop_header *sprite_header = NULL; + struct redraw_context ctx = { + .interactive = false, + .background_images = true, + .plot = &ro_plotters + }; + + assert(content); + assert(bitmap); + + LOG("content %p in bitmap %p", content, bitmap); + + /* check if we have access to 32bpp sprites natively */ + if (thumbnail_32bpp_available == -1) { + thumbnail_test(); + } + + /* if we don't support 32bpp sprites then we redirect to an 8bpp + * image and then convert back. + */ + if (thumbnail_32bpp_available != 1) { + sprite_area = thumbnail_create_8bpp(bitmap); + if (!sprite_area) + return false; + sprite_header = (osspriteop_header *)(sprite_area + 1); + } else { + const uint8_t *pixbufp = riscos_bitmap_get_buffer(bitmap); + if (!pixbufp || !bitmap->sprite_area) + return false; + sprite_area = bitmap->sprite_area; + sprite_header = (osspriteop_header *)(sprite_area + 1); + } + + /* set up the plotters */ + ro_plot_origin_x = 0; + ro_plot_origin_y = bitmap->height * 2; + + /* switch output and redraw */ + save_area = thumbnail_switch_output(sprite_area, sprite_header); + if (!save_area) { + if (thumbnail_32bpp_available != 1) + free(sprite_area); + return false; + } + rufl_invalidate_cache(); + colourtrans_set_gcol(os_COLOUR_WHITE, colourtrans_SET_BG_GCOL, + os_ACTION_OVERWRITE, 0); + + /* render the content */ + content_scaled_redraw(content, bitmap->width, bitmap->height, &ctx); + + thumbnail_restore_output(save_area); + rufl_invalidate_cache(); + + /* if we changed to 8bpp then go back to 32bpp */ + if (thumbnail_32bpp_available != 1) { + const uint8_t *pixbufp = riscos_bitmap_get_buffer(bitmap); + _kernel_oserror *error; + + if (!pixbufp || !bitmap->sprite_area) { + free(sprite_area); + return false; + } + error = _swix(Tinct_ConvertSprite, _INR(2,3), + sprite_header, + (osspriteop_header *)(bitmap->sprite_area + 1)); + free(sprite_area); + if (error) + return false; + } + + bitmap_modified(bitmap); + + return NSERROR_OK; +} + +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 = bitmap_get_rowstride, + .get_width = bitmap_get_width, + .get_height = bitmap_get_height, + .get_bpp = bitmap_get_bpp, + .save = riscos_bitmap_save, + .modified = bitmap_modified, + .render = riscos_bitmap_render, +}; + +struct gui_bitmap_table *riscos_bitmap_table = &bitmap_table; |