winex11: Don't access the source rectangle in PutImage until needed.
[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,TMP,GXnand),
83       OP(TMP,DST,GXand), OP(SRC,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,TMP,GXnand),
91       OP(TMP,DST,GXand), OP(SRC,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,TMP,GXxor),
95       OP(TMP,DST,GXand), OP(SRC,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,TMP,GXand),
111       OP(TMP,DST,GXor), OP(SRC,DST,GXxor) },         /* 0x26  S^(D|(S&P))    */
112     { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXequiv),
113       OP(TMP,DST,GXor), OP(SRC,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,TMP,GXand),
116       OP(TMP,DST,GXor), OP(SRC,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 BYTE *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,TMP):
559                     tmp = do_bitop( pat, tmp, *opcode & 0xf );
560                     break;
561                 case OP_ARGS(PAT,DST):
562                     dst = do_bitop( pat, dst, *opcode & 0xf );
563                     dstUsed = 1;
564                     break;
565                 case OP_ARGS(PAT,SRC):
566                     src = do_bitop( pat, src, *opcode & 0xf );
567                     break;
568                 case OP_ARGS(TMP,DST):
569                     dst = do_bitop( tmp, dst, *opcode & 0xf );
570                     dstUsed = 1;
571                     break;
572                 case OP_ARGS(TMP,SRC):
573                     src = do_bitop( tmp, src, *opcode & 0xf );
574                     break;
575                 default:
576                     printf( "Invalid opcode %x\n", *opcode );
577                 }
578             }
579             if (!dstUsed) dst = src;
580             if (dst) res |= 1 << i;
581         }
582         if (res != rop) printf( "%02x: ERROR, res=%02x\n", rop, res );
583     }
584
585     return 0;
586 }
587
588 #endif  /* BITBLT_TEST */
589
590
591 static void get_colors(X11DRV_PDEVICE *physDevDst, X11DRV_PDEVICE *physDevSrc,
592                        int *fg, int *bg)
593 {
594     RGBQUAD rgb[2];
595
596     *fg = physDevDst->textPixel;
597     *bg = physDevDst->backgroundPixel;
598     if(physDevSrc->depth == 1) {
599         if(GetDIBColorTable(physDevSrc->dev.hdc, 0, 2, rgb) == 2) {
600             DWORD logcolor;
601             logcolor = RGB(rgb[0].rgbRed, rgb[0].rgbGreen, rgb[0].rgbBlue);
602             *fg = X11DRV_PALETTE_ToPhysical( physDevDst, logcolor );
603             logcolor = RGB(rgb[1].rgbRed, rgb[1].rgbGreen,rgb[1].rgbBlue);
604             *bg = X11DRV_PALETTE_ToPhysical( physDevDst, logcolor );
605         }
606     }
607 }
608
609 /* return a mask for meaningful bits when doing an XGetPixel on an image */
610 static unsigned long image_pixel_mask( X11DRV_PDEVICE *physDev )
611 {
612     unsigned long ret;
613     ColorShifts *shifts = physDev->color_shifts;
614
615     if (!shifts) shifts = &X11DRV_PALETTE_default_shifts;
616     ret = (shifts->physicalRed.max << shifts->physicalRed.shift) |
617         (shifts->physicalGreen.max << shifts->physicalGreen.shift) |
618         (shifts->physicalBlue.max << shifts->physicalBlue.shift);
619     if (!ret) ret = (1 << physDev->depth) - 1;
620     return ret;
621 }
622
623
624 /***********************************************************************
625  *           BITBLT_StretchRow
626  *
627  * Stretch a row of pixels. Helper function for BITBLT_StretchImage.
628  */
629 static void BITBLT_StretchRow( int *rowSrc, int *rowDst,
630                                INT startDst, INT widthDst,
631                                INT xinc, INT xoff, WORD mode )
632 {
633     register INT xsrc = xinc * startDst + xoff;
634     rowDst += startDst;
635     switch(mode)
636     {
637     case STRETCH_ANDSCANS:
638         for(; widthDst > 0; widthDst--, xsrc += xinc)
639             *rowDst++ &= rowSrc[xsrc >> 16];
640         break;
641     case STRETCH_ORSCANS:
642         for(; widthDst > 0; widthDst--, xsrc += xinc)
643             *rowDst++ |= rowSrc[xsrc >> 16];
644         break;
645     case STRETCH_DELETESCANS:
646         for(; widthDst > 0; widthDst--, xsrc += xinc)
647             *rowDst++ = rowSrc[xsrc >> 16];
648         break;
649     }
650 }
651
652
653 /***********************************************************************
654  *           BITBLT_ShrinkRow
655  *
656  * Shrink a row of pixels. Helper function for BITBLT_StretchImage.
657  */
658 static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst,
659                               INT startSrc, INT widthSrc,
660                               INT xinc, INT xoff, WORD mode )
661 {
662     register INT xdst = xinc * startSrc + xoff;
663     rowSrc += startSrc;
664     switch(mode)
665     {
666     case STRETCH_ORSCANS:
667         for(; widthSrc > 0; widthSrc--, xdst += xinc)
668             rowDst[xdst >> 16] |= *rowSrc++;
669         break;
670     case STRETCH_ANDSCANS:
671         for(; widthSrc > 0; widthSrc--, xdst += xinc)
672             rowDst[xdst >> 16] &= *rowSrc++;
673         break;
674     case STRETCH_DELETESCANS:
675         for(; widthSrc > 0; widthSrc--, xdst += xinc)
676             rowDst[xdst >> 16] = *rowSrc++;
677         break;
678     }
679 }
680
681
682 /***********************************************************************
683  *           BITBLT_GetRow
684  *
685  * Retrieve a row from an image. Helper function for BITBLT_StretchImage.
686  */
687 static void BITBLT_GetRow( XImage *image, int *pdata, INT row,
688                            INT start, INT width, INT depthDst,
689                            int fg, int bg, unsigned long pixel_mask, BOOL swap)
690 {
691     register INT i;
692
693     assert( (row >= 0) && (row < image->height) );
694     assert( (start >= 0) && (width <= image->width) );
695
696     pdata += swap ? start+width-1 : start;
697     if (image->depth == depthDst)  /* color -> color */
698     {
699         if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1))
700             if (swap) for (i = 0; i < width; i++)
701                 *pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
702             else for (i = 0; i < width; i++)
703                 *pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
704         else
705             if (swap) for (i = 0; i < width; i++)
706                 *pdata-- = XGetPixel( image, i, row );
707             else for (i = 0; i < width; i++)
708                 *pdata++ = XGetPixel( image, i, row );
709     }
710     else
711     {
712         if (image->depth == 1)  /* monochrome -> color */
713         {
714             if (X11DRV_PALETTE_XPixelToPalette)
715             {
716                 fg = X11DRV_PALETTE_XPixelToPalette[fg];
717                 bg = X11DRV_PALETTE_XPixelToPalette[bg];
718             }
719             if (swap) for (i = 0; i < width; i++)
720                 *pdata-- = XGetPixel( image, i, row ) ? bg : fg;
721             else for (i = 0; i < width; i++)
722                 *pdata++ = XGetPixel( image, i, row ) ? bg : fg;
723         }
724         else  /* color -> monochrome */
725         {
726             if (swap) for (i = 0; i < width; i++)
727                 *pdata-- = ((XGetPixel( image, i, row ) & pixel_mask) == bg) ? 1 : 0;
728             else for (i = 0; i < width; i++)
729                 *pdata++ = ((XGetPixel( image, i, row ) & pixel_mask) == bg) ? 1 : 0;
730         }
731     }
732 }
733
734
735 /***********************************************************************
736  *           BITBLT_StretchImage
737  *
738  * Stretch an X image.
739  * FIXME: does not work for full 32-bit coordinates.
740  */
741 static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage,
742                                  INT widthSrc, INT heightSrc,
743                                  INT widthDst, INT heightDst,
744                                  RECT *visRectSrc, RECT *visRectDst,
745                                  int foreground, int background,
746                                  unsigned long pixel_mask, WORD mode )
747 {
748     int *rowSrc, *rowDst, *pixel;
749     char *pdata;
750     INT xinc, xoff, yinc, ysrc, ydst;
751     register INT x, y;
752     BOOL hstretch, vstretch, hswap, vswap;
753
754     hswap = widthSrc * widthDst < 0;
755     vswap = heightSrc * heightDst < 0;
756     widthSrc  = abs(widthSrc);
757     heightSrc = abs(heightSrc);
758     widthDst  = abs(widthDst);
759     heightDst = abs(heightDst);
760
761     if (!(rowSrc = HeapAlloc( GetProcessHeap(), 0,
762                               (widthSrc+widthDst)*sizeof(int) ))) return;
763     rowDst = rowSrc + widthSrc;
764
765       /* When stretching, all modes are the same, and DELETESCANS is faster */
766     if ((widthSrc < widthDst) && (heightSrc < heightDst))
767         mode = STRETCH_DELETESCANS;
768
769     if (mode == STRETCH_HALFTONE) /* FIXME */
770         mode = STRETCH_DELETESCANS;
771
772     if (mode != STRETCH_DELETESCANS)
773         memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
774                 widthDst*sizeof(int) );
775
776     hstretch = (widthSrc < widthDst);
777     vstretch = (heightSrc < heightDst);
778
779     if (hstretch)
780     {
781         xinc = (widthSrc << 16) / widthDst;
782         xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
783     }
784     else
785     {
786         xinc = ((int)widthDst << 16) / widthSrc;
787         xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
788     }
789
790     wine_tsx11_lock();
791     if (vstretch)
792     {
793         yinc = (heightSrc << 16) / heightDst;
794         ydst = visRectDst->top;
795         if (vswap)
796         {
797             ysrc = yinc * (heightDst - ydst - 1);
798             yinc = -yinc;
799         }
800         else
801             ysrc = yinc * ydst;
802
803         for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
804         {
805             if (((ysrc >> 16) < visRectSrc->top) ||
806                 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
807
808             /* Retrieve a source row */
809             BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
810                            hswap ? widthSrc - visRectSrc->right
811                                  : visRectSrc->left,
812                            visRectSrc->right - visRectSrc->left,
813                            dstImage->depth, foreground, background, pixel_mask, hswap );
814
815             /* Stretch or shrink it */
816             if (hstretch)
817                 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
818                                    visRectDst->right - visRectDst->left,
819                                    xinc, xoff, mode );
820             else BITBLT_ShrinkRow( rowSrc, rowDst,
821                                    hswap ? widthSrc - visRectSrc->right
822                                          : visRectSrc->left,
823                                    visRectSrc->right - visRectSrc->left,
824                                    xinc, xoff, mode );
825
826             /* Store the destination row */
827             pixel = rowDst + visRectDst->right - 1;
828             y = ydst - visRectDst->top;
829             for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
830                 XPutPixel( dstImage, x, y, *pixel-- );
831             if (mode != STRETCH_DELETESCANS)
832                 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
833                         widthDst*sizeof(int) );
834
835             /* Make copies of the destination row */
836
837             pdata = dstImage->data + dstImage->bytes_per_line * y;
838             while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
839                    (ydst < visRectDst->bottom-1))
840             {
841                 memcpy( pdata + dstImage->bytes_per_line, pdata,
842                         dstImage->bytes_per_line );
843                 pdata += dstImage->bytes_per_line;
844                 ysrc += yinc;
845                 ydst++;
846             }
847         }
848     }
849     else  /* Shrinking */
850     {
851         yinc = (heightDst << 16) / heightSrc;
852         ysrc = visRectSrc->top;
853         ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
854         if (vswap)
855         {
856             ydst += yinc * (heightSrc - ysrc - 1);
857             yinc = -yinc;
858         }
859         else
860             ydst += yinc * ysrc;
861
862         for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
863         {
864             if (((ydst >> 16) < visRectDst->top) ||
865                 ((ydst >> 16) >= visRectDst->bottom)) continue;
866
867             /* Retrieve a source row */
868             BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
869                            hswap ? widthSrc - visRectSrc->right
870                                  : visRectSrc->left,
871                            visRectSrc->right - visRectSrc->left,
872                            dstImage->depth, foreground, background, pixel_mask, hswap );
873
874             /* Stretch or shrink it */
875             if (hstretch)
876                 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
877                                    visRectDst->right - visRectDst->left,
878                                    xinc, xoff, mode );
879             else BITBLT_ShrinkRow( rowSrc, rowDst,
880                                    hswap ? widthSrc - visRectSrc->right
881                                          : visRectSrc->left,
882                                    visRectSrc->right - visRectSrc->left,
883                                    xinc, xoff, mode );
884
885             /* Merge several source rows into the destination */
886             if (mode == STRETCH_DELETESCANS)
887             {
888                 /* Simply skip the overlapping rows */
889                 while (((ydst + yinc) >> 16 == ydst >> 16) &&
890                        (ysrc < visRectSrc->bottom-1))
891                 {
892                     ydst += yinc;
893                     ysrc++;
894                 }
895             }
896             else if (((ydst + yinc) >> 16 == ydst >> 16) &&
897                      (ysrc < visRectSrc->bottom-1))
898                 continue;  /* Restart loop for next overlapping row */
899
900             /* Store the destination row */
901             pixel = rowDst + visRectDst->right - 1;
902             y = (ydst >> 16) - visRectDst->top;
903             for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
904                 XPutPixel( dstImage, x, y, *pixel-- );
905             if (mode != STRETCH_DELETESCANS)
906                 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
907                         widthDst*sizeof(int) );
908         }
909     }
910     wine_tsx11_unlock();
911     HeapFree( GetProcessHeap(), 0, rowSrc );
912 }
913
914
915 /***********************************************************************
916  *           BITBLT_GetSrcAreaStretch
917  *
918  * Retrieve an area from the source DC, stretching and mapping all the
919  * pixels to Windows colors.
920  */
921 static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
922                                      Pixmap pixmap, GC gc,
923                                      const struct bitblt_coords *src, const struct bitblt_coords *dst )
924 {
925     XImage *imageSrc, *imageDst;
926     RECT rectSrc = src->visrect;
927     RECT rectDst = dst->visrect;
928     int fg, bg;
929
930     rectSrc.left   -= src->x;
931     rectSrc.right  -= src->x;
932     rectSrc.top    -= src->y;
933     rectSrc.bottom -= src->y;
934     rectDst.left   -= dst->x;
935     rectDst.right  -= dst->x;
936     rectDst.top    -= dst->y;
937     rectDst.bottom -= dst->y;
938     if (src->width < 0)
939     {
940         rectSrc.left  -= src->width;
941         rectSrc.right -= src->width;
942     }
943     if (dst->width < 0)
944     {
945         rectDst.left  -= dst->width;
946         rectDst.right -= dst->width;
947     }
948     if (src->height < 0)
949     {
950         rectSrc.top    -= src->height;
951         rectSrc.bottom -= src->height;
952     }
953     if (dst->height < 0)
954     {
955         rectDst.top    -= dst->height;
956         rectDst.bottom -= dst->height;
957     }
958
959     get_colors(physDevDst, physDevSrc, &fg, &bg);
960     wine_tsx11_lock();
961     /* FIXME: avoid BadMatch errors */
962     imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
963                           physDevSrc->dc_rect.left + src->visrect.left,
964                           physDevSrc->dc_rect.top + src->visrect.top,
965                           src->visrect.right - src->visrect.left,
966                           src->visrect.bottom - src->visrect.top,
967                           AllPlanes, ZPixmap );
968     wine_tsx11_unlock();
969
970     imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
971                                         rectDst.bottom - rectDst.top, physDevDst->depth );
972     BITBLT_StretchImage( imageSrc, imageDst, src->width, src->height,
973                          dst->width, dst->height, &rectSrc, &rectDst,
974                          fg, physDevDst->depth != 1 ? bg : physDevSrc->backgroundPixel,
975                          image_pixel_mask( physDevSrc ), GetStretchBltMode(physDevDst->dev.hdc) );
976     wine_tsx11_lock();
977     XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
978                rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
979     XDestroyImage( imageSrc );
980     X11DRV_DIB_DestroyXImage( imageDst );
981     wine_tsx11_unlock();
982     return 0;  /* no exposure events generated */
983 }
984
985
986 /***********************************************************************
987  *           BITBLT_GetSrcArea
988  *
989  * Retrieve an area from the source DC, mapping all the
990  * pixels to Windows colors.
991  */
992 static int BITBLT_GetSrcArea( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
993                               Pixmap pixmap, GC gc, RECT *visRectSrc )
994 {
995     XImage *imageSrc, *imageDst;
996     register INT x, y;
997     int exposures = 0;
998     INT width  = visRectSrc->right - visRectSrc->left;
999     INT height = visRectSrc->bottom - visRectSrc->top;
1000     int fg, bg;
1001     BOOL memdc = (GetObjectType(physDevSrc->dev.hdc) == OBJ_MEMDC);
1002
1003     if (physDevSrc->depth == physDevDst->depth)
1004     {
1005         wine_tsx11_lock();
1006         if (!X11DRV_PALETTE_XPixelToPalette ||
1007             (physDevDst->depth == 1))  /* monochrome -> monochrome */
1008         {
1009             if (physDevDst->depth == 1)
1010             {
1011                 /* MSDN says if StretchBlt must convert a bitmap from monochrome
1012                    to color or vice versa, the foreground and background color of
1013                    the device context are used.  In fact, it also applies to the
1014                    case when it is converted from mono to mono. */
1015                 XSetBackground( gdi_display, gc, physDevDst->textPixel );
1016                 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
1017                 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
1018                             physDevSrc->dc_rect.left + visRectSrc->left,
1019                             physDevSrc->dc_rect.top + visRectSrc->top,
1020                             width, height, 0, 0, 1);
1021             }
1022             else
1023                 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
1024                            physDevSrc->dc_rect.left + visRectSrc->left,
1025                            physDevSrc->dc_rect.top + visRectSrc->top,
1026                            width, height, 0, 0);
1027             exposures++;
1028         }
1029         else  /* color -> color */
1030         {
1031             if (memdc)
1032                 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
1033                                       physDevSrc->dc_rect.left + visRectSrc->left,
1034                                       physDevSrc->dc_rect.top + visRectSrc->top,
1035                                       width, height, AllPlanes, ZPixmap );
1036             else
1037             {
1038                 /* Make sure we don't get a BadMatch error */
1039                 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
1040                            physDevSrc->dc_rect.left + visRectSrc->left,
1041                            physDevSrc->dc_rect.top + visRectSrc->top,
1042                            width, height, 0, 0);
1043                 exposures++;
1044                 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1045                                       AllPlanes, ZPixmap );
1046             }
1047             for (y = 0; y < height; y++)
1048                 for (x = 0; x < width; x++)
1049                     XPutPixel(imageSrc, x, y,
1050                               X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
1051             XPutImage( gdi_display, pixmap, gc, imageSrc,
1052                        0, 0, 0, 0, width, height );
1053             XDestroyImage( imageSrc );
1054         }
1055         wine_tsx11_unlock();
1056     }
1057     else
1058     {
1059         if (physDevSrc->depth == 1)  /* monochrome -> color */
1060         {
1061             get_colors(physDevDst, physDevSrc, &fg, &bg);
1062
1063             wine_tsx11_lock();
1064             if (X11DRV_PALETTE_XPixelToPalette)
1065             {
1066                 XSetBackground( gdi_display, gc,
1067                              X11DRV_PALETTE_XPixelToPalette[fg] );
1068                 XSetForeground( gdi_display, gc,
1069                              X11DRV_PALETTE_XPixelToPalette[bg]);
1070             }
1071             else
1072             {
1073                 XSetBackground( gdi_display, gc, fg );
1074                 XSetForeground( gdi_display, gc, bg );
1075             }
1076             XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
1077                         physDevSrc->dc_rect.left + visRectSrc->left,
1078                         physDevSrc->dc_rect.top + visRectSrc->top,
1079                         width, height, 0, 0, 1 );
1080             exposures++;
1081             wine_tsx11_unlock();
1082         }
1083         else  /* color -> monochrome */
1084         {
1085             unsigned long pixel_mask;
1086             wine_tsx11_lock();
1087             /* FIXME: avoid BadMatch error */
1088             imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
1089                                   physDevSrc->dc_rect.left + visRectSrc->left,
1090                                   physDevSrc->dc_rect.top + visRectSrc->top,
1091                                   width, height, AllPlanes, ZPixmap );
1092             if (!imageSrc)
1093             {
1094                 wine_tsx11_unlock();
1095                 return exposures;
1096             }
1097             imageDst = X11DRV_DIB_CreateXImage( width, height, physDevDst->depth );
1098             if (!imageDst)
1099             {
1100                 XDestroyImage(imageSrc);
1101                 wine_tsx11_unlock();
1102                 return exposures;
1103             }
1104             pixel_mask = image_pixel_mask( physDevSrc );
1105             for (y = 0; y < height; y++)
1106                 for (x = 0; x < width; x++)
1107                     XPutPixel(imageDst, x, y,
1108                               !((XGetPixel(imageSrc,x,y) ^ physDevSrc->backgroundPixel) & pixel_mask));
1109             XPutImage( gdi_display, pixmap, gc, imageDst,
1110                        0, 0, 0, 0, width, height );
1111             XDestroyImage( imageSrc );
1112             X11DRV_DIB_DestroyXImage( imageDst );
1113             wine_tsx11_unlock();
1114         }
1115     }
1116     return exposures;
1117 }
1118
1119
1120 /***********************************************************************
1121  *           BITBLT_GetDstArea
1122  *
1123  * Retrieve an area from the destination DC, mapping all the
1124  * pixels to Windows colors.
1125  */
1126 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, const RECT *visRectDst)
1127 {
1128     int exposures = 0;
1129     INT width  = visRectDst->right - visRectDst->left;
1130     INT height = visRectDst->bottom - visRectDst->top;
1131     BOOL memdc = (GetObjectType( physDev->dev.hdc ) == OBJ_MEMDC);
1132
1133     wine_tsx11_lock();
1134
1135     if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) ||
1136         (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1137     {
1138         XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1139                    physDev->dc_rect.left + visRectDst->left, physDev->dc_rect.top + visRectDst->top,
1140                    width, height, 0, 0 );
1141         exposures++;
1142     }
1143     else
1144     {
1145         register INT x, y;
1146         XImage *image;
1147
1148         if (memdc)
1149             image = XGetImage( gdi_display, physDev->drawable,
1150                                physDev->dc_rect.left + visRectDst->left,
1151                                physDev->dc_rect.top + visRectDst->top,
1152                                width, height, AllPlanes, ZPixmap );
1153         else
1154         {
1155             /* Make sure we don't get a BadMatch error */
1156             XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1157                        physDev->dc_rect.left + visRectDst->left,
1158                        physDev->dc_rect.top + visRectDst->top,
1159                        width, height, 0, 0);
1160             exposures++;
1161             image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1162                                AllPlanes, ZPixmap );
1163         }
1164         if (image)
1165         {
1166             for (y = 0; y < height; y++)
1167                 for (x = 0; x < width; x++)
1168                     XPutPixel( image, x, y,
1169                                X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1170             XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1171             XDestroyImage( image );
1172         }
1173     }
1174
1175     wine_tsx11_unlock();
1176     return exposures;
1177 }
1178
1179
1180 /***********************************************************************
1181  *           BITBLT_PutDstArea
1182  *
1183  * Put an area back into the destination DC, mapping the pixel
1184  * colors to X pixels.
1185  */
1186 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, const RECT *visRectDst)
1187 {
1188     int exposures = 0;
1189     INT width  = visRectDst->right - visRectDst->left;
1190     INT height = visRectDst->bottom - visRectDst->top;
1191
1192     /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1193
1194     if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) ||
1195         (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1196     {
1197         XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1198                    physDev->dc_rect.left + visRectDst->left,
1199                    physDev->dc_rect.top + visRectDst->top );
1200         exposures++;
1201     }
1202     else
1203     {
1204         register INT x, y;
1205         XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1206                                    AllPlanes, ZPixmap );
1207         for (y = 0; y < height; y++)
1208             for (x = 0; x < width; x++)
1209             {
1210                 XPutPixel( image, x, y,
1211                            X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1212             }
1213         XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1214                    physDev->dc_rect.left + visRectDst->left,
1215                    physDev->dc_rect.top + visRectDst->top, width, height );
1216         XDestroyImage( image );
1217     }
1218     return exposures;
1219 }
1220
1221
1222 /***********************************************************************
1223  *           client_side_dib_copy
1224  */
1225 static BOOL client_side_dib_copy( X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1226                                   X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1227                                   INT width, INT height )
1228 {
1229     DIBSECTION srcDib, dstDib;
1230     BYTE *srcPtr, *dstPtr;
1231     INT srcRowOffset, dstRowOffset;
1232     INT bytesPerPixel;
1233     INT bytesToCopy;
1234     INT y;
1235     static RECT unusedRect;
1236
1237     if (GetObjectW(physDevSrc->bitmap->hbitmap, sizeof(srcDib), &srcDib) != sizeof(srcDib))
1238       return FALSE;
1239     if (GetObjectW(physDevDst->bitmap->hbitmap, sizeof(dstDib), &dstDib) != sizeof(dstDib))
1240       return FALSE;
1241
1242     /* check for oversized values, just like X11DRV_DIB_CopyDIBSection() */
1243     if (xSrc > srcDib.dsBm.bmWidth || ySrc > srcDib.dsBm.bmHeight)
1244       return FALSE;
1245     if (xSrc + width > srcDib.dsBm.bmWidth)
1246       width = srcDib.dsBm.bmWidth - xSrc;
1247     if (ySrc + height > srcDib.dsBm.bmHeight)
1248       height = srcDib.dsBm.bmHeight - ySrc;
1249
1250     if (GetRgnBox(physDevDst->region, &unusedRect) == COMPLEXREGION)
1251     {
1252       /* for simple regions, the clipping was already done by BITBLT_GetVisRectangles */
1253       FIXME("potential optimization: client-side complex region clipping\n");
1254       return FALSE;
1255     }
1256     if (dstDib.dsBm.bmBitsPixel <= 8)
1257     {
1258       static BOOL fixme_once;
1259       if(!fixme_once++) FIXME("potential optimization: client-side color-index mode DIB copy\n");
1260       return FALSE;
1261     }
1262     if (!(srcDib.dsBmih.biCompression == BI_BITFIELDS &&
1263           dstDib.dsBmih.biCompression == BI_BITFIELDS &&
1264           !memcmp(srcDib.dsBitfields, dstDib.dsBitfields, 3*sizeof(DWORD)))
1265         && !(srcDib.dsBmih.biCompression == BI_RGB &&
1266              dstDib.dsBmih.biCompression == BI_RGB))
1267     {
1268       FIXME("potential optimization: client-side compressed DIB copy\n");
1269       return FALSE;
1270     }
1271     if (srcDib.dsBm.bmBitsPixel != dstDib.dsBm.bmBitsPixel)
1272     {
1273       FIXME("potential optimization: pixel format conversion\n");
1274       return FALSE;
1275     }
1276     if (srcDib.dsBmih.biWidth < 0 || dstDib.dsBmih.biWidth < 0)
1277     {
1278       FIXME("negative widths not yet implemented\n");
1279       return FALSE;
1280     }
1281
1282     switch (dstDib.dsBm.bmBitsPixel)
1283     {
1284       case 15:
1285       case 16:
1286         bytesPerPixel = 2;
1287         break;
1288       case 24:
1289         bytesPerPixel = 3;
1290         break;
1291       case 32:
1292         bytesPerPixel = 4;
1293         break;
1294       default:
1295         FIXME("don't know how to work with a depth of %d\n", physDevSrc->depth);
1296         return FALSE;
1297     }
1298
1299     bytesToCopy = width * bytesPerPixel;
1300
1301     if (physDevSrc->bitmap->topdown)
1302     {
1303       srcPtr = &physDevSrc->bitmap->base[ySrc*srcDib.dsBm.bmWidthBytes + xSrc*bytesPerPixel];
1304       srcRowOffset = srcDib.dsBm.bmWidthBytes;
1305     }
1306     else
1307     {
1308       srcPtr = &physDevSrc->bitmap->base[(srcDib.dsBm.bmHeight-ySrc-1)*srcDib.dsBm.bmWidthBytes
1309         + xSrc*bytesPerPixel];
1310       srcRowOffset = -srcDib.dsBm.bmWidthBytes;
1311     }
1312     if (physDevDst->bitmap->topdown)
1313     {
1314       dstPtr = &physDevDst->bitmap->base[yDst*dstDib.dsBm.bmWidthBytes + xDst*bytesPerPixel];
1315       dstRowOffset = dstDib.dsBm.bmWidthBytes;
1316     }
1317     else
1318     {
1319       dstPtr = &physDevDst->bitmap->base[(dstDib.dsBm.bmHeight-yDst-1)*dstDib.dsBm.bmWidthBytes
1320         + xDst*bytesPerPixel];
1321       dstRowOffset = -dstDib.dsBm.bmWidthBytes;
1322     }
1323
1324     /* Handle overlapping regions on the same DIB */
1325     if (physDevSrc == physDevDst && ySrc < yDst)
1326     {
1327       srcPtr += srcRowOffset * (height - 1);
1328       srcRowOffset = -srcRowOffset;
1329       dstPtr += dstRowOffset * (height - 1);
1330       dstRowOffset = -dstRowOffset;
1331     }
1332
1333     for (y = yDst; y < yDst + height; ++y)
1334     {
1335       memmove(dstPtr, srcPtr, bytesToCopy);
1336       srcPtr += srcRowOffset;
1337       dstPtr += dstRowOffset;
1338     }
1339
1340     return TRUE;
1341 }
1342
1343 static BOOL same_format(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst)
1344 {
1345     if (physDevSrc->depth != physDevDst->depth) return FALSE;
1346     if (!physDevSrc->color_shifts && !physDevDst->color_shifts) return TRUE;
1347     if (physDevSrc->color_shifts && physDevDst->color_shifts)
1348         return !memcmp(physDevSrc->color_shifts, physDevDst->color_shifts, sizeof(ColorShifts));
1349     return FALSE;
1350 }
1351
1352 static void execute_rop( X11DRV_PDEVICE *physdev, Pixmap src_pixmap, GC gc,
1353                          const RECT *visrect, DWORD rop )
1354 {
1355     Pixmap pixmaps[3];
1356     Pixmap result = src_pixmap;
1357     BOOL null_brush;
1358     const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1359     BOOL use_pat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1360     BOOL use_dst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1361     int width  = visrect->right - visrect->left;
1362     int height = visrect->bottom - visrect->top;
1363
1364     pixmaps[SRC] = src_pixmap;
1365     pixmaps[TMP] = 0;
1366     wine_tsx11_lock();
1367     pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height, physdev->depth );
1368     wine_tsx11_unlock();
1369
1370     if (use_dst) BITBLT_GetDstArea( physdev, pixmaps[DST], gc, visrect );
1371     null_brush = use_pat && !X11DRV_SetupGCForPatBlt( physdev, gc, TRUE );
1372
1373     wine_tsx11_lock();
1374     for ( ; *opcode; opcode++)
1375     {
1376         if (OP_DST(*opcode) == DST) result = pixmaps[DST];
1377         XSetFunction( gdi_display, gc, OP_ROP(*opcode) );
1378         switch(OP_SRCDST(*opcode))
1379         {
1380         case OP_ARGS(DST,TMP):
1381         case OP_ARGS(SRC,TMP):
1382             if (!pixmaps[TMP])
1383                 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window, width, height, physdev->depth );
1384             /* fall through */
1385         case OP_ARGS(DST,SRC):
1386         case OP_ARGS(SRC,DST):
1387         case OP_ARGS(TMP,SRC):
1388         case OP_ARGS(TMP,DST):
1389             XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)], pixmaps[OP_DST(*opcode)], gc,
1390                        0, 0, width, height, 0, 0 );
1391             break;
1392
1393         case OP_ARGS(PAT,TMP):
1394             if (!pixmaps[TMP] && !null_brush)
1395                 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window, width, height, physdev->depth );
1396             /* fall through */
1397         case OP_ARGS(PAT,DST):
1398         case OP_ARGS(PAT,SRC):
1399             if (!null_brush)
1400                 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)], gc, 0, 0, width, height );
1401             break;
1402         }
1403     }
1404     XSetFunction( gdi_display, physdev->gc, GXcopy );
1405     physdev->exposures += BITBLT_PutDstArea( physdev, result, visrect );
1406     XFreePixmap( gdi_display, pixmaps[DST] );
1407     if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1408     wine_tsx11_unlock();
1409 }
1410
1411 /***********************************************************************
1412  *           X11DRV_PatBlt
1413  */
1414 BOOL X11DRV_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
1415 {
1416     X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
1417     BOOL usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1418     const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1419
1420     if (IsRectEmpty( &dst->visrect )) return TRUE;
1421     if (usePat && !X11DRV_SetupGCForBrush( physDev )) return TRUE;
1422
1423     X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1424
1425     wine_tsx11_lock();
1426     XSetFunction( gdi_display, physDev->gc, OP_ROP(*opcode) );
1427
1428     switch(rop)  /* a few special cases */
1429     {
1430     case BLACKNESS:  /* 0x00 */
1431     case WHITENESS:  /* 0xff */
1432         if ((physDev->depth != 1) && X11DRV_PALETTE_PaletteToXPixel)
1433         {
1434             XSetFunction( gdi_display, physDev->gc, GXcopy );
1435             if (rop == BLACKNESS)
1436                 XSetForeground( gdi_display, physDev->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1437             else
1438                 XSetForeground( gdi_display, physDev->gc,
1439                                 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1440             XSetFillStyle( gdi_display, physDev->gc, FillSolid );
1441         }
1442         break;
1443     case DSTINVERT:  /* 0x55 */
1444         if (!(X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL)))
1445         {
1446             /* Xor is much better when we do not have full colormap.   */
1447             /* Using white^black ensures that we invert at least black */
1448             /* and white. */
1449             unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1450                                      BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1451             XSetFunction( gdi_display, physDev->gc, GXxor );
1452             XSetForeground( gdi_display, physDev->gc, xor_pix);
1453             XSetFillStyle( gdi_display, physDev->gc, FillSolid );
1454         }
1455         break;
1456     }
1457     XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1458                     physDev->dc_rect.left + dst->visrect.left,
1459                     physDev->dc_rect.top + dst->visrect.top,
1460                     dst->visrect.right - dst->visrect.left,
1461                     dst->visrect.bottom - dst->visrect.top );
1462     wine_tsx11_unlock();
1463
1464     X11DRV_UnlockDIBSection( physDev, TRUE );
1465     return TRUE;
1466 }
1467
1468
1469 /***********************************************************************
1470  *           X11DRV_StretchBlt
1471  */
1472 BOOL X11DRV_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
1473                         PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
1474 {
1475     X11DRV_PDEVICE *physDevDst = get_x11drv_dev( dst_dev );
1476     X11DRV_PDEVICE *physDevSrc = get_x11drv_dev( src_dev ); /* FIXME: check that it's really an x11 dev */
1477     BOOL fStretch;
1478     INT width, height;
1479     INT sDst, sSrc = DIB_Status_None;
1480     const BYTE *opcode;
1481     Pixmap src_pixmap;
1482     GC tmpGC;
1483
1484     if (IsRectEmpty( &dst->visrect )) return TRUE;
1485
1486     fStretch = (src->width != dst->width) || (src->height != dst->height);
1487
1488     if (physDevDst != physDevSrc)
1489         sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None );
1490
1491     width  = dst->visrect.right - dst->visrect.left;
1492     height = dst->visrect.bottom - dst->visrect.top;
1493
1494     sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None );
1495     if (physDevDst == physDevSrc) sSrc = sDst;
1496
1497     /* try client-side DIB copy */
1498     if (!fStretch && rop == SRCCOPY &&
1499         sSrc == DIB_Status_AppMod && sDst == DIB_Status_AppMod &&
1500         same_format(physDevSrc, physDevDst))
1501     {
1502         if (client_side_dib_copy( physDevSrc, src->visrect.left, src->visrect.top,
1503                                   physDevDst, dst->visrect.left, dst->visrect.top, width, height ))
1504             goto done;
1505     }
1506
1507     X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod );
1508
1509     opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1510
1511     /* a few optimizations for single-op ROPs */
1512     if (!fStretch && !opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1513     {
1514         if (same_format(physDevSrc, physDevDst))
1515         {
1516             wine_tsx11_lock();
1517             XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1518             wine_tsx11_unlock();
1519
1520             if (physDevSrc != physDevDst)
1521             {
1522                 if (sSrc == DIB_Status_AppMod)
1523                 {
1524                     X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, src->visrect.left, src->visrect.top,
1525                                                dst->visrect.left, dst->visrect.top, width, height );
1526                     goto done;
1527                 }
1528                 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1529             }
1530             wine_tsx11_lock();
1531             XCopyArea( gdi_display, physDevSrc->drawable,
1532                        physDevDst->drawable, physDevDst->gc,
1533                        physDevSrc->dc_rect.left + src->visrect.left,
1534                        physDevSrc->dc_rect.top + src->visrect.top,
1535                        width, height,
1536                        physDevDst->dc_rect.left + dst->visrect.left,
1537                        physDevDst->dc_rect.top + dst->visrect.top );
1538             physDevDst->exposures++;
1539             wine_tsx11_unlock();
1540             goto done;
1541         }
1542         if (physDevSrc->depth == 1)
1543         {
1544             int fg, bg;
1545
1546             X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1547             get_colors(physDevDst, physDevSrc, &fg, &bg);
1548             wine_tsx11_lock();
1549             XSetBackground( gdi_display, physDevDst->gc, fg );
1550             XSetForeground( gdi_display, physDevDst->gc, bg );
1551             XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1552             XCopyPlane( gdi_display, physDevSrc->drawable,
1553                         physDevDst->drawable, physDevDst->gc,
1554                         physDevSrc->dc_rect.left + src->visrect.left,
1555                         physDevSrc->dc_rect.top + src->visrect.top,
1556                         width, height,
1557                         physDevDst->dc_rect.left + dst->visrect.left,
1558                         physDevDst->dc_rect.top + dst->visrect.top, 1 );
1559             physDevDst->exposures++;
1560             wine_tsx11_unlock();
1561             goto done;
1562         }
1563     }
1564
1565     wine_tsx11_lock();
1566     tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1567     XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1568     XSetGraphicsExposures( gdi_display, tmpGC, False );
1569     src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, physDevDst->depth );
1570     wine_tsx11_unlock();
1571
1572     if (physDevDst != physDevSrc) X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1573
1574     if(!X11DRV_XRender_GetSrcAreaStretch( physDevSrc, physDevDst, src_pixmap, tmpGC, src, dst ))
1575     {
1576         if (fStretch)
1577             BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, src_pixmap, tmpGC, src, dst );
1578         else
1579             BITBLT_GetSrcArea( physDevSrc, physDevDst, src_pixmap, tmpGC, &src->visrect );
1580     }
1581
1582     execute_rop( physDevDst, src_pixmap, tmpGC, &dst->visrect, rop );
1583
1584     wine_tsx11_lock();
1585     XFreePixmap( gdi_display, src_pixmap );
1586     XFreeGC( gdi_display, tmpGC );
1587     wine_tsx11_unlock();
1588
1589 done:
1590     if (physDevDst != physDevSrc) X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1591     X11DRV_UnlockDIBSection( physDevDst, TRUE );
1592     return TRUE;
1593 }
1594
1595
1596 /***********************************************************************
1597  *           X11DRV_AlphaBlend
1598  */
1599 BOOL X11DRV_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
1600                         PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
1601 {
1602     X11DRV_PDEVICE *physDevDst = get_x11drv_dev( dst_dev );
1603     X11DRV_PDEVICE *physDevSrc = get_x11drv_dev( src_dev ); /* FIXME: check that it's really an x11 dev */
1604
1605     if (src->x < 0 || src->y < 0 || src->width < 0 || src->height < 0 ||
1606         src->width > physDevSrc->drawable_rect.right - physDevSrc->drawable_rect.left - src->x ||
1607         src->height > physDevSrc->drawable_rect.bottom - physDevSrc->drawable_rect.top - src->y)
1608     {
1609         WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src->x, src->y, src->width, src->height );
1610         SetLastError( ERROR_INVALID_PARAMETER );
1611         return FALSE;
1612     }
1613     if (IsRectEmpty( &dst->visrect )) return TRUE;
1614
1615     return XRender_AlphaBlend( physDevDst, dst, physDevSrc, src, blendfn );
1616 }
1617
1618
1619 static void free_heap_bits( struct gdi_image_bits *bits )
1620 {
1621     HeapFree( GetProcessHeap(), 0, bits->ptr );
1622 }
1623
1624 static void free_ximage_bits( struct gdi_image_bits *bits )
1625 {
1626     wine_tsx11_lock();
1627     XFree( bits->ptr );
1628     wine_tsx11_unlock();
1629 }
1630
1631 /* store the palette or color mask data in the bitmap info structure */
1632 static void set_color_info( const ColorShifts *color_shifts, BITMAPINFO *info )
1633 {
1634     DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1635
1636     switch (info->bmiHeader.biBitCount)
1637     {
1638     case 1:
1639     case 4:
1640     case 8:
1641         info->bmiHeader.biCompression = BI_RGB;
1642         /* FIXME: set color palette */
1643         break;
1644     case 16:
1645     case 32:
1646         info->bmiHeader.biCompression = BI_BITFIELDS;
1647         colors[0] = color_shifts->logicalRed.max << color_shifts->logicalRed.shift;
1648         colors[1] = color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift;
1649         colors[2] = color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift;
1650         break;
1651     case 24:
1652         info->bmiHeader.biCompression = BI_RGB;
1653         break;
1654     }
1655 }
1656
1657 /* copy the image bits, fixing up alignment and byte swapping as necessary */
1658  DWORD copy_image_bits( BITMAPINFO *info, const ColorShifts *color_shifts, XImage *image,
1659                               const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits,
1660                               unsigned int zeropad_mask )
1661 {
1662 #ifdef WORDS_BIGENDIAN
1663     static const int client_byte_order = MSBFirst;
1664 #else
1665     static const int client_byte_order = LSBFirst;
1666 #endif
1667     BOOL need_byteswap;
1668     int x, y, height = abs(info->bmiHeader.biHeight);
1669     int width_bytes = image->bytes_per_line;
1670     int padding_pos;
1671     unsigned char *src, *dst;
1672
1673     switch (info->bmiHeader.biBitCount)
1674     {
1675     case 1:
1676         need_byteswap = (image->bitmap_bit_order != MSBFirst);
1677         break;
1678     case 4:
1679         need_byteswap = (image->byte_order != MSBFirst);
1680         break;
1681     case 16:
1682     case 32:
1683         need_byteswap = (image->byte_order != client_byte_order);
1684         break;
1685     case 24:
1686         need_byteswap = ((image->byte_order == LSBFirst && color_shifts->logicalBlue.shift == 16) ||
1687                          (image->byte_order == MSBFirst && color_shifts->logicalBlue.shift == 0));
1688         break;
1689     default:
1690         need_byteswap = FALSE;
1691         break;
1692     }
1693
1694     if ((need_byteswap && !src_bits->is_copy) ||  /* need to swap bytes */
1695         (zeropad_mask != ~0u && !src_bits->is_copy) ||  /* need to clear padding bytes */
1696         (width_bytes & 3) ||  /* need to fixup line alignment */
1697         (info->bmiHeader.biHeight > 0))  /* need to flip vertically */
1698     {
1699         width_bytes = (width_bytes + 3) & ~3;
1700         info->bmiHeader.biSizeImage = height * width_bytes;
1701         if (!(dst_bits->ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage )))
1702             return ERROR_OUTOFMEMORY;
1703         dst_bits->offset = src_bits->offset;
1704         dst_bits->is_copy = TRUE;
1705         dst_bits->free = free_heap_bits;
1706     }
1707     else
1708     {
1709         /* swap bits in place */
1710         dst_bits->ptr = src_bits->ptr;
1711         dst_bits->offset = src_bits->offset;
1712         dst_bits->is_copy = src_bits->is_copy;
1713         dst_bits->free = NULL;
1714         if (!need_byteswap && zeropad_mask == ~0u) return ERROR_SUCCESS;  /* nothing to do */
1715     }
1716
1717     src = src_bits->ptr;
1718     dst = dst_bits->ptr;
1719     padding_pos = width_bytes/sizeof(unsigned int) - 1;
1720
1721     if (info->bmiHeader.biHeight > 0)
1722     {
1723         dst += (height - 1) * width_bytes;
1724         width_bytes = -width_bytes;
1725     }
1726
1727     if (need_byteswap)
1728     {
1729         switch (info->bmiHeader.biBitCount)
1730         {
1731         case 1:
1732             for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1733             {
1734                 for (x = 0; x < image->bytes_per_line; x++)
1735                     dst[x] = bit_swap[src[x]];
1736                 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1737             }
1738             break;
1739         case 4:
1740             for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1741             {
1742                 for (x = 0; x < image->bytes_per_line; x++)
1743                     dst[x] = (src[x] << 4) | (src[x] >> 4);
1744                 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1745             }
1746             break;
1747         case 16:
1748             for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1749             {
1750                 for (x = 0; x < info->bmiHeader.biWidth; x++)
1751                     ((USHORT *)dst)[x] = RtlUshortByteSwap( ((const USHORT *)src)[x] );
1752                 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1753             }
1754             break;
1755         case 24:
1756             for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1757             {
1758                 for (x = 0; x < info->bmiHeader.biWidth; x++)
1759                 {
1760                     unsigned char tmp = src[3 * x];
1761                     dst[3 * x]     = src[3 * x + 2];
1762                     dst[3 * x + 1] = src[3 * x + 1];
1763                     dst[3 * x + 2] = tmp;
1764                 }
1765                 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1766             }
1767             break;
1768         case 32:
1769             for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1770                 for (x = 0; x < info->bmiHeader.biWidth; x++)
1771                     ((ULONG *)dst)[x] = RtlUlongByteSwap( ((const ULONG *)src)[x] );
1772             break;
1773         }
1774     }
1775     else if (src != dst)
1776     {
1777         for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1778         {
1779             memcpy( dst, src, image->bytes_per_line );
1780             ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1781         }
1782     }
1783     else  /* only need to clear the padding */
1784     {
1785         for (y = 0; y < height; y++, dst += width_bytes)
1786             ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1787     }
1788     return ERROR_SUCCESS;
1789 }
1790
1791 /***********************************************************************
1792  *           X11DRV_PutImage
1793  */
1794 DWORD X11DRV_PutImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info, const struct gdi_image_bits *bits,
1795                        const RECT *rect, DWORD rop )
1796 {
1797     X11DRV_PDEVICE *physdev;
1798     X_PHYSBITMAP *bitmap;
1799     DWORD ret = ERROR_SUCCESS;
1800     XImage *image;
1801     int depth;
1802     struct gdi_image_bits dst_bits;
1803     const XPixmapFormatValues *format;
1804     const ColorShifts *color_shifts;
1805
1806     if (hbitmap)
1807     {
1808         if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
1809         physdev = NULL;
1810         depth = bitmap->pixmap_depth;
1811         color_shifts = &bitmap->pixmap_color_shifts;
1812     }
1813     else
1814     {
1815         physdev = get_x11drv_dev( dev );
1816         bitmap = NULL;
1817         depth = physdev->depth;
1818         color_shifts = physdev->color_shifts;
1819     }
1820     format = pixmap_formats[depth];
1821
1822     if (info->bmiHeader.biPlanes != 1) goto update_format;
1823     if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1824     /* FIXME: could try to handle 1-bpp using XCopyPlane */
1825
1826     if (info->bmiHeader.biCompression == BI_BITFIELDS)
1827     {
1828         DWORD *masks = (DWORD *)((char *)info + info->bmiHeader.biSize);
1829         if (color_shifts->logicalRed.max << color_shifts->logicalRed.shift != masks[0] ||
1830             color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift != masks[1] ||
1831             color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift != masks[2])
1832             goto update_format;
1833     }
1834     else if (info->bmiHeader.biCompression == BI_RGB)
1835     {
1836         switch (info->bmiHeader.biBitCount)
1837         {
1838         case 16:
1839             if (color_shifts->logicalRed.max << color_shifts->logicalRed.shift     != 0x7c00 ||
1840                 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift != 0x03e0 ||
1841                 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift   != 0x001f)
1842                 goto update_format;
1843             break;
1844         case 24:
1845         case 32:
1846             if (color_shifts->logicalRed.max << color_shifts->logicalRed.shift     != 0xff0000 ||
1847                 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift != 0x00ff00 ||
1848                 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift   != 0x0000ff)
1849                 goto update_format;
1850             break;
1851         }
1852     }
1853     else goto update_format;
1854
1855     if (!bits) return ret;  /* just querying the format */
1856
1857     wine_tsx11_lock();
1858     image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1859                           info->bmiHeader.biWidth, abs(info->bmiHeader.biHeight), 32, 0 );
1860     wine_tsx11_unlock();
1861     if (!image) return ERROR_OUTOFMEMORY;
1862
1863     ret = copy_image_bits( info, color_shifts, image, bits, &dst_bits, ~0u );
1864
1865     if (!ret)
1866     {
1867         int width = rect->right - rect->left;
1868         int height = rect->bottom - rect->top;
1869
1870         image->data = dst_bits.ptr;
1871         if (bitmap)
1872         {
1873             wine_tsx11_lock();
1874             XPutImage( gdi_display, bitmap->pixmap, get_bitmap_gc(depth), image, dst_bits.offset, 0,
1875                        rect->left, rect->top, width, height );
1876             wine_tsx11_unlock();
1877         }
1878         else
1879         {
1880             const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1881
1882             X11DRV_LockDIBSection( physdev, DIB_Status_GdiMod );
1883
1884             /* optimization for single-op ROPs */
1885             if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1886             {
1887                 wine_tsx11_lock();
1888                 XSetFunction( gdi_display, physdev->gc, OP_ROP(*opcode) );
1889                 XPutImage( gdi_display, physdev->drawable, physdev->gc, image, dst_bits.offset, 0,
1890                            physdev->dc_rect.left + rect->left, physdev->dc_rect.top + rect->top,
1891                            width, height );
1892                 wine_tsx11_unlock();
1893             }
1894             else
1895             {
1896                 Pixmap src_pixmap;
1897                 GC gc;
1898
1899                 wine_tsx11_lock();
1900                 gc = XCreateGC( gdi_display, physdev->drawable, 0, NULL );
1901                 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
1902                 XSetGraphicsExposures( gdi_display, gc, False );
1903                 src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1904                 XPutImage( gdi_display, src_pixmap, gc, image, dst_bits.offset, 0, 0, 0, width, height );
1905                 wine_tsx11_unlock();
1906
1907                 execute_rop( physdev, src_pixmap, gc, rect, rop );
1908
1909                 wine_tsx11_lock();
1910                 XFreePixmap( gdi_display, src_pixmap );
1911                 XFreeGC( gdi_display, gc );
1912                 wine_tsx11_unlock();
1913             }
1914
1915             X11DRV_UnlockDIBSection( physdev, !ret );
1916         }
1917         image->data = NULL;
1918     }
1919
1920     wine_tsx11_lock();
1921     XDestroyImage( image );
1922     wine_tsx11_unlock();
1923     if (dst_bits.free) dst_bits.free( &dst_bits );
1924     return ret;
1925
1926 update_format:
1927     info->bmiHeader.biPlanes   = 1;
1928     info->bmiHeader.biBitCount = format->bits_per_pixel;
1929     if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1930     set_color_info( physdev->color_shifts, info );
1931     return ERROR_BAD_FORMAT;
1932 }
1933
1934 /***********************************************************************
1935  *           X11DRV_GetImage
1936  */
1937 DWORD X11DRV_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1938                        struct gdi_image_bits *bits, const RECT *rect )
1939 {
1940     X11DRV_PDEVICE *physdev;
1941     X_PHYSBITMAP *bitmap;
1942     DWORD ret = ERROR_SUCCESS;
1943     XImage *image;
1944     UINT align, x, y, width, height;
1945     int depth;
1946     struct gdi_image_bits src_bits;
1947     const XPixmapFormatValues *format;
1948     const ColorShifts *color_shifts;
1949
1950     if (hbitmap)
1951     {
1952         if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
1953         physdev = NULL;
1954         depth = bitmap->pixmap_depth;
1955         color_shifts = &bitmap->pixmap_color_shifts;
1956     }
1957     else
1958     {
1959         physdev = get_x11drv_dev( dev );
1960         bitmap = NULL;
1961         depth = physdev->depth;
1962         color_shifts = physdev->color_shifts;
1963     }
1964     format = pixmap_formats[depth];
1965
1966     /* align start and width to 32-bit boundary */
1967     switch (format->bits_per_pixel)
1968     {
1969     case 1:  align = 32; break;
1970     case 4:  align = 8;  break;
1971     case 8:  align = 4;  break;
1972     case 16: align = 2;  break;
1973     case 24: align = 4;  break;
1974     case 32: align = 1;  break;
1975     default:
1976         FIXME( "depth %u bpp %u not supported yet\n", depth, format->bits_per_pixel );
1977         return ERROR_BAD_FORMAT;
1978     }
1979     src_bits.offset = rect->left & (align - 1);
1980     x = rect->left - src_bits.offset;
1981     y = rect->top;
1982     width = rect->right - x;
1983     height = rect->bottom - rect->top;
1984     if (format->scanline_pad != 32) width = (width + (align - 1)) & ~(align - 1);
1985
1986     if (bitmap)
1987     {
1988         BITMAP bm;
1989         GetObjectW( hbitmap, sizeof(bm), &bm );
1990         width = min( width, bm.bmWidth - x );
1991         height = min( height, bm.bmHeight - y );
1992         X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
1993         wine_tsx11_lock();
1994         image = XGetImage( gdi_display, bitmap->pixmap, x, y, width, height, AllPlanes, ZPixmap );
1995         wine_tsx11_unlock();
1996         X11DRV_DIB_Unlock( bitmap, TRUE );
1997     }
1998     else if (GetObjectType( dev->hdc ) == OBJ_MEMDC)
1999     {
2000         X11DRV_LockDIBSection( physdev, DIB_Status_GdiMod );
2001         width = min( width, physdev->dc_rect.right - physdev->dc_rect.left - x );
2002         height = min( height, physdev->dc_rect.bottom - physdev->dc_rect.top - y );
2003         wine_tsx11_lock();
2004         image = XGetImage( gdi_display, physdev->drawable,
2005                            physdev->dc_rect.left + x, physdev->dc_rect.top + y,
2006                            width, height, AllPlanes, ZPixmap );
2007         wine_tsx11_unlock();
2008         X11DRV_UnlockDIBSection( physdev, FALSE );
2009     }
2010     else
2011     {
2012         Pixmap pixmap;
2013
2014         wine_tsx11_lock();
2015         /* use a temporary pixmap to avoid BadMatch errors */
2016         pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
2017         XCopyArea( gdi_display, physdev->drawable, pixmap, get_bitmap_gc(depth),
2018                    physdev->dc_rect.left + x, physdev->dc_rect.top + y, width, height, 0, 0 );
2019         image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
2020         XFreePixmap( gdi_display, pixmap );
2021         wine_tsx11_unlock();
2022     }
2023     if (!image) return ERROR_OUTOFMEMORY;
2024
2025     info->bmiHeader.biSize          = sizeof(info->bmiHeader);
2026     info->bmiHeader.biWidth         = width;
2027     info->bmiHeader.biHeight        = -height;
2028     info->bmiHeader.biPlanes        = 1;
2029     info->bmiHeader.biBitCount      = image->bits_per_pixel;
2030     info->bmiHeader.biSizeImage     = height * image->bytes_per_line;
2031     info->bmiHeader.biXPelsPerMeter = 0;
2032     info->bmiHeader.biYPelsPerMeter = 0;
2033     info->bmiHeader.biClrUsed       = 0;
2034     info->bmiHeader.biClrImportant  = 0;
2035     set_color_info( color_shifts, info );
2036
2037     src_bits.ptr     = image->data;
2038     src_bits.is_copy = TRUE;
2039     ret = copy_image_bits( info, color_shifts, image, &src_bits, bits,
2040                            zeropad_masks[(width * image->bits_per_pixel) & 31] );
2041
2042     if (!ret && bits->ptr == image->data)
2043     {
2044         bits->free = free_ximage_bits;
2045         image->data = NULL;
2046     }
2047     wine_tsx11_lock();
2048     XDestroyImage( image );
2049     wine_tsx11_unlock();
2050     return ret;
2051 }