summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Wilson <rjw@netsurf-browser.org>2004-04-10 18:19:35 +0000
committerRichard Wilson <rjw@netsurf-browser.org>2004-04-10 18:19:35 +0000
commitf61d7fe881c3cac0de02733738c1694d638282cf (patch)
tree7c4a5fa83beb07582bbc5d90f4f59b4f507a31e7
parent4934762dd694feae9a95feb4afb006056b02c4af (diff)
downloadnetsurf-f61d7fe881c3cac0de02733738c1694d638282cf.tar.gz
netsurf-f61d7fe881c3cac0de02733738c1694d638282cf.tar.bz2
[project @ 2004-04-10 18:19:35 by rjw]
Thumnails now created with a palette to fix incorrect colour rendition. Thumnails output to a 32bpp sprite where possible. Thumnails oversampled to improve display if desired. svn path=/import/netsurf/; revision=744
-rw-r--r--riscos/thumbnail.c367
-rw-r--r--riscos/thumbnail.h1
2 files changed, 322 insertions, 46 deletions
diff --git a/riscos/thumbnail.c b/riscos/thumbnail.c
index 704ef51a8..72e0b8ce3 100644
--- a/riscos/thumbnail.c
+++ b/riscos/thumbnail.c
@@ -1,8 +1,9 @@
/*
* This file is part of NetSurf, http://netsurf.sourceforge.net/
* Licensed under the GNU General Public License,
- * http://www.opensource.org/licenses/gpl-license
+ * http://www.opensource.org/licenses/gpl-license
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net>
*/
/** \file
@@ -12,80 +13,354 @@
* page at a small scale.
*/
+#include <string.h>
+#include <swis.h>
#include "oslib/colourtrans.h"
+#include "oslib/osfile.h"
#include "oslib/osspriteop.h"
#include "netsurf/content/content.h"
+#include "netsurf/riscos/options.h"
#include "netsurf/riscos/thumbnail.h"
+#include "netsurf/riscos/tinct.h"
#include "netsurf/utils/log.h"
+/* 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;
+};
+
+
+/* Internal prototypes
+*/
+static void thumbnail_test(void);
+static struct thumbnail_save_area* thumbnail_switch_output(osspriteop_area *sprite_area,
+ osspriteop_header *sprite_header);
+static void thumbnail_restore_output(struct thumbnail_save_area *save_area);
+
+
/**
* Create a thumbnail of a page.
*
* \param content content structure to thumbnail
- * \param area sprite area containing thumbnail sprite
+ * \param area sprite area containing thumbnail sprite
* \param sprite pointer to sprite
* \param width sprite width / pixels
* \param height sprite height / pixels
*
* The thumbnail is rendered in the given sprite.
*/
-
void thumbnail_create(struct content *content, osspriteop_area *area,
- osspriteop_header *sprite, int width, int height)
-{
- int size;
- int context1, context2, context3;
+ osspriteop_header *sprite, int width, int height) {
float scale;
- osspriteop_save_area *save_area;
- os_error *error;
+ osspriteop_area *oversampled_area = NULL;
+ struct thumbnail_save_area *save_area;
- scale = (float) width / (float) content->width;
+ /* Check for 32bpp support in case we've been called for a sprite
+ we didn't set up.
+ */
+ if (thumbnail_32bpp_available == -1) thumbnail_test();
- /* allocate save area */
- error = xosspriteop_read_save_area_size(osspriteop_PTR, area,
- (osspriteop_id) sprite, &size);
- if (error) {
- LOG(("xosspriteop_read_save_area_size failed: 0x%x: %s",
- error->errnum, error->errmess));
- return;
+ /* Check our oversampling is within a usable range
+ */
+ if (option_thumbnail_oversampling < 0) option_thumbnail_oversampling = 0;
+ if (option_thumbnail_oversampling > 4) option_thumbnail_oversampling = 4;
+
+ /* Get the oversampled sprite holder. We perform oversamling if either we
+ want to oversample, or the output sprite is 8bpp and we can do 32bpp and
+ thus improve the final rendition via dithering.
+ */
+ if ((thumbnail_32bpp_available == 1) &&
+ ((option_thumbnail_oversampling > 0) || (sprite->mode != (os_mode)0x301680b5))) {
+ oversampled_area = thumbnail_initialise(
+ width << option_thumbnail_oversampling,
+ height << option_thumbnail_oversampling,
+ (os_mode)0x301680b5);
+ }
+
+ /* Oversample if we have an oversampled sprite, don't otherwise
+ */
+ if (oversampled_area != NULL) {
+ /* Scale up for oversampling
+ */
+ width = width << option_thumbnail_oversampling;
+ height = height << option_thumbnail_oversampling;
+
+ /* Calculate the scale
+ */
+ scale = (float) width / (float) content->width;
+
+ /* Switch output and redraw oversampled
+ */
+ save_area = thumbnail_switch_output(oversampled_area,
+ (osspriteop_header *)(oversampled_area + 1));
+ if (save_area == NULL) return;
+ content_redraw(content, 0, height * 2, width * 2, height * 2,
+ 0, 0, width * 2, height * 2, scale);
+ thumbnail_restore_output(save_area);
+
+/* xosspriteop_save_sprite_file(osspriteop_USER_AREA,
+ oversampled_area, "oversample");
+*/
+ /* Scale back
+ */
+ width = width >> option_thumbnail_oversampling;
+ height = height >> option_thumbnail_oversampling;
+
+ /* Switch output to the final sprite
+ */
+ save_area = thumbnail_switch_output(area, sprite);
+ if (save_area == NULL) {
+ free(oversampled_area);
+ return;
+ }
+
+ /* Get Tinct to dither and bilinear filter back to what we want.
+ */
+ _swix(Tinct_PlotScaled, _IN(2) | _IN(3) | _IN(4) | _IN(5) | _IN(6) | _IN(7),
+ (char *)(oversampled_area + 1), 0, 0, width * 2, height * 2,
+ (1<<1) | (1<<2));
+
+ /* Restore output
+ */
+ thumbnail_restore_output(save_area);
+
+/* xosspriteop_save_sprite_file(osspriteop_USER_AREA,
+ area, "thumb_scaled");
+*/
+
+ } else {
+ /* Calculate the scale
+ */
+ scale = (float) width / (float) content->width;
+
+ /* Switch output and redraw
+ */
+ save_area = thumbnail_switch_output(area, sprite);
+ if (save_area == NULL) return;
+ content_redraw(content, 0, height * 2, width * 2, height * 2,
+ 0, 0, width * 2, height * 2, scale);
+ thumbnail_restore_output(save_area);
+
+/* xosspriteop_save_sprite_file(osspriteop_USER_AREA,
+ area, "thumb");
+*/
+ }
+}
+
+
+/**
+ * Initialises a sprite.
+ *
+ * The sprite background cleared to white.
+ * Any necessary palette data is set up to the default palette.
+ * The sprite name is set to "thumbnail".
+ *
+ * @param width The sprite width
+ * @param height The sprite height
+ * @param mode The preferred mode (0x301680b5 or os_MODE8BPP90X90)
+ * @return
+ */
+osspriteop_area* thumbnail_initialise(int width, int height, os_mode mode) {
+ unsigned int area_size;
+ unsigned int remaining_bytes;
+ osspriteop_area *sprite_area;
+ osspriteop_header *sprite_header;
+ char *sprite_image;
+
+ /* Check if we can use 32bpp sprites if we haven't already. By
+ doing it this way we don't need to allocate lot of memory
+ first which will probably not be available on machines that
+ can't handle such sprites..
+ */
+ if (thumbnail_32bpp_available == -1) thumbnail_test();
+
+ /* If we can't handle 32bpp then we get 8bpp.
+ */
+ if (thumbnail_32bpp_available != 1) mode = os_MODE8BPP90X90;
+
+ /* Calculate our required memory
+ */
+ area_size = sizeof(osspriteop_area) + sizeof(osspriteop_header);
+ if (mode == (os_mode)0x301680b5) {
+ area_size += width * height * 4;
+ } else {
+ area_size += ((width + 3) & ~3) * height + 2048;
}
- save_area = malloc((unsigned) size);
- if (!save_area) {
- LOG(("malloc failed"));
- return;
+
+ /* Try to get enough memory
+ */
+ if ((sprite_area = (osspriteop_area *)malloc(area_size)) == NULL) {
+ LOG(("Insufficient memory to create thumbnail."));
+ return NULL;
+ }
+
+ /* Initialise the sprite area
+ */
+ sprite_area->size = area_size;
+ sprite_area->sprite_count = 1;
+ sprite_area->first = 16;
+ sprite_area->used = area_size;
+
+ /* Initialise the sprite header. We can't trust OS_SpriteOp to
+ set up our palette properly due to insane legacy 8bpp palettes,
+ so we do it all manually.
+ */
+ 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, "thumbnail");
+ sprite_header->left_bit = 0;
+ sprite_header->height = height - 1;
+ sprite_header->mode = mode;
+ if (mode == (os_mode)0x301680b5) {
+ sprite_header->right_bit = 31;
+ sprite_header->width = width - 1;
+ sprite_header->image = sizeof(osspriteop_header);
+ sprite_header->mask = sizeof(osspriteop_header);
+
+ /* Clear to white, full opacity
+ */
+ sprite_image = ((char *)sprite_header) + sprite_header->image;
+ memset(sprite_image, 0xff, area_size - sizeof(osspriteop_area) -
+ sizeof(osspriteop_header));
+ } else {
+ sprite_header->right_bit = ((width << 3) - 1) & 31;
+ sprite_header->width = ((width + 3) >> 2) - 1;
+ sprite_header->image = sizeof(osspriteop_header) + 2048;
+ sprite_header->mask = sizeof(osspriteop_header) + 2048;
+
+ /* 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 *)mode, (osspriteop_id)0,
+ (os_palette *)(sprite_header + 1), 2048,
+ (colourtrans_palette_flags)(1 << 1), &remaining_bytes);
+
+ /* Clear to white
+ */
+ sprite_image = ((char *)sprite_header) + sprite_header->image;
+ memset(sprite_image, 0xff, area_size - sizeof(osspriteop_area) -
+ sizeof(osspriteop_header) - 2048);
}
- save_area->a[0] = 0;
-
- /* switch output to sprite */
- error = xosspriteop_switch_output_to_sprite(osspriteop_PTR, area,
- (osspriteop_id) sprite, save_area,
- 0, &context1, &context2, &context3);
- if (error) {
- LOG(("xosspriteop_switch_output_to_sprite failed: 0x%x: %s",
- error->errnum, error->errmess));
+/* xosfile_save_stamped("thumb", 0xff9,
+ ((char *)sprite_area) + 4,
+ ((char *)sprite_area) + area_size);
+
+*/
+ /* Return our sprite area
+ */
+ return sprite_area;
+}
+
+
+/*
+ * Checks 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;
+
+ /* Get enough memory for 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;
}
+
+ /* Initialise the sprite area
+ */
+ sprite_area->size = area_size + 1;
+ sprite_area->sprite_count = 0;
+ sprite_area->first = 16;
+ sprite_area->used = 16;
+
+ /* Try to create a 32bpp sprite
+ */
+ if (xosspriteop_create_sprite(osspriteop_NAME, sprite_area,
+ "test", false, 1, 1, (os_mode)0x301680b5)) {
+ thumbnail_32bpp_available = 0;
+ } else {
+ thumbnail_32bpp_available = 1;
+ }
+
+ /* Free our memory
+ */
+ free(sprite_area);
+}
- /* clear background to white */
- colourtrans_set_gcol(os_COLOUR_WHITE, colourtrans_SET_BG,
- os_ACTION_OVERWRITE, 0);
- os_clg();
- /* render content */
- content_redraw(content, 0, height * 2, width * 2, height * 2,
- 0, 0, width * 2, height * 2, scale);
+/* 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;
+ }
- /* switch output back to screen */
- error = xosspriteop_switch_output_to_sprite(osspriteop_PTR,
- (osspriteop_area *) context1,
- (osspriteop_id) context2,
- (osspriteop_save_area *) context3,
- 0, 0, 0, 0);
- if (error) {
- LOG(("xosspriteop_switch_output_to_sprite failed: %s",
- error->errmess));
+ /* 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 our workspace
+ */
+ free(save_area->save_area);
free(save_area);
}
diff --git a/riscos/thumbnail.h b/riscos/thumbnail.h
index 7482b3c39..429e14fa8 100644
--- a/riscos/thumbnail.h
+++ b/riscos/thumbnail.h
@@ -13,3 +13,4 @@
void thumbnail_create(struct content *content, osspriteop_area *area,
osspriteop_header *sprite, int width, int height);
+osspriteop_area* thumbnail_initialise(int width, int height, os_mode mode);