Added regedit unit test, a couple minor changes to regedit.
[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_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 (dcSrc->flags & DC_MEMORY)
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             imageDst = X11DRV_DIB_CreateXImage( width, height, dcDst->bitsPerPixel );
1011             for (y = 0; y < height; y++)
1012                 for (x = 0; x < width; x++)
1013                     XPutPixel(imageDst, x, y, (XGetPixel(imageSrc,x,y) ==
1014                                                physDevSrc->backgroundPixel) );
1015             XPutImage( gdi_display, pixmap, gc, imageDst,
1016                        0, 0, 0, 0, width, height );
1017             XDestroyImage( imageSrc );
1018             XDestroyImage( imageDst );
1019         }
1020     }
1021     return exposures;
1022 }
1023
1024
1025 /***********************************************************************
1026  *           BITBLT_GetDstArea
1027  *
1028  * Retrieve an area from the destination DC, mapping all the
1029  * pixels to Windows colors.
1030  */
1031 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, RECT *visRectDst)
1032 {
1033     int exposures = 0;
1034     INT width  = visRectDst->right - visRectDst->left;
1035     INT height = visRectDst->bottom - visRectDst->top;
1036
1037     if (!X11DRV_PALETTE_XPixelToPalette || (physDev->dc->bitsPerPixel == 1) ||
1038         (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1039     {
1040         XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1041                    physDev->org.x + visRectDst->left, physDev->org.y + visRectDst->top,
1042                    width, height, 0, 0 );
1043         exposures++;
1044     }
1045     else
1046     {
1047         register INT x, y;
1048         XImage *image;
1049
1050         if (physDev->dc->flags & DC_MEMORY)
1051             image = XGetImage( gdi_display, physDev->drawable,
1052                                physDev->org.x + visRectDst->left,
1053                                physDev->org.y + visRectDst->top,
1054                                width, height, AllPlanes, ZPixmap );
1055         else
1056         {
1057             /* Make sure we don't get a BadMatch error */
1058             XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1059                        physDev->org.x + visRectDst->left,
1060                        physDev->org.y + visRectDst->top,
1061                        width, height, 0, 0);
1062             exposures++;
1063             image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1064                                AllPlanes, ZPixmap );
1065         }
1066         for (y = 0; y < height; y++)
1067             for (x = 0; x < width; x++)
1068                 XPutPixel( image, x, y,
1069                            X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1070         XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1071         XDestroyImage( image );
1072     }
1073     return exposures;
1074 }
1075
1076
1077 /***********************************************************************
1078  *           BITBLT_PutDstArea
1079  *
1080  * Put an area back into the destination DC, mapping the pixel
1081  * colors to X pixels.
1082  */
1083 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, RECT *visRectDst)
1084 {
1085     int exposures = 0;
1086     INT width  = visRectDst->right - visRectDst->left;
1087     INT height = visRectDst->bottom - visRectDst->top;
1088
1089     /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1090
1091     if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->dc->bitsPerPixel == 1) ||
1092         (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1093     {
1094         XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1095                    physDev->org.x + visRectDst->left,
1096                    physDev->org.y + visRectDst->top );
1097         exposures++;
1098     }
1099     else
1100     {
1101         register INT x, y;
1102         XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1103                                    AllPlanes, ZPixmap );
1104         for (y = 0; y < height; y++)
1105             for (x = 0; x < width; x++)
1106             {
1107                 XPutPixel( image, x, y,
1108                            X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1109             }
1110         XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1111                    physDev->org.x + visRectDst->left,
1112                    physDev->org.y + visRectDst->top, width, height );
1113         XDestroyImage( image );
1114     }
1115     return exposures;
1116 }
1117
1118
1119 /***********************************************************************
1120  *           BITBLT_GetVisRectangles
1121  *
1122  * Get the source and destination visible rectangles for StretchBlt().
1123  * Return FALSE if one of the rectangles is empty.
1124  */
1125 static BOOL BITBLT_GetVisRectangles( DC *dcDst, INT xDst, INT yDst,
1126                                      INT widthDst, INT heightDst,
1127                                      DC *dcSrc, INT xSrc, INT ySrc,
1128                                      INT widthSrc, INT heightSrc,
1129                                      RECT *visRectSrc, RECT *visRectDst )
1130 {
1131     RECT rect, clipRect;
1132
1133       /* Get the destination visible rectangle */
1134
1135     rect.left   = xDst;
1136     rect.top    = yDst;
1137     rect.right  = xDst + widthDst;
1138     rect.bottom = yDst + heightDst;
1139     if (widthDst < 0) SWAP_INT32( &rect.left, &rect.right );
1140     if (heightDst < 0) SWAP_INT32( &rect.top, &rect.bottom );
1141     GetRgnBox( dcDst->hGCClipRgn, &clipRect );
1142     if (!IntersectRect( visRectDst, &rect, &clipRect )) return FALSE;
1143
1144       /* Get the source visible rectangle */
1145
1146     if (!dcSrc) return TRUE;
1147     rect.left   = xSrc;
1148     rect.top    = ySrc;
1149     rect.right  = xSrc + widthSrc;
1150     rect.bottom = ySrc + heightSrc;
1151     if (widthSrc < 0) SWAP_INT32( &rect.left, &rect.right );
1152     if (heightSrc < 0) SWAP_INT32( &rect.top, &rect.bottom );
1153     /* Apparently the clipping and visible regions are only for output,
1154        so just check against totalExtent here to avoid BadMatch errors */
1155     if (!IntersectRect( visRectSrc, &rect, &dcSrc->totalExtent ))
1156         return FALSE;
1157
1158       /* Intersect the rectangles */
1159
1160     if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1161     {
1162         visRectSrc->left   += xDst - xSrc;
1163         visRectSrc->right  += xDst - xSrc;
1164         visRectSrc->top    += yDst - ySrc;
1165         visRectSrc->bottom += yDst - ySrc;
1166         if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1167         *visRectSrc = *visRectDst = rect;
1168         visRectSrc->left   += xSrc - xDst;
1169         visRectSrc->right  += xSrc - xDst;
1170         visRectSrc->top    += ySrc - yDst;
1171         visRectSrc->bottom += ySrc - yDst;
1172     }
1173     else  /* stretching */
1174     {
1175         /* Map source rectangle into destination coordinates */
1176         rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1177         rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1178         rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1179         rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1180         if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1181         if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1182
1183         /* Avoid rounding errors */
1184         rect.left--;
1185         rect.top--;
1186         rect.right++;
1187         rect.bottom++;
1188         if (!IntersectRect( visRectDst, &rect, visRectDst )) return FALSE;
1189
1190         /* Map destination rectangle back to source coordinates */
1191         rect = *visRectDst;
1192         rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1193         rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1194         rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1195         rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1196         if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1197         if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1198
1199         /* Avoid rounding errors */
1200         rect.left--;
1201         rect.top--;
1202         rect.right++;
1203         rect.bottom++;
1204         if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1205     }
1206     return TRUE;
1207 }
1208
1209
1210 /***********************************************************************
1211  *           BITBLT_InternalStretchBlt
1212  *
1213  * Implementation of PatBlt(), BitBlt() and StretchBlt().
1214  */
1215 static BOOL BITBLT_InternalStretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1216                                        INT widthDst, INT heightDst,
1217                                        X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1218                                        INT widthSrc, INT heightSrc,
1219                                        DWORD rop )
1220 {
1221     BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1222     RECT visRectDst, visRectSrc;
1223     INT width, height;
1224     const BYTE *opcode;
1225     Pixmap pixmaps[3] = { 0, 0, 0 };  /* pixmaps for DST, SRC, TMP */
1226     GC tmpGC = 0;
1227     DC *dcSrc = physDevSrc ? physDevSrc->dc : NULL;
1228     DC *dcDst = physDevDst->dc;
1229
1230     /* compensate for off-by-one shifting for negative widths and heights */
1231     if (widthDst < 0)
1232         ++xDst;
1233     if (heightDst < 0)
1234         ++yDst;
1235     if (widthSrc < 0)
1236         ++xSrc;
1237     if (heightSrc < 0)
1238         ++ySrc;
1239
1240     usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1241     useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1242     useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1243     if (!dcSrc && useSrc) return FALSE;
1244
1245       /* Map the coordinates to device coords */
1246
1247     xDst      = XLPTODP( dcDst, xDst );
1248     yDst      = YLPTODP( dcDst, yDst );
1249
1250     /* Here we have to round to integers, not truncate */
1251     widthDst  = MulDiv(widthDst, dcDst->vportExtX, dcDst->wndExtX);
1252     heightDst = MulDiv(heightDst, dcDst->vportExtY, dcDst->wndExtY);
1253
1254     TRACE("    vportdst=%d,%d-%d,%d wnddst=%d,%d-%d,%d\n",
1255                     dcDst->vportOrgX, dcDst->vportOrgY,
1256                     dcDst->vportExtX, dcDst->vportExtY,
1257                     dcDst->wndOrgX, dcDst->wndOrgY,
1258                     dcDst->wndExtX, dcDst->wndExtY );
1259     TRACE("    rectdst=%d,%d-%d,%d orgdst=%ld,%ld\n",
1260                     xDst, yDst, widthDst, heightDst,
1261                     physDevDst->org.x, physDevDst->org.y );
1262
1263     if (useSrc)
1264     {
1265         xSrc      = XLPTODP( dcSrc, xSrc );
1266         ySrc      = YLPTODP( dcSrc, ySrc );
1267         widthSrc  = widthSrc * dcSrc->vportExtX / dcSrc->wndExtX;
1268         heightSrc = heightSrc * dcSrc->vportExtY / dcSrc->wndExtY;
1269         fStretch  = (widthSrc != widthDst) || (heightSrc != heightDst);
1270         TRACE("    vportsrc=%d,%d-%d,%d wndsrc=%d,%d-%d,%d\n",
1271                         dcSrc->vportOrgX, dcSrc->vportOrgY,
1272                         dcSrc->vportExtX, dcSrc->vportExtY,
1273                         dcSrc->wndOrgX, dcSrc->wndOrgY,
1274                         dcSrc->wndExtX, dcSrc->wndExtY );
1275         TRACE("    rectsrc=%d,%d-%d,%d orgsrc=%ld,%ld\n",
1276                         xSrc, ySrc, widthSrc, heightSrc,
1277                         physDevSrc->org.x, physDevSrc->org.y );
1278         if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1279                                       dcSrc, xSrc, ySrc, widthSrc, heightSrc,
1280                                       &visRectSrc, &visRectDst ))
1281             return TRUE;
1282         TRACE("    vissrc=%d,%d-%d,%d visdst=%d,%d-%d,%d\n",
1283                         visRectSrc.left, visRectSrc.top,
1284                         visRectSrc.right, visRectSrc.bottom,
1285                         visRectDst.left, visRectDst.top,
1286                         visRectDst.right, visRectDst.bottom );
1287     }
1288     else
1289     {
1290         fStretch = FALSE;
1291         if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1292                                       NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1293             return TRUE;
1294         TRACE("    vissrc=none visdst=%d,%d-%d,%d\n",
1295                         visRectDst.left, visRectDst.top,
1296                         visRectDst.right, visRectDst.bottom );
1297     }
1298
1299     width  = visRectDst.right - visRectDst.left;
1300     height = visRectDst.bottom - visRectDst.top;
1301
1302     if (!fStretch) switch(rop)  /* A few optimisations */
1303     {
1304     case BLACKNESS:  /* 0x00 */
1305         wine_tsx11_lock();
1306         if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1307             XSetFunction( gdi_display, physDevDst->gc, GXclear );
1308         else
1309         {
1310             XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1311             XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1312             XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1313         }
1314         XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1315                         physDevDst->org.x + visRectDst.left,
1316                         physDevDst->org.y + visRectDst.top,
1317                         width, height );
1318         wine_tsx11_unlock();
1319         return TRUE;
1320
1321     case DSTINVERT:  /* 0x55 */
1322         if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel ||
1323             !perfect_graphics())
1324         {
1325             wine_tsx11_lock();
1326             XSetFunction( gdi_display, physDevDst->gc, GXinvert );
1327
1328             if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1329                 XSetFunction( gdi_display, physDevDst->gc, GXinvert);
1330             else
1331             {
1332                 /* Xor is much better when we do not have full colormap.   */
1333                 /* Using white^black ensures that we invert at least black */
1334                 /* and white. */
1335                 Pixel xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1336                                  BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1337                 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1338                 XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1339                 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1340             }
1341             XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1342                             physDevDst->org.x + visRectDst.left,
1343                             physDevDst->org.y + visRectDst.top,
1344                             width, height );
1345             wine_tsx11_unlock();
1346             return TRUE;
1347         }
1348         break;
1349
1350     case PATINVERT:  /* 0x5a */
1351         if (perfect_graphics()) break;
1352         if (X11DRV_SetupGCForBrush( physDevDst ))
1353         {
1354             wine_tsx11_lock();
1355             XSetFunction( gdi_display, physDevDst->gc, GXxor );
1356             XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1357                             physDevDst->org.x + visRectDst.left,
1358                             physDevDst->org.y + visRectDst.top,
1359                             width, height );
1360             wine_tsx11_unlock();
1361         }
1362         return TRUE;
1363
1364     case 0xa50065:
1365         if (perfect_graphics()) break;
1366         if (X11DRV_SetupGCForBrush( physDevDst ))
1367         {
1368             wine_tsx11_lock();
1369             XSetFunction( gdi_display, physDevDst->gc, GXequiv );
1370             XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1371                             physDevDst->org.x + visRectDst.left,
1372                             physDevDst->org.y + visRectDst.top,
1373                             width, height );
1374             wine_tsx11_unlock();
1375         }
1376         return TRUE;
1377
1378     case SRCCOPY:  /* 0xcc */
1379         if (dcSrc->bitsPerPixel == dcDst->bitsPerPixel)
1380         {
1381             wine_tsx11_lock();
1382             XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1383             XCopyArea( gdi_display, physDevSrc->drawable,
1384                        physDevDst->drawable, physDevDst->gc,
1385                        physDevSrc->org.x + visRectSrc.left,
1386                        physDevSrc->org.y + visRectSrc.top,
1387                        width, height,
1388                        physDevDst->org.x + visRectDst.left,
1389                        physDevDst->org.y + visRectDst.top );
1390             physDevDst->exposures++;
1391             wine_tsx11_unlock();
1392             return TRUE;
1393         }
1394         if (dcSrc->bitsPerPixel == 1)
1395         {
1396             wine_tsx11_lock();
1397             XSetBackground( gdi_display, physDevDst->gc, physDevDst->textPixel );
1398             XSetForeground( gdi_display, physDevDst->gc, physDevDst->backgroundPixel );
1399             XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1400             XCopyPlane( gdi_display, physDevSrc->drawable,
1401                         physDevDst->drawable, physDevDst->gc,
1402                         physDevSrc->org.x + visRectSrc.left,
1403                         physDevSrc->org.y + visRectSrc.top,
1404                         width, height,
1405                         physDevDst->org.x + visRectDst.left,
1406                         physDevDst->org.y + visRectDst.top, 1 );
1407             physDevDst->exposures++;
1408             wine_tsx11_unlock();
1409             return TRUE;
1410         }
1411         break;
1412
1413     case PATCOPY:  /* 0xf0 */
1414         if (!X11DRV_SetupGCForBrush( physDevDst )) return TRUE;
1415         wine_tsx11_lock();
1416         XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1417         XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1418                         physDevDst->org.x + visRectDst.left,
1419                         physDevDst->org.y + visRectDst.top,
1420                         width, height );
1421         wine_tsx11_unlock();
1422         return TRUE;
1423
1424     case WHITENESS:  /* 0xff */
1425         wine_tsx11_lock();
1426         if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1427             XSetFunction( gdi_display, physDevDst->gc, GXset );
1428         else
1429         {
1430             XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1431             XSetForeground( gdi_display, physDevDst->gc,
1432                             WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1433             XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1434         }
1435         XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1436                         physDevDst->org.x + visRectDst.left,
1437                         physDevDst->org.y + visRectDst.top,
1438                         width, height );
1439         wine_tsx11_unlock();
1440         return TRUE;
1441     }
1442
1443     wine_tsx11_lock();
1444
1445     tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1446     XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1447     XSetGraphicsExposures( gdi_display, tmpGC, False );
1448     pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1449                                   dcDst->bitsPerPixel );
1450     if (useSrc)
1451     {
1452         pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1453                                       dcDst->bitsPerPixel );
1454         if (fStretch)
1455             BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1456                                       xSrc, ySrc, widthSrc, heightSrc,
1457                                       xDst, yDst, widthDst, heightDst,
1458                                       &visRectSrc, &visRectDst );
1459         else
1460             BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1461                                xSrc, ySrc, &visRectSrc );
1462     }
1463
1464     if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &visRectDst );
1465     if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1466     else fNullBrush = FALSE;
1467     destUsed = FALSE;
1468
1469     for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1470     {
1471         if (OP_DST(*opcode) == DST) destUsed = TRUE;
1472         XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1473         switch(OP_SRCDST(*opcode))
1474         {
1475         case OP_ARGS(DST,TMP):
1476         case OP_ARGS(SRC,TMP):
1477             if (!pixmaps[TMP])
1478                 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1479                                               width, height,
1480                                               dcDst->bitsPerPixel );
1481             /* fall through */
1482         case OP_ARGS(DST,SRC):
1483         case OP_ARGS(SRC,DST):
1484         case OP_ARGS(TMP,SRC):
1485         case OP_ARGS(TMP,DST):
1486             XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1487                        pixmaps[OP_DST(*opcode)], tmpGC,
1488                        0, 0, width, height, 0, 0 );
1489             break;
1490
1491         case OP_ARGS(PAT,TMP):
1492             if (!pixmaps[TMP] && !fNullBrush)
1493                 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1494                                               width, height,
1495                                               dcDst->bitsPerPixel );
1496             /* fall through */
1497         case OP_ARGS(PAT,DST):
1498         case OP_ARGS(PAT,SRC):
1499             if (!fNullBrush)
1500                 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1501                                 tmpGC, 0, 0, width, height );
1502             break;
1503         }
1504     }
1505     XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1506     physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC],
1507                                                 &visRectDst );
1508     XFreePixmap( gdi_display, pixmaps[DST] );
1509     if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1510     if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1511     XFreeGC( gdi_display, tmpGC );
1512     wine_tsx11_unlock();
1513     return TRUE;
1514 }
1515
1516
1517 /***********************************************************************
1518  *           X11DRV_PatBlt
1519  */
1520 BOOL X11DRV_PatBlt( X11DRV_PDEVICE *physDev, INT left, INT top, INT width, INT height, DWORD rop )
1521 {
1522     BOOL result;
1523
1524     X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1525     result = BITBLT_InternalStretchBlt( physDev, left, top, width, height, NULL, 0, 0, 0, 0, rop );
1526     X11DRV_UnlockDIBSection( physDev, TRUE );
1527     return result;
1528 }
1529
1530
1531 /***********************************************************************
1532  *           X11DRV_BitBlt
1533  */
1534 BOOL X11DRV_BitBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1535                     INT width, INT height, X11DRV_PDEVICE *physDevSrc,
1536                     INT xSrc, INT ySrc, DWORD rop )
1537 {
1538     BOOL result = FALSE;
1539     INT sSrc, sDst;
1540     RECT visRectDst, visRectSrc;
1541     DC *dcSrc = physDevSrc ? physDevSrc->dc : NULL;
1542     DC *dcDst = physDevDst->dc;
1543
1544     if (((rop >> 16) & 0x55) == ((rop >> 17) & 0x55)) {
1545       /* FIXME: seems the ROP doesn't include destination;
1546        * now if the destination area include the entire dcDst,
1547        * we can pass TRUE instead of FALSE to CoerceDIBSection(dcDst...),
1548        * which may avoid a copy in some situations */
1549     }
1550     sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None, FALSE );
1551     sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None, FALSE );
1552
1553     if ((sSrc == DIB_Status_AppMod) && (rop == SRCCOPY) &&
1554         (dcSrc->bitsPerPixel == dcDst->bitsPerPixel))
1555     {
1556       /* do everything ourselves; map coordinates */
1557       xSrc = XLPTODP( dcSrc, xSrc );
1558       ySrc = YLPTODP( dcSrc, ySrc );
1559       xDst = XLPTODP( dcDst, xDst );
1560       yDst = YLPTODP( dcDst, yDst );
1561       width  = MulDiv(width, dcDst->vportExtX, dcDst->wndExtX);
1562       height = MulDiv(height, dcDst->vportExtY, dcDst->wndExtY);
1563
1564       /* Perform basic clipping */
1565       if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, width, height,
1566                                     dcSrc, xSrc, ySrc, width, height,
1567                                     &visRectSrc, &visRectDst ))
1568         goto END;
1569
1570       xSrc = visRectSrc.left;
1571       ySrc = visRectSrc.top;
1572       xDst = visRectDst.left;
1573       yDst = visRectDst.top;
1574       width = visRectDst.right - visRectDst.left;
1575       height = visRectDst.bottom - visRectDst.top;
1576
1577       if (sDst == DIB_Status_AppMod) {
1578         FIXME("potential optimization - client-side DIB copy\n");
1579       }
1580       X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1581
1582       X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, xSrc, ySrc, xDst, yDst, width, height );
1583       result = TRUE;
1584       goto END;
1585     }
1586
1587     X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1588     X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1589
1590     result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, width, height,
1591                                         physDevSrc, xSrc, ySrc, width, height, rop );
1592
1593 END:
1594     X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1595     X11DRV_UnlockDIBSection( physDevDst, TRUE );
1596
1597     return result;
1598 }
1599
1600
1601 /***********************************************************************
1602  *           X11DRV_StretchBlt
1603  */
1604 BOOL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1605                         INT widthDst, INT heightDst,
1606                         X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1607                         INT widthSrc, INT heightSrc, DWORD rop )
1608 {
1609     BOOL result;
1610
1611     X11DRV_LockDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1612     X11DRV_LockDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1613
1614     result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, widthDst, heightDst,
1615                                         physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop );
1616
1617     X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1618     X11DRV_UnlockDIBSection( physDevDst, TRUE );
1619     return result;
1620 }