2 * GDI bit-blit operations
4 * Copyright 1993, 1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <X11/Intrinsic.h>
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
42 #define DST 0 /* Destination drawable */
43 #define SRC 1 /* Source drawable */
44 #define TMP 2 /* Temporary drawable */
45 #define PAT 3 /* Pattern (brush) in destination DC */
47 #define OP(src,dst,rop) (OP_ARGS(src,dst) << 4 | (rop))
48 #define OP_ARGS(src,dst) (((src) << 2) | (dst))
50 #define OP_SRC(opcode) ((opcode) >> 6)
51 #define OP_DST(opcode) (((opcode) >> 4) & 3)
52 #define OP_SRCDST(opcode) ((opcode) >> 4)
53 #define OP_ROP(opcode) ((opcode) & 0x0f)
55 #define MAX_OP_LEN 6 /* Longest opcode + 1 for the terminating 0 */
57 #define SWAP_INT32(i1,i2) \
58 do { INT __t = *(i1); *(i1) = *(i2); *(i2) = __t; } while(0)
60 static const unsigned char BITBLT_Opcodes[256][MAX_OP_LEN] =
62 { OP(PAT,DST,GXclear) }, /* 0x00 0 */
63 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnor) }, /* 0x01 ~(D|(P|S)) */
64 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXand) }, /* 0x02 D&~(P|S) */
65 { OP(PAT,SRC,GXnor) }, /* 0x03 ~(P|S) */
66 { OP(PAT,DST,GXnor), OP(SRC,DST,GXand) }, /* 0x04 S&~(D|P) */
67 { OP(PAT,DST,GXnor) }, /* 0x05 ~(D|P) */
68 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnor), }, /* 0x06 ~(P|~(D^S)) */
69 { OP(SRC,DST,GXand), OP(PAT,DST,GXnor) }, /* 0x07 ~(P|(D&S)) */
70 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXand) },/* 0x08 S&D&~P */
71 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnor) }, /* 0x09 ~(P|(D^S)) */
72 { OP(PAT,DST,GXandInverted) }, /* 0x0a D&~P */
73 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXnor) }, /* 0x0b ~(P|(S&~D)) */
74 { OP(PAT,SRC,GXandInverted) }, /* 0x0c S&~P */
75 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXnor) },/* 0x0d ~(P|(D&~S)) */
76 { OP(SRC,DST,GXnor), OP(PAT,DST,GXnor) }, /* 0x0e ~(P|~(D|S)) */
77 { OP(PAT,DST,GXcopyInverted) }, /* 0x0f ~P */
78 { OP(SRC,DST,GXnor), OP(PAT,DST,GXand) }, /* 0x10 P&~(S|D) */
79 { OP(SRC,DST,GXnor) }, /* 0x11 ~(D|S) */
80 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnor) }, /* 0x12 ~(S|~(D^P)) */
81 { OP(PAT,DST,GXand), OP(SRC,DST,GXnor) }, /* 0x13 ~(S|(D&P)) */
82 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnor) }, /* 0x14 ~(D|~(P^S)) */
83 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnor) }, /* 0x15 ~(D|(P&S)) */
84 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
85 OP(TMP,DST,GXand), OP(SRC,DST,GXxor),
86 OP(PAT,DST,GXxor) }, /* 0x16 P^S^(D&~(P&S) */
87 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
88 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
89 OP(TMP,DST,GXequiv) }, /* 0x17 ~S^((S^P)&(S^D))*/
90 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
91 OP(SRC,DST,GXand) }, /* 0x18 (S^P)&(D^P) */
92 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
93 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x19 ~S^(D&~(P&S)) */
94 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
95 OP(PAT,DST,GXxor) }, /* 0x1a P^(D|(S&P)) */
96 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXxor),
97 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x1b ~S^(D&(P^S)) */
98 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
99 OP(PAT,DST,GXxor) }, /* 0x1c P^(S|(D&P)) */
100 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
101 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x1d ~D^(S&(D^P)) */
102 { OP(SRC,DST,GXor), OP(PAT,DST,GXxor) }, /* 0x1e P^(D|S) */
103 { OP(SRC,DST,GXor), OP(PAT,DST,GXnand) }, /* 0x1f ~(P&(D|S)) */
104 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXand) }, /* 0x20 D&(P&~S) */
105 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnor) }, /* 0x21 ~(S|(D^P)) */
106 { OP(SRC,DST,GXandInverted) }, /* 0x22 ~S&D */
107 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x23 ~(S|(P&~D)) */
108 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
109 OP(SRC,DST,GXand) }, /* 0x24 (S^P)&(S^D) */
110 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand),
111 OP(PAT,DST,GXequiv) }, /* 0x25 ~P^(D&~(S&P)) */
112 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
113 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x26 S^(D|(S&P)) */
114 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXequiv),
115 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x27 S^(D|~(P^S)) */
116 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand) }, /* 0x28 D&(P^S) */
117 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
118 OP(TMP,DST,GXor), OP(SRC,DST,GXxor),
119 OP(PAT,DST,GXequiv) }, /* 0x29 ~P^S^(D|(P&S)) */
120 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand) }, /* 0x2a D&~(P&S) */
121 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
122 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
123 OP(TMP,DST,GXequiv) }, /* 0x2b ~S^((P^S)&(P^D))*/
124 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
125 OP(SRC,DST,GXxor) }, /* 0x2c S^(P&(S|D)) */
126 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXxor) }, /* 0x2d P^(S|~D) */
127 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
128 OP(PAT,DST,GXxor) }, /* 0x2e P^(S|(D^P)) */
129 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXnand) }, /* 0x2f ~(P&(S|~D)) */
130 { OP(PAT,SRC,GXandReverse) }, /* 0x30 P&~S */
131 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXnor) },/* 0x31 ~(S|(D&~P)) */
132 { OP(SRC,DST,GXor), OP(PAT,DST,GXor),
133 OP(SRC,DST,GXxor) }, /* 0x32 S^(D|P|S) */
134 { OP(SRC,DST,GXcopyInverted) }, /* 0x33 ~S */
135 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
136 OP(SRC,DST,GXxor) }, /* 0x34 S^(P|(D&S)) */
137 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor),
138 OP(SRC,DST,GXxor) }, /* 0x35 S^(P|~(D^S)) */
139 { OP(PAT,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x36 S^(D|P) */
140 { OP(PAT,DST,GXor), OP(SRC,DST,GXnand) }, /* 0x37 ~(S&(D|P)) */
141 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
142 OP(PAT,DST,GXxor) }, /* 0x38 P^(S&(D|P)) */
143 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x39 S^(P|~D) */
144 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
145 OP(SRC,DST,GXxor) }, /* 0x3a S^(P|(D^S)) */
146 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x3b ~(S&(P|~D)) */
147 { OP(PAT,SRC,GXxor) }, /* 0x3c P^S */
148 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
149 OP(SRC,DST,GXxor) }, /* 0x3d S^(P|~(D|S)) */
150 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
151 OP(SRC,DST,GXxor) }, /* 0x3e S^(P|(D&~S)) */
152 { OP(PAT,SRC,GXnand) }, /* 0x3f ~(P&S) */
153 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXand) }, /* 0x40 P&S&~D */
154 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnor) }, /* 0x41 ~(D|(P^S)) */
155 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
156 OP(SRC,DST,GXand) }, /* 0x42 (S^D)&(P^D) */
157 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
158 OP(SRC,DST,GXequiv) }, /* 0x43 ~S^(P&~(D&S)) */
159 { OP(SRC,DST,GXandReverse) }, /* 0x44 S&~D */
160 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x45 ~(D|(P&~S)) */
161 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
162 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x46 D^(S|(P&D)) */
163 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
164 OP(PAT,DST,GXequiv) }, /* 0x47 ~P^(S&(D^P)) */
165 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand) }, /* 0x48 S&(P^D) */
166 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
167 OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
168 OP(PAT,DST,GXequiv) }, /* 0x49 ~P^D^(S|(P&D)) */
169 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
170 OP(SRC,DST,GXxor) }, /* 0x4a D^(P&(S|D)) */
171 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXxor) }, /* 0x4b P^(D|~S) */
172 { OP(PAT,DST,GXnand), OP(SRC,DST,GXand) }, /* 0x4c S&~(D&P) */
173 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
174 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
175 OP(TMP,DST,GXequiv) }, /* 0x4d ~S^((S^P)|(S^D))*/
176 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
177 OP(PAT,DST,GXxor) }, /* 0x4e P^(D|(S^P)) */
178 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXnand) },/* 0x4f ~(P&(D|~S)) */
179 { OP(PAT,DST,GXandReverse) }, /* 0x50 P&~D */
180 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXnor) },/* 0x51 ~(D|(S&~P)) */
181 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
182 OP(SRC,DST,GXxor) }, /* 0x52 D^(P|(S&D)) */
183 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
184 OP(SRC,DST,GXequiv) }, /* 0x53 ~S^(P&(D^S)) */
185 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXnor) }, /* 0x54 ~(D|~(P|S)) */
186 { OP(PAT,DST,GXinvert) }, /* 0x55 ~D */
187 { OP(PAT,SRC,GXor), OP(SRC,DST,GXxor) }, /* 0x56 D^(P|S) */
188 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnand) }, /* 0x57 ~(D&(P|S)) */
189 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
190 OP(PAT,DST,GXxor) }, /* 0x58 P^(D&(P|S)) */
191 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x59 D^(P|~S) */
192 { OP(PAT,DST,GXxor) }, /* 0x5a D^P */
193 { OP(DST,SRC,GXnor), OP(PAT,SRC,GXor),
194 OP(SRC,DST,GXxor) }, /* 0x5b D^(P|~(S|D)) */
195 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
196 OP(SRC,DST,GXxor) }, /* 0x5c D^(P|(S^D)) */
197 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x5d ~(D&(P|~S)) */
198 { OP(DST,SRC,GXandInverted), OP(PAT,SRC,GXor),
199 OP(SRC,DST,GXxor) }, /* 0x5e D^(P|(S&~D)) */
200 { OP(PAT,DST,GXnand) }, /* 0x5f ~(D&P) */
201 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand) }, /* 0x60 P&(D^S) */
202 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
203 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
204 OP(TMP,DST,GXequiv) }, /* 0x61 ~D^S^(P|(D&S)) */
205 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
206 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x62 D^(S&(P|D)) */
207 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x63 S^(D|~P) */
208 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
209 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x64 S^(D&(P|S)) */
210 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x65 D^(S|~P) */
211 { OP(SRC,DST,GXxor) }, /* 0x66 S^D */
212 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
213 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x67 S^(D|~(S|P) */
214 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnor),
215 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
216 OP(TMP,DST,GXequiv) }, /* 0x68 ~D^S^(P|~(D|S))*/
217 { OP(SRC,DST,GXxor), OP(PAT,DST,GXequiv) }, /* 0x69 ~P^(D^S) */
218 { OP(PAT,SRC,GXand), OP(SRC,DST,GXxor) }, /* 0x6a D^(P&S) */
219 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
220 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
221 OP(PAT,DST,GXequiv) }, /* 0x6b ~P^S^(D&(P|S)) */
222 { OP(PAT,DST,GXand), OP(SRC,DST,GXxor) }, /* 0x6c S^(D&P) */
223 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
224 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
225 OP(PAT,DST,GXequiv) }, /* 0x6d ~P^D^(S&(P|D)) */
226 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
227 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x6e S^(D&(P|~S)) */
228 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnand) }, /* 0x6f ~(P&~(S^D)) */
229 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand) }, /* 0x70 P&~(D&S) */
230 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
231 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
232 OP(TMP,DST,GXequiv) }, /* 0x71 ~S^((S^D)&(P^D))*/
233 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
234 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x72 S^(D|(P^S)) */
235 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXnand) },/* 0x73 ~(S&(D|~P)) */
236 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
237 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x74 D^(S|(P^D)) */
238 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXnand) },/* 0x75 ~(D&(S|~P)) */
239 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
240 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x76 S^(D|(P&~S)) */
241 { OP(SRC,DST,GXnand) }, /* 0x77 ~(S&D) */
242 { OP(SRC,DST,GXand), OP(PAT,DST,GXxor) }, /* 0x78 P^(D&S) */
243 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
244 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
245 OP(TMP,DST,GXequiv) }, /* 0x79 ~D^S^(P&(D|S)) */
246 { OP(DST,SRC,GXorInverted), OP(PAT,SRC,GXand),
247 OP(SRC,DST,GXxor) }, /* 0x7a D^(P&(S|~D)) */
248 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7b ~(S&~(D^P)) */
249 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
250 OP(SRC,DST,GXxor) }, /* 0x7c S^(P&(D|~S)) */
251 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7d ~(D&~(P^S)) */
252 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
253 OP(SRC,DST,GXor) }, /* 0x7e (S^P)|(S^D) */
254 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnand) }, /* 0x7f ~(D&P&S) */
255 { OP(PAT,SRC,GXand), OP(SRC,DST,GXand) }, /* 0x80 D&P&S */
256 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
257 OP(SRC,DST,GXnor) }, /* 0x81 ~((S^P)|(S^D)) */
258 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXand) }, /* 0x82 D&~(P^S) */
259 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
260 OP(SRC,DST,GXequiv) }, /* 0x83 ~S^(P&(D|~S)) */
261 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXand) }, /* 0x84 S&~(D^P) */
262 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand),
263 OP(PAT,DST,GXequiv) }, /* 0x85 ~P^(D&(S|~P)) */
264 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
265 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
266 OP(TMP,DST,GXxor) }, /* 0x86 D^S^(P&(D|S)) */
267 { OP(SRC,DST,GXand), OP(PAT,DST,GXequiv) }, /* 0x87 ~P^(D&S) */
268 { OP(SRC,DST,GXand) }, /* 0x88 S&D */
269 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
270 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x89 ~S^(D|(P&~S)) */
271 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8a D&(S|~P) */
272 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
273 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8b ~D^(S|(P^D)) */
274 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8c S&(D|~P) */
275 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
276 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8d ~S^(D|(P^S)) */
277 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
278 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
279 OP(TMP,DST,GXxor) }, /* 0x8e S^((S^D)&(P^D))*/
280 { OP(SRC,DST,GXnand), OP(PAT,DST,GXnand) }, /* 0x8f ~(P&~(D&S)) */
281 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXand) }, /* 0x90 P&~(D^S) */
282 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
283 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x91 ~S^(D&(P|~S)) */
284 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
285 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
286 OP(TMP,DST,GXxor) }, /* 0x92 D^P^(S&(D|P)) */
287 { OP(PAT,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x93 ~S^(P&D) */
288 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
289 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
290 OP(TMP,DST,GXxor) }, /* 0x94 S^P^(D&(P|S)) */
291 { OP(PAT,SRC,GXand), OP(SRC,DST,GXequiv) }, /* 0x95 ~D^(P&S) */
292 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXxor) }, /* 0x96 D^P^S */
293 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
294 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
295 OP(TMP,DST,GXxor) }, /* 0x97 S^P^(D|~(P|S)) */
296 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
297 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x98 ~S^(D|~(P|S)) */
298 { OP(SRC,DST,GXequiv) }, /* 0x99 ~S^D */
299 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9a D^(P&~S) */
300 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
301 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9b ~S^(D&(P|S)) */
302 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9c S^(P&~D) */
303 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
304 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9d ~D^(S&(P|D)) */
305 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
306 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
307 OP(TMP,DST,GXxor) }, /* 0x9e D^S^(P|(D&S)) */
308 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnand) }, /* 0x9f ~(P&(D^S)) */
309 { OP(PAT,DST,GXand) }, /* 0xa0 D&P */
310 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor),
311 OP(PAT,DST,GXequiv) }, /* 0xa1 ~P^(D|(S&~P)) */
312 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXand) }, /* 0xa2 D&(P|~S) */
313 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
314 OP(SRC,DST,GXequiv) }, /* 0xa3 ~D^(P|(S^D)) */
315 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor),
316 OP(PAT,DST,GXequiv) }, /* 0xa4 ~P^(D|~(S|P)) */
317 { OP(PAT,DST,GXequiv) }, /* 0xa5 ~P^D */
318 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXxor) },/* 0xa6 D^(S&~P) */
319 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
320 OP(PAT,DST,GXequiv) }, /* 0xa7 ~P^(D&(S|P)) */
321 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand) }, /* 0xa8 D&(P|S) */
322 { OP(PAT,SRC,GXor), OP(SRC,DST,GXequiv) }, /* 0xa9 ~D^(P|S) */
323 { OP(SRC,DST,GXnoop) }, /* 0xaa D */
324 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor) }, /* 0xab D|~(P|S) */
325 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
326 OP(SRC,DST,GXxor) }, /* 0xac S^(P&(D^S)) */
327 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
328 OP(SRC,DST,GXequiv) }, /* 0xad ~D^(P|(S&D)) */
329 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor) }, /* 0xae D|(S&~P) */
330 { OP(PAT,DST,GXorInverted) }, /* 0xaf D|~P */
331 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand) }, /* 0xb0 P&(D|~S) */
332 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
333 OP(PAT,DST,GXequiv) }, /* 0xb1 ~P^(D|(S^P)) */
334 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
335 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
336 OP(TMP,DST,GXxor) }, /* 0xb2 S^((S^P)|(S^D))*/
337 { OP(PAT,DST,GXnand), OP(SRC,DST,GXnand) }, /* 0xb3 ~(S&~(D&P)) */
338 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXxor) }, /* 0xb4 P^(S&~D) */
339 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
340 OP(SRC,DST,GXequiv) }, /* 0xb5 ~D^(P&(S|D)) */
341 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
342 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
343 OP(TMP,DST,GXxor) }, /* 0xb6 D^P^(S|(D&P)) */
344 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnand) }, /* 0xb7 ~(S&(D^P)) */
345 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
346 OP(PAT,DST,GXxor) }, /* 0xb8 P^(S&(D^P)) */
347 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
348 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xb9 ~D^(S|(P&D)) */
349 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXor) }, /* 0xba D|(P&~S) */
350 { OP(SRC,DST,GXorInverted) }, /* 0xbb ~S|D */
351 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
352 OP(SRC,DST,GXxor) }, /* 0xbc S^(P&~(D&S)) */
353 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
354 OP(SRC,DST,GXnand) }, /* 0xbd ~((S^D)&(P^D)) */
355 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor) }, /* 0xbe D|(P^S) */
356 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXor) }, /* 0xbf D|~(P&S) */
357 { OP(PAT,SRC,GXand) }, /* 0xc0 P&S */
358 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
359 OP(SRC,DST,GXequiv) }, /* 0xc1 ~S^(P|(D&~S)) */
360 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
361 OP(SRC,DST,GXequiv) }, /* 0xc2 ~S^(P|~(D|S)) */
362 { OP(PAT,SRC,GXequiv) }, /* 0xc3 ~P^S */
363 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXand) }, /* 0xc4 S&(P|~D) */
364 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
365 OP(SRC,DST,GXequiv) }, /* 0xc5 ~S^(P|(D^S)) */
366 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXxor) },/* 0xc6 S^(D&~P) */
367 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
368 OP(PAT,DST,GXequiv) }, /* 0xc7 ~P^(S&(D|P)) */
369 { OP(PAT,DST,GXor), OP(SRC,DST,GXand) }, /* 0xc8 S&(D|P) */
370 { OP(PAT,DST,GXor), OP(SRC,DST,GXequiv) }, /* 0xc9 ~S^(P|D) */
371 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXand),
372 OP(SRC,DST,GXxor) }, /* 0xca D^(P&(S^D)) */
373 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
374 OP(SRC,DST,GXequiv) }, /* 0xcb ~S^(P|(D&S)) */
375 { OP(SRC,DST,GXcopy) }, /* 0xcc S */
376 { OP(PAT,DST,GXnor), OP(SRC,DST,GXor) }, /* 0xcd S|~(D|P) */
377 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXor) }, /* 0xce S|(D&~P) */
378 { OP(PAT,SRC,GXorInverted) }, /* 0xcf S|~P */
379 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXand) }, /* 0xd0 P&(S|~D) */
380 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
381 OP(PAT,DST,GXequiv) }, /* 0xd1 ~P^(S|(D^P)) */
382 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXxor) },/* 0xd2 P^(D&~S) */
383 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
384 OP(SRC,DST,GXequiv) }, /* 0xd3 ~S^(P&(D|S)) */
385 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
386 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
387 OP(TMP,DST,GXxor) }, /* 0xd4 S^((S^P)&(D^P))*/
388 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXnand) }, /* 0xd5 ~(D&~(P&S)) */
389 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
390 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
391 OP(TMP,DST,GXxor) }, /* 0xd6 S^P^(D|(P&S)) */
392 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnand) }, /* 0xd7 ~(D&(P^S)) */
393 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
394 OP(PAT,DST,GXxor) }, /* 0xd8 P^(D&(S^P)) */
395 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
396 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xd9 ~S^(D|(P&S)) */
397 { OP(DST,SRC,GXnand), OP(PAT,SRC,GXand),
398 OP(SRC,DST,GXxor) }, /* 0xda D^(P&~(S&D)) */
399 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
400 OP(SRC,DST,GXnand) }, /* 0xdb ~((S^P)&(S^D)) */
401 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXor) }, /* 0xdc S|(P&~D) */
402 { OP(SRC,DST,GXorReverse) }, /* 0xdd S|~D */
403 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor) }, /* 0xde S|(D^P) */
404 { OP(PAT,DST,GXnand), OP(SRC,DST,GXor) }, /* 0xdf S|~(D&P) */
405 { OP(SRC,DST,GXor), OP(PAT,DST,GXand) }, /* 0xe0 P&(D|S) */
406 { OP(SRC,DST,GXor), OP(PAT,DST,GXequiv) }, /* 0xe1 ~P^(D|S) */
407 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
408 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe2 D^(S&(P^D)) */
409 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
410 OP(PAT,DST,GXequiv) }, /* 0xe3 ~P^(S|(D&P)) */
411 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
412 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe4 S^(D&(P^S)) */
413 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
414 OP(PAT,DST,GXequiv) }, /* 0xe5 ~P^(D|(S&P)) */
415 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
416 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe6 S^(D&~(P&S)) */
417 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
418 OP(SRC,DST,GXnand) }, /* 0xe7 ~((S^P)&(D^P)) */
419 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
420 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
421 OP(TMP,DST,GXxor) }, /* 0xe8 S^((S^P)&(S^D))*/
422 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnand),
423 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
424 OP(TMP,DST,GXequiv) }, /* 0xe9 ~D^S^(P&~(S&D))*/
425 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor) }, /* 0xea D|(P&S) */
426 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXor) }, /* 0xeb D|~(P^S) */
427 { OP(PAT,DST,GXand), OP(SRC,DST,GXor) }, /* 0xec S|(D&P) */
428 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXor) }, /* 0xed S|~(D^P) */
429 { OP(SRC,DST,GXor) }, /* 0xee S|D */
430 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXor) }, /* 0xef S|D|~P */
431 { OP(PAT,DST,GXcopy) }, /* 0xf0 P */
432 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor) }, /* 0xf1 P|~(D|S) */
433 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor) }, /* 0xf2 P|(D&~S) */
434 { OP(PAT,SRC,GXorReverse) }, /* 0xf3 P|~S */
435 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXor) }, /* 0xf4 P|(S&~D) */
436 { OP(PAT,DST,GXorReverse) }, /* 0xf5 P|~D */
437 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor) }, /* 0xf6 P|(D^S) */
438 { OP(SRC,DST,GXnand), OP(PAT,DST,GXor) }, /* 0xf7 P|~(S&D) */
439 { OP(SRC,DST,GXand), OP(PAT,DST,GXor) }, /* 0xf8 P|(D&S) */
440 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor) }, /* 0xf9 P|~(D^S) */
441 { OP(PAT,DST,GXor) }, /* 0xfa D|P */
442 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXor) }, /* 0xfb D|P|~S */
443 { OP(PAT,SRC,GXor) }, /* 0xfc P|S */
444 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXor) }, /* 0xfd P|S|~D */
445 { OP(SRC,DST,GXor), OP(PAT,DST,GXor) }, /* 0xfe P|D|S */
446 { OP(PAT,DST,GXset) } /* 0xff 1 */
450 #ifdef BITBLT_TEST /* Opcodes test */
452 static int do_bitop( int s, int d, int rop )
457 case GXclear: res = 0; break;
458 case GXand: res = s & d; break;
459 case GXandReverse: res = s & ~d; break;
460 case GXcopy: res = s; break;
461 case GXandInverted: res = ~s & d; break;
462 case GXnoop: res = d; break;
463 case GXxor: res = s ^ d; break;
464 case GXor: res = s | d; break;
465 case GXnor: res = ~(s | d); break;
466 case GXequiv: res = ~s ^ d; break;
467 case GXinvert: res = ~d; break;
468 case GXorReverse: res = s | ~d; break;
469 case GXcopyInverted: res = ~s; break;
470 case GXorInverted: res = ~s | d; break;
471 case GXnand: res = ~(s & d); break;
472 case GXset: res = 1; break;
479 int rop, i, res, src, dst, pat, tmp, dstUsed;
482 for (rop = 0; rop < 256; rop++)
485 for (i = 0; i < 8; i++)
490 for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
494 case OP_ARGS(DST,TMP):
495 tmp = do_bitop( dst, tmp, *opcode & 0xf );
497 case OP_ARGS(DST,SRC):
498 src = do_bitop( dst, src, *opcode & 0xf );
500 case OP_ARGS(SRC,TMP):
501 tmp = do_bitop( src, tmp, *opcode & 0xf );
503 case OP_ARGS(SRC,DST):
504 dst = do_bitop( src, dst, *opcode & 0xf );
507 case OP_ARGS(PAT,TMP):
508 tmp = do_bitop( pat, tmp, *opcode & 0xf );
510 case OP_ARGS(PAT,DST):
511 dst = do_bitop( pat, dst, *opcode & 0xf );
514 case OP_ARGS(PAT,SRC):
515 src = do_bitop( pat, src, *opcode & 0xf );
517 case OP_ARGS(TMP,DST):
518 dst = do_bitop( tmp, dst, *opcode & 0xf );
521 case OP_ARGS(TMP,SRC):
522 src = do_bitop( tmp, src, *opcode & 0xf );
525 printf( "Invalid opcode %x\n", *opcode );
528 if (!dstUsed) dst = src;
529 if (dst) res |= 1 << i;
531 if (res != rop) printf( "%02x: ERROR, res=%02x\n", rop, res );
537 #endif /* BITBLT_TEST */
540 /***********************************************************************
543 * Favor correctness or speed?
545 static int perfect_graphics(void)
547 static int perfect = -1;
554 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
556 DWORD type, count = sizeof(buffer);
557 if(!RegQueryValueExA(hkey, "PerfectGraphics", 0, &type, buffer, &count))
560 perfect = (ch == 'y' || ch == 'Y' || ch == 't' || ch == 'T' || ch == '1');
568 /***********************************************************************
571 * Stretch a row of pixels. Helper function for BITBLT_StretchImage.
573 static void BITBLT_StretchRow( int *rowSrc, int *rowDst,
574 INT startDst, INT widthDst,
575 INT xinc, INT xoff, WORD mode )
577 register INT xsrc = xinc * startDst + xoff;
581 case STRETCH_ANDSCANS:
582 for(; widthDst > 0; widthDst--, xsrc += xinc)
583 *rowDst++ &= rowSrc[xsrc >> 16];
585 case STRETCH_ORSCANS:
586 for(; widthDst > 0; widthDst--, xsrc += xinc)
587 *rowDst++ |= rowSrc[xsrc >> 16];
589 case STRETCH_DELETESCANS:
590 for(; widthDst > 0; widthDst--, xsrc += xinc)
591 *rowDst++ = rowSrc[xsrc >> 16];
597 /***********************************************************************
600 * Shrink a row of pixels. Helper function for BITBLT_StretchImage.
602 static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst,
603 INT startSrc, INT widthSrc,
604 INT xinc, INT xoff, WORD mode )
606 register INT xdst = xinc * startSrc + xoff;
610 case STRETCH_ORSCANS:
611 for(; widthSrc > 0; widthSrc--, xdst += xinc)
612 rowDst[xdst >> 16] |= *rowSrc++;
614 case STRETCH_ANDSCANS:
615 for(; widthSrc > 0; widthSrc--, xdst += xinc)
616 rowDst[xdst >> 16] &= *rowSrc++;
618 case STRETCH_DELETESCANS:
619 for(; widthSrc > 0; widthSrc--, xdst += xinc)
620 rowDst[xdst >> 16] = *rowSrc++;
626 /***********************************************************************
629 * Retrieve a row from an image. Helper function for BITBLT_StretchImage.
631 static void BITBLT_GetRow( XImage *image, int *pdata, INT row,
632 INT start, INT width, INT depthDst,
633 int fg, int bg, BOOL swap)
637 assert( (row >= 0) && (row < image->height) );
638 assert( (start >= 0) && (width <= image->width) );
640 pdata += swap ? start+width-1 : start;
641 if (image->depth == depthDst) /* color -> color */
643 if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1))
644 if (swap) for (i = 0; i < width; i++)
645 *pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
646 else for (i = 0; i < width; i++)
647 *pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
649 if (swap) for (i = 0; i < width; i++)
650 *pdata-- = XGetPixel( image, i, row );
651 else for (i = 0; i < width; i++)
652 *pdata++ = XGetPixel( image, i, row );
656 if (image->depth == 1) /* monochrome -> color */
658 if (X11DRV_PALETTE_XPixelToPalette)
660 fg = X11DRV_PALETTE_XPixelToPalette[fg];
661 bg = X11DRV_PALETTE_XPixelToPalette[bg];
663 if (swap) for (i = 0; i < width; i++)
664 *pdata-- = XGetPixel( image, i, row ) ? bg : fg;
665 else for (i = 0; i < width; i++)
666 *pdata++ = XGetPixel( image, i, row ) ? bg : fg;
668 else /* color -> monochrome */
670 if (swap) for (i = 0; i < width; i++)
671 *pdata-- = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
672 else for (i = 0; i < width; i++)
673 *pdata++ = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
679 /***********************************************************************
680 * BITBLT_StretchImage
682 * Stretch an X image.
683 * FIXME: does not work for full 32-bit coordinates.
685 static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage,
686 INT widthSrc, INT heightSrc,
687 INT widthDst, INT heightDst,
688 RECT *visRectSrc, RECT *visRectDst,
689 int foreground, int background, WORD mode )
691 int *rowSrc, *rowDst, *pixel;
693 INT xinc, xoff, yinc, ysrc, ydst;
695 BOOL hstretch, vstretch, hswap, vswap;
697 hswap = ((int)widthSrc * widthDst) < 0;
698 vswap = ((int)heightSrc * heightDst) < 0;
699 widthSrc = abs(widthSrc);
700 heightSrc = abs(heightSrc);
701 widthDst = abs(widthDst);
702 heightDst = abs(heightDst);
704 if (!(rowSrc = (int *)HeapAlloc( GetProcessHeap(), 0,
705 (widthSrc+widthDst)*sizeof(int) ))) return;
706 rowDst = rowSrc + widthSrc;
708 /* When stretching, all modes are the same, and DELETESCANS is faster */
709 if ((widthSrc < widthDst) && (heightSrc < heightDst))
710 mode = STRETCH_DELETESCANS;
712 if (mode != STRETCH_DELETESCANS)
713 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
714 widthDst*sizeof(int) );
716 hstretch = (widthSrc < widthDst);
717 vstretch = (heightSrc < heightDst);
721 xinc = ((int)widthSrc << 16) / widthDst;
722 xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
726 xinc = ((int)widthDst << 16) / widthSrc;
727 xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
732 yinc = ((int)heightSrc << 16) / heightDst;
733 ydst = visRectDst->top;
736 ysrc = yinc * (heightDst - ydst - 1);
742 for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
744 if (((ysrc >> 16) < visRectSrc->top) ||
745 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
747 /* Retrieve a source row */
748 BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
749 hswap ? widthSrc - visRectSrc->right
751 visRectSrc->right - visRectSrc->left,
752 dstImage->depth, foreground, background, hswap );
754 /* Stretch or shrink it */
756 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
757 visRectDst->right - visRectDst->left,
759 else BITBLT_ShrinkRow( rowSrc, rowDst,
760 hswap ? widthSrc - visRectSrc->right
762 visRectSrc->right - visRectSrc->left,
765 /* Store the destination row */
766 pixel = rowDst + visRectDst->right - 1;
767 y = ydst - visRectDst->top;
768 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
769 XPutPixel( dstImage, x, y, *pixel-- );
770 if (mode != STRETCH_DELETESCANS)
771 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
772 widthDst*sizeof(int) );
774 /* Make copies of the destination row */
776 pdata = dstImage->data + dstImage->bytes_per_line * y;
777 while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
778 (ydst < visRectDst->bottom-1))
780 memcpy( pdata + dstImage->bytes_per_line, pdata,
781 dstImage->bytes_per_line );
782 pdata += dstImage->bytes_per_line;
790 yinc = ((int)heightDst << 16) / heightSrc;
791 ysrc = visRectSrc->top;
792 ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
795 ydst += yinc * (heightSrc - ysrc - 1);
801 for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
803 if (((ydst >> 16) < visRectDst->top) ||
804 ((ydst >> 16) >= visRectDst->bottom)) continue;
806 /* Retrieve a source row */
807 BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
808 hswap ? widthSrc - visRectSrc->right
810 visRectSrc->right - visRectSrc->left,
811 dstImage->depth, foreground, background, hswap );
813 /* Stretch or shrink it */
815 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
816 visRectDst->right - visRectDst->left,
818 else BITBLT_ShrinkRow( rowSrc, rowDst,
819 hswap ? widthSrc - visRectSrc->right
821 visRectSrc->right - visRectSrc->left,
824 /* Merge several source rows into the destination */
825 if (mode == STRETCH_DELETESCANS)
827 /* Simply skip the overlapping rows */
828 while (((ydst + yinc) >> 16 == ydst >> 16) &&
829 (ysrc < visRectSrc->bottom-1))
835 else if (((ydst + yinc) >> 16 == ydst >> 16) &&
836 (ysrc < visRectSrc->bottom-1))
837 continue; /* Restart loop for next overlapping row */
839 /* Store the destination row */
840 pixel = rowDst + visRectDst->right - 1;
841 y = (ydst >> 16) - visRectDst->top;
842 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
843 XPutPixel( dstImage, x, y, *pixel-- );
844 if (mode != STRETCH_DELETESCANS)
845 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
846 widthDst*sizeof(int) );
849 HeapFree( GetProcessHeap(), 0, rowSrc );
853 /***********************************************************************
854 * BITBLT_GetSrcAreaStretch
856 * Retrieve an area from the source DC, stretching and mapping all the
857 * pixels to Windows colors.
859 static int BITBLT_GetSrcAreaStretch( DC *dcSrc, DC *dcDst,
860 Pixmap pixmap, GC gc,
862 INT widthSrc, INT heightSrc,
864 INT widthDst, INT heightDst,
865 RECT *visRectSrc, RECT *visRectDst )
867 XImage *imageSrc, *imageDst;
868 X11DRV_PDEVICE *physDevSrc = (X11DRV_PDEVICE *)dcSrc->physDev;
869 X11DRV_PDEVICE *physDevDst = (X11DRV_PDEVICE *)dcDst->physDev;
871 RECT rectSrc = *visRectSrc;
872 RECT rectDst = *visRectDst;
874 if (widthSrc < 0) xSrc += widthSrc;
875 if (widthDst < 0) xDst += widthDst;
876 if (heightSrc < 0) ySrc += heightSrc;
877 if (heightDst < 0) yDst += heightDst;
878 rectSrc.left -= xSrc;
879 rectSrc.right -= xSrc;
881 rectSrc.bottom -= ySrc;
882 rectDst.left -= xDst;
883 rectDst.right -= xDst;
885 rectDst.bottom -= yDst;
887 /* FIXME: avoid BadMatch errors */
888 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
889 visRectSrc->left, visRectSrc->top,
890 visRectSrc->right - visRectSrc->left,
891 visRectSrc->bottom - visRectSrc->top,
892 AllPlanes, ZPixmap );
893 imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
894 rectDst.bottom - rectDst.top, dcDst->bitsPerPixel );
895 BITBLT_StretchImage( imageSrc, imageDst, widthSrc, heightSrc,
896 widthDst, heightDst, &rectSrc, &rectDst,
897 physDevDst->textPixel, dcDst->bitsPerPixel != 1 ?
898 physDevDst->backgroundPixel :
899 physDevSrc->backgroundPixel,
900 dcDst->stretchBltMode );
901 XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
902 rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
903 XDestroyImage( imageSrc );
904 XDestroyImage( imageDst );
905 return 0; /* no exposure events generated */
909 /***********************************************************************
912 * Retrieve an area from the source DC, mapping all the
913 * pixels to Windows colors.
915 static int BITBLT_GetSrcArea( DC *dcSrc, DC *dcDst, Pixmap pixmap, GC gc,
916 INT xSrc, INT ySrc, RECT *visRectSrc )
918 XImage *imageSrc, *imageDst;
921 INT width = visRectSrc->right - visRectSrc->left;
922 INT height = visRectSrc->bottom - visRectSrc->top;
923 X11DRV_PDEVICE *physDevSrc = (X11DRV_PDEVICE *)dcSrc->physDev;
924 X11DRV_PDEVICE *physDevDst = (X11DRV_PDEVICE *)dcDst->physDev;
926 if (dcSrc->bitsPerPixel == dcDst->bitsPerPixel)
928 if (!X11DRV_PALETTE_XPixelToPalette ||
929 (dcDst->bitsPerPixel == 1)) /* monochrome -> monochrome */
931 if (dcDst->bitsPerPixel == 1)
933 /* MSDN says if StretchBlt must convert a bitmap from monochrome
934 to color or vice versa, the forground and background color of
935 the device context are used. In fact, it also applies to the
936 case when it is converted from mono to mono. */
937 XSetBackground( gdi_display, gc, physDevDst->textPixel );
938 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
939 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
940 visRectSrc->left, visRectSrc->top,
941 width, height, 0, 0, 1);
944 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
945 visRectSrc->left, visRectSrc->top, width, height, 0, 0);
948 else /* color -> color */
950 if (dcSrc->flags & DC_MEMORY)
951 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
952 visRectSrc->left, visRectSrc->top,
953 width, height, AllPlanes, ZPixmap );
956 /* Make sure we don't get a BadMatch error */
957 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
958 visRectSrc->left, visRectSrc->top,
959 width, height, 0, 0);
961 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
962 AllPlanes, ZPixmap );
964 for (y = 0; y < height; y++)
965 for (x = 0; x < width; x++)
966 XPutPixel(imageSrc, x, y,
967 X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
968 XPutImage( gdi_display, pixmap, gc, imageSrc,
969 0, 0, 0, 0, width, height );
970 XDestroyImage( imageSrc );
975 if (dcSrc->bitsPerPixel == 1) /* monochrome -> color */
977 if (X11DRV_PALETTE_XPixelToPalette)
979 XSetBackground( gdi_display, gc,
980 X11DRV_PALETTE_XPixelToPalette[physDevDst->textPixel] );
981 XSetForeground( gdi_display, gc,
982 X11DRV_PALETTE_XPixelToPalette[physDevDst->backgroundPixel]);
986 XSetBackground( gdi_display, gc, physDevDst->textPixel );
987 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
989 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
990 visRectSrc->left, visRectSrc->top,
991 width, height, 0, 0, 1 );
994 else /* color -> monochrome */
996 /* FIXME: avoid BadMatch error */
997 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
998 visRectSrc->left, visRectSrc->top,
999 width, height, AllPlanes, ZPixmap );
1000 imageDst = X11DRV_DIB_CreateXImage( width, height, dcDst->bitsPerPixel );
1001 for (y = 0; y < height; y++)
1002 for (x = 0; x < width; x++)
1003 XPutPixel(imageDst, x, y, (XGetPixel(imageSrc,x,y) ==
1004 physDevSrc->backgroundPixel) );
1005 XPutImage( gdi_display, pixmap, gc, imageDst,
1006 0, 0, 0, 0, width, height );
1007 XDestroyImage( imageSrc );
1008 XDestroyImage( imageDst );
1015 /***********************************************************************
1018 * Retrieve an area from the destination DC, mapping all the
1019 * pixels to Windows colors.
1021 static int BITBLT_GetDstArea(DC *dc, Pixmap pixmap, GC gc, RECT *visRectDst)
1024 INT width = visRectDst->right - visRectDst->left;
1025 INT height = visRectDst->bottom - visRectDst->top;
1026 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1028 if (!X11DRV_PALETTE_XPixelToPalette || (dc->bitsPerPixel == 1) ||
1029 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1031 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1032 visRectDst->left, visRectDst->top, width, height, 0, 0 );
1040 if (dc->flags & DC_MEMORY)
1041 image = XGetImage( gdi_display, physDev->drawable,
1042 visRectDst->left, visRectDst->top,
1043 width, height, AllPlanes, ZPixmap );
1046 /* Make sure we don't get a BadMatch error */
1047 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1048 visRectDst->left, visRectDst->top, width, height, 0, 0);
1050 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1051 AllPlanes, ZPixmap );
1053 for (y = 0; y < height; y++)
1054 for (x = 0; x < width; x++)
1055 XPutPixel( image, x, y,
1056 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1057 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1058 XDestroyImage( image );
1064 /***********************************************************************
1067 * Put an area back into the destination DC, mapping the pixel
1068 * colors to X pixels.
1070 static int BITBLT_PutDstArea(DC *dc, Pixmap pixmap, GC gc, RECT *visRectDst)
1073 INT width = visRectDst->right - visRectDst->left;
1074 INT height = visRectDst->bottom - visRectDst->top;
1075 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1077 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1079 if (!X11DRV_PALETTE_PaletteToXPixel || (dc->bitsPerPixel == 1) ||
1080 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1082 XCopyArea( gdi_display, pixmap, physDev->drawable, gc, 0, 0,
1083 width, height, visRectDst->left, visRectDst->top );
1089 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1090 AllPlanes, ZPixmap );
1091 for (y = 0; y < height; y++)
1092 for (x = 0; x < width; x++)
1094 XPutPixel( image, x, y,
1095 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1097 XPutImage( gdi_display, physDev->drawable, gc, image, 0, 0,
1098 visRectDst->left, visRectDst->top, width, height );
1099 XDestroyImage( image );
1105 /***********************************************************************
1106 * BITBLT_GetVisRectangles
1108 * Get the source and destination visible rectangles for StretchBlt().
1109 * Return FALSE if one of the rectangles is empty.
1111 static BOOL BITBLT_GetVisRectangles( DC *dcDst, INT xDst, INT yDst,
1112 INT widthDst, INT heightDst,
1113 DC *dcSrc, INT xSrc, INT ySrc,
1114 INT widthSrc, INT heightSrc,
1115 RECT *visRectSrc, RECT *visRectDst )
1117 RECT rect, clipRect;
1119 /* Get the destination visible rectangle */
1123 rect.right = xDst + widthDst;
1124 rect.bottom = yDst + heightDst;
1125 if (widthDst < 0) SWAP_INT32( &rect.left, &rect.right );
1126 if (heightDst < 0) SWAP_INT32( &rect.top, &rect.bottom );
1127 GetRgnBox( dcDst->hGCClipRgn, &clipRect );
1128 if (!IntersectRect( visRectDst, &rect, &clipRect )) return FALSE;
1130 /* Get the source visible rectangle */
1132 if (!dcSrc) return TRUE;
1135 rect.right = xSrc + widthSrc;
1136 rect.bottom = ySrc + heightSrc;
1137 if (widthSrc < 0) SWAP_INT32( &rect.left, &rect.right );
1138 if (heightSrc < 0) SWAP_INT32( &rect.top, &rect.bottom );
1139 /* Apparently the clipping and visible regions are only for output,
1140 so just check against totalExtent here to avoid BadMatch errors */
1141 if (!IntersectRect( visRectSrc, &rect, &dcSrc->totalExtent ))
1144 /* Intersect the rectangles */
1146 if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1148 visRectSrc->left += xDst - xSrc;
1149 visRectSrc->right += xDst - xSrc;
1150 visRectSrc->top += yDst - ySrc;
1151 visRectSrc->bottom += yDst - ySrc;
1152 if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1153 *visRectSrc = *visRectDst = rect;
1154 visRectSrc->left += xSrc - xDst;
1155 visRectSrc->right += xSrc - xDst;
1156 visRectSrc->top += ySrc - yDst;
1157 visRectSrc->bottom += ySrc - yDst;
1159 else /* stretching */
1161 /* Map source rectangle into destination coordinates */
1162 rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1163 rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1164 rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1165 rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
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( visRectDst, &rect, visRectDst )) return FALSE;
1176 /* Map destination rectangle back to source coordinates */
1178 rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1179 rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1180 rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1181 rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1182 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1183 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1185 /* Avoid rounding errors */
1190 if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1196 /***********************************************************************
1197 * BITBLT_InternalStretchBlt
1199 * Implementation of PatBlt(), BitBlt() and StretchBlt().
1201 static BOOL BITBLT_InternalStretchBlt( DC *dcDst, INT xDst, INT yDst,
1202 INT widthDst, INT heightDst,
1203 DC *dcSrc, INT xSrc, INT ySrc,
1204 INT widthSrc, INT heightSrc,
1207 BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1208 RECT visRectDst, visRectSrc;
1211 Pixmap pixmaps[3] = { 0, 0, 0 }; /* pixmaps for DST, SRC, TMP */
1213 X11DRV_PDEVICE *physDevSrc = NULL;
1214 X11DRV_PDEVICE *physDevDst = (X11DRV_PDEVICE *)dcDst->physDev;
1216 /* compensate for off-by-one shifting for negative widths and heights */
1226 if(dcSrc) physDevSrc = (X11DRV_PDEVICE *)dcSrc->physDev;
1227 usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1228 useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1229 useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1230 if (!dcSrc && useSrc) return FALSE;
1232 /* Map the coordinates to device coords */
1234 xDst = dcDst->DCOrgX + XLPTODP( dcDst, xDst );
1235 yDst = dcDst->DCOrgY + YLPTODP( dcDst, yDst );
1237 /* Here we have to round to integers, not truncate */
1238 widthDst = MulDiv(widthDst, dcDst->vportExtX, dcDst->wndExtX);
1239 heightDst = MulDiv(heightDst, dcDst->vportExtY, dcDst->wndExtY);
1241 TRACE(" vportdst=%d,%d-%d,%d wnddst=%d,%d-%d,%d\n",
1242 dcDst->vportOrgX, dcDst->vportOrgY,
1243 dcDst->vportExtX, dcDst->vportExtY,
1244 dcDst->wndOrgX, dcDst->wndOrgY,
1245 dcDst->wndExtX, dcDst->wndExtY );
1246 TRACE(" rectdst=%d,%d-%d,%d orgdst=%d,%d\n",
1247 xDst, yDst, widthDst, heightDst,
1248 dcDst->DCOrgX, dcDst->DCOrgY );
1252 xSrc = dcSrc->DCOrgX + XLPTODP( dcSrc, xSrc );
1253 ySrc = dcSrc->DCOrgY + YLPTODP( dcSrc, ySrc );
1254 widthSrc = widthSrc * dcSrc->vportExtX / dcSrc->wndExtX;
1255 heightSrc = heightSrc * dcSrc->vportExtY / dcSrc->wndExtY;
1256 fStretch = (widthSrc != widthDst) || (heightSrc != heightDst);
1257 TRACE(" vportsrc=%d,%d-%d,%d wndsrc=%d,%d-%d,%d\n",
1258 dcSrc->vportOrgX, dcSrc->vportOrgY,
1259 dcSrc->vportExtX, dcSrc->vportExtY,
1260 dcSrc->wndOrgX, dcSrc->wndOrgY,
1261 dcSrc->wndExtX, dcSrc->wndExtY );
1262 TRACE(" rectsrc=%d,%d-%d,%d orgsrc=%d,%d\n",
1263 xSrc, ySrc, widthSrc, heightSrc,
1264 dcSrc->DCOrgX, dcSrc->DCOrgY );
1265 if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1266 dcSrc, xSrc, ySrc, widthSrc, heightSrc,
1267 &visRectSrc, &visRectDst ))
1269 TRACE(" vissrc=%d,%d-%d,%d visdst=%d,%d-%d,%d\n",
1270 visRectSrc.left, visRectSrc.top,
1271 visRectSrc.right, visRectSrc.bottom,
1272 visRectDst.left, visRectDst.top,
1273 visRectDst.right, visRectDst.bottom );
1278 if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1279 NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1281 TRACE(" vissrc=none visdst=%d,%d-%d,%d\n",
1282 visRectDst.left, visRectDst.top,
1283 visRectDst.right, visRectDst.bottom );
1286 width = visRectDst.right - visRectDst.left;
1287 height = visRectDst.bottom - visRectDst.top;
1289 if (!fStretch) switch(rop) /* A few optimisations */
1291 case BLACKNESS: /* 0x00 */
1293 if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1294 XSetFunction( gdi_display, physDevDst->gc, GXclear );
1297 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1298 XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1299 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1301 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1302 visRectDst.left, visRectDst.top, width, height );
1303 wine_tsx11_unlock();
1306 case DSTINVERT: /* 0x55 */
1307 if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel ||
1308 !perfect_graphics())
1311 XSetFunction( gdi_display, physDevDst->gc, GXinvert );
1313 if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1314 XSetFunction( gdi_display, physDevDst->gc, GXinvert);
1317 /* Xor is much better when we do not have full colormap. */
1318 /* Using white^black ensures that we invert at least black */
1320 Pixel xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1321 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1322 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1323 XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1324 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1326 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1327 visRectDst.left, visRectDst.top, width, height );
1328 wine_tsx11_unlock();
1333 case PATINVERT: /* 0x5a */
1334 if (perfect_graphics()) break;
1335 if (X11DRV_SetupGCForBrush( dcDst ))
1338 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1339 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1340 visRectDst.left, visRectDst.top, width, height );
1341 wine_tsx11_unlock();
1346 if (perfect_graphics()) break;
1347 if (X11DRV_SetupGCForBrush( dcDst ))
1350 XSetFunction( gdi_display, physDevDst->gc, GXequiv );
1351 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1352 visRectDst.left, visRectDst.top, width, height );
1353 wine_tsx11_unlock();
1357 case SRCCOPY: /* 0xcc */
1358 if (dcSrc->bitsPerPixel == dcDst->bitsPerPixel)
1361 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1362 XCopyArea( gdi_display, physDevSrc->drawable,
1363 physDevDst->drawable, physDevDst->gc,
1364 visRectSrc.left, visRectSrc.top,
1365 width, height, visRectDst.left, visRectDst.top );
1366 physDevDst->exposures++;
1367 wine_tsx11_unlock();
1370 if (dcSrc->bitsPerPixel == 1)
1373 XSetBackground( gdi_display, physDevDst->gc, physDevDst->textPixel );
1374 XSetForeground( gdi_display, physDevDst->gc, physDevDst->backgroundPixel );
1375 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1376 XCopyPlane( gdi_display, physDevSrc->drawable,
1377 physDevDst->drawable, physDevDst->gc,
1378 visRectSrc.left, visRectSrc.top,
1379 width, height, visRectDst.left, visRectDst.top, 1 );
1380 physDevDst->exposures++;
1381 wine_tsx11_unlock();
1386 case PATCOPY: /* 0xf0 */
1387 if (!X11DRV_SetupGCForBrush( dcDst )) return TRUE;
1389 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1390 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1391 visRectDst.left, visRectDst.top, width, height );
1392 wine_tsx11_unlock();
1395 case WHITENESS: /* 0xff */
1397 if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1398 XSetFunction( gdi_display, physDevDst->gc, GXset );
1401 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1402 XSetForeground( gdi_display, physDevDst->gc,
1403 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1404 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1406 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1407 visRectDst.left, visRectDst.top, width, height );
1408 wine_tsx11_unlock();
1414 tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1415 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1416 XSetGraphicsExposures( gdi_display, tmpGC, False );
1417 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1418 dcDst->bitsPerPixel );
1421 pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1422 dcDst->bitsPerPixel );
1424 BITBLT_GetSrcAreaStretch( dcSrc, dcDst, pixmaps[SRC], tmpGC,
1425 xSrc, ySrc, widthSrc, heightSrc,
1426 xDst, yDst, widthDst, heightDst,
1427 &visRectSrc, &visRectDst );
1429 BITBLT_GetSrcArea( dcSrc, dcDst, pixmaps[SRC], tmpGC,
1430 xSrc, ySrc, &visRectSrc );
1433 if (useDst) BITBLT_GetDstArea( dcDst, pixmaps[DST], tmpGC, &visRectDst );
1434 if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( dcDst, tmpGC, TRUE );
1435 else fNullBrush = FALSE;
1438 for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1440 if (OP_DST(*opcode) == DST) destUsed = TRUE;
1441 XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1442 switch(OP_SRCDST(*opcode))
1444 case OP_ARGS(DST,TMP):
1445 case OP_ARGS(SRC,TMP):
1447 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1449 dcDst->bitsPerPixel );
1451 case OP_ARGS(DST,SRC):
1452 case OP_ARGS(SRC,DST):
1453 case OP_ARGS(TMP,SRC):
1454 case OP_ARGS(TMP,DST):
1455 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1456 pixmaps[OP_DST(*opcode)], tmpGC,
1457 0, 0, width, height, 0, 0 );
1460 case OP_ARGS(PAT,TMP):
1461 if (!pixmaps[TMP] && !fNullBrush)
1462 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1464 dcDst->bitsPerPixel );
1466 case OP_ARGS(PAT,DST):
1467 case OP_ARGS(PAT,SRC):
1469 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1470 tmpGC, 0, 0, width, height );
1474 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1475 physDevDst->exposures += BITBLT_PutDstArea( dcDst, pixmaps[destUsed ? DST : SRC],
1476 physDevDst->gc, &visRectDst );
1477 XFreePixmap( gdi_display, pixmaps[DST] );
1478 if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1479 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1480 XFreeGC( gdi_display, tmpGC );
1481 wine_tsx11_unlock();
1486 /***********************************************************************
1489 BOOL X11DRV_PatBlt( DC *dc, INT left, INT top,
1490 INT width, INT height, DWORD rop )
1494 X11DRV_LockDIBSection( dc, DIB_Status_GdiMod, FALSE );
1495 result = BITBLT_InternalStretchBlt( dc, left, top, width, height, NULL, 0, 0, 0, 0, rop );
1496 X11DRV_UnlockDIBSection( dc, TRUE );
1501 /***********************************************************************
1504 BOOL X11DRV_BitBlt( DC *dcDst, INT xDst, INT yDst,
1505 INT width, INT height, DC *dcSrc,
1506 INT xSrc, INT ySrc, DWORD rop )
1508 BOOL result = FALSE;
1510 RECT visRectDst, visRectSrc;
1512 if (((rop >> 16) & 0x55) == ((rop >> 17) & 0x55)) {
1513 /* FIXME: seems the ROP doesn't include destination;
1514 * now if the destination area include the entire dcDst,
1515 * we can pass TRUE instead of FALSE to CoerceDIBSection(dcDst...),
1516 * which may avoid a copy in some situations */
1518 sDst = X11DRV_LockDIBSection( dcDst, DIB_Status_None, FALSE );
1519 sSrc = X11DRV_LockDIBSection( dcSrc, DIB_Status_None, FALSE );
1521 if ((sSrc == DIB_Status_AppMod) && (rop == SRCCOPY) &&
1522 (dcSrc->bitsPerPixel == dcDst->bitsPerPixel))
1524 /* do everything ourselves; map coordinates */
1525 xSrc = dcSrc->DCOrgX + XLPTODP( dcSrc, xSrc );
1526 ySrc = dcSrc->DCOrgY + YLPTODP( dcSrc, ySrc );
1527 xDst = dcDst->DCOrgX + XLPTODP( dcDst, xDst );
1528 yDst = dcDst->DCOrgY + YLPTODP( dcDst, yDst );
1529 width = MulDiv(width, dcDst->vportExtX, dcDst->wndExtX);
1530 height = MulDiv(height, dcDst->vportExtY, dcDst->wndExtY);
1532 /* Perform basic clipping */
1533 if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, width, height,
1534 dcSrc, xSrc, ySrc, width, height,
1535 &visRectSrc, &visRectDst ))
1538 xSrc = visRectSrc.left;
1539 ySrc = visRectSrc.top;
1540 xDst = visRectDst.left;
1541 yDst = visRectDst.top;
1542 width = visRectDst.right - visRectDst.left;
1543 height = visRectDst.bottom - visRectDst.top;
1545 if (sDst == DIB_Status_AppMod) {
1546 FIXME("potential optimization - client-side DIB copy\n");
1548 X11DRV_CoerceDIBSection( dcDst, DIB_Status_GdiMod, FALSE );
1550 X11DRV_DIB_CopyDIBSection( dcSrc, dcDst, xSrc, ySrc, xDst, yDst, width, height );
1555 X11DRV_CoerceDIBSection( dcDst, DIB_Status_GdiMod, FALSE );
1556 X11DRV_CoerceDIBSection( dcSrc, DIB_Status_GdiMod, FALSE );
1558 result = BITBLT_InternalStretchBlt( dcDst, xDst, yDst, width, height,
1559 dcSrc, xSrc, ySrc, width, height, rop );
1562 X11DRV_UnlockDIBSection( dcSrc, FALSE );
1563 X11DRV_UnlockDIBSection( dcDst, TRUE );
1569 /***********************************************************************
1572 BOOL X11DRV_StretchBlt( DC *dcDst, INT xDst, INT yDst,
1573 INT widthDst, INT heightDst,
1574 DC *dcSrc, INT xSrc, INT ySrc,
1575 INT widthSrc, INT heightSrc, DWORD rop )
1579 X11DRV_LockDIBSection( dcDst, DIB_Status_GdiMod, FALSE );
1580 X11DRV_LockDIBSection( dcSrc, DIB_Status_GdiMod, FALSE );
1582 result = BITBLT_InternalStretchBlt( dcDst, xDst, yDst, widthDst, heightDst,
1583 dcSrc, xSrc, ySrc, widthSrc, heightSrc, rop );
1585 X11DRV_UnlockDIBSection( dcSrc, FALSE );
1586 X11DRV_UnlockDIBSection( dcDst, TRUE );