Removed X_DISPLAY_MISSING.
[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 "bitmap.h"
17 #include "callback.h"
18 #include "color.h"
19 #include "dc.h"
20 #include "metafile.h"
21 #include "options.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) perfect = PROFILE_GetWineIniBool( "x11drv", "PerfectGraphics", 0 );
533     return perfect;
534 }
535
536 /***********************************************************************
537  *           BITBLT_StretchRow
538  *
539  * Stretch a row of pixels. Helper function for BITBLT_StretchImage.
540  */
541 static void BITBLT_StretchRow( int *rowSrc, int *rowDst,
542                                INT startDst, INT widthDst,
543                                INT xinc, INT xoff, WORD mode )
544 {
545     register INT xsrc = xinc * startDst + xoff;
546     rowDst += startDst;
547     switch(mode)
548     {
549     case STRETCH_ANDSCANS:
550         for(; widthDst > 0; widthDst--, xsrc += xinc)
551             *rowDst++ &= rowSrc[xsrc >> 16];
552         break;
553     case STRETCH_ORSCANS:
554         for(; widthDst > 0; widthDst--, xsrc += xinc)
555             *rowDst++ |= rowSrc[xsrc >> 16];
556         break;
557     case STRETCH_DELETESCANS:
558         for(; widthDst > 0; widthDst--, xsrc += xinc)
559             *rowDst++ = rowSrc[xsrc >> 16];
560         break;
561     }
562 }
563
564
565 /***********************************************************************
566  *           BITBLT_ShrinkRow
567  *
568  * Shrink a row of pixels. Helper function for BITBLT_StretchImage.
569  */
570 static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst,
571                               INT startSrc, INT widthSrc,
572                               INT xinc, INT xoff, WORD mode )
573 {
574     register INT xdst = xinc * startSrc + xoff;
575     rowSrc += startSrc;
576     switch(mode)
577     {
578     case STRETCH_ORSCANS:
579         for(; widthSrc > 0; widthSrc--, xdst += xinc)
580             rowDst[xdst >> 16] |= *rowSrc++;
581         break;
582     case STRETCH_ANDSCANS:
583         for(; widthSrc > 0; widthSrc--, xdst += xinc)
584             rowDst[xdst >> 16] &= *rowSrc++;
585         break;
586     case STRETCH_DELETESCANS:
587         for(; widthSrc > 0; widthSrc--, xdst += xinc)
588             rowDst[xdst >> 16] = *rowSrc++;
589         break;
590     }
591 }
592
593
594 /***********************************************************************
595  *           BITBLT_GetRow
596  *
597  * Retrieve a row from an image. Helper function for BITBLT_StretchImage.
598  */
599 static void BITBLT_GetRow( XImage *image, int *pdata, INT row,
600                            INT start, INT width, INT depthDst,
601                            int fg, int bg, BOOL swap)
602 {
603     register INT i;
604
605     assert( (row >= 0) && (row < image->height) );
606     assert( (start >= 0) && (width <= image->width) );
607
608     pdata += swap ? start+width-1 : start;
609     if (image->depth == depthDst)  /* color -> color */
610     {
611         if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1))
612             if (swap) for (i = 0; i < width; i++)
613                 *pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
614             else for (i = 0; i < width; i++)
615                 *pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
616         else
617             if (swap) for (i = 0; i < width; i++)
618                 *pdata-- = XGetPixel( image, i, row );
619             else for (i = 0; i < width; i++)
620                 *pdata++ = XGetPixel( image, i, row );
621     }
622     else
623     {
624         if (image->depth == 1)  /* monochrome -> color */
625         {
626             if (X11DRV_PALETTE_XPixelToPalette)
627             {
628                 fg = X11DRV_PALETTE_XPixelToPalette[fg];
629                 bg = X11DRV_PALETTE_XPixelToPalette[bg];
630             }
631             if (swap) for (i = 0; i < width; i++)
632                 *pdata-- = XGetPixel( image, i, row ) ? bg : fg;
633             else for (i = 0; i < width; i++)
634                 *pdata++ = XGetPixel( image, i, row ) ? bg : fg;
635         }
636         else  /* color -> monochrome */
637         {
638             if (swap) for (i = 0; i < width; i++)
639                 *pdata-- = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
640             else for (i = 0; i < width; i++)
641                 *pdata++ = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
642         }
643     }
644 }
645
646
647 /***********************************************************************
648  *           BITBLT_StretchImage
649  *
650  * Stretch an X image.
651  * FIXME: does not work for full 32-bit coordinates.
652  */
653 static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage,
654                                  INT widthSrc, INT heightSrc,
655                                  INT widthDst, INT heightDst,
656                                  RECT *visRectSrc, RECT *visRectDst,
657                                  int foreground, int background, WORD mode )
658 {
659     int *rowSrc, *rowDst, *pixel;
660     char *pdata;
661     INT xinc, xoff, yinc, ysrc, ydst;
662     register INT x, y;
663     BOOL hstretch, vstretch, hswap, vswap;
664
665     hswap = ((int)widthSrc * widthDst) < 0;
666     vswap = ((int)heightSrc * heightDst) < 0;
667     widthSrc  = abs(widthSrc);
668     heightSrc = abs(heightSrc);
669     widthDst  = abs(widthDst);
670     heightDst = abs(heightDst);
671
672     if (!(rowSrc = (int *)HeapAlloc( GetProcessHeap(), 0,
673                                     (widthSrc+widthDst)*sizeof(int) ))) return;
674     rowDst = rowSrc + widthSrc;
675
676       /* When stretching, all modes are the same, and DELETESCANS is faster */
677     if ((widthSrc < widthDst) && (heightSrc < heightDst))
678         mode = STRETCH_DELETESCANS;
679
680     if (mode != STRETCH_DELETESCANS)
681         memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
682                 widthDst*sizeof(int) );
683
684     hstretch = (widthSrc < widthDst);
685     vstretch = (heightSrc < heightDst);
686
687     if (hstretch)
688     {
689         xinc = ((int)widthSrc << 16) / widthDst;
690         xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
691     }
692     else
693     {
694         xinc = ((int)widthDst << 16) / widthSrc;
695         xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
696     }
697
698     if (vstretch)
699     {
700         yinc = ((int)heightSrc << 16) / heightDst;
701         ydst = visRectDst->top;
702         if (vswap)
703         {
704             ysrc = yinc * (heightDst - ydst - 1);
705             yinc = -yinc;
706         }
707         else
708             ysrc = yinc * ydst;
709
710         for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
711         {
712             if (((ysrc >> 16) < visRectSrc->top) ||
713                 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
714
715             /* Retrieve a source row */
716             BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
717                            hswap ? widthSrc - visRectSrc->right
718                                  : visRectSrc->left,
719                            visRectSrc->right - visRectSrc->left,
720                            dstImage->depth, foreground, background, hswap );
721
722             /* Stretch or shrink it */
723             if (hstretch)
724                 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
725                                    visRectDst->right - visRectDst->left,
726                                    xinc, xoff, mode );
727             else BITBLT_ShrinkRow( rowSrc, rowDst,
728                                    hswap ? widthSrc - visRectSrc->right
729                                          : visRectSrc->left,
730                                    visRectSrc->right - visRectSrc->left,
731                                    xinc, xoff, mode );
732
733             /* Store the destination row */
734             pixel = rowDst + visRectDst->right - 1;
735             y = ydst - visRectDst->top;
736             for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
737                 XPutPixel( dstImage, x, y, *pixel-- );
738             if (mode != STRETCH_DELETESCANS)
739                 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
740                         widthDst*sizeof(int) );
741
742             /* Make copies of the destination row */
743
744             pdata = dstImage->data + dstImage->bytes_per_line * y;
745             while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
746                    (ydst < visRectDst->bottom-1))
747             {
748                 memcpy( pdata + dstImage->bytes_per_line, pdata,
749                         dstImage->bytes_per_line );
750                 pdata += dstImage->bytes_per_line;
751                 ysrc += yinc;
752                 ydst++;
753             }
754         }        
755     }
756     else  /* Shrinking */
757     {
758         yinc = ((int)heightDst << 16) / heightSrc;
759         ysrc = visRectSrc->top;
760         ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
761         if (vswap)
762         {
763             ydst += yinc * (heightSrc - ysrc - 1);
764             yinc = -yinc;
765         }
766         else
767             ydst += yinc * ysrc;
768
769         for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
770         {
771             if (((ydst >> 16) < visRectDst->top) ||
772                 ((ydst >> 16) >= visRectDst->bottom)) continue;
773
774             /* Retrieve a source row */
775             BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
776                            hswap ? widthSrc - visRectSrc->right
777                                  : visRectSrc->left,
778                            visRectSrc->right - visRectSrc->left,
779                            dstImage->depth, foreground, background, hswap );
780
781             /* Stretch or shrink it */
782             if (hstretch)
783                 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
784                                    visRectDst->right - visRectDst->left,
785                                    xinc, xoff, mode );
786             else BITBLT_ShrinkRow( rowSrc, rowDst,
787                                    hswap ? widthSrc - visRectSrc->right
788                                          : visRectSrc->left,
789                                    visRectSrc->right - visRectSrc->left,
790                                    xinc, xoff, mode );
791
792             /* Merge several source rows into the destination */
793             if (mode == STRETCH_DELETESCANS)
794             {
795                 /* Simply skip the overlapping rows */
796                 while (((ydst + yinc) >> 16 == ydst >> 16) &&
797                        (ysrc < visRectSrc->bottom-1))
798                 {
799                     ydst += yinc;
800                     ysrc++;
801                 }
802             }
803             else if (((ydst + yinc) >> 16 == ydst >> 16) &&
804                      (ysrc < visRectSrc->bottom-1))
805                 continue;  /* Restart loop for next overlapping row */
806         
807             /* Store the destination row */
808             pixel = rowDst + visRectDst->right - 1;
809             y = (ydst >> 16) - visRectDst->top;
810             for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
811                 XPutPixel( dstImage, x, y, *pixel-- );
812             if (mode != STRETCH_DELETESCANS)
813                 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
814                         widthDst*sizeof(int) );
815         }
816     }        
817     HeapFree( GetProcessHeap(), 0, rowSrc );
818 }
819
820
821 /***********************************************************************
822  *           BITBLT_GetSrcAreaStretch
823  *
824  * Retrieve an area from the source DC, stretching and mapping all the
825  * pixels to Windows colors.
826  */
827 static void BITBLT_GetSrcAreaStretch( DC *dcSrc, DC *dcDst,
828                                       Pixmap pixmap, GC gc,
829                                       INT xSrc, INT ySrc,
830                                       INT widthSrc, INT heightSrc,
831                                       INT xDst, INT yDst,
832                                       INT widthDst, INT heightDst,
833                                       RECT *visRectSrc, RECT *visRectDst )
834 {
835     XImage *imageSrc, *imageDst;
836     X11DRV_PDEVICE *physDevSrc = (X11DRV_PDEVICE *)dcSrc->physDev;
837     X11DRV_PDEVICE *physDevDst = (X11DRV_PDEVICE *)dcDst->physDev;
838
839     RECT rectSrc = *visRectSrc;
840     RECT rectDst = *visRectDst;
841
842     if (widthSrc < 0) xSrc += widthSrc;
843     if (widthDst < 0) xDst += widthDst;
844     if (heightSrc < 0) ySrc += heightSrc;
845     if (heightDst < 0) yDst += heightDst;
846     rectSrc.left   -= xSrc;
847     rectSrc.right  -= xSrc;
848     rectSrc.top    -= ySrc;
849     rectSrc.bottom -= ySrc;
850     rectDst.left   -= xDst;
851     rectDst.right  -= xDst;
852     rectDst.top    -= yDst;
853     rectDst.bottom -= yDst;
854
855     /* FIXME: avoid BadMatch errors */
856     imageSrc = XGetImage( display, physDevSrc->drawable,
857                           visRectSrc->left, visRectSrc->top,
858                           visRectSrc->right - visRectSrc->left,
859                           visRectSrc->bottom - visRectSrc->top,
860                           AllPlanes, ZPixmap );
861     XCREATEIMAGE( imageDst, rectDst.right - rectDst.left,
862                   rectDst.bottom - rectDst.top, dcDst->w.bitsPerPixel );
863     BITBLT_StretchImage( imageSrc, imageDst, widthSrc, heightSrc,
864                          widthDst, heightDst, &rectSrc, &rectDst,
865                          physDevDst->textPixel, dcDst->w.bitsPerPixel != 1 ?
866                          physDevDst->backgroundPixel :
867                          physDevSrc->backgroundPixel,
868                          dcDst->w.stretchBltMode );
869     XPutImage( display, pixmap, gc, imageDst, 0, 0, 0, 0,
870                rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
871     XDestroyImage( imageSrc );
872     XDestroyImage( imageDst );
873 }
874
875
876 /***********************************************************************
877  *           BITBLT_GetSrcArea
878  *
879  * Retrieve an area from the source DC, mapping all the
880  * pixels to Windows colors.
881  */
882 static void BITBLT_GetSrcArea( DC *dcSrc, DC *dcDst, Pixmap pixmap, GC gc,
883                                INT xSrc, INT ySrc, RECT *visRectSrc )
884 {
885     XImage *imageSrc, *imageDst;
886     register INT x, y;
887     INT width  = visRectSrc->right - visRectSrc->left;
888     INT height = visRectSrc->bottom - visRectSrc->top;
889     X11DRV_PDEVICE *physDevSrc = (X11DRV_PDEVICE *)dcSrc->physDev;
890     X11DRV_PDEVICE *physDevDst = (X11DRV_PDEVICE *)dcDst->physDev;
891
892     if (dcSrc->w.bitsPerPixel == dcDst->w.bitsPerPixel)
893     {
894         if (!X11DRV_PALETTE_XPixelToPalette ||
895             (dcDst->w.bitsPerPixel == 1))  /* monochrome -> monochrome */
896         {
897             XCopyArea( display, physDevSrc->drawable, pixmap, gc,
898                        visRectSrc->left, visRectSrc->top, width, height, 0, 0);
899         }
900         else  /* color -> color */
901         {
902             if (dcSrc->w.flags & DC_MEMORY)
903                 imageSrc = XGetImage( display, physDevSrc->drawable,
904                                       visRectSrc->left, visRectSrc->top,
905                                       width, height, AllPlanes, ZPixmap );
906             else
907             {
908                 /* Make sure we don't get a BadMatch error */
909                 XCopyArea( display, physDevSrc->drawable, pixmap, gc,
910                            visRectSrc->left, visRectSrc->top,
911                            width, height, 0, 0);
912                 imageSrc = XGetImage( display, pixmap, 0, 0, width, height,
913                                       AllPlanes, ZPixmap );
914             }
915             for (y = 0; y < height; y++)
916                 for (x = 0; x < width; x++)
917                     XPutPixel(imageSrc, x, y,
918                               X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
919             XPutImage( display, pixmap, gc, imageSrc,
920                        0, 0, 0, 0, width, height );
921             XDestroyImage( imageSrc );
922         }
923     }
924     else
925     {
926         if (dcSrc->w.bitsPerPixel == 1)  /* monochrome -> color */
927         {
928             if (X11DRV_PALETTE_XPixelToPalette)
929             {
930                 XSetBackground( display, gc, 
931                              X11DRV_PALETTE_XPixelToPalette[physDevDst->textPixel] );
932                 XSetForeground( display, gc,
933                              X11DRV_PALETTE_XPixelToPalette[physDevDst->backgroundPixel]);
934             }
935             else
936             {
937                 XSetBackground( display, gc, physDevDst->textPixel );
938                 XSetForeground( display, gc, physDevDst->backgroundPixel );
939             }
940             XCopyPlane( display, physDevSrc->drawable, pixmap, gc,
941                         visRectSrc->left, visRectSrc->top,
942                         width, height, 0, 0, 1 );
943         }
944         else  /* color -> monochrome */
945         {
946             /* FIXME: avoid BadMatch error */
947             imageSrc = XGetImage( display, physDevSrc->drawable,
948                                   visRectSrc->left, visRectSrc->top,
949                                   width, height, AllPlanes, ZPixmap );
950             XCREATEIMAGE( imageDst, width, height, dcDst->w.bitsPerPixel );
951             for (y = 0; y < height; y++)
952                 for (x = 0; x < width; x++)
953                     XPutPixel(imageDst, x, y, (XGetPixel(imageSrc,x,y) ==
954                                                physDevSrc->backgroundPixel) );
955             XPutImage( display, pixmap, gc, imageDst,
956                        0, 0, 0, 0, width, height );
957             XDestroyImage( imageSrc );
958             XDestroyImage( imageDst );
959         }
960     }
961 }
962
963
964 /***********************************************************************
965  *           BITBLT_GetDstArea
966  *
967  * Retrieve an area from the destination DC, mapping all the
968  * pixels to Windows colors.
969  */
970 static void BITBLT_GetDstArea(DC *dc, Pixmap pixmap, GC gc, RECT *visRectDst)
971 {
972     INT width  = visRectDst->right - visRectDst->left;
973     INT height = visRectDst->bottom - visRectDst->top;
974     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
975
976     if (!X11DRV_PALETTE_XPixelToPalette || (dc->w.bitsPerPixel == 1) ||
977         (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
978     {
979         XCopyArea( display, physDev->drawable, pixmap, gc,
980                    visRectDst->left, visRectDst->top, width, height, 0, 0 );
981     }
982     else
983     {
984         register INT x, y;
985         XImage *image;
986
987         if (dc->w.flags & DC_MEMORY)
988             image = XGetImage( display, physDev->drawable,
989                                visRectDst->left, visRectDst->top,
990                                width, height, AllPlanes, ZPixmap );
991         else
992         {
993             /* Make sure we don't get a BadMatch error */
994             XCopyArea( display, physDev->drawable, pixmap, gc,
995                        visRectDst->left, visRectDst->top, width, height, 0, 0);
996             image = XGetImage( display, pixmap, 0, 0, width, height,
997                                AllPlanes, ZPixmap );
998         }
999         for (y = 0; y < height; y++)
1000             for (x = 0; x < width; x++)
1001                 XPutPixel( image, x, y,
1002                            X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1003         XPutImage( display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1004         XDestroyImage( image );
1005     }
1006 }
1007
1008
1009 /***********************************************************************
1010  *           BITBLT_PutDstArea
1011  *
1012  * Put an area back into the destination DC, mapping the pixel
1013  * colors to X pixels.
1014  */
1015 static void BITBLT_PutDstArea(DC *dc, Pixmap pixmap, GC gc, RECT *visRectDst)
1016 {
1017     INT width  = visRectDst->right - visRectDst->left;
1018     INT height = visRectDst->bottom - visRectDst->top;
1019     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1020
1021     /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1022
1023     if (!X11DRV_PALETTE_PaletteToXPixel || (dc->w.bitsPerPixel == 1) || 
1024         (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1025     {
1026         XCopyArea( display, pixmap, physDev->drawable, gc, 0, 0,
1027                    width, height, visRectDst->left, visRectDst->top );
1028     }
1029     else
1030     {
1031         register INT x, y;
1032         XImage *image = XGetImage( display, pixmap, 0, 0, width, height,
1033                                    AllPlanes, ZPixmap );
1034         for (y = 0; y < height; y++)
1035             for (x = 0; x < width; x++)
1036             {
1037                 XPutPixel( image, x, y,
1038                            X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1039             }
1040         XPutImage( display, physDev->drawable, gc, image, 0, 0,
1041                    visRectDst->left, visRectDst->top, width, height );
1042         XDestroyImage( image );
1043     }
1044 }
1045
1046
1047 /***********************************************************************
1048  *           BITBLT_GetVisRectangles
1049  *
1050  * Get the source and destination visible rectangles for StretchBlt().
1051  * Return FALSE if one of the rectangles is empty.
1052  */
1053 static BOOL BITBLT_GetVisRectangles( DC *dcDst, INT xDst, INT yDst,
1054                                        INT widthDst, INT heightDst,
1055                                        DC *dcSrc, INT xSrc, INT ySrc,
1056                                        INT widthSrc, INT heightSrc,
1057                                        RECT *visRectSrc, RECT *visRectDst )
1058 {
1059     RECT rect, clipRect;
1060
1061       /* Get the destination visible rectangle */
1062
1063     rect.left   = xDst;
1064     rect.top    = yDst;
1065     rect.right  = xDst + widthDst;
1066     rect.bottom = yDst + heightDst;
1067     if (widthDst < 0) SWAP_INT32( &rect.left, &rect.right );
1068     if (heightDst < 0) SWAP_INT32( &rect.top, &rect.bottom );
1069     GetRgnBox( dcDst->w.hGCClipRgn, &clipRect );
1070     if (!IntersectRect( visRectDst, &rect, &clipRect )) return FALSE;
1071
1072       /* Get the source visible rectangle */
1073
1074     if (!dcSrc) return TRUE;
1075     rect.left   = xSrc;
1076     rect.top    = ySrc;
1077     rect.right  = xSrc + widthSrc;
1078     rect.bottom = ySrc + heightSrc;
1079     if (widthSrc < 0) SWAP_INT32( &rect.left, &rect.right );
1080     if (heightSrc < 0) SWAP_INT32( &rect.top, &rect.bottom );
1081     /* Apparently the clipping and visible regions are only for output, 
1082        so just check against totalExtent here to avoid BadMatch errors */
1083     if (!IntersectRect( visRectSrc, &rect, &dcSrc->w.totalExtent )) 
1084         return FALSE;
1085
1086       /* Intersect the rectangles */
1087
1088     if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1089     {
1090         visRectSrc->left   += xDst - xSrc;
1091         visRectSrc->right  += xDst - xSrc;
1092         visRectSrc->top    += yDst - ySrc;
1093         visRectSrc->bottom += yDst - ySrc;
1094         if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1095         *visRectSrc = *visRectDst = rect;
1096         visRectSrc->left   += xSrc - xDst;
1097         visRectSrc->right  += xSrc - xDst;
1098         visRectSrc->top    += ySrc - yDst;
1099         visRectSrc->bottom += ySrc - yDst;
1100     }
1101     else  /* stretching */
1102     {
1103         /* Map source rectangle into destination coordinates */
1104         rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1105         rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1106         rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1107         rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1108         if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1109         if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1110
1111         /* Avoid rounding errors */
1112         rect.left--;
1113         rect.top--;
1114         rect.right++;
1115         rect.bottom++;
1116         if (!IntersectRect( visRectDst, &rect, visRectDst )) return FALSE;
1117
1118         /* Map destination rectangle back to source coordinates */
1119         rect = *visRectDst;
1120         rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1121         rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1122         rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1123         rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1124         if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1125         if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1126
1127         /* Avoid rounding errors */
1128         rect.left--;
1129         rect.top--;
1130         rect.right++;
1131         rect.bottom++;
1132         if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1133     }
1134     return TRUE;
1135 }
1136
1137
1138 /***********************************************************************
1139  *           BITBLT_InternalStretchBlt
1140  *
1141  * Implementation of PatBlt(), BitBlt() and StretchBlt().
1142  */
1143 static BOOL BITBLT_InternalStretchBlt( DC *dcDst, INT xDst, INT yDst,
1144                                          INT widthDst, INT heightDst,
1145                                          DC *dcSrc, INT xSrc, INT ySrc,
1146                                          INT widthSrc, INT heightSrc,
1147                                          DWORD rop )
1148 {
1149     BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1150     RECT visRectDst, visRectSrc;
1151     INT width, height;
1152     const BYTE *opcode;
1153     Pixmap pixmaps[3] = { 0, 0, 0 };  /* pixmaps for DST, SRC, TMP */
1154     GC tmpGC = 0;
1155     X11DRV_PDEVICE *physDevSrc = NULL;
1156     X11DRV_PDEVICE *physDevDst = (X11DRV_PDEVICE *)dcDst->physDev;
1157
1158     /* compensate for off-by-one shifting for negative widths and heights */
1159     if (widthDst < 0)
1160         ++xDst;
1161     if (heightDst < 0)
1162         ++yDst;
1163     if (widthSrc < 0)
1164         ++xSrc;
1165     if (heightSrc < 0)
1166         ++ySrc;
1167
1168     if(dcSrc) physDevSrc = (X11DRV_PDEVICE *)dcSrc->physDev;
1169     usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1170     useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1171     useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1172     if (!dcSrc && useSrc) return FALSE;
1173
1174       /* Map the coordinates to device coords */
1175
1176     xDst      = dcDst->w.DCOrgX + XLPTODP( dcDst, xDst );
1177     yDst      = dcDst->w.DCOrgY + YLPTODP( dcDst, yDst );
1178
1179     /* Here we have to round to integers, not truncate */
1180     widthDst  = MulDiv(widthDst, dcDst->vportExtX, dcDst->wndExtX);
1181     heightDst = MulDiv(heightDst, dcDst->vportExtY, dcDst->wndExtY);
1182
1183     TRACE("    vportdst=%d,%d-%d,%d wnddst=%d,%d-%d,%d\n",
1184                     dcDst->vportOrgX, dcDst->vportOrgY,
1185                     dcDst->vportExtX, dcDst->vportExtY,
1186                     dcDst->wndOrgX, dcDst->wndOrgY,
1187                     dcDst->wndExtX, dcDst->wndExtY );
1188     TRACE("    rectdst=%d,%d-%d,%d orgdst=%d,%d\n",
1189                     xDst, yDst, widthDst, heightDst,
1190                     dcDst->w.DCOrgX, dcDst->w.DCOrgY );
1191
1192     if (useSrc)
1193     {
1194         xSrc      = dcSrc->w.DCOrgX + XLPTODP( dcSrc, xSrc );
1195         ySrc      = dcSrc->w.DCOrgY + YLPTODP( dcSrc, ySrc );
1196         widthSrc  = widthSrc * dcSrc->vportExtX / dcSrc->wndExtX;
1197         heightSrc = heightSrc * dcSrc->vportExtY / dcSrc->wndExtY;
1198         fStretch  = (widthSrc != widthDst) || (heightSrc != heightDst);
1199         TRACE("    vportsrc=%d,%d-%d,%d wndsrc=%d,%d-%d,%d\n",
1200                         dcSrc->vportOrgX, dcSrc->vportOrgY,
1201                         dcSrc->vportExtX, dcSrc->vportExtY,
1202                         dcSrc->wndOrgX, dcSrc->wndOrgY,
1203                         dcSrc->wndExtX, dcSrc->wndExtY );
1204         TRACE("    rectsrc=%d,%d-%d,%d orgsrc=%d,%d\n",
1205                         xSrc, ySrc, widthSrc, heightSrc,
1206                         dcSrc->w.DCOrgX, dcSrc->w.DCOrgY );
1207         if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1208                                       dcSrc, xSrc, ySrc, widthSrc, heightSrc,
1209                                       &visRectSrc, &visRectDst ))
1210             return TRUE;
1211         TRACE("    vissrc=%d,%d-%d,%d visdst=%d,%d-%d,%d\n",
1212                         visRectSrc.left, visRectSrc.top,
1213                         visRectSrc.right, visRectSrc.bottom,
1214                         visRectDst.left, visRectDst.top,
1215                         visRectDst.right, visRectDst.bottom );
1216     }
1217     else
1218     {
1219         fStretch = FALSE;
1220         if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1221                                       NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1222             return TRUE;
1223         TRACE("    vissrc=none visdst=%d,%d-%d,%d\n",
1224                         visRectDst.left, visRectDst.top,
1225                         visRectDst.right, visRectDst.bottom );
1226     }
1227
1228     width  = visRectDst.right - visRectDst.left;
1229     height = visRectDst.bottom - visRectDst.top;
1230
1231     if (!fStretch) switch(rop)  /* A few optimisations */
1232     {
1233     case BLACKNESS:  /* 0x00 */
1234         if ((dcDst->w.bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1235             XSetFunction( display, physDevDst->gc, GXclear );
1236         else
1237         {
1238             XSetFunction( display, physDevDst->gc, GXcopy );
1239             XSetForeground( display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1240             XSetFillStyle( display, physDevDst->gc, FillSolid );
1241         }
1242         XFillRectangle( display, physDevDst->drawable, physDevDst->gc,
1243                         visRectDst.left, visRectDst.top, width, height );
1244         return TRUE;
1245
1246     case DSTINVERT:  /* 0x55 */
1247         if ((dcDst->w.bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel ||
1248             !perfect_graphics())
1249         {
1250             XSetFunction( display, physDevDst->gc, GXinvert );
1251
1252             if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1253                 XSetFunction( display, physDevDst->gc, GXinvert);
1254             else
1255             {
1256                 /* Xor is much better when we do not have full colormap.   */
1257                 /* Using white^black ensures that we invert at least black */
1258                 /* and white. */
1259                 Pixel xor_pix = (WhitePixelOfScreen(X11DRV_GetXScreen()) ^
1260                                  BlackPixelOfScreen(X11DRV_GetXScreen()));
1261                 XSetFunction( display, physDevDst->gc, GXxor );
1262                 XSetForeground( display, physDevDst->gc, xor_pix);
1263                 XSetFillStyle( display, physDevDst->gc, FillSolid ); 
1264             }
1265             XFillRectangle( display, physDevDst->drawable, physDevDst->gc,
1266                             visRectDst.left, visRectDst.top, width, height ); 
1267             return TRUE;
1268         }
1269         break;
1270
1271     case PATINVERT:  /* 0x5a */
1272         if (perfect_graphics()) break;
1273         if (X11DRV_SetupGCForBrush( dcDst ))
1274         {
1275             XSetFunction( display, physDevDst->gc, GXxor );
1276             XFillRectangle( display, physDevDst->drawable, physDevDst->gc,
1277                             visRectDst.left, visRectDst.top, width, height );
1278         }
1279         return TRUE;
1280
1281     case 0xa50065:
1282         if (perfect_graphics()) break;
1283         if (X11DRV_SetupGCForBrush( dcDst ))
1284         {
1285             XSetFunction( display, physDevDst->gc, GXequiv );
1286             XFillRectangle( display, physDevDst->drawable, physDevDst->gc,
1287                             visRectDst.left, visRectDst.top, width, height );
1288         }
1289         return TRUE;
1290
1291     case SRCCOPY:  /* 0xcc */
1292         if (dcSrc->w.bitsPerPixel == dcDst->w.bitsPerPixel)
1293         {
1294             BOOL expose = !(dcSrc->w.flags & DC_MEMORY) && !(dcDst->w.flags & DC_MEMORY);
1295             if ( expose ) XSetGraphicsExposures( display, physDevDst->gc, True );
1296             XSetFunction( display, physDevDst->gc, GXcopy );
1297             XCopyArea( display, physDevSrc->drawable,
1298                        physDevDst->drawable, physDevDst->gc,
1299                        visRectSrc.left, visRectSrc.top,
1300                        width, height, visRectDst.left, visRectDst.top );
1301             if ( expose ) XSetGraphicsExposures( display, physDevDst->gc, False );
1302             return TRUE;
1303         }
1304         if (dcSrc->w.bitsPerPixel == 1)
1305         {
1306             BOOL expose = !(dcSrc->w.flags & DC_MEMORY) && !(dcDst->w.flags & DC_MEMORY);
1307             XSetBackground( display, physDevDst->gc, physDevDst->textPixel );
1308             XSetForeground( display, physDevDst->gc, 
1309                             physDevDst->backgroundPixel );
1310             XSetFunction( display, physDevDst->gc, GXcopy );
1311             if ( expose ) XSetGraphicsExposures( display, physDevDst->gc, True );
1312             XCopyPlane( display, physDevSrc->drawable,
1313                         physDevDst->drawable, physDevDst->gc,
1314                         visRectSrc.left, visRectSrc.top,
1315                         width, height, visRectDst.left, visRectDst.top, 1 );
1316             if ( expose ) XSetGraphicsExposures( display, physDevDst->gc, False );
1317             return TRUE;
1318         }
1319         break;
1320
1321     case PATCOPY:  /* 0xf0 */
1322         if (!X11DRV_SetupGCForBrush( dcDst )) return TRUE;
1323         XSetFunction( display, physDevDst->gc, GXcopy );
1324         XFillRectangle( display, physDevDst->drawable, physDevDst->gc,
1325                         visRectDst.left, visRectDst.top, width, height );
1326         return TRUE;
1327
1328     case WHITENESS:  /* 0xff */
1329         if ((dcDst->w.bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1330             XSetFunction( display, physDevDst->gc, GXset );
1331         else
1332         {
1333             XSetFunction( display, physDevDst->gc, GXcopy );
1334             XSetForeground( display, physDevDst->gc, 
1335                             WhitePixelOfScreen( X11DRV_GetXScreen() ));
1336             XSetFillStyle( display, physDevDst->gc, FillSolid );
1337         }
1338         XFillRectangle( display, physDevDst->drawable, physDevDst->gc,
1339                         visRectDst.left, visRectDst.top, width, height );
1340         return TRUE;
1341     }
1342
1343     tmpGC = XCreateGC( display, physDevDst->drawable, 0, NULL );
1344     XSetGraphicsExposures( display, tmpGC, False );
1345     pixmaps[DST] = XCreatePixmap( display, X11DRV_GetXRootWindow(), width, height,
1346                                   dcDst->w.bitsPerPixel );
1347     if (useSrc)
1348     {
1349         pixmaps[SRC] = XCreatePixmap( display, X11DRV_GetXRootWindow(), width, height,
1350                                       dcDst->w.bitsPerPixel );
1351         if (fStretch)
1352             BITBLT_GetSrcAreaStretch( dcSrc, dcDst, pixmaps[SRC], tmpGC,
1353                                       xSrc, ySrc, widthSrc, heightSrc,
1354                                       xDst, yDst, widthDst, heightDst,
1355                                       &visRectSrc, &visRectDst );
1356         else
1357             BITBLT_GetSrcArea( dcSrc, dcDst, pixmaps[SRC], tmpGC,
1358                                xSrc, ySrc, &visRectSrc );
1359     }
1360     if (useDst) BITBLT_GetDstArea( dcDst, pixmaps[DST], tmpGC, &visRectDst );
1361     if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( dcDst, tmpGC, TRUE );
1362     else fNullBrush = FALSE;
1363     destUsed = FALSE;
1364
1365     for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1366     {
1367         if (OP_DST(*opcode) == DST) destUsed = TRUE;
1368         XSetFunction( display, tmpGC, OP_ROP(*opcode) );
1369         switch(OP_SRCDST(*opcode))
1370         {
1371         case OP_ARGS(DST,TMP):
1372         case OP_ARGS(SRC,TMP):
1373             if (!pixmaps[TMP])
1374                 pixmaps[TMP] = XCreatePixmap( display, X11DRV_GetXRootWindow(),
1375                                               width, height,
1376                                               dcDst->w.bitsPerPixel );
1377             /* fall through */
1378         case OP_ARGS(DST,SRC):
1379         case OP_ARGS(SRC,DST):
1380         case OP_ARGS(TMP,SRC):
1381         case OP_ARGS(TMP,DST):
1382             XCopyArea( display, pixmaps[OP_SRC(*opcode)],
1383                        pixmaps[OP_DST(*opcode)], tmpGC,
1384                        0, 0, width, height, 0, 0 );
1385             break;
1386
1387         case OP_ARGS(PAT,TMP):
1388             if (!pixmaps[TMP] && !fNullBrush)
1389                 pixmaps[TMP] = XCreatePixmap( display, X11DRV_GetXRootWindow(),
1390                                               width, height,
1391                                               dcDst->w.bitsPerPixel );
1392             /* fall through */
1393         case OP_ARGS(PAT,DST):
1394         case OP_ARGS(PAT,SRC):
1395             if (!fNullBrush)
1396                 XFillRectangle( display, pixmaps[OP_DST(*opcode)],
1397                                 tmpGC, 0, 0, width, height );
1398             break;
1399         }
1400     }
1401     XSetFunction( display, physDevDst->gc, GXcopy );
1402     BITBLT_PutDstArea( dcDst, pixmaps[destUsed ? DST : SRC],
1403                        physDevDst->gc, &visRectDst );
1404     XFreePixmap( display, pixmaps[DST] );
1405     if (pixmaps[SRC]) XFreePixmap( display, pixmaps[SRC] );
1406     if (pixmaps[TMP]) XFreePixmap( display, pixmaps[TMP] );
1407     XFreeGC( display, tmpGC );
1408     return TRUE;
1409 }
1410
1411 struct StretchBlt_params
1412 {
1413     DC   *dcDst;
1414     INT xDst;
1415     INT yDst;
1416     INT widthDst;
1417     INT heightDst;
1418     DC   *dcSrc;
1419     INT xSrc;
1420     INT ySrc;
1421     INT widthSrc;
1422     INT heightSrc;
1423     DWORD rop;
1424 };
1425
1426 /***********************************************************************
1427  *           BITBLT_DoStretchBlt
1428  *
1429  * Wrapper function for BITBLT_InternalStretchBlt
1430  * to use with CALL_LARGE_STACK.
1431  */
1432 static int BITBLT_DoStretchBlt( const struct StretchBlt_params *p )
1433 {
1434     return (int)BITBLT_InternalStretchBlt( p->dcDst, p->xDst, p->yDst,
1435                                            p->widthDst, p->heightDst,
1436                                            p->dcSrc, p->xSrc, p->ySrc,
1437                                            p->widthSrc, p->heightSrc, p->rop );
1438 }
1439
1440 /***********************************************************************
1441  *           X11DRV_PatBlt
1442  */
1443 BOOL X11DRV_PatBlt( DC *dc, INT left, INT top,
1444                       INT width, INT height, DWORD rop )
1445 {
1446     struct StretchBlt_params params;
1447     BOOL result;
1448
1449     params.dcDst = dc;
1450     params.xDst = left;
1451     params.yDst = top;
1452     params.widthDst = width;
1453     params.heightDst = height;
1454     params.dcSrc = NULL;
1455     params.xSrc = 0;
1456     params.ySrc = 0;
1457     params.widthSrc = 0;
1458     params.heightSrc = 0;
1459     params.rop = rop;
1460
1461     if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion( dc );
1462
1463     X11DRV_DIB_UpdateDIBSection( dc, FALSE );
1464     EnterCriticalSection( &X11DRV_CritSection );
1465     result = (BOOL)CALL_LARGE_STACK( BITBLT_DoStretchBlt, &params );
1466     LeaveCriticalSection( &X11DRV_CritSection );
1467     X11DRV_DIB_UpdateDIBSection( dc, TRUE );
1468     return result;
1469 }
1470
1471
1472 /***********************************************************************
1473  *           X11DRV_BitBlt
1474  */
1475 BOOL X11DRV_BitBlt( DC *dcDst, INT xDst, INT yDst,
1476                       INT width, INT height, DC *dcSrc,
1477                       INT xSrc, INT ySrc, DWORD rop )
1478 {
1479     struct StretchBlt_params params;
1480     BOOL result;
1481
1482     params.dcDst = dcDst;
1483     params.xDst = xDst;
1484     params.yDst = yDst;
1485     params.widthDst = width;
1486     params.heightDst = height;
1487     params.dcSrc = dcSrc;
1488     params.xSrc = xSrc;
1489     params.ySrc = ySrc;
1490     params.widthSrc = width;
1491     params.heightSrc = height;
1492     params.rop = rop;
1493
1494     X11DRV_DIB_UpdateDIBSection( dcDst, FALSE );
1495     X11DRV_DIB_UpdateDIBSection( dcSrc, FALSE );
1496
1497     if (dcDst->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion( dcDst );
1498     if (dcSrc && (dcSrc->w.flags & DC_DIRTY)) CLIPPING_UpdateGCRegion( dcSrc );
1499
1500     EnterCriticalSection( &X11DRV_CritSection );
1501     result = (BOOL)CALL_LARGE_STACK( BITBLT_DoStretchBlt, &params );
1502     LeaveCriticalSection( &X11DRV_CritSection );
1503     X11DRV_DIB_UpdateDIBSection( dcDst, TRUE );
1504     return result;
1505 }
1506
1507
1508 /***********************************************************************
1509  *           X11DRV_StretchBlt
1510  */
1511 BOOL X11DRV_StretchBlt( DC *dcDst, INT xDst, INT yDst,
1512                           INT widthDst, INT heightDst,
1513                           DC *dcSrc, INT xSrc, INT ySrc,
1514                           INT widthSrc, INT heightSrc, DWORD rop )
1515 {
1516     struct StretchBlt_params params;
1517     BOOL result;
1518
1519     params.dcDst = dcDst;
1520     params.xDst = xDst;
1521     params.yDst = yDst;
1522     params.widthDst = widthDst;
1523     params.heightDst = heightDst;
1524     params.dcSrc = dcSrc;
1525     params.xSrc = xSrc;
1526     params.ySrc = ySrc;
1527     params.widthSrc = widthSrc;
1528     params.heightSrc = heightSrc;
1529     params.rop = rop;
1530
1531     X11DRV_DIB_UpdateDIBSection( dcDst, FALSE );
1532     X11DRV_DIB_UpdateDIBSection( dcSrc, FALSE );
1533
1534     if (dcDst->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion( dcDst );
1535     if (dcSrc && (dcSrc->w.flags & DC_DIRTY)) CLIPPING_UpdateGCRegion( dcSrc );
1536
1537     EnterCriticalSection( &X11DRV_CritSection );
1538     result = (BOOL)CALL_LARGE_STACK( BITBLT_DoStretchBlt, &params );
1539     LeaveCriticalSection( &X11DRV_CritSection );
1540     X11DRV_DIB_UpdateDIBSection( dcDst, TRUE );
1541     return result;
1542 }
1543