16-bit resource size must be scaled by alignment.
[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             if (dcDst->w.bitsPerPixel == 1)
898             {
899                 /* MSDN says if StretchBlt must convert a bitmap from monochrome
900                    to color or vice versa, the forground and background color of
901                    the device context are used.  In fact, it also applies to the
902                    case when it is converted from mono to mono. */ 
903                 XSetBackground( display, gc, physDevDst->textPixel );
904                 XSetForeground( display, gc, physDevDst->backgroundPixel );
905                 XCopyPlane( display, physDevSrc->drawable, pixmap, gc,
906                             visRectSrc->left, visRectSrc->top,
907                             width, height, 0, 0, 1);
908             }
909             else
910                 XCopyArea( display, physDevSrc->drawable, pixmap, gc, visRectSrc
911                            ->left, visRectSrc->top, width, height, 0, 0);
912         }
913         else  /* color -> color */
914         {
915             if (dcSrc->w.flags & DC_MEMORY)
916                 imageSrc = XGetImage( display, physDevSrc->drawable,
917                                       visRectSrc->left, visRectSrc->top,
918                                       width, height, AllPlanes, ZPixmap );
919             else
920             {
921                 /* Make sure we don't get a BadMatch error */
922                 XCopyArea( display, physDevSrc->drawable, pixmap, gc,
923                            visRectSrc->left, visRectSrc->top,
924                            width, height, 0, 0);
925                 imageSrc = XGetImage( display, pixmap, 0, 0, width, height,
926                                       AllPlanes, ZPixmap );
927             }
928             for (y = 0; y < height; y++)
929                 for (x = 0; x < width; x++)
930                     XPutPixel(imageSrc, x, y,
931                               X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
932             XPutImage( display, pixmap, gc, imageSrc,
933                        0, 0, 0, 0, width, height );
934             XDestroyImage( imageSrc );
935         }
936     }
937     else
938     {
939         if (dcSrc->w.bitsPerPixel == 1)  /* monochrome -> color */
940         {
941             if (X11DRV_PALETTE_XPixelToPalette)
942             {
943                 XSetBackground( display, gc, 
944                              X11DRV_PALETTE_XPixelToPalette[physDevDst->textPixel] );
945                 XSetForeground( display, gc,
946                              X11DRV_PALETTE_XPixelToPalette[physDevDst->backgroundPixel]);
947             }
948             else
949             {
950                 XSetBackground( display, gc, physDevDst->textPixel );
951                 XSetForeground( display, gc, physDevDst->backgroundPixel );
952             }
953             XCopyPlane( display, physDevSrc->drawable, pixmap, gc,
954                         visRectSrc->left, visRectSrc->top,
955                         width, height, 0, 0, 1 );
956         }
957         else  /* color -> monochrome */
958         {
959             /* FIXME: avoid BadMatch error */
960             imageSrc = XGetImage( display, physDevSrc->drawable,
961                                   visRectSrc->left, visRectSrc->top,
962                                   width, height, AllPlanes, ZPixmap );
963             XCREATEIMAGE( imageDst, width, height, dcDst->w.bitsPerPixel );
964             for (y = 0; y < height; y++)
965                 for (x = 0; x < width; x++)
966                     XPutPixel(imageDst, x, y, (XGetPixel(imageSrc,x,y) ==
967                                                physDevSrc->backgroundPixel) );
968             XPutImage( display, pixmap, gc, imageDst,
969                        0, 0, 0, 0, width, height );
970             XDestroyImage( imageSrc );
971             XDestroyImage( imageDst );
972         }
973     }
974 }
975
976
977 /***********************************************************************
978  *           BITBLT_GetDstArea
979  *
980  * Retrieve an area from the destination DC, mapping all the
981  * pixels to Windows colors.
982  */
983 static void BITBLT_GetDstArea(DC *dc, Pixmap pixmap, GC gc, RECT *visRectDst)
984 {
985     INT width  = visRectDst->right - visRectDst->left;
986     INT height = visRectDst->bottom - visRectDst->top;
987     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
988
989     if (!X11DRV_PALETTE_XPixelToPalette || (dc->w.bitsPerPixel == 1) ||
990         (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
991     {
992         XCopyArea( display, physDev->drawable, pixmap, gc,
993                    visRectDst->left, visRectDst->top, width, height, 0, 0 );
994     }
995     else
996     {
997         register INT x, y;
998         XImage *image;
999
1000         if (dc->w.flags & DC_MEMORY)
1001             image = XGetImage( display, physDev->drawable,
1002                                visRectDst->left, visRectDst->top,
1003                                width, height, AllPlanes, ZPixmap );
1004         else
1005         {
1006             /* Make sure we don't get a BadMatch error */
1007             XCopyArea( display, physDev->drawable, pixmap, gc,
1008                        visRectDst->left, visRectDst->top, width, height, 0, 0);
1009             image = XGetImage( display, pixmap, 0, 0, width, height,
1010                                AllPlanes, ZPixmap );
1011         }
1012         for (y = 0; y < height; y++)
1013             for (x = 0; x < width; x++)
1014                 XPutPixel( image, x, y,
1015                            X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1016         XPutImage( display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1017         XDestroyImage( image );
1018     }
1019 }
1020
1021
1022 /***********************************************************************
1023  *           BITBLT_PutDstArea
1024  *
1025  * Put an area back into the destination DC, mapping the pixel
1026  * colors to X pixels.
1027  */
1028 static void BITBLT_PutDstArea(DC *dc, Pixmap pixmap, GC gc, RECT *visRectDst)
1029 {
1030     INT width  = visRectDst->right - visRectDst->left;
1031     INT height = visRectDst->bottom - visRectDst->top;
1032     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1033
1034     /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1035
1036     if (!X11DRV_PALETTE_PaletteToXPixel || (dc->w.bitsPerPixel == 1) || 
1037         (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1038     {
1039         XCopyArea( display, pixmap, physDev->drawable, gc, 0, 0,
1040                    width, height, visRectDst->left, visRectDst->top );
1041     }
1042     else
1043     {
1044         register INT x, y;
1045         XImage *image = XGetImage( display, pixmap, 0, 0, width, height,
1046                                    AllPlanes, ZPixmap );
1047         for (y = 0; y < height; y++)
1048             for (x = 0; x < width; x++)
1049             {
1050                 XPutPixel( image, x, y,
1051                            X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1052             }
1053         XPutImage( display, physDev->drawable, gc, image, 0, 0,
1054                    visRectDst->left, visRectDst->top, width, height );
1055         XDestroyImage( image );
1056     }
1057 }
1058
1059
1060 /***********************************************************************
1061  *           BITBLT_GetVisRectangles
1062  *
1063  * Get the source and destination visible rectangles for StretchBlt().
1064  * Return FALSE if one of the rectangles is empty.
1065  */
1066 static BOOL BITBLT_GetVisRectangles( DC *dcDst, INT xDst, INT yDst,
1067                                        INT widthDst, INT heightDst,
1068                                        DC *dcSrc, INT xSrc, INT ySrc,
1069                                        INT widthSrc, INT heightSrc,
1070                                        RECT *visRectSrc, RECT *visRectDst )
1071 {
1072     RECT rect, clipRect;
1073
1074       /* Get the destination visible rectangle */
1075
1076     rect.left   = xDst;
1077     rect.top    = yDst;
1078     rect.right  = xDst + widthDst;
1079     rect.bottom = yDst + heightDst;
1080     if (widthDst < 0) SWAP_INT32( &rect.left, &rect.right );
1081     if (heightDst < 0) SWAP_INT32( &rect.top, &rect.bottom );
1082     GetRgnBox( dcDst->w.hGCClipRgn, &clipRect );
1083     if (!IntersectRect( visRectDst, &rect, &clipRect )) return FALSE;
1084
1085       /* Get the source visible rectangle */
1086
1087     if (!dcSrc) return TRUE;
1088     rect.left   = xSrc;
1089     rect.top    = ySrc;
1090     rect.right  = xSrc + widthSrc;
1091     rect.bottom = ySrc + heightSrc;
1092     if (widthSrc < 0) SWAP_INT32( &rect.left, &rect.right );
1093     if (heightSrc < 0) SWAP_INT32( &rect.top, &rect.bottom );
1094     /* Apparently the clipping and visible regions are only for output, 
1095        so just check against totalExtent here to avoid BadMatch errors */
1096     if (!IntersectRect( visRectSrc, &rect, &dcSrc->w.totalExtent )) 
1097         return FALSE;
1098
1099       /* Intersect the rectangles */
1100
1101     if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1102     {
1103         visRectSrc->left   += xDst - xSrc;
1104         visRectSrc->right  += xDst - xSrc;
1105         visRectSrc->top    += yDst - ySrc;
1106         visRectSrc->bottom += yDst - ySrc;
1107         if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1108         *visRectSrc = *visRectDst = rect;
1109         visRectSrc->left   += xSrc - xDst;
1110         visRectSrc->right  += xSrc - xDst;
1111         visRectSrc->top    += ySrc - yDst;
1112         visRectSrc->bottom += ySrc - yDst;
1113     }
1114     else  /* stretching */
1115     {
1116         /* Map source rectangle into destination coordinates */
1117         rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1118         rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1119         rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1120         rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1121         if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1122         if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1123
1124         /* Avoid rounding errors */
1125         rect.left--;
1126         rect.top--;
1127         rect.right++;
1128         rect.bottom++;
1129         if (!IntersectRect( visRectDst, &rect, visRectDst )) return FALSE;
1130
1131         /* Map destination rectangle back to source coordinates */
1132         rect = *visRectDst;
1133         rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1134         rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1135         rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1136         rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1137         if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1138         if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1139
1140         /* Avoid rounding errors */
1141         rect.left--;
1142         rect.top--;
1143         rect.right++;
1144         rect.bottom++;
1145         if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1146     }
1147     return TRUE;
1148 }
1149
1150
1151 /***********************************************************************
1152  *           BITBLT_InternalStretchBlt
1153  *
1154  * Implementation of PatBlt(), BitBlt() and StretchBlt().
1155  */
1156 static BOOL BITBLT_InternalStretchBlt( DC *dcDst, INT xDst, INT yDst,
1157                                          INT widthDst, INT heightDst,
1158                                          DC *dcSrc, INT xSrc, INT ySrc,
1159                                          INT widthSrc, INT heightSrc,
1160                                          DWORD rop )
1161 {
1162     BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1163     RECT visRectDst, visRectSrc;
1164     INT width, height;
1165     const BYTE *opcode;
1166     Pixmap pixmaps[3] = { 0, 0, 0 };  /* pixmaps for DST, SRC, TMP */
1167     GC tmpGC = 0;
1168     X11DRV_PDEVICE *physDevSrc = NULL;
1169     X11DRV_PDEVICE *physDevDst = (X11DRV_PDEVICE *)dcDst->physDev;
1170
1171     /* compensate for off-by-one shifting for negative widths and heights */
1172     if (widthDst < 0)
1173         ++xDst;
1174     if (heightDst < 0)
1175         ++yDst;
1176     if (widthSrc < 0)
1177         ++xSrc;
1178     if (heightSrc < 0)
1179         ++ySrc;
1180
1181     if(dcSrc) physDevSrc = (X11DRV_PDEVICE *)dcSrc->physDev;
1182     usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1183     useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1184     useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1185     if (!dcSrc && useSrc) return FALSE;
1186
1187       /* Map the coordinates to device coords */
1188
1189     xDst      = dcDst->w.DCOrgX + XLPTODP( dcDst, xDst );
1190     yDst      = dcDst->w.DCOrgY + YLPTODP( dcDst, yDst );
1191
1192     /* Here we have to round to integers, not truncate */
1193     widthDst  = MulDiv(widthDst, dcDst->vportExtX, dcDst->wndExtX);
1194     heightDst = MulDiv(heightDst, dcDst->vportExtY, dcDst->wndExtY);
1195
1196     TRACE("    vportdst=%d,%d-%d,%d wnddst=%d,%d-%d,%d\n",
1197                     dcDst->vportOrgX, dcDst->vportOrgY,
1198                     dcDst->vportExtX, dcDst->vportExtY,
1199                     dcDst->wndOrgX, dcDst->wndOrgY,
1200                     dcDst->wndExtX, dcDst->wndExtY );
1201     TRACE("    rectdst=%d,%d-%d,%d orgdst=%d,%d\n",
1202                     xDst, yDst, widthDst, heightDst,
1203                     dcDst->w.DCOrgX, dcDst->w.DCOrgY );
1204
1205     if (useSrc)
1206     {
1207         xSrc      = dcSrc->w.DCOrgX + XLPTODP( dcSrc, xSrc );
1208         ySrc      = dcSrc->w.DCOrgY + YLPTODP( dcSrc, ySrc );
1209         widthSrc  = widthSrc * dcSrc->vportExtX / dcSrc->wndExtX;
1210         heightSrc = heightSrc * dcSrc->vportExtY / dcSrc->wndExtY;
1211         fStretch  = (widthSrc != widthDst) || (heightSrc != heightDst);
1212         TRACE("    vportsrc=%d,%d-%d,%d wndsrc=%d,%d-%d,%d\n",
1213                         dcSrc->vportOrgX, dcSrc->vportOrgY,
1214                         dcSrc->vportExtX, dcSrc->vportExtY,
1215                         dcSrc->wndOrgX, dcSrc->wndOrgY,
1216                         dcSrc->wndExtX, dcSrc->wndExtY );
1217         TRACE("    rectsrc=%d,%d-%d,%d orgsrc=%d,%d\n",
1218                         xSrc, ySrc, widthSrc, heightSrc,
1219                         dcSrc->w.DCOrgX, dcSrc->w.DCOrgY );
1220         if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1221                                       dcSrc, xSrc, ySrc, widthSrc, heightSrc,
1222                                       &visRectSrc, &visRectDst ))
1223             return TRUE;
1224         TRACE("    vissrc=%d,%d-%d,%d visdst=%d,%d-%d,%d\n",
1225                         visRectSrc.left, visRectSrc.top,
1226                         visRectSrc.right, visRectSrc.bottom,
1227                         visRectDst.left, visRectDst.top,
1228                         visRectDst.right, visRectDst.bottom );
1229     }
1230     else
1231     {
1232         fStretch = FALSE;
1233         if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1234                                       NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1235             return TRUE;
1236         TRACE("    vissrc=none visdst=%d,%d-%d,%d\n",
1237                         visRectDst.left, visRectDst.top,
1238                         visRectDst.right, visRectDst.bottom );
1239     }
1240
1241     width  = visRectDst.right - visRectDst.left;
1242     height = visRectDst.bottom - visRectDst.top;
1243
1244     if (!fStretch) switch(rop)  /* A few optimisations */
1245     {
1246     case BLACKNESS:  /* 0x00 */
1247         if ((dcDst->w.bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1248             XSetFunction( display, physDevDst->gc, GXclear );
1249         else
1250         {
1251             XSetFunction( display, physDevDst->gc, GXcopy );
1252             XSetForeground( display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1253             XSetFillStyle( display, physDevDst->gc, FillSolid );
1254         }
1255         XFillRectangle( display, physDevDst->drawable, physDevDst->gc,
1256                         visRectDst.left, visRectDst.top, width, height );
1257         return TRUE;
1258
1259     case DSTINVERT:  /* 0x55 */
1260         if ((dcDst->w.bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel ||
1261             !perfect_graphics())
1262         {
1263             XSetFunction( display, physDevDst->gc, GXinvert );
1264
1265             if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1266                 XSetFunction( display, physDevDst->gc, GXinvert);
1267             else
1268             {
1269                 /* Xor is much better when we do not have full colormap.   */
1270                 /* Using white^black ensures that we invert at least black */
1271                 /* and white. */
1272                 Pixel xor_pix = (WhitePixelOfScreen(X11DRV_GetXScreen()) ^
1273                                  BlackPixelOfScreen(X11DRV_GetXScreen()));
1274                 XSetFunction( display, physDevDst->gc, GXxor );
1275                 XSetForeground( display, physDevDst->gc, xor_pix);
1276                 XSetFillStyle( display, physDevDst->gc, FillSolid ); 
1277             }
1278             XFillRectangle( display, physDevDst->drawable, physDevDst->gc,
1279                             visRectDst.left, visRectDst.top, width, height ); 
1280             return TRUE;
1281         }
1282         break;
1283
1284     case PATINVERT:  /* 0x5a */
1285         if (perfect_graphics()) break;
1286         if (X11DRV_SetupGCForBrush( dcDst ))
1287         {
1288             XSetFunction( display, physDevDst->gc, GXxor );
1289             XFillRectangle( display, physDevDst->drawable, physDevDst->gc,
1290                             visRectDst.left, visRectDst.top, width, height );
1291         }
1292         return TRUE;
1293
1294     case 0xa50065:
1295         if (perfect_graphics()) break;
1296         if (X11DRV_SetupGCForBrush( dcDst ))
1297         {
1298             XSetFunction( display, physDevDst->gc, GXequiv );
1299             XFillRectangle( display, physDevDst->drawable, physDevDst->gc,
1300                             visRectDst.left, visRectDst.top, width, height );
1301         }
1302         return TRUE;
1303
1304     case SRCCOPY:  /* 0xcc */
1305         if (dcSrc->w.bitsPerPixel == dcDst->w.bitsPerPixel)
1306         {
1307             BOOL expose = !(dcSrc->w.flags & DC_MEMORY) && !(dcDst->w.flags & DC_MEMORY);
1308             if ( expose ) XSetGraphicsExposures( display, physDevDst->gc, True );
1309             XSetFunction( display, physDevDst->gc, GXcopy );
1310             XCopyArea( display, physDevSrc->drawable,
1311                        physDevDst->drawable, physDevDst->gc,
1312                        visRectSrc.left, visRectSrc.top,
1313                        width, height, visRectDst.left, visRectDst.top );
1314             if ( expose ) XSetGraphicsExposures( display, physDevDst->gc, False );
1315             return TRUE;
1316         }
1317         if (dcSrc->w.bitsPerPixel == 1)
1318         {
1319             BOOL expose = !(dcSrc->w.flags & DC_MEMORY) && !(dcDst->w.flags & DC_MEMORY);
1320             XSetBackground( display, physDevDst->gc, physDevDst->textPixel );
1321             XSetForeground( display, physDevDst->gc, 
1322                             physDevDst->backgroundPixel );
1323             XSetFunction( display, physDevDst->gc, GXcopy );
1324             if ( expose ) XSetGraphicsExposures( display, physDevDst->gc, True );
1325             XCopyPlane( display, physDevSrc->drawable,
1326                         physDevDst->drawable, physDevDst->gc,
1327                         visRectSrc.left, visRectSrc.top,
1328                         width, height, visRectDst.left, visRectDst.top, 1 );
1329             if ( expose ) XSetGraphicsExposures( display, physDevDst->gc, False );
1330             return TRUE;
1331         }
1332         break;
1333
1334     case PATCOPY:  /* 0xf0 */
1335         if (!X11DRV_SetupGCForBrush( dcDst )) return TRUE;
1336         XSetFunction( display, physDevDst->gc, GXcopy );
1337         XFillRectangle( display, physDevDst->drawable, physDevDst->gc,
1338                         visRectDst.left, visRectDst.top, width, height );
1339         return TRUE;
1340
1341     case WHITENESS:  /* 0xff */
1342         if ((dcDst->w.bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1343             XSetFunction( display, physDevDst->gc, GXset );
1344         else
1345         {
1346             XSetFunction( display, physDevDst->gc, GXcopy );
1347             XSetForeground( display, physDevDst->gc, 
1348                             WhitePixelOfScreen( X11DRV_GetXScreen() ));
1349             XSetFillStyle( display, physDevDst->gc, FillSolid );
1350         }
1351         XFillRectangle( display, physDevDst->drawable, physDevDst->gc,
1352                         visRectDst.left, visRectDst.top, width, height );
1353         return TRUE;
1354     }
1355
1356     tmpGC = XCreateGC( display, physDevDst->drawable, 0, NULL );
1357     XSetGraphicsExposures( display, tmpGC, False );
1358     pixmaps[DST] = XCreatePixmap( display, X11DRV_GetXRootWindow(), width, height,
1359                                   dcDst->w.bitsPerPixel );
1360     if (useSrc)
1361     {
1362         pixmaps[SRC] = XCreatePixmap( display, X11DRV_GetXRootWindow(), width, height,
1363                                       dcDst->w.bitsPerPixel );
1364         if (fStretch)
1365             BITBLT_GetSrcAreaStretch( dcSrc, dcDst, pixmaps[SRC], tmpGC,
1366                                       xSrc, ySrc, widthSrc, heightSrc,
1367                                       xDst, yDst, widthDst, heightDst,
1368                                       &visRectSrc, &visRectDst );
1369         else
1370             BITBLT_GetSrcArea( dcSrc, dcDst, pixmaps[SRC], tmpGC,
1371                                xSrc, ySrc, &visRectSrc );
1372     }
1373     if (useDst) BITBLT_GetDstArea( dcDst, pixmaps[DST], tmpGC, &visRectDst );
1374     if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( dcDst, tmpGC, TRUE );
1375     else fNullBrush = FALSE;
1376     destUsed = FALSE;
1377
1378     for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1379     {
1380         if (OP_DST(*opcode) == DST) destUsed = TRUE;
1381         XSetFunction( display, tmpGC, OP_ROP(*opcode) );
1382         switch(OP_SRCDST(*opcode))
1383         {
1384         case OP_ARGS(DST,TMP):
1385         case OP_ARGS(SRC,TMP):
1386             if (!pixmaps[TMP])
1387                 pixmaps[TMP] = XCreatePixmap( display, X11DRV_GetXRootWindow(),
1388                                               width, height,
1389                                               dcDst->w.bitsPerPixel );
1390             /* fall through */
1391         case OP_ARGS(DST,SRC):
1392         case OP_ARGS(SRC,DST):
1393         case OP_ARGS(TMP,SRC):
1394         case OP_ARGS(TMP,DST):
1395             XCopyArea( display, pixmaps[OP_SRC(*opcode)],
1396                        pixmaps[OP_DST(*opcode)], tmpGC,
1397                        0, 0, width, height, 0, 0 );
1398             break;
1399
1400         case OP_ARGS(PAT,TMP):
1401             if (!pixmaps[TMP] && !fNullBrush)
1402                 pixmaps[TMP] = XCreatePixmap( display, X11DRV_GetXRootWindow(),
1403                                               width, height,
1404                                               dcDst->w.bitsPerPixel );
1405             /* fall through */
1406         case OP_ARGS(PAT,DST):
1407         case OP_ARGS(PAT,SRC):
1408             if (!fNullBrush)
1409                 XFillRectangle( display, pixmaps[OP_DST(*opcode)],
1410                                 tmpGC, 0, 0, width, height );
1411             break;
1412         }
1413     }
1414     XSetFunction( display, physDevDst->gc, GXcopy );
1415     BITBLT_PutDstArea( dcDst, pixmaps[destUsed ? DST : SRC],
1416                        physDevDst->gc, &visRectDst );
1417     XFreePixmap( display, pixmaps[DST] );
1418     if (pixmaps[SRC]) XFreePixmap( display, pixmaps[SRC] );
1419     if (pixmaps[TMP]) XFreePixmap( display, pixmaps[TMP] );
1420     XFreeGC( display, tmpGC );
1421     return TRUE;
1422 }
1423
1424 struct StretchBlt_params
1425 {
1426     DC   *dcDst;
1427     INT xDst;
1428     INT yDst;
1429     INT widthDst;
1430     INT heightDst;
1431     DC   *dcSrc;
1432     INT xSrc;
1433     INT ySrc;
1434     INT widthSrc;
1435     INT heightSrc;
1436     DWORD rop;
1437 };
1438
1439 /***********************************************************************
1440  *           BITBLT_DoStretchBlt
1441  *
1442  * Wrapper function for BITBLT_InternalStretchBlt
1443  * to use with CALL_LARGE_STACK.
1444  */
1445 static int BITBLT_DoStretchBlt( const struct StretchBlt_params *p )
1446 {
1447     return (int)BITBLT_InternalStretchBlt( p->dcDst, p->xDst, p->yDst,
1448                                            p->widthDst, p->heightDst,
1449                                            p->dcSrc, p->xSrc, p->ySrc,
1450                                            p->widthSrc, p->heightSrc, p->rop );
1451 }
1452
1453 /***********************************************************************
1454  *           X11DRV_PatBlt
1455  */
1456 BOOL X11DRV_PatBlt( DC *dc, INT left, INT top,
1457                       INT width, INT height, DWORD rop )
1458 {
1459     struct StretchBlt_params params;
1460     BOOL result;
1461
1462     params.dcDst = dc;
1463     params.xDst = left;
1464     params.yDst = top;
1465     params.widthDst = width;
1466     params.heightDst = height;
1467     params.dcSrc = NULL;
1468     params.xSrc = 0;
1469     params.ySrc = 0;
1470     params.widthSrc = 0;
1471     params.heightSrc = 0;
1472     params.rop = rop;
1473
1474     X11DRV_DIB_UpdateDIBSection( dc, FALSE );
1475     EnterCriticalSection( &X11DRV_CritSection );
1476     result = (BOOL)CALL_LARGE_STACK( BITBLT_DoStretchBlt, &params );
1477     LeaveCriticalSection( &X11DRV_CritSection );
1478     X11DRV_DIB_UpdateDIBSection( dc, TRUE );
1479     return result;
1480 }
1481
1482
1483 /***********************************************************************
1484  *           X11DRV_BitBlt
1485  */
1486 BOOL X11DRV_BitBlt( DC *dcDst, INT xDst, INT yDst,
1487                       INT width, INT height, DC *dcSrc,
1488                       INT xSrc, INT ySrc, DWORD rop )
1489 {
1490     struct StretchBlt_params params;
1491     BOOL result;
1492
1493     params.dcDst = dcDst;
1494     params.xDst = xDst;
1495     params.yDst = yDst;
1496     params.widthDst = width;
1497     params.heightDst = height;
1498     params.dcSrc = dcSrc;
1499     params.xSrc = xSrc;
1500     params.ySrc = ySrc;
1501     params.widthSrc = width;
1502     params.heightSrc = height;
1503     params.rop = rop;
1504
1505     X11DRV_DIB_UpdateDIBSection( dcDst, FALSE );
1506     X11DRV_DIB_UpdateDIBSection( dcSrc, FALSE );
1507
1508     EnterCriticalSection( &X11DRV_CritSection );
1509     result = (BOOL)CALL_LARGE_STACK( BITBLT_DoStretchBlt, &params );
1510     LeaveCriticalSection( &X11DRV_CritSection );
1511     X11DRV_DIB_UpdateDIBSection( dcDst, TRUE );
1512     return result;
1513 }
1514
1515
1516 /***********************************************************************
1517  *           X11DRV_StretchBlt
1518  */
1519 BOOL X11DRV_StretchBlt( DC *dcDst, INT xDst, INT yDst,
1520                           INT widthDst, INT heightDst,
1521                           DC *dcSrc, INT xSrc, INT ySrc,
1522                           INT widthSrc, INT heightSrc, DWORD rop )
1523 {
1524     struct StretchBlt_params params;
1525     BOOL result;
1526
1527     params.dcDst = dcDst;
1528     params.xDst = xDst;
1529     params.yDst = yDst;
1530     params.widthDst = widthDst;
1531     params.heightDst = heightDst;
1532     params.dcSrc = dcSrc;
1533     params.xSrc = xSrc;
1534     params.ySrc = ySrc;
1535     params.widthSrc = widthSrc;
1536     params.heightSrc = heightSrc;
1537     params.rop = rop;
1538
1539     X11DRV_DIB_UpdateDIBSection( dcDst, FALSE );
1540     X11DRV_DIB_UpdateDIBSection( dcSrc, FALSE );
1541
1542     EnterCriticalSection( &X11DRV_CritSection );
1543     result = (BOOL)CALL_LARGE_STACK( BITBLT_DoStretchBlt, &params );
1544     LeaveCriticalSection( &X11DRV_CritSection );
1545     X11DRV_DIB_UpdateDIBSection( dcDst, TRUE );
1546     return result;
1547 }
1548