Release 971101
[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 *)HeapAlloc( GetProcessHeap(), 0,
659                                     (widthSrc+widthDst)*sizeof(int) ))) return;
660     rowDst = rowSrc + widthSrc;
661
662       /* When stretching, all modes are the same, and DELETESCANS is faster */
663     if ((widthSrc < widthDst) && (heightSrc < heightDst))
664         mode = STRETCH_DELETESCANS;
665
666     if (mode != STRETCH_DELETESCANS)
667         memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
668                 widthDst*sizeof(int) );
669
670     hstretch = (widthSrc < widthDst);
671     vstretch = (heightSrc < heightDst);
672
673     if (hstretch)
674     {
675         xinc = ((int)widthSrc << 16) / widthDst;
676         xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
677     }
678     else
679     {
680         xinc = ((int)widthDst << 16) / widthSrc;
681         xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
682     }
683
684     if (vstretch)
685     {
686         yinc = ((int)heightSrc << 16) / heightDst;
687         ydst = visRectDst->top;
688         if (vswap)
689         {
690             ysrc = yinc * (heightDst - ydst - 1);
691             yinc = -yinc;
692         }
693         else
694             ysrc = yinc * ydst;
695
696         for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
697         {
698             if (((ysrc >> 16) < visRectSrc->top) ||
699                 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
700
701             /* Retrieve a source row */
702             BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
703                            hswap ? widthSrc - visRectSrc->right
704                                  : visRectSrc->left,
705                            visRectSrc->right - visRectSrc->left,
706                            dstImage->depth, foreground, background, hswap );
707
708             /* Stretch or shrink it */
709             if (hstretch)
710                 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
711                                    visRectDst->right - visRectDst->left,
712                                    xinc, xoff, mode );
713             else BITBLT_ShrinkRow( rowSrc, rowDst,
714                                    hswap ? widthSrc - visRectSrc->right
715                                          : visRectSrc->left,
716                                    visRectSrc->right - visRectSrc->left,
717                                    xinc, xoff, mode );
718
719             /* Store the destination row */
720             pixel = rowDst + visRectDst->right - 1;
721             y = ydst - visRectDst->top;
722             for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
723                 XPutPixel( dstImage, x, y, *pixel-- );
724             if (mode != STRETCH_DELETESCANS)
725                 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
726                         widthDst*sizeof(int) );
727
728             /* Make copies of the destination row */
729
730             pdata = dstImage->data + dstImage->bytes_per_line * y;
731             while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
732                    (ydst < visRectDst->bottom-1))
733             {
734                 memcpy( pdata + dstImage->bytes_per_line, pdata,
735                         dstImage->bytes_per_line );
736                 pdata += dstImage->bytes_per_line;
737                 ysrc += yinc;
738                 ydst++;
739             }
740         }        
741     }
742     else  /* Shrinking */
743     {
744         yinc = ((int)heightDst << 16) / heightSrc;
745         ysrc = visRectSrc->top;
746         ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
747         if (vswap)
748         {
749             ydst += yinc * (heightSrc - ysrc - 1);
750             yinc = -yinc;
751         }
752         else
753             ydst += yinc * ysrc;
754
755         for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
756         {
757             if (((ydst >> 16) < visRectDst->top) ||
758                 ((ydst >> 16) >= visRectDst->bottom)) continue;
759
760             /* Retrieve a source row */
761             BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
762                            hswap ? widthSrc - visRectSrc->right
763                                  : visRectSrc->left,
764                            visRectSrc->right - visRectSrc->left,
765                            dstImage->depth, foreground, background, hswap );
766
767             /* Stretch or shrink it */
768             if (hstretch)
769                 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
770                                    visRectDst->right - visRectDst->left,
771                                    xinc, xoff, mode );
772             else BITBLT_ShrinkRow( rowSrc, rowDst,
773                                    hswap ? widthSrc - visRectSrc->right
774                                          : visRectSrc->left,
775                                    visRectSrc->right - visRectSrc->left,
776                                    xinc, xoff, mode );
777
778             /* Merge several source rows into the destination */
779             if (mode == STRETCH_DELETESCANS)
780             {
781                 /* Simply skip the overlapping rows */
782                 while (((ydst + yinc) >> 16 == ydst >> 16) &&
783                        (ysrc < visRectSrc->bottom-1))
784                 {
785                     ydst += yinc;
786                     ysrc++;
787                 }
788             }
789             else if (((ydst + yinc) >> 16 == ydst >> 16) &&
790                      (ysrc < visRectSrc->bottom-1))
791                 continue;  /* Restart loop for next overlapping row */
792         
793             /* Store the destination row */
794             pixel = rowDst + visRectDst->right - 1;
795             y = (ydst >> 16) - visRectDst->top;
796             for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
797                 XPutPixel( dstImage, x, y, *pixel-- );
798             if (mode != STRETCH_DELETESCANS)
799                 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
800                         widthDst*sizeof(int) );
801         }
802     }        
803     HeapFree( GetProcessHeap(), 0, rowSrc );
804 }
805
806
807 /***********************************************************************
808  *           BITBLT_GetSrcAreaStretch
809  *
810  * Retrieve an area from the source DC, stretching and mapping all the
811  * pixels to Windows colors.
812  */
813 static void BITBLT_GetSrcAreaStretch( DC *dcSrc, DC *dcDst,
814                                       Pixmap pixmap, GC gc,
815                                       INT32 xSrc, INT32 ySrc,
816                                       INT32 widthSrc, INT32 heightSrc,
817                                       INT32 xDst, INT32 yDst,
818                                       INT32 widthDst, INT32 heightDst,
819                                       RECT32 *visRectSrc, RECT32 *visRectDst )
820 {
821     XImage *imageSrc, *imageDst;
822
823     RECT32 rectSrc = *visRectSrc;
824     RECT32 rectDst = *visRectDst;
825
826     if (widthSrc < 0) xSrc += widthSrc;
827     if (widthDst < 0) xDst += widthDst;
828     if (heightSrc < 0) ySrc += heightSrc;
829     if (heightDst < 0) yDst += heightDst;
830     OffsetRect32( &rectSrc, -xSrc, -ySrc );
831     OffsetRect32( &rectDst, -xDst, -yDst );
832
833     /* FIXME: avoid BadMatch errors */
834     imageSrc = XGetImage( display, dcSrc->u.x.drawable,
835                           visRectSrc->left, visRectSrc->top,
836                           visRectSrc->right - visRectSrc->left,
837                           visRectSrc->bottom - visRectSrc->top,
838                           AllPlanes, ZPixmap );
839     XCREATEIMAGE( imageDst, rectDst.right - rectDst.left,
840                   rectDst.bottom - rectDst.top, dcDst->w.bitsPerPixel );
841     BITBLT_StretchImage( imageSrc, imageDst, widthSrc, heightSrc,
842                          widthDst, heightDst, &rectSrc, &rectDst,
843                          dcDst->w.textPixel, dcDst->w.bitsPerPixel != 1 ?
844                            dcDst->w.backgroundPixel : dcSrc->w.backgroundPixel,
845                          dcDst->w.stretchBltMode );
846     XPutImage( display, pixmap, gc, imageDst, 0, 0, 0, 0,
847                rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
848     XDestroyImage( imageSrc );
849     XDestroyImage( imageDst );
850 }
851
852
853 /***********************************************************************
854  *           BITBLT_GetSrcArea
855  *
856  * Retrieve an area from the source DC, mapping all the
857  * pixels to Windows colors.
858  */
859 static void BITBLT_GetSrcArea( DC *dcSrc, DC *dcDst, Pixmap pixmap, GC gc,
860                                INT32 xSrc, INT32 ySrc, RECT32 *visRectSrc )
861 {
862     XImage *imageSrc, *imageDst;
863     register INT32 x, y;
864     INT32 width  = visRectSrc->right - visRectSrc->left;
865     INT32 height = visRectSrc->bottom - visRectSrc->top;
866
867     if (dcSrc->w.bitsPerPixel == dcDst->w.bitsPerPixel)
868     {
869         if (!COLOR_PixelToPalette ||
870             (dcDst->w.bitsPerPixel == 1))  /* monochrome -> monochrome */
871         {
872             XCopyArea( display, dcSrc->u.x.drawable, pixmap, gc,
873                        visRectSrc->left, visRectSrc->top, width, height, 0, 0);
874         }
875         else  /* color -> color */
876         {
877             if (dcSrc->w.flags & DC_MEMORY)
878                 imageSrc = XGetImage( display, dcSrc->u.x.drawable,
879                                       visRectSrc->left, visRectSrc->top,
880                                       width, height, AllPlanes, ZPixmap );
881             else
882             {
883                 /* Make sure we don't get a BadMatch error */
884                 XCopyArea( display, dcSrc->u.x.drawable, pixmap, gc,
885                            visRectSrc->left, visRectSrc->top,
886                            width, height, 0, 0);
887                 imageSrc = XGetImage( display, pixmap, 0, 0, width, height,
888                                       AllPlanes, ZPixmap );
889             }
890             for (y = 0; y < height; y++)
891                 for (x = 0; x < width; x++)
892                     XPutPixel(imageSrc, x, y,
893                               COLOR_PixelToPalette[XGetPixel(imageSrc, x, y)]);
894             XPutImage( display, pixmap, gc, imageSrc,
895                        0, 0, 0, 0, width, height );
896             XDestroyImage( imageSrc );
897         }
898     }
899     else
900     {
901         if (dcSrc->w.bitsPerPixel == 1)  /* monochrome -> color */
902         {
903             if (COLOR_PixelToPalette)
904             {
905                 XSetBackground( display, gc, 
906                                COLOR_PixelToPalette[dcDst->w.textPixel] );
907                 XSetForeground( display, gc,
908                                COLOR_PixelToPalette[dcDst->w.backgroundPixel]);
909             }
910             else
911             {
912                 XSetBackground( display, gc, dcDst->w.textPixel );
913                 XSetForeground( display, gc, dcDst->w.backgroundPixel );
914             }
915             XCopyPlane( display, dcSrc->u.x.drawable, pixmap, gc,
916                         visRectSrc->left, visRectSrc->top,
917                         width, height, 0, 0, 1 );
918         }
919         else  /* color -> monochrome */
920         {
921             /* FIXME: avoid BadMatch error */
922             imageSrc = XGetImage( display, dcSrc->u.x.drawable,
923                                   visRectSrc->left, visRectSrc->top,
924                                   width, height, AllPlanes, ZPixmap );
925             XCREATEIMAGE( imageDst, width, height, dcDst->w.bitsPerPixel );
926             for (y = 0; y < height; y++)
927                 for (x = 0; x < width; x++)
928                     XPutPixel(imageDst, x, y, (XGetPixel(imageSrc,x,y) ==
929                                                dcSrc->w.backgroundPixel) );
930             XPutImage( display, pixmap, gc, imageDst,
931                        0, 0, 0, 0, width, height );
932             XDestroyImage( imageSrc );
933             XDestroyImage( imageDst );
934         }
935     }
936 }
937
938
939 /***********************************************************************
940  *           BITBLT_GetDstArea
941  *
942  * Retrieve an area from the destination DC, mapping all the
943  * pixels to Windows colors.
944  */
945 static void BITBLT_GetDstArea(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     if (!COLOR_PixelToPalette || (dc->w.bitsPerPixel == 1) ||
951         (COLOR_GetSystemPaletteFlags() & COLOR_VIRTUAL) )
952     {
953         XCopyArea( display, dc->u.x.drawable, pixmap, gc,
954                    visRectDst->left, visRectDst->top, width, height, 0, 0 );
955     }
956     else
957     {
958         register INT32 x, y;
959         XImage *image;
960
961         if (dc->w.flags & DC_MEMORY)
962             image = XGetImage( display, dc->u.x.drawable,
963                                visRectDst->left, visRectDst->top,
964                                width, height, AllPlanes, ZPixmap );
965         else
966         {
967             /* Make sure we don't get a BadMatch error */
968             XCopyArea( display, dc->u.x.drawable, pixmap, gc,
969                        visRectDst->left, visRectDst->top, width, height, 0, 0);
970             image = XGetImage( display, pixmap, 0, 0, width, height,
971                                AllPlanes, ZPixmap );
972         }
973         for (y = 0; y < height; y++)
974             for (x = 0; x < width; x++)
975                 XPutPixel( image, x, y,
976                            COLOR_PixelToPalette[XGetPixel( image, x, y )]);
977         XPutImage( display, pixmap, gc, image, 0, 0, 0, 0, width, height );
978     }
979 }
980
981
982 /***********************************************************************
983  *           BITBLT_PutDstArea
984  *
985  * Put an area back into the destination DC, mapping the pixel
986  * colors to X pixels.
987  */
988 static void BITBLT_PutDstArea(DC *dc, Pixmap pixmap, GC gc, RECT32 *visRectDst)
989 {
990     INT32 width  = visRectDst->right - visRectDst->left;
991     INT32 height = visRectDst->bottom - visRectDst->top;
992
993     /* !COLOR_PaletteToPixel is _NOT_ enough */
994
995     if (!COLOR_PaletteToPixel || (dc->w.bitsPerPixel == 1) || 
996         (COLOR_GetSystemPaletteFlags() & COLOR_VIRTUAL) )
997     {
998         XCopyArea( display, pixmap, dc->u.x.drawable, gc, 0, 0,
999                    width, height, visRectDst->left, visRectDst->top );
1000     }
1001     else
1002     {
1003         register INT32 x, y;
1004         XImage *image = XGetImage( display, pixmap, 0, 0, width, height,
1005                                    AllPlanes, ZPixmap );
1006         for (y = 0; y < height; y++)
1007             for (x = 0; x < width; x++)
1008             {
1009                 XPutPixel( image, x, y,
1010                            COLOR_PaletteToPixel[XGetPixel( image, x, y )]);
1011             }
1012         XPutImage( display, dc->u.x.drawable, gc, image, 0, 0,
1013                    visRectDst->left, visRectDst->top, width, height );
1014         XDestroyImage( image );
1015     }
1016 }
1017
1018
1019 /***********************************************************************
1020  *           BITBLT_GetVisRectangles
1021  *
1022  * Get the source and destination visible rectangles for StretchBlt().
1023  * Return FALSE if one of the rectangles is empty.
1024  */
1025 static BOOL32 BITBLT_GetVisRectangles( DC *dcDst, INT32 xDst, INT32 yDst,
1026                                        INT32 widthDst, INT32 heightDst,
1027                                        DC *dcSrc, INT32 xSrc, INT32 ySrc,
1028                                        INT32 widthSrc, INT32 heightSrc,
1029                                        RECT32 *visRectSrc, RECT32 *visRectDst )
1030 {
1031     RECT32 rect, clipRect;
1032
1033       /* Get the destination visible rectangle */
1034
1035     SetRect32( &rect, xDst, yDst, xDst + widthDst, yDst + heightDst );
1036     if (widthDst < 0) SWAP_INT32( &rect.left, &rect.right );
1037     if (heightDst < 0) SWAP_INT32( &rect.top, &rect.bottom );
1038     GetRgnBox32( dcDst->w.hGCClipRgn, &clipRect );
1039     OffsetRect32( &clipRect, dcDst->w.DCOrgX, dcDst->w.DCOrgY );
1040     if (!IntersectRect32( visRectDst, &rect, &clipRect )) return FALSE;
1041
1042       /* Get the source visible rectangle */
1043
1044     if (!dcSrc) return TRUE;
1045     SetRect32( &rect, xSrc, ySrc, xSrc + widthSrc, ySrc + heightSrc );
1046     if (widthSrc < 0) SWAP_INT32( &rect.left, &rect.right );
1047     if (heightSrc < 0) SWAP_INT32( &rect.top, &rect.bottom );
1048     /* Apparently the clip region is only for output, so use hVisRgn here */
1049     GetRgnBox32( dcSrc->w.hVisRgn, &clipRect );
1050     OffsetRect32( &clipRect, dcSrc->w.DCOrgX, dcSrc->w.DCOrgY );
1051     if (!IntersectRect32( visRectSrc, &rect, &clipRect )) return FALSE;
1052
1053       /* Intersect the rectangles */
1054
1055     if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1056     {
1057         OffsetRect32( visRectSrc, xDst - xSrc, yDst - ySrc );
1058         if (!IntersectRect32( &rect, visRectSrc, visRectDst )) return FALSE;
1059         *visRectSrc = *visRectDst = rect;
1060         OffsetRect32( visRectSrc, xSrc - xDst, ySrc - yDst );
1061     }
1062     else  /* stretching */
1063     {
1064         /* Map source rectangle into destination coordinates */
1065         rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1066         rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1067         rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1068         rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1069         if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1070         if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1071         InflateRect32( &rect, 1, 1 );  /* Avoid rounding errors */
1072         if (!IntersectRect32( visRectDst, &rect, visRectDst )) return FALSE;
1073
1074         /* Map destination rectangle back to source coordinates */
1075         rect = *visRectDst;
1076         rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1077         rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1078         rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1079         rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1080         if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1081         if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1082         InflateRect32( &rect, 1, 1 );  /* Avoid rounding errors */
1083         if (!IntersectRect32( visRectSrc, &rect, visRectSrc )) return FALSE;
1084     }
1085     return TRUE;
1086 }
1087
1088
1089 /***********************************************************************
1090  *           BITBLT_InternalStretchBlt
1091  *
1092  * Implementation of PatBlt(), BitBlt() and StretchBlt().
1093  */
1094 BOOL32 BITBLT_InternalStretchBlt( DC *dcDst, INT32 xDst, INT32 yDst,
1095                                   INT32 widthDst, INT32 heightDst,
1096                                   DC *dcSrc, INT32 xSrc, INT32 ySrc,
1097                                   INT32 widthSrc, INT32 heightSrc, DWORD rop )
1098 {
1099     BOOL32 usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1100     RECT32 visRectDst, visRectSrc;
1101     INT32 width, height;
1102     const BYTE *opcode;
1103     Pixmap pixmaps[3] = { 0, 0, 0 };  /* pixmaps for DST, SRC, TMP */
1104     GC tmpGC = 0;
1105
1106     usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1107     useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1108     useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1109     if (!dcSrc && useSrc) return FALSE;
1110
1111     if (dcDst->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion( dcDst );
1112     if (dcSrc && (dcSrc->w.flags & DC_DIRTY)) CLIPPING_UpdateGCRegion( dcSrc );
1113
1114       /* Map the coordinates to device coords */
1115
1116     xDst      = dcDst->w.DCOrgX + XLPTODP( dcDst, xDst );
1117     yDst      = dcDst->w.DCOrgY + YLPTODP( dcDst, yDst );
1118     widthDst  = widthDst * dcDst->vportExtX / dcDst->wndExtX;
1119     heightDst = heightDst * dcDst->vportExtY / dcDst->wndExtY;
1120
1121     dprintf_bitblt( stddeb, "    vportdst=%d,%d-%d,%d wnddst=%d,%d-%d,%d\n",
1122                     dcDst->vportOrgX, dcDst->vportOrgY,
1123                     dcDst->vportExtX, dcDst->vportExtY,
1124                     dcDst->wndOrgX, dcDst->wndOrgY,
1125                     dcDst->wndExtX, dcDst->wndExtY );
1126     dprintf_bitblt( stddeb, "    rectdst=%d,%d-%d,%d orgdst=%d,%d\n",
1127                     xDst, yDst, widthDst, heightDst,
1128                     dcDst->w.DCOrgX, dcDst->w.DCOrgY );
1129
1130     if (useSrc)
1131     {
1132         xSrc      = dcSrc->w.DCOrgX + XLPTODP( dcSrc, xSrc );
1133         ySrc      = dcSrc->w.DCOrgY + YLPTODP( dcSrc, ySrc );
1134         widthSrc  = widthSrc * dcSrc->vportExtX / dcSrc->wndExtX;
1135         heightSrc = heightSrc * dcSrc->vportExtY / dcSrc->wndExtY;
1136         fStretch  = (widthSrc != widthDst) || (heightSrc != heightDst);
1137         dprintf_bitblt( stddeb,"    vportsrc=%d,%d-%d,%d wndsrc=%d,%d-%d,%d\n",
1138                         dcSrc->vportOrgX, dcSrc->vportOrgY,
1139                         dcSrc->vportExtX, dcSrc->vportExtY,
1140                         dcSrc->wndOrgX, dcSrc->wndOrgY,
1141                         dcSrc->wndExtX, dcSrc->wndExtY );
1142         dprintf_bitblt( stddeb, "    rectsrc=%d,%d-%d,%d orgsrc=%d,%d\n",
1143                         xSrc, ySrc, widthSrc, heightSrc,
1144                         dcSrc->w.DCOrgX, dcSrc->w.DCOrgY );
1145         if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1146                                       dcSrc, xSrc, ySrc, widthSrc, heightSrc,
1147                                       &visRectSrc, &visRectDst ))
1148             return TRUE;
1149         dprintf_bitblt( stddeb, "    vissrc=%d,%d-%d,%d visdst=%d,%d-%d,%d\n",
1150                         visRectSrc.left, visRectSrc.top,
1151                         visRectSrc.right, visRectSrc.bottom,
1152                         visRectDst.left, visRectDst.top,
1153                         visRectDst.right, visRectDst.bottom );
1154     }
1155     else
1156     {
1157         fStretch = FALSE;
1158         if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1159                                       NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1160             return TRUE;
1161         dprintf_bitblt( stddeb, "    vissrc=none visdst=%d,%d-%d,%d\n",
1162                         visRectDst.left, visRectDst.top,
1163                         visRectDst.right, visRectDst.bottom );
1164     }
1165
1166     width  = visRectDst.right - visRectDst.left;
1167     height = visRectDst.bottom - visRectDst.top;
1168
1169     if (!fStretch) switch(rop)  /* A few optimisations */
1170     {
1171     case BLACKNESS:  /* 0x00 */
1172         if ((dcDst->w.bitsPerPixel == 1) || !COLOR_PaletteToPixel)
1173             XSetFunction( display, dcDst->u.x.gc, GXclear );
1174         else
1175         {
1176             XSetFunction( display, dcDst->u.x.gc, GXcopy );
1177             XSetForeground( display, dcDst->u.x.gc, COLOR_PaletteToPixel[0] );
1178             XSetFillStyle( display, dcDst->u.x.gc, FillSolid );
1179         }
1180         XFillRectangle( display, dcDst->u.x.drawable, dcDst->u.x.gc,
1181                         visRectDst.left, visRectDst.top, width, height );
1182         return TRUE;
1183
1184     case DSTINVERT:  /* 0x55 */
1185         if ((dcDst->w.bitsPerPixel == 1) || !COLOR_PaletteToPixel ||
1186             !Options.perfectGraphics)
1187         {
1188             XSetFunction( display, dcDst->u.x.gc, GXinvert );
1189
1190             if( COLOR_GetSystemPaletteFlags() & (COLOR_PRIVATE | COLOR_VIRTUAL) )
1191                 XSetFunction( display, dcDst->u.x.gc, GXinvert);
1192             else
1193             {
1194                 /* Xor is much better when we do not have full colormap.   */
1195                 /* Using white^black ensures that we invert at least black */
1196                 /* and white. */
1197                 Pixel xor_pix = (WhitePixelOfScreen(screen) ^
1198                                  BlackPixelOfScreen(screen));
1199                 XSetFunction( display, dcDst->u.x.gc, GXxor );
1200                 XSetForeground( display, dcDst->u.x.gc, xor_pix);
1201                 XSetFillStyle( display, dcDst->u.x.gc, FillSolid ); 
1202             }
1203             XFillRectangle( display, dcDst->u.x.drawable, dcDst->u.x.gc,
1204                             visRectDst.left, visRectDst.top, width, height ); 
1205             return TRUE;
1206         }
1207         break;
1208
1209     case PATINVERT:  /* 0x5a */
1210         if (Options.perfectGraphics) break;
1211         if (DC_SetupGCForBrush( dcDst ))
1212         {
1213             XSetFunction( display, dcDst->u.x.gc, GXxor );
1214             XFillRectangle( display, dcDst->u.x.drawable, dcDst->u.x.gc,
1215                             visRectDst.left, visRectDst.top, width, height );
1216         }
1217         return TRUE;
1218
1219     case 0xa50065:
1220         if (Options.perfectGraphics) break;
1221         if (DC_SetupGCForBrush( dcDst ))
1222         {
1223             XSetFunction( display, dcDst->u.x.gc, GXequiv );
1224             XFillRectangle( display, dcDst->u.x.drawable, dcDst->u.x.gc,
1225                             visRectDst.left, visRectDst.top, width, height );
1226         }
1227         return TRUE;
1228
1229     case SRCCOPY:  /* 0xcc */
1230         if (dcSrc->w.bitsPerPixel == dcDst->w.bitsPerPixel)
1231         {
1232             XSetGraphicsExposures( display, dcDst->u.x.gc, True );
1233             XSetFunction( display, dcDst->u.x.gc, GXcopy );
1234             XCopyArea( display, dcSrc->u.x.drawable,
1235                        dcDst->u.x.drawable, dcDst->u.x.gc,
1236                        visRectSrc.left, visRectSrc.top,
1237                        width, height, visRectDst.left, visRectDst.top );
1238             XSetGraphicsExposures( display, dcDst->u.x.gc, False );
1239             return TRUE;
1240         }
1241         if (dcSrc->w.bitsPerPixel == 1)
1242         {
1243             XSetBackground( display, dcDst->u.x.gc, dcDst->w.textPixel );
1244             XSetForeground( display, dcDst->u.x.gc, dcDst->w.backgroundPixel );
1245             XSetFunction( display, dcDst->u.x.gc, GXcopy );
1246             XSetGraphicsExposures( display, dcDst->u.x.gc, True );
1247             XCopyPlane( display, dcSrc->u.x.drawable,
1248                         dcDst->u.x.drawable, dcDst->u.x.gc,
1249                         visRectSrc.left, visRectSrc.top,
1250                         width, height, visRectDst.left, visRectDst.top, 1 );
1251             XSetGraphicsExposures( display, dcDst->u.x.gc, False );
1252             return TRUE;
1253         }
1254         break;
1255
1256     case PATCOPY:  /* 0xf0 */
1257         if (!DC_SetupGCForBrush( dcDst )) return TRUE;
1258         XSetFunction( display, dcDst->u.x.gc, GXcopy );
1259         XFillRectangle( display, dcDst->u.x.drawable, dcDst->u.x.gc,
1260                         visRectDst.left, visRectDst.top, width, height );
1261         return TRUE;
1262
1263     case WHITENESS:  /* 0xff */
1264         if ((dcDst->w.bitsPerPixel == 1) || !COLOR_PaletteToPixel)
1265             XSetFunction( display, dcDst->u.x.gc, GXset );
1266         else
1267         {
1268             XSetFunction( display, dcDst->u.x.gc, GXcopy );
1269             XSetForeground( display, dcDst->u.x.gc, 
1270                             COLOR_PaletteToPixel[COLOR_GetSystemPaletteSize() - 1]);
1271             XSetFillStyle( display, dcDst->u.x.gc, FillSolid );
1272         }
1273         XFillRectangle( display, dcDst->u.x.drawable, dcDst->u.x.gc,
1274                         visRectDst.left, visRectDst.top, width, height );
1275         return TRUE;
1276     }
1277
1278     tmpGC = XCreateGC( display, dcDst->u.x.drawable, 0, NULL );
1279     pixmaps[DST] = XCreatePixmap( display, rootWindow, width, height,
1280                                   dcDst->w.bitsPerPixel );
1281     if (useSrc)
1282     {
1283         pixmaps[SRC] = XCreatePixmap( display, rootWindow, width, height,
1284                                       dcDst->w.bitsPerPixel );
1285         if (fStretch)
1286             BITBLT_GetSrcAreaStretch( dcSrc, dcDst, pixmaps[SRC], tmpGC,
1287                                       xSrc, ySrc, widthSrc, heightSrc,
1288                                       xDst, yDst, widthDst, heightDst,
1289                                       &visRectSrc, &visRectDst );
1290         else
1291             BITBLT_GetSrcArea( dcSrc, dcDst, pixmaps[SRC], tmpGC,
1292                                xSrc, ySrc, &visRectSrc );
1293     }
1294     if (useDst) BITBLT_GetDstArea( dcDst, pixmaps[DST], tmpGC, &visRectDst );
1295     if (usePat) fNullBrush = !DC_SetupGCForPatBlt( dcDst, tmpGC, TRUE );
1296     else fNullBrush = FALSE;
1297     destUsed = FALSE;
1298
1299     for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1300     {
1301         if (OP_DST(*opcode) == DST) destUsed = TRUE;
1302         XSetFunction( display, tmpGC, OP_ROP(*opcode) );
1303         switch(OP_SRCDST(*opcode))
1304         {
1305         case OP_ARGS(DST,TMP):
1306         case OP_ARGS(SRC,TMP):
1307             if (!pixmaps[TMP])
1308                 pixmaps[TMP] = XCreatePixmap( display, rootWindow,
1309                                               width, height,
1310                                               dcDst->w.bitsPerPixel );
1311             /* fall through */
1312         case OP_ARGS(DST,SRC):
1313         case OP_ARGS(SRC,DST):
1314         case OP_ARGS(TMP,SRC):
1315         case OP_ARGS(TMP,DST):
1316             XCopyArea( display, pixmaps[OP_SRC(*opcode)],
1317                        pixmaps[OP_DST(*opcode)], tmpGC,
1318                        0, 0, width, height, 0, 0 );
1319             break;
1320
1321         case OP_ARGS(PAT,TMP):
1322             if (!pixmaps[TMP] && !fNullBrush)
1323                 pixmaps[TMP] = XCreatePixmap( display, rootWindow,
1324                                               width, height,
1325                                               dcDst->w.bitsPerPixel );
1326             /* fall through */
1327         case OP_ARGS(PAT,DST):
1328         case OP_ARGS(PAT,SRC):
1329             if (!fNullBrush)
1330                 XFillRectangle( display, pixmaps[OP_DST(*opcode)],
1331                                 tmpGC, 0, 0, width, height );
1332             break;
1333         }
1334     }
1335     XSetFunction( display, dcDst->u.x.gc, GXcopy );
1336     BITBLT_PutDstArea( dcDst, pixmaps[destUsed ? DST : SRC],
1337                        dcDst->u.x.gc, &visRectDst );
1338     XFreePixmap( display, pixmaps[DST] );
1339     if (pixmaps[SRC]) XFreePixmap( display, pixmaps[SRC] );
1340     if (pixmaps[TMP]) XFreePixmap( display, pixmaps[TMP] );
1341     XFreeGC( display, tmpGC );
1342     return TRUE;
1343 }
1344
1345 struct StretchBlt_params
1346 {
1347     DC   *dcDst;
1348     INT32 xDst;
1349     INT32 yDst;
1350     INT32 widthDst;
1351     INT32 heightDst;
1352     DC   *dcSrc;
1353     INT32 xSrc;
1354     INT32 ySrc;
1355     INT32 widthSrc;
1356     INT32 heightSrc;
1357     DWORD rop;
1358 };
1359
1360 /***********************************************************************
1361  *           BITBLT_DoStretchBlt
1362  *
1363  * Wrapper function for BITBLT_InternalStretchBlt
1364  * to use with CALL_LARGE_STACK.
1365  */
1366 static int BITBLT_DoStretchBlt( const struct StretchBlt_params *p )
1367 {
1368     return (int)BITBLT_InternalStretchBlt( p->dcDst, p->xDst, p->yDst,
1369                                            p->widthDst, p->heightDst,
1370                                            p->dcSrc, p->xSrc, p->ySrc,
1371                                            p->widthSrc, p->heightSrc, p->rop );
1372 }
1373
1374 /***********************************************************************
1375  *           X11DRV_PatBlt
1376  */
1377 BOOL32 X11DRV_PatBlt( DC *dc, INT32 left, INT32 top,
1378                       INT32 width, INT32 height, DWORD rop )
1379 {
1380     struct StretchBlt_params params = { dc, left, top, width, height,
1381                                         NULL, 0, 0, 0, 0, rop };
1382     return (BOOL32)CALL_LARGE_STACK( BITBLT_DoStretchBlt, &params );
1383 }
1384
1385
1386 /***********************************************************************
1387  *           X11DRV_BitBlt
1388  */
1389 BOOL32 X11DRV_BitBlt( DC *dcDst, INT32 xDst, INT32 yDst,
1390                       INT32 width, INT32 height, DC *dcSrc,
1391                       INT32 xSrc, INT32 ySrc, DWORD rop )
1392 {
1393     struct StretchBlt_params params = { dcDst, xDst, yDst, width, height,
1394                                         dcSrc, xSrc, ySrc, width, height, rop};
1395     return (BOOL32)CALL_LARGE_STACK( BITBLT_DoStretchBlt, &params );
1396 }
1397
1398
1399 /***********************************************************************
1400  *           X11DRV_StretchBlt
1401  */
1402 BOOL32 X11DRV_StretchBlt( DC *dcDst, INT32 xDst, INT32 yDst,
1403                           INT32 widthDst, INT32 heightDst,
1404                           DC *dcSrc, INT32 xSrc, INT32 ySrc,
1405                           INT32 widthSrc, INT32 heightSrc, DWORD rop )
1406 {
1407     struct StretchBlt_params params = { dcDst, xDst, yDst, widthDst, heightDst,
1408                                         dcSrc, xSrc, ySrc, widthSrc, heightSrc,
1409                                         rop };
1410     return (BOOL32)CALL_LARGE_STACK( BITBLT_DoStretchBlt, &params );
1411 }