/** * Create a thumbnail of a page. * * \param content content structure to thumbnail * \param bitmap the bitmap to draw to * \param url the URL the thumnail belongs to, or NULL */ bool thumbnail_create(hlcache_handle *content, struct bitmap *bitmap, const char *url) { cairo_surface_t *dsurface = bitmap->surface; cairo_surface_t *surface; cairo_t *old_cr; gint dwidth, dheight; int cwidth, cheight; struct redraw_context ctx = { .interactive = false, .background_images = true, .plot = &nsgtk_plotters }; assert(content); assert(bitmap); dwidth = cairo_image_surface_get_width(dsurface); dheight = cairo_image_surface_get_height(dsurface); /* Calculate size of buffer to render the content into */ /* We get the width from the content width, unless it exceeds 1024, * in which case we use 1024. This means we never create excessively * large render buffers for huge contents, which would eat memory and * cripple performance. */ cwidth = min(content_get_width(content), 1024); /* The height is set in proportion with the width, according to the * aspect ratio of the required thumbnail. */ cheight = ((cwidth * dheight) + (dwidth / 2)) / dwidth; /* Create surface to render into */ surface = cairo_surface_create_similar(dsurface, CAIRO_CONTENT_COLOR_ALPHA, cwidth, cheight); if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { cairo_surface_destroy(surface); return false; } old_cr = current_cr; current_cr = cairo_create(surface); /* render the content */ thumbnail_redraw(content, cwidth, cheight, &ctx); cairo_destroy(current_cr); current_cr = old_cr; cairo_t *cr = cairo_create(dsurface); /* Scale *before* setting the source surface (1) */ cairo_scale (cr, (double)dwidth / cwidth, (double)dheight / cheight); cairo_set_source_surface (cr, surface, 0, 0); /* To avoid getting the edge pixels blended with 0 alpha, * which would occur with the default EXTEND_NONE. Use * EXTEND_PAD for 1.2 or newer (2) */ cairo_pattern_set_extend (cairo_get_source(cr), CAIRO_EXTEND_REFLECT); /* Replace the destination with the source instead of overlaying */ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); /* Do the actual drawing */ cairo_paint(cr); cairo_destroy(cr); cairo_surface_destroy(surface); /* register the thumbnail with the URL */ if (url) urldb_set_thumbnail(url, bitmap); return true; }
/** * Recursively redraw a history_entry. * * \param history history containing the entry * \param entry entry to render * \param x0 area top left x coordinate * \param y0 area top left y coordinate * \param x1 area bottom right x coordinate * \param y1 area bottom right y coordinate * \param x window x offset * \param y window y offset * \param clip clip redraw * \param ctx current redraw context */ static bool browser_window_history__redraw_entry(struct history *history, struct history_entry *entry, int x0, int y0, int x1, int y1, int x, int y, bool clip, const struct redraw_context *ctx) { const struct plotter_table *plot = ctx->plot; size_t char_offset; int actual_x; struct history_entry *child; colour c = entry == history->current ? HISTORY_COLOUR_SELECTED : HISTORY_COLOUR_FOREGROUND; int tailsize = 5; int xoffset = x - x0; int yoffset = y - y0; plot_style_t pstyle_history_rect = { .stroke_type = PLOT_OP_TYPE_SOLID, .stroke_colour = c, .stroke_width = entry == history->current ? 3 : 1, }; plot_font_style_t fstyle = *plot_style_font; if (clip) { struct rect rect; rect.x0 = x0 + xoffset; rect.y0 = y0 + yoffset; rect.x1 = x1 + xoffset; rect.y1 = y1 + yoffset; if (!plot->clip(&rect)) { return false; } } /* Only attempt to plot bitmap if it is present */ if (entry->bitmap != NULL) { plot->bitmap(entry->x + xoffset, entry->y + yoffset, WIDTH, HEIGHT, entry->bitmap, 0xffffff, 0); } if (!plot->rectangle(entry->x - 1 + xoffset, entry->y - 1 + yoffset, entry->x + xoffset + WIDTH, entry->y + yoffset + HEIGHT, &pstyle_history_rect)) return false; if (!nsfont.font_position_in_string(plot_style_font, entry->page.title, strlen(entry->page.title), WIDTH, &char_offset, &actual_x)) return false; fstyle.background = HISTORY_COLOUR_BACKGROUND; fstyle.foreground = c; fstyle.weight = entry == history->current ? 900 : 400; if (!plot->text(entry->x + xoffset, entry->y + HEIGHT + 12 + yoffset, entry->page.title, char_offset, &fstyle)) return false; for (child = entry->forward; child; child = child->next) { if (!plot->line(entry->x + WIDTH + xoffset, entry->y + HEIGHT / 2 + yoffset, entry->x + WIDTH + tailsize + xoffset, entry->y + HEIGHT / 2 + yoffset, plot_style_stroke_history)) return false; if (!plot->line(entry->x + WIDTH + tailsize + xoffset, entry->y + HEIGHT / 2 + yoffset, child->x - tailsize +xoffset, child->y + HEIGHT / 2 + yoffset, plot_style_stroke_history)) return false; if (!plot->line(child->x - tailsize + xoffset, child->y + HEIGHT / 2 + yoffset, child->x + xoffset, child->y + HEIGHT / 2 + yoffset, plot_style_stroke_history)) return false; if (!browser_window_history__redraw_entry(history, child, x0, y0, x1, y1, x, y, clip, ctx)) return false; } return true; } /** * Find the history entry at a position. * * \param entry entry to search from * \param x coordinate * \param y coordinate * \return an entry if found, 0 if none */ static struct history_entry *browser_window_history__find_position( struct history_entry *entry, int x, int y) { struct history_entry *child; struct history_entry *found; if (!entry) return 0; if (entry->x <= x && x <= entry->x + WIDTH && entry->y <= y && y <= entry->y + HEIGHT) return entry; for (child = entry->forward; child; child = child->next) { found = browser_window_history__find_position(child, x, y); if (found) return found; } return 0; } /** * Enumerate subentries in history * See also history_enumerate() * * \param bw The browser window to enumerate history of * \param entry entry to start enumeration at * \param cb callback function * \param ud context pointer passed to cb * \return true to continue enumeration, false to cancel */ static bool browser_window_history__enumerate_entry( const struct browser_window *bw, const struct history_entry *entry, browser_window_history_enumerate_cb cb, void *ud) { const struct history_entry *child; if (!cb(bw, entry->x, entry->y, entry->x + WIDTH, entry->y + HEIGHT, entry, ud)) return false; for (child = entry->forward; child; child = child->next) { if (!browser_window_history__enumerate_entry(bw, child, cb, ud)) return false; } return true; } /* -------------------------------------------------------------------------- */ /* exported interface documented in desktop/browser_history.h */ nserror browser_window_history_create(struct browser_window *bw) { struct history *history; bw->history = NULL; history = calloc(1, sizeof *history); if (history == NULL) { return NSERROR_NOMEM; } history->width = RIGHT_MARGIN / 2; history->height = BOTTOM_MARGIN / 2; bw->history = history; return NSERROR_OK; } /* exported interface documented in desktop/browser_history.h */ nserror browser_window_history_clone(const struct browser_window *existing, struct browser_window *clone) { struct history *new_history; clone->history = NULL; if (existing == NULL || existing->history == NULL || existing->history->start == NULL) /* Nothing to clone, create new history for clone window */ return browser_window_history_create(clone); /* Make cloned history */ new_history = malloc(sizeof *new_history); if (!new_history) return NSERROR_NOMEM; clone->history = new_history; memcpy(new_history, existing->history, sizeof *new_history); new_history->start = browser_window_history__clone_entry(new_history, new_history->start); if (!new_history->start) { LOG("Insufficient memory to clone history"); browser_window_history_destroy(clone); clone->history = NULL; return NSERROR_NOMEM; } return NSERROR_OK; } /* exported interface documented in desktop/browser_history.h */ nserror browser_window_history_add(struct browser_window *bw, struct hlcache_handle *content, lwc_string *frag_id) { struct history *history; struct history_entry *entry; nsurl *nsurl = hlcache_handle_get_url(content); char *title; struct bitmap *bitmap; nserror ret; assert(bw); assert(bw->history); assert(content); history = bw->history; /* allocate space */ entry = malloc(sizeof *entry); if (entry == NULL) { return NSERROR_NOMEM; } title = strdup(content_get_title(content)); if (title == NULL) { free(entry); return NSERROR_NOMEM; } entry->page.url = nsurl_ref(nsurl); entry->page.frag_id = frag_id ? lwc_string_ref(frag_id) : 0; entry->page.title = title; entry->back = history->current; entry->next = 0; entry->forward = entry->forward_pref = entry->forward_last = 0; entry->children = 0; entry->bitmap = 0; if (history->current) { if (history->current->forward_last) history->current->forward_last->next = entry; else history->current->forward = entry; history->current->forward_pref = entry; history->current->forward_last = entry; history->current->children++; } else { history->start = entry; } history->current = entry; /* if we have a thumbnail, don't update until the page has finished * loading */ bitmap = urldb_get_thumbnail(nsurl); if (bitmap == NULL) { LOG("Creating thumbnail for %s", nsurl_access(nsurl)); bitmap = guit->bitmap->create(WIDTH, HEIGHT, BITMAP_NEW | BITMAP_CLEAR_MEMORY | BITMAP_OPAQUE); if (bitmap != NULL) { ret = guit->bitmap->render(bitmap, content); if (ret == NSERROR_OK) { /* Successful thumbnail so register it * with the url. */ urldb_set_thumbnail(nsurl, bitmap); } else { /* Thumbnailing failed. Ignore it * silently but clean up bitmap. */ LOG("Thumbnail renderfailed"); guit->bitmap->destroy(bitmap); bitmap = NULL; } } } entry->bitmap = bitmap; browser_window_history__layout(history); return NSERROR_OK; } /* exported interface documented in desktop/browser_history.h */ nserror browser_window_history_update(struct browser_window *bw, struct hlcache_handle *content) { struct history *history; char *title; assert(bw != NULL); history = bw->history; if (!history || !history->current || !history->current->bitmap) { return NSERROR_INVALID; } assert(history->current->page.url); assert(history->current->page.title); title = strdup(content_get_title(content)); if (title == NULL) { return NSERROR_NOMEM; } free(history->current->page.title); history->current->page.title = title; guit->bitmap->render(history->current->bitmap, content); return NSERROR_OK; } /* exported interface documented in desktop/browser_history.h */ void browser_window_history_destroy(struct browser_window *bw) { assert(bw != NULL); if (bw->history == NULL) return; browser_window_history__free_entry(bw->history->start); free(bw->history); bw->history = NULL; }
bool thumbnail_create(hlcache_handle *content, struct bitmap *bitmap, const char *url) { struct BitScaleArgs bsa; int plot_width; int plot_height; int redraw_tile_size = nsoption_int(redraw_tile_size_x); struct redraw_context ctx = { .interactive = false, .background_images = true, .plot = &amiplot }; if(nsoption_int(redraw_tile_size_y) < nsoption_int(redraw_tile_size_x)) redraw_tile_size = nsoption_int(redraw_tile_size_y); plot_width = MIN(content_get_width(content), redraw_tile_size); plot_height = ((plot_width * bitmap->height) + (bitmap->width / 2)) / bitmap->width; bitmap->nativebm = p96AllocBitMap(bitmap->width, bitmap->height, 32, BMF_CLEAR | BMF_DISPLAYABLE | BMF_INTERLEAVED, browserglob.bm, RGBFB_A8R8G8B8); bitmap->nativebmwidth = bitmap->width; bitmap->nativebmheight = bitmap->height; ami_clearclipreg(&browserglob); thumbnail_redraw(content, plot_width, plot_height, &ctx); if(GfxBase->LibNode.lib_Version >= 53) // AutoDoc says v52, but this function isn't in OS4.0, so checking for v53 (OS4.1) { float resample_scale = bitmap->width / (float)plot_width; uint32 flags = COMPFLAG_IgnoreDestAlpha | COMPFLAG_SrcAlphaOverride; if(nsoption_bool(scale_quality)) flags |= COMPFLAG_SrcFilter; CompositeTags(COMPOSITE_Src,browserglob.bm,bitmap->nativebm, COMPTAG_ScaleX, COMP_FLOAT_TO_FIX(resample_scale), COMPTAG_ScaleY, COMP_FLOAT_TO_FIX(resample_scale), COMPTAG_Flags,flags, COMPTAG_DestX,0, COMPTAG_DestY,0, COMPTAG_DestWidth,bitmap->width, COMPTAG_DestHeight,bitmap->height, COMPTAG_OffsetX,0, COMPTAG_OffsetY,0, TAG_DONE); } else { bsa.bsa_SrcX = 0; bsa.bsa_SrcY = 0; bsa.bsa_SrcWidth = plot_width; bsa.bsa_SrcHeight = plot_height; bsa.bsa_DestX = 0; bsa.bsa_DestY = 0; // bsa.bsa_DestWidth = width; // bsa.bsa_DestHeight = height; bsa.bsa_XSrcFactor = plot_width; bsa.bsa_XDestFactor = bitmap->width; bsa.bsa_YSrcFactor = plot_height; bsa.bsa_YDestFactor = bitmap->height; bsa.bsa_SrcBitMap = browserglob.bm; bsa.bsa_DestBitMap = bitmap->nativebm; bsa.bsa_Flags = 0; BitMapScale(&bsa); } if (url) urldb_set_thumbnail(url, bitmap); return true; }