mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-11-24 23:39:51 +03:00
6807b4208a
NetSurf includes are now done with ""s and other system includes with <>s as C intended. The scandeps tool has been updated to only look for ""ed includes, and to verify that the files exist in the tree before adding them to the dependency lines. The depend rule has therefore been augmented to make sure the autogenerated files are built before it is run. This is untested under self-hosted RISC OS builds. All else tested and works. svn path=/trunk/netsurf/; revision=3307
350 lines
9.5 KiB
C
350 lines
9.5 KiB
C
/*
|
|
* This file is part of NetSurf, http://netsurf-browser.org/
|
|
* Licensed under the GNU General Public License,
|
|
* http://www.opensource.org/licenses/gpl-license
|
|
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
|
|
* Copyright 2005 Richard Wilson <info@tinct.net>
|
|
*/
|
|
|
|
/** \file
|
|
* Page thumbnail creation (implementation).
|
|
*
|
|
* Thumbnails are created by redirecting output to a sprite and rendering the
|
|
* page at a small scale.
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <swis.h>
|
|
#include "rufl.h"
|
|
#include "oslib/colourtrans.h"
|
|
#include "oslib/osfile.h"
|
|
#include <oslib/osspriteop.h>
|
|
#include "content/content.h"
|
|
#include "content/urldb.h"
|
|
#include "desktop/plotters.h"
|
|
#include "image/bitmap.h"
|
|
#include "render/font.h"
|
|
#include "riscos/bitmap.h"
|
|
#include "riscos/gui.h"
|
|
#include "riscos/options.h"
|
|
#include "riscos/thumbnail.h"
|
|
#include "riscos/tinct.h"
|
|
#include "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 osspriteop_area *thumbnail_create_8bpp(struct bitmap *bitmap);
|
|
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 bitmap the bitmap to draw to
|
|
* \param url the URL the thumbnail belongs to, or NULL
|
|
*/
|
|
bool thumbnail_create(struct content *content, struct bitmap *bitmap,
|
|
const char *url)
|
|
{
|
|
float scale = 1.0;
|
|
struct thumbnail_save_area *save_area;
|
|
osspriteop_area *sprite_area = NULL;
|
|
osspriteop_header *sprite_header = NULL;
|
|
_kernel_oserror *error;
|
|
|
|
assert(content);
|
|
assert(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 {
|
|
char *pixbufp = 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 */
|
|
plot = ro_plotters;
|
|
ro_plot_origin_x = 0;
|
|
ro_plot_origin_y = bitmap->height * 2;
|
|
if (content->width)
|
|
scale = (float)bitmap->width / (float)content->width;
|
|
ro_plot_set_scale(scale);
|
|
current_redraw_browser = NULL; /* no selection */
|
|
|
|
/* 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,
|
|
os_ACTION_OVERWRITE, 0);
|
|
os_clg();
|
|
content_redraw(content, 0, 0, bitmap->width, bitmap->height,
|
|
0, 0, bitmap->width, bitmap->height, scale, 0xFFFFFF);
|
|
thumbnail_restore_output(save_area);
|
|
rufl_invalidate_cache();
|
|
|
|
/* if we changed to 8bpp then go back to 32bpp */
|
|
if (thumbnail_32bpp_available != 1) {
|
|
char *pixbufp = bitmap_get_buffer(bitmap);
|
|
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;
|
|
}
|
|
|
|
/* register the thumbnail with the URL */
|
|
if (url)
|
|
urldb_set_thumbnail(url, bitmap);
|
|
bitmap_modified(bitmap);
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Convert a bitmap to 8bpp.
|
|
*
|
|
* \param bitmap the bitmap to convert
|
|
* \return a sprite area containing an 8bpp sprite
|
|
*/
|
|
osspriteop_area *thumbnail_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 */
|
|
unsigned *dp = (unsigned*)bitmap_get_buffer(bitmap);
|
|
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;
|
|
}
|
|
|
|
|
|
/**
|
|
* Creates an 8bpp canvas.
|
|
*
|
|
* \param bitmap the bitmap to clone the size of
|
|
* \return a sprite area containing an 8bpp sprite
|
|
*/
|
|
osspriteop_area *thumbnail_create_8bpp(struct bitmap *bitmap)
|
|
{
|
|
unsigned image_size = ((bitmap->width + 3) & ~3) * bitmap->height;
|
|
bool opaque = 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;
|
|
}
|
|
|
|
|
|
/**
|
|
* 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);
|
|
}
|
|
|
|
|
|
/**
|
|
* 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);
|
|
}
|