зеркало из 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
|
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 ====
|
==== pixman patches ====
|
||||||
|
|
||||||
endian.patch: include cairo-platform.h for endian macros
|
endian.patch: include cairo-platform.h for endian macros
|
||||||
|
|
|
@ -117,6 +117,9 @@ enum {
|
||||||
|
|
||||||
/* Whether we can use GradientFill rectangles with this surface */
|
/* Whether we can use GradientFill rectangles with this surface */
|
||||||
CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT = (1<<6),
|
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
|
cairo_status_t
|
||||||
|
|
|
@ -560,6 +560,56 @@ _cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface,
|
||||||
return CAIRO_STATUS_SUCCESS;
|
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
|
static cairo_status_t
|
||||||
_cairo_win32_surface_acquire_source_image (void *abstract_surface,
|
_cairo_win32_surface_acquire_source_image (void *abstract_surface,
|
||||||
cairo_image_surface_t **image_out,
|
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_win32_surface_t *local = NULL;
|
||||||
cairo_status_t status;
|
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) {
|
if (surface->image) {
|
||||||
*image_out = (cairo_image_surface_t *)surface->image;
|
*image_out = (cairo_image_surface_t *)surface->image;
|
||||||
*image_extra = NULL;
|
*image_extra = NULL;
|
||||||
|
@ -2133,3 +2194,61 @@ _cairo_win32_debug_dump_hrgn (HRGN rgn, char *header)
|
||||||
free(rd);
|
free(rd);
|
||||||
fflush (stderr);
|
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
|
* 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_public cairo_font_face_t *
|
||||||
cairo_win32_font_face_create_for_logfontw (LOGFONTW *logfont);
|
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);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче