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