[2/3] win32: CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH and other argb32 flags set+check

Submitted by Vasily Galkin on April 28, 2018, 7:27 p.m.

Details

Message ID 20180428192701.22786-2-galkin-vv@yandex.ru
State New
Series "Series without cover letter"
Headers show

Commit Message

Vasily Galkin April 28, 2018, 7:27 p.m.
This belongs to a patch series that speedups the CAIRO_OPERATOR_SOURCE
when used to copy data
to a argb32 cairo   surface corresponding to a win32 dc
from a "backbuffer" - DibSection-based cairo surface
created with cairo_surface_create_similar().

This patch introduces checks that ensure that no solid brush gdi operations
are done with argb32 surfaces.
This is needed for enabling gdi compositor usage for win32 argb32 surfaces.

To make this checks working the calculatinig function correctly fills
argb32 flags disabling STRETCHBLT, STRETCHDIB and RGB_BRUSH.

_cairo_win32_flags_for_dc refactored to make rgb24 vs argb32 distinction
more readable. All logic&flags for rgb24 surfaces are kept,
except addition of CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH.

The logic of forbidding AlphaBlend on display surfaces
kept as is without investigation.
---
 src/win32/cairo-win32-device.c         | 36 ++++++++++++++++++++++------------
 src/win32/cairo-win32-gdi-compositor.c | 18 ++++++++++++++++-
 2 files changed, 40 insertions(+), 14 deletions(-)

Patch hide | download patch | download mbox

diff --git a/src/win32/cairo-win32-device.c b/src/win32/cairo-win32-device.c
index 309f16c..a2c9508 100644
--- a/src/win32/cairo-win32-device.c
+++ b/src/win32/cairo-win32-device.c
@@ -156,17 +156,31 @@  unsigned
 _cairo_win32_flags_for_dc (HDC dc, cairo_format_t format)
 {
     uint32_t flags = 0;
-    int cap;
+    cairo_bool_t is_display = GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY;
+
+    if (format == CAIRO_FORMAT_RGB24 || format == CAIRO_FORMAT_ARGB32)
+    {
+	int cap = GetDeviceCaps(dc, RASTERCAPS);
+	if (cap & RC_BITBLT)
+	    flags |= CAIRO_WIN32_SURFACE_CAN_BITBLT;
+	if (!is_display && GetDeviceCaps(dc, SHADEBLENDCAPS) != SB_NONE)
+	    flags |= CAIRO_WIN32_SURFACE_CAN_ALPHABLEND;
 
-    cap = GetDeviceCaps(dc, RASTERCAPS);
-    if (cap & RC_BITBLT)
-	flags |= CAIRO_WIN32_SURFACE_CAN_BITBLT;
-    if (cap & RC_STRETCHBLT)
-	flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHBLT;
-    if (cap & RC_STRETCHDIB)
-	flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHDIB;
+	/* ARGB32 available operations is a strict subset of RGB24 available
+	 * operations. It's because the same gdi functions can be used but most
+	 * of them always reset alpha channel to 0 which is bad for ARGB32.
+	 */
+	if (format == CAIRO_FORMAT_RGB24)
+	{
+	    flags |= CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH;
+	    if (cap & RC_STRETCHBLT)
+		flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHBLT;
+	    if (cap & RC_STRETCHDIB)
+		flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHDIB;
+	}
+    }
 
-    if (GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
+    if (is_display) {
 	flags |= CAIRO_WIN32_SURFACE_IS_DISPLAY;
 
 	/* These will always be possible, but the actual GetDeviceCaps
@@ -181,10 +195,6 @@  _cairo_win32_flags_for_dc (HDC dc, cairo_format_t format)
 	flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHBLT;
 	flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHDIB;
 #endif
-    } else {
-	cap = GetDeviceCaps(dc, SHADEBLENDCAPS);
-	if (cap != SB_NONE)
-	    flags |= CAIRO_WIN32_SURFACE_CAN_ALPHABLEND;
     }
 
     return flags;
diff --git a/src/win32/cairo-win32-gdi-compositor.c b/src/win32/cairo-win32-gdi-compositor.c
index 2858aff..0873391 100644
--- a/src/win32/cairo-win32-gdi-compositor.c
+++ b/src/win32/cairo-win32-gdi-compositor.c
@@ -179,6 +179,9 @@  fill_boxes (cairo_win32_display_surface_t	*dst,
 
     TRACE ((stderr, "%s\n", __FUNCTION__));
 
+    if ((dst->win32.flags & CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH) == 0)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
     fb.dc = dst->win32.dc;
     fb.brush = CreateSolidBrush (color_to_rgb(color));
     if (!fb.brush)
@@ -213,6 +216,7 @@  copy_boxes (cairo_win32_display_surface_t *dst,
     struct copy_box cb;
     cairo_surface_t *surface;
     cairo_status_t status;
+    cairo_win32_surface_t *src;
 
     TRACE ((stderr, "%s\n", __FUNCTION__));
 
@@ -230,8 +234,16 @@  copy_boxes (cairo_win32_display_surface_t *dst,
 						&cb.tx, &cb.ty))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
+    src = to_win32_surface(surface);
+
+    if (src->format != dst->win32.format &&
+	!(src->format == CAIRO_FORMAT_ARGB32 && dst->win32.format == CAIRO_FORMAT_RGB24))
+    {
+	/* forbid copy different surfaces unless it is from argb32 to rgb (alpha-drop) */
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
     cb.dst = dst->win32.dc;
-    cb.src = to_win32_surface(surface)->dc;
+    cb.src = src->dc;
 
     /* First check that the data is entirely within the image */
     if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &cb))
@@ -614,6 +626,10 @@  _cairo_win32_gdi_compositor_glyphs (const cairo_compositor_t	*compositor,
 	cairo_win32_display_surface_t *dst = to_win32_display_surface (composite->surface);
 
 	TRACE ((stderr, "%s\n", __FUNCTION__));
+
+	if ((dst->win32.flags & CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH) == 0)
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+
 	status = _cairo_win32_display_surface_set_clip(dst, composite->clip);
 	if (status)
 	    return status;