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