diff options
Diffstat (limited to 'frontends/riscos/buffer.c')
-rw-r--r-- | frontends/riscos/buffer.c | 396 |
1 files changed, 396 insertions, 0 deletions
diff --git a/frontends/riscos/buffer.c b/frontends/riscos/buffer.c new file mode 100644 index 000000000..7176c1c1c --- /dev/null +++ b/frontends/riscos/buffer.c @@ -0,0 +1,396 @@ +/* + * Copyright 2004, 2005 Richard Wilson <info@tinct.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/>. + */ + +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <swis.h> +#include <oslib/colourtrans.h> +#include <oslib/os.h> +#include <oslib/osspriteop.h> +#include <oslib/wimp.h> +#include <oslib/wimpreadsysinfo.h> + +#include "utils/nsoption.h" +#include "utils/log.h" + +#include "riscos/buffer.h" +#include "riscos/gui.h" +#include "riscos/tinct.h" +#include "riscos/wimp.h" +#include "riscos/wimputils.h" + +#define BUFFER_EXCLUSIVE_USER_REDRAW "Only support pure user redraw (faster)" +//#define BUFFER_EMULATE_32BPP "Redirect to a 32bpp sprite and plot with Tinct" + +/** Absent from OSLib +*/ +#ifndef osspriteop_TYPEEXPANSION +#define osspriteop_TYPEEXPANSION ((osspriteop_mode_word) 0xFu) +#endif +#ifndef osspriteop_TYPE16BPP4K +#define osspriteop_TYPE16BPP4K ((osspriteop_mode_word) 0x10u) +#endif + +static void ro_gui_buffer_free(void); + + +/** The buffer characteristics +*/ +static osspriteop_area *buffer = NULL; +static char buffer_name[12] = "scr_buffer"; + +/** The current clip area +*/ +static os_box clipping; + +/** The current save area +*/ +static osspriteop_save_area *save_area; +static int context0; +static int context1; +static int context2; +static int context3; + +/** The current sprite mode +*/ +static os_mode mode; + + +/** + * Opens a buffer for writing to. + * + * The ro_plot_origin_ variables are updated to reflect the new screen origin, + * so the variables should be set before calling this function, and not + * changed until after ro_gui_buffer_close() has been called. + * + * \param redraw the current WIMP redraw area to buffer + */ +void ro_gui_buffer_open(wimp_draw *redraw) +{ + int size; + int total_size; + os_coord sprite_size; + int bpp, word_width; + bool palette; + os_error *error; + int palette_size = 0; +#ifdef BUFFER_EXCLUSIVE_USER_REDRAW + osspriteop_header *header; +#endif + + /* Close any open buffer + */ + if (buffer) + ro_gui_buffer_close(); + + /* Store our clipping region + */ + clipping = redraw->clip; + + /* Stop bad rectangles + */ + if ((clipping.x1 < clipping.x0) || + (clipping.y1 < clipping.y0)) { + LOG("Invalid clipping rectangle (%i, %i) to (%i,%i)", clipping.x0, clipping.y0, clipping.x1, clipping.y1); + return; + } + + /* Work out how much buffer we need + */ + sprite_size.x = clipping.x1 - clipping.x0 + 1; + sprite_size.y = clipping.y1 - clipping.y0 + 1; + ro_convert_os_units_to_pixels(&sprite_size, (os_mode)-1); + if (sprite_size.y == 1) /* work around SpriteExtend bug */ + sprite_size.y = 2; + +#ifdef BUFFER_EMULATE_32BPP + bpp = 5; + palette = false; +#else + /* Get the screen depth as we can't use palettes for >8bpp + */ + xos_read_mode_variable((os_mode)-1, os_MODEVAR_LOG2_BPP, &bpp, 0); + palette = (bpp < 4); +#endif + + /* Get our required buffer size + */ + word_width = ((sprite_size.x << bpp) + 31) >> 5; + if (palette) + palette_size = ((1 << (1 << bpp)) << 3); + total_size = sizeof(osspriteop_area) + sizeof(osspriteop_header) + + (word_width * sprite_size.y * 4) + palette_size; + buffer = (osspriteop_area *)malloc(total_size); + if (!buffer) { + LOG("Failed to allocate memory"); + ro_gui_buffer_free(); + return; + } + buffer->size = total_size; + buffer->first = 16; + +#ifdef BUFFER_EMULATE_32BPP + mode = tinct_SPRITE_MODE; +#else + if ((error = xwimpreadsysinfo_wimp_mode(&mode)) != NULL) { + LOG("Error reading mode '%s'", error->errmess); + ro_gui_buffer_free(); + return; + } + + /* if we're not in a numbered screen mode then we need + to build a suitable sprite mode word */ + if (mode >= (os_mode)0x100) { + static const ns_os_vdu_var_list vars = { + os_MODEVAR_LOG2_BPP, + { + os_MODEVAR_MODE_FLAGS, + os_MODEVAR_NCOLOUR, + os_MODEVAR_XEIG_FACTOR, + os_MODEVAR_YEIG_FACTOR, + os_VDUVAR_END_LIST + } + }; + struct { + int log2bpp; + int flags; + int ncolour; + int xeig, yeig; + } vals; + int type; + + error = xos_read_vdu_variables(PTR_OS_VDU_VAR_LIST(&vars), (int *)&vals); + if (error) { + LOG("Error reading mode properties '%s'", error->errmess); + ro_gui_buffer_free(); + return; + } + + switch (vals.ncolour) { + case 1: + case 3: + case 15: + case 63: + case 255: + /* Paletted modes are pixel packing order agnostic */ + type = 1 + vals.log2bpp; + mode = (os_mode)((type << osspriteop_TYPE_SHIFT) | + osspriteop_NEW_STYLE | + ((180 >> vals.yeig) << osspriteop_YRES_SHIFT) | + ((180 >> vals.xeig) << osspriteop_XRES_SHIFT)); + break; + case 4095: + /* 16bpp 4k colours */ + type = osspriteop_TYPE16BPP4K; + mode = (os_mode)((osspriteop_TYPEEXPANSION << osspriteop_TYPE_SHIFT) | + osspriteop_NEW_STYLE | + (vals.yeig << 6) | + (vals.xeig << 4) | + (type << 20) | + (vals.flags & 0xFF00)); + break; + case 65535: + switch ((vals.flags & 0x3000) >> os_MODE_FLAG_DATA_FORMAT_SHIFT) { + case os_MODE_FLAG_DATA_FORMAT_RGB: + if (vals.flags & 0xC000) { + /* Non VIDC packing order */ + if (vals.flags & os_MODE_FLAG_FULL_PALETTE) + type = osspriteop_TYPE16BPP64K; + else + type = osspriteop_TYPE16BPP; + mode = (os_mode)((osspriteop_TYPEEXPANSION << osspriteop_TYPE_SHIFT) | + osspriteop_NEW_STYLE | + (vals.yeig << 6) | + (vals.xeig << 4) | + (type << 20) | + (vals.flags & 0xFF00)); + } else { + /* VIDC packing order */ + if (vals.flags & os_MODE_FLAG_FULL_PALETTE) + type = osspriteop_TYPE16BPP64K; + else + type = osspriteop_TYPE16BPP; + mode = (os_mode)((type << osspriteop_TYPE_SHIFT) | + osspriteop_NEW_STYLE | + ((180 >> vals.yeig) << osspriteop_YRES_SHIFT) | + ((180 >> vals.xeig) << osspriteop_XRES_SHIFT)); + } + break; + default: + LOG("Unhandled 16bpp format from flags %d", vals.flags); + ro_gui_buffer_free(); + return; + } + break; + case -1: + /* 16M colours */ + switch ((vals.flags & 0x3000) >> os_MODE_FLAG_DATA_FORMAT_SHIFT) { + case os_MODE_FLAG_DATA_FORMAT_RGB: + if (vals.flags & 0xC000) { + /* Non VIDC packing order */ + type = osspriteop_TYPE32BPP; + mode = (os_mode)((osspriteop_TYPEEXPANSION << osspriteop_TYPE_SHIFT) | + osspriteop_NEW_STYLE | + (vals.yeig << 6) | + (vals.xeig << 4) | + (type << 20) | + (vals.flags & 0xFF00)); + } else { + /* VIDC packing order */ + type = osspriteop_TYPE32BPP; + mode = (os_mode)((type << osspriteop_TYPE_SHIFT) | + osspriteop_NEW_STYLE | + ((180 >> vals.yeig) << osspriteop_YRES_SHIFT) | + ((180 >> vals.xeig) << osspriteop_XRES_SHIFT)); + } + break; + default: + LOG("Unhandled 32bpp data format from flags %d", vals.flags); + ro_gui_buffer_free(); + return; + } + break; + default: + LOG("Unhandled NCOLOUR value %d", vals.ncolour); + ro_gui_buffer_free(); + return; + } + } +#endif + +#ifdef BUFFER_EXCLUSIVE_USER_REDRAW + /* Create the sprite manually so we don't waste time clearing the + background. + */ + buffer->sprite_count = 1; + buffer->used = total_size; + header = (osspriteop_header *)(buffer + 1); + header->size = total_size - sizeof(osspriteop_area); + memcpy(header->name, buffer_name, 12); + header->width = word_width - 1; + header->height = sprite_size.y - 1; + header->left_bit = 0; + header->right_bit = ((sprite_size.x << bpp) - 1) & 31; + header->image = sizeof(osspriteop_header) + palette_size; + header->mask = header->image; + header->mode = mode; + if (palette) + xcolourtrans_read_palette((osspriteop_area *)mode, + (osspriteop_id)os_CURRENT_MODE, + (os_palette *)(header + 1), palette_size, + (colourtrans_palette_flags) + colourtrans_FLASHING_PALETTE, 0); +#else + /* Read the current contents of the screen + */ + buffer->sprite_count = 0; + buffer->used = 16; + if ((error = xosspriteop_get_sprite_user_coords(osspriteop_NAME, + buffer, buffer_name, palette, + clipping.x0, clipping.y0, + clipping.x1, clipping.y1)) != NULL) { + LOG("Grab error '%s'", error->errmess); + ro_gui_buffer_free(); + return; + } +#endif + /* Allocate OS_SpriteOp save area + */ + if ((error = xosspriteop_read_save_area_size(osspriteop_PTR, + buffer, (osspriteop_id)(buffer + 1), &size)) != NULL) { + LOG("Save area error '%s'", error->errmess); + ro_gui_buffer_free(); + return; + } + if ((save_area = malloc((size_t)size)) == NULL) { + ro_gui_buffer_free(); + return; + } + save_area->a[0] = 0; + + /* Switch output to sprite + */ + if ((error = xosspriteop_switch_output_to_sprite(osspriteop_PTR, + buffer, (osspriteop_id)(buffer + 1), save_area, + &context0, &context1, &context2, &context3)) != NULL) { + LOG("Switching error '%s'", error->errmess); + free(save_area); + ro_gui_buffer_free(); + return; + } + + /* Emulate an origin as the FontManager doesn't respect it in + most cases. + */ + ro_plot_origin_x -= clipping.x0; + ro_plot_origin_y -= clipping.y0; + + /* Update the ECF origin + */ + if ((error = xos_set_ecf_origin(-ro_plot_origin_x, + -ro_plot_origin_y)) != NULL) { + LOG("Invalid ECF origin: '%s'", error->errmess); + } +} + + +/** + * Closes any open buffer and flushes the contents to screen + */ +void ro_gui_buffer_close(void) +{ + /* Check we have an open buffer + */ + if (!buffer) + return; + + /* Remove any previous redirection + */ + ro_plot_origin_x += clipping.x0; + ro_plot_origin_y += clipping.y0; + xosspriteop_unswitch_output(context0, context1, context2, context3); + free(save_area); + + /* Plot the contents to screen + */ + if (mode == tinct_SPRITE_MODE) + _swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7), + (char *)(buffer + 1), + clipping.x0, clipping.y0, + nsoption_int(plot_fg_quality)); + else + xosspriteop_put_sprite_user_coords(osspriteop_PTR, + buffer, (osspriteop_id)(buffer + 1), + clipping.x0, clipping.y0, (os_action)0); + ro_gui_buffer_free(); + + /* Update the ECF origin + */ + os_set_ecf_origin(0, 0); +} + + +/** + * Releases any buffer memory depending on cache constraints. + */ +static void ro_gui_buffer_free(void) +{ + free(buffer); + buffer = NULL; +} |