|
1 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 |
|
2 |
|
3 If a DDB is used as a source for an operation that can't be handled |
|
4 natively by GDI, we end up needing to take a really slow path (creating a |
|
5 temporary surface for acquire_source) for each operation. If we convert |
|
6 the DDB to a DIB, we then end up having a real image buffer and can hand |
|
7 things off to pixman directly. |
|
8 |
|
9 This isn't the default mode because I'm not sure if there are cases where a |
|
10 DDB is explicitly needed (e.g. for printing), and it would change |
|
11 current cairo behaviour. It might become the default at some point in the |
|
12 future. |
|
13 |
|
14 diff --git a/gfx/cairo/cairo/src/cairo-win32-private.h b/gfx/cairo/cairo/src/cairo-win32-private.h |
|
15 --- a/gfx/cairo/cairo/src/cairo-win32-private.h |
|
16 +++ b/gfx/cairo/cairo/src/cairo-win32-private.h |
|
17 @@ -117,6 +117,9 @@ |
|
18 |
|
19 /* Whether we can use the CHECKJPEGFORMAT escape function */ |
|
20 CAIRO_WIN32_SURFACE_CAN_CHECK_PNG = (1<<8), |
|
21 + |
|
22 + /* if this DDB surface can be converted to a DIB if necessary */ |
|
23 + CAIRO_WIN32_SURFACE_CAN_CONVERT_TO_DIB = (1<<9), |
|
24 }; |
|
25 |
|
26 cairo_status_t |
|
27 diff --git a/gfx/cairo/cairo/src/cairo-win32-surface.c b/gfx/cairo/cairo/src/cairo-win32-surface.c |
|
28 --- a/gfx/cairo/cairo/src/cairo-win32-surface.c |
|
29 +++ b/gfx/cairo/cairo/src/cairo-win32-surface.c |
|
30 @@ -560,6 +560,56 @@ |
|
31 return CAIRO_STATUS_SUCCESS; |
|
32 } |
|
33 |
|
34 +static void |
|
35 +_cairo_win32_convert_ddb_to_dib (cairo_win32_surface_t *surface) |
|
36 +{ |
|
37 + cairo_win32_surface_t *new_surface; |
|
38 + int width = surface->extents.width; |
|
39 + int height = surface->extents.height; |
|
40 + |
|
41 + BOOL ok; |
|
42 + HBITMAP oldbitmap; |
|
43 + |
|
44 + new_surface = (cairo_win32_surface_t*) |
|
45 + _cairo_win32_surface_create_for_dc (surface->dc, |
|
46 + surface->format, |
|
47 + width, |
|
48 + height); |
|
49 + |
|
50 + if (new_surface->base.status) |
|
51 + return; |
|
52 + |
|
53 + /* DDB can't be 32bpp, so BitBlt is safe */ |
|
54 + ok = BitBlt (new_surface->dc, |
|
55 + 0, 0, width, height, |
|
56 + surface->dc, |
|
57 + 0, 0, SRCCOPY); |
|
58 + |
|
59 + if (!ok) |
|
60 + goto out; |
|
61 + |
|
62 + /* Now swap around new_surface and surface's internal bitmap |
|
63 + * pointers. */ |
|
64 + DeleteDC (new_surface->dc); |
|
65 + new_surface->dc = NULL; |
|
66 + |
|
67 + oldbitmap = SelectObject (surface->dc, new_surface->bitmap); |
|
68 + DeleteObject (oldbitmap); |
|
69 + |
|
70 + surface->image = new_surface->image; |
|
71 + surface->is_dib = new_surface->is_dib; |
|
72 + surface->bitmap = new_surface->bitmap; |
|
73 + |
|
74 + new_surface->bitmap = NULL; |
|
75 + new_surface->image = NULL; |
|
76 + |
|
77 + /* Finally update flags */ |
|
78 + surface->flags = _cairo_win32_flags_for_dc (surface->dc); |
|
79 + |
|
80 + out: |
|
81 + cairo_surface_destroy ((cairo_surface_t*)new_surface); |
|
82 +} |
|
83 + |
|
84 static cairo_status_t |
|
85 _cairo_win32_surface_acquire_source_image (void *abstract_surface, |
|
86 cairo_image_surface_t **image_out, |
|
87 @@ -568,6 +618,17 @@ |
|
88 cairo_win32_surface_t *surface = abstract_surface; |
|
89 cairo_win32_surface_t *local = NULL; |
|
90 cairo_status_t status; |
|
91 + |
|
92 + if (!surface->image && !surface->is_dib && surface->bitmap && |
|
93 + (surface->flags & CAIRO_WIN32_SURFACE_CAN_CONVERT_TO_DIB) != 0) |
|
94 + { |
|
95 + /* This is a DDB, and we're being asked to use it as a source for |
|
96 + * something that we couldn't support natively. So turn it into |
|
97 + * a DIB, so that we have an equivalent image surface, as long |
|
98 + * as we're allowed to via flags. |
|
99 + */ |
|
100 + _cairo_win32_convert_ddb_to_dib (surface); |
|
101 + } |
|
102 |
|
103 if (surface->image) { |
|
104 *image_out = (cairo_image_surface_t *)surface->image; |
|
105 @@ -2133,3 +2194,61 @@ |
|
106 free(rd); |
|
107 fflush (stderr); |
|
108 } |
|
109 + |
|
110 +/** |
|
111 + * cairo_win32_surface_set_can_convert_to_dib |
|
112 + * @surface: a #cairo_surface_t |
|
113 + * @can_convert: a #cairo_bool_t indicating whether this surface can |
|
114 + * be coverted to a DIB if necessary |
|
115 + * |
|
116 + * A DDB surface with this flag set can be converted to a DIB if it's |
|
117 + * used as a source in a way that GDI can't natively handle; for |
|
118 + * example, drawing a RGB24 DDB onto an ARGB32 DIB. Doing this |
|
119 + * conversion results in a significant speed optimization, because we |
|
120 + * can call on pixman to perform the operation natively, instead of |
|
121 + * reading the data from the DC each time. |
|
122 + * |
|
123 + * Return value: %CAIRO_STATUS_SUCCESS if the flag was successfully |
|
124 + * changed, or an error otherwise. |
|
125 + * |
|
126 + */ |
|
127 +cairo_status_t |
|
128 +cairo_win32_surface_set_can_convert_to_dib (cairo_surface_t *asurface, cairo_bool_t can_convert) |
|
129 +{ |
|
130 + cairo_win32_surface_t *surface = (cairo_win32_surface_t*) asurface; |
|
131 + if (surface->base.type != CAIRO_SURFACE_TYPE_WIN32) |
|
132 + return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; |
|
133 + |
|
134 + if (surface->bitmap) { |
|
135 + if (can_convert) |
|
136 + surface->flags |= CAIRO_WIN32_SURFACE_CAN_CONVERT_TO_DIB; |
|
137 + else |
|
138 + surface->flags &= ~CAIRO_WIN32_SURFACE_CAN_CONVERT_TO_DIB; |
|
139 + } |
|
140 + |
|
141 + return CAIRO_STATUS_SUCCESS; |
|
142 +} |
|
143 + |
|
144 +/** |
|
145 + * cairo_win32_surface_get_can_convert_to_dib |
|
146 + * @surface: a #cairo_surface_t |
|
147 + * @can_convert: a #cairo_bool_t* that receives the return value |
|
148 + * |
|
149 + * Returns the value of the flag indicating whether the surface can be |
|
150 + * converted to a DIB if necessary, as set by |
|
151 + * cairo_win32_surface_set_can_convert_to_dib. |
|
152 + * |
|
153 + * Return value: %CAIRO_STATUS_SUCCESS if the flag was successfully |
|
154 + * retreived, or an error otherwise. |
|
155 + * |
|
156 + */ |
|
157 +cairo_status_t |
|
158 +cairo_win32_surface_get_can_convert_to_dib (cairo_surface_t *asurface, cairo_bool_t *can_convert) |
|
159 +{ |
|
160 + cairo_win32_surface_t *surface = (cairo_win32_surface_t*) asurface; |
|
161 + if (surface->base.type != CAIRO_SURFACE_TYPE_WIN32) |
|
162 + return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; |
|
163 + |
|
164 + *can_convert = ((surface->flags & CAIRO_WIN32_SURFACE_CAN_CONVERT_TO_DIB) != 0); |
|
165 + return CAIRO_STATUS_SUCCESS; |
|
166 +} |
|
167 diff --git a/gfx/cairo/cairo/src/cairo-win32.h b/gfx/cairo/cairo/src/cairo-win32.h |
|
168 --- a/gfx/cairo/cairo/src/cairo-win32.h |
|
169 +++ b/gfx/cairo/cairo/src/cairo-win32.h |
|
170 @@ -68,6 +68,12 @@ cairo_win32_surface_get_dc (cairo_surface_t *surface); |
|
171 cairo_public cairo_surface_t * |
|
172 cairo_win32_surface_get_image (cairo_surface_t *surface); |
|
173 |
|
174 +cairo_public cairo_status_t |
|
175 +cairo_win32_surface_set_can_convert_to_dib (cairo_surface_t *surface, cairo_bool_t can_convert); |
|
176 + |
|
177 +cairo_public cairo_status_t |
|
178 +cairo_win32_surface_get_can_convert_to_dib (cairo_surface_t *surface, cairo_bool_t *can_convert); |
|
179 + |
|
180 #if CAIRO_HAS_WIN32_FONT |
|
181 |