- Reduce the number of messages being passed to itself by using the
[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     POINT pts[2];
1228     DC *dcSrc = physDevSrc ? physDevSrc->dc : NULL;
1229     DC *dcDst = physDevDst->dc;
1230
1231     /* compensate for off-by-one shifting for negative widths and heights */
1232     if (widthDst < 0)
1233         ++xDst;
1234     if (heightDst < 0)
1235         ++yDst;
1236     if (widthSrc < 0)
1237         ++xSrc;
1238     if (heightSrc < 0)
1239         ++ySrc;
1240
1241     usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1242     useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1243     useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1244     if (!dcSrc && useSrc) return FALSE;
1245
1246       /* Map the coordinates to device coords */
1247
1248     pts[0].x = xDst;
1249     pts[0].y = yDst;
1250     pts[1].x = xDst + widthDst;
1251     pts[1].y = yDst + heightDst;
1252     LPtoDP(physDevDst->hdc, pts, 2);
1253     xDst      = pts[0].x;
1254     yDst      = pts[0].y;
1255     widthDst  = pts[1].x - pts[0].x;
1256     heightDst = pts[1].y - pts[0].y;
1257
1258     TRACE("    vportdst=%d,%d-%d,%d wnddst=%d,%d-%d,%d\n",
1259                     dcDst->vportOrgX, dcDst->vportOrgY,
1260                     dcDst->vportExtX, dcDst->vportExtY,
1261                     dcDst->wndOrgX, dcDst->wndOrgY,
1262                     dcDst->wndExtX, dcDst->wndExtY );
1263     TRACE("    rectdst=%d,%d-%d,%d orgdst=%ld,%ld\n",
1264                     xDst, yDst, widthDst, heightDst,
1265                     physDevDst->org.x, physDevDst->org.y );
1266
1267     if (useSrc)
1268     {
1269         pts[0].x = xSrc;
1270         pts[0].y = ySrc;
1271         pts[1].x = xSrc + widthSrc;
1272         pts[1].y = ySrc + heightSrc;
1273         LPtoDP(physDevSrc->hdc, pts, 2);
1274         xSrc      = pts[0].x;
1275         ySrc      = pts[0].y;
1276         widthSrc  = pts[1].x - pts[0].x;
1277         heightSrc = pts[1].y - pts[0].y;
1278
1279         fStretch  = (widthSrc != widthDst) || (heightSrc != heightDst);
1280         TRACE("    vportsrc=%d,%d-%d,%d wndsrc=%d,%d-%d,%d\n",
1281                         dcSrc->vportOrgX, dcSrc->vportOrgY,
1282                         dcSrc->vportExtX, dcSrc->vportExtY,
1283                         dcSrc->wndOrgX, dcSrc->wndOrgY,
1284                         dcSrc->wndExtX, dcSrc->wndExtY );
1285         TRACE("    rectsrc=%d,%d-%d,%d orgsrc=%ld,%ld\n",
1286                         xSrc, ySrc, widthSrc, heightSrc,
1287                         physDevSrc->org.x, physDevSrc->org.y );
1288         if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1289                                       dcSrc, xSrc, ySrc, widthSrc, heightSrc,
1290                                       &visRectSrc, &visRectDst ))
1291             return TRUE;
1292         TRACE("    vissrc=%d,%d-%d,%d visdst=%d,%d-%d,%d\n",
1293                         visRectSrc.left, visRectSrc.top,
1294                         visRectSrc.right, visRectSrc.bottom,
1295                         visRectDst.left, visRectDst.top,
1296                         visRectDst.right, visRectDst.bottom );
1297     }
1298     else
1299     {
1300         fStretch = FALSE;
1301         if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1302                                       NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1303             return TRUE;
1304         TRACE("    vissrc=none visdst=%d,%d-%d,%d\n",
1305                         visRectDst.left, visRectDst.top,
1306                         visRectDst.right, visRectDst.bottom );
1307     }
1308
1309     width  = visRectDst.right - visRectDst.left;
1310     height = visRectDst.bottom - visRectDst.top;
1311
1312     if (!fStretch) switch(rop)  /* A few optimisations */
1313     {
1314     case BLACKNESS:  /* 0x00 */
1315         wine_tsx11_lock();
1316         if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1317             XSetFunction( gdi_display, physDevDst->gc, GXclear );
1318         else
1319         {
1320             XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1321             XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1322             XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1323         }
1324         XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1325                         physDevDst->org.x + visRectDst.left,
1326                         physDevDst->org.y + visRectDst.top,
1327                         width, height );
1328         wine_tsx11_unlock();
1329         return TRUE;
1330
1331     case DSTINVERT:  /* 0x55 */
1332         if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel ||
1333             !perfect_graphics())
1334         {
1335             wine_tsx11_lock();
1336             XSetFunction( gdi_display, physDevDst->gc, GXinvert );
1337
1338             if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1339                 XSetFunction( gdi_display, physDevDst->gc, GXinvert);
1340             else
1341             {
1342                 /* Xor is much better when we do not have full colormap.   */
1343                 /* Using white^black ensures that we invert at least black */
1344                 /* and white. */
1345                 Pixel xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1346                                  BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1347                 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1348                 XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1349                 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1350             }
1351             XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1352                             physDevDst->org.x + visRectDst.left,
1353                             physDevDst->org.y + visRectDst.top,
1354                             width, height );
1355             wine_tsx11_unlock();
1356             return TRUE;
1357         }
1358         break;
1359
1360     case PATINVERT:  /* 0x5a */
1361         if (perfect_graphics()) break;
1362         if (X11DRV_SetupGCForBrush( physDevDst ))
1363         {
1364             wine_tsx11_lock();
1365             XSetFunction( gdi_display, physDevDst->gc, GXxor );
1366             XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1367                             physDevDst->org.x + visRectDst.left,
1368                             physDevDst->org.y + visRectDst.top,
1369                             width, height );
1370             wine_tsx11_unlock();
1371         }
1372         return TRUE;
1373
1374     case 0xa50065:
1375         if (perfect_graphics()) break;
1376         if (X11DRV_SetupGCForBrush( physDevDst ))
1377         {
1378             wine_tsx11_lock();
1379             XSetFunction( gdi_display, physDevDst->gc, GXequiv );
1380             XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1381                             physDevDst->org.x + visRectDst.left,
1382                             physDevDst->org.y + visRectDst.top,
1383                             width, height );
1384             wine_tsx11_unlock();
1385         }
1386         return TRUE;
1387
1388     case SRCCOPY:  /* 0xcc */
1389         if (dcSrc->bitsPerPixel == dcDst->bitsPerPixel)
1390         {
1391             wine_tsx11_lock();
1392             XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1393             XCopyArea( gdi_display, physDevSrc->drawable,
1394                        physDevDst->drawable, physDevDst->gc,
1395                        physDevSrc->org.x + visRectSrc.left,
1396                        physDevSrc->org.y + visRectSrc.top,
1397                        width, height,
1398                        physDevDst->org.x + visRectDst.left,
1399                        physDevDst->org.y + visRectDst.top );
1400             physDevDst->exposures++;
1401             wine_tsx11_unlock();
1402             return TRUE;
1403         }
1404         if (dcSrc->bitsPerPixel == 1)
1405         {
1406             wine_tsx11_lock();
1407             XSetBackground( gdi_display, physDevDst->gc, physDevDst->textPixel );
1408             XSetForeground( gdi_display, physDevDst->gc, physDevDst->backgroundPixel );
1409             XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1410             XCopyPlane( gdi_display, physDevSrc->drawable,
1411                         physDevDst->drawable, physDevDst->gc,
1412                         physDevSrc->org.x + visRectSrc.left,
1413                         physDevSrc->org.y + visRectSrc.top,
1414                         width, height,
1415                         physDevDst->org.x + visRectDst.left,
1416                         physDevDst->org.y + visRectDst.top, 1 );
1417             physDevDst->exposures++;
1418             wine_tsx11_unlock();
1419             return TRUE;
1420         }
1421         break;
1422
1423     case PATCOPY:  /* 0xf0 */
1424         if (!X11DRV_SetupGCForBrush( physDevDst )) return TRUE;
1425         wine_tsx11_lock();
1426         XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1427         XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1428                         physDevDst->org.x + visRectDst.left,
1429                         physDevDst->org.y + visRectDst.top,
1430                         width, height );
1431         wine_tsx11_unlock();
1432         return TRUE;
1433
1434     case WHITENESS:  /* 0xff */
1435         wine_tsx11_lock();
1436         if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1437             XSetFunction( gdi_display, physDevDst->gc, GXset );
1438         else
1439         {
1440             XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1441             XSetForeground( gdi_display, physDevDst->gc,
1442                             WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1443             XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1444         }
1445         XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1446                         physDevDst->org.x + visRectDst.left,
1447                         physDevDst->org.y + visRectDst.top,
1448                         width, height );
1449         wine_tsx11_unlock();
1450         return TRUE;
1451     }
1452
1453     wine_tsx11_lock();
1454
1455     tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1456     XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1457     XSetGraphicsExposures( gdi_display, tmpGC, False );
1458     pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1459                                   dcDst->bitsPerPixel );
1460     if (useSrc)
1461     {
1462         pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1463                                       dcDst->bitsPerPixel );
1464         if (fStretch)
1465             BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1466                                       xSrc, ySrc, widthSrc, heightSrc,
1467                                       xDst, yDst, widthDst, heightDst,
1468                                       &visRectSrc, &visRectDst );
1469         else
1470             BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1471                                xSrc, ySrc, &visRectSrc );
1472     }
1473
1474     if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &visRectDst );
1475     if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1476     else fNullBrush = FALSE;
1477     destUsed = FALSE;
1478
1479     for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1480     {
1481         if (OP_DST(*opcode) == DST) destUsed = TRUE;
1482         XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1483         switch(OP_SRCDST(*opcode))
1484         {
1485         case OP_ARGS(DST,TMP):
1486         case OP_ARGS(SRC,TMP):
1487             if (!pixmaps[TMP])
1488                 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1489                                               width, height,
1490                                               dcDst->bitsPerPixel );
1491             /* fall through */
1492         case OP_ARGS(DST,SRC):
1493         case OP_ARGS(SRC,DST):
1494         case OP_ARGS(TMP,SRC):
1495         case OP_ARGS(TMP,DST):
1496             XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1497                        pixmaps[OP_DST(*opcode)], tmpGC,
1498                        0, 0, width, height, 0, 0 );
1499             break;
1500
1501         case OP_ARGS(PAT,TMP):
1502             if (!pixmaps[TMP] && !fNullBrush)
1503                 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1504                                               width, height,
1505                                               dcDst->bitsPerPixel );
1506             /* fall through */
1507         case OP_ARGS(PAT,DST):
1508         case OP_ARGS(PAT,SRC):
1509             if (!fNullBrush)
1510                 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1511                                 tmpGC, 0, 0, width, height );
1512             break;
1513         }
1514     }
1515     XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1516     physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC],
1517                                                 &visRectDst );
1518     XFreePixmap( gdi_display, pixmaps[DST] );
1519     if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1520     if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1521     XFreeGC( gdi_display, tmpGC );
1522     wine_tsx11_unlock();
1523     return TRUE;
1524 }
1525
1526
1527 /***********************************************************************
1528  *           X11DRV_PatBlt
1529  */
1530 BOOL X11DRV_PatBlt( X11DRV_PDEVICE *physDev, INT left, INT top, INT width, INT height, DWORD rop )
1531 {
1532     BOOL result;
1533
1534     X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1535     result = BITBLT_InternalStretchBlt( physDev, left, top, width, height, NULL, 0, 0, 0, 0, rop );
1536     X11DRV_UnlockDIBSection( physDev, TRUE );
1537     return result;
1538 }
1539
1540
1541 /***********************************************************************
1542  *           X11DRV_BitBlt
1543  */
1544 BOOL X11DRV_BitBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1545                     INT width, INT height, X11DRV_PDEVICE *physDevSrc,
1546                     INT xSrc, INT ySrc, DWORD rop )
1547 {
1548     BOOL result = FALSE;
1549     INT sSrc, sDst;
1550     RECT visRectDst, visRectSrc;
1551     DC *dcSrc = physDevSrc ? physDevSrc->dc : NULL;
1552     DC *dcDst = physDevDst->dc;
1553
1554     if (((rop >> 16) & 0x55) == ((rop >> 17) & 0x55)) {
1555       /* FIXME: seems the ROP doesn't include destination;
1556        * now if the destination area include the entire dcDst,
1557        * we can pass TRUE instead of FALSE to CoerceDIBSection(dcDst...),
1558        * which may avoid a copy in some situations */
1559     }
1560     sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None, FALSE );
1561     sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None, FALSE );
1562
1563     if ((sSrc == DIB_Status_AppMod) && (rop == SRCCOPY) &&
1564         (dcSrc->bitsPerPixel == dcDst->bitsPerPixel))
1565     {
1566       POINT pts[2];
1567       /* do everything ourselves; map coordinates */
1568
1569       pts[0].x = xSrc;
1570       pts[0].y = ySrc;
1571       pts[1].x = xSrc + width;
1572       pts[1].y = ySrc + height;
1573
1574       LPtoDP(physDevSrc->hdc, pts, 2);
1575       width = pts[1].x - pts[0].x;
1576       height = pts[1].y - pts[0].y;
1577       xSrc = pts[0].x;
1578       ySrc = pts[0].y;
1579
1580       pts[0].x = xDst;
1581       pts[0].y = yDst;
1582       LPtoDP(physDevDst->hdc, pts, 1);
1583
1584       xDst = pts[0].x;
1585       yDst = pts[0].y;
1586
1587       /* Perform basic clipping */
1588       if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, width, height,
1589                                     dcSrc, xSrc, ySrc, width, height,
1590                                     &visRectSrc, &visRectDst ))
1591         goto END;
1592
1593       xSrc = visRectSrc.left;
1594       ySrc = visRectSrc.top;
1595       xDst = visRectDst.left;
1596       yDst = visRectDst.top;
1597       width = visRectDst.right - visRectDst.left;
1598       height = visRectDst.bottom - visRectDst.top;
1599
1600       if (sDst == DIB_Status_AppMod) {
1601         FIXME("potential optimization - client-side DIB copy\n");
1602       }
1603       X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1604
1605       X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, xSrc, ySrc, xDst, yDst, width, height );
1606       result = TRUE;
1607       goto END;
1608     }
1609
1610     X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1611     X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1612
1613     result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, width, height,
1614                                         physDevSrc, xSrc, ySrc, width, height, rop );
1615
1616 END:
1617     X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1618     X11DRV_UnlockDIBSection( physDevDst, TRUE );
1619
1620     return result;
1621 }
1622
1623
1624 /***********************************************************************
1625  *           X11DRV_StretchBlt
1626  */
1627 BOOL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1628                         INT widthDst, INT heightDst,
1629                         X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1630                         INT widthSrc, INT heightSrc, DWORD rop )
1631 {
1632     BOOL result;
1633
1634     X11DRV_LockDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1635     X11DRV_LockDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1636
1637     result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, widthDst, heightDst,
1638                                         physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop );
1639
1640     X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1641     X11DRV_UnlockDIBSection( physDevDst, TRUE );
1642     return result;
1643 }