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