michael@0: b=455513; add optional flag to allow converting a DDB to a DIB internally, if the surface is every used as a source; r=jmuizelaar michael@0: michael@0: If a DDB is used as a source for an operation that can't be handled michael@0: natively by GDI, we end up needing to take a really slow path (creating a michael@0: temporary surface for acquire_source) for each operation. If we convert michael@0: the DDB to a DIB, we then end up having a real image buffer and can hand michael@0: things off to pixman directly. michael@0: michael@0: This isn't the default mode because I'm not sure if there are cases where a michael@0: DDB is explicitly needed (e.g. for printing), and it would change michael@0: current cairo behaviour. It might become the default at some point in the michael@0: future. michael@0: michael@0: diff --git a/gfx/cairo/cairo/src/cairo-win32-private.h b/gfx/cairo/cairo/src/cairo-win32-private.h michael@0: --- a/gfx/cairo/cairo/src/cairo-win32-private.h michael@0: +++ b/gfx/cairo/cairo/src/cairo-win32-private.h michael@0: @@ -117,6 +117,9 @@ michael@0: michael@0: /* Whether we can use the CHECKJPEGFORMAT escape function */ michael@0: CAIRO_WIN32_SURFACE_CAN_CHECK_PNG = (1<<8), michael@0: + michael@0: + /* if this DDB surface can be converted to a DIB if necessary */ michael@0: + CAIRO_WIN32_SURFACE_CAN_CONVERT_TO_DIB = (1<<9), michael@0: }; michael@0: michael@0: cairo_status_t michael@0: diff --git a/gfx/cairo/cairo/src/cairo-win32-surface.c b/gfx/cairo/cairo/src/cairo-win32-surface.c michael@0: --- a/gfx/cairo/cairo/src/cairo-win32-surface.c michael@0: +++ b/gfx/cairo/cairo/src/cairo-win32-surface.c michael@0: @@ -560,6 +560,56 @@ michael@0: return CAIRO_STATUS_SUCCESS; michael@0: } michael@0: michael@0: +static void michael@0: +_cairo_win32_convert_ddb_to_dib (cairo_win32_surface_t *surface) michael@0: +{ michael@0: + cairo_win32_surface_t *new_surface; michael@0: + int width = surface->extents.width; michael@0: + int height = surface->extents.height; michael@0: + michael@0: + BOOL ok; michael@0: + HBITMAP oldbitmap; michael@0: + michael@0: + new_surface = (cairo_win32_surface_t*) michael@0: + _cairo_win32_surface_create_for_dc (surface->dc, michael@0: + surface->format, michael@0: + width, michael@0: + height); michael@0: + michael@0: + if (new_surface->base.status) michael@0: + return; michael@0: + michael@0: + /* DDB can't be 32bpp, so BitBlt is safe */ michael@0: + ok = BitBlt (new_surface->dc, michael@0: + 0, 0, width, height, michael@0: + surface->dc, michael@0: + 0, 0, SRCCOPY); michael@0: + michael@0: + if (!ok) michael@0: + goto out; michael@0: + michael@0: + /* Now swap around new_surface and surface's internal bitmap michael@0: + * pointers. */ michael@0: + DeleteDC (new_surface->dc); michael@0: + new_surface->dc = NULL; michael@0: + michael@0: + oldbitmap = SelectObject (surface->dc, new_surface->bitmap); michael@0: + DeleteObject (oldbitmap); michael@0: + michael@0: + surface->image = new_surface->image; michael@0: + surface->is_dib = new_surface->is_dib; michael@0: + surface->bitmap = new_surface->bitmap; michael@0: + michael@0: + new_surface->bitmap = NULL; michael@0: + new_surface->image = NULL; michael@0: + michael@0: + /* Finally update flags */ michael@0: + surface->flags = _cairo_win32_flags_for_dc (surface->dc); michael@0: + michael@0: + out: michael@0: + cairo_surface_destroy ((cairo_surface_t*)new_surface); michael@0: +} michael@0: + michael@0: static cairo_status_t michael@0: _cairo_win32_surface_acquire_source_image (void *abstract_surface, michael@0: cairo_image_surface_t **image_out, michael@0: @@ -568,6 +618,17 @@ michael@0: cairo_win32_surface_t *surface = abstract_surface; michael@0: cairo_win32_surface_t *local = NULL; michael@0: cairo_status_t status; michael@0: + michael@0: + if (!surface->image && !surface->is_dib && surface->bitmap && michael@0: + (surface->flags & CAIRO_WIN32_SURFACE_CAN_CONVERT_TO_DIB) != 0) michael@0: + { michael@0: + /* This is a DDB, and we're being asked to use it as a source for michael@0: + * something that we couldn't support natively. So turn it into michael@0: + * a DIB, so that we have an equivalent image surface, as long michael@0: + * as we're allowed to via flags. michael@0: + */ michael@0: + _cairo_win32_convert_ddb_to_dib (surface); michael@0: + } michael@0: michael@0: if (surface->image) { michael@0: *image_out = (cairo_image_surface_t *)surface->image; michael@0: @@ -2133,3 +2194,61 @@ michael@0: free(rd); michael@0: fflush (stderr); michael@0: } michael@0: + michael@0: +/** michael@0: + * cairo_win32_surface_set_can_convert_to_dib michael@0: + * @surface: a #cairo_surface_t michael@0: + * @can_convert: a #cairo_bool_t indicating whether this surface can michael@0: + * be coverted to a DIB if necessary michael@0: + * michael@0: + * A DDB surface with this flag set can be converted to a DIB if it's michael@0: + * used as a source in a way that GDI can't natively handle; for michael@0: + * example, drawing a RGB24 DDB onto an ARGB32 DIB. Doing this michael@0: + * conversion results in a significant speed optimization, because we michael@0: + * can call on pixman to perform the operation natively, instead of michael@0: + * reading the data from the DC each time. michael@0: + * michael@0: + * Return value: %CAIRO_STATUS_SUCCESS if the flag was successfully michael@0: + * changed, or an error otherwise. michael@0: + * michael@0: + */ michael@0: +cairo_status_t michael@0: +cairo_win32_surface_set_can_convert_to_dib (cairo_surface_t *asurface, cairo_bool_t can_convert) michael@0: +{ michael@0: + cairo_win32_surface_t *surface = (cairo_win32_surface_t*) asurface; michael@0: + if (surface->base.type != CAIRO_SURFACE_TYPE_WIN32) michael@0: + return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; michael@0: + michael@0: + if (surface->bitmap) { michael@0: + if (can_convert) michael@0: + surface->flags |= CAIRO_WIN32_SURFACE_CAN_CONVERT_TO_DIB; michael@0: + else michael@0: + surface->flags &= ~CAIRO_WIN32_SURFACE_CAN_CONVERT_TO_DIB; michael@0: + } michael@0: + michael@0: + return CAIRO_STATUS_SUCCESS; michael@0: +} michael@0: + michael@0: +/** michael@0: + * cairo_win32_surface_get_can_convert_to_dib michael@0: + * @surface: a #cairo_surface_t michael@0: + * @can_convert: a #cairo_bool_t* that receives the return value michael@0: + * michael@0: + * Returns the value of the flag indicating whether the surface can be michael@0: + * converted to a DIB if necessary, as set by michael@0: + * cairo_win32_surface_set_can_convert_to_dib. michael@0: + * michael@0: + * Return value: %CAIRO_STATUS_SUCCESS if the flag was successfully michael@0: + * retreived, or an error otherwise. michael@0: + * michael@0: + */ michael@0: +cairo_status_t michael@0: +cairo_win32_surface_get_can_convert_to_dib (cairo_surface_t *asurface, cairo_bool_t *can_convert) michael@0: +{ michael@0: + cairo_win32_surface_t *surface = (cairo_win32_surface_t*) asurface; michael@0: + if (surface->base.type != CAIRO_SURFACE_TYPE_WIN32) michael@0: + return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; michael@0: + michael@0: + *can_convert = ((surface->flags & CAIRO_WIN32_SURFACE_CAN_CONVERT_TO_DIB) != 0); michael@0: + return CAIRO_STATUS_SUCCESS; michael@0: +} michael@0: diff --git a/gfx/cairo/cairo/src/cairo-win32.h b/gfx/cairo/cairo/src/cairo-win32.h michael@0: --- a/gfx/cairo/cairo/src/cairo-win32.h michael@0: +++ b/gfx/cairo/cairo/src/cairo-win32.h michael@0: @@ -68,6 +68,12 @@ cairo_win32_surface_get_dc (cairo_surface_t *surface); michael@0: cairo_public cairo_surface_t * michael@0: cairo_win32_surface_get_image (cairo_surface_t *surface); michael@0: michael@0: +cairo_public cairo_status_t michael@0: +cairo_win32_surface_set_can_convert_to_dib (cairo_surface_t *surface, cairo_bool_t can_convert); michael@0: + michael@0: +cairo_public cairo_status_t michael@0: +cairo_win32_surface_get_can_convert_to_dib (cairo_surface_t *surface, cairo_bool_t *can_convert); michael@0: + michael@0: #if CAIRO_HAS_WIN32_FONT michael@0: