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