kernel32/tests: Add tests for console codepages.
[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->dc_rect.left + visRectSrc->left,
880                           physDevSrc->dc_rect.top + 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->dc_rect.left + visRectSrc->left,
930                             physDevSrc->dc_rect.top + visRectSrc->top,
931                             width, height, 0, 0, 1);
932             }
933             else
934                 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
935                            physDevSrc->dc_rect.left + visRectSrc->left,
936                            physDevSrc->dc_rect.top + 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->dc_rect.left + visRectSrc->left,
945                                       physDevSrc->dc_rect.top + 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->dc_rect.left + visRectSrc->left,
952                            physDevSrc->dc_rect.top + 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->dc_rect.left + visRectSrc->left,
987                         physDevSrc->dc_rect.top + 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->dc_rect.left + visRectSrc->left,
996                                   physDevSrc->dc_rect.top + 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->dc_rect.left + visRectDst->left, physDev->dc_rect.top + 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->dc_rect.left + visRectDst->left,
1050                                physDev->dc_rect.top + 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->dc_rect.left + visRectDst->left,
1057                        physDev->dc_rect.top + 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->dc_rect.left + visRectDst->left,
1093                    physDev->dc_rect.top + 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->dc_rect.left + visRectDst->left,
1109                    physDev->dc_rect.top + 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     clipRect = physDevSrc->drawable_rect;
1153     OffsetRect( &clipRect, -(physDevSrc->drawable_rect.left + physDevSrc->dc_rect.left),
1154                 -(physDevSrc->drawable_rect.top + physDevSrc->dc_rect.top) );
1155     if (!IntersectRect( visRectSrc, &rect, &clipRect ))
1156         return FALSE;
1157
1158       /* Intersect the rectangles */
1159
1160     if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1161     {
1162         visRectSrc->left   += xDst - xSrc;
1163         visRectSrc->right  += xDst - xSrc;
1164         visRectSrc->top    += yDst - ySrc;
1165         visRectSrc->bottom += yDst - ySrc;
1166         if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1167         *visRectSrc = *visRectDst = rect;
1168         visRectSrc->left   += xSrc - xDst;
1169         visRectSrc->right  += xSrc - xDst;
1170         visRectSrc->top    += ySrc - yDst;
1171         visRectSrc->bottom += ySrc - yDst;
1172     }
1173     else  /* stretching */
1174     {
1175         /* Map source rectangle into destination coordinates */
1176         rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1177         rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1178         rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1179         rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1180         if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1181         if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1182
1183         /* Avoid rounding errors */
1184         rect.left--;
1185         rect.top--;
1186         rect.right++;
1187         rect.bottom++;
1188         if (!IntersectRect( visRectDst, &rect, visRectDst )) return FALSE;
1189
1190         /* Map destination rectangle back to source coordinates */
1191         rect = *visRectDst;
1192         rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1193         rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1194         rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1195         rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1196         if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1197         if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1198
1199         /* Avoid rounding errors */
1200         rect.left--;
1201         rect.top--;
1202         rect.right++;
1203         rect.bottom++;
1204         if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1205     }
1206     return TRUE;
1207 }
1208
1209
1210 /***********************************************************************
1211  *           BITBLT_InternalStretchBlt
1212  *
1213  * Implementation of PatBlt(), BitBlt() and StretchBlt().
1214  */
1215 static BOOL BITBLT_InternalStretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1216                                        INT widthDst, INT heightDst,
1217                                        X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1218                                        INT widthSrc, INT heightSrc,
1219                                        DWORD rop )
1220 {
1221     BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1222     RECT visRectDst, visRectSrc;
1223     INT width, height;
1224     const BYTE *opcode;
1225     Pixmap pixmaps[3] = { 0, 0, 0 };  /* pixmaps for DST, SRC, TMP */
1226     GC tmpGC = 0;
1227     POINT pts[2];
1228
1229     /* compensate for off-by-one shifting for negative widths and heights */
1230     if (widthDst < 0)
1231         ++xDst;
1232     if (heightDst < 0)
1233         ++yDst;
1234     if (widthSrc < 0)
1235         ++xSrc;
1236     if (heightSrc < 0)
1237         ++ySrc;
1238
1239     usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1240     useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1241     useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1242     if (!physDevSrc && useSrc) return FALSE;
1243
1244       /* Map the coordinates to device coords */
1245
1246     pts[0].x = xDst;
1247     pts[0].y = yDst;
1248     pts[1].x = xDst + widthDst;
1249     pts[1].y = yDst + heightDst;
1250     LPtoDP(physDevDst->hdc, pts, 2);
1251     xDst      = pts[0].x;
1252     yDst      = pts[0].y;
1253     widthDst  = pts[1].x - pts[0].x;
1254     heightDst = pts[1].y - pts[0].y;
1255
1256     TRACE("    rectdst=%d,%d-%d,%d orgdst=%d,%d\n",
1257                     xDst, yDst, widthDst, heightDst,
1258                     physDevDst->dc_rect.left, physDevDst->dc_rect.top );
1259
1260     if (useSrc)
1261     {
1262         pts[0].x = xSrc;
1263         pts[0].y = ySrc;
1264         pts[1].x = xSrc + widthSrc;
1265         pts[1].y = ySrc + heightSrc;
1266         LPtoDP(physDevSrc->hdc, pts, 2);
1267         xSrc      = pts[0].x;
1268         ySrc      = pts[0].y;
1269         widthSrc  = pts[1].x - pts[0].x;
1270         heightSrc = pts[1].y - pts[0].y;
1271
1272         fStretch  = (widthSrc != widthDst) || (heightSrc != heightDst);
1273         TRACE("    rectsrc=%d,%d-%d,%d orgsrc=%d,%d\n",
1274                         xSrc, ySrc, widthSrc, heightSrc,
1275                         physDevSrc->dc_rect.left, physDevSrc->dc_rect.top );
1276         if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1277                                       physDevSrc, xSrc, ySrc, widthSrc, heightSrc,
1278                                       &visRectSrc, &visRectDst ))
1279             return TRUE;
1280         TRACE("    vissrc=%d,%d-%d,%d visdst=%d,%d-%d,%d\n",
1281                         visRectSrc.left, visRectSrc.top,
1282                         visRectSrc.right, visRectSrc.bottom,
1283                         visRectDst.left, visRectDst.top,
1284                         visRectDst.right, visRectDst.bottom );
1285     }
1286     else
1287     {
1288         fStretch = FALSE;
1289         if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1290                                       NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1291             return TRUE;
1292         TRACE("    vissrc=none visdst=%d,%d-%d,%d\n",
1293                         visRectDst.left, visRectDst.top,
1294                         visRectDst.right, visRectDst.bottom );
1295     }
1296
1297     width  = visRectDst.right - visRectDst.left;
1298     height = visRectDst.bottom - visRectDst.top;
1299
1300     if (!fStretch) switch(rop)  /* A few optimisations */
1301     {
1302     case BLACKNESS:  /* 0x00 */
1303         wine_tsx11_lock();
1304         if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1305             XSetFunction( gdi_display, physDevDst->gc, GXclear );
1306         else
1307         {
1308             XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1309             XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1310             XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1311         }
1312         XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1313                         physDevDst->dc_rect.left + visRectDst.left,
1314                         physDevDst->dc_rect.top + visRectDst.top,
1315                         width, height );
1316         wine_tsx11_unlock();
1317         return TRUE;
1318
1319     case DSTINVERT:  /* 0x55 */
1320         wine_tsx11_lock();
1321         XSetFunction( gdi_display, physDevDst->gc, GXinvert );
1322
1323         if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1324             XSetFunction( gdi_display, physDevDst->gc, GXinvert);
1325         else
1326         {
1327             /* Xor is much better when we do not have full colormap.   */
1328             /* Using white^black ensures that we invert at least black */
1329             /* and white. */
1330             unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1331                                      BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1332             XSetFunction( gdi_display, physDevDst->gc, GXxor );
1333             XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1334             XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1335         }
1336         XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1337                         physDevDst->dc_rect.left + visRectDst.left,
1338                         physDevDst->dc_rect.top + visRectDst.top,
1339                         width, height );
1340         wine_tsx11_unlock();
1341         return TRUE;
1342
1343     case PATINVERT:  /* 0x5a */
1344         if (X11DRV_SetupGCForBrush( physDevDst ))
1345         {
1346             wine_tsx11_lock();
1347             XSetFunction( gdi_display, physDevDst->gc, GXxor );
1348             XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1349                             physDevDst->dc_rect.left + visRectDst.left,
1350                             physDevDst->dc_rect.top + visRectDst.top,
1351                             width, height );
1352             wine_tsx11_unlock();
1353         }
1354         return TRUE;
1355
1356     case 0xa50065:
1357         if (X11DRV_SetupGCForBrush( physDevDst ))
1358         {
1359             wine_tsx11_lock();
1360             XSetFunction( gdi_display, physDevDst->gc, GXequiv );
1361             XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1362                             physDevDst->dc_rect.left + visRectDst.left,
1363                             physDevDst->dc_rect.top + visRectDst.top,
1364                             width, height );
1365             wine_tsx11_unlock();
1366         }
1367         return TRUE;
1368
1369     case SRCCOPY:  /* 0xcc */
1370         if (physDevSrc->depth == physDevDst->depth)
1371         {
1372             wine_tsx11_lock();
1373             XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1374             XCopyArea( gdi_display, physDevSrc->drawable,
1375                        physDevDst->drawable, physDevDst->gc,
1376                        physDevSrc->dc_rect.left + visRectSrc.left,
1377                        physDevSrc->dc_rect.top + visRectSrc.top,
1378                        width, height,
1379                        physDevDst->dc_rect.left + visRectDst.left,
1380                        physDevDst->dc_rect.top + visRectDst.top );
1381             physDevDst->exposures++;
1382             wine_tsx11_unlock();
1383             return TRUE;
1384         }
1385
1386         if (physDevSrc->depth == 1)
1387         {
1388             int fg, bg;
1389             get_colors(physDevDst, physDevSrc, &fg, &bg);
1390             wine_tsx11_lock();
1391
1392             XSetBackground( gdi_display, physDevDst->gc, fg );
1393             XSetForeground( gdi_display, physDevDst->gc, bg );
1394             XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1395             XCopyPlane( gdi_display, physDevSrc->drawable,
1396                         physDevDst->drawable, physDevDst->gc,
1397                         physDevSrc->dc_rect.left + visRectSrc.left,
1398                         physDevSrc->dc_rect.top + visRectSrc.top,
1399                         width, height,
1400                         physDevDst->dc_rect.left + visRectDst.left,
1401                         physDevDst->dc_rect.top + visRectDst.top, 1 );
1402             physDevDst->exposures++;
1403             wine_tsx11_unlock();
1404             return TRUE;
1405         }
1406         break;
1407
1408     case PATCOPY:  /* 0xf0 */
1409         if (!X11DRV_SetupGCForBrush( physDevDst )) return TRUE;
1410         wine_tsx11_lock();
1411         XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1412         XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1413                         physDevDst->dc_rect.left + visRectDst.left,
1414                         physDevDst->dc_rect.top + visRectDst.top,
1415                         width, height );
1416         wine_tsx11_unlock();
1417         return TRUE;
1418
1419     case WHITENESS:  /* 0xff */
1420         wine_tsx11_lock();
1421         if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1422             XSetFunction( gdi_display, physDevDst->gc, GXset );
1423         else
1424         {
1425             XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1426             XSetForeground( gdi_display, physDevDst->gc,
1427                             WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1428             XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1429         }
1430         XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1431                         physDevDst->dc_rect.left + visRectDst.left,
1432                         physDevDst->dc_rect.top + visRectDst.top,
1433                         width, height );
1434         wine_tsx11_unlock();
1435         return TRUE;
1436     }
1437
1438     wine_tsx11_lock();
1439
1440     tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1441     XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1442     XSetGraphicsExposures( gdi_display, tmpGC, False );
1443     pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1444                                   physDevDst->depth );
1445     if (useSrc)
1446     {
1447         pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1448                                       physDevDst->depth );
1449         if (fStretch)
1450             BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1451                                       xSrc, ySrc, widthSrc, heightSrc,
1452                                       xDst, yDst, widthDst, heightDst,
1453                                       &visRectSrc, &visRectDst );
1454         else
1455             BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1456                                xSrc, ySrc, &visRectSrc );
1457     }
1458
1459     if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &visRectDst );
1460     if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1461     else fNullBrush = FALSE;
1462     destUsed = FALSE;
1463
1464     for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1465     {
1466         if (OP_DST(*opcode) == DST) destUsed = TRUE;
1467         XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1468         switch(OP_SRCDST(*opcode))
1469         {
1470         case OP_ARGS(DST,TMP):
1471         case OP_ARGS(SRC,TMP):
1472             if (!pixmaps[TMP])
1473                 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1474                                               width, height, physDevDst->depth );
1475             /* fall through */
1476         case OP_ARGS(DST,SRC):
1477         case OP_ARGS(SRC,DST):
1478         case OP_ARGS(TMP,SRC):
1479         case OP_ARGS(TMP,DST):
1480             if (useSrc)
1481                 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1482                            pixmaps[OP_DST(*opcode)], tmpGC,
1483                            0, 0, width, height, 0, 0 );
1484             break;
1485
1486         case OP_ARGS(PAT,TMP):
1487             if (!pixmaps[TMP] && !fNullBrush)
1488                 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1489                                               width, height, physDevDst->depth );
1490             /* fall through */
1491         case OP_ARGS(PAT,DST):
1492         case OP_ARGS(PAT,SRC):
1493             if (!fNullBrush)
1494                 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1495                                 tmpGC, 0, 0, width, height );
1496             break;
1497         }
1498     }
1499     XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1500     physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC],
1501                                                 &visRectDst );
1502     XFreePixmap( gdi_display, pixmaps[DST] );
1503     if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1504     if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1505     XFreeGC( gdi_display, tmpGC );
1506     wine_tsx11_unlock();
1507     return TRUE;
1508 }
1509
1510
1511 /***********************************************************************
1512  *           X11DRV_PatBlt
1513  */
1514 BOOL X11DRV_PatBlt( X11DRV_PDEVICE *physDev, INT left, INT top, INT width, INT height, DWORD rop )
1515 {
1516     BOOL result;
1517
1518     X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1519     result = BITBLT_InternalStretchBlt( physDev, left, top, width, height, NULL, 0, 0, 0, 0, rop );
1520     X11DRV_UnlockDIBSection( physDev, TRUE );
1521     return result;
1522 }
1523
1524
1525 /***********************************************************************
1526  *           X11DRV_ClientSideDIBCopy
1527  */
1528 static BOOL X11DRV_ClientSideDIBCopy( X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1529                                       X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1530                                       INT width, INT height )
1531 {
1532     DIBSECTION srcDib, dstDib;
1533     BYTE *srcPtr, *dstPtr;
1534     INT srcRowOffset, dstRowOffset;
1535     INT bytesPerPixel;
1536     INT bytesToCopy;
1537     INT y;
1538     static RECT unusedRect;
1539
1540     if (GetObjectW(physDevSrc->bitmap->hbitmap, sizeof(srcDib), &srcDib) != sizeof(srcDib))
1541       return FALSE;
1542     if (GetObjectW(physDevDst->bitmap->hbitmap, sizeof(dstDib), &dstDib) != sizeof(dstDib))
1543       return FALSE;
1544
1545     /* check for oversized values, just like X11DRV_DIB_CopyDIBSection() */
1546     if (xSrc > srcDib.dsBm.bmWidth || ySrc > srcDib.dsBm.bmHeight)
1547       return FALSE;
1548     if (xSrc + width > srcDib.dsBm.bmWidth)
1549       width = srcDib.dsBm.bmWidth - xSrc;
1550     if (ySrc + height > srcDib.dsBm.bmHeight)
1551       height = srcDib.dsBm.bmHeight - ySrc;
1552
1553     if (GetRgnBox(physDevSrc->region, &unusedRect) == COMPLEXREGION ||
1554         GetRgnBox(physDevDst->region, &unusedRect) == COMPLEXREGION)
1555     {
1556       /* for simple regions, the clipping was already done by BITBLT_GetVisRectangles */
1557       FIXME("potential optimization: client-side complex region clipping\n");
1558       return FALSE;
1559     }
1560     if (dstDib.dsBm.bmBitsPixel <= 8)
1561     {
1562       FIXME("potential optimization: client-side color-index mode DIB copy\n");
1563       return FALSE;
1564     }
1565     if (!(srcDib.dsBmih.biCompression == BI_BITFIELDS &&
1566           dstDib.dsBmih.biCompression == BI_BITFIELDS &&
1567           !memcmp(srcDib.dsBitfields, dstDib.dsBitfields, 3*sizeof(DWORD)))
1568         && !(srcDib.dsBmih.biCompression == BI_RGB &&
1569              dstDib.dsBmih.biCompression == BI_RGB))
1570     {
1571       FIXME("potential optimization: client-side compressed DIB copy\n");
1572       return FALSE;
1573     }
1574     if (srcDib.dsBm.bmBitsPixel != dstDib.dsBm.bmBitsPixel)
1575     {
1576       FIXME("potential optimization: pixel format conversion\n");
1577       return FALSE;
1578     }
1579     if (srcDib.dsBmih.biWidth < 0 || dstDib.dsBmih.biWidth < 0)
1580     {
1581       FIXME("negative widths not yet implemented\n");
1582       return FALSE;
1583     }
1584
1585     switch (dstDib.dsBm.bmBitsPixel)
1586     {
1587       case 15:
1588       case 16:
1589         bytesPerPixel = 2;
1590         break;
1591       case 24:
1592         bytesPerPixel = 3;
1593         break;
1594       case 32:
1595         bytesPerPixel = 4;
1596         break;
1597       default:
1598         FIXME("don't know how to work with a depth of %d\n", physDevSrc->depth);
1599         return FALSE;
1600     }
1601
1602     bytesToCopy = width * bytesPerPixel;
1603
1604     if (srcDib.dsBmih.biHeight < 0)
1605     {
1606       srcPtr = &physDevSrc->bitmap->base[ySrc*srcDib.dsBm.bmWidthBytes + xSrc*bytesPerPixel];
1607       srcRowOffset = srcDib.dsBm.bmWidthBytes;
1608     }
1609     else
1610     {
1611       srcPtr = &physDevSrc->bitmap->base[(srcDib.dsBm.bmHeight-ySrc-1)*srcDib.dsBm.bmWidthBytes
1612         + xSrc*bytesPerPixel];
1613       srcRowOffset = -srcDib.dsBm.bmWidthBytes;
1614     }
1615     if (dstDib.dsBmih.biHeight < 0)
1616     {
1617       dstPtr = &physDevDst->bitmap->base[yDst*dstDib.dsBm.bmWidthBytes + xDst*bytesPerPixel];
1618       dstRowOffset = dstDib.dsBm.bmWidthBytes;
1619     }
1620     else
1621     {
1622       dstPtr = &physDevDst->bitmap->base[(dstDib.dsBm.bmHeight-yDst-1)*dstDib.dsBm.bmWidthBytes
1623         + xDst*bytesPerPixel];
1624       dstRowOffset = -dstDib.dsBm.bmWidthBytes;
1625     }
1626
1627     for (y = yDst; y < yDst + height; ++y)
1628     {
1629       memcpy(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, FALSE );
1657     if (physDevDst != physDevSrc)
1658         sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None, FALSE );
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, FALSE );
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, FALSE );
1719     if (physDevDst != physDevSrc)
1720       X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
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, FALSE );
1745     if (physDevDst != physDevSrc)
1746       X11DRV_LockDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
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 }