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