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