summaryrefslogtreecommitdiffstats
path: root/gfx/cairo/gdi-RGB24-ARGB32.patch
blob: 1df95f9ac0cbc1205152ef109262064a603e7d51 (plain)
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
changeset:   106848:28db6dbdd9ea
tag:         gdi-patch
tag:         qbase
tag:         qtip
tag:         tip
user:        Jeff Muizelaar <jmuizelaar@mozilla.com>
date:        Wed Sep 12 22:52:06 2012 -0400
summary:     Bug 788794. Use BitBlt to do SOURCE and OVER from RGB24 to ARGB32. r=nical

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
@@ -884,16 +884,28 @@ static cairo_int_status_t
 		      src_x, src_y,
 		      src_w, src_h,
 		      blend_function))
 	return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(AlphaBlend)");
 
     return CAIRO_STATUS_SUCCESS;
 }
 
+/* makes the alpha channel in a RGB24 surface 0xff */
+static void
+make_opaque (cairo_image_surface_t *image, cairo_rectangle_int_t src_r)
+{
+    int x; int y;
+    for (y = src_r.y; y < src_r.height; y++) {
+        for (x = src_r.x; x < src_r.width; x++) {
+            image->data[y * image->stride + x*4 + 3] = 0xff;
+        }
+    }
+}
+
 static cairo_int_status_t
 _cairo_win32_surface_composite_inner (cairo_win32_surface_t *src,
 				      cairo_image_surface_t *src_image,
 				      cairo_win32_surface_t *dst,
 				      cairo_rectangle_int_t src_extents,
 				      cairo_rectangle_int_t src_r,
 				      cairo_rectangle_int_t dst_r,
 				      int alpha,
@@ -935,16 +947,24 @@ static cairo_int_status_t
 				src_r.width, - (int) src_r.height,
 				src_image->data,
 				&bi,
 				DIB_RGB_COLORS,
 				SRCCOPY))
 		return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(StretchDIBits)");
 	}
     } else if (!needs_alpha) {
+	if (src->format == CAIRO_FORMAT_RGB24 && dst->format == CAIRO_FORMAT_ARGB32) {
+	    /* Because we store RGB24 & ARGB32 in the same way GDI has no way
+	     * to ignore the alpha channel from a RGB24 source. Therefore, we set
+	     * the alpha channel in our RGB24 source to opaque so that we can treat
+	     * it like ARGB32. */
+	    GdiFlush();
+	    make_opaque(src->image, src_r);
+	}
 	/* BitBlt or StretchBlt? */
 	if (!needs_scale && (dst->flags & CAIRO_WIN32_SURFACE_CAN_BITBLT)) {
             if (!BitBlt (dst->dc,
 			 dst_r.x, dst_r.y,
 			 dst_r.width, dst_r.height,
 			 src->dc,
 			 src_r.x, src_r.y,
 			 SRCCOPY))
@@ -1184,28 +1204,36 @@ static cairo_int_status_t
 	}
     } else {
 	needs_repeat = TRUE;
     }
 
     /*
      * Operations that we can do:
      *
+     * AlphaBlend uses the following formula for alpha when not use the per-pixel alpha (AlphaFormat = 0)
+     *   Dst.Alpha = Src.Alpha * (SCA/255.0) + Dst.Alpha * (1.0 - (SCA/255.0))
+     * This turns into Dst.Alpha = Src.Alpha when SCA = 255.
+     * (http://msdn.microsoft.com/en-us/library/aa921335.aspx)
+     *
      *  RGB OVER  RGB -> BitBlt (same as SOURCE)
-     *  RGB OVER ARGB -> UNSUPPORTED (AlphaBlend treats this as a BitBlt, even with SCA 255 and no AC_SRC_ALPHA)
+     *  RGB OVER ARGB -> Partially supported, We convert this operation into a ARGB SOURCE ARGB
+     *                   by setting the alpha values of the source to 255.
      * ARGB OVER ARGB -> AlphaBlend, with AC_SRC_ALPHA
      * ARGB OVER  RGB -> AlphaBlend, with AC_SRC_ALPHA; we'll have junk in the dst A byte
      * 
      *  RGB OVER  RGB + mask -> AlphaBlend, no AC_SRC_ALPHA
-     *  RGB OVER ARGB + mask -> UNSUPPORTED
+     *  RGB OVER ARGB + mask -> Partially supported, We convert this operation into a ARGB OVER ARGB + mask
+     *                          by setting the alpha values of the source to 255.
      * ARGB OVER ARGB + mask -> AlphaBlend, with AC_SRC_ALPHA
      * ARGB OVER  RGB + mask -> AlphaBlend, with AC_SRC_ALPHA; junk in the dst A byte
      * 
      *  RGB SOURCE  RGB -> BitBlt
-     *  RGB SOURCE ARGB -> UNSUPPORTED (AlphaBlend treats this as a BitBlt, even with SCA 255 and no AC_SRC_ALPHA)
+     *  RGB SOURCE ARGB -> Partially supported, We convert this operation into a ARGB SOURCE ARGB
+     *                     by setting the alpha values of the source to 255.
      * ARGB SOURCE ARGB -> BitBlt
      * ARGB SOURCE  RGB -> BitBlt
      * 
      *  RGB SOURCE  RGB + mask -> unsupported
      *  RGB SOURCE ARGB + mask -> unsupported
      * ARGB SOURCE ARGB + mask -> unsupported
      * ARGB SOURCE  RGB + mask -> unsupported
      */
@@ -1222,22 +1250,32 @@ static cairo_int_status_t
 		needs_alpha = FALSE;
 	    } else {
 		needs_alpha = TRUE;
 	    }
 	} else if (src_format == CAIRO_FORMAT_ARGB32 &&
 		   dst->format == CAIRO_FORMAT_RGB24)
 	{
 	    needs_alpha = TRUE;
+	} else if (src_format == CAIRO_FORMAT_RGB24 &&
+		   dst->format == CAIRO_FORMAT_ARGB32 &&
+		   src->image)
+	{
+	    if (alpha == 255) {
+		needs_alpha = FALSE;
+	    } else {
+		needs_alpha = TRUE;
+	    }
 	} else {
 	    goto UNSUPPORTED;
 	}
     } else if (alpha == 255 && op == CAIRO_OPERATOR_SOURCE) {
 	if ((src_format == dst->format) ||
-	    (src_format == CAIRO_FORMAT_ARGB32 && dst->format == CAIRO_FORMAT_RGB24))
+	    (src_format == CAIRO_FORMAT_ARGB32 && dst->format == CAIRO_FORMAT_RGB24) ||
+	    (src_format == CAIRO_FORMAT_RGB24  && dst->format == CAIRO_FORMAT_ARGB32 && src->image))
 	{
 	    needs_alpha = FALSE;
 	} else {
 	    goto UNSUPPORTED;
 	}
     } else {
 	goto UNSUPPORTED;
     }