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

If a DDB is used as a source for an operation that can't be handled
natively by GDI, we end up needing to take a really slow path (creating a
temporary surface for acquire_source) for each operation.  If we convert
the DDB to a DIB, we then end up having a real image buffer and can hand
things off to pixman directly.

This isn't the default mode because I'm not sure if there are cases where a
DDB is explicitly needed (e.g. for printing), and it would change
current cairo behaviour.  It might become the default at some point in the
future.
This commit is contained in:
Vladimir Vukicevic 2008-11-09 15:40:55 -08:00
Родитель a93b615c31
Коммит 3679e3522b
5 изменённых файлов: 312 добавлений и 0 удалений

Просмотреть файл

@ -30,6 +30,8 @@ tmpfile_wince.patch: Make Windows CE use tmpfile() on windows mobile due to the
cairo-version-fixes.patch: fix up cairo-version.c/cairo-version.h for in-place builds
win32-ddb-dib.patch: fix for bug 455513; not upstream yet pending feebdack
==== pixman patches ====
endian.patch: include cairo-platform.h for endian macros

Просмотреть файл

@ -117,6 +117,9 @@ enum {
/* Whether we can use GradientFill rectangles with this surface */
CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT = (1<<6),
/* if this DDB surface can be converted to a DIB if necessary */
CAIRO_WIN32_SURFACE_CAN_CONVERT_TO_DIB = (1<<7),
};
cairo_status_t

Просмотреть файл

@ -560,6 +560,56 @@ _cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_win32_convert_ddb_to_dib (cairo_win32_surface_t *surface)
{
cairo_win32_surface_t *new_surface;
int width = surface->extents.width;
int height = surface->extents.height;
BOOL ok;
HBITMAP oldbitmap;
new_surface = (cairo_win32_surface_t*)
_cairo_win32_surface_create_for_dc (surface->dc,
surface->format,
width,
height);
if (new_surface->base.status)
return;
/* DDB can't be 32bpp, so BitBlt is safe */
ok = BitBlt (new_surface->dc,
0, 0, width, height,
surface->dc,
0, 0, SRCCOPY);
if (!ok)
goto out;
/* Now swap around new_surface and surface's internal bitmap
* pointers. */
DeleteDC (new_surface->dc);
new_surface->dc = NULL;
oldbitmap = SelectObject (surface->dc, new_surface->bitmap);
DeleteObject (oldbitmap);
surface->image = new_surface->image;
surface->is_dib = new_surface->is_dib;
surface->bitmap = new_surface->bitmap;
new_surface->bitmap = NULL;
new_surface->image = NULL;
/* Finally update flags */
surface->flags = _cairo_win32_flags_for_dc (surface->dc);
out:
cairo_surface_destroy ((cairo_surface_t*)new_surface);
}
static cairo_status_t
_cairo_win32_surface_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out,
@ -569,6 +619,17 @@ _cairo_win32_surface_acquire_source_image (void *abstract_sur
cairo_win32_surface_t *local = NULL;
cairo_status_t status;
if (!surface->image && !surface->is_dib && surface->bitmap &&
(surface->flags & CAIRO_WIN32_SURFACE_CAN_CONVERT_TO_DIB) != 0)
{
/* This is a DDB, and we're being asked to use it as a source for
* something that we couldn't support natively. So turn it into
* a DIB, so that we have an equivalent image surface, as long
* as we're allowed to via flags.
*/
_cairo_win32_convert_ddb_to_dib (surface);
}
if (surface->image) {
*image_out = (cairo_image_surface_t *)surface->image;
*image_extra = NULL;
@ -2133,3 +2194,61 @@ _cairo_win32_debug_dump_hrgn (HRGN rgn, char *header)
free(rd);
fflush (stderr);
}
/**
* cairo_win32_surface_set_can_convert_to_dib
* @surface: a #cairo_surface_t
* @can_convert: a #cairo_bool_t indicating whether this surface can
* be coverted to a DIB if necessary
*
* A DDB surface with this flag set can be converted to a DIB if it's
* used as a source in a way that GDI can't natively handle; for
* example, drawing a RGB24 DDB onto an ARGB32 DIB. Doing this
* conversion results in a significant speed optimization, because we
* can call on pixman to perform the operation natively, instead of
* reading the data from the DC each time.
*
* Return value: %CAIRO_STATUS_SUCCESS if the flag was successfully
* changed, or an error otherwise.
*
*/
cairo_status_t
cairo_win32_surface_set_can_convert_to_dib (cairo_surface_t *asurface, cairo_bool_t can_convert)
{
cairo_win32_surface_t *surface = (cairo_win32_surface_t*) asurface;
if (surface->base.type != CAIRO_SURFACE_TYPE_WIN32)
return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
if (surface->bitmap) {
if (can_convert)
surface->flags |= CAIRO_WIN32_SURFACE_CAN_CONVERT_TO_DIB;
else
surface->flags &= ~CAIRO_WIN32_SURFACE_CAN_CONVERT_TO_DIB;
}
return CAIRO_STATUS_SUCCESS;
}
/**
* cairo_win32_surface_get_can_convert_to_dib
* @surface: a #cairo_surface_t
* @can_convert: a #cairo_bool_t* that receives the return value
*
* Returns the value of the flag indicating whether the surface can be
* converted to a DIB if necessary, as set by
* cairo_win32_surface_set_can_convert_to_dib.
*
* Return value: %CAIRO_STATUS_SUCCESS if the flag was successfully
* retreived, or an error otherwise.
*
*/
cairo_status_t
cairo_win32_surface_get_can_convert_to_dib (cairo_surface_t *asurface, cairo_bool_t *can_convert)
{
cairo_win32_surface_t *surface = (cairo_win32_surface_t*) asurface;
if (surface->base.type != CAIRO_SURFACE_TYPE_WIN32)
return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
*can_convert = ((surface->flags & CAIRO_WIN32_SURFACE_CAN_CONVERT_TO_DIB) != 0);
return CAIRO_STATUS_SUCCESS;
}

Просмотреть файл

@ -74,6 +74,12 @@ cairo_win32_surface_get_image (cairo_surface_t *surface);
* Win32 font support
*/
cairo_public cairo_status_t
cairo_win32_surface_set_can_convert_to_dib (cairo_surface_t *surface, cairo_bool_t can_convert);
cairo_public cairo_status_t
cairo_win32_surface_get_can_convert_to_dib (cairo_surface_t *surface, cairo_bool_t *can_convert);
cairo_public cairo_font_face_t *
cairo_win32_font_face_create_for_logfontw (LOGFONTW *logfont);

Просмотреть файл

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