mciqtz32: Fix open/close omissions.
[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     X11DRV_DIB_DestroyXImage( 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             X11DRV_DIB_DestroyXImage( 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  *           client_side_dib_copy
1235  */
1236 static BOOL client_side_dib_copy( X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1237                                   X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1238                                   INT width, INT height )
1239 {
1240     DIBSECTION srcDib, dstDib;
1241     BYTE *srcPtr, *dstPtr;
1242     INT srcRowOffset, dstRowOffset;
1243     INT bytesPerPixel;
1244     INT bytesToCopy;
1245     INT y;
1246     static RECT unusedRect;
1247
1248     if (GetObjectW(physDevSrc->bitmap->hbitmap, sizeof(srcDib), &srcDib) != sizeof(srcDib))
1249       return FALSE;
1250     if (GetObjectW(physDevDst->bitmap->hbitmap, sizeof(dstDib), &dstDib) != sizeof(dstDib))
1251       return FALSE;
1252
1253     /* check for oversized values, just like X11DRV_DIB_CopyDIBSection() */
1254     if (xSrc > srcDib.dsBm.bmWidth || ySrc > srcDib.dsBm.bmHeight)
1255       return FALSE;
1256     if (xSrc + width > srcDib.dsBm.bmWidth)
1257       width = srcDib.dsBm.bmWidth - xSrc;
1258     if (ySrc + height > srcDib.dsBm.bmHeight)
1259       height = srcDib.dsBm.bmHeight - ySrc;
1260
1261     if (GetRgnBox(physDevDst->region, &unusedRect) == COMPLEXREGION)
1262     {
1263       /* for simple regions, the clipping was already done by BITBLT_GetVisRectangles */
1264       FIXME("potential optimization: client-side complex region clipping\n");
1265       return FALSE;
1266     }
1267     if (dstDib.dsBm.bmBitsPixel <= 8)
1268     {
1269       FIXME("potential optimization: client-side color-index mode DIB copy\n");
1270       return FALSE;
1271     }
1272     if (!(srcDib.dsBmih.biCompression == BI_BITFIELDS &&
1273           dstDib.dsBmih.biCompression == BI_BITFIELDS &&
1274           !memcmp(srcDib.dsBitfields, dstDib.dsBitfields, 3*sizeof(DWORD)))
1275         && !(srcDib.dsBmih.biCompression == BI_RGB &&
1276              dstDib.dsBmih.biCompression == BI_RGB))
1277     {
1278       FIXME("potential optimization: client-side compressed DIB copy\n");
1279       return FALSE;
1280     }
1281     if (srcDib.dsBm.bmBitsPixel != dstDib.dsBm.bmBitsPixel)
1282     {
1283       FIXME("potential optimization: pixel format conversion\n");
1284       return FALSE;
1285     }
1286     if (srcDib.dsBmih.biWidth < 0 || dstDib.dsBmih.biWidth < 0)
1287     {
1288       FIXME("negative widths not yet implemented\n");
1289       return FALSE;
1290     }
1291
1292     switch (dstDib.dsBm.bmBitsPixel)
1293     {
1294       case 15:
1295       case 16:
1296         bytesPerPixel = 2;
1297         break;
1298       case 24:
1299         bytesPerPixel = 3;
1300         break;
1301       case 32:
1302         bytesPerPixel = 4;
1303         break;
1304       default:
1305         FIXME("don't know how to work with a depth of %d\n", physDevSrc->depth);
1306         return FALSE;
1307     }
1308
1309     bytesToCopy = width * bytesPerPixel;
1310
1311     if (srcDib.dsBmih.biHeight < 0)
1312     {
1313       srcPtr = &physDevSrc->bitmap->base[ySrc*srcDib.dsBm.bmWidthBytes + xSrc*bytesPerPixel];
1314       srcRowOffset = srcDib.dsBm.bmWidthBytes;
1315     }
1316     else
1317     {
1318       srcPtr = &physDevSrc->bitmap->base[(srcDib.dsBm.bmHeight-ySrc-1)*srcDib.dsBm.bmWidthBytes
1319         + xSrc*bytesPerPixel];
1320       srcRowOffset = -srcDib.dsBm.bmWidthBytes;
1321     }
1322     if (dstDib.dsBmih.biHeight < 0)
1323     {
1324       dstPtr = &physDevDst->bitmap->base[yDst*dstDib.dsBm.bmWidthBytes + xDst*bytesPerPixel];
1325       dstRowOffset = dstDib.dsBm.bmWidthBytes;
1326     }
1327     else
1328     {
1329       dstPtr = &physDevDst->bitmap->base[(dstDib.dsBm.bmHeight-yDst-1)*dstDib.dsBm.bmWidthBytes
1330         + xDst*bytesPerPixel];
1331       dstRowOffset = -dstDib.dsBm.bmWidthBytes;
1332     }
1333
1334     /* Handle overlapping regions on the same DIB */
1335     if (physDevSrc == physDevDst && ySrc < yDst)
1336     {
1337       srcPtr += srcRowOffset * (height - 1);
1338       srcRowOffset = -srcRowOffset;
1339       dstPtr += dstRowOffset * (height - 1);
1340       dstRowOffset = -dstRowOffset;
1341     }
1342
1343     for (y = yDst; y < yDst + height; ++y)
1344     {
1345       memmove(dstPtr, srcPtr, bytesToCopy);
1346       srcPtr += srcRowOffset;
1347       dstPtr += dstRowOffset;
1348     }
1349
1350     return TRUE;
1351 }
1352
1353 static BOOL same_format(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst)
1354 {
1355     if (physDevSrc->depth != physDevDst->depth) return FALSE;
1356     if (!physDevSrc->color_shifts && !physDevDst->color_shifts) return TRUE;
1357     if (physDevSrc->color_shifts && physDevDst->color_shifts)
1358         return !memcmp(physDevSrc->color_shifts, physDevDst->color_shifts, sizeof(ColorShifts));
1359     return FALSE;
1360 }
1361
1362 /***********************************************************************
1363  *           X11DRV_StretchBlt
1364  */
1365 BOOL CDECL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1366                               X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1367                               DWORD rop )
1368 {
1369     BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1370     RECT visRectDst, visRectSrc;
1371     INT width, height;
1372     INT sDst, sSrc = DIB_Status_None;
1373     const BYTE *opcode;
1374     Pixmap pixmaps[3] = { 0, 0, 0 };  /* pixmaps for DST, SRC, TMP */
1375     GC tmpGC = 0;
1376     POINT pts[2];
1377
1378     /* compensate for off-by-one shifting for negative widths and heights */
1379     if (widthDst < 0)
1380         ++xDst;
1381     if (heightDst < 0)
1382         ++yDst;
1383     if (widthSrc < 0)
1384         ++xSrc;
1385     if (heightSrc < 0)
1386         ++ySrc;
1387
1388     usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1389     useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1390     useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1391     if (!physDevSrc && useSrc) return FALSE;
1392
1393       /* Map the coordinates to device coords */
1394
1395     pts[0].x = xDst;
1396     pts[0].y = yDst;
1397     pts[1].x = xDst + widthDst;
1398     pts[1].y = yDst + heightDst;
1399     LPtoDP(physDevDst->hdc, pts, 2);
1400     xDst      = pts[0].x;
1401     yDst      = pts[0].y;
1402     widthDst  = pts[1].x - pts[0].x;
1403     heightDst = pts[1].y - pts[0].y;
1404
1405     TRACE("    rectdst=%d,%d-%d,%d orgdst=%d,%d\n",
1406                     xDst, yDst, widthDst, heightDst,
1407                     physDevDst->dc_rect.left, physDevDst->dc_rect.top );
1408
1409     if (useSrc)
1410     {
1411         pts[0].x = xSrc;
1412         pts[0].y = ySrc;
1413         pts[1].x = xSrc + widthSrc;
1414         pts[1].y = ySrc + heightSrc;
1415         LPtoDP(physDevSrc->hdc, pts, 2);
1416         xSrc      = pts[0].x;
1417         ySrc      = pts[0].y;
1418         widthSrc  = pts[1].x - pts[0].x;
1419         heightSrc = pts[1].y - pts[0].y;
1420
1421         fStretch  = (widthSrc != widthDst) || (heightSrc != heightDst);
1422         TRACE("    rectsrc=%d,%d-%d,%d orgsrc=%d,%d\n",
1423                         xSrc, ySrc, widthSrc, heightSrc,
1424                         physDevSrc->dc_rect.left, physDevSrc->dc_rect.top );
1425         if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1426                                       physDevSrc, xSrc, ySrc, widthSrc, heightSrc,
1427                                       &visRectSrc, &visRectDst ))
1428             return TRUE;
1429         TRACE("    vissrc=%d,%d-%d,%d visdst=%d,%d-%d,%d\n",
1430                         visRectSrc.left, visRectSrc.top,
1431                         visRectSrc.right, visRectSrc.bottom,
1432                         visRectDst.left, visRectDst.top,
1433                         visRectDst.right, visRectDst.bottom );
1434         if (physDevDst != physDevSrc)
1435             sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None );
1436     }
1437     else
1438     {
1439         fStretch = FALSE;
1440         if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1441                                       NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1442             return TRUE;
1443         TRACE("    vissrc=none visdst=%d,%d-%d,%d\n",
1444                         visRectDst.left, visRectDst.top,
1445                         visRectDst.right, visRectDst.bottom );
1446     }
1447
1448     width  = visRectDst.right - visRectDst.left;
1449     height = visRectDst.bottom - visRectDst.top;
1450
1451     sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None );
1452     if (physDevDst == physDevSrc) sSrc = sDst;
1453
1454     /* try client-side DIB copy */
1455     if (!fStretch && rop == SRCCOPY &&
1456         sSrc == DIB_Status_AppMod && sDst == DIB_Status_AppMod &&
1457         same_format(physDevSrc, physDevDst))
1458     {
1459         if (client_side_dib_copy( physDevSrc, visRectSrc.left, visRectSrc.top,
1460                                   physDevDst, visRectDst.left, visRectDst.top, width, height ))
1461             goto done;
1462     }
1463
1464     X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod );
1465
1466     opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1467
1468     /* a few optimizations for single-op ROPs */
1469     if (!fStretch && !opcode[1])
1470     {
1471         if (OP_SRCDST(*opcode) == OP_ARGS(PAT,DST))
1472         {
1473             switch(rop)  /* a few special cases */
1474             {
1475             case BLACKNESS:  /* 0x00 */
1476             case WHITENESS:  /* 0xff */
1477                 if ((physDevDst->depth != 1) && X11DRV_PALETTE_PaletteToXPixel)
1478                 {
1479                     wine_tsx11_lock();
1480                     XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1481                     if (rop == BLACKNESS)
1482                         XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1483                     else
1484                         XSetForeground( gdi_display, physDevDst->gc,
1485                                         WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1486                     XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1487                     XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1488                                     physDevDst->dc_rect.left + visRectDst.left,
1489                                     physDevDst->dc_rect.top + visRectDst.top,
1490                                     width, height );
1491                     wine_tsx11_unlock();
1492                     goto done;
1493                 }
1494                 break;
1495             case DSTINVERT:  /* 0x55 */
1496                 if (!(X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL)))
1497                 {
1498                     /* Xor is much better when we do not have full colormap.   */
1499                     /* Using white^black ensures that we invert at least black */
1500                     /* and white. */
1501                     unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1502                                              BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1503                     wine_tsx11_lock();
1504                     XSetFunction( gdi_display, physDevDst->gc, GXxor );
1505                     XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1506                     XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1507                     XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1508                                     physDevDst->dc_rect.left + visRectDst.left,
1509                                     physDevDst->dc_rect.top + visRectDst.top,
1510                                     width, height );
1511                     wine_tsx11_unlock();
1512                     goto done;
1513                 }
1514                 break;
1515             }
1516             if (!usePat || X11DRV_SetupGCForBrush( physDevDst ))
1517             {
1518                 wine_tsx11_lock();
1519                 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1520                 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1521                                 physDevDst->dc_rect.left + visRectDst.left,
1522                                 physDevDst->dc_rect.top + visRectDst.top,
1523                                 width, height );
1524                 wine_tsx11_unlock();
1525             }
1526             goto done;
1527         }
1528         else if (OP_SRCDST(*opcode) == OP_ARGS(SRC,DST))
1529         {
1530             if (same_format(physDevSrc, physDevDst))
1531             {
1532                 wine_tsx11_lock();
1533                 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1534                 wine_tsx11_unlock();
1535
1536                 if (physDevSrc != physDevDst)
1537                 {
1538                     if (sSrc == DIB_Status_AppMod)
1539                     {
1540                         X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, visRectSrc.left, visRectSrc.top,
1541                                                    visRectDst.left, visRectDst.top, width, height );
1542                         goto done;
1543                     }
1544                     X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1545                 }
1546                 wine_tsx11_lock();
1547                 XCopyArea( gdi_display, physDevSrc->drawable,
1548                            physDevDst->drawable, physDevDst->gc,
1549                            physDevSrc->dc_rect.left + visRectSrc.left,
1550                            physDevSrc->dc_rect.top + visRectSrc.top,
1551                            width, height,
1552                            physDevDst->dc_rect.left + visRectDst.left,
1553                            physDevDst->dc_rect.top + visRectDst.top );
1554                 physDevDst->exposures++;
1555                 wine_tsx11_unlock();
1556                 goto done;
1557             }
1558             if (physDevSrc->depth == 1)
1559             {
1560                 int fg, bg;
1561
1562                 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1563                 get_colors(physDevDst, physDevSrc, &fg, &bg);
1564                 wine_tsx11_lock();
1565                 XSetBackground( gdi_display, physDevDst->gc, fg );
1566                 XSetForeground( gdi_display, physDevDst->gc, bg );
1567                 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1568                 XCopyPlane( gdi_display, physDevSrc->drawable,
1569                             physDevDst->drawable, physDevDst->gc,
1570                             physDevSrc->dc_rect.left + visRectSrc.left,
1571                             physDevSrc->dc_rect.top + visRectSrc.top,
1572                             width, height,
1573                             physDevDst->dc_rect.left + visRectDst.left,
1574                             physDevDst->dc_rect.top + visRectDst.top, 1 );
1575                 physDevDst->exposures++;
1576                 wine_tsx11_unlock();
1577                 goto done;
1578             }
1579         }
1580     }
1581
1582     wine_tsx11_lock();
1583     tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1584     XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1585     XSetGraphicsExposures( gdi_display, tmpGC, False );
1586     pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1587                                   physDevDst->depth );
1588     wine_tsx11_unlock();
1589
1590     if (useSrc)
1591     {
1592         wine_tsx11_lock();
1593         pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1594                                       physDevDst->depth );
1595         wine_tsx11_unlock();
1596
1597         if (physDevDst != physDevSrc) X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1598
1599         if(!X11DRV_XRender_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1600                                               widthSrc, heightSrc, widthDst, heightDst,
1601                                               &visRectSrc, &visRectDst))
1602         {
1603             if (fStretch)
1604                 BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1605                                           xSrc, ySrc, widthSrc, heightSrc,
1606                                           xDst, yDst, widthDst, heightDst,
1607                                           &visRectSrc, &visRectDst );
1608             else
1609                 BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1610                                   &visRectSrc );
1611         }
1612     }
1613
1614     if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &visRectDst );
1615     if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1616     else fNullBrush = FALSE;
1617     destUsed = FALSE;
1618
1619     wine_tsx11_lock();
1620     for ( ; *opcode; opcode++)
1621     {
1622         if (OP_DST(*opcode) == DST) destUsed = TRUE;
1623         XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1624         switch(OP_SRCDST(*opcode))
1625         {
1626         case OP_ARGS(DST,TMP):
1627         case OP_ARGS(SRC,TMP):
1628             if (!pixmaps[TMP])
1629                 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1630                                               width, height, physDevDst->depth );
1631             /* fall through */
1632         case OP_ARGS(DST,SRC):
1633         case OP_ARGS(SRC,DST):
1634         case OP_ARGS(TMP,SRC):
1635         case OP_ARGS(TMP,DST):
1636             if (useSrc)
1637                 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1638                            pixmaps[OP_DST(*opcode)], tmpGC,
1639                            0, 0, width, height, 0, 0 );
1640             break;
1641
1642         case OP_ARGS(PAT,TMP):
1643             if (!pixmaps[TMP] && !fNullBrush)
1644                 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1645                                               width, height, physDevDst->depth );
1646             /* fall through */
1647         case OP_ARGS(PAT,DST):
1648         case OP_ARGS(PAT,SRC):
1649             if (!fNullBrush)
1650                 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1651                                 tmpGC, 0, 0, width, height );
1652             break;
1653         }
1654     }
1655     XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1656     physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC],
1657                                                 &visRectDst );
1658     XFreePixmap( gdi_display, pixmaps[DST] );
1659     if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1660     if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1661     XFreeGC( gdi_display, tmpGC );
1662     wine_tsx11_unlock();
1663
1664 done:
1665     if (useSrc && physDevDst != physDevSrc) X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1666     X11DRV_UnlockDIBSection( physDevDst, TRUE );
1667     return TRUE;
1668 }