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