From 4b03028b5111ca43dc5028c4aee471a83dbae58f Mon Sep 17 00:00:00 2001 From: Adrian Lees Date: Fri, 24 Mar 2006 03:44:37 +0000 Subject: [project @ 2006-03-24 03:44:33 by adrianl] Use thumbnails for iconised windows svn path=/import/netsurf/; revision=2157 --- !NetSurf/5Sprites,ff9 | Bin 27024 -> 30964 bytes !NetSurf/5Sprites11,ff9 | Bin 54360 -> 64228 bytes !NetSurf/5Sprites22,ff9 | Bin 35100 -> 40800 bytes image/bitmap.h | 3 ++ riscos/bitmap.c | 102 +++++++++++++++++++++++++++++++++++++ riscos/bitmap.h | 2 +- riscos/gui.c | 25 +++++++++- riscos/gui.h | 3 ++ riscos/print.c | 6 +++ riscos/save.c | 2 +- riscos/sprite.c | 34 +++++++++++++ riscos/sprite.h | 3 ++ riscos/thumbnail.c | 38 ++++++++++++-- riscos/window.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++ 14 files changed, 341 insertions(+), 7 deletions(-) diff --git a/!NetSurf/5Sprites,ff9 b/!NetSurf/5Sprites,ff9 index c6efeaa9b..b0cf1c95f 100755 Binary files a/!NetSurf/5Sprites,ff9 and b/!NetSurf/5Sprites,ff9 differ diff --git a/!NetSurf/5Sprites11,ff9 b/!NetSurf/5Sprites11,ff9 index a45f00a5a..c039ea180 100755 Binary files a/!NetSurf/5Sprites11,ff9 and b/!NetSurf/5Sprites11,ff9 differ diff --git a/!NetSurf/5Sprites22,ff9 b/!NetSurf/5Sprites22,ff9 index 3212636de..766471428 100755 Binary files a/!NetSurf/5Sprites22,ff9 and b/!NetSurf/5Sprites22,ff9 differ diff --git a/image/bitmap.h b/image/bitmap.h index bae1e1a15..3581564b5 100644 --- a/image/bitmap.h +++ b/image/bitmap.h @@ -45,4 +45,7 @@ void bitmap_modified(struct bitmap *bitmap); void bitmap_set_suspendable(struct bitmap *bitmap, void *private_word, void (*invalidate)(struct bitmap *bitmap, void *private_word)); +int bitmap_get_width(struct bitmap *bitmap); +int bitmap_get_height(struct bitmap *bitmap); + #endif diff --git a/riscos/bitmap.c b/riscos/bitmap.c index f9c66bb34..b0d245fd0 100644 --- a/riscos/bitmap.c +++ b/riscos/bitmap.c @@ -25,10 +25,14 @@ #include "netsurf/riscos/filename.h" #include "netsurf/riscos/image.h" #include "netsurf/riscos/options.h" +#include "netsurf/riscos/sprite.h" #include "netsurf/riscos/tinct.h" #include "netsurf/utils/log.h" #include "netsurf/utils/utils.h" +/** Colour in the overlay sprite that allows the bitmap to show through */ +#define OVERLAY_KEY 0xff0000U + #define MAINTENANCE_THRESHOLD 32 /** The head of the bitmap list @@ -222,6 +226,92 @@ struct bitmap *bitmap_create_file(char *file) } +/** + * Overlay a sprite onto the given bitmap + * + * \param bitmap bitmap object + * \param s 8bpp sprite to be overlayed onto bitmap + */ + +void 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 = (unsigned*)bitmap_get_buffer(bitmap); + sp = (byte*)s + s->image; + mp = (byte*)s + s->mask; + + sp += s->left_bit / 8; + mp += s->left_bit / 8; + + if (s->image > 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_KEY 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 (d == OVERLAY_KEY) 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; + } +} + + /** * Initialise a bitmaps sprite area. * @@ -852,3 +942,15 @@ void bitmap_delete_file(struct bitmap *bitmap) ro_filename_release(bitmap->filename); bitmap->filename[0] = 0; } + + +int bitmap_get_width(struct bitmap *bitmap) +{ + return bitmap->width; +} + + +int bitmap_get_height(struct bitmap *bitmap) +{ + return bitmap->height; +} diff --git a/riscos/bitmap.h b/riscos/bitmap.h index a113d9b1b..ac196661a 100644 --- a/riscos/bitmap.h +++ b/riscos/bitmap.h @@ -32,6 +32,7 @@ struct bitmap { }; struct bitmap *bitmap_create_file(char *file); +void bitmap_overlay_sprite(struct bitmap *bitmap, const osspriteop_header *s); void bitmap_initialise_memory(void); void bitmap_quit(void); void bitmap_maintain(void); @@ -52,5 +53,4 @@ extern unsigned int bitmap_direct_size; */ extern unsigned int bitmap_compressed_size; - #endif diff --git a/riscos/gui.c b/riscos/gui.c index b5ef080bf..d01ee6dfb 100644 --- a/riscos/gui.c +++ b/riscos/gui.c @@ -174,7 +174,7 @@ static struct { } prev_sigs; /** Accepted wimp user messages. */ -static wimp_MESSAGE_LIST(40) task_messages = { { +static wimp_MESSAGE_LIST(41) task_messages = { { message_HELP_REQUEST, message_DATA_SAVE, message_DATA_SAVE_ACK, @@ -185,6 +185,7 @@ static wimp_MESSAGE_LIST(40) task_messages = { { message_SAVE_DESKTOP, message_MENU_WARNING, message_MENUS_DELETED, + message_WINDOW_INFO, message_MODE_CHANGE, message_CLAIM_ENTITY, message_DATA_REQUEST, @@ -261,6 +262,7 @@ static void ro_msg_dataopen(wimp_message *message); static void ro_gui_get_screen_properties(void); static void ro_msg_prequit(wimp_message *message); static void ro_msg_save_desktop(wimp_message *message); +static void ro_msg_window_info(wimp_message *message); static void ro_gui_view_source_bounce(wimp_message *message); @@ -410,6 +412,8 @@ void gui_init(int argc, char** argv) ro_gui_selection_dragging); ro_message_register_route(message_DRAG_CLAIM, ro_gui_selection_drag_claim); + ro_message_register_route(message_WINDOW_INFO, + ro_msg_window_info); /* end of handler registration */ nsfont_init(); @@ -1961,6 +1965,25 @@ void ro_msg_save_desktop(wimp_message *message) } +/** + * Handle WindowInfo message (part of the iconising protocol) + * + * \param message WindowInfo message from the Iconiser + */ + +void ro_msg_window_info(wimp_message *message) +{ + wimp_full_message_window_info *wi; + struct gui_window *g; + + wi = (wimp_full_message_window_info*)message; + g = ro_gui_window_lookup(wi->w); + + /* ic_ will suffice for our other windows */ + if (g) ro_gui_window_iconise(g, wi); +} + + /** * Convert a RISC OS pathname to a file: URL. * diff --git a/riscos/gui.h b/riscos/gui.h index c6266bc9a..7eb55b746 100644 --- a/riscos/gui.h +++ b/riscos/gui.h @@ -80,6 +80,8 @@ struct gui_window { int throbber; /**< Current frame of throbber animation. */ int throbtime; /**< Time of last throbber frame. */ + int iconise_icon; /**< ID number of icon when window is iconised */ + /** Options. */ struct { float scale; /**< Scale, 1.0 = 100%. */ @@ -161,6 +163,7 @@ bool ro_gui_shift_pressed(void); bool ro_gui_ctrl_pressed(void); void ro_gui_window_scroll_end(struct gui_window *g, wimp_dragged *drag); void ro_gui_window_set_scale(struct gui_window *g, float scale); +void ro_gui_window_iconise(struct gui_window *g, wimp_full_message_window_info *wi); /* in history.c */ void ro_gui_history_init(void); diff --git a/riscos/print.c b/riscos/print.c index 21b3a511b..724576aff 100644 --- a/riscos/print.c +++ b/riscos/print.c @@ -99,6 +99,8 @@ static bool print_fonts_plot_text(int x, int y, struct css_style *style, const char *text, size_t length, colour bg, colour c); static bool print_fonts_plot_disc(int x, int y, int radius, colour c, bool filled); +static bool print_fonts_plot_arc(int x, int y, int radius, int angle1, int angle2, + colour c); static bool print_fonts_plot_bitmap(int x, int y, int width, int height, struct bitmap *bitmap, colour bg); static bool print_fonts_plot_bitmap_tile(int x, int y, int width, int height, @@ -123,6 +125,7 @@ static const struct plotter_table print_fonts_plotters = { print_fonts_plot_clip, print_fonts_plot_text, print_fonts_plot_disc, + print_fonts_plot_arc, print_fonts_plot_bitmap, print_fonts_plot_bitmap_tile, print_fonts_plot_group_start, @@ -811,6 +814,9 @@ bool print_fonts_plot_clip(int clip_x0, int clip_y0, int clip_x1, int clip_y1) { return true; } bool print_fonts_plot_disc(int x, int y, int radius, colour colour, bool filled) { return true; } +bool print_fonts_plot_arc(int x, int y, int radius, int angle1, int angle2, + colour c) + { return true; } bool print_fonts_plot_bitmap(int x, int y, int width, int height, struct bitmap *bitmap, colour bg) { return true; } bool print_fonts_plot_bitmap_tile(int x, int y, int width, int height, diff --git a/riscos/save.c b/riscos/save.c index 2fe3c59eb..67a860ee1 100644 --- a/riscos/save.c +++ b/riscos/save.c @@ -1033,7 +1033,7 @@ bool ro_gui_save_create_thumbnail(struct content *c, const char *name) } sprite_header = (osspriteop_header *)(area + 1); - memcpy(sprite_header->name, name, 12); + strncpy(sprite_header->name, name, 12); /* we can't resize the saveas sprite area because it may move and we have no elegant way to update the window definition on all OS versions */ diff --git a/riscos/sprite.c b/riscos/sprite.c index 27bc4f8af..941e224f0 100644 --- a/riscos/sprite.c +++ b/riscos/sprite.c @@ -110,3 +110,37 @@ bool sprite_redraw(struct content *c, int x, int y, } #endif + + +/** + * Returns the bit depth of a sprite + * + * \param s sprite + * \return depth in bpp + */ + +byte sprite_bpp(const osspriteop_header *s) +{ + /* bit 31 indicates the presence of a full alpha channel rather than a binary mask */ + int type = ((unsigned)s->mode >> osspriteop_TYPE_SHIFT) & 15; + byte bpp = 0; + + switch (type) { + case osspriteop_TYPE_OLD: + { + bits psr; + int val; + if (!xos_read_mode_variable(s->mode, os_MODEVAR_LOG2_BPP, &val, &psr) && + !(psr & _C)) bpp = 1 << val; + } + break; + case osspriteop_TYPE1BPP: bpp = 1; break; + case osspriteop_TYPE2BPP: bpp = 2; break; + case osspriteop_TYPE4BPP: bpp = 4; break; + case osspriteop_TYPE8BPP: bpp = 8; break; + case osspriteop_TYPE16BPP: bpp = 16; break; + case osspriteop_TYPE32BPP: bpp = 32; break; + case osspriteop_TYPE_CMYK: bpp = 32; break; + } + return bpp; +} diff --git a/riscos/sprite.h b/riscos/sprite.h index f360d2bb0..3e9c836bb 100644 --- a/riscos/sprite.h +++ b/riscos/sprite.h @@ -13,6 +13,7 @@ #define _NETSURF_RISCOS_SPRITE_H_ #include +#include "oslib/osspriteop.h" struct content; @@ -27,4 +28,6 @@ bool sprite_redraw(struct content *c, int x, int y, int clip_x0, int clip_y0, int clip_x1, int clip_y1, float scale, colour background_colour); +byte sprite_bpp(const osspriteop_header *s); + #endif diff --git a/riscos/thumbnail.c b/riscos/thumbnail.c index 8c5351cac..ed240fd28 100644 --- a/riscos/thumbnail.c +++ b/riscos/thumbnail.c @@ -156,7 +156,7 @@ osspriteop_area *thumbnail_convert_8bpp(struct bitmap *bitmap) osspriteop_area *sprite_area = NULL; osspriteop_header *sprite_header = NULL; - sprite_area = thumbnail_create_8bpp(bitmap); + sprite_area = thumbnail_create_8bpp(bitmap); if (!sprite_area) return NULL; sprite_header = (osspriteop_header *)(sprite_area + 1); @@ -175,6 +175,30 @@ osspriteop_area *thumbnail_convert_8bpp(struct bitmap *bitmap) 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); + int h = bitmap_get_width(bitmap); + int w = 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; } @@ -187,15 +211,20 @@ osspriteop_area *thumbnail_convert_8bpp(struct bitmap *bitmap) */ osspriteop_area *thumbnail_create_8bpp(struct bitmap *bitmap) { - unsigned int area_size; - osspriteop_area *sprite_area = NULL; + 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) + - ((bitmap->width + 3) & ~3) * bitmap->height + + image_size + 2048; + + if (!opaque) area_size += image_size; + sprite_area = (osspriteop_area *)malloc(area_size); if (!sprite_area) { LOG(("no memory for malloc()")); @@ -216,6 +245,7 @@ osspriteop_area *thumbnail_create_8bpp(struct bitmap *bitmap) 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 diff --git a/riscos/window.c b/riscos/window.c index 26e3be4e3..cb66962df 100644 --- a/riscos/window.c +++ b/riscos/window.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,7 @@ #include "netsurf/desktop/gui.h" #include "netsurf/render/box.h" #include "netsurf/render/form.h" +#include "netsurf/riscos/bitmap.h" #include "netsurf/riscos/buffer.h" #include "netsurf/riscos/dialog.h" #include "netsurf/riscos/global_history.h" @@ -61,6 +63,10 @@ #define SCROLL_VISIBLE_PADDING 32 +/** Remembers which iconised sprite numbers are in use */ +static bool iconise_used[64]; +static int iconise_next = 0; + /** List of all browser windows. */ static struct gui_window *window_list = 0; /** GUI window which is being redrawn. Valid only during redraw. */ @@ -112,6 +118,7 @@ struct gui_window *gui_create_browser_window(struct browser_window *bw, strcpy(g->title, "NetSurf"); g->throbber = 0; g->throbtime = 0; + g->iconise_icon = -1; /* Set the window position */ @@ -1173,6 +1180,12 @@ void ro_gui_window_open(struct gui_window *g, wimp_open *open) int key_down = 0; int inset = 0; + if (open->next == wimp_TOP && g->iconise_icon >= 0) { + /* window is no longer iconised, release its sprite number */ + iconise_used[g->iconise_icon] = false; + g->iconise_icon = -1; + } + content = g->bw->current_content; /* check for toggle to full size so we can force to full height for short contents */ @@ -2931,3 +2944,120 @@ bool ro_gui_window_import_text(struct gui_window *g, const char *filename, free(utf8_buf); return true; } + + +/** + * Window is being iconised. Create a suitable thumbnail sprite + * (which, sadly, must be in the Wimp sprite pool), and return + * the sprite name and truncated title to the iconiser + * + * \param g the gui window being iconised + * \param wi the WindowInfo message from the iconiser + */ + +void ro_gui_window_iconise(struct gui_window *g, wimp_full_message_window_info *wi) +{ + /* sadly there is no 'legal' way to get the sprite into + the Wimp sprite pool other than via a filing system */ + const char *temp_fname = "Pipe:$._tmpfile"; + struct browser_window *bw = g->bw; + osspriteop_header *overlay = NULL; + osspriteop_header *sprite_header; + struct bitmap *bitmap; + osspriteop_area *area; + int w = 34, h = 34; + struct content *c; + os_error *error; + int len, id; + + assert(bw); + + c = bw->current_content; + if (!c) return; + + /* if an overlay sprite is defined, locate it and gets its dimensions + so that we can produce a thumbnail with the same dimensions */ + if (!ro_gui_wimp_get_sprite("ic_netsfxx", &overlay)) { + error = xosspriteop_read_sprite_info(osspriteop_PTR, + (osspriteop_area *)0x100, + (osspriteop_id)overlay, &w, &h, NULL, NULL); + if (error) { + LOG(("xosspriteop_read_sprite_info: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("MiscError", error->errmess); + overlay = NULL; + } + else if (sprite_bpp(overlay) != 8) { + LOG(("overlay sprite is not 8bpp")); + overlay = NULL; + } + } + + /* create the thumbnail sprite */ + bitmap = bitmap_create(w, h, BITMAP_NEW | BITMAP_OPAQUE | BITMAP_CLEAR_MEMORY); + if (!bitmap) { + LOG(("Thumbnail initialisation failed.")); + return; + } + thumbnail_create(c, bitmap, NULL); + if (overlay) bitmap_overlay_sprite(bitmap, overlay); + + area = thumbnail_convert_8bpp(bitmap); + bitmap_destroy(bitmap); + if (!area) { + LOG(("Thumbnail conversion failed.")); + return; + } + + /* choose a suitable sprite name */ + id = 0; + while (iconise_used[id]) + if (++id >= NOF_ELEMENTS(iconise_used)) { + id = iconise_next; + if (++iconise_next >= NOF_ELEMENTS(iconise_used)) + iconise_next = 0; + break; + } + + sprite_header = (osspriteop_header *)(area + 1); + len = sprintf(sprite_header->name, "ic_netsf%.2d", id); + + error = xosspriteop_save_sprite_file(osspriteop_USER_AREA, + area, temp_fname); + if (error) { + LOG(("xosspriteop_save_sprite_file: 0x%x:%s", + error->errnum, error->errmess)); + warn_user("MiscError", error->errmess); + free(area); + return; + } + + error = xwimpspriteop_merge_sprite_file(temp_fname); + if (error) { + LOG(("xwimpspriteop_merge_sprite_file: 0x%x:%s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + remove(temp_fname); + free(area); + return; + } + + memcpy(wi->sprite_name, sprite_header->name + 3, len - 2); /* inc NUL */ + strncpy(wi->title, g->title, sizeof(wi->title)); + wi->title[sizeof(wi->title) - 1] = '\0'; + + wi->size = sizeof(wimp_full_message_window_info); + wi->your_ref = wi->my_ref; + error = xwimp_send_message(wimp_USER_MESSAGE, (wimp_message*)wi, wi->sender); + if (error) { + LOG(("xwimp_send_message: 0x%x:%s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + } + else { + g->iconise_icon = id; + iconise_used[id] = true; + } + + free(area); +} -- cgit v1.2.3