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