зеркало из https://github.com/mozilla/pjs.git
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:
Родитель
a93b615c31
Коммит
3679e3522b
|
@ -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);
|
||||
|
Загрузка…
Ссылка в новой задаче