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