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