winex11: Implement a separate entry point for PatBlt and simplify the StretchBlt...
[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->layout & LAYOUT_RTL && dst->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
1191     {
1192         SWAP_INT32( &rect.left, &rect.right );
1193         dst->x = rect.left;
1194         dst->width = rect.right - rect.left;
1195     }
1196     if (rect.left > rect.right) { SWAP_INT32( &rect.left, &rect.right ); rect.left++; rect.right++; }
1197     if (rect.top > rect.bottom) { SWAP_INT32( &rect.top, &rect.bottom ); rect.top++; rect.bottom++; }
1198
1199     GetRgnBox( physDevDst->region, &clipRect );
1200     if (!IntersectRect( &dst->visrect, &rect, &clipRect )) return FALSE;
1201
1202       /* Get the source visible rectangle */
1203
1204     if (!physDevSrc) return TRUE;
1205
1206     rect.left   = src->x;
1207     rect.top    = src->y;
1208     rect.right  = src->x + src->width;
1209     rect.bottom = src->y + src->height;
1210     LPtoDP( physDevSrc->hdc, (POINT *)&rect, 2 );
1211     src->x      = rect.left;
1212     src->y      = rect.top;
1213     src->width  = rect.right - rect.left;
1214     src->height = rect.bottom - rect.top;
1215     if (src->layout & LAYOUT_RTL && src->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
1216     {
1217         SWAP_INT32( &rect.left, &rect.right );
1218         src->x = rect.left;
1219         src->width = rect.right - rect.left;
1220     }
1221     if (rect.left > rect.right) { SWAP_INT32( &rect.left, &rect.right ); rect.left++; rect.right++; }
1222     if (rect.top > rect.bottom) { SWAP_INT32( &rect.top, &rect.bottom ); rect.top++; rect.bottom++; }
1223
1224     /* Apparently the clipping and visible regions are only for output,
1225        so just check against dc extent here to avoid BadMatch errors */
1226     clipRect = physDevSrc->drawable_rect;
1227     OffsetRect( &clipRect, -(physDevSrc->drawable_rect.left + physDevSrc->dc_rect.left),
1228                 -(physDevSrc->drawable_rect.top + physDevSrc->dc_rect.top) );
1229     if (!IntersectRect( &src->visrect, &rect, &clipRect ))
1230         return FALSE;
1231
1232       /* Intersect the rectangles */
1233
1234     if ((src->width == dst->width) && (src->height == dst->height)) /* no stretching */
1235     {
1236         OffsetRect( &src->visrect, dst->x - src->x, dst->y - src->y );
1237         if (!IntersectRect( &rect, &src->visrect, &dst->visrect )) return FALSE;
1238         src->visrect = dst->visrect = rect;
1239         OffsetRect( &src->visrect, src->x - dst->x, src->y - dst->y );
1240     }
1241     else  /* stretching */
1242     {
1243         /* Map source rectangle into destination coordinates */
1244         rect.left   = dst->x + (src->visrect.left - src->x)*dst->width/src->width;
1245         rect.top    = dst->y + (src->visrect.top - src->y)*dst->height/src->height;
1246         rect.right  = dst->x + (src->visrect.right - src->x)*dst->width/src->width;
1247         rect.bottom = dst->y + (src->visrect.bottom - src->y)*dst->height/src->height;
1248         if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1249         if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1250
1251         /* Avoid rounding errors */
1252         rect.left--;
1253         rect.top--;
1254         rect.right++;
1255         rect.bottom++;
1256         if (!IntersectRect( &dst->visrect, &rect, &dst->visrect )) return FALSE;
1257
1258         /* Map destination rectangle back to source coordinates */
1259         rect = dst->visrect;
1260         rect.left   = src->x + (dst->visrect.left - dst->x)*src->width/dst->width;
1261         rect.top    = src->y + (dst->visrect.top - dst->y)*src->height/dst->height;
1262         rect.right  = src->x + (dst->visrect.right - dst->x)*src->width/dst->width;
1263         rect.bottom = src->y + (dst->visrect.bottom - dst->y)*src->height/dst->height;
1264         if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1265         if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1266
1267         /* Avoid rounding errors */
1268         rect.left--;
1269         rect.top--;
1270         rect.right++;
1271         rect.bottom++;
1272         if (!IntersectRect( &src->visrect, &rect, &src->visrect )) return FALSE;
1273     }
1274     return TRUE;
1275 }
1276
1277
1278 /***********************************************************************
1279  *           client_side_dib_copy
1280  */
1281 static BOOL client_side_dib_copy( X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1282                                   X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1283                                   INT width, INT height )
1284 {
1285     DIBSECTION srcDib, dstDib;
1286     BYTE *srcPtr, *dstPtr;
1287     INT srcRowOffset, dstRowOffset;
1288     INT bytesPerPixel;
1289     INT bytesToCopy;
1290     INT y;
1291     static RECT unusedRect;
1292
1293     if (GetObjectW(physDevSrc->bitmap->hbitmap, sizeof(srcDib), &srcDib) != sizeof(srcDib))
1294       return FALSE;
1295     if (GetObjectW(physDevDst->bitmap->hbitmap, sizeof(dstDib), &dstDib) != sizeof(dstDib))
1296       return FALSE;
1297
1298     /* check for oversized values, just like X11DRV_DIB_CopyDIBSection() */
1299     if (xSrc > srcDib.dsBm.bmWidth || ySrc > srcDib.dsBm.bmHeight)
1300       return FALSE;
1301     if (xSrc + width > srcDib.dsBm.bmWidth)
1302       width = srcDib.dsBm.bmWidth - xSrc;
1303     if (ySrc + height > srcDib.dsBm.bmHeight)
1304       height = srcDib.dsBm.bmHeight - ySrc;
1305
1306     if (GetRgnBox(physDevDst->region, &unusedRect) == COMPLEXREGION)
1307     {
1308       /* for simple regions, the clipping was already done by BITBLT_GetVisRectangles */
1309       FIXME("potential optimization: client-side complex region clipping\n");
1310       return FALSE;
1311     }
1312     if (dstDib.dsBm.bmBitsPixel <= 8)
1313     {
1314       static BOOL fixme_once;
1315       if(!fixme_once++) FIXME("potential optimization: client-side color-index mode DIB copy\n");
1316       return FALSE;
1317     }
1318     if (!(srcDib.dsBmih.biCompression == BI_BITFIELDS &&
1319           dstDib.dsBmih.biCompression == BI_BITFIELDS &&
1320           !memcmp(srcDib.dsBitfields, dstDib.dsBitfields, 3*sizeof(DWORD)))
1321         && !(srcDib.dsBmih.biCompression == BI_RGB &&
1322              dstDib.dsBmih.biCompression == BI_RGB))
1323     {
1324       FIXME("potential optimization: client-side compressed DIB copy\n");
1325       return FALSE;
1326     }
1327     if (srcDib.dsBm.bmBitsPixel != dstDib.dsBm.bmBitsPixel)
1328     {
1329       FIXME("potential optimization: pixel format conversion\n");
1330       return FALSE;
1331     }
1332     if (srcDib.dsBmih.biWidth < 0 || dstDib.dsBmih.biWidth < 0)
1333     {
1334       FIXME("negative widths not yet implemented\n");
1335       return FALSE;
1336     }
1337
1338     switch (dstDib.dsBm.bmBitsPixel)
1339     {
1340       case 15:
1341       case 16:
1342         bytesPerPixel = 2;
1343         break;
1344       case 24:
1345         bytesPerPixel = 3;
1346         break;
1347       case 32:
1348         bytesPerPixel = 4;
1349         break;
1350       default:
1351         FIXME("don't know how to work with a depth of %d\n", physDevSrc->depth);
1352         return FALSE;
1353     }
1354
1355     bytesToCopy = width * bytesPerPixel;
1356
1357     if (physDevSrc->bitmap->topdown)
1358     {
1359       srcPtr = &physDevSrc->bitmap->base[ySrc*srcDib.dsBm.bmWidthBytes + xSrc*bytesPerPixel];
1360       srcRowOffset = srcDib.dsBm.bmWidthBytes;
1361     }
1362     else
1363     {
1364       srcPtr = &physDevSrc->bitmap->base[(srcDib.dsBm.bmHeight-ySrc-1)*srcDib.dsBm.bmWidthBytes
1365         + xSrc*bytesPerPixel];
1366       srcRowOffset = -srcDib.dsBm.bmWidthBytes;
1367     }
1368     if (physDevDst->bitmap->topdown)
1369     {
1370       dstPtr = &physDevDst->bitmap->base[yDst*dstDib.dsBm.bmWidthBytes + xDst*bytesPerPixel];
1371       dstRowOffset = dstDib.dsBm.bmWidthBytes;
1372     }
1373     else
1374     {
1375       dstPtr = &physDevDst->bitmap->base[(dstDib.dsBm.bmHeight-yDst-1)*dstDib.dsBm.bmWidthBytes
1376         + xDst*bytesPerPixel];
1377       dstRowOffset = -dstDib.dsBm.bmWidthBytes;
1378     }
1379
1380     /* Handle overlapping regions on the same DIB */
1381     if (physDevSrc == physDevDst && ySrc < yDst)
1382     {
1383       srcPtr += srcRowOffset * (height - 1);
1384       srcRowOffset = -srcRowOffset;
1385       dstPtr += dstRowOffset * (height - 1);
1386       dstRowOffset = -dstRowOffset;
1387     }
1388
1389     for (y = yDst; y < yDst + height; ++y)
1390     {
1391       memmove(dstPtr, srcPtr, bytesToCopy);
1392       srcPtr += srcRowOffset;
1393       dstPtr += dstRowOffset;
1394     }
1395
1396     return TRUE;
1397 }
1398
1399 static BOOL same_format(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst)
1400 {
1401     if (physDevSrc->depth != physDevDst->depth) return FALSE;
1402     if (!physDevSrc->color_shifts && !physDevDst->color_shifts) return TRUE;
1403     if (physDevSrc->color_shifts && physDevDst->color_shifts)
1404         return !memcmp(physDevSrc->color_shifts, physDevDst->color_shifts, sizeof(ColorShifts));
1405     return FALSE;
1406 }
1407
1408 /***********************************************************************
1409  *           X11DRV_PatBlt
1410  */
1411 BOOL CDECL X11DRV_PatBlt( X11DRV_PDEVICE *physDev, INT x, INT y, INT width, INT height, DWORD rop )
1412 {
1413     BOOL usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1414     const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1415     struct bitblt_coords dst;
1416
1417     dst.x      = x;
1418     dst.y      = y;
1419     dst.width  = width;
1420     dst.height = height;
1421     dst.layout = GetLayout( physDev->hdc );
1422
1423     if (rop & NOMIRRORBITMAP)
1424     {
1425         dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
1426         rop &= ~NOMIRRORBITMAP;
1427     }
1428
1429     if (!BITBLT_GetVisRectangles( physDev, NULL, &dst, NULL )) return TRUE;
1430     if (usePat && !X11DRV_SetupGCForBrush( physDev )) return TRUE;
1431
1432     TRACE( "rect=%d,%d %dx%d org=%d,%d vis=%s\n",
1433           dst.x, dst.y, dst.width, dst.height,
1434           physDev->dc_rect.left, physDev->dc_rect.top, wine_dbgstr_rect( &dst.visrect ) );
1435
1436     width  = dst.visrect.right - dst.visrect.left;
1437     height = dst.visrect.bottom - dst.visrect.top;
1438
1439     X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1440
1441     wine_tsx11_lock();
1442     XSetFunction( gdi_display, physDev->gc, OP_ROP(*opcode) );
1443
1444     switch(rop)  /* a few special cases */
1445     {
1446     case BLACKNESS:  /* 0x00 */
1447     case WHITENESS:  /* 0xff */
1448         if ((physDev->depth != 1) && X11DRV_PALETTE_PaletteToXPixel)
1449         {
1450             XSetFunction( gdi_display, physDev->gc, GXcopy );
1451             if (rop == BLACKNESS)
1452                 XSetForeground( gdi_display, physDev->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1453             else
1454                 XSetForeground( gdi_display, physDev->gc,
1455                                 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1456             XSetFillStyle( gdi_display, physDev->gc, FillSolid );
1457         }
1458         break;
1459     case DSTINVERT:  /* 0x55 */
1460         if (!(X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL)))
1461         {
1462             /* Xor is much better when we do not have full colormap.   */
1463             /* Using white^black ensures that we invert at least black */
1464             /* and white. */
1465             unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1466                                      BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1467             XSetFunction( gdi_display, physDev->gc, GXxor );
1468             XSetForeground( gdi_display, physDev->gc, xor_pix);
1469             XSetFillStyle( gdi_display, physDev->gc, FillSolid );
1470         }
1471         break;
1472     }
1473     XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1474                     physDev->dc_rect.left + dst.visrect.left,
1475                     physDev->dc_rect.top + dst.visrect.top,
1476                     dst.visrect.right - dst.visrect.left,
1477                     dst.visrect.bottom - dst.visrect.top );
1478     wine_tsx11_unlock();
1479
1480     X11DRV_UnlockDIBSection( physDev, TRUE );
1481     return TRUE;
1482 }
1483
1484
1485 /***********************************************************************
1486  *           X11DRV_StretchBlt
1487  */
1488 BOOL CDECL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1489                               X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1490                               DWORD rop )
1491 {
1492     BOOL usePat, useDst, destUsed, fStretch, fNullBrush;
1493     struct bitblt_coords src, dst;
1494     INT width, height;
1495     INT sDst, sSrc = DIB_Status_None;
1496     const BYTE *opcode;
1497     Pixmap pixmaps[3] = { 0, 0, 0 };  /* pixmaps for DST, SRC, TMP */
1498     GC tmpGC = 0;
1499
1500     usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1501     useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1502
1503     src.x      = xSrc;
1504     src.y      = ySrc;
1505     src.width  = widthSrc;
1506     src.height = heightSrc;
1507     src.layout = physDevSrc ? GetLayout( physDevSrc->hdc ) : 0;
1508     dst.x      = xDst;
1509     dst.y      = yDst;
1510     dst.width  = widthDst;
1511     dst.height = heightDst;
1512     dst.layout = GetLayout( physDevDst->hdc );
1513
1514     if (rop & NOMIRRORBITMAP)
1515     {
1516         src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
1517         dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
1518         rop &= ~NOMIRRORBITMAP;
1519     }
1520
1521     if (!BITBLT_GetVisRectangles( physDevDst, physDevSrc, &dst, &src ))
1522         return TRUE;
1523     fStretch = (src.width != dst.width) || (src.height != dst.height);
1524
1525     if (physDevDst != physDevSrc)
1526         sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None );
1527
1528     TRACE("    rectdst=%d,%d %dx%d orgdst=%d,%d visdst=%s\n",
1529           dst.x, dst.y, dst.width, dst.height,
1530           physDevDst->dc_rect.left, physDevDst->dc_rect.top, wine_dbgstr_rect( &dst.visrect ) );
1531     TRACE("    rectsrc=%d,%d %dx%d orgsrc=%d,%d vissrc=%s\n",
1532           src.x, src.y, src.width, src.height,
1533           physDevSrc->dc_rect.left, physDevSrc->dc_rect.top, wine_dbgstr_rect( &src.visrect ) );
1534
1535     width  = dst.visrect.right - dst.visrect.left;
1536     height = dst.visrect.bottom - dst.visrect.top;
1537
1538     sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None );
1539     if (physDevDst == physDevSrc) sSrc = sDst;
1540
1541     /* try client-side DIB copy */
1542     if (!fStretch && rop == SRCCOPY &&
1543         sSrc == DIB_Status_AppMod && sDst == DIB_Status_AppMod &&
1544         same_format(physDevSrc, physDevDst))
1545     {
1546         if (client_side_dib_copy( physDevSrc, src.visrect.left, src.visrect.top,
1547                                   physDevDst, dst.visrect.left, dst.visrect.top, width, height ))
1548             goto done;
1549     }
1550
1551     X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod );
1552
1553     opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1554
1555     /* a few optimizations for single-op ROPs */
1556     if (!fStretch && !opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1557     {
1558         if (same_format(physDevSrc, physDevDst))
1559         {
1560             wine_tsx11_lock();
1561             XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1562             wine_tsx11_unlock();
1563
1564             if (physDevSrc != physDevDst)
1565             {
1566                 if (sSrc == DIB_Status_AppMod)
1567                 {
1568                     X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, src.visrect.left, src.visrect.top,
1569                                                dst.visrect.left, dst.visrect.top, width, height );
1570                     goto done;
1571                 }
1572                 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1573             }
1574             wine_tsx11_lock();
1575             XCopyArea( gdi_display, physDevSrc->drawable,
1576                        physDevDst->drawable, physDevDst->gc,
1577                        physDevSrc->dc_rect.left + src.visrect.left,
1578                        physDevSrc->dc_rect.top + src.visrect.top,
1579                        width, height,
1580                        physDevDst->dc_rect.left + dst.visrect.left,
1581                        physDevDst->dc_rect.top + dst.visrect.top );
1582             physDevDst->exposures++;
1583             wine_tsx11_unlock();
1584             goto done;
1585         }
1586         if (physDevSrc->depth == 1)
1587         {
1588             int fg, bg;
1589
1590             X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1591             get_colors(physDevDst, physDevSrc, &fg, &bg);
1592             wine_tsx11_lock();
1593             XSetBackground( gdi_display, physDevDst->gc, fg );
1594             XSetForeground( gdi_display, physDevDst->gc, bg );
1595             XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1596             XCopyPlane( gdi_display, physDevSrc->drawable,
1597                         physDevDst->drawable, physDevDst->gc,
1598                         physDevSrc->dc_rect.left + src.visrect.left,
1599                         physDevSrc->dc_rect.top + src.visrect.top,
1600                         width, height,
1601                         physDevDst->dc_rect.left + dst.visrect.left,
1602                         physDevDst->dc_rect.top + dst.visrect.top, 1 );
1603             physDevDst->exposures++;
1604             wine_tsx11_unlock();
1605             goto done;
1606         }
1607     }
1608
1609     wine_tsx11_lock();
1610     tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1611     XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1612     XSetGraphicsExposures( gdi_display, tmpGC, False );
1613     pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1614                                   physDevDst->depth );
1615     pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1616                                   physDevDst->depth );
1617     wine_tsx11_unlock();
1618
1619     if (physDevDst != physDevSrc) X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1620
1621     if(!X11DRV_XRender_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC, &src, &dst ))
1622     {
1623         if (fStretch)
1624             BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC, &src, &dst );
1625         else
1626             BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC, &src.visrect );
1627     }
1628
1629     if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &dst.visrect );
1630     if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1631     else fNullBrush = FALSE;
1632     destUsed = FALSE;
1633
1634     wine_tsx11_lock();
1635     for ( ; *opcode; opcode++)
1636     {
1637         if (OP_DST(*opcode) == DST) destUsed = TRUE;
1638         XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1639         switch(OP_SRCDST(*opcode))
1640         {
1641         case OP_ARGS(DST,TMP):
1642         case OP_ARGS(SRC,TMP):
1643             if (!pixmaps[TMP])
1644                 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1645                                               width, height, physDevDst->depth );
1646             /* fall through */
1647         case OP_ARGS(DST,SRC):
1648         case OP_ARGS(SRC,DST):
1649         case OP_ARGS(TMP,SRC):
1650         case OP_ARGS(TMP,DST):
1651             XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1652                        pixmaps[OP_DST(*opcode)], tmpGC,
1653                        0, 0, width, height, 0, 0 );
1654             break;
1655
1656         case OP_ARGS(PAT,TMP):
1657             if (!pixmaps[TMP] && !fNullBrush)
1658                 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1659                                               width, height, physDevDst->depth );
1660             /* fall through */
1661         case OP_ARGS(PAT,DST):
1662         case OP_ARGS(PAT,SRC):
1663             if (!fNullBrush)
1664                 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1665                                 tmpGC, 0, 0, width, height );
1666             break;
1667         }
1668     }
1669     XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1670     physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC], &dst.visrect );
1671     XFreePixmap( gdi_display, pixmaps[DST] );
1672     if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1673     if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1674     XFreeGC( gdi_display, tmpGC );
1675     wine_tsx11_unlock();
1676
1677 done:
1678     if (physDevDst != physDevSrc) X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1679     X11DRV_UnlockDIBSection( physDevDst, TRUE );
1680     return TRUE;
1681 }
1682
1683
1684 /***********************************************************************
1685  *           X11DRV_AlphaBlend
1686  */
1687 BOOL CDECL X11DRV_AlphaBlend( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1688                               X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1689                               BLENDFUNCTION blendfn )
1690 {
1691     struct bitblt_coords src, dst;
1692
1693     src.x      = xSrc;
1694     src.y      = ySrc;
1695     src.width  = widthSrc;
1696     src.height = heightSrc;
1697     src.layout = GetLayout( physDevSrc->hdc );
1698     dst.x      = xDst;
1699     dst.y      = yDst;
1700     dst.width  = widthDst;
1701     dst.height = heightDst;
1702     dst.layout = GetLayout( physDevDst->hdc );
1703
1704     if (!BITBLT_GetVisRectangles( physDevDst, physDevSrc, &dst, &src )) return TRUE;
1705
1706     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",
1707            blendfn.AlphaFormat, blendfn.SourceConstantAlpha, dst.x, dst.y, dst.width, dst.height,
1708            physDevDst->dc_rect.left, physDevDst->dc_rect.top, wine_dbgstr_rect( &dst.visrect ),
1709            src.x, src.y, src.width, src.height,
1710            physDevSrc->dc_rect.left, physDevSrc->dc_rect.top, wine_dbgstr_rect( &src.visrect ) );
1711
1712     if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
1713         src.width > physDevSrc->drawable_rect.right - physDevSrc->drawable_rect.left - src.x ||
1714         src.height > physDevSrc->drawable_rect.bottom - physDevSrc->drawable_rect.top - src.y)
1715     {
1716         WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
1717         SetLastError( ERROR_INVALID_PARAMETER );
1718         return FALSE;
1719     }
1720
1721     return XRender_AlphaBlend( physDevDst, physDevSrc, &dst, &src, blendfn );
1722 }