dinput: BuildActionMap and SetActionMap stubs for generic joystick.
[wine] / dlls / winex11.drv / bitblt.c
1 /*
2  * GDI bit-blit operations
3  *
4  * Copyright 1993, 1994  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 "x11drv.h"
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
37
38
39 #define DST 0   /* Destination drawable */
40 #define SRC 1   /* Source drawable */
41 #define TMP 2   /* Temporary drawable */
42 #define PAT 3   /* Pattern (brush) in destination DC */
43
44 #define OP(src,dst,rop)   (OP_ARGS(src,dst) << 4 | (rop))
45 #define OP_ARGS(src,dst)  (((src) << 2) | (dst))
46
47 #define OP_SRC(opcode)    ((opcode) >> 6)
48 #define OP_DST(opcode)    (((opcode) >> 4) & 3)
49 #define OP_SRCDST(opcode) ((opcode) >> 4)
50 #define OP_ROP(opcode)    ((opcode) & 0x0f)
51
52 #define MAX_OP_LEN  6  /* Longest opcode + 1 for the terminating 0 */
53
54 #define SWAP_INT32(i1,i2) \
55     do { INT __t = *(i1); *(i1) = *(i2); *(i2) = __t; } while(0)
56
57 static const unsigned char BITBLT_Opcodes[256][MAX_OP_LEN] =
58 {
59     { OP(PAT,DST,GXclear) },                         /* 0x00  0              */
60     { OP(PAT,SRC,GXor), OP(SRC,DST,GXnor) },         /* 0x01  ~(D|(P|S))     */
61     { OP(PAT,SRC,GXnor), OP(SRC,DST,GXand) },        /* 0x02  D&~(P|S)       */
62     { OP(PAT,SRC,GXnor) },                           /* 0x03  ~(P|S)         */
63     { OP(PAT,DST,GXnor), OP(SRC,DST,GXand) },        /* 0x04  S&~(D|P)       */
64     { OP(PAT,DST,GXnor) },                           /* 0x05  ~(D|P)         */
65     { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnor), },     /* 0x06  ~(P|~(D^S))    */
66     { OP(SRC,DST,GXand), OP(PAT,DST,GXnor) },        /* 0x07  ~(P|(D&S))     */
67     { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXand) },/* 0x08  S&D&~P         */
68     { OP(SRC,DST,GXxor), OP(PAT,DST,GXnor) },        /* 0x09  ~(P|(D^S))     */
69     { OP(PAT,DST,GXandInverted) },                   /* 0x0a  D&~P           */
70     { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXnor) }, /* 0x0b  ~(P|(S&~D))    */
71     { OP(PAT,SRC,GXandInverted) },                   /* 0x0c  S&~P           */
72     { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXnor) },/* 0x0d  ~(P|(D&~S))    */
73     { OP(SRC,DST,GXnor), OP(PAT,DST,GXnor) },        /* 0x0e  ~(P|~(D|S))    */
74     { OP(PAT,DST,GXcopyInverted) },                  /* 0x0f  ~P             */
75     { OP(SRC,DST,GXnor), OP(PAT,DST,GXand) },        /* 0x10  P&~(S|D)       */
76     { OP(SRC,DST,GXnor) },                           /* 0x11  ~(D|S)         */
77     { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnor) },      /* 0x12  ~(S|~(D^P))    */
78     { OP(PAT,DST,GXand), OP(SRC,DST,GXnor) },        /* 0x13  ~(S|(D&P))     */
79     { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnor) },      /* 0x14  ~(D|~(P^S))    */
80     { OP(PAT,SRC,GXand), OP(SRC,DST,GXnor) },        /* 0x15  ~(D|(P&S))     */
81     { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
82       OP(TMP,DST,GXand), OP(SRC,DST,GXxor),
83       OP(PAT,DST,GXxor) },                           /* 0x16  P^S^(D&~(P&S)  */
84     { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
85       OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
86       OP(TMP,DST,GXequiv) },                         /* 0x17 ~S^((S^P)&(S^D))*/
87     { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
88         OP(SRC,DST,GXand) },                         /* 0x18  (S^P)&(D^P)    */
89     { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
90       OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) },      /* 0x19  ~S^(D&~(P&S))  */
91     { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
92       OP(PAT,DST,GXxor) },                           /* 0x1a  P^(D|(S&P))    */
93     { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXxor),
94       OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) },      /* 0x1b  ~S^(D&(P^S))   */
95     { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
96       OP(PAT,DST,GXxor) },                           /* 0x1c  P^(S|(D&P))    */
97     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
98       OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) },      /* 0x1d  ~D^(S&(D^P))   */
99     { OP(SRC,DST,GXor), OP(PAT,DST,GXxor) },         /* 0x1e  P^(D|S)        */
100     { OP(SRC,DST,GXor), OP(PAT,DST,GXnand) },        /* 0x1f  ~(P&(D|S))     */
101     { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXand) }, /* 0x20  D&(P&~S)       */
102     { OP(PAT,DST,GXxor), OP(SRC,DST,GXnor) },        /* 0x21  ~(S|(D^P))     */
103     { OP(SRC,DST,GXandInverted) },                   /* 0x22  ~S&D           */
104     { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x23  ~(S|(P&~D))    */
105     { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
106       OP(SRC,DST,GXand) },                           /* 0x24   (S^P)&(S^D)   */
107     { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand),
108       OP(PAT,DST,GXequiv) },                         /* 0x25  ~P^(D&~(S&P))  */
109     { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
110       OP(TMP,DST,GXor), OP(SRC,DST,GXxor) },         /* 0x26  S^(D|(S&P))    */
111     { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXequiv),
112       OP(TMP,DST,GXor), OP(SRC,DST,GXxor) },         /* 0x27  S^(D|~(P^S))   */
113     { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand) },        /* 0x28  D&(P^S)        */
114     { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
115       OP(TMP,DST,GXor), OP(SRC,DST,GXxor),
116       OP(PAT,DST,GXequiv) },                         /* 0x29  ~P^S^(D|(P&S)) */
117     { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand) },       /* 0x2a  D&~(P&S)       */
118     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
119       OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
120       OP(TMP,DST,GXequiv) },                         /* 0x2b ~S^((P^S)&(P^D))*/
121     { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
122       OP(SRC,DST,GXxor) },                           /* 0x2c  S^(P&(S|D))    */
123     { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXxor) },  /* 0x2d  P^(S|~D)       */
124     { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
125       OP(PAT,DST,GXxor) },                           /* 0x2e  P^(S|(D^P))    */
126     { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXnand) }, /* 0x2f  ~(P&(S|~D))    */
127     { OP(PAT,SRC,GXandReverse) },                    /* 0x30  P&~S           */
128     { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXnor) },/* 0x31  ~(S|(D&~P))    */
129     { OP(SRC,DST,GXor), OP(PAT,DST,GXor),
130       OP(SRC,DST,GXxor) },                           /* 0x32  S^(D|P|S)      */
131     { OP(SRC,DST,GXcopyInverted) },                  /* 0x33  ~S             */
132     { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
133       OP(SRC,DST,GXxor) },                           /* 0x34  S^(P|(D&S))    */
134     { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor),
135       OP(SRC,DST,GXxor) },                           /* 0x35  S^(P|~(D^S))   */
136     { OP(PAT,DST,GXor), OP(SRC,DST,GXxor) },         /* 0x36  S^(D|P)        */
137     { OP(PAT,DST,GXor), OP(SRC,DST,GXnand) },        /* 0x37  ~(S&(D|P))     */
138     { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
139       OP(PAT,DST,GXxor) },                           /* 0x38  P^(S&(D|P))    */
140     { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXxor) },  /* 0x39  S^(P|~D)       */
141     { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
142       OP(SRC,DST,GXxor) },                           /* 0x3a  S^(P|(D^S))    */
143     { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x3b  ~(S&(P|~D))    */
144     { OP(PAT,SRC,GXxor) },                           /* 0x3c  P^S            */
145     { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
146       OP(SRC,DST,GXxor) },                           /* 0x3d  S^(P|~(D|S))   */
147     { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
148       OP(SRC,DST,GXxor) },                           /* 0x3e  S^(P|(D&~S))   */
149     { OP(PAT,SRC,GXnand) },                          /* 0x3f  ~(P&S)         */
150     { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXand) }, /* 0x40  P&S&~D         */
151     { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnor) },        /* 0x41  ~(D|(P^S))     */
152     { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
153       OP(SRC,DST,GXand) },                           /* 0x42  (S^D)&(P^D)    */
154     { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
155       OP(SRC,DST,GXequiv) },                         /* 0x43  ~S^(P&~(D&S))  */
156     { OP(SRC,DST,GXandReverse) },                    /* 0x44  S&~D           */
157     { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x45  ~(D|(P&~S))    */
158     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
159       OP(SRC,DST,GXor), OP(TMP,DST,GXxor) },         /* 0x46  D^(S|(P&D))    */
160     { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
161       OP(PAT,DST,GXequiv) },                         /* 0x47  ~P^(S&(D^P))   */
162     { OP(PAT,DST,GXxor), OP(SRC,DST,GXand) },        /* 0x48  S&(P^D)        */
163     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
164       OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
165       OP(PAT,DST,GXequiv) },                         /* 0x49  ~P^D^(S|(P&D)) */
166     { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
167       OP(SRC,DST,GXxor) },                           /* 0x4a  D^(P&(S|D))    */
168     { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXxor) }, /* 0x4b  P^(D|~S)       */
169     { OP(PAT,DST,GXnand), OP(SRC,DST,GXand) },       /* 0x4c  S&~(D&P)       */
170     { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
171       OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
172       OP(TMP,DST,GXequiv) },                         /* 0x4d ~S^((S^P)|(S^D))*/
173     { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
174       OP(PAT,DST,GXxor) },                           /* 0x4e  P^(D|(S^P))    */
175     { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXnand) },/* 0x4f  ~(P&(D|~S))    */
176     { OP(PAT,DST,GXandReverse) },                    /* 0x50  P&~D           */
177     { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXnor) },/* 0x51  ~(D|(S&~P))    */
178     { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
179       OP(SRC,DST,GXxor) },                           /* 0x52  D^(P|(S&D))    */
180     { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
181       OP(SRC,DST,GXequiv) },                         /* 0x53  ~S^(P&(D^S))   */
182     { OP(PAT,SRC,GXnor), OP(SRC,DST,GXnor) },        /* 0x54  ~(D|~(P|S))    */
183     { OP(PAT,DST,GXinvert) },                        /* 0x55  ~D             */
184     { OP(PAT,SRC,GXor), OP(SRC,DST,GXxor) },         /* 0x56  D^(P|S)        */
185     { OP(PAT,SRC,GXor), OP(SRC,DST,GXnand) },        /* 0x57  ~(D&(P|S))     */
186     { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
187       OP(PAT,DST,GXxor) },                           /* 0x58  P^(D&(P|S))    */
188     { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXxor) },  /* 0x59  D^(P|~S)       */
189     { OP(PAT,DST,GXxor) },                           /* 0x5a  D^P            */
190     { OP(DST,SRC,GXnor), OP(PAT,SRC,GXor),
191       OP(SRC,DST,GXxor) },                           /* 0x5b  D^(P|~(S|D))   */
192     { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
193       OP(SRC,DST,GXxor) },                           /* 0x5c  D^(P|(S^D))    */
194     { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x5d  ~(D&(P|~S))    */
195     { OP(DST,SRC,GXandInverted), OP(PAT,SRC,GXor),
196       OP(SRC,DST,GXxor) },                           /* 0x5e  D^(P|(S&~D))   */
197     { OP(PAT,DST,GXnand) },                          /* 0x5f  ~(D&P)         */
198     { OP(SRC,DST,GXxor), OP(PAT,DST,GXand) },        /* 0x60  P&(D^S)        */
199     { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
200       OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
201       OP(TMP,DST,GXequiv) },                         /* 0x61  ~D^S^(P|(D&S)) */
202     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
203       OP(SRC,DST,GXand), OP(TMP,DST,GXxor) },        /* 0x62  D^(S&(P|D))    */
204     { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x63  S^(D|~P)       */
205     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
206       OP(SRC,DST,GXand), OP(TMP,DST,GXxor) },        /* 0x64  S^(D&(P|S))    */
207     { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x65  D^(S|~P)       */
208     { OP(SRC,DST,GXxor) },                           /* 0x66  S^D            */
209     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
210       OP(SRC,DST,GXor), OP(TMP,DST,GXxor) },         /* 0x67  S^(D|~(S|P)    */
211     { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnor),
212       OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
213       OP(TMP,DST,GXequiv) },                         /* 0x68  ~D^S^(P|~(D|S))*/
214     { OP(SRC,DST,GXxor), OP(PAT,DST,GXequiv) },      /* 0x69  ~P^(D^S)       */
215     { OP(PAT,SRC,GXand), OP(SRC,DST,GXxor) },        /* 0x6a  D^(P&S)        */
216     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
217       OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
218       OP(PAT,DST,GXequiv) },                         /* 0x6b  ~P^S^(D&(P|S)) */
219     { OP(PAT,DST,GXand), OP(SRC,DST,GXxor) },        /* 0x6c  S^(D&P)        */
220     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
221       OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
222       OP(PAT,DST,GXequiv) },                         /* 0x6d  ~P^D^(S&(P|D)) */
223     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
224       OP(SRC,DST,GXand), OP(TMP,DST,GXxor) },        /* 0x6e  S^(D&(P|~S))   */
225     { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnand) },     /* 0x6f  ~(P&~(S^D))    */
226     { OP(SRC,DST,GXnand), OP(PAT,DST,GXand) },       /* 0x70  P&~(D&S)       */
227     { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
228       OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
229       OP(TMP,DST,GXequiv) },                         /* 0x71 ~S^((S^D)&(P^D))*/
230     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
231       OP(SRC,DST,GXor), OP(TMP,DST,GXxor) },         /* 0x72  S^(D|(P^S))    */
232     { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXnand) },/* 0x73  ~(S&(D|~P))    */
233     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
234       OP(SRC,DST,GXor), OP(TMP,DST,GXxor) },         /* 0x74   D^(S|(P^D))   */
235     { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXnand) },/* 0x75  ~(D&(S|~P))    */
236     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
237       OP(SRC,DST,GXor), OP(TMP,DST,GXxor) },         /* 0x76  S^(D|(P&~S))   */
238     { OP(SRC,DST,GXnand) },                          /* 0x77  ~(S&D)         */
239     { OP(SRC,DST,GXand), OP(PAT,DST,GXxor) },        /* 0x78  P^(D&S)        */
240     { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
241       OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
242       OP(TMP,DST,GXequiv) },                         /* 0x79  ~D^S^(P&(D|S)) */
243     { OP(DST,SRC,GXorInverted), OP(PAT,SRC,GXand),
244       OP(SRC,DST,GXxor) },                           /* 0x7a  D^(P&(S|~D))   */
245     { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnand) },     /* 0x7b  ~(S&~(D^P))    */
246     { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
247       OP(SRC,DST,GXxor) },                           /* 0x7c  S^(P&(D|~S))   */
248     { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnand) },     /* 0x7d  ~(D&~(P^S))    */
249     { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
250       OP(SRC,DST,GXor) },                            /* 0x7e  (S^P)|(S^D)    */
251     { OP(PAT,SRC,GXand), OP(SRC,DST,GXnand) },       /* 0x7f  ~(D&P&S)       */
252     { OP(PAT,SRC,GXand), OP(SRC,DST,GXand) },        /* 0x80  D&P&S          */
253     { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
254       OP(SRC,DST,GXnor) },                           /* 0x81  ~((S^P)|(S^D)) */
255     { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXand) },      /* 0x82  D&~(P^S)       */
256     { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
257       OP(SRC,DST,GXequiv) },                         /* 0x83  ~S^(P&(D|~S))  */
258     { OP(PAT,DST,GXequiv), OP(SRC,DST,GXand) },      /* 0x84  S&~(D^P)       */
259     { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand),
260       OP(PAT,DST,GXequiv) },                         /* 0x85  ~P^(D&(S|~P))  */
261     { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
262       OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
263       OP(TMP,DST,GXxor) },                           /* 0x86  D^S^(P&(D|S))  */
264     { OP(SRC,DST,GXand), OP(PAT,DST,GXequiv) },      /* 0x87  ~P^(D&S)       */
265     { OP(SRC,DST,GXand) },                           /* 0x88  S&D            */
266     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
267       OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) },       /* 0x89  ~S^(D|(P&~S))  */
268     { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8a  D&(S|~P)       */
269     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
270       OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) },       /* 0x8b  ~D^(S|(P^D))   */
271     { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8c  S&(D|~P)       */
272     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
273       OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) },       /* 0x8d  ~S^(D|(P^S))   */
274     { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
275       OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
276       OP(TMP,DST,GXxor) },                           /* 0x8e  S^((S^D)&(P^D))*/
277     { OP(SRC,DST,GXnand), OP(PAT,DST,GXnand) },      /* 0x8f  ~(P&~(D&S))    */
278     { OP(SRC,DST,GXequiv), OP(PAT,DST,GXand) },      /* 0x90  P&~(D^S)       */
279     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
280       OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) },      /* 0x91  ~S^(D&(P|~S))  */
281     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
282       OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
283       OP(TMP,DST,GXxor) },                           /* 0x92  D^P^(S&(D|P))  */
284     { OP(PAT,DST,GXand), OP(SRC,DST,GXequiv) },      /* 0x93  ~S^(P&D)       */
285     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
286       OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
287       OP(TMP,DST,GXxor) },                           /* 0x94  S^P^(D&(P|S))  */
288     { OP(PAT,SRC,GXand), OP(SRC,DST,GXequiv) },      /* 0x95  ~D^(P&S)       */
289     { OP(PAT,SRC,GXxor), OP(SRC,DST,GXxor) },        /* 0x96  D^P^S          */
290     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
291       OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
292       OP(TMP,DST,GXxor) },                           /* 0x97  S^P^(D|~(P|S)) */
293     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
294       OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) },       /* 0x98  ~S^(D|~(P|S))  */
295     { OP(SRC,DST,GXequiv) },                         /* 0x99  ~S^D           */
296     { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9a  D^(P&~S)       */
297     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
298       OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) },      /* 0x9b  ~S^(D&(P|S))   */
299     { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9c  S^(P&~D)       */
300     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
301       OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) },      /* 0x9d  ~D^(S&(P|D))   */
302     { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
303       OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
304       OP(TMP,DST,GXxor) },                           /* 0x9e  D^S^(P|(D&S))  */
305     { OP(SRC,DST,GXxor), OP(PAT,DST,GXnand) },       /* 0x9f  ~(P&(D^S))     */
306     { OP(PAT,DST,GXand) },                           /* 0xa0  D&P            */
307     { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor),
308       OP(PAT,DST,GXequiv) },                         /* 0xa1  ~P^(D|(S&~P))  */
309     { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXand) },  /* 0xa2  D&(P|~S)       */
310     { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
311       OP(SRC,DST,GXequiv) },                         /* 0xa3  ~D^(P|(S^D))   */
312     { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor),
313       OP(PAT,DST,GXequiv) },                         /* 0xa4  ~P^(D|~(S|P))  */
314     { OP(PAT,DST,GXequiv) },                         /* 0xa5  ~P^D           */
315     { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXxor) },/* 0xa6  D^(S&~P)       */
316     { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
317       OP(PAT,DST,GXequiv) },                         /* 0xa7  ~P^(D&(S|P))   */
318     { OP(PAT,SRC,GXor), OP(SRC,DST,GXand) },         /* 0xa8  D&(P|S)        */
319     { OP(PAT,SRC,GXor), OP(SRC,DST,GXequiv) },       /* 0xa9  ~D^(P|S)       */
320     { OP(PAT,DST,GXnoop) },                          /* 0xaa  D              */
321     { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor) },         /* 0xab  D|~(P|S)       */
322     { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
323       OP(SRC,DST,GXxor) },                           /* 0xac  S^(P&(D^S))    */
324     { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
325       OP(SRC,DST,GXequiv) },                         /* 0xad  ~D^(P|(S&D))   */
326     { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor) }, /* 0xae  D|(S&~P)       */
327     { OP(PAT,DST,GXorInverted) },                    /* 0xaf  D|~P           */
328     { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand) }, /* 0xb0  P&(D|~S)       */
329     { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
330       OP(PAT,DST,GXequiv) },                         /* 0xb1  ~P^(D|(S^P))   */
331     { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
332       OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
333       OP(TMP,DST,GXxor) },                           /* 0xb2  S^((S^P)|(S^D))*/
334     { OP(PAT,DST,GXnand), OP(SRC,DST,GXnand) },      /* 0xb3  ~(S&~(D&P))    */
335     { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXxor) }, /* 0xb4  P^(S&~D)       */
336     { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
337       OP(SRC,DST,GXequiv) },                         /* 0xb5  ~D^(P&(S|D))   */
338     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
339       OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
340       OP(TMP,DST,GXxor) },                           /* 0xb6  D^P^(S|(D&P))  */
341     { OP(PAT,DST,GXxor), OP(SRC,DST,GXnand) },       /* 0xb7  ~(S&(D^P))     */
342     { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
343       OP(PAT,DST,GXxor) },                           /* 0xb8  P^(S&(D^P))    */
344     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
345       OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) },       /* 0xb9  ~D^(S|(P&D))   */
346     { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXor) },  /* 0xba  D|(P&~S)       */
347     { OP(SRC,DST,GXorInverted) },                    /* 0xbb  ~S|D           */
348     { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
349       OP(SRC,DST,GXxor) },                           /* 0xbc  S^(P&~(D&S))   */
350     { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
351       OP(SRC,DST,GXnand) },                          /* 0xbd  ~((S^D)&(P^D)) */
352     { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor) },         /* 0xbe  D|(P^S)        */
353     { OP(PAT,SRC,GXnand), OP(SRC,DST,GXor) },        /* 0xbf  D|~(P&S)       */
354     { OP(PAT,SRC,GXand) },                           /* 0xc0  P&S            */
355     { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
356       OP(SRC,DST,GXequiv) },                         /* 0xc1  ~S^(P|(D&~S))  */
357     { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
358       OP(SRC,DST,GXequiv) },                         /* 0xc2  ~S^(P|~(D|S))  */
359     { OP(PAT,SRC,GXequiv) },                         /* 0xc3  ~P^S           */
360     { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXand) },  /* 0xc4  S&(P|~D)       */
361     { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
362       OP(SRC,DST,GXequiv) },                         /* 0xc5  ~S^(P|(D^S))   */
363     { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXxor) },/* 0xc6  S^(D&~P)       */
364     { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
365       OP(PAT,DST,GXequiv) },                         /* 0xc7  ~P^(S&(D|P))   */
366     { OP(PAT,DST,GXor), OP(SRC,DST,GXand) },         /* 0xc8  S&(D|P)        */
367     { OP(PAT,DST,GXor), OP(SRC,DST,GXequiv) },       /* 0xc9  ~S^(P|D)       */
368     { OP(DST,SRC,GXxor), OP(PAT,SRC,GXand),
369       OP(SRC,DST,GXxor) },                           /* 0xca  D^(P&(S^D))    */
370     { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
371       OP(SRC,DST,GXequiv) },                         /* 0xcb  ~S^(P|(D&S))   */
372     { OP(SRC,DST,GXcopy) },                          /* 0xcc  S              */
373     { OP(PAT,DST,GXnor), OP(SRC,DST,GXor) },         /* 0xcd  S|~(D|P)       */
374     { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXor) }, /* 0xce  S|(D&~P)       */
375     { OP(PAT,SRC,GXorInverted) },                    /* 0xcf  S|~P           */
376     { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXand) },  /* 0xd0  P&(S|~D)       */
377     { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
378       OP(PAT,DST,GXequiv) },                         /* 0xd1  ~P^(S|(D^P))   */
379     { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXxor) },/* 0xd2  P^(D&~S)       */
380     { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
381       OP(SRC,DST,GXequiv) },                         /* 0xd3  ~S^(P&(D|S))   */
382     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
383       OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
384       OP(TMP,DST,GXxor) },                           /* 0xd4  S^((S^P)&(D^P))*/
385     { OP(PAT,SRC,GXnand), OP(SRC,DST,GXnand) },      /* 0xd5  ~(D&~(P&S))    */
386     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
387       OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
388       OP(TMP,DST,GXxor) },                           /* 0xd6  S^P^(D|(P&S))  */
389     { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnand) },       /* 0xd7  ~(D&(P^S))     */
390     { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
391       OP(PAT,DST,GXxor) },                           /* 0xd8  P^(D&(S^P))    */
392     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
393       OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) },       /* 0xd9  ~S^(D|(P&S))   */
394     { OP(DST,SRC,GXnand), OP(PAT,SRC,GXand),
395       OP(SRC,DST,GXxor) },                           /* 0xda  D^(P&~(S&D))   */
396     { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
397       OP(SRC,DST,GXnand) },                          /* 0xdb  ~((S^P)&(S^D)) */
398     { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXor) },  /* 0xdc  S|(P&~D)       */
399     { OP(SRC,DST,GXorReverse) },                     /* 0xdd  S|~D           */
400     { OP(PAT,DST,GXxor), OP(SRC,DST,GXor) },         /* 0xde  S|(D^P)        */
401     { OP(PAT,DST,GXnand), OP(SRC,DST,GXor) },        /* 0xdf  S|~(D&P)       */
402     { OP(SRC,DST,GXor), OP(PAT,DST,GXand) },         /* 0xe0  P&(D|S)        */
403     { OP(SRC,DST,GXor), OP(PAT,DST,GXequiv) },       /* 0xe1  ~P^(D|S)       */
404     { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
405       OP(SRC,DST,GXand), OP(TMP,DST,GXxor) },        /* 0xe2  D^(S&(P^D))    */
406     { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
407       OP(PAT,DST,GXequiv) },                         /* 0xe3  ~P^(S|(D&P))   */
408     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
409       OP(SRC,DST,GXand), OP(TMP,DST,GXxor) },        /* 0xe4  S^(D&(P^S))    */
410     { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
411       OP(PAT,DST,GXequiv) },                         /* 0xe5  ~P^(D|(S&P))   */
412     { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
413       OP(SRC,DST,GXand), OP(TMP,DST,GXxor) },        /* 0xe6  S^(D&~(P&S))   */
414     { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
415       OP(SRC,DST,GXnand) },                          /* 0xe7  ~((S^P)&(D^P)) */
416     { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
417       OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
418       OP(TMP,DST,GXxor) },                           /* 0xe8  S^((S^P)&(S^D))*/
419     { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnand),
420       OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
421       OP(TMP,DST,GXequiv) },                         /* 0xe9  ~D^S^(P&~(S&D))*/
422     { OP(PAT,SRC,GXand), OP(SRC,DST,GXor) },         /* 0xea  D|(P&S)        */
423     { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXor) },       /* 0xeb  D|~(P^S)       */
424     { OP(PAT,DST,GXand), OP(SRC,DST,GXor) },         /* 0xec  S|(D&P)        */
425     { OP(PAT,DST,GXequiv), OP(SRC,DST,GXor) },       /* 0xed  S|~(D^P)       */
426     { OP(SRC,DST,GXor) },                            /* 0xee  S|D            */
427     { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXor) },  /* 0xef  S|D|~P         */
428     { OP(PAT,DST,GXcopy) },                          /* 0xf0  P              */
429     { OP(SRC,DST,GXnor), OP(PAT,DST,GXor) },         /* 0xf1  P|~(D|S)       */
430     { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor) }, /* 0xf2  P|(D&~S)       */
431     { OP(PAT,SRC,GXorReverse) },                     /* 0xf3  P|~S           */
432     { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXor) },  /* 0xf4  P|(S&~D)       */
433     { OP(PAT,DST,GXorReverse) },                     /* 0xf5  P|~D           */
434     { OP(SRC,DST,GXxor), OP(PAT,DST,GXor) },         /* 0xf6  P|(D^S)        */
435     { OP(SRC,DST,GXnand), OP(PAT,DST,GXor) },        /* 0xf7  P|~(S&D)       */
436     { OP(SRC,DST,GXand), OP(PAT,DST,GXor) },         /* 0xf8  P|(D&S)        */
437     { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor) },       /* 0xf9  P|~(D^S)       */
438     { OP(PAT,DST,GXor) },                            /* 0xfa  D|P            */
439     { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXor) },   /* 0xfb  D|P|~S         */
440     { OP(PAT,SRC,GXor) },                            /* 0xfc  P|S            */
441     { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXor) },   /* 0xfd  P|S|~D         */
442     { OP(SRC,DST,GXor), OP(PAT,DST,GXor) },          /* 0xfe  P|D|S          */
443     { OP(PAT,DST,GXset) }                            /* 0xff  1              */
444 };
445
446
447 #ifdef BITBLT_TEST  /* Opcodes test */
448
449 static int do_bitop( int s, int d, int rop )
450 {
451     int res;
452     switch(rop)
453     {
454     case GXclear:        res = 0; break;
455     case GXand:          res = s & d; break;
456     case GXandReverse:   res = s & ~d; break;
457     case GXcopy:         res = s; break;
458     case GXandInverted:  res = ~s & d; break;
459     case GXnoop:         res = d; break;
460     case GXxor:          res = s ^ d; break;
461     case GXor:           res = s | d; break;
462     case GXnor:          res = ~(s | d); break;
463     case GXequiv:        res = ~s ^ d; break;
464     case GXinvert:       res = ~d; break;
465     case GXorReverse:    res = s | ~d; break;
466     case GXcopyInverted: res = ~s; break;
467     case GXorInverted:   res = ~s | d; break;
468     case GXnand:         res = ~(s & d); break;
469     case GXset:          res = 1; break;
470     }
471     return res & 1;
472 }
473
474 int main()
475 {
476     int rop, i, res, src, dst, pat, tmp, dstUsed;
477     const BYTE *opcode;
478
479     for (rop = 0; rop < 256; rop++)
480     {
481         res = dstUsed = 0;
482         for (i = 0; i < 8; i++)
483         {
484             pat = (i >> 2) & 1;
485             src = (i >> 1) & 1;
486             dst = i & 1;
487             for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
488             {
489                 switch(*opcode >> 4)
490                 {
491                 case OP_ARGS(DST,TMP):
492                     tmp = do_bitop( dst, tmp, *opcode & 0xf );
493                     break;
494                 case OP_ARGS(DST,SRC):
495                     src = do_bitop( dst, src, *opcode & 0xf );
496                     break;
497                 case OP_ARGS(SRC,TMP):
498                     tmp = do_bitop( src, tmp, *opcode & 0xf );
499                     break;
500                 case OP_ARGS(SRC,DST):
501                     dst = do_bitop( src, dst, *opcode & 0xf );
502                     dstUsed = 1;
503                     break;
504                 case OP_ARGS(PAT,TMP):
505                     tmp = do_bitop( pat, tmp, *opcode & 0xf );
506                     break;
507                 case OP_ARGS(PAT,DST):
508                     dst = do_bitop( pat, dst, *opcode & 0xf );
509                     dstUsed = 1;
510                     break;
511                 case OP_ARGS(PAT,SRC):
512                     src = do_bitop( pat, src, *opcode & 0xf );
513                     break;
514                 case OP_ARGS(TMP,DST):
515                     dst = do_bitop( tmp, dst, *opcode & 0xf );
516                     dstUsed = 1;
517                     break;
518                 case OP_ARGS(TMP,SRC):
519                     src = do_bitop( tmp, src, *opcode & 0xf );
520                     break;
521                 default:
522                     printf( "Invalid opcode %x\n", *opcode );
523                 }
524             }
525             if (!dstUsed) dst = src;
526             if (dst) res |= 1 << i;
527         }
528         if (res != rop) printf( "%02x: ERROR, res=%02x\n", rop, res );
529     }
530
531     return 0;
532 }
533
534 #endif  /* BITBLT_TEST */
535
536
537 static void get_colors(X11DRV_PDEVICE *physDevDst, X11DRV_PDEVICE *physDevSrc,
538                        int *fg, int *bg)
539 {
540     RGBQUAD rgb[2];
541
542     *fg = physDevDst->textPixel;
543     *bg = physDevDst->backgroundPixel;
544     if(physDevSrc->depth == 1) {
545         if(GetDIBColorTable(physDevSrc->dev.hdc, 0, 2, rgb) == 2) {
546             DWORD logcolor;
547             logcolor = RGB(rgb[0].rgbRed, rgb[0].rgbGreen, rgb[0].rgbBlue);
548             *fg = X11DRV_PALETTE_ToPhysical( physDevDst, logcolor );
549             logcolor = RGB(rgb[1].rgbRed, rgb[1].rgbGreen,rgb[1].rgbBlue);
550             *bg = X11DRV_PALETTE_ToPhysical( physDevDst, logcolor );
551         }
552     }
553 }
554
555 /* return a mask for meaningful bits when doing an XGetPixel on an image */
556 static unsigned long image_pixel_mask( X11DRV_PDEVICE *physDev )
557 {
558     unsigned long ret;
559     ColorShifts *shifts = physDev->color_shifts;
560
561     if (!shifts) shifts = &X11DRV_PALETTE_default_shifts;
562     ret = (shifts->physicalRed.max << shifts->physicalRed.shift) |
563         (shifts->physicalGreen.max << shifts->physicalGreen.shift) |
564         (shifts->physicalBlue.max << shifts->physicalBlue.shift);
565     if (!ret) ret = (1 << physDev->depth) - 1;
566     return ret;
567 }
568
569
570 /***********************************************************************
571  *           BITBLT_StretchRow
572  *
573  * Stretch a row of pixels. Helper function for BITBLT_StretchImage.
574  */
575 static void BITBLT_StretchRow( int *rowSrc, int *rowDst,
576                                INT startDst, INT widthDst,
577                                INT xinc, INT xoff, WORD mode )
578 {
579     register INT xsrc = xinc * startDst + xoff;
580     rowDst += startDst;
581     switch(mode)
582     {
583     case STRETCH_ANDSCANS:
584         for(; widthDst > 0; widthDst--, xsrc += xinc)
585             *rowDst++ &= rowSrc[xsrc >> 16];
586         break;
587     case STRETCH_ORSCANS:
588         for(; widthDst > 0; widthDst--, xsrc += xinc)
589             *rowDst++ |= rowSrc[xsrc >> 16];
590         break;
591     case STRETCH_DELETESCANS:
592         for(; widthDst > 0; widthDst--, xsrc += xinc)
593             *rowDst++ = rowSrc[xsrc >> 16];
594         break;
595     }
596 }
597
598
599 /***********************************************************************
600  *           BITBLT_ShrinkRow
601  *
602  * Shrink a row of pixels. Helper function for BITBLT_StretchImage.
603  */
604 static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst,
605                               INT startSrc, INT widthSrc,
606                               INT xinc, INT xoff, WORD mode )
607 {
608     register INT xdst = xinc * startSrc + xoff;
609     rowSrc += startSrc;
610     switch(mode)
611     {
612     case STRETCH_ORSCANS:
613         for(; widthSrc > 0; widthSrc--, xdst += xinc)
614             rowDst[xdst >> 16] |= *rowSrc++;
615         break;
616     case STRETCH_ANDSCANS:
617         for(; widthSrc > 0; widthSrc--, xdst += xinc)
618             rowDst[xdst >> 16] &= *rowSrc++;
619         break;
620     case STRETCH_DELETESCANS:
621         for(; widthSrc > 0; widthSrc--, xdst += xinc)
622             rowDst[xdst >> 16] = *rowSrc++;
623         break;
624     }
625 }
626
627
628 /***********************************************************************
629  *           BITBLT_GetRow
630  *
631  * Retrieve a row from an image. Helper function for BITBLT_StretchImage.
632  */
633 static void BITBLT_GetRow( XImage *image, int *pdata, INT row,
634                            INT start, INT width, INT depthDst,
635                            int fg, int bg, unsigned long pixel_mask, BOOL swap)
636 {
637     register INT i;
638
639     assert( (row >= 0) && (row < image->height) );
640     assert( (start >= 0) && (width <= image->width) );
641
642     pdata += swap ? start+width-1 : start;
643     if (image->depth == depthDst)  /* color -> color */
644     {
645         if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1))
646             if (swap) for (i = 0; i < width; i++)
647                 *pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
648             else for (i = 0; i < width; i++)
649                 *pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
650         else
651             if (swap) for (i = 0; i < width; i++)
652                 *pdata-- = XGetPixel( image, i, row );
653             else for (i = 0; i < width; i++)
654                 *pdata++ = XGetPixel( image, i, row );
655     }
656     else
657     {
658         if (image->depth == 1)  /* monochrome -> color */
659         {
660             if (X11DRV_PALETTE_XPixelToPalette)
661             {
662                 fg = X11DRV_PALETTE_XPixelToPalette[fg];
663                 bg = X11DRV_PALETTE_XPixelToPalette[bg];
664             }
665             if (swap) for (i = 0; i < width; i++)
666                 *pdata-- = XGetPixel( image, i, row ) ? bg : fg;
667             else for (i = 0; i < width; i++)
668                 *pdata++ = XGetPixel( image, i, row ) ? bg : fg;
669         }
670         else  /* color -> monochrome */
671         {
672             if (swap) for (i = 0; i < width; i++)
673                 *pdata-- = ((XGetPixel( image, i, row ) & pixel_mask) == bg) ? 1 : 0;
674             else for (i = 0; i < width; i++)
675                 *pdata++ = ((XGetPixel( image, i, row ) & pixel_mask) == bg) ? 1 : 0;
676         }
677     }
678 }
679
680
681 /***********************************************************************
682  *           BITBLT_StretchImage
683  *
684  * Stretch an X image.
685  * FIXME: does not work for full 32-bit coordinates.
686  */
687 static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage,
688                                  INT widthSrc, INT heightSrc,
689                                  INT widthDst, INT heightDst,
690                                  RECT *visRectSrc, RECT *visRectDst,
691                                  int foreground, int background,
692                                  unsigned long pixel_mask, WORD mode )
693 {
694     int *rowSrc, *rowDst, *pixel;
695     char *pdata;
696     INT xinc, xoff, yinc, ysrc, ydst;
697     register INT x, y;
698     BOOL hstretch, vstretch, hswap, vswap;
699
700     hswap = widthSrc * widthDst < 0;
701     vswap = heightSrc * heightDst < 0;
702     widthSrc  = abs(widthSrc);
703     heightSrc = abs(heightSrc);
704     widthDst  = abs(widthDst);
705     heightDst = abs(heightDst);
706
707     if (!(rowSrc = HeapAlloc( GetProcessHeap(), 0,
708                               (widthSrc+widthDst)*sizeof(int) ))) return;
709     rowDst = rowSrc + widthSrc;
710
711       /* When stretching, all modes are the same, and DELETESCANS is faster */
712     if ((widthSrc < widthDst) && (heightSrc < heightDst))
713         mode = STRETCH_DELETESCANS;
714
715     if (mode == STRETCH_HALFTONE) /* FIXME */
716         mode = STRETCH_DELETESCANS;
717
718     if (mode != STRETCH_DELETESCANS)
719         memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
720                 widthDst*sizeof(int) );
721
722     hstretch = (widthSrc < widthDst);
723     vstretch = (heightSrc < heightDst);
724
725     if (hstretch)
726     {
727         xinc = (widthSrc << 16) / widthDst;
728         xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
729     }
730     else
731     {
732         xinc = ((int)widthDst << 16) / widthSrc;
733         xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
734     }
735
736     wine_tsx11_lock();
737     if (vstretch)
738     {
739         yinc = (heightSrc << 16) / heightDst;
740         ydst = visRectDst->top;
741         if (vswap)
742         {
743             ysrc = yinc * (heightDst - ydst - 1);
744             yinc = -yinc;
745         }
746         else
747             ysrc = yinc * ydst;
748
749         for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
750         {
751             if (((ysrc >> 16) < visRectSrc->top) ||
752                 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
753
754             /* Retrieve a source row */
755             BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
756                            hswap ? widthSrc - visRectSrc->right
757                                  : visRectSrc->left,
758                            visRectSrc->right - visRectSrc->left,
759                            dstImage->depth, foreground, background, pixel_mask, hswap );
760
761             /* Stretch or shrink it */
762             if (hstretch)
763                 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
764                                    visRectDst->right - visRectDst->left,
765                                    xinc, xoff, mode );
766             else BITBLT_ShrinkRow( rowSrc, rowDst,
767                                    hswap ? widthSrc - visRectSrc->right
768                                          : visRectSrc->left,
769                                    visRectSrc->right - visRectSrc->left,
770                                    xinc, xoff, mode );
771
772             /* Store the destination row */
773             pixel = rowDst + visRectDst->right - 1;
774             y = ydst - visRectDst->top;
775             for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
776                 XPutPixel( dstImage, x, y, *pixel-- );
777             if (mode != STRETCH_DELETESCANS)
778                 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
779                         widthDst*sizeof(int) );
780
781             /* Make copies of the destination row */
782
783             pdata = dstImage->data + dstImage->bytes_per_line * y;
784             while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
785                    (ydst < visRectDst->bottom-1))
786             {
787                 memcpy( pdata + dstImage->bytes_per_line, pdata,
788                         dstImage->bytes_per_line );
789                 pdata += dstImage->bytes_per_line;
790                 ysrc += yinc;
791                 ydst++;
792             }
793         }
794     }
795     else  /* Shrinking */
796     {
797         yinc = (heightDst << 16) / heightSrc;
798         ysrc = visRectSrc->top;
799         ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
800         if (vswap)
801         {
802             ydst += yinc * (heightSrc - ysrc - 1);
803             yinc = -yinc;
804         }
805         else
806             ydst += yinc * ysrc;
807
808         for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
809         {
810             if (((ydst >> 16) < visRectDst->top) ||
811                 ((ydst >> 16) >= visRectDst->bottom)) continue;
812
813             /* Retrieve a source row */
814             BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
815                            hswap ? widthSrc - visRectSrc->right
816                                  : visRectSrc->left,
817                            visRectSrc->right - visRectSrc->left,
818                            dstImage->depth, foreground, background, pixel_mask, hswap );
819
820             /* Stretch or shrink it */
821             if (hstretch)
822                 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
823                                    visRectDst->right - visRectDst->left,
824                                    xinc, xoff, mode );
825             else BITBLT_ShrinkRow( rowSrc, rowDst,
826                                    hswap ? widthSrc - visRectSrc->right
827                                          : visRectSrc->left,
828                                    visRectSrc->right - visRectSrc->left,
829                                    xinc, xoff, mode );
830
831             /* Merge several source rows into the destination */
832             if (mode == STRETCH_DELETESCANS)
833             {
834                 /* Simply skip the overlapping rows */
835                 while (((ydst + yinc) >> 16 == ydst >> 16) &&
836                        (ysrc < visRectSrc->bottom-1))
837                 {
838                     ydst += yinc;
839                     ysrc++;
840                 }
841             }
842             else if (((ydst + yinc) >> 16 == ydst >> 16) &&
843                      (ysrc < visRectSrc->bottom-1))
844                 continue;  /* Restart loop for next overlapping row */
845
846             /* Store the destination row */
847             pixel = rowDst + visRectDst->right - 1;
848             y = (ydst >> 16) - visRectDst->top;
849             for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
850                 XPutPixel( dstImage, x, y, *pixel-- );
851             if (mode != STRETCH_DELETESCANS)
852                 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
853                         widthDst*sizeof(int) );
854         }
855     }
856     wine_tsx11_unlock();
857     HeapFree( GetProcessHeap(), 0, rowSrc );
858 }
859
860
861 /***********************************************************************
862  *           BITBLT_GetSrcAreaStretch
863  *
864  * Retrieve an area from the source DC, stretching and mapping all the
865  * pixels to Windows colors.
866  */
867 static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
868                                      Pixmap pixmap, GC gc,
869                                      const struct bitblt_coords *src, const struct bitblt_coords *dst )
870 {
871     XImage *imageSrc, *imageDst;
872     RECT rectSrc = src->visrect;
873     RECT rectDst = dst->visrect;
874     int fg, bg;
875
876     rectSrc.left   -= src->x;
877     rectSrc.right  -= src->x;
878     rectSrc.top    -= src->y;
879     rectSrc.bottom -= src->y;
880     rectDst.left   -= dst->x;
881     rectDst.right  -= dst->x;
882     rectDst.top    -= dst->y;
883     rectDst.bottom -= dst->y;
884     if (src->width < 0)
885     {
886         rectSrc.left  -= src->width;
887         rectSrc.right -= src->width;
888     }
889     if (dst->width < 0)
890     {
891         rectDst.left  -= dst->width;
892         rectDst.right -= dst->width;
893     }
894     if (src->height < 0)
895     {
896         rectSrc.top    -= src->height;
897         rectSrc.bottom -= src->height;
898     }
899     if (dst->height < 0)
900     {
901         rectDst.top    -= dst->height;
902         rectDst.bottom -= dst->height;
903     }
904
905     get_colors(physDevDst, physDevSrc, &fg, &bg);
906     wine_tsx11_lock();
907     /* FIXME: avoid BadMatch errors */
908     imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
909                           physDevSrc->dc_rect.left + src->visrect.left,
910                           physDevSrc->dc_rect.top + src->visrect.top,
911                           src->visrect.right - src->visrect.left,
912                           src->visrect.bottom - src->visrect.top,
913                           AllPlanes, ZPixmap );
914     wine_tsx11_unlock();
915
916     imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
917                                         rectDst.bottom - rectDst.top, physDevDst->depth );
918     BITBLT_StretchImage( imageSrc, imageDst, src->width, src->height,
919                          dst->width, dst->height, &rectSrc, &rectDst,
920                          fg, physDevDst->depth != 1 ? bg : physDevSrc->backgroundPixel,
921                          image_pixel_mask( physDevSrc ), GetStretchBltMode(physDevDst->dev.hdc) );
922     wine_tsx11_lock();
923     XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
924                rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
925     XDestroyImage( imageSrc );
926     X11DRV_DIB_DestroyXImage( imageDst );
927     wine_tsx11_unlock();
928     return 0;  /* no exposure events generated */
929 }
930
931
932 /***********************************************************************
933  *           BITBLT_GetSrcArea
934  *
935  * Retrieve an area from the source DC, mapping all the
936  * pixels to Windows colors.
937  */
938 static int BITBLT_GetSrcArea( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
939                               Pixmap pixmap, GC gc, RECT *visRectSrc )
940 {
941     XImage *imageSrc, *imageDst;
942     register INT x, y;
943     int exposures = 0;
944     INT width  = visRectSrc->right - visRectSrc->left;
945     INT height = visRectSrc->bottom - visRectSrc->top;
946     int fg, bg;
947     BOOL memdc = (GetObjectType(physDevSrc->dev.hdc) == OBJ_MEMDC);
948
949     if (physDevSrc->depth == physDevDst->depth)
950     {
951         wine_tsx11_lock();
952         if (!X11DRV_PALETTE_XPixelToPalette ||
953             (physDevDst->depth == 1))  /* monochrome -> monochrome */
954         {
955             if (physDevDst->depth == 1)
956             {
957                 /* MSDN says if StretchBlt must convert a bitmap from monochrome
958                    to color or vice versa, the foreground and background color of
959                    the device context are used.  In fact, it also applies to the
960                    case when it is converted from mono to mono. */
961                 XSetBackground( gdi_display, gc, physDevDst->textPixel );
962                 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
963                 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
964                             physDevSrc->dc_rect.left + visRectSrc->left,
965                             physDevSrc->dc_rect.top + visRectSrc->top,
966                             width, height, 0, 0, 1);
967             }
968             else
969                 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
970                            physDevSrc->dc_rect.left + visRectSrc->left,
971                            physDevSrc->dc_rect.top + visRectSrc->top,
972                            width, height, 0, 0);
973             exposures++;
974         }
975         else  /* color -> color */
976         {
977             if (memdc)
978                 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
979                                       physDevSrc->dc_rect.left + visRectSrc->left,
980                                       physDevSrc->dc_rect.top + visRectSrc->top,
981                                       width, height, AllPlanes, ZPixmap );
982             else
983             {
984                 /* Make sure we don't get a BadMatch error */
985                 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
986                            physDevSrc->dc_rect.left + visRectSrc->left,
987                            physDevSrc->dc_rect.top + visRectSrc->top,
988                            width, height, 0, 0);
989                 exposures++;
990                 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
991                                       AllPlanes, ZPixmap );
992             }
993             for (y = 0; y < height; y++)
994                 for (x = 0; x < width; x++)
995                     XPutPixel(imageSrc, x, y,
996                               X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
997             XPutImage( gdi_display, pixmap, gc, imageSrc,
998                        0, 0, 0, 0, width, height );
999             XDestroyImage( imageSrc );
1000         }
1001         wine_tsx11_unlock();
1002     }
1003     else
1004     {
1005         if (physDevSrc->depth == 1)  /* monochrome -> color */
1006         {
1007             get_colors(physDevDst, physDevSrc, &fg, &bg);
1008
1009             wine_tsx11_lock();
1010             if (X11DRV_PALETTE_XPixelToPalette)
1011             {
1012                 XSetBackground( gdi_display, gc,
1013                              X11DRV_PALETTE_XPixelToPalette[fg] );
1014                 XSetForeground( gdi_display, gc,
1015                              X11DRV_PALETTE_XPixelToPalette[bg]);
1016             }
1017             else
1018             {
1019                 XSetBackground( gdi_display, gc, fg );
1020                 XSetForeground( gdi_display, gc, bg );
1021             }
1022             XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
1023                         physDevSrc->dc_rect.left + visRectSrc->left,
1024                         physDevSrc->dc_rect.top + visRectSrc->top,
1025                         width, height, 0, 0, 1 );
1026             exposures++;
1027             wine_tsx11_unlock();
1028         }
1029         else  /* color -> monochrome */
1030         {
1031             unsigned long pixel_mask;
1032             wine_tsx11_lock();
1033             /* FIXME: avoid BadMatch error */
1034             imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
1035                                   physDevSrc->dc_rect.left + visRectSrc->left,
1036                                   physDevSrc->dc_rect.top + visRectSrc->top,
1037                                   width, height, AllPlanes, ZPixmap );
1038             if (!imageSrc)
1039             {
1040                 wine_tsx11_unlock();
1041                 return exposures;
1042             }
1043             imageDst = X11DRV_DIB_CreateXImage( width, height, physDevDst->depth );
1044             if (!imageDst)
1045             {
1046                 XDestroyImage(imageSrc);
1047                 wine_tsx11_unlock();
1048                 return exposures;
1049             }
1050             pixel_mask = image_pixel_mask( physDevSrc );
1051             for (y = 0; y < height; y++)
1052                 for (x = 0; x < width; x++)
1053                     XPutPixel(imageDst, x, y,
1054                               !((XGetPixel(imageSrc,x,y) ^ physDevSrc->backgroundPixel) & pixel_mask));
1055             XPutImage( gdi_display, pixmap, gc, imageDst,
1056                        0, 0, 0, 0, width, height );
1057             XDestroyImage( imageSrc );
1058             X11DRV_DIB_DestroyXImage( imageDst );
1059             wine_tsx11_unlock();
1060         }
1061     }
1062     return exposures;
1063 }
1064
1065
1066 /***********************************************************************
1067  *           BITBLT_GetDstArea
1068  *
1069  * Retrieve an area from the destination DC, mapping all the
1070  * pixels to Windows colors.
1071  */
1072 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, RECT *visRectDst)
1073 {
1074     int exposures = 0;
1075     INT width  = visRectDst->right - visRectDst->left;
1076     INT height = visRectDst->bottom - visRectDst->top;
1077     BOOL memdc = (GetObjectType( physDev->dev.hdc ) == OBJ_MEMDC);
1078
1079     wine_tsx11_lock();
1080
1081     if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) ||
1082         (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1083     {
1084         XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1085                    physDev->dc_rect.left + visRectDst->left, physDev->dc_rect.top + visRectDst->top,
1086                    width, height, 0, 0 );
1087         exposures++;
1088     }
1089     else
1090     {
1091         register INT x, y;
1092         XImage *image;
1093
1094         if (memdc)
1095             image = XGetImage( gdi_display, physDev->drawable,
1096                                physDev->dc_rect.left + visRectDst->left,
1097                                physDev->dc_rect.top + visRectDst->top,
1098                                width, height, AllPlanes, ZPixmap );
1099         else
1100         {
1101             /* Make sure we don't get a BadMatch error */
1102             XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1103                        physDev->dc_rect.left + visRectDst->left,
1104                        physDev->dc_rect.top + visRectDst->top,
1105                        width, height, 0, 0);
1106             exposures++;
1107             image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1108                                AllPlanes, ZPixmap );
1109         }
1110         if (image)
1111         {
1112             for (y = 0; y < height; y++)
1113                 for (x = 0; x < width; x++)
1114                     XPutPixel( image, x, y,
1115                                X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1116             XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1117             XDestroyImage( image );
1118         }
1119     }
1120
1121     wine_tsx11_unlock();
1122     return exposures;
1123 }
1124
1125
1126 /***********************************************************************
1127  *           BITBLT_PutDstArea
1128  *
1129  * Put an area back into the destination DC, mapping the pixel
1130  * colors to X pixels.
1131  */
1132 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, RECT *visRectDst)
1133 {
1134     int exposures = 0;
1135     INT width  = visRectDst->right - visRectDst->left;
1136     INT height = visRectDst->bottom - visRectDst->top;
1137
1138     /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1139
1140     if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) ||
1141         (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1142     {
1143         XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1144                    physDev->dc_rect.left + visRectDst->left,
1145                    physDev->dc_rect.top + visRectDst->top );
1146         exposures++;
1147     }
1148     else
1149     {
1150         register INT x, y;
1151         XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1152                                    AllPlanes, ZPixmap );
1153         for (y = 0; y < height; y++)
1154             for (x = 0; x < width; x++)
1155             {
1156                 XPutPixel( image, x, y,
1157                            X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1158             }
1159         XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1160                    physDev->dc_rect.left + visRectDst->left,
1161                    physDev->dc_rect.top + visRectDst->top, width, height );
1162         XDestroyImage( image );
1163     }
1164     return exposures;
1165 }
1166
1167
1168 /***********************************************************************
1169  *           client_side_dib_copy
1170  */
1171 static BOOL client_side_dib_copy( X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1172                                   X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1173                                   INT width, INT height )
1174 {
1175     DIBSECTION srcDib, dstDib;
1176     BYTE *srcPtr, *dstPtr;
1177     INT srcRowOffset, dstRowOffset;
1178     INT bytesPerPixel;
1179     INT bytesToCopy;
1180     INT y;
1181     static RECT unusedRect;
1182
1183     if (GetObjectW(physDevSrc->bitmap->hbitmap, sizeof(srcDib), &srcDib) != sizeof(srcDib))
1184       return FALSE;
1185     if (GetObjectW(physDevDst->bitmap->hbitmap, sizeof(dstDib), &dstDib) != sizeof(dstDib))
1186       return FALSE;
1187
1188     /* check for oversized values, just like X11DRV_DIB_CopyDIBSection() */
1189     if (xSrc > srcDib.dsBm.bmWidth || ySrc > srcDib.dsBm.bmHeight)
1190       return FALSE;
1191     if (xSrc + width > srcDib.dsBm.bmWidth)
1192       width = srcDib.dsBm.bmWidth - xSrc;
1193     if (ySrc + height > srcDib.dsBm.bmHeight)
1194       height = srcDib.dsBm.bmHeight - ySrc;
1195
1196     if (GetRgnBox(physDevDst->region, &unusedRect) == COMPLEXREGION)
1197     {
1198       /* for simple regions, the clipping was already done by BITBLT_GetVisRectangles */
1199       FIXME("potential optimization: client-side complex region clipping\n");
1200       return FALSE;
1201     }
1202     if (dstDib.dsBm.bmBitsPixel <= 8)
1203     {
1204       static BOOL fixme_once;
1205       if(!fixme_once++) FIXME("potential optimization: client-side color-index mode DIB copy\n");
1206       return FALSE;
1207     }
1208     if (!(srcDib.dsBmih.biCompression == BI_BITFIELDS &&
1209           dstDib.dsBmih.biCompression == BI_BITFIELDS &&
1210           !memcmp(srcDib.dsBitfields, dstDib.dsBitfields, 3*sizeof(DWORD)))
1211         && !(srcDib.dsBmih.biCompression == BI_RGB &&
1212              dstDib.dsBmih.biCompression == BI_RGB))
1213     {
1214       FIXME("potential optimization: client-side compressed DIB copy\n");
1215       return FALSE;
1216     }
1217     if (srcDib.dsBm.bmBitsPixel != dstDib.dsBm.bmBitsPixel)
1218     {
1219       FIXME("potential optimization: pixel format conversion\n");
1220       return FALSE;
1221     }
1222     if (srcDib.dsBmih.biWidth < 0 || dstDib.dsBmih.biWidth < 0)
1223     {
1224       FIXME("negative widths not yet implemented\n");
1225       return FALSE;
1226     }
1227
1228     switch (dstDib.dsBm.bmBitsPixel)
1229     {
1230       case 15:
1231       case 16:
1232         bytesPerPixel = 2;
1233         break;
1234       case 24:
1235         bytesPerPixel = 3;
1236         break;
1237       case 32:
1238         bytesPerPixel = 4;
1239         break;
1240       default:
1241         FIXME("don't know how to work with a depth of %d\n", physDevSrc->depth);
1242         return FALSE;
1243     }
1244
1245     bytesToCopy = width * bytesPerPixel;
1246
1247     if (physDevSrc->bitmap->topdown)
1248     {
1249       srcPtr = &physDevSrc->bitmap->base[ySrc*srcDib.dsBm.bmWidthBytes + xSrc*bytesPerPixel];
1250       srcRowOffset = srcDib.dsBm.bmWidthBytes;
1251     }
1252     else
1253     {
1254       srcPtr = &physDevSrc->bitmap->base[(srcDib.dsBm.bmHeight-ySrc-1)*srcDib.dsBm.bmWidthBytes
1255         + xSrc*bytesPerPixel];
1256       srcRowOffset = -srcDib.dsBm.bmWidthBytes;
1257     }
1258     if (physDevDst->bitmap->topdown)
1259     {
1260       dstPtr = &physDevDst->bitmap->base[yDst*dstDib.dsBm.bmWidthBytes + xDst*bytesPerPixel];
1261       dstRowOffset = dstDib.dsBm.bmWidthBytes;
1262     }
1263     else
1264     {
1265       dstPtr = &physDevDst->bitmap->base[(dstDib.dsBm.bmHeight-yDst-1)*dstDib.dsBm.bmWidthBytes
1266         + xDst*bytesPerPixel];
1267       dstRowOffset = -dstDib.dsBm.bmWidthBytes;
1268     }
1269
1270     /* Handle overlapping regions on the same DIB */
1271     if (physDevSrc == physDevDst && ySrc < yDst)
1272     {
1273       srcPtr += srcRowOffset * (height - 1);
1274       srcRowOffset = -srcRowOffset;
1275       dstPtr += dstRowOffset * (height - 1);
1276       dstRowOffset = -dstRowOffset;
1277     }
1278
1279     for (y = yDst; y < yDst + height; ++y)
1280     {
1281       memmove(dstPtr, srcPtr, bytesToCopy);
1282       srcPtr += srcRowOffset;
1283       dstPtr += dstRowOffset;
1284     }
1285
1286     return TRUE;
1287 }
1288
1289 static BOOL same_format(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst)
1290 {
1291     if (physDevSrc->depth != physDevDst->depth) return FALSE;
1292     if (!physDevSrc->color_shifts && !physDevDst->color_shifts) return TRUE;
1293     if (physDevSrc->color_shifts && physDevDst->color_shifts)
1294         return !memcmp(physDevSrc->color_shifts, physDevDst->color_shifts, sizeof(ColorShifts));
1295     return FALSE;
1296 }
1297
1298 /***********************************************************************
1299  *           X11DRV_PatBlt
1300  */
1301 BOOL CDECL X11DRV_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
1302 {
1303     X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
1304     BOOL usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1305     const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1306
1307     if (IsRectEmpty( &dst->visrect )) return TRUE;
1308     if (usePat && !X11DRV_SetupGCForBrush( physDev )) return TRUE;
1309
1310     X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1311
1312     wine_tsx11_lock();
1313     XSetFunction( gdi_display, physDev->gc, OP_ROP(*opcode) );
1314
1315     switch(rop)  /* a few special cases */
1316     {
1317     case BLACKNESS:  /* 0x00 */
1318     case WHITENESS:  /* 0xff */
1319         if ((physDev->depth != 1) && X11DRV_PALETTE_PaletteToXPixel)
1320         {
1321             XSetFunction( gdi_display, physDev->gc, GXcopy );
1322             if (rop == BLACKNESS)
1323                 XSetForeground( gdi_display, physDev->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1324             else
1325                 XSetForeground( gdi_display, physDev->gc,
1326                                 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1327             XSetFillStyle( gdi_display, physDev->gc, FillSolid );
1328         }
1329         break;
1330     case DSTINVERT:  /* 0x55 */
1331         if (!(X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL)))
1332         {
1333             /* Xor is much better when we do not have full colormap.   */
1334             /* Using white^black ensures that we invert at least black */
1335             /* and white. */
1336             unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1337                                      BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1338             XSetFunction( gdi_display, physDev->gc, GXxor );
1339             XSetForeground( gdi_display, physDev->gc, xor_pix);
1340             XSetFillStyle( gdi_display, physDev->gc, FillSolid );
1341         }
1342         break;
1343     }
1344     XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1345                     physDev->dc_rect.left + dst->visrect.left,
1346                     physDev->dc_rect.top + dst->visrect.top,
1347                     dst->visrect.right - dst->visrect.left,
1348                     dst->visrect.bottom - dst->visrect.top );
1349     wine_tsx11_unlock();
1350
1351     X11DRV_UnlockDIBSection( physDev, TRUE );
1352     return TRUE;
1353 }
1354
1355
1356 /***********************************************************************
1357  *           X11DRV_StretchBlt
1358  */
1359 BOOL CDECL X11DRV_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
1360                               PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
1361 {
1362     X11DRV_PDEVICE *physDevDst = get_x11drv_dev( dst_dev );
1363     X11DRV_PDEVICE *physDevSrc = get_x11drv_dev( src_dev ); /* FIXME: check that it's really an x11 dev */
1364     BOOL usePat, useDst, destUsed, fStretch, fNullBrush;
1365     INT width, height;
1366     INT sDst, sSrc = DIB_Status_None;
1367     const BYTE *opcode;
1368     Pixmap pixmaps[3] = { 0, 0, 0 };  /* pixmaps for DST, SRC, TMP */
1369     GC tmpGC = 0;
1370
1371     if (IsRectEmpty( &dst->visrect )) return TRUE;
1372
1373     usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1374     useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1375     fStretch = (src->width != dst->width) || (src->height != dst->height);
1376
1377     if (physDevDst != physDevSrc)
1378         sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None );
1379
1380     width  = dst->visrect.right - dst->visrect.left;
1381     height = dst->visrect.bottom - dst->visrect.top;
1382
1383     sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None );
1384     if (physDevDst == physDevSrc) sSrc = sDst;
1385
1386     /* try client-side DIB copy */
1387     if (!fStretch && rop == SRCCOPY &&
1388         sSrc == DIB_Status_AppMod && sDst == DIB_Status_AppMod &&
1389         same_format(physDevSrc, physDevDst))
1390     {
1391         if (client_side_dib_copy( physDevSrc, src->visrect.left, src->visrect.top,
1392                                   physDevDst, dst->visrect.left, dst->visrect.top, width, height ))
1393             goto done;
1394     }
1395
1396     X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod );
1397
1398     opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1399
1400     /* a few optimizations for single-op ROPs */
1401     if (!fStretch && !opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1402     {
1403         if (same_format(physDevSrc, physDevDst))
1404         {
1405             wine_tsx11_lock();
1406             XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1407             wine_tsx11_unlock();
1408
1409             if (physDevSrc != physDevDst)
1410             {
1411                 if (sSrc == DIB_Status_AppMod)
1412                 {
1413                     X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, src->visrect.left, src->visrect.top,
1414                                                dst->visrect.left, dst->visrect.top, width, height );
1415                     goto done;
1416                 }
1417                 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1418             }
1419             wine_tsx11_lock();
1420             XCopyArea( gdi_display, physDevSrc->drawable,
1421                        physDevDst->drawable, physDevDst->gc,
1422                        physDevSrc->dc_rect.left + src->visrect.left,
1423                        physDevSrc->dc_rect.top + src->visrect.top,
1424                        width, height,
1425                        physDevDst->dc_rect.left + dst->visrect.left,
1426                        physDevDst->dc_rect.top + dst->visrect.top );
1427             physDevDst->exposures++;
1428             wine_tsx11_unlock();
1429             goto done;
1430         }
1431         if (physDevSrc->depth == 1)
1432         {
1433             int fg, bg;
1434
1435             X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1436             get_colors(physDevDst, physDevSrc, &fg, &bg);
1437             wine_tsx11_lock();
1438             XSetBackground( gdi_display, physDevDst->gc, fg );
1439             XSetForeground( gdi_display, physDevDst->gc, bg );
1440             XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1441             XCopyPlane( gdi_display, physDevSrc->drawable,
1442                         physDevDst->drawable, physDevDst->gc,
1443                         physDevSrc->dc_rect.left + src->visrect.left,
1444                         physDevSrc->dc_rect.top + src->visrect.top,
1445                         width, height,
1446                         physDevDst->dc_rect.left + dst->visrect.left,
1447                         physDevDst->dc_rect.top + dst->visrect.top, 1 );
1448             physDevDst->exposures++;
1449             wine_tsx11_unlock();
1450             goto done;
1451         }
1452     }
1453
1454     wine_tsx11_lock();
1455     tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1456     XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1457     XSetGraphicsExposures( gdi_display, tmpGC, False );
1458     pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1459                                   physDevDst->depth );
1460     pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1461                                   physDevDst->depth );
1462     wine_tsx11_unlock();
1463
1464     if (physDevDst != physDevSrc) X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1465
1466     if(!X11DRV_XRender_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC, src, dst ))
1467     {
1468         if (fStretch)
1469             BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC, src, dst );
1470         else
1471             BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC, &src->visrect );
1472     }
1473
1474     if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &dst->visrect );
1475     if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1476     else fNullBrush = FALSE;
1477     destUsed = FALSE;
1478
1479     wine_tsx11_lock();
1480     for ( ; *opcode; opcode++)
1481     {
1482         if (OP_DST(*opcode) == DST) destUsed = TRUE;
1483         XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1484         switch(OP_SRCDST(*opcode))
1485         {
1486         case OP_ARGS(DST,TMP):
1487         case OP_ARGS(SRC,TMP):
1488             if (!pixmaps[TMP])
1489                 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1490                                               width, height, physDevDst->depth );
1491             /* fall through */
1492         case OP_ARGS(DST,SRC):
1493         case OP_ARGS(SRC,DST):
1494         case OP_ARGS(TMP,SRC):
1495         case OP_ARGS(TMP,DST):
1496             XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1497                        pixmaps[OP_DST(*opcode)], tmpGC,
1498                        0, 0, width, height, 0, 0 );
1499             break;
1500
1501         case OP_ARGS(PAT,TMP):
1502             if (!pixmaps[TMP] && !fNullBrush)
1503                 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1504                                               width, height, physDevDst->depth );
1505             /* fall through */
1506         case OP_ARGS(PAT,DST):
1507         case OP_ARGS(PAT,SRC):
1508             if (!fNullBrush)
1509                 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1510                                 tmpGC, 0, 0, width, height );
1511             break;
1512         }
1513     }
1514     XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1515     physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC], &dst->visrect );
1516     XFreePixmap( gdi_display, pixmaps[DST] );
1517     if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1518     if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1519     XFreeGC( gdi_display, tmpGC );
1520     wine_tsx11_unlock();
1521
1522 done:
1523     if (physDevDst != physDevSrc) X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1524     X11DRV_UnlockDIBSection( physDevDst, TRUE );
1525     return TRUE;
1526 }
1527
1528
1529 /***********************************************************************
1530  *           X11DRV_AlphaBlend
1531  */
1532 BOOL CDECL X11DRV_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
1533                               PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
1534 {
1535     X11DRV_PDEVICE *physDevDst = get_x11drv_dev( dst_dev );
1536     X11DRV_PDEVICE *physDevSrc = get_x11drv_dev( src_dev ); /* FIXME: check that it's really an x11 dev */
1537
1538     if (src->x < 0 || src->y < 0 || src->width < 0 || src->height < 0 ||
1539         src->width > physDevSrc->drawable_rect.right - physDevSrc->drawable_rect.left - src->x ||
1540         src->height > physDevSrc->drawable_rect.bottom - physDevSrc->drawable_rect.top - src->y)
1541     {
1542         WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src->x, src->y, src->width, src->height );
1543         SetLastError( ERROR_INVALID_PARAMETER );
1544         return FALSE;
1545     }
1546     if (IsRectEmpty( &dst->visrect )) return TRUE;
1547
1548     return XRender_AlphaBlend( physDevDst, dst, physDevSrc, src, blendfn );
1549 }