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