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