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