2 * GDI bit-blit operations
4 * Copyright 1993, 1994 Alexandre Julliard
9 #include <X11/Intrinsic.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 )
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;
465 int rop, i, res, src, dst, pat, tmp, dstUsed;
468 for (rop = 0; rop < 256; rop++)
471 for (i = 0; i < 8; i++)
476 for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
480 case OP_ARGS(DST,TMP):
481 tmp = do_bitop( dst, tmp, *opcode & 0xf );
483 case OP_ARGS(DST,SRC):
484 src = do_bitop( dst, src, *opcode & 0xf );
486 case OP_ARGS(SRC,TMP):
487 tmp = do_bitop( src, tmp, *opcode & 0xf );
489 case OP_ARGS(SRC,DST):
490 dst = do_bitop( src, dst, *opcode & 0xf );
493 case OP_ARGS(PAT,TMP):
494 tmp = do_bitop( pat, tmp, *opcode & 0xf );
496 case OP_ARGS(PAT,DST):
497 dst = do_bitop( pat, dst, *opcode & 0xf );
500 case OP_ARGS(PAT,SRC):
501 src = do_bitop( pat, src, *opcode & 0xf );
503 case OP_ARGS(TMP,DST):
504 dst = do_bitop( tmp, dst, *opcode & 0xf );
507 case OP_ARGS(TMP,SRC):
508 src = do_bitop( tmp, src, *opcode & 0xf );
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 /***********************************************************************
527 * Favor correctness or speed?
529 static inline int perfect_graphics(void)
531 static int perfect = -1;
538 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
540 DWORD type, count = sizeof(buffer);
541 if(!RegQueryValueExA(hkey, "PerfectGraphics", 0, &type, buffer, &count))
544 perfect = (ch == 'y' || ch == 'Y' || ch == 't' || ch == 'T' || ch == '1');
552 /***********************************************************************
555 * Stretch a row of pixels. Helper function for BITBLT_StretchImage.
557 static void BITBLT_StretchRow( int *rowSrc, int *rowDst,
558 INT startDst, INT widthDst,
559 INT xinc, INT xoff, WORD mode )
561 register INT xsrc = xinc * startDst + xoff;
565 case STRETCH_ANDSCANS:
566 for(; widthDst > 0; widthDst--, xsrc += xinc)
567 *rowDst++ &= rowSrc[xsrc >> 16];
569 case STRETCH_ORSCANS:
570 for(; widthDst > 0; widthDst--, xsrc += xinc)
571 *rowDst++ |= rowSrc[xsrc >> 16];
573 case STRETCH_DELETESCANS:
574 for(; widthDst > 0; widthDst--, xsrc += xinc)
575 *rowDst++ = rowSrc[xsrc >> 16];
581 /***********************************************************************
584 * Shrink a row of pixels. Helper function for BITBLT_StretchImage.
586 static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst,
587 INT startSrc, INT widthSrc,
588 INT xinc, INT xoff, WORD mode )
590 register INT xdst = xinc * startSrc + xoff;
594 case STRETCH_ORSCANS:
595 for(; widthSrc > 0; widthSrc--, xdst += xinc)
596 rowDst[xdst >> 16] |= *rowSrc++;
598 case STRETCH_ANDSCANS:
599 for(; widthSrc > 0; widthSrc--, xdst += xinc)
600 rowDst[xdst >> 16] &= *rowSrc++;
602 case STRETCH_DELETESCANS:
603 for(; widthSrc > 0; widthSrc--, xdst += xinc)
604 rowDst[xdst >> 16] = *rowSrc++;
610 /***********************************************************************
613 * Retrieve a row from an image. Helper function for BITBLT_StretchImage.
615 static void BITBLT_GetRow( XImage *image, int *pdata, INT row,
616 INT start, INT width, INT depthDst,
617 int fg, int bg, BOOL swap)
621 assert( (row >= 0) && (row < image->height) );
622 assert( (start >= 0) && (width <= image->width) );
624 pdata += swap ? start+width-1 : start;
625 if (image->depth == depthDst) /* color -> color */
627 if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1))
628 if (swap) for (i = 0; i < width; i++)
629 *pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
630 else for (i = 0; i < width; i++)
631 *pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
633 if (swap) for (i = 0; i < width; i++)
634 *pdata-- = XGetPixel( image, i, row );
635 else for (i = 0; i < width; i++)
636 *pdata++ = XGetPixel( image, i, row );
640 if (image->depth == 1) /* monochrome -> color */
642 if (X11DRV_PALETTE_XPixelToPalette)
644 fg = X11DRV_PALETTE_XPixelToPalette[fg];
645 bg = X11DRV_PALETTE_XPixelToPalette[bg];
647 if (swap) for (i = 0; i < width; i++)
648 *pdata-- = XGetPixel( image, i, row ) ? bg : fg;
649 else for (i = 0; i < width; i++)
650 *pdata++ = XGetPixel( image, i, row ) ? bg : fg;
652 else /* color -> monochrome */
654 if (swap) for (i = 0; i < width; i++)
655 *pdata-- = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
656 else for (i = 0; i < width; i++)
657 *pdata++ = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
663 /***********************************************************************
664 * BITBLT_StretchImage
666 * Stretch an X image.
667 * FIXME: does not work for full 32-bit coordinates.
669 static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage,
670 INT widthSrc, INT heightSrc,
671 INT widthDst, INT heightDst,
672 RECT *visRectSrc, RECT *visRectDst,
673 int foreground, int background, WORD mode )
675 int *rowSrc, *rowDst, *pixel;
677 INT xinc, xoff, yinc, ysrc, ydst;
679 BOOL hstretch, vstretch, hswap, vswap;
681 hswap = ((int)widthSrc * widthDst) < 0;
682 vswap = ((int)heightSrc * heightDst) < 0;
683 widthSrc = abs(widthSrc);
684 heightSrc = abs(heightSrc);
685 widthDst = abs(widthDst);
686 heightDst = abs(heightDst);
688 if (!(rowSrc = (int *)HeapAlloc( GetProcessHeap(), 0,
689 (widthSrc+widthDst)*sizeof(int) ))) return;
690 rowDst = rowSrc + widthSrc;
692 /* When stretching, all modes are the same, and DELETESCANS is faster */
693 if ((widthSrc < widthDst) && (heightSrc < heightDst))
694 mode = STRETCH_DELETESCANS;
696 if (mode != STRETCH_DELETESCANS)
697 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
698 widthDst*sizeof(int) );
700 hstretch = (widthSrc < widthDst);
701 vstretch = (heightSrc < heightDst);
705 xinc = ((int)widthSrc << 16) / widthDst;
706 xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
710 xinc = ((int)widthDst << 16) / widthSrc;
711 xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
716 yinc = ((int)heightSrc << 16) / heightDst;
717 ydst = visRectDst->top;
720 ysrc = yinc * (heightDst - ydst - 1);
726 for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
728 if (((ysrc >> 16) < visRectSrc->top) ||
729 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
731 /* Retrieve a source row */
732 BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
733 hswap ? widthSrc - visRectSrc->right
735 visRectSrc->right - visRectSrc->left,
736 dstImage->depth, foreground, background, hswap );
738 /* Stretch or shrink it */
740 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
741 visRectDst->right - visRectDst->left,
743 else BITBLT_ShrinkRow( rowSrc, rowDst,
744 hswap ? widthSrc - visRectSrc->right
746 visRectSrc->right - visRectSrc->left,
749 /* Store the destination row */
750 pixel = rowDst + visRectDst->right - 1;
751 y = ydst - visRectDst->top;
752 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
753 XPutPixel( dstImage, x, y, *pixel-- );
754 if (mode != STRETCH_DELETESCANS)
755 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
756 widthDst*sizeof(int) );
758 /* Make copies of the destination row */
760 pdata = dstImage->data + dstImage->bytes_per_line * y;
761 while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
762 (ydst < visRectDst->bottom-1))
764 memcpy( pdata + dstImage->bytes_per_line, pdata,
765 dstImage->bytes_per_line );
766 pdata += dstImage->bytes_per_line;
774 yinc = ((int)heightDst << 16) / heightSrc;
775 ysrc = visRectSrc->top;
776 ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
779 ydst += yinc * (heightSrc - ysrc - 1);
785 for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
787 if (((ydst >> 16) < visRectDst->top) ||
788 ((ydst >> 16) >= visRectDst->bottom)) continue;
790 /* Retrieve a source row */
791 BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
792 hswap ? widthSrc - visRectSrc->right
794 visRectSrc->right - visRectSrc->left,
795 dstImage->depth, foreground, background, hswap );
797 /* Stretch or shrink it */
799 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
800 visRectDst->right - visRectDst->left,
802 else BITBLT_ShrinkRow( rowSrc, rowDst,
803 hswap ? widthSrc - visRectSrc->right
805 visRectSrc->right - visRectSrc->left,
808 /* Merge several source rows into the destination */
809 if (mode == STRETCH_DELETESCANS)
811 /* Simply skip the overlapping rows */
812 while (((ydst + yinc) >> 16 == ydst >> 16) &&
813 (ysrc < visRectSrc->bottom-1))
819 else if (((ydst + yinc) >> 16 == ydst >> 16) &&
820 (ysrc < visRectSrc->bottom-1))
821 continue; /* Restart loop for next overlapping row */
823 /* Store the destination row */
824 pixel = rowDst + visRectDst->right - 1;
825 y = (ydst >> 16) - visRectDst->top;
826 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
827 XPutPixel( dstImage, x, y, *pixel-- );
828 if (mode != STRETCH_DELETESCANS)
829 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
830 widthDst*sizeof(int) );
833 HeapFree( GetProcessHeap(), 0, rowSrc );
837 /***********************************************************************
838 * BITBLT_GetSrcAreaStretch
840 * Retrieve an area from the source DC, stretching and mapping all the
841 * pixels to Windows colors.
843 static int BITBLT_GetSrcAreaStretch( DC *dcSrc, DC *dcDst,
844 Pixmap pixmap, GC gc,
846 INT widthSrc, INT heightSrc,
848 INT widthDst, INT heightDst,
849 RECT *visRectSrc, RECT *visRectDst )
851 XImage *imageSrc, *imageDst;
852 X11DRV_PDEVICE *physDevSrc = (X11DRV_PDEVICE *)dcSrc->physDev;
853 X11DRV_PDEVICE *physDevDst = (X11DRV_PDEVICE *)dcDst->physDev;
855 RECT rectSrc = *visRectSrc;
856 RECT rectDst = *visRectDst;
858 if (widthSrc < 0) xSrc += widthSrc;
859 if (widthDst < 0) xDst += widthDst;
860 if (heightSrc < 0) ySrc += heightSrc;
861 if (heightDst < 0) yDst += heightDst;
862 rectSrc.left -= xSrc;
863 rectSrc.right -= xSrc;
865 rectSrc.bottom -= ySrc;
866 rectDst.left -= xDst;
867 rectDst.right -= xDst;
869 rectDst.bottom -= yDst;
871 /* FIXME: avoid BadMatch errors */
872 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
873 visRectSrc->left, visRectSrc->top,
874 visRectSrc->right - visRectSrc->left,
875 visRectSrc->bottom - visRectSrc->top,
876 AllPlanes, ZPixmap );
877 imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
878 rectDst.bottom - rectDst.top, dcDst->bitsPerPixel );
879 BITBLT_StretchImage( imageSrc, imageDst, widthSrc, heightSrc,
880 widthDst, heightDst, &rectSrc, &rectDst,
881 physDevDst->textPixel, dcDst->bitsPerPixel != 1 ?
882 physDevDst->backgroundPixel :
883 physDevSrc->backgroundPixel,
884 dcDst->stretchBltMode );
885 XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
886 rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
887 XDestroyImage( imageSrc );
888 XDestroyImage( imageDst );
889 return 0; /* no exposure events generated */
893 /***********************************************************************
896 * Retrieve an area from the source DC, mapping all the
897 * pixels to Windows colors.
899 static int BITBLT_GetSrcArea( DC *dcSrc, DC *dcDst, Pixmap pixmap, GC gc,
900 INT xSrc, INT ySrc, RECT *visRectSrc )
902 XImage *imageSrc, *imageDst;
905 INT width = visRectSrc->right - visRectSrc->left;
906 INT height = visRectSrc->bottom - visRectSrc->top;
907 X11DRV_PDEVICE *physDevSrc = (X11DRV_PDEVICE *)dcSrc->physDev;
908 X11DRV_PDEVICE *physDevDst = (X11DRV_PDEVICE *)dcDst->physDev;
910 if (dcSrc->bitsPerPixel == dcDst->bitsPerPixel)
912 if (!X11DRV_PALETTE_XPixelToPalette ||
913 (dcDst->bitsPerPixel == 1)) /* monochrome -> monochrome */
915 if (dcDst->bitsPerPixel == 1)
917 /* MSDN says if StretchBlt must convert a bitmap from monochrome
918 to color or vice versa, the forground and background color of
919 the device context are used. In fact, it also applies to the
920 case when it is converted from mono to mono. */
921 XSetBackground( gdi_display, gc, physDevDst->textPixel );
922 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
923 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
924 visRectSrc->left, visRectSrc->top,
925 width, height, 0, 0, 1);
928 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
929 visRectSrc->left, visRectSrc->top, width, height, 0, 0);
932 else /* color -> color */
934 if (dcSrc->flags & DC_MEMORY)
935 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
936 visRectSrc->left, visRectSrc->top,
937 width, height, AllPlanes, ZPixmap );
940 /* Make sure we don't get a BadMatch error */
941 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
942 visRectSrc->left, visRectSrc->top,
943 width, height, 0, 0);
945 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
946 AllPlanes, ZPixmap );
948 for (y = 0; y < height; y++)
949 for (x = 0; x < width; x++)
950 XPutPixel(imageSrc, x, y,
951 X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
952 XPutImage( gdi_display, pixmap, gc, imageSrc,
953 0, 0, 0, 0, width, height );
954 XDestroyImage( imageSrc );
959 if (dcSrc->bitsPerPixel == 1) /* monochrome -> color */
961 if (X11DRV_PALETTE_XPixelToPalette)
963 XSetBackground( gdi_display, gc,
964 X11DRV_PALETTE_XPixelToPalette[physDevDst->textPixel] );
965 XSetForeground( gdi_display, gc,
966 X11DRV_PALETTE_XPixelToPalette[physDevDst->backgroundPixel]);
970 XSetBackground( gdi_display, gc, physDevDst->textPixel );
971 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
973 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
974 visRectSrc->left, visRectSrc->top,
975 width, height, 0, 0, 1 );
978 else /* color -> monochrome */
980 /* FIXME: avoid BadMatch error */
981 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
982 visRectSrc->left, visRectSrc->top,
983 width, height, AllPlanes, ZPixmap );
984 imageDst = X11DRV_DIB_CreateXImage( width, height, dcDst->bitsPerPixel );
985 for (y = 0; y < height; y++)
986 for (x = 0; x < width; x++)
987 XPutPixel(imageDst, x, y, (XGetPixel(imageSrc,x,y) ==
988 physDevSrc->backgroundPixel) );
989 XPutImage( gdi_display, pixmap, gc, imageDst,
990 0, 0, 0, 0, width, height );
991 XDestroyImage( imageSrc );
992 XDestroyImage( imageDst );
999 /***********************************************************************
1002 * Retrieve an area from the destination DC, mapping all the
1003 * pixels to Windows colors.
1005 static int BITBLT_GetDstArea(DC *dc, Pixmap pixmap, GC gc, RECT *visRectDst)
1008 INT width = visRectDst->right - visRectDst->left;
1009 INT height = visRectDst->bottom - visRectDst->top;
1010 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1012 if (!X11DRV_PALETTE_XPixelToPalette || (dc->bitsPerPixel == 1) ||
1013 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1015 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1016 visRectDst->left, visRectDst->top, width, height, 0, 0 );
1024 if (dc->flags & DC_MEMORY)
1025 image = XGetImage( gdi_display, physDev->drawable,
1026 visRectDst->left, visRectDst->top,
1027 width, height, AllPlanes, ZPixmap );
1030 /* Make sure we don't get a BadMatch error */
1031 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1032 visRectDst->left, visRectDst->top, width, height, 0, 0);
1034 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1035 AllPlanes, ZPixmap );
1037 for (y = 0; y < height; y++)
1038 for (x = 0; x < width; x++)
1039 XPutPixel( image, x, y,
1040 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1041 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1042 XDestroyImage( image );
1048 /***********************************************************************
1051 * Put an area back into the destination DC, mapping the pixel
1052 * colors to X pixels.
1054 static int BITBLT_PutDstArea(DC *dc, Pixmap pixmap, GC gc, RECT *visRectDst)
1057 INT width = visRectDst->right - visRectDst->left;
1058 INT height = visRectDst->bottom - visRectDst->top;
1059 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1061 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1063 if (!X11DRV_PALETTE_PaletteToXPixel || (dc->bitsPerPixel == 1) ||
1064 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1066 XCopyArea( gdi_display, pixmap, physDev->drawable, gc, 0, 0,
1067 width, height, visRectDst->left, visRectDst->top );
1073 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1074 AllPlanes, ZPixmap );
1075 for (y = 0; y < height; y++)
1076 for (x = 0; x < width; x++)
1078 XPutPixel( image, x, y,
1079 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1081 XPutImage( gdi_display, physDev->drawable, gc, image, 0, 0,
1082 visRectDst->left, visRectDst->top, width, height );
1083 XDestroyImage( image );
1089 /***********************************************************************
1090 * BITBLT_GetVisRectangles
1092 * Get the source and destination visible rectangles for StretchBlt().
1093 * Return FALSE if one of the rectangles is empty.
1095 static BOOL BITBLT_GetVisRectangles( DC *dcDst, INT xDst, INT yDst,
1096 INT widthDst, INT heightDst,
1097 DC *dcSrc, INT xSrc, INT ySrc,
1098 INT widthSrc, INT heightSrc,
1099 RECT *visRectSrc, RECT *visRectDst )
1101 RECT rect, clipRect;
1103 /* Get the destination visible rectangle */
1107 rect.right = xDst + widthDst;
1108 rect.bottom = yDst + heightDst;
1109 if (widthDst < 0) SWAP_INT32( &rect.left, &rect.right );
1110 if (heightDst < 0) SWAP_INT32( &rect.top, &rect.bottom );
1111 GetRgnBox( dcDst->hGCClipRgn, &clipRect );
1112 if (!IntersectRect( visRectDst, &rect, &clipRect )) return FALSE;
1114 /* Get the source visible rectangle */
1116 if (!dcSrc) return TRUE;
1119 rect.right = xSrc + widthSrc;
1120 rect.bottom = ySrc + heightSrc;
1121 if (widthSrc < 0) SWAP_INT32( &rect.left, &rect.right );
1122 if (heightSrc < 0) SWAP_INT32( &rect.top, &rect.bottom );
1123 /* Apparently the clipping and visible regions are only for output,
1124 so just check against totalExtent here to avoid BadMatch errors */
1125 if (!IntersectRect( visRectSrc, &rect, &dcSrc->totalExtent ))
1128 /* Intersect the rectangles */
1130 if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1132 visRectSrc->left += xDst - xSrc;
1133 visRectSrc->right += xDst - xSrc;
1134 visRectSrc->top += yDst - ySrc;
1135 visRectSrc->bottom += yDst - ySrc;
1136 if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1137 *visRectSrc = *visRectDst = rect;
1138 visRectSrc->left += xSrc - xDst;
1139 visRectSrc->right += xSrc - xDst;
1140 visRectSrc->top += ySrc - yDst;
1141 visRectSrc->bottom += ySrc - yDst;
1143 else /* stretching */
1145 /* Map source rectangle into destination coordinates */
1146 rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1147 rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1148 rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1149 rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1150 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1151 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1153 /* Avoid rounding errors */
1158 if (!IntersectRect( visRectDst, &rect, visRectDst )) return FALSE;
1160 /* Map destination rectangle back to source coordinates */
1162 rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1163 rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1164 rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1165 rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1166 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1167 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1169 /* Avoid rounding errors */
1174 if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1180 /***********************************************************************
1181 * BITBLT_InternalStretchBlt
1183 * Implementation of PatBlt(), BitBlt() and StretchBlt().
1185 static BOOL BITBLT_InternalStretchBlt( DC *dcDst, INT xDst, INT yDst,
1186 INT widthDst, INT heightDst,
1187 DC *dcSrc, INT xSrc, INT ySrc,
1188 INT widthSrc, INT heightSrc,
1191 BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1192 RECT visRectDst, visRectSrc;
1195 Pixmap pixmaps[3] = { 0, 0, 0 }; /* pixmaps for DST, SRC, TMP */
1197 X11DRV_PDEVICE *physDevSrc = NULL;
1198 X11DRV_PDEVICE *physDevDst = (X11DRV_PDEVICE *)dcDst->physDev;
1200 /* compensate for off-by-one shifting for negative widths and heights */
1210 if(dcSrc) physDevSrc = (X11DRV_PDEVICE *)dcSrc->physDev;
1211 usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1212 useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1213 useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1214 if (!dcSrc && useSrc) return FALSE;
1216 /* Map the coordinates to device coords */
1218 xDst = dcDst->DCOrgX + XLPTODP( dcDst, xDst );
1219 yDst = dcDst->DCOrgY + YLPTODP( dcDst, yDst );
1221 /* Here we have to round to integers, not truncate */
1222 widthDst = MulDiv(widthDst, dcDst->vportExtX, dcDst->wndExtX);
1223 heightDst = MulDiv(heightDst, dcDst->vportExtY, dcDst->wndExtY);
1225 TRACE(" vportdst=%d,%d-%d,%d wnddst=%d,%d-%d,%d\n",
1226 dcDst->vportOrgX, dcDst->vportOrgY,
1227 dcDst->vportExtX, dcDst->vportExtY,
1228 dcDst->wndOrgX, dcDst->wndOrgY,
1229 dcDst->wndExtX, dcDst->wndExtY );
1230 TRACE(" rectdst=%d,%d-%d,%d orgdst=%d,%d\n",
1231 xDst, yDst, widthDst, heightDst,
1232 dcDst->DCOrgX, dcDst->DCOrgY );
1236 xSrc = dcSrc->DCOrgX + XLPTODP( dcSrc, xSrc );
1237 ySrc = dcSrc->DCOrgY + YLPTODP( dcSrc, ySrc );
1238 widthSrc = widthSrc * dcSrc->vportExtX / dcSrc->wndExtX;
1239 heightSrc = heightSrc * dcSrc->vportExtY / dcSrc->wndExtY;
1240 fStretch = (widthSrc != widthDst) || (heightSrc != heightDst);
1241 TRACE(" vportsrc=%d,%d-%d,%d wndsrc=%d,%d-%d,%d\n",
1242 dcSrc->vportOrgX, dcSrc->vportOrgY,
1243 dcSrc->vportExtX, dcSrc->vportExtY,
1244 dcSrc->wndOrgX, dcSrc->wndOrgY,
1245 dcSrc->wndExtX, dcSrc->wndExtY );
1246 TRACE(" rectsrc=%d,%d-%d,%d orgsrc=%d,%d\n",
1247 xSrc, ySrc, widthSrc, heightSrc,
1248 dcSrc->DCOrgX, dcSrc->DCOrgY );
1249 if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1250 dcSrc, xSrc, ySrc, widthSrc, heightSrc,
1251 &visRectSrc, &visRectDst ))
1253 TRACE(" vissrc=%d,%d-%d,%d visdst=%d,%d-%d,%d\n",
1254 visRectSrc.left, visRectSrc.top,
1255 visRectSrc.right, visRectSrc.bottom,
1256 visRectDst.left, visRectDst.top,
1257 visRectDst.right, visRectDst.bottom );
1262 if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1263 NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1265 TRACE(" vissrc=none visdst=%d,%d-%d,%d\n",
1266 visRectDst.left, visRectDst.top,
1267 visRectDst.right, visRectDst.bottom );
1270 width = visRectDst.right - visRectDst.left;
1271 height = visRectDst.bottom - visRectDst.top;
1273 if (!fStretch) switch(rop) /* A few optimisations */
1275 case BLACKNESS: /* 0x00 */
1277 if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1278 XSetFunction( gdi_display, physDevDst->gc, GXclear );
1281 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1282 XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1283 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1285 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1286 visRectDst.left, visRectDst.top, width, height );
1287 wine_tsx11_unlock();
1290 case DSTINVERT: /* 0x55 */
1291 if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel ||
1292 !perfect_graphics())
1295 XSetFunction( gdi_display, physDevDst->gc, GXinvert );
1297 if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1298 XSetFunction( gdi_display, physDevDst->gc, GXinvert);
1301 /* Xor is much better when we do not have full colormap. */
1302 /* Using white^black ensures that we invert at least black */
1304 Pixel xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1305 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1306 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1307 XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1308 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1310 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1311 visRectDst.left, visRectDst.top, width, height );
1312 wine_tsx11_unlock();
1317 case PATINVERT: /* 0x5a */
1318 if (perfect_graphics()) break;
1319 if (X11DRV_SetupGCForBrush( dcDst ))
1322 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1323 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1324 visRectDst.left, visRectDst.top, width, height );
1325 wine_tsx11_unlock();
1330 if (perfect_graphics()) break;
1331 if (X11DRV_SetupGCForBrush( dcDst ))
1334 XSetFunction( gdi_display, physDevDst->gc, GXequiv );
1335 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1336 visRectDst.left, visRectDst.top, width, height );
1337 wine_tsx11_unlock();
1341 case SRCCOPY: /* 0xcc */
1342 if (dcSrc->bitsPerPixel == dcDst->bitsPerPixel)
1345 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1346 XCopyArea( gdi_display, physDevSrc->drawable,
1347 physDevDst->drawable, physDevDst->gc,
1348 visRectSrc.left, visRectSrc.top,
1349 width, height, visRectDst.left, visRectDst.top );
1350 physDevDst->exposures++;
1351 wine_tsx11_unlock();
1354 if (dcSrc->bitsPerPixel == 1)
1357 XSetBackground( gdi_display, physDevDst->gc, physDevDst->textPixel );
1358 XSetForeground( gdi_display, physDevDst->gc, physDevDst->backgroundPixel );
1359 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1360 XCopyPlane( gdi_display, physDevSrc->drawable,
1361 physDevDst->drawable, physDevDst->gc,
1362 visRectSrc.left, visRectSrc.top,
1363 width, height, visRectDst.left, visRectDst.top, 1 );
1364 physDevDst->exposures++;
1365 wine_tsx11_unlock();
1370 case PATCOPY: /* 0xf0 */
1371 if (!X11DRV_SetupGCForBrush( dcDst )) return TRUE;
1373 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1374 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1375 visRectDst.left, visRectDst.top, width, height );
1376 wine_tsx11_unlock();
1379 case WHITENESS: /* 0xff */
1381 if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1382 XSetFunction( gdi_display, physDevDst->gc, GXset );
1385 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1386 XSetForeground( gdi_display, physDevDst->gc,
1387 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1388 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1390 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1391 visRectDst.left, visRectDst.top, width, height );
1392 wine_tsx11_unlock();
1398 tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1399 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1400 XSetGraphicsExposures( gdi_display, tmpGC, False );
1401 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1402 dcDst->bitsPerPixel );
1405 pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1406 dcDst->bitsPerPixel );
1408 BITBLT_GetSrcAreaStretch( dcSrc, dcDst, pixmaps[SRC], tmpGC,
1409 xSrc, ySrc, widthSrc, heightSrc,
1410 xDst, yDst, widthDst, heightDst,
1411 &visRectSrc, &visRectDst );
1413 BITBLT_GetSrcArea( dcSrc, dcDst, pixmaps[SRC], tmpGC,
1414 xSrc, ySrc, &visRectSrc );
1417 if (useDst) BITBLT_GetDstArea( dcDst, pixmaps[DST], tmpGC, &visRectDst );
1418 if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( dcDst, tmpGC, TRUE );
1419 else fNullBrush = FALSE;
1422 for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1424 if (OP_DST(*opcode) == DST) destUsed = TRUE;
1425 XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1426 switch(OP_SRCDST(*opcode))
1428 case OP_ARGS(DST,TMP):
1429 case OP_ARGS(SRC,TMP):
1431 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1433 dcDst->bitsPerPixel );
1435 case OP_ARGS(DST,SRC):
1436 case OP_ARGS(SRC,DST):
1437 case OP_ARGS(TMP,SRC):
1438 case OP_ARGS(TMP,DST):
1439 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1440 pixmaps[OP_DST(*opcode)], tmpGC,
1441 0, 0, width, height, 0, 0 );
1444 case OP_ARGS(PAT,TMP):
1445 if (!pixmaps[TMP] && !fNullBrush)
1446 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1448 dcDst->bitsPerPixel );
1450 case OP_ARGS(PAT,DST):
1451 case OP_ARGS(PAT,SRC):
1453 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1454 tmpGC, 0, 0, width, height );
1458 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1459 physDevDst->exposures += BITBLT_PutDstArea( dcDst, pixmaps[destUsed ? DST : SRC],
1460 physDevDst->gc, &visRectDst );
1461 XFreePixmap( gdi_display, pixmaps[DST] );
1462 if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1463 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1464 XFreeGC( gdi_display, tmpGC );
1465 wine_tsx11_unlock();
1470 /***********************************************************************
1473 BOOL X11DRV_PatBlt( DC *dc, INT left, INT top,
1474 INT width, INT height, DWORD rop )
1478 X11DRV_LockDIBSection( dc, DIB_Status_GdiMod, FALSE );
1479 result = BITBLT_InternalStretchBlt( dc, left, top, width, height, NULL, 0, 0, 0, 0, rop );
1480 X11DRV_UnlockDIBSection( dc, TRUE );
1485 /***********************************************************************
1488 BOOL X11DRV_BitBlt( DC *dcDst, INT xDst, INT yDst,
1489 INT width, INT height, DC *dcSrc,
1490 INT xSrc, INT ySrc, DWORD rop )
1492 BOOL result = FALSE;
1494 RECT visRectDst, visRectSrc;
1496 if (((rop >> 16) & 0x55) == ((rop >> 17) & 0x55)) {
1497 /* FIXME: seems the ROP doesn't include destination;
1498 * now if the destination area include the entire dcDst,
1499 * we can pass TRUE instead of FALSE to CoerceDIBSection(dcDst...),
1500 * which may avoid a copy in some situations */
1502 sDst = X11DRV_LockDIBSection( dcDst, DIB_Status_None, FALSE );
1503 sSrc = X11DRV_LockDIBSection( dcSrc, DIB_Status_None, FALSE );
1505 if ((sSrc == DIB_Status_AppMod) && (rop == SRCCOPY)) {
1506 /* do everything ourselves; map coordinates */
1507 xSrc = dcSrc->DCOrgX + XLPTODP( dcSrc, xSrc );
1508 ySrc = dcSrc->DCOrgY + YLPTODP( dcSrc, ySrc );
1509 xDst = dcDst->DCOrgX + XLPTODP( dcDst, xDst );
1510 yDst = dcDst->DCOrgY + YLPTODP( dcDst, yDst );
1511 width = MulDiv(width, dcDst->vportExtX, dcDst->wndExtX);
1512 height = MulDiv(height, dcDst->vportExtY, dcDst->wndExtY);
1514 /* Perform basic clipping */
1515 if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, width, height,
1516 dcSrc, xSrc, ySrc, width, height,
1517 &visRectSrc, &visRectDst ))
1520 xSrc = visRectSrc.left;
1521 ySrc = visRectSrc.top;
1522 xDst = visRectDst.left;
1523 yDst = visRectDst.top;
1524 width = visRectDst.right - visRectDst.left;
1525 height = visRectDst.bottom - visRectDst.top;
1527 if (sDst == DIB_Status_AppMod) {
1528 FIXME("potential optimization - client-side DIB copy\n");
1530 X11DRV_CoerceDIBSection( dcDst, DIB_Status_GdiMod, FALSE );
1532 X11DRV_DIB_CopyDIBSection( dcSrc, dcDst, xSrc, ySrc, xDst, yDst, width, height );
1537 X11DRV_CoerceDIBSection( dcDst, DIB_Status_GdiMod, FALSE );
1538 X11DRV_CoerceDIBSection( dcSrc, DIB_Status_GdiMod, FALSE );
1540 result = BITBLT_InternalStretchBlt( dcDst, xDst, yDst, width, height,
1541 dcSrc, xSrc, ySrc, width, height, rop );
1544 X11DRV_UnlockDIBSection( dcSrc, FALSE );
1545 X11DRV_UnlockDIBSection( dcDst, TRUE );
1551 /***********************************************************************
1554 BOOL X11DRV_StretchBlt( DC *dcDst, INT xDst, INT yDst,
1555 INT widthDst, INT heightDst,
1556 DC *dcSrc, INT xSrc, INT ySrc,
1557 INT widthSrc, INT heightSrc, DWORD rop )
1561 X11DRV_LockDIBSection( dcDst, DIB_Status_GdiMod, FALSE );
1562 X11DRV_LockDIBSection( dcSrc, DIB_Status_GdiMod, FALSE );
1564 result = BITBLT_InternalStretchBlt( dcDst, xDst, yDst, widthDst, heightDst,
1565 dcSrc, xSrc, ySrc, widthSrc, heightSrc, rop );
1567 X11DRV_UnlockDIBSection( dcSrc, FALSE );
1568 X11DRV_UnlockDIBSection( dcDst, TRUE );