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