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