winex11: Add a StretchBlt entry point to the XRender driver.
[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(!X11DRV_XRender_GetSrcAreaStretch( physDevSrc, physDevDst, src_pixmap, tmpGC, src, dst ))
1408     {
1409         if (fStretch)
1410             BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, src_pixmap, tmpGC, src, dst );
1411         else
1412             BITBLT_GetSrcArea( physDevSrc, physDevDst, src_pixmap, tmpGC, &src->visrect );
1413     }
1414
1415     execute_rop( physDevDst, src_pixmap, tmpGC, &dst->visrect, rop );
1416
1417     wine_tsx11_lock();
1418     XFreePixmap( gdi_display, src_pixmap );
1419     XFreeGC( gdi_display, tmpGC );
1420     wine_tsx11_unlock();
1421
1422 done:
1423     if (physDevDst != physDevSrc) X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1424     X11DRV_UnlockDIBSection( physDevDst, TRUE );
1425     return TRUE;
1426 }
1427
1428
1429 static void free_heap_bits( struct gdi_image_bits *bits )
1430 {
1431     HeapFree( GetProcessHeap(), 0, bits->ptr );
1432 }
1433
1434 static void free_ximage_bits( struct gdi_image_bits *bits )
1435 {
1436     wine_tsx11_lock();
1437     XFree( bits->ptr );
1438     wine_tsx11_unlock();
1439 }
1440
1441 /* store the palette or color mask data in the bitmap info structure */
1442 static void set_color_info( PHYSDEV dev, const ColorShifts *color_shifts, BITMAPINFO *info )
1443 {
1444     DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1445
1446     info->bmiHeader.biCompression = BI_RGB;
1447     info->bmiHeader.biClrUsed = 0;
1448
1449     switch (info->bmiHeader.biBitCount)
1450     {
1451     case 4:
1452     case 8:
1453     {
1454         RGBQUAD *rgb = (RGBQUAD *)colors;
1455         PALETTEENTRY palette[256];
1456         UINT i, count;
1457
1458         info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
1459         count = X11DRV_GetSystemPaletteEntries( dev, 0, info->bmiHeader.biClrUsed, palette );
1460         for (i = 0; i < count; i++)
1461         {
1462             rgb[i].rgbRed   = palette[i].peRed;
1463             rgb[i].rgbGreen = palette[i].peGreen;
1464             rgb[i].rgbBlue  = palette[i].peBlue;
1465             rgb[i].rgbReserved = 0;
1466         }
1467         memset( &rgb[count], 0, (info->bmiHeader.biClrUsed - count) * sizeof(*rgb) );
1468         break;
1469     }
1470     case 16:
1471         colors[0] = color_shifts->logicalRed.max << color_shifts->logicalRed.shift;
1472         colors[1] = color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift;
1473         colors[2] = color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift;
1474         info->bmiHeader.biCompression = BI_BITFIELDS;
1475         break;
1476     case 32:
1477         colors[0] = color_shifts->logicalRed.max << color_shifts->logicalRed.shift;
1478         colors[1] = color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift;
1479         colors[2] = color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift;
1480         if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1481             info->bmiHeader.biCompression = BI_BITFIELDS;
1482         break;
1483     }
1484 }
1485
1486 /* check if the specified color info is suitable for PutImage */
1487 static BOOL matching_color_info( PHYSDEV dev, const ColorShifts *color_shifts, const BITMAPINFO *info )
1488 {
1489     DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1490
1491     switch (info->bmiHeader.biBitCount)
1492     {
1493     case 1:
1494         if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
1495         return !info->bmiHeader.biClrUsed;  /* color map not allowed */
1496     case 4:
1497     case 8:
1498     {
1499         RGBQUAD *rgb = (RGBQUAD *)colors;
1500         PALETTEENTRY palette[256];
1501         UINT i, count;
1502
1503         if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
1504         count = X11DRV_GetSystemPaletteEntries( dev, 0, 1 << info->bmiHeader.biBitCount, palette );
1505         if (count != info->bmiHeader.biClrUsed) return FALSE;
1506         for (i = 0; i < count; i++)
1507         {
1508             if (rgb[i].rgbRed   != palette[i].peRed ||
1509                 rgb[i].rgbGreen != palette[i].peGreen ||
1510                 rgb[i].rgbBlue  != palette[i].peBlue) return FALSE;
1511         }
1512         return TRUE;
1513     }
1514     case 16:
1515         if (info->bmiHeader.biCompression == BI_BITFIELDS)
1516             return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == colors[0] &&
1517                     color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == colors[1] &&
1518                     color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == colors[2]);
1519         if (info->bmiHeader.biCompression == BI_RGB)
1520             return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift     == 0x7c00 &&
1521                     color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == 0x03e0 &&
1522                     color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift   == 0x001f);
1523         break;
1524     case 32:
1525         if (info->bmiHeader.biCompression == BI_BITFIELDS)
1526             return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == colors[0] &&
1527                     color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == colors[1] &&
1528                     color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == colors[2]);
1529         /* fall through */
1530     case 24:
1531         if (info->bmiHeader.biCompression == BI_RGB)
1532             return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift     == 0xff0000 &&
1533                     color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == 0x00ff00 &&
1534                     color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift   == 0x0000ff);
1535         break;
1536     }
1537     return FALSE;
1538 }
1539
1540 /* copy the image bits, fixing up alignment and byte swapping as necessary */
1541 static DWORD copy_image_bits( BITMAPINFO *info, const ColorShifts *color_shifts, XImage *image,
1542                               const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits,
1543                               struct bitblt_coords *coords, const int *mapping, unsigned int zeropad_mask )
1544 {
1545 #ifdef WORDS_BIGENDIAN
1546     static const int client_byte_order = MSBFirst;
1547 #else
1548     static const int client_byte_order = LSBFirst;
1549 #endif
1550     BOOL need_byteswap;
1551     int x, y, height = coords->visrect.bottom - coords->visrect.top;
1552     int width_bytes = image->bytes_per_line;
1553     int padding_pos;
1554     unsigned char *src, *dst;
1555
1556     switch (info->bmiHeader.biBitCount)
1557     {
1558     case 1:
1559         need_byteswap = (image->bitmap_bit_order != MSBFirst);
1560         break;
1561     case 4:
1562         need_byteswap = (image->byte_order != MSBFirst);
1563         break;
1564     case 16:
1565     case 32:
1566         need_byteswap = (image->byte_order != client_byte_order);
1567         break;
1568     case 24:
1569         need_byteswap = ((image->byte_order == LSBFirst && color_shifts->logicalBlue.shift == 16) ||
1570                          (image->byte_order == MSBFirst && color_shifts->logicalBlue.shift == 0));
1571         break;
1572     default:
1573         need_byteswap = FALSE;
1574         break;
1575     }
1576
1577     src = src_bits->ptr;
1578     if (info->bmiHeader.biHeight > 0)
1579         src += (info->bmiHeader.biHeight - coords->visrect.bottom) * width_bytes;
1580     else
1581         src += coords->visrect.top * width_bytes;
1582
1583     if ((need_byteswap && !src_bits->is_copy) ||  /* need to swap bytes */
1584         (zeropad_mask != ~0u && !src_bits->is_copy) ||  /* need to clear padding bytes */
1585         (mapping && !src_bits->is_copy) ||  /* need to remap pixels */
1586         (width_bytes & 3) ||  /* need to fixup line alignment */
1587         (info->bmiHeader.biHeight > 0))  /* need to flip vertically */
1588     {
1589         width_bytes = (width_bytes + 3) & ~3;
1590         info->bmiHeader.biSizeImage = height * width_bytes;
1591         if (!(dst_bits->ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage )))
1592             return ERROR_OUTOFMEMORY;
1593         dst_bits->is_copy = TRUE;
1594         dst_bits->free = free_heap_bits;
1595     }
1596     else
1597     {
1598         /* swap bits in place */
1599         dst_bits->ptr = src;
1600         dst_bits->is_copy = src_bits->is_copy;
1601         dst_bits->free = NULL;
1602         if (!need_byteswap && zeropad_mask == ~0u && !mapping) return ERROR_SUCCESS;  /* nothing to do */
1603     }
1604
1605     dst = dst_bits->ptr;
1606     padding_pos = width_bytes/sizeof(unsigned int) - 1;
1607
1608     if (info->bmiHeader.biHeight > 0)
1609     {
1610         dst += (height - 1) * width_bytes;
1611         width_bytes = -width_bytes;
1612     }
1613
1614     if (need_byteswap || mapping)
1615     {
1616         switch (info->bmiHeader.biBitCount)
1617         {
1618         case 1:
1619             for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1620             {
1621                 for (x = 0; x < image->bytes_per_line; x++)
1622                     dst[x] = bit_swap[src[x]];
1623                 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1624             }
1625             break;
1626         case 4:
1627             for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1628             {
1629                 if (mapping)
1630                     for (x = 0; x < image->bytes_per_line; x++)
1631                         dst[x] = (mapping[src[x] & 0x0f] << 4) | mapping[src[x] >> 4];
1632                 else
1633                     for (x = 0; x < image->bytes_per_line; x++)
1634                         dst[x] = (src[x] << 4) | (src[x] >> 4);
1635                 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1636             }
1637             break;
1638         case 8:
1639             for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1640             {
1641                 for (x = 0; x < image->bytes_per_line; x++)
1642                     dst[x] = mapping[src[x]];
1643                 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1644             }
1645             break;
1646         case 16:
1647             for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1648             {
1649                 for (x = 0; x < info->bmiHeader.biWidth; x++)
1650                     ((USHORT *)dst)[x] = RtlUshortByteSwap( ((const USHORT *)src)[x] );
1651                 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1652             }
1653             break;
1654         case 24:
1655             for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1656             {
1657                 for (x = 0; x < info->bmiHeader.biWidth; x++)
1658                 {
1659                     unsigned char tmp = src[3 * x];
1660                     dst[3 * x]     = src[3 * x + 2];
1661                     dst[3 * x + 1] = src[3 * x + 1];
1662                     dst[3 * x + 2] = tmp;
1663                 }
1664                 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1665             }
1666             break;
1667         case 32:
1668             for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1669                 for (x = 0; x < info->bmiHeader.biWidth; x++)
1670                     ((ULONG *)dst)[x] = RtlUlongByteSwap( ((const ULONG *)src)[x] );
1671             break;
1672         }
1673     }
1674     else if (src != dst)
1675     {
1676         for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1677         {
1678             memcpy( dst, src, image->bytes_per_line );
1679             ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1680         }
1681     }
1682     else  /* only need to clear the padding */
1683     {
1684         for (y = 0; y < height; y++, dst += width_bytes)
1685             ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1686     }
1687     return ERROR_SUCCESS;
1688 }
1689
1690 /***********************************************************************
1691  *           X11DRV_PutImage
1692  */
1693 DWORD X11DRV_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
1694                        const struct gdi_image_bits *bits, struct bitblt_coords *src,
1695                        struct bitblt_coords *dst, DWORD rop )
1696 {
1697     X11DRV_PDEVICE *physdev;
1698     X_PHYSBITMAP *bitmap;
1699     DWORD ret;
1700     XImage *image;
1701     int depth;
1702     struct gdi_image_bits dst_bits;
1703     const XPixmapFormatValues *format;
1704     const ColorShifts *color_shifts;
1705     const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1706     const int *mapping = NULL;
1707
1708     if (hbitmap)
1709     {
1710         if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
1711         physdev = NULL;
1712         depth = bitmap->pixmap_depth;
1713         color_shifts = &bitmap->pixmap_color_shifts;
1714     }
1715     else
1716     {
1717         physdev = get_x11drv_dev( dev );
1718         bitmap = NULL;
1719         depth = physdev->depth;
1720         color_shifts = physdev->color_shifts;
1721     }
1722     format = pixmap_formats[depth];
1723
1724     if (info->bmiHeader.biPlanes != 1) goto update_format;
1725     if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1726     /* FIXME: could try to handle 1-bpp using XCopyPlane */
1727     if (!matching_color_info( dev, color_shifts, info )) goto update_format;
1728     if (!bits) return ERROR_SUCCESS;  /* just querying the format */
1729     if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
1730
1731     wine_tsx11_lock();
1732     image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1733                           info->bmiHeader.biWidth, src->visrect.bottom - src->visrect.top, 32, 0 );
1734     wine_tsx11_unlock();
1735     if (!image) return ERROR_OUTOFMEMORY;
1736
1737     if (image->bits_per_pixel == 4 || image->bits_per_pixel == 8)
1738     {
1739         if (bitmap || (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST)))
1740             mapping = X11DRV_PALETTE_PaletteToXPixel;
1741     }
1742
1743     ret = copy_image_bits( info, color_shifts, image, bits, &dst_bits, src, mapping, ~0u );
1744
1745     if (!ret)
1746     {
1747         int width = dst->visrect.right - dst->visrect.left;
1748         int height = dst->visrect.bottom - dst->visrect.top;
1749
1750         image->data = dst_bits.ptr;
1751         /* hack: make sure the bits are readable if we are reading from a DIB section */
1752         /* to be removed once we get rid of DIB access protections */
1753         if (!dst_bits.is_copy) IsBadReadPtr( dst_bits.ptr, height * image->bytes_per_line );
1754
1755         if (bitmap)
1756         {
1757             RGNDATA *clip_data = NULL;
1758             GC gc;
1759
1760             if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
1761             X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
1762
1763             wine_tsx11_lock();
1764             gc = XCreateGC( gdi_display, bitmap->pixmap, 0, NULL );
1765             XSetGraphicsExposures( gdi_display, gc, False );
1766             if (clip_data) XSetClipRectangles( gdi_display, gc, 0, 0, (XRectangle *)clip_data->Buffer,
1767                                                clip_data->rdh.nCount, YXBanded );
1768             XPutImage( gdi_display, bitmap->pixmap, gc, image, src->visrect.left, 0,
1769                        dst->visrect.left, dst->visrect.top, width, height );
1770             XFreeGC( gdi_display, gc );
1771             wine_tsx11_unlock();
1772
1773             X11DRV_DIB_Unlock( bitmap, TRUE );
1774             HeapFree( GetProcessHeap(), 0, clip_data );
1775         }
1776         else
1777         {
1778             RGNDATA *saved_region = NULL;
1779
1780             if (clip) saved_region = add_extra_clipping_region( physdev, clip );
1781             X11DRV_LockDIBSection( physdev, DIB_Status_GdiMod );
1782
1783             /* optimization for single-op ROPs */
1784             if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1785             {
1786                 wine_tsx11_lock();
1787                 XSetFunction( gdi_display, physdev->gc, OP_ROP(*opcode) );
1788                 XPutImage( gdi_display, physdev->drawable, physdev->gc, image, src->visrect.left, 0,
1789                            physdev->dc_rect.left + dst->visrect.left,
1790                            physdev->dc_rect.top + dst->visrect.top, width, height );
1791                 wine_tsx11_unlock();
1792             }
1793             else
1794             {
1795                 Pixmap src_pixmap;
1796                 GC gc;
1797
1798                 wine_tsx11_lock();
1799                 gc = XCreateGC( gdi_display, physdev->drawable, 0, NULL );
1800                 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
1801                 XSetGraphicsExposures( gdi_display, gc, False );
1802                 src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1803                 XPutImage( gdi_display, src_pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1804                 wine_tsx11_unlock();
1805
1806                 execute_rop( physdev, src_pixmap, gc, &dst->visrect, rop );
1807
1808                 wine_tsx11_lock();
1809                 XFreePixmap( gdi_display, src_pixmap );
1810                 XFreeGC( gdi_display, gc );
1811                 wine_tsx11_unlock();
1812             }
1813
1814             X11DRV_UnlockDIBSection( physdev, !ret );
1815             restore_clipping_region( physdev, saved_region );
1816         }
1817         image->data = NULL;
1818     }
1819
1820     wine_tsx11_lock();
1821     XDestroyImage( image );
1822     wine_tsx11_unlock();
1823     if (dst_bits.free) dst_bits.free( &dst_bits );
1824     return ret;
1825
1826 update_format:
1827     info->bmiHeader.biPlanes   = 1;
1828     info->bmiHeader.biBitCount = format->bits_per_pixel;
1829     if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1830     set_color_info( dev, color_shifts, info );
1831     return ERROR_BAD_FORMAT;
1832 }
1833
1834 /***********************************************************************
1835  *           X11DRV_GetImage
1836  */
1837 DWORD X11DRV_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1838                        struct gdi_image_bits *bits, struct bitblt_coords *src )
1839 {
1840     X11DRV_PDEVICE *physdev;
1841     X_PHYSBITMAP *bitmap;
1842     DWORD ret = ERROR_SUCCESS;
1843     XImage *image;
1844     UINT align, x, y, width, height;
1845     int depth;
1846     struct gdi_image_bits src_bits;
1847     const XPixmapFormatValues *format;
1848     const ColorShifts *color_shifts;
1849     const int *mapping = NULL;
1850
1851     if (hbitmap)
1852     {
1853         if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
1854         physdev = NULL;
1855         depth = bitmap->pixmap_depth;
1856         color_shifts = &bitmap->pixmap_color_shifts;
1857     }
1858     else
1859     {
1860         physdev = get_x11drv_dev( dev );
1861         bitmap = NULL;
1862         depth = physdev->depth;
1863         color_shifts = physdev->color_shifts;
1864     }
1865     format = pixmap_formats[depth];
1866
1867     /* align start and width to 32-bit boundary */
1868     switch (format->bits_per_pixel)
1869     {
1870     case 1:  align = 32; break;
1871     case 4:  align = 8;  mapping = X11DRV_PALETTE_XPixelToPalette; break;
1872     case 8:  align = 4;  mapping = X11DRV_PALETTE_XPixelToPalette; break;
1873     case 16: align = 2;  break;
1874     case 24: align = 4;  break;
1875     case 32: align = 1;  break;
1876     default:
1877         FIXME( "depth %u bpp %u not supported yet\n", depth, format->bits_per_pixel );
1878         return ERROR_BAD_FORMAT;
1879     }
1880
1881     info->bmiHeader.biSize          = sizeof(info->bmiHeader);
1882     info->bmiHeader.biPlanes        = 1;
1883     info->bmiHeader.biBitCount      = format->bits_per_pixel;
1884     info->bmiHeader.biXPelsPerMeter = 0;
1885     info->bmiHeader.biYPelsPerMeter = 0;
1886     info->bmiHeader.biClrImportant  = 0;
1887     set_color_info( dev, color_shifts, info );
1888
1889     if (!bits) return ERROR_SUCCESS;  /* just querying the color information */
1890
1891     x = src->visrect.left & ~(align - 1);
1892     y = src->visrect.top;
1893     width = src->visrect.right - x;
1894     height = src->visrect.bottom - src->visrect.top;
1895     if (format->scanline_pad != 32) width = (width + (align - 1)) & ~(align - 1);
1896     /* make the source rectangle relative to the returned bits */
1897     src->x -= x;
1898     src->y -= y;
1899     OffsetRect( &src->visrect, -x, -y );
1900
1901     if (bitmap)
1902     {
1903         BITMAP bm;
1904         GetObjectW( hbitmap, sizeof(bm), &bm );
1905         width = min( width, bm.bmWidth - x );
1906         height = min( height, bm.bmHeight - y );
1907         X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
1908         wine_tsx11_lock();
1909         image = XGetImage( gdi_display, bitmap->pixmap, x, y, width, height, AllPlanes, ZPixmap );
1910         wine_tsx11_unlock();
1911         X11DRV_DIB_Unlock( bitmap, TRUE );
1912     }
1913     else if (GetObjectType( dev->hdc ) == OBJ_MEMDC)
1914     {
1915         X11DRV_LockDIBSection( physdev, DIB_Status_GdiMod );
1916         width = min( width, physdev->dc_rect.right - physdev->dc_rect.left - x );
1917         height = min( height, physdev->dc_rect.bottom - physdev->dc_rect.top - y );
1918         wine_tsx11_lock();
1919         image = XGetImage( gdi_display, physdev->drawable,
1920                            physdev->dc_rect.left + x, physdev->dc_rect.top + y,
1921                            width, height, AllPlanes, ZPixmap );
1922         wine_tsx11_unlock();
1923         X11DRV_UnlockDIBSection( physdev, FALSE );
1924     }
1925     else
1926     {
1927         Pixmap pixmap;
1928
1929         wine_tsx11_lock();
1930         /* use a temporary pixmap to avoid BadMatch errors */
1931         pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1932         XCopyArea( gdi_display, physdev->drawable, pixmap, get_bitmap_gc(depth),
1933                    physdev->dc_rect.left + x, physdev->dc_rect.top + y, width, height, 0, 0 );
1934         image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
1935         XFreePixmap( gdi_display, pixmap );
1936         wine_tsx11_unlock();
1937     }
1938     if (!image) return ERROR_OUTOFMEMORY;
1939
1940     info->bmiHeader.biWidth     = width;
1941     info->bmiHeader.biHeight    = -height;
1942     info->bmiHeader.biSizeImage = height * image->bytes_per_line;
1943
1944     src_bits.ptr     = image->data;
1945     src_bits.is_copy = TRUE;
1946     ret = copy_image_bits( info, color_shifts, image, &src_bits, bits, src, mapping,
1947                            zeropad_masks[(width * image->bits_per_pixel) & 31] );
1948
1949     if (!ret && bits->ptr == image->data)
1950     {
1951         bits->free = free_ximage_bits;
1952         image->data = NULL;
1953     }
1954     wine_tsx11_lock();
1955     XDestroyImage( image );
1956     wine_tsx11_unlock();
1957     return ret;
1958 }