appwiz.cpl: Convert the application list to a standard Wine list.
[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       FIXME("potential optimization: client-side color-index mode DIB copy\n");
1315       return FALSE;
1316     }
1317     if (!(srcDib.dsBmih.biCompression == BI_BITFIELDS &&
1318           dstDib.dsBmih.biCompression == BI_BITFIELDS &&
1319           !memcmp(srcDib.dsBitfields, dstDib.dsBitfields, 3*sizeof(DWORD)))
1320         && !(srcDib.dsBmih.biCompression == BI_RGB &&
1321              dstDib.dsBmih.biCompression == BI_RGB))
1322     {
1323       FIXME("potential optimization: client-side compressed DIB copy\n");
1324       return FALSE;
1325     }
1326     if (srcDib.dsBm.bmBitsPixel != dstDib.dsBm.bmBitsPixel)
1327     {
1328       FIXME("potential optimization: pixel format conversion\n");
1329       return FALSE;
1330     }
1331     if (srcDib.dsBmih.biWidth < 0 || dstDib.dsBmih.biWidth < 0)
1332     {
1333       FIXME("negative widths not yet implemented\n");
1334       return FALSE;
1335     }
1336
1337     switch (dstDib.dsBm.bmBitsPixel)
1338     {
1339       case 15:
1340       case 16:
1341         bytesPerPixel = 2;
1342         break;
1343       case 24:
1344         bytesPerPixel = 3;
1345         break;
1346       case 32:
1347         bytesPerPixel = 4;
1348         break;
1349       default:
1350         FIXME("don't know how to work with a depth of %d\n", physDevSrc->depth);
1351         return FALSE;
1352     }
1353
1354     bytesToCopy = width * bytesPerPixel;
1355
1356     if (physDevSrc->bitmap->topdown)
1357     {
1358       srcPtr = &physDevSrc->bitmap->base[ySrc*srcDib.dsBm.bmWidthBytes + xSrc*bytesPerPixel];
1359       srcRowOffset = srcDib.dsBm.bmWidthBytes;
1360     }
1361     else
1362     {
1363       srcPtr = &physDevSrc->bitmap->base[(srcDib.dsBm.bmHeight-ySrc-1)*srcDib.dsBm.bmWidthBytes
1364         + xSrc*bytesPerPixel];
1365       srcRowOffset = -srcDib.dsBm.bmWidthBytes;
1366     }
1367     if (physDevDst->bitmap->topdown)
1368     {
1369       dstPtr = &physDevDst->bitmap->base[yDst*dstDib.dsBm.bmWidthBytes + xDst*bytesPerPixel];
1370       dstRowOffset = dstDib.dsBm.bmWidthBytes;
1371     }
1372     else
1373     {
1374       dstPtr = &physDevDst->bitmap->base[(dstDib.dsBm.bmHeight-yDst-1)*dstDib.dsBm.bmWidthBytes
1375         + xDst*bytesPerPixel];
1376       dstRowOffset = -dstDib.dsBm.bmWidthBytes;
1377     }
1378
1379     /* Handle overlapping regions on the same DIB */
1380     if (physDevSrc == physDevDst && ySrc < yDst)
1381     {
1382       srcPtr += srcRowOffset * (height - 1);
1383       srcRowOffset = -srcRowOffset;
1384       dstPtr += dstRowOffset * (height - 1);
1385       dstRowOffset = -dstRowOffset;
1386     }
1387
1388     for (y = yDst; y < yDst + height; ++y)
1389     {
1390       memmove(dstPtr, srcPtr, bytesToCopy);
1391       srcPtr += srcRowOffset;
1392       dstPtr += dstRowOffset;
1393     }
1394
1395     return TRUE;
1396 }
1397
1398 static BOOL same_format(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst)
1399 {
1400     if (physDevSrc->depth != physDevDst->depth) return FALSE;
1401     if (!physDevSrc->color_shifts && !physDevDst->color_shifts) return TRUE;
1402     if (physDevSrc->color_shifts && physDevDst->color_shifts)
1403         return !memcmp(physDevSrc->color_shifts, physDevDst->color_shifts, sizeof(ColorShifts));
1404     return FALSE;
1405 }
1406
1407 /***********************************************************************
1408  *           X11DRV_StretchBlt
1409  */
1410 BOOL CDECL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1411                               X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1412                               DWORD rop )
1413 {
1414     BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1415     struct bitblt_coords src, dst;
1416     INT width, height;
1417     INT sDst, sSrc = DIB_Status_None;
1418     const BYTE *opcode;
1419     Pixmap pixmaps[3] = { 0, 0, 0 };  /* pixmaps for DST, SRC, TMP */
1420     GC tmpGC = 0;
1421
1422     usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1423     useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1424     useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1425     if (!physDevSrc && useSrc) return FALSE;
1426
1427     src.x      = xSrc;
1428     src.y      = ySrc;
1429     src.width  = widthSrc;
1430     src.height = heightSrc;
1431     src.layout = physDevSrc ? GetLayout( physDevSrc->hdc ) : 0;
1432     dst.x      = xDst;
1433     dst.y      = yDst;
1434     dst.width  = widthDst;
1435     dst.height = heightDst;
1436     dst.layout = GetLayout( physDevDst->hdc );
1437
1438     if (rop & NOMIRRORBITMAP)
1439     {
1440         src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
1441         dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
1442         rop &= ~NOMIRRORBITMAP;
1443     }
1444
1445     if (useSrc)
1446     {
1447         if (!BITBLT_GetVisRectangles( physDevDst, physDevSrc, &dst, &src ))
1448             return TRUE;
1449         fStretch = (src.width != dst.width) || (src.height != dst.height);
1450
1451         if (physDevDst != physDevSrc)
1452             sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None );
1453     }
1454     else
1455     {
1456         fStretch = FALSE;
1457         if (!BITBLT_GetVisRectangles( physDevDst, NULL, &dst, NULL ))
1458             return TRUE;
1459     }
1460
1461     TRACE("    rectdst=%d,%d %dx%d orgdst=%d,%d visdst=%s\n",
1462           dst.x, dst.y, dst.width, dst.height,
1463           physDevDst->dc_rect.left, physDevDst->dc_rect.top, wine_dbgstr_rect( &dst.visrect ) );
1464     if (useSrc)
1465         TRACE("    rectsrc=%d,%d %dx%d orgsrc=%d,%d vissrc=%s\n",
1466               src.x, src.y, src.width, src.height,
1467               physDevSrc->dc_rect.left, physDevSrc->dc_rect.top, wine_dbgstr_rect( &src.visrect ) );
1468
1469     width  = dst.visrect.right - dst.visrect.left;
1470     height = dst.visrect.bottom - dst.visrect.top;
1471
1472     sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None );
1473     if (physDevDst == physDevSrc) sSrc = sDst;
1474
1475     /* try client-side DIB copy */
1476     if (!fStretch && rop == SRCCOPY &&
1477         sSrc == DIB_Status_AppMod && sDst == DIB_Status_AppMod &&
1478         same_format(physDevSrc, physDevDst))
1479     {
1480         if (client_side_dib_copy( physDevSrc, src.visrect.left, src.visrect.top,
1481                                   physDevDst, dst.visrect.left, dst.visrect.top, width, height ))
1482             goto done;
1483     }
1484
1485     X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod );
1486
1487     opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1488
1489     /* a few optimizations for single-op ROPs */
1490     if (!fStretch && !opcode[1])
1491     {
1492         if (OP_SRCDST(*opcode) == OP_ARGS(PAT,DST))
1493         {
1494             switch(rop)  /* a few special cases */
1495             {
1496             case BLACKNESS:  /* 0x00 */
1497             case WHITENESS:  /* 0xff */
1498                 if ((physDevDst->depth != 1) && X11DRV_PALETTE_PaletteToXPixel)
1499                 {
1500                     wine_tsx11_lock();
1501                     XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1502                     if (rop == BLACKNESS)
1503                         XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1504                     else
1505                         XSetForeground( gdi_display, physDevDst->gc,
1506                                         WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1507                     XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1508                     XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1509                                     physDevDst->dc_rect.left + dst.visrect.left,
1510                                     physDevDst->dc_rect.top + dst.visrect.top,
1511                                     width, height );
1512                     wine_tsx11_unlock();
1513                     goto done;
1514                 }
1515                 break;
1516             case DSTINVERT:  /* 0x55 */
1517                 if (!(X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL)))
1518                 {
1519                     /* Xor is much better when we do not have full colormap.   */
1520                     /* Using white^black ensures that we invert at least black */
1521                     /* and white. */
1522                     unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1523                                              BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1524                     wine_tsx11_lock();
1525                     XSetFunction( gdi_display, physDevDst->gc, GXxor );
1526                     XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1527                     XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1528                     XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1529                                     physDevDst->dc_rect.left + dst.visrect.left,
1530                                     physDevDst->dc_rect.top + dst.visrect.top,
1531                                     width, height );
1532                     wine_tsx11_unlock();
1533                     goto done;
1534                 }
1535                 break;
1536             }
1537             if (!usePat || X11DRV_SetupGCForBrush( physDevDst ))
1538             {
1539                 wine_tsx11_lock();
1540                 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1541                 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1542                                 physDevDst->dc_rect.left + dst.visrect.left,
1543                                 physDevDst->dc_rect.top + dst.visrect.top,
1544                                 width, height );
1545                 wine_tsx11_unlock();
1546             }
1547             goto done;
1548         }
1549         else if (OP_SRCDST(*opcode) == OP_ARGS(SRC,DST))
1550         {
1551             if (same_format(physDevSrc, physDevDst))
1552             {
1553                 wine_tsx11_lock();
1554                 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1555                 wine_tsx11_unlock();
1556
1557                 if (physDevSrc != physDevDst)
1558                 {
1559                     if (sSrc == DIB_Status_AppMod)
1560                     {
1561                         X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, src.visrect.left, src.visrect.top,
1562                                                    dst.visrect.left, dst.visrect.top, width, height );
1563                         goto done;
1564                     }
1565                     X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1566                 }
1567                 wine_tsx11_lock();
1568                 XCopyArea( gdi_display, physDevSrc->drawable,
1569                            physDevDst->drawable, physDevDst->gc,
1570                            physDevSrc->dc_rect.left + src.visrect.left,
1571                            physDevSrc->dc_rect.top + src.visrect.top,
1572                            width, height,
1573                            physDevDst->dc_rect.left + dst.visrect.left,
1574                            physDevDst->dc_rect.top + dst.visrect.top );
1575                 physDevDst->exposures++;
1576                 wine_tsx11_unlock();
1577                 goto done;
1578             }
1579             if (physDevSrc->depth == 1)
1580             {
1581                 int fg, bg;
1582
1583                 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1584                 get_colors(physDevDst, physDevSrc, &fg, &bg);
1585                 wine_tsx11_lock();
1586                 XSetBackground( gdi_display, physDevDst->gc, fg );
1587                 XSetForeground( gdi_display, physDevDst->gc, bg );
1588                 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1589                 XCopyPlane( gdi_display, physDevSrc->drawable,
1590                             physDevDst->drawable, physDevDst->gc,
1591                             physDevSrc->dc_rect.left + src.visrect.left,
1592                             physDevSrc->dc_rect.top + src.visrect.top,
1593                             width, height,
1594                             physDevDst->dc_rect.left + dst.visrect.left,
1595                             physDevDst->dc_rect.top + dst.visrect.top, 1 );
1596                 physDevDst->exposures++;
1597                 wine_tsx11_unlock();
1598                 goto done;
1599             }
1600         }
1601     }
1602
1603     wine_tsx11_lock();
1604     tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1605     XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1606     XSetGraphicsExposures( gdi_display, tmpGC, False );
1607     pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1608                                   physDevDst->depth );
1609     wine_tsx11_unlock();
1610
1611     if (useSrc)
1612     {
1613         wine_tsx11_lock();
1614         pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1615                                       physDevDst->depth );
1616         wine_tsx11_unlock();
1617
1618         if (physDevDst != physDevSrc) X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1619
1620         if(!X11DRV_XRender_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC, &src, &dst ))
1621         {
1622             if (fStretch)
1623                 BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC, &src, &dst );
1624             else
1625                 BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC, &src.visrect );
1626         }
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             if (useSrc)
1652                 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1653                            pixmaps[OP_DST(*opcode)], tmpGC,
1654                            0, 0, width, height, 0, 0 );
1655             break;
1656
1657         case OP_ARGS(PAT,TMP):
1658             if (!pixmaps[TMP] && !fNullBrush)
1659                 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1660                                               width, height, physDevDst->depth );
1661             /* fall through */
1662         case OP_ARGS(PAT,DST):
1663         case OP_ARGS(PAT,SRC):
1664             if (!fNullBrush)
1665                 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1666                                 tmpGC, 0, 0, width, height );
1667             break;
1668         }
1669     }
1670     XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1671     physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC], &dst.visrect );
1672     XFreePixmap( gdi_display, pixmaps[DST] );
1673     if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1674     if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1675     XFreeGC( gdi_display, tmpGC );
1676     wine_tsx11_unlock();
1677
1678 done:
1679     if (useSrc && physDevDst != physDevSrc) X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1680     X11DRV_UnlockDIBSection( physDevDst, TRUE );
1681     return TRUE;
1682 }
1683
1684
1685 /***********************************************************************
1686  *           X11DRV_AlphaBlend
1687  */
1688 BOOL CDECL X11DRV_AlphaBlend( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1689                               X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1690                               BLENDFUNCTION blendfn )
1691 {
1692     struct bitblt_coords src, dst;
1693
1694     src.x      = xSrc;
1695     src.y      = ySrc;
1696     src.width  = widthSrc;
1697     src.height = heightSrc;
1698     src.layout = GetLayout( physDevSrc->hdc );
1699     dst.x      = xDst;
1700     dst.y      = yDst;
1701     dst.width  = widthDst;
1702     dst.height = heightDst;
1703     dst.layout = GetLayout( physDevDst->hdc );
1704
1705     if (!BITBLT_GetVisRectangles( physDevDst, physDevSrc, &dst, &src )) return TRUE;
1706
1707     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",
1708            blendfn.AlphaFormat, blendfn.SourceConstantAlpha, dst.x, dst.y, dst.width, dst.height,
1709            physDevDst->dc_rect.left, physDevDst->dc_rect.top, wine_dbgstr_rect( &dst.visrect ),
1710            src.x, src.y, src.width, src.height,
1711            physDevSrc->dc_rect.left, physDevSrc->dc_rect.top, wine_dbgstr_rect( &src.visrect ) );
1712
1713     if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
1714         src.width > physDevSrc->drawable_rect.right - physDevSrc->drawable_rect.left - src.x ||
1715         src.height > physDevSrc->drawable_rect.bottom - physDevSrc->drawable_rect.top - src.y)
1716     {
1717         WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
1718         SetLastError( ERROR_INVALID_PARAMETER );
1719         return FALSE;
1720     }
1721
1722     return XRender_AlphaBlend( physDevDst, physDevSrc, &dst, &src, blendfn );
1723 }