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