DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (31ec81b5d7bb)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
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 the CHECKJPEGFORMAT escape function */
     CAIRO_WIN32_SURFACE_CAN_CHECK_PNG = (1<<8),
+
+    /* if this DDB surface can be converted to a DIB if necessary */
+    CAIRO_WIN32_SURFACE_CAN_CONVERT_TO_DIB = (1<<9),
 };
 
 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
@@ -68,6 +68,12 @@ cairo_win32_surface_get_dc (cairo_surface_t *surface);
 cairo_public cairo_surface_t *
 cairo_win32_surface_get_image (cairo_surface_t *surface);
 
+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);
+
 #if CAIRO_HAS_WIN32_FONT