winex11: Add support for the LWA_COLORKEY layered window attribute.
[wine] / dlls / winex11.drv / bitblt.c
1 /*
2  * GDI bit-blit operations
3  *
4  * Copyright 1993, 1994, 2011 Alexandre Julliard
5  * Copyright 2006 Damjan Jovanovic
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28
29 #include <X11/Xlib.h>
30 #include <X11/Xresource.h>
31 #include <X11/Xutil.h>
32 #ifdef HAVE_LIBXSHAPE
33 #include <X11/extensions/shape.h>
34 #endif
35
36 #include "windef.h"
37 #include "winbase.h"
38 #include "wingdi.h"
39 #include "winuser.h"
40 #include "x11drv.h"
41 #include "winternl.h"
42 #include "wine/debug.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
45
46
47 #define DST 0   /* Destination drawable */
48 #define SRC 1   /* Source drawable */
49 #define TMP 2   /* Temporary drawable */
50 #define PAT 3   /* Pattern (brush) in destination DC */
51
52 #define OP(src,dst,rop)   (OP_ARGS(src,dst) << 4 | (rop))
53 #define OP_ARGS(src,dst)  (((src) << 2) | (dst))
54
55 #define OP_SRC(opcode)    ((opcode) >> 6)
56 #define OP_DST(opcode)    (((opcode) >> 4) & 3)
57 #define OP_SRCDST(opcode) ((opcode) >> 4)
58 #define OP_ROP(opcode)    ((opcode) & 0x0f)
59
60 #define MAX_OP_LEN  6  /* Longest opcode + 1 for the terminating 0 */
61
62 static const unsigned char BITBLT_Opcodes[256][MAX_OP_LEN] =
63 {
64     { OP(PAT,DST,GXclear) },                         /* 0x00  0              */
65     { OP(PAT,SRC,GXor), OP(SRC,DST,GXnor) },         /* 0x01  ~(D|(P|S))     */
66     { OP(PAT,SRC,GXnor), OP(SRC,DST,GXand) },        /* 0x02  D&~(P|S)       */
67     { OP(PAT,SRC,GXnor) },                           /* 0x03  ~(P|S)         */
68     { OP(PAT,DST,GXnor), OP(SRC,DST,GXand) },        /* 0x04  S&~(D|P)       */
69     { OP(PAT,DST,GXnor) },                           /* 0x05  ~(D|P)         */
70     { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnor), },     /* 0x06  ~(P|~(D^S))    */
71     { OP(SRC,DST,GXand), OP(PAT,DST,GXnor) },        /* 0x07  ~(P|(D&S))     */
72     { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXand) },/* 0x08  S&D&~P         */
73     { OP(SRC,DST,GXxor), OP(PAT,DST,GXnor) },        /* 0x09  ~(P|(D^S))     */
74     { OP(PAT,DST,GXandInverted) },                   /* 0x0a  D&~P           */
75     { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXnor) }, /* 0x0b  ~(P|(S&~D))    */
76     { OP(PAT,SRC,GXandInverted) },                   /* 0x0c  S&~P           */
77     { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXnor) },/* 0x0d  ~(P|(D&~S))    */
78     { OP(SRC,DST,GXnor), OP(PAT,DST,GXnor) },        /* 0x0e  ~(P|~(D|S))    */
79     { OP(PAT,DST,GXcopyInverted) },                  /* 0x0f  ~P             */
80     { OP(SRC,DST,GXnor), OP(PAT,DST,GXand) },        /* 0x10  P&~(S|D)       */
81     { OP(SRC,DST,GXnor) },                           /* 0x11  ~(D|S)         */
82     { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnor) },      /* 0x12  ~(S|~(D^P))    */
83     { OP(PAT,DST,GXand), OP(SRC,DST,GXnor) },        /* 0x13  ~(S|(D&P))     */
84     { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnor) },      /* 0x14  ~(D|~(P^S))    */
85     { OP(PAT,SRC,GXand), OP(SRC,DST,GXnor) },        /* 0x15  ~(D|(P&S))     */
86     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
87       OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
88       OP(PAT,DST,GXxor) },                           /* 0x16  P^S^(D&~(P&S)  */
89     { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
90       OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
91       OP(TMP,DST,GXequiv) },                         /* 0x17 ~S^((S^P)&(S^D))*/
92     { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
93         OP(SRC,DST,GXand) },                         /* 0x18  (S^P)&(D^P)    */
94     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
95       OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) },      /* 0x19  ~S^(D&~(P&S))  */
96     { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
97       OP(PAT,DST,GXxor) },                           /* 0x1a  P^(D|(S&P))    */
98     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
99       OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) },      /* 0x1b  ~S^(D&(P^S))   */
100     { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
101       OP(PAT,DST,GXxor) },                           /* 0x1c  P^(S|(D&P))    */
102     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
103       OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) },      /* 0x1d  ~D^(S&(D^P))   */
104     { OP(SRC,DST,GXor), OP(PAT,DST,GXxor) },         /* 0x1e  P^(D|S)        */
105     { OP(SRC,DST,GXor), OP(PAT,DST,GXnand) },        /* 0x1f  ~(P&(D|S))     */
106     { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXand) }, /* 0x20  D&(P&~S)       */
107     { OP(PAT,DST,GXxor), OP(SRC,DST,GXnor) },        /* 0x21  ~(S|(D^P))     */
108     { OP(SRC,DST,GXandInverted) },                   /* 0x22  ~S&D           */
109     { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x23  ~(S|(P&~D))    */
110     { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
111       OP(SRC,DST,GXand) },                           /* 0x24   (S^P)&(S^D)   */
112     { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand),
113       OP(PAT,DST,GXequiv) },                         /* 0x25  ~P^(D&~(S&P))  */
114     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
115       OP(SRC,DST,GXor), OP(TMP,DST,GXxor) },         /* 0x26  S^(D|(S&P))    */
116     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXequiv),
117       OP(SRC,DST,GXor), OP(TMP,DST,GXxor) },         /* 0x27  S^(D|~(P^S))   */
118     { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand) },        /* 0x28  D&(P^S)        */
119     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
120       OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
121       OP(PAT,DST,GXequiv) },                         /* 0x29  ~P^S^(D|(P&S)) */
122     { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand) },       /* 0x2a  D&~(P&S)       */
123     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
124       OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
125       OP(TMP,DST,GXequiv) },                         /* 0x2b ~S^((P^S)&(P^D))*/
126     { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
127       OP(SRC,DST,GXxor) },                           /* 0x2c  S^(P&(S|D))    */
128     { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXxor) },  /* 0x2d  P^(S|~D)       */
129     { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
130       OP(PAT,DST,GXxor) },                           /* 0x2e  P^(S|(D^P))    */
131     { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXnand) }, /* 0x2f  ~(P&(S|~D))    */
132     { OP(PAT,SRC,GXandReverse) },                    /* 0x30  P&~S           */
133     { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXnor) },/* 0x31  ~(S|(D&~P))    */
134     { OP(SRC,DST,GXor), OP(PAT,DST,GXor),
135       OP(SRC,DST,GXxor) },                           /* 0x32  S^(D|P|S)      */
136     { OP(SRC,DST,GXcopyInverted) },                  /* 0x33  ~S             */
137     { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
138       OP(SRC,DST,GXxor) },                           /* 0x34  S^(P|(D&S))    */
139     { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor),
140       OP(SRC,DST,GXxor) },                           /* 0x35  S^(P|~(D^S))   */
141     { OP(PAT,DST,GXor), OP(SRC,DST,GXxor) },         /* 0x36  S^(D|P)        */
142     { OP(PAT,DST,GXor), OP(SRC,DST,GXnand) },        /* 0x37  ~(S&(D|P))     */
143     { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
144       OP(PAT,DST,GXxor) },                           /* 0x38  P^(S&(D|P))    */
145     { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXxor) },  /* 0x39  S^(P|~D)       */
146     { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
147       OP(SRC,DST,GXxor) },                           /* 0x3a  S^(P|(D^S))    */
148     { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x3b  ~(S&(P|~D))    */
149     { OP(PAT,SRC,GXxor) },                           /* 0x3c  P^S            */
150     { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
151       OP(SRC,DST,GXxor) },                           /* 0x3d  S^(P|~(D|S))   */
152     { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
153       OP(SRC,DST,GXxor) },                           /* 0x3e  S^(P|(D&~S))   */
154     { OP(PAT,SRC,GXnand) },                          /* 0x3f  ~(P&S)         */
155     { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXand) }, /* 0x40  P&S&~D         */
156     { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnor) },        /* 0x41  ~(D|(P^S))     */
157     { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
158       OP(SRC,DST,GXand) },                           /* 0x42  (S^D)&(P^D)    */
159     { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
160       OP(SRC,DST,GXequiv) },                         /* 0x43  ~S^(P&~(D&S))  */
161     { OP(SRC,DST,GXandReverse) },                    /* 0x44  S&~D           */
162     { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x45  ~(D|(P&~S))    */
163     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
164       OP(SRC,DST,GXor), OP(TMP,DST,GXxor) },         /* 0x46  D^(S|(P&D))    */
165     { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
166       OP(PAT,DST,GXequiv) },                         /* 0x47  ~P^(S&(D^P))   */
167     { OP(PAT,DST,GXxor), OP(SRC,DST,GXand) },        /* 0x48  S&(P^D)        */
168     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
169       OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
170       OP(PAT,DST,GXequiv) },                         /* 0x49  ~P^D^(S|(P&D)) */
171     { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
172       OP(SRC,DST,GXxor) },                           /* 0x4a  D^(P&(S|D))    */
173     { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXxor) }, /* 0x4b  P^(D|~S)       */
174     { OP(PAT,DST,GXnand), OP(SRC,DST,GXand) },       /* 0x4c  S&~(D&P)       */
175     { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
176       OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
177       OP(TMP,DST,GXequiv) },                         /* 0x4d ~S^((S^P)|(S^D))*/
178     { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
179       OP(PAT,DST,GXxor) },                           /* 0x4e  P^(D|(S^P))    */
180     { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXnand) },/* 0x4f  ~(P&(D|~S))    */
181     { OP(PAT,DST,GXandReverse) },                    /* 0x50  P&~D           */
182     { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXnor) },/* 0x51  ~(D|(S&~P))    */
183     { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
184       OP(SRC,DST,GXxor) },                           /* 0x52  D^(P|(S&D))    */
185     { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
186       OP(SRC,DST,GXequiv) },                         /* 0x53  ~S^(P&(D^S))   */
187     { OP(PAT,SRC,GXnor), OP(SRC,DST,GXnor) },        /* 0x54  ~(D|~(P|S))    */
188     { OP(PAT,DST,GXinvert) },                        /* 0x55  ~D             */
189     { OP(PAT,SRC,GXor), OP(SRC,DST,GXxor) },         /* 0x56  D^(P|S)        */
190     { OP(PAT,SRC,GXor), OP(SRC,DST,GXnand) },        /* 0x57  ~(D&(P|S))     */
191     { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
192       OP(PAT,DST,GXxor) },                           /* 0x58  P^(D&(P|S))    */
193     { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXxor) },  /* 0x59  D^(P|~S)       */
194     { OP(PAT,DST,GXxor) },                           /* 0x5a  D^P            */
195     { OP(DST,SRC,GXnor), OP(PAT,SRC,GXor),
196       OP(SRC,DST,GXxor) },                           /* 0x5b  D^(P|~(S|D))   */
197     { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
198       OP(SRC,DST,GXxor) },                           /* 0x5c  D^(P|(S^D))    */
199     { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x5d  ~(D&(P|~S))    */
200     { OP(DST,SRC,GXandInverted), OP(PAT,SRC,GXor),
201       OP(SRC,DST,GXxor) },                           /* 0x5e  D^(P|(S&~D))   */
202     { OP(PAT,DST,GXnand) },                          /* 0x5f  ~(D&P)         */
203     { OP(SRC,DST,GXxor), OP(PAT,DST,GXand) },        /* 0x60  P&(D^S)        */
204     { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
205       OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
206       OP(TMP,DST,GXequiv) },                         /* 0x61  ~D^S^(P|(D&S)) */
207     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
208       OP(SRC,DST,GXand), OP(TMP,DST,GXxor) },        /* 0x62  D^(S&(P|D))    */
209     { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x63  S^(D|~P)       */
210     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
211       OP(SRC,DST,GXand), OP(TMP,DST,GXxor) },        /* 0x64  S^(D&(P|S))    */
212     { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x65  D^(S|~P)       */
213     { OP(SRC,DST,GXxor) },                           /* 0x66  S^D            */
214     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
215       OP(SRC,DST,GXor), OP(TMP,DST,GXxor) },         /* 0x67  S^(D|~(S|P)    */
216     { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnor),
217       OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
218       OP(TMP,DST,GXequiv) },                         /* 0x68  ~D^S^(P|~(D|S))*/
219     { OP(SRC,DST,GXxor), OP(PAT,DST,GXequiv) },      /* 0x69  ~P^(D^S)       */
220     { OP(PAT,SRC,GXand), OP(SRC,DST,GXxor) },        /* 0x6a  D^(P&S)        */
221     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
222       OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
223       OP(PAT,DST,GXequiv) },                         /* 0x6b  ~P^S^(D&(P|S)) */
224     { OP(PAT,DST,GXand), OP(SRC,DST,GXxor) },        /* 0x6c  S^(D&P)        */
225     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
226       OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
227       OP(PAT,DST,GXequiv) },                         /* 0x6d  ~P^D^(S&(P|D)) */
228     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
229       OP(SRC,DST,GXand), OP(TMP,DST,GXxor) },        /* 0x6e  S^(D&(P|~S))   */
230     { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnand) },     /* 0x6f  ~(P&~(S^D))    */
231     { OP(SRC,DST,GXnand), OP(PAT,DST,GXand) },       /* 0x70  P&~(D&S)       */
232     { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
233       OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
234       OP(TMP,DST,GXequiv) },                         /* 0x71 ~S^((S^D)&(P^D))*/
235     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
236       OP(SRC,DST,GXor), OP(TMP,DST,GXxor) },         /* 0x72  S^(D|(P^S))    */
237     { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXnand) },/* 0x73  ~(S&(D|~P))    */
238     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
239       OP(SRC,DST,GXor), OP(TMP,DST,GXxor) },         /* 0x74   D^(S|(P^D))   */
240     { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXnand) },/* 0x75  ~(D&(S|~P))    */
241     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
242       OP(SRC,DST,GXor), OP(TMP,DST,GXxor) },         /* 0x76  S^(D|(P&~S))   */
243     { OP(SRC,DST,GXnand) },                          /* 0x77  ~(S&D)         */
244     { OP(SRC,DST,GXand), OP(PAT,DST,GXxor) },        /* 0x78  P^(D&S)        */
245     { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
246       OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
247       OP(TMP,DST,GXequiv) },                         /* 0x79  ~D^S^(P&(D|S)) */
248     { OP(DST,SRC,GXorInverted), OP(PAT,SRC,GXand),
249       OP(SRC,DST,GXxor) },                           /* 0x7a  D^(P&(S|~D))   */
250     { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnand) },     /* 0x7b  ~(S&~(D^P))    */
251     { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
252       OP(SRC,DST,GXxor) },                           /* 0x7c  S^(P&(D|~S))   */
253     { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnand) },     /* 0x7d  ~(D&~(P^S))    */
254     { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
255       OP(SRC,DST,GXor) },                            /* 0x7e  (S^P)|(S^D)    */
256     { OP(PAT,SRC,GXand), OP(SRC,DST,GXnand) },       /* 0x7f  ~(D&P&S)       */
257     { OP(PAT,SRC,GXand), OP(SRC,DST,GXand) },        /* 0x80  D&P&S          */
258     { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
259       OP(SRC,DST,GXnor) },                           /* 0x81  ~((S^P)|(S^D)) */
260     { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXand) },      /* 0x82  D&~(P^S)       */
261     { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
262       OP(SRC,DST,GXequiv) },                         /* 0x83  ~S^(P&(D|~S))  */
263     { OP(PAT,DST,GXequiv), OP(SRC,DST,GXand) },      /* 0x84  S&~(D^P)       */
264     { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand),
265       OP(PAT,DST,GXequiv) },                         /* 0x85  ~P^(D&(S|~P))  */
266     { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
267       OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
268       OP(TMP,DST,GXxor) },                           /* 0x86  D^S^(P&(D|S))  */
269     { OP(SRC,DST,GXand), OP(PAT,DST,GXequiv) },      /* 0x87  ~P^(D&S)       */
270     { OP(SRC,DST,GXand) },                           /* 0x88  S&D            */
271     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
272       OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) },       /* 0x89  ~S^(D|(P&~S))  */
273     { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8a  D&(S|~P)       */
274     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
275       OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) },       /* 0x8b  ~D^(S|(P^D))   */
276     { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8c  S&(D|~P)       */
277     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
278       OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) },       /* 0x8d  ~S^(D|(P^S))   */
279     { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
280       OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
281       OP(TMP,DST,GXxor) },                           /* 0x8e  S^((S^D)&(P^D))*/
282     { OP(SRC,DST,GXnand), OP(PAT,DST,GXnand) },      /* 0x8f  ~(P&~(D&S))    */
283     { OP(SRC,DST,GXequiv), OP(PAT,DST,GXand) },      /* 0x90  P&~(D^S)       */
284     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
285       OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) },      /* 0x91  ~S^(D&(P|~S))  */
286     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
287       OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
288       OP(TMP,DST,GXxor) },                           /* 0x92  D^P^(S&(D|P))  */
289     { OP(PAT,DST,GXand), OP(SRC,DST,GXequiv) },      /* 0x93  ~S^(P&D)       */
290     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
291       OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
292       OP(TMP,DST,GXxor) },                           /* 0x94  S^P^(D&(P|S))  */
293     { OP(PAT,SRC,GXand), OP(SRC,DST,GXequiv) },      /* 0x95  ~D^(P&S)       */
294     { OP(PAT,SRC,GXxor), OP(SRC,DST,GXxor) },        /* 0x96  D^P^S          */
295     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
296       OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
297       OP(TMP,DST,GXxor) },                           /* 0x97  S^P^(D|~(P|S)) */
298     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
299       OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) },       /* 0x98  ~S^(D|~(P|S))  */
300     { OP(SRC,DST,GXequiv) },                         /* 0x99  ~S^D           */
301     { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9a  D^(P&~S)       */
302     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
303       OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) },      /* 0x9b  ~S^(D&(P|S))   */
304     { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9c  S^(P&~D)       */
305     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
306       OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) },      /* 0x9d  ~D^(S&(P|D))   */
307     { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
308       OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
309       OP(TMP,DST,GXxor) },                           /* 0x9e  D^S^(P|(D&S))  */
310     { OP(SRC,DST,GXxor), OP(PAT,DST,GXnand) },       /* 0x9f  ~(P&(D^S))     */
311     { OP(PAT,DST,GXand) },                           /* 0xa0  D&P            */
312     { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor),
313       OP(PAT,DST,GXequiv) },                         /* 0xa1  ~P^(D|(S&~P))  */
314     { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXand) },  /* 0xa2  D&(P|~S)       */
315     { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
316       OP(SRC,DST,GXequiv) },                         /* 0xa3  ~D^(P|(S^D))   */
317     { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor),
318       OP(PAT,DST,GXequiv) },                         /* 0xa4  ~P^(D|~(S|P))  */
319     { OP(PAT,DST,GXequiv) },                         /* 0xa5  ~P^D           */
320     { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXxor) },/* 0xa6  D^(S&~P)       */
321     { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
322       OP(PAT,DST,GXequiv) },                         /* 0xa7  ~P^(D&(S|P))   */
323     { OP(PAT,SRC,GXor), OP(SRC,DST,GXand) },         /* 0xa8  D&(P|S)        */
324     { OP(PAT,SRC,GXor), OP(SRC,DST,GXequiv) },       /* 0xa9  ~D^(P|S)       */
325     { OP(PAT,DST,GXnoop) },                          /* 0xaa  D              */
326     { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor) },         /* 0xab  D|~(P|S)       */
327     { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
328       OP(SRC,DST,GXxor) },                           /* 0xac  S^(P&(D^S))    */
329     { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
330       OP(SRC,DST,GXequiv) },                         /* 0xad  ~D^(P|(S&D))   */
331     { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor) }, /* 0xae  D|(S&~P)       */
332     { OP(PAT,DST,GXorInverted) },                    /* 0xaf  D|~P           */
333     { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand) }, /* 0xb0  P&(D|~S)       */
334     { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
335       OP(PAT,DST,GXequiv) },                         /* 0xb1  ~P^(D|(S^P))   */
336     { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
337       OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
338       OP(TMP,DST,GXxor) },                           /* 0xb2  S^((S^P)|(S^D))*/
339     { OP(PAT,DST,GXnand), OP(SRC,DST,GXnand) },      /* 0xb3  ~(S&~(D&P))    */
340     { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXxor) }, /* 0xb4  P^(S&~D)       */
341     { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
342       OP(SRC,DST,GXequiv) },                         /* 0xb5  ~D^(P&(S|D))   */
343     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
344       OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
345       OP(TMP,DST,GXxor) },                           /* 0xb6  D^P^(S|(D&P))  */
346     { OP(PAT,DST,GXxor), OP(SRC,DST,GXnand) },       /* 0xb7  ~(S&(D^P))     */
347     { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
348       OP(PAT,DST,GXxor) },                           /* 0xb8  P^(S&(D^P))    */
349     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
350       OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) },       /* 0xb9  ~D^(S|(P&D))   */
351     { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXor) },  /* 0xba  D|(P&~S)       */
352     { OP(SRC,DST,GXorInverted) },                    /* 0xbb  ~S|D           */
353     { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
354       OP(SRC,DST,GXxor) },                           /* 0xbc  S^(P&~(D&S))   */
355     { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
356       OP(SRC,DST,GXnand) },                          /* 0xbd  ~((S^D)&(P^D)) */
357     { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor) },         /* 0xbe  D|(P^S)        */
358     { OP(PAT,SRC,GXnand), OP(SRC,DST,GXor) },        /* 0xbf  D|~(P&S)       */
359     { OP(PAT,SRC,GXand) },                           /* 0xc0  P&S            */
360     { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
361       OP(SRC,DST,GXequiv) },                         /* 0xc1  ~S^(P|(D&~S))  */
362     { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
363       OP(SRC,DST,GXequiv) },                         /* 0xc2  ~S^(P|~(D|S))  */
364     { OP(PAT,SRC,GXequiv) },                         /* 0xc3  ~P^S           */
365     { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXand) },  /* 0xc4  S&(P|~D)       */
366     { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
367       OP(SRC,DST,GXequiv) },                         /* 0xc5  ~S^(P|(D^S))   */
368     { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXxor) },/* 0xc6  S^(D&~P)       */
369     { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
370       OP(PAT,DST,GXequiv) },                         /* 0xc7  ~P^(S&(D|P))   */
371     { OP(PAT,DST,GXor), OP(SRC,DST,GXand) },         /* 0xc8  S&(D|P)        */
372     { OP(PAT,DST,GXor), OP(SRC,DST,GXequiv) },       /* 0xc9  ~S^(P|D)       */
373     { OP(DST,SRC,GXxor), OP(PAT,SRC,GXand),
374       OP(SRC,DST,GXxor) },                           /* 0xca  D^(P&(S^D))    */
375     { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
376       OP(SRC,DST,GXequiv) },                         /* 0xcb  ~S^(P|(D&S))   */
377     { OP(SRC,DST,GXcopy) },                          /* 0xcc  S              */
378     { OP(PAT,DST,GXnor), OP(SRC,DST,GXor) },         /* 0xcd  S|~(D|P)       */
379     { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXor) }, /* 0xce  S|(D&~P)       */
380     { OP(PAT,SRC,GXorInverted) },                    /* 0xcf  S|~P           */
381     { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXand) },  /* 0xd0  P&(S|~D)       */
382     { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
383       OP(PAT,DST,GXequiv) },                         /* 0xd1  ~P^(S|(D^P))   */
384     { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXxor) },/* 0xd2  P^(D&~S)       */
385     { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
386       OP(SRC,DST,GXequiv) },                         /* 0xd3  ~S^(P&(D|S))   */
387     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
388       OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
389       OP(TMP,DST,GXxor) },                           /* 0xd4  S^((S^P)&(D^P))*/
390     { OP(PAT,SRC,GXnand), OP(SRC,DST,GXnand) },      /* 0xd5  ~(D&~(P&S))    */
391     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
392       OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
393       OP(TMP,DST,GXxor) },                           /* 0xd6  S^P^(D|(P&S))  */
394     { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnand) },       /* 0xd7  ~(D&(P^S))     */
395     { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
396       OP(PAT,DST,GXxor) },                           /* 0xd8  P^(D&(S^P))    */
397     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
398       OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) },       /* 0xd9  ~S^(D|(P&S))   */
399     { OP(DST,SRC,GXnand), OP(PAT,SRC,GXand),
400       OP(SRC,DST,GXxor) },                           /* 0xda  D^(P&~(S&D))   */
401     { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
402       OP(SRC,DST,GXnand) },                          /* 0xdb  ~((S^P)&(S^D)) */
403     { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXor) },  /* 0xdc  S|(P&~D)       */
404     { OP(SRC,DST,GXorReverse) },                     /* 0xdd  S|~D           */
405     { OP(PAT,DST,GXxor), OP(SRC,DST,GXor) },         /* 0xde  S|(D^P)        */
406     { OP(PAT,DST,GXnand), OP(SRC,DST,GXor) },        /* 0xdf  S|~(D&P)       */
407     { OP(SRC,DST,GXor), OP(PAT,DST,GXand) },         /* 0xe0  P&(D|S)        */
408     { OP(SRC,DST,GXor), OP(PAT,DST,GXequiv) },       /* 0xe1  ~P^(D|S)       */
409     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
410       OP(SRC,DST,GXand), OP(TMP,DST,GXxor) },        /* 0xe2  D^(S&(P^D))    */
411     { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
412       OP(PAT,DST,GXequiv) },                         /* 0xe3  ~P^(S|(D&P))   */
413     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
414       OP(SRC,DST,GXand), OP(TMP,DST,GXxor) },        /* 0xe4  S^(D&(P^S))    */
415     { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
416       OP(PAT,DST,GXequiv) },                         /* 0xe5  ~P^(D|(S&P))   */
417     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
418       OP(SRC,DST,GXand), OP(TMP,DST,GXxor) },        /* 0xe6  S^(D&~(P&S))   */
419     { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
420       OP(SRC,DST,GXnand) },                          /* 0xe7  ~((S^P)&(D^P)) */
421     { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
422       OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
423       OP(TMP,DST,GXxor) },                           /* 0xe8  S^((S^P)&(S^D))*/
424     { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnand),
425       OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
426       OP(TMP,DST,GXequiv) },                         /* 0xe9  ~D^S^(P&~(S&D))*/
427     { OP(PAT,SRC,GXand), OP(SRC,DST,GXor) },         /* 0xea  D|(P&S)        */
428     { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXor) },       /* 0xeb  D|~(P^S)       */
429     { OP(PAT,DST,GXand), OP(SRC,DST,GXor) },         /* 0xec  S|(D&P)        */
430     { OP(PAT,DST,GXequiv), OP(SRC,DST,GXor) },       /* 0xed  S|~(D^P)       */
431     { OP(SRC,DST,GXor) },                            /* 0xee  S|D            */
432     { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXor) },  /* 0xef  S|D|~P         */
433     { OP(PAT,DST,GXcopy) },                          /* 0xf0  P              */
434     { OP(SRC,DST,GXnor), OP(PAT,DST,GXor) },         /* 0xf1  P|~(D|S)       */
435     { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor) }, /* 0xf2  P|(D&~S)       */
436     { OP(PAT,SRC,GXorReverse) },                     /* 0xf3  P|~S           */
437     { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXor) },  /* 0xf4  P|(S&~D)       */
438     { OP(PAT,DST,GXorReverse) },                     /* 0xf5  P|~D           */
439     { OP(SRC,DST,GXxor), OP(PAT,DST,GXor) },         /* 0xf6  P|(D^S)        */
440     { OP(SRC,DST,GXnand), OP(PAT,DST,GXor) },        /* 0xf7  P|~(S&D)       */
441     { OP(SRC,DST,GXand), OP(PAT,DST,GXor) },         /* 0xf8  P|(D&S)        */
442     { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor) },       /* 0xf9  P|~(D^S)       */
443     { OP(PAT,DST,GXor) },                            /* 0xfa  D|P            */
444     { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXor) },   /* 0xfb  D|P|~S         */
445     { OP(PAT,SRC,GXor) },                            /* 0xfc  P|S            */
446     { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXor) },   /* 0xfd  P|S|~D         */
447     { OP(SRC,DST,GXor), OP(PAT,DST,GXor) },          /* 0xfe  P|D|S          */
448     { OP(PAT,DST,GXset) }                            /* 0xff  1              */
449 };
450
451 static const unsigned char bit_swap[256] =
452 {
453     0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
454     0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
455     0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
456     0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
457     0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
458     0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
459     0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
460     0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
461     0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
462     0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
463     0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
464     0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
465     0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
466     0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
467     0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
468     0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
469     0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
470     0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
471     0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
472     0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
473     0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
474     0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
475     0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
476     0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
477     0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
478     0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
479     0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
480     0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
481     0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
482     0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
483     0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
484     0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
485 };
486
487 #ifdef WORDS_BIGENDIAN
488 static const unsigned int zeropad_masks[32] =
489 {
490     0xffffffff, 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xf8000000, 0xfc000000, 0xfe000000,
491     0xff000000, 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000,
492     0xffff0000, 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00,
493     0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 0xfffffff8, 0xfffffffc, 0xfffffffe
494 };
495 #else
496 static const unsigned int zeropad_masks[32] =
497 {
498     0xffffffff, 0x00000080, 0x000000c0, 0x000000e0, 0x000000f0, 0x000000f8, 0x000000fc, 0x000000fe,
499     0x000000ff, 0x000080ff, 0x0000c0ff, 0x0000e0ff, 0x0000f0ff, 0x0000f8ff, 0x0000fcff, 0x0000feff,
500     0x0000ffff, 0x0080ffff, 0x00c0ffff, 0x00e0ffff, 0x00f0ffff, 0x00f8ffff, 0x00fcffff, 0x00feffff,
501     0x00ffffff, 0x80ffffff, 0xc0ffffff, 0xe0ffffff, 0xf0ffffff, 0xf8ffffff, 0xfcffffff, 0xfeffffff
502 };
503 #endif
504
505 #ifdef BITBLT_TEST  /* Opcodes test */
506
507 static int do_bitop( int s, int d, int rop )
508 {
509     int res;
510     switch(rop)
511     {
512     case GXclear:        res = 0; break;
513     case GXand:          res = s & d; break;
514     case GXandReverse:   res = s & ~d; break;
515     case GXcopy:         res = s; break;
516     case GXandInverted:  res = ~s & d; break;
517     case GXnoop:         res = d; break;
518     case GXxor:          res = s ^ d; break;
519     case GXor:           res = s | d; break;
520     case GXnor:          res = ~(s | d); break;
521     case GXequiv:        res = ~s ^ d; break;
522     case GXinvert:       res = ~d; break;
523     case GXorReverse:    res = s | ~d; break;
524     case GXcopyInverted: res = ~s; break;
525     case GXorInverted:   res = ~s | d; break;
526     case GXnand:         res = ~(s & d); break;
527     case GXset:          res = 1; break;
528     }
529     return res & 1;
530 }
531
532 int main()
533 {
534     int rop, i, res, src, dst, pat, tmp, dstUsed;
535     const unsigned char *opcode;
536
537     for (rop = 0; rop < 256; rop++)
538     {
539         res = dstUsed = 0;
540         for (i = 0; i < 8; i++)
541         {
542             pat = (i >> 2) & 1;
543             src = (i >> 1) & 1;
544             dst = i & 1;
545             for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
546             {
547                 switch(*opcode >> 4)
548                 {
549                 case OP_ARGS(DST,TMP):
550                     tmp = do_bitop( dst, tmp, *opcode & 0xf );
551                     break;
552                 case OP_ARGS(DST,SRC):
553                     src = do_bitop( dst, src, *opcode & 0xf );
554                     break;
555                 case OP_ARGS(SRC,TMP):
556                     tmp = do_bitop( src, tmp, *opcode & 0xf );
557                     break;
558                 case OP_ARGS(SRC,DST):
559                     dst = do_bitop( src, dst, *opcode & 0xf );
560                     dstUsed = 1;
561                     break;
562                 case OP_ARGS(PAT,DST):
563                     dst = do_bitop( pat, dst, *opcode & 0xf );
564                     dstUsed = 1;
565                     break;
566                 case OP_ARGS(PAT,SRC):
567                     src = do_bitop( pat, src, *opcode & 0xf );
568                     break;
569                 case OP_ARGS(TMP,DST):
570                     dst = do_bitop( tmp, dst, *opcode & 0xf );
571                     dstUsed = 1;
572                     break;
573                 case OP_ARGS(TMP,SRC):
574                     src = do_bitop( tmp, src, *opcode & 0xf );
575                     break;
576                 default:
577                     printf( "Invalid opcode %x\n", *opcode );
578                 }
579             }
580             if (!dstUsed) dst = src;
581             if (dst) res |= 1 << i;
582         }
583         if (res != rop) printf( "%02x: ERROR, res=%02x\n", rop, res );
584     }
585
586     return 0;
587 }
588
589 #endif  /* BITBLT_TEST */
590
591
592 /* handler for XGetImage BadMatch errors */
593 static int XGetImage_handler( Display *dpy, XErrorEvent *event, void *arg )
594 {
595     return (event->request_code == X_GetImage && event->error_code == BadMatch);
596 }
597
598 /***********************************************************************
599  *           BITBLT_GetDstArea
600  *
601  * Retrieve an area from the destination DC, mapping all the
602  * pixels to Windows colors.
603  */
604 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, const RECT *visRectDst)
605 {
606     int exposures = 0;
607     INT width  = visRectDst->right - visRectDst->left;
608     INT height = visRectDst->bottom - visRectDst->top;
609
610     if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) ||
611         (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
612     {
613         XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
614                    physDev->dc_rect.left + visRectDst->left, physDev->dc_rect.top + visRectDst->top,
615                    width, height, 0, 0 );
616         exposures++;
617     }
618     else
619     {
620         INT x, y;
621         XImage *image;
622
623         /* Make sure we don't get a BadMatch error */
624         XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
625                    physDev->dc_rect.left + visRectDst->left,
626                    physDev->dc_rect.top + visRectDst->top,
627                    width, height, 0, 0);
628         exposures++;
629         image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
630                            AllPlanes, ZPixmap );
631         if (image)
632         {
633             for (y = 0; y < height; y++)
634                 for (x = 0; x < width; x++)
635                     XPutPixel( image, x, y,
636                                X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
637             XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
638             XDestroyImage( image );
639         }
640     }
641     return exposures;
642 }
643
644
645 /***********************************************************************
646  *           BITBLT_PutDstArea
647  *
648  * Put an area back into the destination DC, mapping the pixel
649  * colors to X pixels.
650  */
651 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, const RECT *visRectDst)
652 {
653     int exposures = 0;
654     INT width  = visRectDst->right - visRectDst->left;
655     INT height = visRectDst->bottom - visRectDst->top;
656
657     /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
658
659     if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) ||
660         (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
661     {
662         XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
663                    physDev->dc_rect.left + visRectDst->left,
664                    physDev->dc_rect.top + visRectDst->top );
665         exposures++;
666     }
667     else
668     {
669         register INT x, y;
670         XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
671                                    AllPlanes, ZPixmap );
672         for (y = 0; y < height; y++)
673             for (x = 0; x < width; x++)
674             {
675                 XPutPixel( image, x, y,
676                            X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
677             }
678         XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
679                    physDev->dc_rect.left + visRectDst->left,
680                    physDev->dc_rect.top + visRectDst->top, width, height );
681         XDestroyImage( image );
682     }
683     return exposures;
684 }
685
686 static BOOL same_format(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst)
687 {
688     if (physDevSrc->depth != physDevDst->depth) return FALSE;
689     if (!physDevSrc->color_shifts && !physDevDst->color_shifts) return TRUE;
690     if (physDevSrc->color_shifts && physDevDst->color_shifts)
691         return !memcmp(physDevSrc->color_shifts, physDevDst->color_shifts, sizeof(ColorShifts));
692     return FALSE;
693 }
694
695 void execute_rop( X11DRV_PDEVICE *physdev, Pixmap src_pixmap, GC gc, const RECT *visrect, DWORD rop )
696 {
697     Pixmap pixmaps[3];
698     Pixmap result = src_pixmap;
699     BOOL null_brush;
700     const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
701     BOOL use_pat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
702     BOOL use_dst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
703     int width  = visrect->right - visrect->left;
704     int height = visrect->bottom - visrect->top;
705
706     pixmaps[SRC] = src_pixmap;
707     pixmaps[TMP] = 0;
708     pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height, physdev->depth );
709
710     if (use_dst) BITBLT_GetDstArea( physdev, pixmaps[DST], gc, visrect );
711     null_brush = use_pat && !X11DRV_SetupGCForPatBlt( physdev, gc, TRUE );
712
713     for ( ; *opcode; opcode++)
714     {
715         if (OP_DST(*opcode) == DST) result = pixmaps[DST];
716         XSetFunction( gdi_display, gc, OP_ROP(*opcode) );
717         switch(OP_SRCDST(*opcode))
718         {
719         case OP_ARGS(DST,TMP):
720         case OP_ARGS(SRC,TMP):
721             if (!pixmaps[TMP])
722                 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window, width, height, physdev->depth );
723             /* fall through */
724         case OP_ARGS(DST,SRC):
725         case OP_ARGS(SRC,DST):
726         case OP_ARGS(TMP,SRC):
727         case OP_ARGS(TMP,DST):
728             XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)], pixmaps[OP_DST(*opcode)], gc,
729                        0, 0, width, height, 0, 0 );
730             break;
731         case OP_ARGS(PAT,DST):
732         case OP_ARGS(PAT,SRC):
733             if (!null_brush)
734                 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)], gc, 0, 0, width, height );
735             break;
736         }
737     }
738     XSetFunction( gdi_display, physdev->gc, GXcopy );
739     physdev->exposures += BITBLT_PutDstArea( physdev, result, visrect );
740     XFreePixmap( gdi_display, pixmaps[DST] );
741     if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
742     add_device_bounds( physdev, visrect );
743 }
744
745 /***********************************************************************
746  *           X11DRV_PatBlt
747  */
748 BOOL X11DRV_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
749 {
750     X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
751     BOOL usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
752     const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
753
754     if (usePat && !X11DRV_SetupGCForBrush( physDev )) return TRUE;
755
756     XSetFunction( gdi_display, physDev->gc, OP_ROP(*opcode) );
757
758     switch(rop)  /* a few special cases */
759     {
760     case BLACKNESS:  /* 0x00 */
761     case WHITENESS:  /* 0xff */
762         if ((physDev->depth != 1) && X11DRV_PALETTE_PaletteToXPixel)
763         {
764             XSetFunction( gdi_display, physDev->gc, GXcopy );
765             if (rop == BLACKNESS)
766                 XSetForeground( gdi_display, physDev->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
767             else
768                 XSetForeground( gdi_display, physDev->gc,
769                                 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
770             XSetFillStyle( gdi_display, physDev->gc, FillSolid );
771         }
772         break;
773     case DSTINVERT:  /* 0x55 */
774         if (!(X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL)))
775         {
776             /* Xor is much better when we do not have full colormap.   */
777             /* Using white^black ensures that we invert at least black */
778             /* and white. */
779             unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
780                                      BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
781             XSetFunction( gdi_display, physDev->gc, GXxor );
782             XSetForeground( gdi_display, physDev->gc, xor_pix);
783             XSetFillStyle( gdi_display, physDev->gc, FillSolid );
784         }
785         break;
786     }
787     XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
788                     physDev->dc_rect.left + dst->visrect.left,
789                     physDev->dc_rect.top + dst->visrect.top,
790                     dst->visrect.right - dst->visrect.left,
791                     dst->visrect.bottom - dst->visrect.top );
792     add_device_bounds( physDev, &dst->visrect );
793     return TRUE;
794 }
795
796
797 /***********************************************************************
798  *           X11DRV_StretchBlt
799  */
800 BOOL X11DRV_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
801                         PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
802 {
803     X11DRV_PDEVICE *physDevDst = get_x11drv_dev( dst_dev );
804     X11DRV_PDEVICE *physDevSrc = get_x11drv_dev( src_dev );
805     INT width, height;
806     const BYTE *opcode;
807     Pixmap src_pixmap;
808     GC gc;
809
810     if (src_dev->funcs != dst_dev->funcs ||
811         src->width != dst->width || src->height != dst->height ||  /* no stretching with core X11 */
812         (physDevDst->depth == 1 && physDevSrc->depth != 1) ||  /* color -> mono done by hand */
813         (X11DRV_PALETTE_XPixelToPalette && physDevSrc->depth != 1))  /* needs palette mapping */
814     {
815         dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
816         return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
817     }
818
819     width  = dst->visrect.right - dst->visrect.left;
820     height = dst->visrect.bottom - dst->visrect.top;
821     opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
822
823     add_device_bounds( physDevDst, &dst->visrect );
824
825     /* a few optimizations for single-op ROPs */
826     if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
827     {
828         if (same_format(physDevSrc, physDevDst))
829         {
830             XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
831             XCopyArea( gdi_display, physDevSrc->drawable,
832                        physDevDst->drawable, physDevDst->gc,
833                        physDevSrc->dc_rect.left + src->visrect.left,
834                        physDevSrc->dc_rect.top + src->visrect.top,
835                        width, height,
836                        physDevDst->dc_rect.left + dst->visrect.left,
837                        physDevDst->dc_rect.top + dst->visrect.top );
838             physDevDst->exposures++;
839             return TRUE;
840         }
841         if (physDevSrc->depth == 1)
842         {
843             int text_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, GetTextColor(physDevDst->dev.hdc) );
844             int bkgnd_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, GetBkColor(physDevDst->dev.hdc) );
845
846             XSetBackground( gdi_display, physDevDst->gc, text_pixel );
847             XSetForeground( gdi_display, physDevDst->gc, bkgnd_pixel );
848             XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
849             XCopyPlane( gdi_display, physDevSrc->drawable,
850                         physDevDst->drawable, physDevDst->gc,
851                         physDevSrc->dc_rect.left + src->visrect.left,
852                         physDevSrc->dc_rect.top + src->visrect.top,
853                         width, height,
854                         physDevDst->dc_rect.left + dst->visrect.left,
855                         physDevDst->dc_rect.top + dst->visrect.top, 1 );
856             physDevDst->exposures++;
857             return TRUE;
858         }
859     }
860
861     gc = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
862     XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
863     XSetGraphicsExposures( gdi_display, gc, False );
864
865     /* retrieve the source */
866
867     src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, physDevDst->depth );
868     if (physDevSrc->depth == 1)
869     {
870         /* MSDN says if StretchBlt must convert a bitmap from monochrome
871            to color or vice versa, the foreground and background color of
872            the device context are used.  In fact, it also applies to the
873            case when it is converted from mono to mono. */
874         int text_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, GetTextColor(physDevDst->dev.hdc) );
875         int bkgnd_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, GetBkColor(physDevDst->dev.hdc) );
876
877         if (X11DRV_PALETTE_XPixelToPalette && physDevDst->depth != 1)
878         {
879             XSetBackground( gdi_display, gc, X11DRV_PALETTE_XPixelToPalette[text_pixel] );
880             XSetForeground( gdi_display, gc, X11DRV_PALETTE_XPixelToPalette[bkgnd_pixel]);
881         }
882         else
883         {
884             XSetBackground( gdi_display, gc, text_pixel );
885             XSetForeground( gdi_display, gc, bkgnd_pixel );
886         }
887         XCopyPlane( gdi_display, physDevSrc->drawable, src_pixmap, gc,
888                     physDevSrc->dc_rect.left + src->visrect.left,
889                     physDevSrc->dc_rect.top + src->visrect.top,
890                     width, height, 0, 0, 1 );
891     }
892     else  /* color -> color */
893     {
894         XCopyArea( gdi_display, physDevSrc->drawable, src_pixmap, gc,
895                    physDevSrc->dc_rect.left + src->visrect.left,
896                    physDevSrc->dc_rect.top + src->visrect.top,
897                    width, height, 0, 0 );
898     }
899
900     execute_rop( physDevDst, src_pixmap, gc, &dst->visrect, rop );
901
902     XFreePixmap( gdi_display, src_pixmap );
903     XFreeGC( gdi_display, gc );
904     return TRUE;
905 }
906
907
908 static void free_heap_bits( struct gdi_image_bits *bits )
909 {
910     HeapFree( GetProcessHeap(), 0, bits->ptr );
911 }
912
913 static void free_ximage_bits( struct gdi_image_bits *bits )
914 {
915     XFree( bits->ptr );
916 }
917
918 /* only for use on sanitized BITMAPINFO structures */
919 static inline int get_dib_info_size( const BITMAPINFO *info, UINT coloruse )
920 {
921     if (info->bmiHeader.biCompression == BI_BITFIELDS)
922         return sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD);
923     if (coloruse == DIB_PAL_COLORS)
924         return sizeof(BITMAPINFOHEADER) + info->bmiHeader.biClrUsed * sizeof(WORD);
925     return FIELD_OFFSET( BITMAPINFO, bmiColors[info->bmiHeader.biClrUsed] );
926 }
927
928 static inline int get_dib_stride( int width, int bpp )
929 {
930     return ((width * bpp + 31) >> 3) & ~3;
931 }
932
933 static inline int get_dib_image_size( const BITMAPINFO *info )
934 {
935     return get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount )
936         * abs( info->bmiHeader.biHeight );
937 }
938
939 /* store the palette or color mask data in the bitmap info structure */
940 static void set_color_info( const XVisualInfo *vis, BITMAPINFO *info )
941 {
942     DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
943
944     info->bmiHeader.biCompression = BI_RGB;
945     info->bmiHeader.biClrUsed = 0;
946
947     switch (info->bmiHeader.biBitCount)
948     {
949     case 4:
950     case 8:
951     {
952         RGBQUAD *rgb = (RGBQUAD *)colors;
953         PALETTEENTRY palette[256];
954         UINT i, count;
955
956         info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
957         count = X11DRV_GetSystemPaletteEntries( NULL, 0, info->bmiHeader.biClrUsed, palette );
958         for (i = 0; i < count; i++)
959         {
960             rgb[i].rgbRed   = palette[i].peRed;
961             rgb[i].rgbGreen = palette[i].peGreen;
962             rgb[i].rgbBlue  = palette[i].peBlue;
963             rgb[i].rgbReserved = 0;
964         }
965         memset( &rgb[count], 0, (info->bmiHeader.biClrUsed - count) * sizeof(*rgb) );
966         break;
967     }
968     case 16:
969         colors[0] = vis->red_mask;
970         colors[1] = vis->green_mask;
971         colors[2] = vis->blue_mask;
972         info->bmiHeader.biCompression = BI_BITFIELDS;
973         break;
974     case 32:
975         colors[0] = vis->red_mask;
976         colors[1] = vis->green_mask;
977         colors[2] = vis->blue_mask;
978         if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
979             info->bmiHeader.biCompression = BI_BITFIELDS;
980         break;
981     }
982 }
983
984 /* check if the specified color info is suitable for PutImage */
985 static BOOL matching_color_info( const XVisualInfo *vis, const BITMAPINFO *info )
986 {
987     DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
988
989     switch (info->bmiHeader.biBitCount)
990     {
991     case 1:
992         if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
993         return !info->bmiHeader.biClrUsed;  /* color map not allowed */
994     case 4:
995     case 8:
996     {
997         RGBQUAD *rgb = (RGBQUAD *)colors;
998         PALETTEENTRY palette[256];
999         UINT i, count;
1000
1001         if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
1002         count = X11DRV_GetSystemPaletteEntries( NULL, 0, 1 << info->bmiHeader.biBitCount, palette );
1003         if (count != info->bmiHeader.biClrUsed) return FALSE;
1004         for (i = 0; i < count; i++)
1005         {
1006             if (rgb[i].rgbRed   != palette[i].peRed ||
1007                 rgb[i].rgbGreen != palette[i].peGreen ||
1008                 rgb[i].rgbBlue  != palette[i].peBlue) return FALSE;
1009         }
1010         return TRUE;
1011     }
1012     case 16:
1013         if (info->bmiHeader.biCompression == BI_BITFIELDS)
1014             return (vis->red_mask == colors[0] &&
1015                     vis->green_mask == colors[1] &&
1016                     vis->blue_mask == colors[2]);
1017         if (info->bmiHeader.biCompression == BI_RGB)
1018             return (vis->red_mask == 0x7c00 && vis->green_mask == 0x03e0 && vis->blue_mask == 0x001f);
1019         break;
1020     case 32:
1021         if (info->bmiHeader.biCompression == BI_BITFIELDS)
1022             return (vis->red_mask == colors[0] &&
1023                     vis->green_mask == colors[1] &&
1024                     vis->blue_mask == colors[2]);
1025         /* fall through */
1026     case 24:
1027         if (info->bmiHeader.biCompression == BI_RGB)
1028             return (vis->red_mask == 0xff0000 && vis->green_mask == 0x00ff00 && vis->blue_mask == 0x0000ff);
1029         break;
1030     }
1031     return FALSE;
1032 }
1033
1034 static inline BOOL is_r8g8b8( const XVisualInfo *vis )
1035 {
1036     return vis->depth == 24 && vis->red_mask == 0xff0000 && vis->blue_mask == 0x0000ff;
1037 }
1038
1039 /* copy the image bits, fixing up alignment and byte swapping as necessary */
1040 DWORD copy_image_bits( BITMAPINFO *info, BOOL is_r8g8b8, XImage *image,
1041                        const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits,
1042                        struct bitblt_coords *coords, const int *mapping, unsigned int zeropad_mask )
1043 {
1044 #ifdef WORDS_BIGENDIAN
1045     static const int client_byte_order = MSBFirst;
1046 #else
1047     static const int client_byte_order = LSBFirst;
1048 #endif
1049     BOOL need_byteswap;
1050     int x, y, height = coords->visrect.bottom - coords->visrect.top;
1051     int width_bytes = image->bytes_per_line;
1052     int padding_pos;
1053     unsigned char *src, *dst;
1054
1055     switch (info->bmiHeader.biBitCount)
1056     {
1057     case 1:
1058         need_byteswap = (image->bitmap_bit_order != MSBFirst);
1059         break;
1060     case 4:
1061         need_byteswap = (image->byte_order != MSBFirst);
1062         break;
1063     case 16:
1064     case 32:
1065         need_byteswap = (image->byte_order != client_byte_order);
1066         break;
1067     case 24:
1068         need_byteswap = (image->byte_order == MSBFirst) ^ !is_r8g8b8;
1069         break;
1070     default:
1071         need_byteswap = FALSE;
1072         break;
1073     }
1074
1075     src = src_bits->ptr;
1076     if (info->bmiHeader.biHeight > 0)
1077         src += (info->bmiHeader.biHeight - coords->visrect.bottom) * width_bytes;
1078     else
1079         src += coords->visrect.top * width_bytes;
1080
1081     if ((need_byteswap && !src_bits->is_copy) ||  /* need to swap bytes */
1082         (zeropad_mask != ~0u && !src_bits->is_copy) ||  /* need to clear padding bytes */
1083         (mapping && !src_bits->is_copy) ||  /* need to remap pixels */
1084         (width_bytes & 3) ||  /* need to fixup line alignment */
1085         (info->bmiHeader.biHeight > 0))  /* need to flip vertically */
1086     {
1087         width_bytes = (width_bytes + 3) & ~3;
1088         info->bmiHeader.biSizeImage = height * width_bytes;
1089         if (!(dst_bits->ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage )))
1090             return ERROR_OUTOFMEMORY;
1091         dst_bits->is_copy = TRUE;
1092         dst_bits->free = free_heap_bits;
1093     }
1094     else
1095     {
1096         /* swap bits in place */
1097         dst_bits->ptr = src;
1098         dst_bits->is_copy = src_bits->is_copy;
1099         dst_bits->free = NULL;
1100         if (!need_byteswap && zeropad_mask == ~0u && !mapping) return ERROR_SUCCESS;  /* nothing to do */
1101     }
1102
1103     dst = dst_bits->ptr;
1104     padding_pos = width_bytes/sizeof(unsigned int) - 1;
1105
1106     if (info->bmiHeader.biHeight > 0)
1107     {
1108         dst += (height - 1) * width_bytes;
1109         width_bytes = -width_bytes;
1110     }
1111
1112     if (need_byteswap || mapping)
1113     {
1114         switch (info->bmiHeader.biBitCount)
1115         {
1116         case 1:
1117             for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1118             {
1119                 for (x = 0; x < image->bytes_per_line; x++)
1120                     dst[x] = bit_swap[src[x]];
1121                 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1122             }
1123             break;
1124         case 4:
1125             for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1126             {
1127                 if (mapping)
1128                     for (x = 0; x < image->bytes_per_line; x++)
1129                         dst[x] = (mapping[src[x] & 0x0f] << 4) | mapping[src[x] >> 4];
1130                 else
1131                     for (x = 0; x < image->bytes_per_line; x++)
1132                         dst[x] = (src[x] << 4) | (src[x] >> 4);
1133                 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1134             }
1135             break;
1136         case 8:
1137             for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1138             {
1139                 for (x = 0; x < image->bytes_per_line; x++)
1140                     dst[x] = mapping[src[x]];
1141                 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1142             }
1143             break;
1144         case 16:
1145             for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1146             {
1147                 for (x = 0; x < info->bmiHeader.biWidth; x++)
1148                     ((USHORT *)dst)[x] = RtlUshortByteSwap( ((const USHORT *)src)[x] );
1149                 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1150             }
1151             break;
1152         case 24:
1153             for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1154             {
1155                 for (x = 0; x < info->bmiHeader.biWidth; x++)
1156                 {
1157                     unsigned char tmp = src[3 * x];
1158                     dst[3 * x]     = src[3 * x + 2];
1159                     dst[3 * x + 1] = src[3 * x + 1];
1160                     dst[3 * x + 2] = tmp;
1161                 }
1162                 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1163             }
1164             break;
1165         case 32:
1166             for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1167                 for (x = 0; x < info->bmiHeader.biWidth; x++)
1168                     ((ULONG *)dst)[x] = RtlUlongByteSwap( ((const ULONG *)src)[x] );
1169             break;
1170         }
1171     }
1172     else if (src != dst)
1173     {
1174         for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1175         {
1176             memcpy( dst, src, image->bytes_per_line );
1177             ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1178         }
1179     }
1180     else  /* only need to clear the padding */
1181     {
1182         for (y = 0; y < height; y++, dst += width_bytes)
1183             ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1184     }
1185     return ERROR_SUCCESS;
1186 }
1187
1188 /***********************************************************************
1189  *           X11DRV_PutImage
1190  */
1191 DWORD X11DRV_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info,
1192                        const struct gdi_image_bits *bits, struct bitblt_coords *src,
1193                        struct bitblt_coords *dst, DWORD rop )
1194 {
1195     X11DRV_PDEVICE *physdev = get_x11drv_dev( dev );
1196     DWORD ret;
1197     XImage *image;
1198     XVisualInfo vis;
1199     struct gdi_image_bits dst_bits;
1200     const XPixmapFormatValues *format;
1201     const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1202     const int *mapping = NULL;
1203
1204     vis.depth = physdev->depth;
1205     if (physdev->color_shifts)
1206     {
1207         vis.red_mask   = physdev->color_shifts->logicalRed.max   << physdev->color_shifts->logicalRed.shift;
1208         vis.green_mask = physdev->color_shifts->logicalGreen.max << physdev->color_shifts->logicalGreen.shift;
1209         vis.blue_mask  = physdev->color_shifts->logicalBlue.max  << physdev->color_shifts->logicalBlue.shift;
1210     }
1211     format = pixmap_formats[vis.depth];
1212
1213     if (info->bmiHeader.biPlanes != 1) goto update_format;
1214     if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1215     /* FIXME: could try to handle 1-bpp using XCopyPlane */
1216     if (!matching_color_info( &vis, info )) goto update_format;
1217     if (!bits) return ERROR_SUCCESS;  /* just querying the format */
1218     if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
1219
1220     image = XCreateImage( gdi_display, visual, vis.depth, ZPixmap, 0, NULL,
1221                           info->bmiHeader.biWidth, src->visrect.bottom - src->visrect.top, 32, 0 );
1222     if (!image) return ERROR_OUTOFMEMORY;
1223
1224     if (image->bits_per_pixel == 4 || image->bits_per_pixel == 8)
1225     {
1226         if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1227             mapping = X11DRV_PALETTE_PaletteToXPixel;
1228     }
1229
1230     ret = copy_image_bits( info, is_r8g8b8(&vis), image, bits, &dst_bits, src, mapping, ~0u );
1231
1232     if (!ret)
1233     {
1234         BOOL restore_region = add_extra_clipping_region( physdev, clip );
1235         int width = dst->visrect.right - dst->visrect.left;
1236         int height = dst->visrect.bottom - dst->visrect.top;
1237
1238         image->data = dst_bits.ptr;
1239
1240         /* optimization for single-op ROPs */
1241         if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1242         {
1243             XSetFunction( gdi_display, physdev->gc, OP_ROP(*opcode) );
1244             XPutImage( gdi_display, physdev->drawable, physdev->gc, image, src->visrect.left, 0,
1245                        physdev->dc_rect.left + dst->visrect.left,
1246                        physdev->dc_rect.top + dst->visrect.top, width, height );
1247         }
1248         else
1249         {
1250             GC gc = XCreateGC( gdi_display, physdev->drawable, 0, NULL );
1251             Pixmap src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, vis.depth );
1252
1253             XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
1254             XSetGraphicsExposures( gdi_display, gc, False );
1255             XPutImage( gdi_display, src_pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1256
1257             execute_rop( physdev, src_pixmap, gc, &dst->visrect, rop );
1258
1259             XFreePixmap( gdi_display, src_pixmap );
1260             XFreeGC( gdi_display, gc );
1261         }
1262
1263         if (restore_region) restore_clipping_region( physdev );
1264         add_device_bounds( physdev, &dst->visrect );
1265         image->data = NULL;
1266     }
1267
1268     XDestroyImage( image );
1269     if (dst_bits.free) dst_bits.free( &dst_bits );
1270     return ret;
1271
1272 update_format:
1273     info->bmiHeader.biPlanes   = 1;
1274     info->bmiHeader.biBitCount = format->bits_per_pixel;
1275     if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1276     set_color_info( &vis, info );
1277     return ERROR_BAD_FORMAT;
1278 }
1279
1280 /***********************************************************************
1281  *           X11DRV_GetImage
1282  */
1283 DWORD X11DRV_GetImage( PHYSDEV dev, BITMAPINFO *info,
1284                        struct gdi_image_bits *bits, struct bitblt_coords *src )
1285 {
1286     X11DRV_PDEVICE *physdev = get_x11drv_dev( dev );
1287     DWORD ret = ERROR_SUCCESS;
1288     XImage *image;
1289     XVisualInfo vis;
1290     UINT align, x, y, width, height;
1291     struct gdi_image_bits src_bits;
1292     const XPixmapFormatValues *format;
1293     const int *mapping = NULL;
1294
1295     vis.depth = physdev->depth;
1296     if (physdev->color_shifts)
1297     {
1298         vis.red_mask   = physdev->color_shifts->logicalRed.max   << physdev->color_shifts->logicalRed.shift;
1299         vis.green_mask = physdev->color_shifts->logicalGreen.max << physdev->color_shifts->logicalGreen.shift;
1300         vis.blue_mask  = physdev->color_shifts->logicalBlue.max  << physdev->color_shifts->logicalBlue.shift;
1301     }
1302     format = pixmap_formats[vis.depth];
1303
1304     /* align start and width to 32-bit boundary */
1305     switch (format->bits_per_pixel)
1306     {
1307     case 1:  align = 32; break;
1308     case 4:  align = 8;  mapping = X11DRV_PALETTE_XPixelToPalette; break;
1309     case 8:  align = 4;  mapping = X11DRV_PALETTE_XPixelToPalette; break;
1310     case 16: align = 2;  break;
1311     case 24: align = 4;  break;
1312     case 32: align = 1;  break;
1313     default:
1314         FIXME( "depth %u bpp %u not supported yet\n", vis.depth, format->bits_per_pixel );
1315         return ERROR_BAD_FORMAT;
1316     }
1317
1318     info->bmiHeader.biSize          = sizeof(info->bmiHeader);
1319     info->bmiHeader.biPlanes        = 1;
1320     info->bmiHeader.biBitCount      = format->bits_per_pixel;
1321     info->bmiHeader.biXPelsPerMeter = 0;
1322     info->bmiHeader.biYPelsPerMeter = 0;
1323     info->bmiHeader.biClrImportant  = 0;
1324     set_color_info( &vis, info );
1325
1326     if (!bits) return ERROR_SUCCESS;  /* just querying the color information */
1327
1328     x = src->visrect.left & ~(align - 1);
1329     y = src->visrect.top;
1330     width = src->visrect.right - x;
1331     height = src->visrect.bottom - src->visrect.top;
1332     if (format->scanline_pad != 32) width = (width + (align - 1)) & ~(align - 1);
1333     /* make the source rectangle relative to the returned bits */
1334     src->x -= x;
1335     src->y -= y;
1336     OffsetRect( &src->visrect, -x, -y );
1337
1338     X11DRV_expect_error( gdi_display, XGetImage_handler, NULL );
1339     image = XGetImage( gdi_display, physdev->drawable,
1340                        physdev->dc_rect.left + x, physdev->dc_rect.top + y,
1341                        width, height, AllPlanes, ZPixmap );
1342     if (X11DRV_check_error())
1343     {
1344         /* use a temporary pixmap to avoid the BadMatch error */
1345         Pixmap pixmap = XCreatePixmap( gdi_display, root_window, width, height, vis.depth );
1346         GC gc = XCreateGC( gdi_display, pixmap, 0, NULL );
1347
1348         XSetGraphicsExposures( gdi_display, gc, False );
1349         XCopyArea( gdi_display, physdev->drawable, pixmap, gc,
1350                    physdev->dc_rect.left + x, physdev->dc_rect.top + y, width, height, 0, 0 );
1351         image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
1352         XFreePixmap( gdi_display, pixmap );
1353         XFreeGC( gdi_display, gc );
1354     }
1355
1356     if (!image) return ERROR_OUTOFMEMORY;
1357
1358     info->bmiHeader.biWidth     = width;
1359     info->bmiHeader.biHeight    = -height;
1360     info->bmiHeader.biSizeImage = height * image->bytes_per_line;
1361
1362     src_bits.ptr     = image->data;
1363     src_bits.is_copy = TRUE;
1364     ret = copy_image_bits( info, is_r8g8b8(&vis), image, &src_bits, bits, src, mapping,
1365                            zeropad_masks[(width * image->bits_per_pixel) & 31] );
1366
1367     if (!ret && bits->ptr == image->data)
1368     {
1369         bits->free = free_ximage_bits;
1370         image->data = NULL;
1371     }
1372     XDestroyImage( image );
1373     return ret;
1374 }
1375
1376
1377 /***********************************************************************
1378  *           put_pixmap_image
1379  *
1380  * Simplified equivalent of X11DRV_PutImage that writes directly to a pixmap.
1381  */
1382 static DWORD put_pixmap_image( Pixmap pixmap, const XVisualInfo *vis,
1383                                BITMAPINFO *info, const struct gdi_image_bits *bits )
1384 {
1385     DWORD ret;
1386     XImage *image;
1387     GC gc;
1388     struct bitblt_coords coords;
1389     struct gdi_image_bits dst_bits;
1390     const XPixmapFormatValues *format = pixmap_formats[vis->depth];
1391     const int *mapping = NULL;
1392
1393     if (!format) return ERROR_INVALID_PARAMETER;
1394     if (info->bmiHeader.biPlanes != 1) goto update_format;
1395     if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1396     /* FIXME: could try to handle 1-bpp using XCopyPlane */
1397     if (!matching_color_info( vis, info )) goto update_format;
1398     if (!bits) return ERROR_SUCCESS;  /* just querying the format */
1399
1400     coords.x = 0;
1401     coords.y = 0;
1402     coords.width = info->bmiHeader.biWidth;
1403     coords.height = abs( info->bmiHeader.biHeight );
1404     SetRect( &coords.visrect, 0, 0, coords.width, coords.height );
1405
1406     image = XCreateImage( gdi_display, visual, vis->depth, ZPixmap, 0, NULL,
1407                           coords.width, coords.height, 32, 0 );
1408     if (!image) return ERROR_OUTOFMEMORY;
1409
1410     if (image->bits_per_pixel == 4 || image->bits_per_pixel == 8)
1411         mapping = X11DRV_PALETTE_PaletteToXPixel;
1412
1413     if (!(ret = copy_image_bits( info, is_r8g8b8(vis), image, bits, &dst_bits, &coords, mapping, ~0u )))
1414     {
1415         image->data = dst_bits.ptr;
1416         gc = XCreateGC( gdi_display, pixmap, 0, NULL );
1417         XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, coords.width, coords.height );
1418         XFreeGC( gdi_display, gc );
1419         image->data = NULL;
1420     }
1421
1422     XDestroyImage( image );
1423     if (dst_bits.free) dst_bits.free( &dst_bits );
1424     return ret;
1425
1426 update_format:
1427     info->bmiHeader.biPlanes   = 1;
1428     info->bmiHeader.biBitCount = format->bits_per_pixel;
1429     if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1430     set_color_info( vis, info );
1431     return ERROR_BAD_FORMAT;
1432 }
1433
1434
1435 /***********************************************************************
1436  *           create_pixmap_from_image
1437  */
1438 Pixmap create_pixmap_from_image( HDC hdc, const XVisualInfo *vis, const BITMAPINFO *info,
1439                                  const struct gdi_image_bits *bits, UINT coloruse )
1440 {
1441     static const RGBQUAD default_colortable[2] = { { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff } };
1442     char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1443     char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1444     BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
1445     BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
1446     struct gdi_image_bits dst_bits;
1447     Pixmap pixmap;
1448     DWORD err;
1449     HBITMAP dib;
1450
1451     pixmap = XCreatePixmap( gdi_display, root_window,
1452                             info->bmiHeader.biWidth, abs(info->bmiHeader.biHeight), vis->depth );
1453     if (!pixmap) return 0;
1454
1455     memcpy( src_info, info, get_dib_info_size( info, coloruse ));
1456     memcpy( dst_info, info, get_dib_info_size( info, coloruse ));
1457
1458     if (coloruse == DIB_PAL_COLORS ||
1459         (err = put_pixmap_image( pixmap, vis, dst_info, bits )) == ERROR_BAD_FORMAT)
1460     {
1461         if (dst_info->bmiHeader.biBitCount == 1)  /* set a default color table for 1-bpp */
1462             memcpy( dst_info->bmiColors, default_colortable, sizeof(default_colortable) );
1463         dib = CreateDIBSection( hdc, dst_info, coloruse, &dst_bits.ptr, 0, 0 );
1464         if (dib)
1465         {
1466             if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
1467                 memcpy( src_info->bmiColors, default_colortable, sizeof(default_colortable) );
1468             SetDIBits( hdc, dib, 0, abs(info->bmiHeader.biHeight), bits->ptr, src_info, coloruse );
1469             dst_bits.free = NULL;
1470             dst_bits.is_copy = TRUE;
1471             err = put_pixmap_image( pixmap, vis, dst_info, &dst_bits );
1472             DeleteObject( dib );
1473         }
1474         else err = ERROR_OUTOFMEMORY;
1475     }
1476
1477     if (!err) return pixmap;
1478
1479     XFreePixmap( gdi_display, pixmap );
1480     return 0;
1481
1482 }
1483
1484
1485 /***********************************************************************
1486  *           get_pixmap_image
1487  *
1488  * Equivalent of X11DRV_GetImage that reads directly from a pixmap.
1489  */
1490 DWORD get_pixmap_image( Pixmap pixmap, int width, int height, const XVisualInfo *vis,
1491                         BITMAPINFO *info, struct gdi_image_bits *bits )
1492 {
1493     DWORD ret = ERROR_SUCCESS;
1494     XImage *image;
1495     struct gdi_image_bits src_bits;
1496     struct bitblt_coords coords;
1497     const XPixmapFormatValues *format = pixmap_formats[vis->depth];
1498     const int *mapping = NULL;
1499
1500     if (!format) return ERROR_INVALID_PARAMETER;
1501
1502     info->bmiHeader.biSize          = sizeof(info->bmiHeader);
1503     info->bmiHeader.biWidth         = width;
1504     info->bmiHeader.biHeight        = -height;
1505     info->bmiHeader.biPlanes        = 1;
1506     info->bmiHeader.biBitCount      = format->bits_per_pixel;
1507     info->bmiHeader.biXPelsPerMeter = 0;
1508     info->bmiHeader.biYPelsPerMeter = 0;
1509     info->bmiHeader.biClrImportant  = 0;
1510     set_color_info( vis, info );
1511
1512     if (!bits) return ERROR_SUCCESS;  /* just querying the color information */
1513
1514     coords.x = 0;
1515     coords.y = 0;
1516     coords.width = width;
1517     coords.height = height;
1518     SetRect( &coords.visrect, 0, 0, width, height );
1519
1520     image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
1521     if (!image) return ERROR_OUTOFMEMORY;
1522
1523     info->bmiHeader.biSizeImage = height * image->bytes_per_line;
1524
1525     src_bits.ptr     = image->data;
1526     src_bits.is_copy = TRUE;
1527     ret = copy_image_bits( info, is_r8g8b8(vis), image, &src_bits, bits, &coords, mapping,
1528                            zeropad_masks[(width * image->bits_per_pixel) & 31] );
1529
1530     if (!ret && bits->ptr == image->data)
1531     {
1532         bits->free = free_ximage_bits;
1533         image->data = NULL;
1534     }
1535     XDestroyImage( image );
1536     return ret;
1537 }
1538
1539
1540 struct x11drv_window_surface
1541 {
1542     struct window_surface header;
1543     Window                window;
1544     GC                    gc;
1545     XImage               *image;
1546     RECT                  bounds;
1547     BOOL                  is_r8g8b8;
1548     COLORREF              color_key;
1549     struct gdi_image_bits bits;
1550     CRITICAL_SECTION      crit;
1551     BITMAPINFO            info;   /* variable size, must be last */
1552 };
1553
1554 static struct x11drv_window_surface *get_x11_surface( struct window_surface *surface )
1555 {
1556     return (struct x11drv_window_surface *)surface;
1557 }
1558
1559 static inline UINT get_color_component( UINT color, UINT mask )
1560 {
1561     int shift;
1562     for (shift = 0; !(mask & 1); shift++) mask >>= 1;
1563     return (color * mask / 255) << shift;
1564 }
1565
1566 static inline void flush_rgn_data( HRGN rgn, RGNDATA *data )
1567 {
1568     HRGN tmp = ExtCreateRegion( NULL, data->rdh.dwSize + data->rdh.nRgnSize, data );
1569     CombineRgn( rgn, rgn, tmp, RGN_OR );
1570     DeleteObject( tmp );
1571     data->rdh.nCount = 0;
1572 }
1573
1574 static inline void add_row( HRGN rgn, RGNDATA *data, int x, int y, int len )
1575 {
1576     RECT *rect = (RECT *)data->Buffer + data->rdh.nCount;
1577
1578     if (len <= 0) return;
1579     rect->left   = x;
1580     rect->top    = y;
1581     rect->right  = x + len;
1582     rect->bottom = y + 1;
1583     data->rdh.nCount++;
1584     if (data->rdh.nCount * sizeof(RECT) > data->rdh.nRgnSize - sizeof(RECT))
1585         flush_rgn_data( rgn, data );
1586 }
1587
1588 /***********************************************************************
1589  *           update_surface_region
1590  */
1591 static void update_surface_region( struct x11drv_window_surface *surface )
1592 {
1593 #ifdef HAVE_LIBXSHAPE
1594     char buffer[4096];
1595     RGNDATA *data = (RGNDATA *)buffer;
1596     BITMAPINFO *info = &surface->info;
1597     UINT *masks = (UINT *)info->bmiColors;
1598     int x, y, start, width;
1599     HRGN rgn;
1600
1601     if (surface->color_key == CLR_INVALID)
1602     {
1603         XShapeCombineMask( gdi_display, surface->window, ShapeBounding, 0, 0, None, ShapeSet );
1604         return;
1605     }
1606
1607     data->rdh.dwSize = sizeof(data->rdh);
1608     data->rdh.iType  = RDH_RECTANGLES;
1609     data->rdh.nCount = 0;
1610     data->rdh.nRgnSize = sizeof(buffer) - sizeof(data->rdh);
1611
1612     rgn = CreateRectRgn( 0, 0, 0, 0 );
1613     width = surface->header.rect.right - surface->header.rect.left;
1614
1615     switch (info->bmiHeader.biBitCount)
1616     {
1617     case 16:
1618     {
1619         WORD *bits = surface->bits.ptr;
1620         int stride = (width + 1) & ~1;
1621         UINT mask = masks[0] | masks[1] | masks[2];
1622
1623         for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += stride)
1624         {
1625             x = 0;
1626             while (x < width)
1627             {
1628                 while (x < width && (bits[x] & mask) == surface->color_key) x++;
1629                 start = x;
1630                 while (x < width && (bits[x] & mask) != surface->color_key) x++;
1631                 add_row( rgn, data, surface->header.rect.left + start, y, x - start );
1632             }
1633         }
1634         break;
1635     }
1636     case 24:
1637     {
1638         BYTE *bits = surface->bits.ptr;
1639         int stride = (width * 3 + 3) & ~3;
1640
1641         for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += stride)
1642         {
1643             x = 0;
1644             while (x < width)
1645             {
1646                 while (x < width &&
1647                        (bits[x * 3] == GetBValue(surface->color_key)) &&
1648                        (bits[x * 3 + 1] == GetGValue(surface->color_key)) &&
1649                        (bits[x * 3 + 2] == GetRValue(surface->color_key)))
1650                     x++;
1651                 start = x;
1652                 while (x < width &&
1653                        ((bits[x * 3] != GetBValue(surface->color_key)) ||
1654                         (bits[x * 3 + 1] != GetGValue(surface->color_key)) ||
1655                         (bits[x * 3 + 2] != GetRValue(surface->color_key))))
1656                     x++;
1657                 add_row( rgn, data, surface->header.rect.left + start, y, x - start );
1658             }
1659         }
1660         break;
1661     }
1662     case 32:
1663     {
1664         DWORD *bits = surface->bits.ptr;
1665         UINT mask = info->bmiHeader.biCompression == BI_RGB ? 0xffffff : (masks[0] | masks[1] | masks[2]);
1666
1667         for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += width)
1668         {
1669             x = 0;
1670             while (x < width)
1671             {
1672                 while (x < width && (bits[x] & mask) == surface->color_key) x++;
1673                 start = x;
1674                 while (x < width && (bits[x] & mask) != surface->color_key) x++;
1675                 add_row( rgn, data, surface->header.rect.left + start, y, x - start );
1676             }
1677         }
1678         break;
1679     }
1680     default:
1681         assert(0);
1682     }
1683
1684     if (data->rdh.nCount) flush_rgn_data( rgn, data );
1685
1686     if ((data = X11DRV_GetRegionData( rgn, 0 )))
1687     {
1688         XShapeCombineRectangles( gdi_display, surface->window, ShapeBounding, 0, 0,
1689                                  (XRectangle *)data->Buffer, data->rdh.nCount, ShapeSet, YXBanded );
1690         HeapFree( GetProcessHeap(), 0, data );
1691     }
1692
1693     DeleteObject( rgn );
1694 #endif
1695 }
1696
1697 /***********************************************************************
1698  *           set_color_key
1699  */
1700 static void set_color_key( struct x11drv_window_surface *surface, COLORREF key )
1701 {
1702     UINT *masks = (UINT *)surface->info.bmiColors;
1703
1704     if (key == CLR_INVALID)
1705         surface->color_key = CLR_INVALID;
1706     else if (surface->info.bmiHeader.biBitCount <= 8)
1707         surface->color_key = CLR_INVALID;
1708     else if (key & (1 << 24))  /* PALETTEINDEX */
1709         surface->color_key = 0;
1710     else if (key >> 16 == 0x10ff)  /* DIBINDEX */
1711         surface->color_key = 0;
1712     else if (surface->info.bmiHeader.biBitCount == 24)
1713         surface->color_key = key;
1714     else if (surface->info.bmiHeader.biCompression == BI_RGB)
1715         surface->color_key = (GetRValue(key) << 16) | (GetGValue(key) << 8) | GetBValue(key);
1716     else
1717         surface->color_key = get_color_component( GetRValue(key), masks[0] ) |
1718                              get_color_component( GetGValue(key), masks[1] ) |
1719                              get_color_component( GetBValue(key), masks[2] );
1720 }
1721
1722 /***********************************************************************
1723  *           x11drv_surface_lock
1724  */
1725 static void x11drv_surface_lock( struct window_surface *window_surface )
1726 {
1727     struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1728
1729     EnterCriticalSection( &surface->crit );
1730 }
1731
1732 /***********************************************************************
1733  *           x11drv_surface_unlock
1734  */
1735 static void x11drv_surface_unlock( struct window_surface *window_surface )
1736 {
1737     struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1738
1739     LeaveCriticalSection( &surface->crit );
1740 }
1741
1742 /***********************************************************************
1743  *           x11drv_surface_get_bitmap_info
1744  */
1745 static void *x11drv_surface_get_bitmap_info( struct window_surface *window_surface, BITMAPINFO *info )
1746 {
1747     struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1748
1749     memcpy( info, &surface->info, get_dib_info_size( &surface->info, DIB_RGB_COLORS ));
1750     return surface->bits.ptr;
1751 }
1752
1753 /***********************************************************************
1754  *           x11drv_surface_get_bounds
1755  */
1756 static RECT *x11drv_surface_get_bounds( struct window_surface *window_surface )
1757 {
1758     struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1759
1760     return &surface->bounds;
1761 }
1762
1763 /***********************************************************************
1764  *           x11drv_surface_flush
1765  */
1766 static void x11drv_surface_flush( struct window_surface *window_surface )
1767 {
1768     struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1769     struct bitblt_coords coords;
1770     struct gdi_image_bits dst_bits;
1771     const int *mapping = NULL;
1772
1773     window_surface->funcs->lock( window_surface );
1774     coords.x = 0;
1775     coords.y = 0;
1776     coords.width  = surface->header.rect.right - surface->header.rect.left;
1777     coords.height = surface->header.rect.bottom - surface->header.rect.top;
1778     SetRect( &coords.visrect, 0, 0, coords.width, coords.height );
1779     if (IntersectRect( &coords.visrect, &coords.visrect, &surface->bounds ))
1780     {
1781         TRACE( "flushing %p %dx%d bounds %s bits %p\n",
1782                surface, coords.width, coords.height,
1783                wine_dbgstr_rect( &surface->bounds ), surface->bits.ptr );
1784
1785         if (surface->color_key != CLR_INVALID) update_surface_region( surface );
1786
1787         if (surface->image->bits_per_pixel == 4 || surface->image->bits_per_pixel == 8)
1788             mapping = X11DRV_PALETTE_PaletteToXPixel;
1789
1790         if (!copy_image_bits( &surface->info, surface->is_r8g8b8, surface->image,
1791                               &surface->bits, &dst_bits, &coords, mapping, ~0u ))
1792         {
1793             surface->image->data = dst_bits.ptr;
1794             XPutImage( gdi_display, surface->window, surface->gc, surface->image,
1795                        coords.visrect.left, 0,
1796                        surface->header.rect.left + coords.visrect.left,
1797                        surface->header.rect.top + coords.visrect.top,
1798                        coords.visrect.right - coords.visrect.left,
1799                        coords.visrect.bottom - coords.visrect.top );
1800             surface->image->data = NULL;
1801         }
1802
1803         if (dst_bits.free) dst_bits.free( &dst_bits );
1804     }
1805     reset_bounds( &surface->bounds );
1806     window_surface->funcs->unlock( window_surface );
1807 }
1808
1809 /***********************************************************************
1810  *           x11drv_surface_destroy
1811  */
1812 static void x11drv_surface_destroy( struct window_surface *window_surface )
1813 {
1814     struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1815
1816     TRACE( "freeing %p bits %p\n", surface, surface->bits.ptr );
1817     if (surface->gc) XFreeGC( gdi_display, surface->gc );
1818     if (surface->image) XDestroyImage( surface->image );
1819     if (surface->bits.free) surface->bits.free( &surface->bits );
1820     surface->crit.DebugInfo->Spare[0] = 0;
1821     DeleteCriticalSection( &surface->crit );
1822     HeapFree( GetProcessHeap(), 0, surface );
1823 }
1824
1825 static const struct window_surface_funcs x11drv_surface_funcs =
1826 {
1827     x11drv_surface_lock,
1828     x11drv_surface_unlock,
1829     x11drv_surface_get_bitmap_info,
1830     x11drv_surface_get_bounds,
1831     x11drv_surface_flush,
1832     x11drv_surface_destroy
1833 };
1834
1835 /***********************************************************************
1836  *           create_surface
1837  */
1838 struct window_surface *create_surface( Window window, const XVisualInfo *vis, const RECT *rect,
1839                                        COLORREF color_key )
1840 {
1841     const XPixmapFormatValues *format = pixmap_formats[vis->depth];
1842     struct x11drv_window_surface *surface;
1843     int width = rect->right - rect->left, height = rect->bottom - rect->top;
1844     int colors = format->bits_per_pixel <= 8 ? 1 << format->bits_per_pixel : 3;
1845
1846     surface = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1847                          FIELD_OFFSET( struct x11drv_window_surface, info.bmiColors[colors] ));
1848     if (!surface) return NULL;
1849     surface->info.bmiHeader.biSize        = sizeof(surface->info.bmiHeader);
1850     surface->info.bmiHeader.biWidth       = width;
1851     surface->info.bmiHeader.biHeight      = -height; /* top-down */
1852     surface->info.bmiHeader.biPlanes      = 1;
1853     surface->info.bmiHeader.biBitCount    = format->bits_per_pixel;
1854     surface->info.bmiHeader.biSizeImage   = get_dib_image_size( &surface->info );
1855     set_color_info( vis, &surface->info );
1856
1857     InitializeCriticalSection( &surface->crit );
1858     surface->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": surface");
1859
1860     surface->header.funcs = &x11drv_surface_funcs;
1861     surface->header.rect  = *rect;
1862     surface->header.ref   = 1;
1863     surface->window = window;
1864     surface->is_r8g8b8 = is_r8g8b8( vis );
1865     set_color_key( surface, color_key );
1866     reset_bounds( &surface->bounds );
1867     if (!(surface->bits.ptr  = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1868                                           surface->info.bmiHeader.biSizeImage )))
1869         goto failed;
1870
1871     surface->bits.free = free_heap_bits;
1872
1873     surface->image = XCreateImage( gdi_display, visual, vis->depth, ZPixmap, 0, NULL,
1874                                    width, height, 32, 0 );
1875     if (!surface->image) goto failed;
1876     surface->gc = XCreateGC( gdi_display, window, 0, NULL );
1877
1878     TRACE( "created %p for %lx %s bits %p-%p\n", surface, window, wine_dbgstr_rect(rect),
1879            surface->bits.ptr, (char *)surface->bits.ptr + surface->info.bmiHeader.biSizeImage );
1880
1881     return &surface->header;
1882
1883 failed:
1884     x11drv_surface_destroy( &surface->header );
1885     return NULL;
1886 }
1887
1888 /***********************************************************************
1889  *           set_surface_color_key
1890  */
1891 void set_surface_color_key( struct window_surface *window_surface, COLORREF color_key )
1892 {
1893     struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1894     COLORREF prev;
1895
1896     window_surface->funcs->lock( window_surface );
1897     prev = surface->color_key;
1898     set_color_key( surface, color_key );
1899     if (surface->color_key != prev) update_surface_region( surface );
1900     window_surface->funcs->unlock( window_surface );
1901 }