winex11.drv: Preliminary support for Xinerama.
[wine] / dlls / winex11.drv / bitblt.c
1 /*
2  * GDI bit-blit operations
3  *
4  * Copyright 1993, 1994  Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winreg.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(SRC,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 = ((int)widthSrc * widthDst) < 0;
685     vswap = ((int)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 = ((int)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     if (vstretch)
721     {
722         yinc = ((int)heightSrc << 16) / heightDst;
723         ydst = visRectDst->top;
724         if (vswap)
725         {
726             ysrc = yinc * (heightDst - ydst - 1);
727             yinc = -yinc;
728         }
729         else
730             ysrc = yinc * ydst;
731
732         for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
733         {
734             if (((ysrc >> 16) < visRectSrc->top) ||
735                 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
736
737             /* Retrieve a source row */
738             BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
739                            hswap ? widthSrc - visRectSrc->right
740                                  : visRectSrc->left,
741                            visRectSrc->right - visRectSrc->left,
742                            dstImage->depth, foreground, background, hswap );
743
744             /* Stretch or shrink it */
745             if (hstretch)
746                 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
747                                    visRectDst->right - visRectDst->left,
748                                    xinc, xoff, mode );
749             else BITBLT_ShrinkRow( rowSrc, rowDst,
750                                    hswap ? widthSrc - visRectSrc->right
751                                          : visRectSrc->left,
752                                    visRectSrc->right - visRectSrc->left,
753                                    xinc, xoff, mode );
754
755             /* Store the destination row */
756             pixel = rowDst + visRectDst->right - 1;
757             y = ydst - visRectDst->top;
758             for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
759                 XPutPixel( dstImage, x, y, *pixel-- );
760             if (mode != STRETCH_DELETESCANS)
761                 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
762                         widthDst*sizeof(int) );
763
764             /* Make copies of the destination row */
765
766             pdata = dstImage->data + dstImage->bytes_per_line * y;
767             while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
768                    (ydst < visRectDst->bottom-1))
769             {
770                 memcpy( pdata + dstImage->bytes_per_line, pdata,
771                         dstImage->bytes_per_line );
772                 pdata += dstImage->bytes_per_line;
773                 ysrc += yinc;
774                 ydst++;
775             }
776         }
777     }
778     else  /* Shrinking */
779     {
780         yinc = ((int)heightDst << 16) / heightSrc;
781         ysrc = visRectSrc->top;
782         ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
783         if (vswap)
784         {
785             ydst += yinc * (heightSrc - ysrc - 1);
786             yinc = -yinc;
787         }
788         else
789             ydst += yinc * ysrc;
790
791         for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
792         {
793             if (((ydst >> 16) < visRectDst->top) ||
794                 ((ydst >> 16) >= visRectDst->bottom)) continue;
795
796             /* Retrieve a source row */
797             BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
798                            hswap ? widthSrc - visRectSrc->right
799                                  : visRectSrc->left,
800                            visRectSrc->right - visRectSrc->left,
801                            dstImage->depth, foreground, background, hswap );
802
803             /* Stretch or shrink it */
804             if (hstretch)
805                 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
806                                    visRectDst->right - visRectDst->left,
807                                    xinc, xoff, mode );
808             else BITBLT_ShrinkRow( rowSrc, rowDst,
809                                    hswap ? widthSrc - visRectSrc->right
810                                          : visRectSrc->left,
811                                    visRectSrc->right - visRectSrc->left,
812                                    xinc, xoff, mode );
813
814             /* Merge several source rows into the destination */
815             if (mode == STRETCH_DELETESCANS)
816             {
817                 /* Simply skip the overlapping rows */
818                 while (((ydst + yinc) >> 16 == ydst >> 16) &&
819                        (ysrc < visRectSrc->bottom-1))
820                 {
821                     ydst += yinc;
822                     ysrc++;
823                 }
824             }
825             else if (((ydst + yinc) >> 16 == ydst >> 16) &&
826                      (ysrc < visRectSrc->bottom-1))
827                 continue;  /* Restart loop for next overlapping row */
828
829             /* Store the destination row */
830             pixel = rowDst + visRectDst->right - 1;
831             y = (ydst >> 16) - visRectDst->top;
832             for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
833                 XPutPixel( dstImage, x, y, *pixel-- );
834             if (mode != STRETCH_DELETESCANS)
835                 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
836                         widthDst*sizeof(int) );
837         }
838     }
839     HeapFree( GetProcessHeap(), 0, rowSrc );
840 }
841
842
843 /***********************************************************************
844  *           BITBLT_GetSrcAreaStretch
845  *
846  * Retrieve an area from the source DC, stretching and mapping all the
847  * pixels to Windows colors.
848  */
849 static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
850                                       Pixmap pixmap, GC gc,
851                                       INT xSrc, INT ySrc,
852                                       INT widthSrc, INT heightSrc,
853                                       INT xDst, INT yDst,
854                                       INT widthDst, INT heightDst,
855                                       RECT *visRectSrc, RECT *visRectDst )
856 {
857     XImage *imageSrc, *imageDst;
858     RECT rectSrc = *visRectSrc;
859     RECT rectDst = *visRectDst;
860     int fg, bg;
861
862     if (widthSrc < 0) xSrc += widthSrc;
863     if (widthDst < 0) xDst += widthDst;
864     if (heightSrc < 0) ySrc += heightSrc;
865     if (heightDst < 0) yDst += heightDst;
866     rectSrc.left   -= xSrc;
867     rectSrc.right  -= xSrc;
868     rectSrc.top    -= ySrc;
869     rectSrc.bottom -= ySrc;
870     rectDst.left   -= xDst;
871     rectDst.right  -= xDst;
872     rectDst.top    -= yDst;
873     rectDst.bottom -= yDst;
874
875     get_colors(physDevDst, physDevSrc, &fg, &bg);
876     /* FIXME: avoid BadMatch errors */
877     imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
878                           physDevSrc->org.x + visRectSrc->left,
879                           physDevSrc->org.y + visRectSrc->top,
880                           visRectSrc->right - visRectSrc->left,
881                           visRectSrc->bottom - visRectSrc->top,
882                           AllPlanes, ZPixmap );
883     imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
884                                         rectDst.bottom - rectDst.top, physDevDst->depth );
885     BITBLT_StretchImage( imageSrc, imageDst, widthSrc, heightSrc,
886                          widthDst, heightDst, &rectSrc, &rectDst,
887                          fg, physDevDst->depth != 1 ?
888                          bg : physDevSrc->backgroundPixel,
889                          GetStretchBltMode(physDevDst->hdc) );
890     XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
891                rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
892     XDestroyImage( imageSrc );
893     XDestroyImage( imageDst );
894     return 0;  /* no exposure events generated */
895 }
896
897
898 /***********************************************************************
899  *           BITBLT_GetSrcArea
900  *
901  * Retrieve an area from the source DC, mapping all the
902  * pixels to Windows colors.
903  */
904 static int BITBLT_GetSrcArea( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
905                               Pixmap pixmap, GC gc, INT xSrc, INT ySrc, RECT *visRectSrc )
906 {
907     XImage *imageSrc, *imageDst;
908     register INT x, y;
909     int exposures = 0;
910     INT width  = visRectSrc->right - visRectSrc->left;
911     INT height = visRectSrc->bottom - visRectSrc->top;
912     int fg, bg;
913
914     if (physDevSrc->depth == physDevDst->depth)
915     {
916         if (!X11DRV_PALETTE_XPixelToPalette ||
917             (physDevDst->depth == 1))  /* monochrome -> monochrome */
918         {
919             if (physDevDst->depth == 1)
920             {
921                 /* MSDN says if StretchBlt must convert a bitmap from monochrome
922                    to color or vice versa, the forground and background color of
923                    the device context are used.  In fact, it also applies to the
924                    case when it is converted from mono to mono. */
925                 XSetBackground( gdi_display, gc, physDevDst->textPixel );
926                 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
927                 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
928                             physDevSrc->org.x + visRectSrc->left,
929                             physDevSrc->org.y + visRectSrc->top,
930                             width, height, 0, 0, 1);
931             }
932             else
933                 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
934                            physDevSrc->org.x + visRectSrc->left,
935                            physDevSrc->org.y + visRectSrc->top,
936                            width, height, 0, 0);
937             exposures++;
938         }
939         else  /* color -> color */
940         {
941             if (GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
942                 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
943                                       physDevSrc->org.x + visRectSrc->left,
944                                       physDevSrc->org.y + visRectSrc->top,
945                                       width, height, AllPlanes, ZPixmap );
946             else
947             {
948                 /* Make sure we don't get a BadMatch error */
949                 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
950                            physDevSrc->org.x + visRectSrc->left,
951                            physDevSrc->org.y + visRectSrc->top,
952                            width, height, 0, 0);
953                 exposures++;
954                 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
955                                       AllPlanes, ZPixmap );
956             }
957             for (y = 0; y < height; y++)
958                 for (x = 0; x < width; x++)
959                     XPutPixel(imageSrc, x, y,
960                               X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
961             XPutImage( gdi_display, pixmap, gc, imageSrc,
962                        0, 0, 0, 0, width, height );
963             XDestroyImage( imageSrc );
964         }
965     }
966     else
967     {
968         if (physDevSrc->depth == 1)  /* monochrome -> color */
969         {
970             get_colors(physDevDst, physDevSrc, &fg, &bg);
971
972             if (X11DRV_PALETTE_XPixelToPalette)
973             {
974                 XSetBackground( gdi_display, gc,
975                              X11DRV_PALETTE_XPixelToPalette[fg] );
976                 XSetForeground( gdi_display, gc,
977                              X11DRV_PALETTE_XPixelToPalette[bg]);
978             }
979             else
980             {
981                 XSetBackground( gdi_display, gc, fg );
982                 XSetForeground( gdi_display, gc, bg );
983             }
984             XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
985                         physDevSrc->org.x + visRectSrc->left,
986                         physDevSrc->org.y + visRectSrc->top,
987                         width, height, 0, 0, 1 );
988             exposures++;
989         }
990         else  /* color -> monochrome */
991         {
992             /* FIXME: avoid BadMatch error */
993             imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
994                                   physDevSrc->org.x + visRectSrc->left,
995                                   physDevSrc->org.y + visRectSrc->top,
996                                   width, height, AllPlanes, ZPixmap );
997             if (!imageSrc)
998             {
999                 return exposures;
1000             }
1001             imageDst = X11DRV_DIB_CreateXImage( width, height, physDevDst->depth );
1002             if (!imageDst) 
1003             {
1004                 XDestroyImage(imageSrc);
1005                 return exposures;
1006             }
1007             for (y = 0; y < height; y++)
1008                 for (x = 0; x < width; x++)
1009                     XPutPixel(imageDst, x, y, (XGetPixel(imageSrc,x,y) ==
1010                                                physDevSrc->backgroundPixel) );
1011             XPutImage( gdi_display, pixmap, gc, imageDst,
1012                        0, 0, 0, 0, width, height );
1013             XDestroyImage( imageSrc );
1014             XDestroyImage( imageDst );
1015         }
1016     }
1017     return exposures;
1018 }
1019
1020
1021 /***********************************************************************
1022  *           BITBLT_GetDstArea
1023  *
1024  * Retrieve an area from the destination DC, mapping all the
1025  * pixels to Windows colors.
1026  */
1027 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, RECT *visRectDst)
1028 {
1029     int exposures = 0;
1030     INT width  = visRectDst->right - visRectDst->left;
1031     INT height = visRectDst->bottom - visRectDst->top;
1032
1033     if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) ||
1034         (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1035     {
1036         XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1037                    physDev->org.x + visRectDst->left, physDev->org.y + visRectDst->top,
1038                    width, height, 0, 0 );
1039         exposures++;
1040     }
1041     else
1042     {
1043         register INT x, y;
1044         XImage *image;
1045
1046         if (GetObjectType( physDev->hdc ) == OBJ_MEMDC)
1047             image = XGetImage( gdi_display, physDev->drawable,
1048                                physDev->org.x + visRectDst->left,
1049                                physDev->org.y + visRectDst->top,
1050                                width, height, AllPlanes, ZPixmap );
1051         else
1052         {
1053             /* Make sure we don't get a BadMatch error */
1054             XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1055                        physDev->org.x + visRectDst->left,
1056                        physDev->org.y + visRectDst->top,
1057                        width, height, 0, 0);
1058             exposures++;
1059             image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1060                                AllPlanes, ZPixmap );
1061         }
1062         for (y = 0; y < height; y++)
1063             for (x = 0; x < width; x++)
1064                 XPutPixel( image, x, y,
1065                            X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1066         XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1067         XDestroyImage( image );
1068     }
1069     return exposures;
1070 }
1071
1072
1073 /***********************************************************************
1074  *           BITBLT_PutDstArea
1075  *
1076  * Put an area back into the destination DC, mapping the pixel
1077  * colors to X pixels.
1078  */
1079 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, RECT *visRectDst)
1080 {
1081     int exposures = 0;
1082     INT width  = visRectDst->right - visRectDst->left;
1083     INT height = visRectDst->bottom - visRectDst->top;
1084
1085     /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1086
1087     if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) ||
1088         (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1089     {
1090         XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1091                    physDev->org.x + visRectDst->left,
1092                    physDev->org.y + visRectDst->top );
1093         exposures++;
1094     }
1095     else
1096     {
1097         register INT x, y;
1098         XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1099                                    AllPlanes, ZPixmap );
1100         for (y = 0; y < height; y++)
1101             for (x = 0; x < width; x++)
1102             {
1103                 XPutPixel( image, x, y,
1104                            X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1105             }
1106         XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1107                    physDev->org.x + visRectDst->left,
1108                    physDev->org.y + visRectDst->top, width, height );
1109         XDestroyImage( image );
1110     }
1111     return exposures;
1112 }
1113
1114
1115 /***********************************************************************
1116  *           BITBLT_GetVisRectangles
1117  *
1118  * Get the source and destination visible rectangles for StretchBlt().
1119  * Return FALSE if one of the rectangles is empty.
1120  */
1121 static BOOL BITBLT_GetVisRectangles( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1122                                      INT widthDst, INT heightDst,
1123                                      X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1124                                      INT widthSrc, INT heightSrc,
1125                                      RECT *visRectSrc, RECT *visRectDst )
1126 {
1127     RECT rect, clipRect;
1128
1129       /* Get the destination visible rectangle */
1130
1131     rect.left   = xDst;
1132     rect.top    = yDst;
1133     rect.right  = xDst + widthDst;
1134     rect.bottom = yDst + heightDst;
1135     if (widthDst < 0) SWAP_INT32( &rect.left, &rect.right );
1136     if (heightDst < 0) SWAP_INT32( &rect.top, &rect.bottom );
1137     GetRgnBox( physDevDst->region, &clipRect );
1138     if (!IntersectRect( visRectDst, &rect, &clipRect )) return FALSE;
1139
1140       /* Get the source visible rectangle */
1141
1142     if (!physDevSrc) return TRUE;
1143     rect.left   = xSrc;
1144     rect.top    = ySrc;
1145     rect.right  = xSrc + widthSrc;
1146     rect.bottom = ySrc + heightSrc;
1147     if (widthSrc < 0) SWAP_INT32( &rect.left, &rect.right );
1148     if (heightSrc < 0) SWAP_INT32( &rect.top, &rect.bottom );
1149     /* Apparently the clipping and visible regions are only for output,
1150        so just check against dc extent here to avoid BadMatch errors */
1151     if (physDevSrc->bitmap)
1152     {
1153         BITMAP bm;
1154         GetObjectW( physDevSrc->bitmap->hbitmap, sizeof(bm), &bm );
1155         SetRect( &clipRect, 0, 0, bm.bmWidth, bm.bmHeight );
1156     }
1157     else clipRect = virtual_screen_rect;
1158     if (!IntersectRect( visRectSrc, &rect, &clipRect ))
1159         return FALSE;
1160
1161       /* Intersect the rectangles */
1162
1163     if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1164     {
1165         visRectSrc->left   += xDst - xSrc;
1166         visRectSrc->right  += xDst - xSrc;
1167         visRectSrc->top    += yDst - ySrc;
1168         visRectSrc->bottom += yDst - ySrc;
1169         if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1170         *visRectSrc = *visRectDst = rect;
1171         visRectSrc->left   += xSrc - xDst;
1172         visRectSrc->right  += xSrc - xDst;
1173         visRectSrc->top    += ySrc - yDst;
1174         visRectSrc->bottom += ySrc - yDst;
1175     }
1176     else  /* stretching */
1177     {
1178         /* Map source rectangle into destination coordinates */
1179         rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1180         rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1181         rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1182         rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1183         if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1184         if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1185
1186         /* Avoid rounding errors */
1187         rect.left--;
1188         rect.top--;
1189         rect.right++;
1190         rect.bottom++;
1191         if (!IntersectRect( visRectDst, &rect, visRectDst )) return FALSE;
1192
1193         /* Map destination rectangle back to source coordinates */
1194         rect = *visRectDst;
1195         rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1196         rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1197         rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1198         rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1199         if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1200         if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1201
1202         /* Avoid rounding errors */
1203         rect.left--;
1204         rect.top--;
1205         rect.right++;
1206         rect.bottom++;
1207         if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1208     }
1209     return TRUE;
1210 }
1211
1212
1213 /***********************************************************************
1214  *           BITBLT_InternalStretchBlt
1215  *
1216  * Implementation of PatBlt(), BitBlt() and StretchBlt().
1217  */
1218 static BOOL BITBLT_InternalStretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1219                                        INT widthDst, INT heightDst,
1220                                        X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1221                                        INT widthSrc, INT heightSrc,
1222                                        DWORD rop )
1223 {
1224     BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1225     RECT visRectDst, visRectSrc;
1226     INT width, height;
1227     const BYTE *opcode;
1228     Pixmap pixmaps[3] = { 0, 0, 0 };  /* pixmaps for DST, SRC, TMP */
1229     GC tmpGC = 0;
1230     POINT pts[2];
1231
1232     /* compensate for off-by-one shifting for negative widths and heights */
1233     if (widthDst < 0)
1234         ++xDst;
1235     if (heightDst < 0)
1236         ++yDst;
1237     if (widthSrc < 0)
1238         ++xSrc;
1239     if (heightSrc < 0)
1240         ++ySrc;
1241
1242     usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1243     useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1244     useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1245     if (!physDevSrc && useSrc) return FALSE;
1246
1247       /* Map the coordinates to device coords */
1248
1249     pts[0].x = xDst;
1250     pts[0].y = yDst;
1251     pts[1].x = xDst + widthDst;
1252     pts[1].y = yDst + heightDst;
1253     LPtoDP(physDevDst->hdc, pts, 2);
1254     xDst      = pts[0].x;
1255     yDst      = pts[0].y;
1256     widthDst  = pts[1].x - pts[0].x;
1257     heightDst = pts[1].y - pts[0].y;
1258
1259     TRACE("    rectdst=%d,%d-%d,%d orgdst=%d,%d\n",
1260                     xDst, yDst, widthDst, heightDst,
1261                     physDevDst->org.x, physDevDst->org.y );
1262
1263     if (useSrc)
1264     {
1265         pts[0].x = xSrc;
1266         pts[0].y = ySrc;
1267         pts[1].x = xSrc + widthSrc;
1268         pts[1].y = ySrc + heightSrc;
1269         LPtoDP(physDevSrc->hdc, pts, 2);
1270         xSrc      = pts[0].x;
1271         ySrc      = pts[0].y;
1272         widthSrc  = pts[1].x - pts[0].x;
1273         heightSrc = pts[1].y - pts[0].y;
1274
1275         fStretch  = (widthSrc != widthDst) || (heightSrc != heightDst);
1276         TRACE("    rectsrc=%d,%d-%d,%d orgsrc=%d,%d\n",
1277                         xSrc, ySrc, widthSrc, heightSrc,
1278                         physDevSrc->org.x, physDevSrc->org.y );
1279         if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1280                                       physDevSrc, xSrc, ySrc, widthSrc, heightSrc,
1281                                       &visRectSrc, &visRectDst ))
1282             return TRUE;
1283         TRACE("    vissrc=%d,%d-%d,%d visdst=%d,%d-%d,%d\n",
1284                         visRectSrc.left, visRectSrc.top,
1285                         visRectSrc.right, visRectSrc.bottom,
1286                         visRectDst.left, visRectDst.top,
1287                         visRectDst.right, visRectDst.bottom );
1288     }
1289     else
1290     {
1291         fStretch = FALSE;
1292         if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1293                                       NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1294             return TRUE;
1295         TRACE("    vissrc=none visdst=%d,%d-%d,%d\n",
1296                         visRectDst.left, visRectDst.top,
1297                         visRectDst.right, visRectDst.bottom );
1298     }
1299
1300     width  = visRectDst.right - visRectDst.left;
1301     height = visRectDst.bottom - visRectDst.top;
1302
1303     if (!fStretch) switch(rop)  /* A few optimisations */
1304     {
1305     case BLACKNESS:  /* 0x00 */
1306         wine_tsx11_lock();
1307         if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1308             XSetFunction( gdi_display, physDevDst->gc, GXclear );
1309         else
1310         {
1311             XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1312             XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1313             XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1314         }
1315         XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1316                         physDevDst->org.x + visRectDst.left,
1317                         physDevDst->org.y + visRectDst.top,
1318                         width, height );
1319         wine_tsx11_unlock();
1320         return TRUE;
1321
1322     case DSTINVERT:  /* 0x55 */
1323         wine_tsx11_lock();
1324         XSetFunction( gdi_display, physDevDst->gc, GXinvert );
1325
1326         if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1327             XSetFunction( gdi_display, physDevDst->gc, GXinvert);
1328         else
1329         {
1330             /* Xor is much better when we do not have full colormap.   */
1331             /* Using white^black ensures that we invert at least black */
1332             /* and white. */
1333             unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1334                                      BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1335             XSetFunction( gdi_display, physDevDst->gc, GXxor );
1336             XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1337             XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1338         }
1339         XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1340                         physDevDst->org.x + visRectDst.left,
1341                         physDevDst->org.y + visRectDst.top,
1342                         width, height );
1343         wine_tsx11_unlock();
1344         return TRUE;
1345
1346     case PATINVERT:  /* 0x5a */
1347         if (X11DRV_SetupGCForBrush( physDevDst ))
1348         {
1349             wine_tsx11_lock();
1350             XSetFunction( gdi_display, physDevDst->gc, GXxor );
1351             XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1352                             physDevDst->org.x + visRectDst.left,
1353                             physDevDst->org.y + visRectDst.top,
1354                             width, height );
1355             wine_tsx11_unlock();
1356         }
1357         return TRUE;
1358
1359     case 0xa50065:
1360         if (X11DRV_SetupGCForBrush( physDevDst ))
1361         {
1362             wine_tsx11_lock();
1363             XSetFunction( gdi_display, physDevDst->gc, GXequiv );
1364             XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1365                             physDevDst->org.x + visRectDst.left,
1366                             physDevDst->org.y + visRectDst.top,
1367                             width, height );
1368             wine_tsx11_unlock();
1369         }
1370         return TRUE;
1371
1372     case SRCCOPY:  /* 0xcc */
1373         if (physDevSrc->depth == physDevDst->depth)
1374         {
1375             wine_tsx11_lock();
1376             XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1377             XCopyArea( gdi_display, physDevSrc->drawable,
1378                        physDevDst->drawable, physDevDst->gc,
1379                        physDevSrc->org.x + visRectSrc.left,
1380                        physDevSrc->org.y + visRectSrc.top,
1381                        width, height,
1382                        physDevDst->org.x + visRectDst.left,
1383                        physDevDst->org.y + visRectDst.top );
1384             physDevDst->exposures++;
1385             wine_tsx11_unlock();
1386             return TRUE;
1387         }
1388
1389         if (physDevSrc->depth == 1)
1390         {
1391             int fg, bg;
1392             get_colors(physDevDst, physDevSrc, &fg, &bg);
1393             wine_tsx11_lock();
1394
1395             XSetBackground( gdi_display, physDevDst->gc, fg );
1396             XSetForeground( gdi_display, physDevDst->gc, bg );
1397             XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1398             XCopyPlane( gdi_display, physDevSrc->drawable,
1399                         physDevDst->drawable, physDevDst->gc,
1400                         physDevSrc->org.x + visRectSrc.left,
1401                         physDevSrc->org.y + visRectSrc.top,
1402                         width, height,
1403                         physDevDst->org.x + visRectDst.left,
1404                         physDevDst->org.y + visRectDst.top, 1 );
1405             physDevDst->exposures++;
1406             wine_tsx11_unlock();
1407             return TRUE;
1408         }
1409         break;
1410
1411     case PATCOPY:  /* 0xf0 */
1412         if (!X11DRV_SetupGCForBrush( physDevDst )) return TRUE;
1413         wine_tsx11_lock();
1414         XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1415         XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1416                         physDevDst->org.x + visRectDst.left,
1417                         physDevDst->org.y + visRectDst.top,
1418                         width, height );
1419         wine_tsx11_unlock();
1420         return TRUE;
1421
1422     case WHITENESS:  /* 0xff */
1423         wine_tsx11_lock();
1424         if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1425             XSetFunction( gdi_display, physDevDst->gc, GXset );
1426         else
1427         {
1428             XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1429             XSetForeground( gdi_display, physDevDst->gc,
1430                             WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1431             XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1432         }
1433         XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1434                         physDevDst->org.x + visRectDst.left,
1435                         physDevDst->org.y + visRectDst.top,
1436                         width, height );
1437         wine_tsx11_unlock();
1438         return TRUE;
1439     }
1440
1441     wine_tsx11_lock();
1442
1443     tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1444     XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1445     XSetGraphicsExposures( gdi_display, tmpGC, False );
1446     pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1447                                   physDevDst->depth );
1448     if (useSrc)
1449     {
1450         pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1451                                       physDevDst->depth );
1452         if (fStretch)
1453             BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1454                                       xSrc, ySrc, widthSrc, heightSrc,
1455                                       xDst, yDst, widthDst, heightDst,
1456                                       &visRectSrc, &visRectDst );
1457         else
1458             BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1459                                xSrc, ySrc, &visRectSrc );
1460     }
1461
1462     if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &visRectDst );
1463     if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1464     else fNullBrush = FALSE;
1465     destUsed = FALSE;
1466
1467     for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1468     {
1469         if (OP_DST(*opcode) == DST) destUsed = TRUE;
1470         XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1471         switch(OP_SRCDST(*opcode))
1472         {
1473         case OP_ARGS(DST,TMP):
1474         case OP_ARGS(SRC,TMP):
1475             if (!pixmaps[TMP])
1476                 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1477                                               width, height, physDevDst->depth );
1478             /* fall through */
1479         case OP_ARGS(DST,SRC):
1480         case OP_ARGS(SRC,DST):
1481         case OP_ARGS(TMP,SRC):
1482         case OP_ARGS(TMP,DST):
1483             if (useSrc)
1484                 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1485                            pixmaps[OP_DST(*opcode)], tmpGC,
1486                            0, 0, width, height, 0, 0 );
1487             break;
1488
1489         case OP_ARGS(PAT,TMP):
1490             if (!pixmaps[TMP] && !fNullBrush)
1491                 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1492                                               width, height, physDevDst->depth );
1493             /* fall through */
1494         case OP_ARGS(PAT,DST):
1495         case OP_ARGS(PAT,SRC):
1496             if (!fNullBrush)
1497                 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1498                                 tmpGC, 0, 0, width, height );
1499             break;
1500         }
1501     }
1502     XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1503     physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC],
1504                                                 &visRectDst );
1505     XFreePixmap( gdi_display, pixmaps[DST] );
1506     if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1507     if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1508     XFreeGC( gdi_display, tmpGC );
1509     wine_tsx11_unlock();
1510     return TRUE;
1511 }
1512
1513
1514 /***********************************************************************
1515  *           X11DRV_PatBlt
1516  */
1517 BOOL X11DRV_PatBlt( X11DRV_PDEVICE *physDev, INT left, INT top, INT width, INT height, DWORD rop )
1518 {
1519     BOOL result;
1520
1521     X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1522     result = BITBLT_InternalStretchBlt( physDev, left, top, width, height, NULL, 0, 0, 0, 0, rop );
1523     X11DRV_UnlockDIBSection( physDev, TRUE );
1524     return result;
1525 }
1526
1527
1528 /***********************************************************************
1529  *           X11DRV_BitBlt
1530  */
1531 BOOL X11DRV_BitBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1532                     INT width, INT height, X11DRV_PDEVICE *physDevSrc,
1533                     INT xSrc, INT ySrc, DWORD rop )
1534 {
1535     BOOL result = FALSE;
1536     INT sSrc, sDst;
1537     RECT visRectDst, visRectSrc;
1538
1539     if (((rop >> 16) & 0x55) == ((rop >> 17) & 0x55)) {
1540       /* FIXME: seems the ROP doesn't include destination;
1541        * now if the destination area include the entire dcDst,
1542        * we can pass TRUE instead of FALSE to CoerceDIBSection(dcDst...),
1543        * which may avoid a copy in some situations */
1544     }
1545
1546     sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None, FALSE );
1547     if (physDevDst != physDevSrc)
1548         sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None, FALSE );
1549     else
1550         sSrc = sDst;
1551
1552     if ((sSrc == DIB_Status_AppMod) && (rop == SRCCOPY) &&
1553         (physDevSrc->depth == physDevDst->depth))
1554     {
1555       POINT pts[2];
1556       /* do everything ourselves; map coordinates */
1557
1558       pts[0].x = xSrc;
1559       pts[0].y = ySrc;
1560       pts[1].x = xSrc + width;
1561       pts[1].y = ySrc + height;
1562
1563       LPtoDP(physDevSrc->hdc, pts, 2);
1564       width = pts[1].x - pts[0].x;
1565       height = pts[1].y - pts[0].y;
1566       xSrc = pts[0].x;
1567       ySrc = pts[0].y;
1568
1569       pts[0].x = xDst;
1570       pts[0].y = yDst;
1571       LPtoDP(physDevDst->hdc, pts, 1);
1572
1573       xDst = pts[0].x;
1574       yDst = pts[0].y;
1575
1576       /* Perform basic clipping */
1577       if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, width, height,
1578                                     physDevSrc, xSrc, ySrc, width, height,
1579                                     &visRectSrc, &visRectDst ))
1580         goto END;
1581
1582       xSrc = visRectSrc.left;
1583       ySrc = visRectSrc.top;
1584       xDst = visRectDst.left;
1585       yDst = visRectDst.top;
1586       width = visRectDst.right - visRectDst.left;
1587       height = visRectDst.bottom - visRectDst.top;
1588
1589       if (sDst == DIB_Status_AppMod) {
1590         FIXME("potential optimization - client-side DIB copy\n");
1591       }
1592       X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1593
1594       wine_tsx11_lock();
1595       XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1596       wine_tsx11_unlock();
1597
1598       X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, xSrc, ySrc, xDst, yDst, width, height );
1599       result = TRUE;
1600       goto END;
1601     }
1602
1603     X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1604     if (physDevDst != physDevSrc)
1605       X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1606
1607     result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, width, height,
1608                                         physDevSrc, xSrc, ySrc, width, height, rop );
1609
1610 END:
1611     if (physDevDst != physDevSrc)
1612       X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1613     X11DRV_UnlockDIBSection( physDevDst, TRUE );
1614
1615     return result;
1616 }
1617
1618
1619 /***********************************************************************
1620  *           X11DRV_StretchBlt
1621  */
1622 BOOL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1623                         INT widthDst, INT heightDst,
1624                         X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1625                         INT widthSrc, INT heightSrc, DWORD rop )
1626 {
1627     BOOL result;
1628
1629     X11DRV_LockDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1630     if (physDevDst != physDevSrc)
1631       X11DRV_LockDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1632
1633     result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, widthDst, heightDst,
1634                                         physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop );
1635
1636     if (physDevDst != physDevSrc)
1637       X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1638     X11DRV_UnlockDIBSection( physDevDst, TRUE );
1639     return result;
1640 }