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