wined3d: Fix WINED3DFMT_R3G3B2.
[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(SRC,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->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 /***********************************************************************
556  *           BITBLT_StretchRow
557  *
558  * Stretch a row of pixels. Helper function for BITBLT_StretchImage.
559  */
560 static void BITBLT_StretchRow( int *rowSrc, int *rowDst,
561                                INT startDst, INT widthDst,
562                                INT xinc, INT xoff, WORD mode )
563 {
564     register INT xsrc = xinc * startDst + xoff;
565     rowDst += startDst;
566     switch(mode)
567     {
568     case STRETCH_ANDSCANS:
569         for(; widthDst > 0; widthDst--, xsrc += xinc)
570             *rowDst++ &= rowSrc[xsrc >> 16];
571         break;
572     case STRETCH_ORSCANS:
573         for(; widthDst > 0; widthDst--, xsrc += xinc)
574             *rowDst++ |= rowSrc[xsrc >> 16];
575         break;
576     case STRETCH_DELETESCANS:
577         for(; widthDst > 0; widthDst--, xsrc += xinc)
578             *rowDst++ = rowSrc[xsrc >> 16];
579         break;
580     }
581 }
582
583
584 /***********************************************************************
585  *           BITBLT_ShrinkRow
586  *
587  * Shrink a row of pixels. Helper function for BITBLT_StretchImage.
588  */
589 static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst,
590                               INT startSrc, INT widthSrc,
591                               INT xinc, INT xoff, WORD mode )
592 {
593     register INT xdst = xinc * startSrc + xoff;
594     rowSrc += startSrc;
595     switch(mode)
596     {
597     case STRETCH_ORSCANS:
598         for(; widthSrc > 0; widthSrc--, xdst += xinc)
599             rowDst[xdst >> 16] |= *rowSrc++;
600         break;
601     case STRETCH_ANDSCANS:
602         for(; widthSrc > 0; widthSrc--, xdst += xinc)
603             rowDst[xdst >> 16] &= *rowSrc++;
604         break;
605     case STRETCH_DELETESCANS:
606         for(; widthSrc > 0; widthSrc--, xdst += xinc)
607             rowDst[xdst >> 16] = *rowSrc++;
608         break;
609     }
610 }
611
612
613 /***********************************************************************
614  *           BITBLT_GetRow
615  *
616  * Retrieve a row from an image. Helper function for BITBLT_StretchImage.
617  */
618 static void BITBLT_GetRow( XImage *image, int *pdata, INT row,
619                            INT start, INT width, INT depthDst,
620                            int fg, int bg, BOOL swap)
621 {
622     register INT i;
623
624     assert( (row >= 0) && (row < image->height) );
625     assert( (start >= 0) && (width <= image->width) );
626
627     pdata += swap ? start+width-1 : start;
628     if (image->depth == depthDst)  /* color -> color */
629     {
630         if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1))
631             if (swap) for (i = 0; i < width; i++)
632                 *pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
633             else for (i = 0; i < width; i++)
634                 *pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
635         else
636             if (swap) for (i = 0; i < width; i++)
637                 *pdata-- = XGetPixel( image, i, row );
638             else for (i = 0; i < width; i++)
639                 *pdata++ = XGetPixel( image, i, row );
640     }
641     else
642     {
643         if (image->depth == 1)  /* monochrome -> color */
644         {
645             if (X11DRV_PALETTE_XPixelToPalette)
646             {
647                 fg = X11DRV_PALETTE_XPixelToPalette[fg];
648                 bg = X11DRV_PALETTE_XPixelToPalette[bg];
649             }
650             if (swap) for (i = 0; i < width; i++)
651                 *pdata-- = XGetPixel( image, i, row ) ? bg : fg;
652             else for (i = 0; i < width; i++)
653                 *pdata++ = XGetPixel( image, i, row ) ? bg : fg;
654         }
655         else  /* color -> monochrome */
656         {
657             if (swap) for (i = 0; i < width; i++)
658                 *pdata-- = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
659             else for (i = 0; i < width; i++)
660                 *pdata++ = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
661         }
662     }
663 }
664
665
666 /***********************************************************************
667  *           BITBLT_StretchImage
668  *
669  * Stretch an X image.
670  * FIXME: does not work for full 32-bit coordinates.
671  */
672 static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage,
673                                  INT widthSrc, INT heightSrc,
674                                  INT widthDst, INT heightDst,
675                                  RECT *visRectSrc, RECT *visRectDst,
676                                  int foreground, int background, WORD mode )
677 {
678     int *rowSrc, *rowDst, *pixel;
679     char *pdata;
680     INT xinc, xoff, yinc, ysrc, ydst;
681     register INT x, y;
682     BOOL hstretch, vstretch, hswap, vswap;
683
684     hswap = ((int)widthSrc * widthDst) < 0;
685     vswap = ((int)heightSrc * heightDst) < 0;
686     widthSrc  = abs(widthSrc);
687     heightSrc = abs(heightSrc);
688     widthDst  = abs(widthDst);
689     heightDst = abs(heightDst);
690
691     if (!(rowSrc = HeapAlloc( GetProcessHeap(), 0,
692                               (widthSrc+widthDst)*sizeof(int) ))) return;
693     rowDst = rowSrc + widthSrc;
694
695       /* When stretching, all modes are the same, and DELETESCANS is faster */
696     if ((widthSrc < widthDst) && (heightSrc < heightDst))
697         mode = STRETCH_DELETESCANS;
698
699     if (mode == STRETCH_HALFTONE) /* FIXME */
700         mode = STRETCH_DELETESCANS;
701
702     if (mode != STRETCH_DELETESCANS)
703         memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
704                 widthDst*sizeof(int) );
705
706     hstretch = (widthSrc < widthDst);
707     vstretch = (heightSrc < heightDst);
708
709     if (hstretch)
710     {
711         xinc = ((int)widthSrc << 16) / widthDst;
712         xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
713     }
714     else
715     {
716         xinc = ((int)widthDst << 16) / widthSrc;
717         xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
718     }
719
720     if (vstretch)
721     {
722         yinc = ((int)heightSrc << 16) / heightDst;
723         ydst = visRectDst->top;
724         if (vswap)
725         {
726             ysrc = yinc * (heightDst - ydst - 1);
727             yinc = -yinc;
728         }
729         else
730             ysrc = yinc * ydst;
731
732         for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
733         {
734             if (((ysrc >> 16) < visRectSrc->top) ||
735                 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
736
737             /* Retrieve a source row */
738             BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
739                            hswap ? widthSrc - visRectSrc->right
740                                  : visRectSrc->left,
741                            visRectSrc->right - visRectSrc->left,
742                            dstImage->depth, foreground, background, hswap );
743
744             /* Stretch or shrink it */
745             if (hstretch)
746                 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
747                                    visRectDst->right - visRectDst->left,
748                                    xinc, xoff, mode );
749             else BITBLT_ShrinkRow( rowSrc, rowDst,
750                                    hswap ? widthSrc - visRectSrc->right
751                                          : visRectSrc->left,
752                                    visRectSrc->right - visRectSrc->left,
753                                    xinc, xoff, mode );
754
755             /* Store the destination row */
756             pixel = rowDst + visRectDst->right - 1;
757             y = ydst - visRectDst->top;
758             for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
759                 XPutPixel( dstImage, x, y, *pixel-- );
760             if (mode != STRETCH_DELETESCANS)
761                 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
762                         widthDst*sizeof(int) );
763
764             /* Make copies of the destination row */
765
766             pdata = dstImage->data + dstImage->bytes_per_line * y;
767             while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
768                    (ydst < visRectDst->bottom-1))
769             {
770                 memcpy( pdata + dstImage->bytes_per_line, pdata,
771                         dstImage->bytes_per_line );
772                 pdata += dstImage->bytes_per_line;
773                 ysrc += yinc;
774                 ydst++;
775             }
776         }
777     }
778     else  /* Shrinking */
779     {
780         yinc = ((int)heightDst << 16) / heightSrc;
781         ysrc = visRectSrc->top;
782         ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
783         if (vswap)
784         {
785             ydst += yinc * (heightSrc - ysrc - 1);
786             yinc = -yinc;
787         }
788         else
789             ydst += yinc * ysrc;
790
791         for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
792         {
793             if (((ydst >> 16) < visRectDst->top) ||
794                 ((ydst >> 16) >= visRectDst->bottom)) continue;
795
796             /* Retrieve a source row */
797             BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
798                            hswap ? widthSrc - visRectSrc->right
799                                  : visRectSrc->left,
800                            visRectSrc->right - visRectSrc->left,
801                            dstImage->depth, foreground, background, hswap );
802
803             /* Stretch or shrink it */
804             if (hstretch)
805                 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
806                                    visRectDst->right - visRectDst->left,
807                                    xinc, xoff, mode );
808             else BITBLT_ShrinkRow( rowSrc, rowDst,
809                                    hswap ? widthSrc - visRectSrc->right
810                                          : visRectSrc->left,
811                                    visRectSrc->right - visRectSrc->left,
812                                    xinc, xoff, mode );
813
814             /* Merge several source rows into the destination */
815             if (mode == STRETCH_DELETESCANS)
816             {
817                 /* Simply skip the overlapping rows */
818                 while (((ydst + yinc) >> 16 == ydst >> 16) &&
819                        (ysrc < visRectSrc->bottom-1))
820                 {
821                     ydst += yinc;
822                     ysrc++;
823                 }
824             }
825             else if (((ydst + yinc) >> 16 == ydst >> 16) &&
826                      (ysrc < visRectSrc->bottom-1))
827                 continue;  /* Restart loop for next overlapping row */
828
829             /* Store the destination row */
830             pixel = rowDst + visRectDst->right - 1;
831             y = (ydst >> 16) - visRectDst->top;
832             for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
833                 XPutPixel( dstImage, x, y, *pixel-- );
834             if (mode != STRETCH_DELETESCANS)
835                 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
836                         widthDst*sizeof(int) );
837         }
838     }
839     HeapFree( GetProcessHeap(), 0, rowSrc );
840 }
841
842
843 /***********************************************************************
844  *           BITBLT_GetSrcAreaStretch
845  *
846  * Retrieve an area from the source DC, stretching and mapping all the
847  * pixels to Windows colors.
848  */
849 static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
850                                       Pixmap pixmap, GC gc,
851                                       INT xSrc, INT ySrc,
852                                       INT widthSrc, INT heightSrc,
853                                       INT xDst, INT yDst,
854                                       INT widthDst, INT heightDst,
855                                       RECT *visRectSrc, RECT *visRectDst )
856 {
857     XImage *imageSrc, *imageDst;
858     RECT rectSrc = *visRectSrc;
859     RECT rectDst = *visRectDst;
860     int fg, bg;
861
862     if (widthSrc < 0) xSrc += widthSrc;
863     if (widthDst < 0) xDst += widthDst;
864     if (heightSrc < 0) ySrc += heightSrc;
865     if (heightDst < 0) yDst += heightDst;
866     rectSrc.left   -= xSrc;
867     rectSrc.right  -= xSrc;
868     rectSrc.top    -= ySrc;
869     rectSrc.bottom -= ySrc;
870     rectDst.left   -= xDst;
871     rectDst.right  -= xDst;
872     rectDst.top    -= yDst;
873     rectDst.bottom -= yDst;
874
875     get_colors(physDevDst, physDevSrc, &fg, &bg);
876     /* FIXME: avoid BadMatch errors */
877     imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
878                           physDevSrc->dc_rect.left + visRectSrc->left,
879                           physDevSrc->dc_rect.top + visRectSrc->top,
880                           visRectSrc->right - visRectSrc->left,
881                           visRectSrc->bottom - visRectSrc->top,
882                           AllPlanes, ZPixmap );
883     imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
884                                         rectDst.bottom - rectDst.top, physDevDst->depth );
885     BITBLT_StretchImage( imageSrc, imageDst, widthSrc, heightSrc,
886                          widthDst, heightDst, &rectSrc, &rectDst,
887                          fg, physDevDst->depth != 1 ?
888                          bg : physDevSrc->backgroundPixel,
889                          GetStretchBltMode(physDevDst->hdc) );
890     XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
891                rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
892     XDestroyImage( imageSrc );
893     XDestroyImage( imageDst );
894     return 0;  /* no exposure events generated */
895 }
896
897
898 /***********************************************************************
899  *           BITBLT_GetSrcArea
900  *
901  * Retrieve an area from the source DC, mapping all the
902  * pixels to Windows colors.
903  */
904 static int BITBLT_GetSrcArea( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
905                               Pixmap pixmap, GC gc, INT xSrc, INT ySrc, RECT *visRectSrc )
906 {
907     XImage *imageSrc, *imageDst;
908     register INT x, y;
909     int exposures = 0;
910     INT width  = visRectSrc->right - visRectSrc->left;
911     INT height = visRectSrc->bottom - visRectSrc->top;
912     int fg, bg;
913
914     if (physDevSrc->depth == physDevDst->depth)
915     {
916         if (!X11DRV_PALETTE_XPixelToPalette ||
917             (physDevDst->depth == 1))  /* monochrome -> monochrome */
918         {
919             if (physDevDst->depth == 1)
920             {
921                 /* MSDN says if StretchBlt must convert a bitmap from monochrome
922                    to color or vice versa, the forground and background color of
923                    the device context are used.  In fact, it also applies to the
924                    case when it is converted from mono to mono. */
925                 XSetBackground( gdi_display, gc, physDevDst->textPixel );
926                 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
927                 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
928                             physDevSrc->dc_rect.left + visRectSrc->left,
929                             physDevSrc->dc_rect.top + visRectSrc->top,
930                             width, height, 0, 0, 1);
931             }
932             else
933                 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
934                            physDevSrc->dc_rect.left + visRectSrc->left,
935                            physDevSrc->dc_rect.top + visRectSrc->top,
936                            width, height, 0, 0);
937             exposures++;
938         }
939         else  /* color -> color */
940         {
941             if (GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
942                 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
943                                       physDevSrc->dc_rect.left + visRectSrc->left,
944                                       physDevSrc->dc_rect.top + visRectSrc->top,
945                                       width, height, AllPlanes, ZPixmap );
946             else
947             {
948                 /* Make sure we don't get a BadMatch error */
949                 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
950                            physDevSrc->dc_rect.left + visRectSrc->left,
951                            physDevSrc->dc_rect.top + visRectSrc->top,
952                            width, height, 0, 0);
953                 exposures++;
954                 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
955                                       AllPlanes, ZPixmap );
956             }
957             for (y = 0; y < height; y++)
958                 for (x = 0; x < width; x++)
959                     XPutPixel(imageSrc, x, y,
960                               X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
961             XPutImage( gdi_display, pixmap, gc, imageSrc,
962                        0, 0, 0, 0, width, height );
963             XDestroyImage( imageSrc );
964         }
965     }
966     else
967     {
968         if (physDevSrc->depth == 1)  /* monochrome -> color */
969         {
970             get_colors(physDevDst, physDevSrc, &fg, &bg);
971
972             if (X11DRV_PALETTE_XPixelToPalette)
973             {
974                 XSetBackground( gdi_display, gc,
975                              X11DRV_PALETTE_XPixelToPalette[fg] );
976                 XSetForeground( gdi_display, gc,
977                              X11DRV_PALETTE_XPixelToPalette[bg]);
978             }
979             else
980             {
981                 XSetBackground( gdi_display, gc, fg );
982                 XSetForeground( gdi_display, gc, bg );
983             }
984             XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
985                         physDevSrc->dc_rect.left + visRectSrc->left,
986                         physDevSrc->dc_rect.top + visRectSrc->top,
987                         width, height, 0, 0, 1 );
988             exposures++;
989         }
990         else  /* color -> monochrome */
991         {
992             /* FIXME: avoid BadMatch error */
993             imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
994                                   physDevSrc->dc_rect.left + visRectSrc->left,
995                                   physDevSrc->dc_rect.top + visRectSrc->top,
996                                   width, height, AllPlanes, ZPixmap );
997             if (!imageSrc)
998             {
999                 return exposures;
1000             }
1001             imageDst = X11DRV_DIB_CreateXImage( width, height, physDevDst->depth );
1002             if (!imageDst) 
1003             {
1004                 XDestroyImage(imageSrc);
1005                 return exposures;
1006             }
1007             for (y = 0; y < height; y++)
1008                 for (x = 0; x < width; x++)
1009                     XPutPixel(imageDst, x, y, (XGetPixel(imageSrc,x,y) ==
1010                                                physDevSrc->backgroundPixel) );
1011             XPutImage( gdi_display, pixmap, gc, imageDst,
1012                        0, 0, 0, 0, width, height );
1013             XDestroyImage( imageSrc );
1014             XDestroyImage( imageDst );
1015         }
1016     }
1017     return exposures;
1018 }
1019
1020
1021 /***********************************************************************
1022  *           BITBLT_GetDstArea
1023  *
1024  * Retrieve an area from the destination DC, mapping all the
1025  * pixels to Windows colors.
1026  */
1027 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, RECT *visRectDst)
1028 {
1029     int exposures = 0;
1030     INT width  = visRectDst->right - visRectDst->left;
1031     INT height = visRectDst->bottom - visRectDst->top;
1032
1033     if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) ||
1034         (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1035     {
1036         XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1037                    physDev->dc_rect.left + visRectDst->left, physDev->dc_rect.top + visRectDst->top,
1038                    width, height, 0, 0 );
1039         exposures++;
1040     }
1041     else
1042     {
1043         register INT x, y;
1044         XImage *image;
1045
1046         if (GetObjectType( physDev->hdc ) == OBJ_MEMDC)
1047             image = XGetImage( gdi_display, physDev->drawable,
1048                                physDev->dc_rect.left + visRectDst->left,
1049                                physDev->dc_rect.top + visRectDst->top,
1050                                width, height, AllPlanes, ZPixmap );
1051         else
1052         {
1053             /* Make sure we don't get a BadMatch error */
1054             XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1055                        physDev->dc_rect.left + visRectDst->left,
1056                        physDev->dc_rect.top + visRectDst->top,
1057                        width, height, 0, 0);
1058             exposures++;
1059             image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1060                                AllPlanes, ZPixmap );
1061         }
1062         for (y = 0; y < height; y++)
1063             for (x = 0; x < width; x++)
1064                 XPutPixel( image, x, y,
1065                            X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1066         XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1067         XDestroyImage( image );
1068     }
1069     return exposures;
1070 }
1071
1072
1073 /***********************************************************************
1074  *           BITBLT_PutDstArea
1075  *
1076  * Put an area back into the destination DC, mapping the pixel
1077  * colors to X pixels.
1078  */
1079 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, RECT *visRectDst)
1080 {
1081     int exposures = 0;
1082     INT width  = visRectDst->right - visRectDst->left;
1083     INT height = visRectDst->bottom - visRectDst->top;
1084
1085     /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1086
1087     if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) ||
1088         (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1089     {
1090         XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1091                    physDev->dc_rect.left + visRectDst->left,
1092                    physDev->dc_rect.top + visRectDst->top );
1093         exposures++;
1094     }
1095     else
1096     {
1097         register INT x, y;
1098         XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1099                                    AllPlanes, ZPixmap );
1100         for (y = 0; y < height; y++)
1101             for (x = 0; x < width; x++)
1102             {
1103                 XPutPixel( image, x, y,
1104                            X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1105             }
1106         XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1107                    physDev->dc_rect.left + visRectDst->left,
1108                    physDev->dc_rect.top + visRectDst->top, width, height );
1109         XDestroyImage( image );
1110     }
1111     return exposures;
1112 }
1113
1114
1115 /***********************************************************************
1116  *           BITBLT_GetVisRectangles
1117  *
1118  * Get the source and destination visible rectangles for StretchBlt().
1119  * Return FALSE if one of the rectangles is empty.
1120  */
1121 static BOOL BITBLT_GetVisRectangles( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1122                                      INT widthDst, INT heightDst,
1123                                      X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1124                                      INT widthSrc, INT heightSrc,
1125                                      RECT *visRectSrc, RECT *visRectDst )
1126 {
1127     RECT rect, clipRect;
1128
1129       /* Get the destination visible rectangle */
1130
1131     rect.left   = xDst;
1132     rect.top    = yDst;
1133     rect.right  = xDst + widthDst;
1134     rect.bottom = yDst + heightDst;
1135     if (widthDst < 0) SWAP_INT32( &rect.left, &rect.right );
1136     if (heightDst < 0) SWAP_INT32( &rect.top, &rect.bottom );
1137     GetRgnBox( physDevDst->region, &clipRect );
1138     if (!IntersectRect( visRectDst, &rect, &clipRect )) return FALSE;
1139
1140       /* Get the source visible rectangle */
1141
1142     if (!physDevSrc) return TRUE;
1143     rect.left   = xSrc;
1144     rect.top    = ySrc;
1145     rect.right  = xSrc + widthSrc;
1146     rect.bottom = ySrc + heightSrc;
1147     if (widthSrc < 0) SWAP_INT32( &rect.left, &rect.right );
1148     if (heightSrc < 0) SWAP_INT32( &rect.top, &rect.bottom );
1149     /* Apparently the clipping and visible regions are only for output,
1150        so just check against dc extent here to avoid BadMatch errors */
1151     clipRect = physDevSrc->drawable_rect;
1152     OffsetRect( &clipRect, -(physDevSrc->drawable_rect.left + physDevSrc->dc_rect.left),
1153                 -(physDevSrc->drawable_rect.top + physDevSrc->dc_rect.top) );
1154     if (!IntersectRect( visRectSrc, &rect, &clipRect ))
1155         return FALSE;
1156
1157       /* Intersect the rectangles */
1158
1159     if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1160     {
1161         visRectSrc->left   += xDst - xSrc;
1162         visRectSrc->right  += xDst - xSrc;
1163         visRectSrc->top    += yDst - ySrc;
1164         visRectSrc->bottom += yDst - ySrc;
1165         if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1166         *visRectSrc = *visRectDst = rect;
1167         visRectSrc->left   += xSrc - xDst;
1168         visRectSrc->right  += xSrc - xDst;
1169         visRectSrc->top    += ySrc - yDst;
1170         visRectSrc->bottom += ySrc - yDst;
1171     }
1172     else  /* stretching */
1173     {
1174         /* Map source rectangle into destination coordinates */
1175         rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1176         rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1177         rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1178         rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1179         if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1180         if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1181
1182         /* Avoid rounding errors */
1183         rect.left--;
1184         rect.top--;
1185         rect.right++;
1186         rect.bottom++;
1187         if (!IntersectRect( visRectDst, &rect, visRectDst )) return FALSE;
1188
1189         /* Map destination rectangle back to source coordinates */
1190         rect = *visRectDst;
1191         rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1192         rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1193         rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1194         rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1195         if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1196         if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1197
1198         /* Avoid rounding errors */
1199         rect.left--;
1200         rect.top--;
1201         rect.right++;
1202         rect.bottom++;
1203         if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1204     }
1205     return TRUE;
1206 }
1207
1208
1209 /***********************************************************************
1210  *           BITBLT_InternalStretchBlt
1211  *
1212  * Implementation of PatBlt(), BitBlt() and StretchBlt().
1213  */
1214 static BOOL BITBLT_InternalStretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1215                                        INT widthDst, INT heightDst,
1216                                        X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1217                                        INT widthSrc, INT heightSrc,
1218                                        DWORD rop )
1219 {
1220     BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1221     RECT visRectDst, visRectSrc;
1222     INT width, height;
1223     const BYTE *opcode;
1224     Pixmap pixmaps[3] = { 0, 0, 0 };  /* pixmaps for DST, SRC, TMP */
1225     GC tmpGC = 0;
1226     POINT pts[2];
1227
1228     /* compensate for off-by-one shifting for negative widths and heights */
1229     if (widthDst < 0)
1230         ++xDst;
1231     if (heightDst < 0)
1232         ++yDst;
1233     if (widthSrc < 0)
1234         ++xSrc;
1235     if (heightSrc < 0)
1236         ++ySrc;
1237
1238     usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1239     useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1240     useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1241     if (!physDevSrc && useSrc) return FALSE;
1242
1243       /* Map the coordinates to device coords */
1244
1245     pts[0].x = xDst;
1246     pts[0].y = yDst;
1247     pts[1].x = xDst + widthDst;
1248     pts[1].y = yDst + heightDst;
1249     LPtoDP(physDevDst->hdc, pts, 2);
1250     xDst      = pts[0].x;
1251     yDst      = pts[0].y;
1252     widthDst  = pts[1].x - pts[0].x;
1253     heightDst = pts[1].y - pts[0].y;
1254
1255     TRACE("    rectdst=%d,%d-%d,%d orgdst=%d,%d\n",
1256                     xDst, yDst, widthDst, heightDst,
1257                     physDevDst->dc_rect.left, physDevDst->dc_rect.top );
1258
1259     if (useSrc)
1260     {
1261         pts[0].x = xSrc;
1262         pts[0].y = ySrc;
1263         pts[1].x = xSrc + widthSrc;
1264         pts[1].y = ySrc + heightSrc;
1265         LPtoDP(physDevSrc->hdc, pts, 2);
1266         xSrc      = pts[0].x;
1267         ySrc      = pts[0].y;
1268         widthSrc  = pts[1].x - pts[0].x;
1269         heightSrc = pts[1].y - pts[0].y;
1270
1271         fStretch  = (widthSrc != widthDst) || (heightSrc != heightDst);
1272         TRACE("    rectsrc=%d,%d-%d,%d orgsrc=%d,%d\n",
1273                         xSrc, ySrc, widthSrc, heightSrc,
1274                         physDevSrc->dc_rect.left, physDevSrc->dc_rect.top );
1275         if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1276                                       physDevSrc, xSrc, ySrc, widthSrc, heightSrc,
1277                                       &visRectSrc, &visRectDst ))
1278             return TRUE;
1279         TRACE("    vissrc=%d,%d-%d,%d visdst=%d,%d-%d,%d\n",
1280                         visRectSrc.left, visRectSrc.top,
1281                         visRectSrc.right, visRectSrc.bottom,
1282                         visRectDst.left, visRectDst.top,
1283                         visRectDst.right, visRectDst.bottom );
1284     }
1285     else
1286     {
1287         fStretch = FALSE;
1288         if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1289                                       NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1290             return TRUE;
1291         TRACE("    vissrc=none visdst=%d,%d-%d,%d\n",
1292                         visRectDst.left, visRectDst.top,
1293                         visRectDst.right, visRectDst.bottom );
1294     }
1295
1296     width  = visRectDst.right - visRectDst.left;
1297     height = visRectDst.bottom - visRectDst.top;
1298
1299     if (!fStretch) switch(rop)  /* A few optimisations */
1300     {
1301     case BLACKNESS:  /* 0x00 */
1302         wine_tsx11_lock();
1303         if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1304             XSetFunction( gdi_display, physDevDst->gc, GXclear );
1305         else
1306         {
1307             XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1308             XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1309             XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1310         }
1311         XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1312                         physDevDst->dc_rect.left + visRectDst.left,
1313                         physDevDst->dc_rect.top + visRectDst.top,
1314                         width, height );
1315         wine_tsx11_unlock();
1316         return TRUE;
1317
1318     case DSTINVERT:  /* 0x55 */
1319         wine_tsx11_lock();
1320         XSetFunction( gdi_display, physDevDst->gc, GXinvert );
1321
1322         if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1323             XSetFunction( gdi_display, physDevDst->gc, GXinvert);
1324         else
1325         {
1326             /* Xor is much better when we do not have full colormap.   */
1327             /* Using white^black ensures that we invert at least black */
1328             /* and white. */
1329             unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1330                                      BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1331             XSetFunction( gdi_display, physDevDst->gc, GXxor );
1332             XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1333             XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1334         }
1335         XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1336                         physDevDst->dc_rect.left + visRectDst.left,
1337                         physDevDst->dc_rect.top + visRectDst.top,
1338                         width, height );
1339         wine_tsx11_unlock();
1340         return TRUE;
1341
1342     case PATINVERT:  /* 0x5a */
1343         if (X11DRV_SetupGCForBrush( physDevDst ))
1344         {
1345             wine_tsx11_lock();
1346             XSetFunction( gdi_display, physDevDst->gc, GXxor );
1347             XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1348                             physDevDst->dc_rect.left + visRectDst.left,
1349                             physDevDst->dc_rect.top + visRectDst.top,
1350                             width, height );
1351             wine_tsx11_unlock();
1352         }
1353         return TRUE;
1354
1355     case 0xa50065:
1356         if (X11DRV_SetupGCForBrush( physDevDst ))
1357         {
1358             wine_tsx11_lock();
1359             XSetFunction( gdi_display, physDevDst->gc, GXequiv );
1360             XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1361                             physDevDst->dc_rect.left + visRectDst.left,
1362                             physDevDst->dc_rect.top + visRectDst.top,
1363                             width, height );
1364             wine_tsx11_unlock();
1365         }
1366         return TRUE;
1367
1368     case SRCCOPY:  /* 0xcc */
1369         if (physDevSrc->depth == physDevDst->depth)
1370         {
1371             wine_tsx11_lock();
1372             XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1373             XCopyArea( gdi_display, physDevSrc->drawable,
1374                        physDevDst->drawable, physDevDst->gc,
1375                        physDevSrc->dc_rect.left + visRectSrc.left,
1376                        physDevSrc->dc_rect.top + visRectSrc.top,
1377                        width, height,
1378                        physDevDst->dc_rect.left + visRectDst.left,
1379                        physDevDst->dc_rect.top + visRectDst.top );
1380             physDevDst->exposures++;
1381             wine_tsx11_unlock();
1382             return TRUE;
1383         }
1384
1385         if (physDevSrc->depth == 1)
1386         {
1387             int fg, bg;
1388             get_colors(physDevDst, physDevSrc, &fg, &bg);
1389             wine_tsx11_lock();
1390
1391             XSetBackground( gdi_display, physDevDst->gc, fg );
1392             XSetForeground( gdi_display, physDevDst->gc, bg );
1393             XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1394             XCopyPlane( gdi_display, physDevSrc->drawable,
1395                         physDevDst->drawable, physDevDst->gc,
1396                         physDevSrc->dc_rect.left + visRectSrc.left,
1397                         physDevSrc->dc_rect.top + visRectSrc.top,
1398                         width, height,
1399                         physDevDst->dc_rect.left + visRectDst.left,
1400                         physDevDst->dc_rect.top + visRectDst.top, 1 );
1401             physDevDst->exposures++;
1402             wine_tsx11_unlock();
1403             return TRUE;
1404         }
1405         break;
1406
1407     case PATCOPY:  /* 0xf0 */
1408         if (!X11DRV_SetupGCForBrush( physDevDst )) return TRUE;
1409         wine_tsx11_lock();
1410         XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1411         XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1412                         physDevDst->dc_rect.left + visRectDst.left,
1413                         physDevDst->dc_rect.top + visRectDst.top,
1414                         width, height );
1415         wine_tsx11_unlock();
1416         return TRUE;
1417
1418     case WHITENESS:  /* 0xff */
1419         wine_tsx11_lock();
1420         if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1421             XSetFunction( gdi_display, physDevDst->gc, GXset );
1422         else
1423         {
1424             XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1425             XSetForeground( gdi_display, physDevDst->gc,
1426                             WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1427             XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1428         }
1429         XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1430                         physDevDst->dc_rect.left + visRectDst.left,
1431                         physDevDst->dc_rect.top + visRectDst.top,
1432                         width, height );
1433         wine_tsx11_unlock();
1434         return TRUE;
1435     }
1436
1437     wine_tsx11_lock();
1438
1439     tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1440     XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1441     XSetGraphicsExposures( gdi_display, tmpGC, False );
1442     pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1443                                   physDevDst->depth );
1444     if (useSrc)
1445     {
1446         pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1447                                       physDevDst->depth );
1448         if (fStretch)
1449             BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1450                                       xSrc, ySrc, widthSrc, heightSrc,
1451                                       xDst, yDst, widthDst, heightDst,
1452                                       &visRectSrc, &visRectDst );
1453         else
1454             BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1455                                xSrc, ySrc, &visRectSrc );
1456     }
1457
1458     if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &visRectDst );
1459     if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1460     else fNullBrush = FALSE;
1461     destUsed = FALSE;
1462
1463     for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1464     {
1465         if (OP_DST(*opcode) == DST) destUsed = TRUE;
1466         XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1467         switch(OP_SRCDST(*opcode))
1468         {
1469         case OP_ARGS(DST,TMP):
1470         case OP_ARGS(SRC,TMP):
1471             if (!pixmaps[TMP])
1472                 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1473                                               width, height, physDevDst->depth );
1474             /* fall through */
1475         case OP_ARGS(DST,SRC):
1476         case OP_ARGS(SRC,DST):
1477         case OP_ARGS(TMP,SRC):
1478         case OP_ARGS(TMP,DST):
1479             if (useSrc)
1480                 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1481                            pixmaps[OP_DST(*opcode)], tmpGC,
1482                            0, 0, width, height, 0, 0 );
1483             break;
1484
1485         case OP_ARGS(PAT,TMP):
1486             if (!pixmaps[TMP] && !fNullBrush)
1487                 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1488                                               width, height, physDevDst->depth );
1489             /* fall through */
1490         case OP_ARGS(PAT,DST):
1491         case OP_ARGS(PAT,SRC):
1492             if (!fNullBrush)
1493                 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1494                                 tmpGC, 0, 0, width, height );
1495             break;
1496         }
1497     }
1498     XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1499     physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC],
1500                                                 &visRectDst );
1501     XFreePixmap( gdi_display, pixmaps[DST] );
1502     if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1503     if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1504     XFreeGC( gdi_display, tmpGC );
1505     wine_tsx11_unlock();
1506     return TRUE;
1507 }
1508
1509
1510 /***********************************************************************
1511  *           X11DRV_PatBlt
1512  */
1513 BOOL X11DRV_PatBlt( X11DRV_PDEVICE *physDev, INT left, INT top, INT width, INT height, DWORD rop )
1514 {
1515     BOOL result;
1516
1517     X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1518     result = BITBLT_InternalStretchBlt( physDev, left, top, width, height, NULL, 0, 0, 0, 0, rop );
1519     X11DRV_UnlockDIBSection( physDev, TRUE );
1520     return result;
1521 }
1522
1523
1524 /***********************************************************************
1525  *           X11DRV_ClientSideDIBCopy
1526  */
1527 static BOOL X11DRV_ClientSideDIBCopy( X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1528                                       X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1529                                       INT width, INT height )
1530 {
1531     DIBSECTION srcDib, dstDib;
1532     BYTE *srcPtr, *dstPtr;
1533     INT srcRowOffset, dstRowOffset;
1534     INT bytesPerPixel;
1535     INT bytesToCopy;
1536     INT y;
1537     static RECT unusedRect;
1538
1539     if (GetObjectW(physDevSrc->bitmap->hbitmap, sizeof(srcDib), &srcDib) != sizeof(srcDib))
1540       return FALSE;
1541     if (GetObjectW(physDevDst->bitmap->hbitmap, sizeof(dstDib), &dstDib) != sizeof(dstDib))
1542       return FALSE;
1543
1544     /* check for oversized values, just like X11DRV_DIB_CopyDIBSection() */
1545     if (xSrc > srcDib.dsBm.bmWidth || ySrc > srcDib.dsBm.bmHeight)
1546       return FALSE;
1547     if (xSrc + width > srcDib.dsBm.bmWidth)
1548       width = srcDib.dsBm.bmWidth - xSrc;
1549     if (ySrc + height > srcDib.dsBm.bmHeight)
1550       height = srcDib.dsBm.bmHeight - ySrc;
1551
1552     if (GetRgnBox(physDevSrc->region, &unusedRect) == COMPLEXREGION ||
1553         GetRgnBox(physDevDst->region, &unusedRect) == COMPLEXREGION)
1554     {
1555       /* for simple regions, the clipping was already done by BITBLT_GetVisRectangles */
1556       FIXME("potential optimization: client-side complex region clipping\n");
1557       return FALSE;
1558     }
1559     if (dstDib.dsBm.bmBitsPixel <= 8)
1560     {
1561       FIXME("potential optimization: client-side color-index mode DIB copy\n");
1562       return FALSE;
1563     }
1564     if (!(srcDib.dsBmih.biCompression == BI_BITFIELDS &&
1565           dstDib.dsBmih.biCompression == BI_BITFIELDS &&
1566           !memcmp(srcDib.dsBitfields, dstDib.dsBitfields, 3*sizeof(DWORD)))
1567         && !(srcDib.dsBmih.biCompression == BI_RGB &&
1568              dstDib.dsBmih.biCompression == BI_RGB))
1569     {
1570       FIXME("potential optimization: client-side compressed DIB copy\n");
1571       return FALSE;
1572     }
1573     if (srcDib.dsBm.bmBitsPixel != dstDib.dsBm.bmBitsPixel)
1574     {
1575       FIXME("potential optimization: pixel format conversion\n");
1576       return FALSE;
1577     }
1578     if (srcDib.dsBmih.biWidth < 0 || dstDib.dsBmih.biWidth < 0)
1579     {
1580       FIXME("negative widths not yet implemented\n");
1581       return FALSE;
1582     }
1583
1584     switch (dstDib.dsBm.bmBitsPixel)
1585     {
1586       case 15:
1587       case 16:
1588         bytesPerPixel = 2;
1589         break;
1590       case 24:
1591         bytesPerPixel = 3;
1592         break;
1593       case 32:
1594         bytesPerPixel = 4;
1595         break;
1596       default:
1597         FIXME("don't know how to work with a depth of %d\n", physDevSrc->depth);
1598         return FALSE;
1599     }
1600
1601     bytesToCopy = width * bytesPerPixel;
1602
1603     if (srcDib.dsBmih.biHeight < 0)
1604     {
1605       srcPtr = &physDevSrc->bitmap->base[ySrc*srcDib.dsBm.bmWidthBytes + xSrc*bytesPerPixel];
1606       srcRowOffset = srcDib.dsBm.bmWidthBytes;
1607     }
1608     else
1609     {
1610       srcPtr = &physDevSrc->bitmap->base[(srcDib.dsBm.bmHeight-ySrc-1)*srcDib.dsBm.bmWidthBytes
1611         + xSrc*bytesPerPixel];
1612       srcRowOffset = -srcDib.dsBm.bmWidthBytes;
1613     }
1614     if (dstDib.dsBmih.biHeight < 0)
1615     {
1616       dstPtr = &physDevDst->bitmap->base[yDst*dstDib.dsBm.bmWidthBytes + xDst*bytesPerPixel];
1617       dstRowOffset = dstDib.dsBm.bmWidthBytes;
1618     }
1619     else
1620     {
1621       dstPtr = &physDevDst->bitmap->base[(dstDib.dsBm.bmHeight-yDst-1)*dstDib.dsBm.bmWidthBytes
1622         + xDst*bytesPerPixel];
1623       dstRowOffset = -dstDib.dsBm.bmWidthBytes;
1624     }
1625
1626     /* Handle overlapping regions on the same DIB */
1627     if (physDevSrc == physDevDst && ySrc < yDst)
1628     {
1629       srcPtr += srcRowOffset * (height - 1);
1630       srcRowOffset = -srcRowOffset;
1631       dstPtr += dstRowOffset * (height - 1);
1632       dstRowOffset = -dstRowOffset;
1633     }
1634
1635     for (y = yDst; y < yDst + height; ++y)
1636     {
1637       memmove(dstPtr, srcPtr, bytesToCopy);
1638       srcPtr += srcRowOffset;
1639       dstPtr += dstRowOffset;
1640     }
1641
1642     return TRUE;
1643 }
1644
1645
1646 /***********************************************************************
1647  *           X11DRV_BitBlt
1648  */
1649 BOOL X11DRV_BitBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1650                     INT width, INT height, X11DRV_PDEVICE *physDevSrc,
1651                     INT xSrc, INT ySrc, DWORD rop )
1652 {
1653     BOOL result = FALSE;
1654     INT sSrc, sDst;
1655     RECT visRectDst, visRectSrc;
1656
1657     if (((rop >> 16) & 0x55) == ((rop >> 17) & 0x55)) {
1658       /* FIXME: seems the ROP doesn't include destination;
1659        * now if the destination area include the entire dcDst,
1660        * we can pass TRUE instead of FALSE to CoerceDIBSection(dcDst...),
1661        * which may avoid a copy in some situations */
1662     }
1663
1664     sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None, FALSE );
1665     if (physDevDst != physDevSrc)
1666         sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None, FALSE );
1667     else
1668         sSrc = sDst;
1669
1670     if ((sSrc == DIB_Status_AppMod) && (rop == SRCCOPY) &&
1671         (physDevSrc->depth == physDevDst->depth))
1672     {
1673       POINT pts[2];
1674       /* do everything ourselves; map coordinates */
1675
1676       pts[0].x = xSrc;
1677       pts[0].y = ySrc;
1678       pts[1].x = xSrc + width;
1679       pts[1].y = ySrc + height;
1680
1681       LPtoDP(physDevSrc->hdc, pts, 2);
1682       width = pts[1].x - pts[0].x;
1683       height = pts[1].y - pts[0].y;
1684       xSrc = pts[0].x;
1685       ySrc = pts[0].y;
1686
1687       pts[0].x = xDst;
1688       pts[0].y = yDst;
1689       LPtoDP(physDevDst->hdc, pts, 1);
1690
1691       xDst = pts[0].x;
1692       yDst = pts[0].y;
1693
1694       /* Perform basic clipping */
1695       if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, width, height,
1696                                     physDevSrc, xSrc, ySrc, width, height,
1697                                     &visRectSrc, &visRectDst ))
1698         goto END;
1699
1700       xSrc = visRectSrc.left;
1701       ySrc = visRectSrc.top;
1702       xDst = visRectDst.left;
1703       yDst = visRectDst.top;
1704       width = visRectDst.right - visRectDst.left;
1705       height = visRectDst.bottom - visRectDst.top;
1706
1707       if (sDst == DIB_Status_AppMod) {
1708         result = X11DRV_ClientSideDIBCopy( physDevSrc, xSrc, ySrc,
1709                                            physDevDst, xDst, yDst,
1710                                            width, height );
1711         if (result)
1712           goto END;
1713         /* fall back to X server copying */
1714       }
1715       X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1716
1717       wine_tsx11_lock();
1718       XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1719       wine_tsx11_unlock();
1720
1721       X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, xSrc, ySrc, xDst, yDst, width, height );
1722       result = TRUE;
1723       goto END;
1724     }
1725
1726     X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1727     if (physDevDst != physDevSrc)
1728       X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1729
1730     result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, width, height,
1731                                         physDevSrc, xSrc, ySrc, width, height, rop );
1732
1733 END:
1734     if (physDevDst != physDevSrc)
1735       X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1736     X11DRV_UnlockDIBSection( physDevDst, TRUE );
1737
1738     return result;
1739 }
1740
1741
1742 /***********************************************************************
1743  *           X11DRV_StretchBlt
1744  */
1745 BOOL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1746                         INT widthDst, INT heightDst,
1747                         X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1748                         INT widthSrc, INT heightSrc, DWORD rop )
1749 {
1750     BOOL result;
1751
1752     X11DRV_LockDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1753     if (physDevDst != physDevSrc)
1754       X11DRV_LockDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1755
1756     result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, widthDst, heightDst,
1757                                         physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop );
1758
1759     if (physDevDst != physDevSrc)
1760       X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1761     X11DRV_UnlockDIBSection( physDevDst, TRUE );
1762     return result;
1763 }