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