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