Beispiel #1
0
/**
 * 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;
}
Beispiel #2
0
/**
 * 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;
}
Beispiel #3
0
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;
}