mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-13 23:17:57 +00:00
2bfaffb3eb
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.
183 lines
6.1 KiB
Diff
183 lines
6.1 KiB
Diff
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);
|
|
|