2 * GDI bit-blit operations
4 * Copyright 1993, 1994 Alexandre Julliard
5 * Copyright 2006 Damjan Jovanovic
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
39 #define DST 0 /* Destination drawable */
40 #define SRC 1 /* Source drawable */
41 #define TMP 2 /* Temporary drawable */
42 #define PAT 3 /* Pattern (brush) in destination DC */
44 #define OP(src,dst,rop) (OP_ARGS(src,dst) << 4 | (rop))
45 #define OP_ARGS(src,dst) (((src) << 2) | (dst))
47 #define OP_SRC(opcode) ((opcode) >> 6)
48 #define OP_DST(opcode) (((opcode) >> 4) & 3)
49 #define OP_SRCDST(opcode) ((opcode) >> 4)
50 #define OP_ROP(opcode) ((opcode) & 0x0f)
52 #define MAX_OP_LEN 6 /* Longest opcode + 1 for the terminating 0 */
54 #define SWAP_INT32(i1,i2) \
55 do { INT __t = *(i1); *(i1) = *(i2); *(i2) = __t; } while(0)
57 static const unsigned char BITBLT_Opcodes[256][MAX_OP_LEN] =
59 { OP(PAT,DST,GXclear) }, /* 0x00 0 */
60 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnor) }, /* 0x01 ~(D|(P|S)) */
61 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXand) }, /* 0x02 D&~(P|S) */
62 { OP(PAT,SRC,GXnor) }, /* 0x03 ~(P|S) */
63 { OP(PAT,DST,GXnor), OP(SRC,DST,GXand) }, /* 0x04 S&~(D|P) */
64 { OP(PAT,DST,GXnor) }, /* 0x05 ~(D|P) */
65 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnor), }, /* 0x06 ~(P|~(D^S)) */
66 { OP(SRC,DST,GXand), OP(PAT,DST,GXnor) }, /* 0x07 ~(P|(D&S)) */
67 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXand) },/* 0x08 S&D&~P */
68 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnor) }, /* 0x09 ~(P|(D^S)) */
69 { OP(PAT,DST,GXandInverted) }, /* 0x0a D&~P */
70 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXnor) }, /* 0x0b ~(P|(S&~D)) */
71 { OP(PAT,SRC,GXandInverted) }, /* 0x0c S&~P */
72 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXnor) },/* 0x0d ~(P|(D&~S)) */
73 { OP(SRC,DST,GXnor), OP(PAT,DST,GXnor) }, /* 0x0e ~(P|~(D|S)) */
74 { OP(PAT,DST,GXcopyInverted) }, /* 0x0f ~P */
75 { OP(SRC,DST,GXnor), OP(PAT,DST,GXand) }, /* 0x10 P&~(S|D) */
76 { OP(SRC,DST,GXnor) }, /* 0x11 ~(D|S) */
77 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnor) }, /* 0x12 ~(S|~(D^P)) */
78 { OP(PAT,DST,GXand), OP(SRC,DST,GXnor) }, /* 0x13 ~(S|(D&P)) */
79 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnor) }, /* 0x14 ~(D|~(P^S)) */
80 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnor) }, /* 0x15 ~(D|(P&S)) */
81 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
82 OP(TMP,DST,GXand), OP(SRC,DST,GXxor),
83 OP(PAT,DST,GXxor) }, /* 0x16 P^S^(D&~(P&S) */
84 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
85 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
86 OP(TMP,DST,GXequiv) }, /* 0x17 ~S^((S^P)&(S^D))*/
87 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
88 OP(SRC,DST,GXand) }, /* 0x18 (S^P)&(D^P) */
89 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
90 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x19 ~S^(D&~(P&S)) */
91 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
92 OP(PAT,DST,GXxor) }, /* 0x1a P^(D|(S&P)) */
93 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXxor),
94 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x1b ~S^(D&(P^S)) */
95 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
96 OP(PAT,DST,GXxor) }, /* 0x1c P^(S|(D&P)) */
97 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
98 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x1d ~D^(S&(D^P)) */
99 { OP(SRC,DST,GXor), OP(PAT,DST,GXxor) }, /* 0x1e P^(D|S) */
100 { OP(SRC,DST,GXor), OP(PAT,DST,GXnand) }, /* 0x1f ~(P&(D|S)) */
101 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXand) }, /* 0x20 D&(P&~S) */
102 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnor) }, /* 0x21 ~(S|(D^P)) */
103 { OP(SRC,DST,GXandInverted) }, /* 0x22 ~S&D */
104 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x23 ~(S|(P&~D)) */
105 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
106 OP(SRC,DST,GXand) }, /* 0x24 (S^P)&(S^D) */
107 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand),
108 OP(PAT,DST,GXequiv) }, /* 0x25 ~P^(D&~(S&P)) */
109 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
110 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x26 S^(D|(S&P)) */
111 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXequiv),
112 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x27 S^(D|~(P^S)) */
113 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand) }, /* 0x28 D&(P^S) */
114 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
115 OP(TMP,DST,GXor), OP(SRC,DST,GXxor),
116 OP(PAT,DST,GXequiv) }, /* 0x29 ~P^S^(D|(P&S)) */
117 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand) }, /* 0x2a D&~(P&S) */
118 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
119 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
120 OP(TMP,DST,GXequiv) }, /* 0x2b ~S^((P^S)&(P^D))*/
121 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
122 OP(SRC,DST,GXxor) }, /* 0x2c S^(P&(S|D)) */
123 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXxor) }, /* 0x2d P^(S|~D) */
124 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
125 OP(PAT,DST,GXxor) }, /* 0x2e P^(S|(D^P)) */
126 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXnand) }, /* 0x2f ~(P&(S|~D)) */
127 { OP(PAT,SRC,GXandReverse) }, /* 0x30 P&~S */
128 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXnor) },/* 0x31 ~(S|(D&~P)) */
129 { OP(SRC,DST,GXor), OP(PAT,DST,GXor),
130 OP(SRC,DST,GXxor) }, /* 0x32 S^(D|P|S) */
131 { OP(SRC,DST,GXcopyInverted) }, /* 0x33 ~S */
132 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
133 OP(SRC,DST,GXxor) }, /* 0x34 S^(P|(D&S)) */
134 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor),
135 OP(SRC,DST,GXxor) }, /* 0x35 S^(P|~(D^S)) */
136 { OP(PAT,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x36 S^(D|P) */
137 { OP(PAT,DST,GXor), OP(SRC,DST,GXnand) }, /* 0x37 ~(S&(D|P)) */
138 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
139 OP(PAT,DST,GXxor) }, /* 0x38 P^(S&(D|P)) */
140 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x39 S^(P|~D) */
141 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
142 OP(SRC,DST,GXxor) }, /* 0x3a S^(P|(D^S)) */
143 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x3b ~(S&(P|~D)) */
144 { OP(PAT,SRC,GXxor) }, /* 0x3c P^S */
145 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
146 OP(SRC,DST,GXxor) }, /* 0x3d S^(P|~(D|S)) */
147 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
148 OP(SRC,DST,GXxor) }, /* 0x3e S^(P|(D&~S)) */
149 { OP(PAT,SRC,GXnand) }, /* 0x3f ~(P&S) */
150 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXand) }, /* 0x40 P&S&~D */
151 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnor) }, /* 0x41 ~(D|(P^S)) */
152 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
153 OP(SRC,DST,GXand) }, /* 0x42 (S^D)&(P^D) */
154 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
155 OP(SRC,DST,GXequiv) }, /* 0x43 ~S^(P&~(D&S)) */
156 { OP(SRC,DST,GXandReverse) }, /* 0x44 S&~D */
157 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x45 ~(D|(P&~S)) */
158 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
159 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x46 D^(S|(P&D)) */
160 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
161 OP(PAT,DST,GXequiv) }, /* 0x47 ~P^(S&(D^P)) */
162 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand) }, /* 0x48 S&(P^D) */
163 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
164 OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
165 OP(PAT,DST,GXequiv) }, /* 0x49 ~P^D^(S|(P&D)) */
166 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
167 OP(SRC,DST,GXxor) }, /* 0x4a D^(P&(S|D)) */
168 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXxor) }, /* 0x4b P^(D|~S) */
169 { OP(PAT,DST,GXnand), OP(SRC,DST,GXand) }, /* 0x4c S&~(D&P) */
170 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
171 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
172 OP(TMP,DST,GXequiv) }, /* 0x4d ~S^((S^P)|(S^D))*/
173 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
174 OP(PAT,DST,GXxor) }, /* 0x4e P^(D|(S^P)) */
175 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXnand) },/* 0x4f ~(P&(D|~S)) */
176 { OP(PAT,DST,GXandReverse) }, /* 0x50 P&~D */
177 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXnor) },/* 0x51 ~(D|(S&~P)) */
178 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
179 OP(SRC,DST,GXxor) }, /* 0x52 D^(P|(S&D)) */
180 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
181 OP(SRC,DST,GXequiv) }, /* 0x53 ~S^(P&(D^S)) */
182 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXnor) }, /* 0x54 ~(D|~(P|S)) */
183 { OP(PAT,DST,GXinvert) }, /* 0x55 ~D */
184 { OP(PAT,SRC,GXor), OP(SRC,DST,GXxor) }, /* 0x56 D^(P|S) */
185 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnand) }, /* 0x57 ~(D&(P|S)) */
186 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
187 OP(PAT,DST,GXxor) }, /* 0x58 P^(D&(P|S)) */
188 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x59 D^(P|~S) */
189 { OP(PAT,DST,GXxor) }, /* 0x5a D^P */
190 { OP(DST,SRC,GXnor), OP(PAT,SRC,GXor),
191 OP(SRC,DST,GXxor) }, /* 0x5b D^(P|~(S|D)) */
192 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
193 OP(SRC,DST,GXxor) }, /* 0x5c D^(P|(S^D)) */
194 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x5d ~(D&(P|~S)) */
195 { OP(DST,SRC,GXandInverted), OP(PAT,SRC,GXor),
196 OP(SRC,DST,GXxor) }, /* 0x5e D^(P|(S&~D)) */
197 { OP(PAT,DST,GXnand) }, /* 0x5f ~(D&P) */
198 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand) }, /* 0x60 P&(D^S) */
199 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
200 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
201 OP(TMP,DST,GXequiv) }, /* 0x61 ~D^S^(P|(D&S)) */
202 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
203 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x62 D^(S&(P|D)) */
204 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x63 S^(D|~P) */
205 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
206 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x64 S^(D&(P|S)) */
207 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x65 D^(S|~P) */
208 { OP(SRC,DST,GXxor) }, /* 0x66 S^D */
209 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
210 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x67 S^(D|~(S|P) */
211 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnor),
212 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
213 OP(TMP,DST,GXequiv) }, /* 0x68 ~D^S^(P|~(D|S))*/
214 { OP(SRC,DST,GXxor), OP(PAT,DST,GXequiv) }, /* 0x69 ~P^(D^S) */
215 { OP(PAT,SRC,GXand), OP(SRC,DST,GXxor) }, /* 0x6a D^(P&S) */
216 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
217 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
218 OP(PAT,DST,GXequiv) }, /* 0x6b ~P^S^(D&(P|S)) */
219 { OP(PAT,DST,GXand), OP(SRC,DST,GXxor) }, /* 0x6c S^(D&P) */
220 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
221 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
222 OP(PAT,DST,GXequiv) }, /* 0x6d ~P^D^(S&(P|D)) */
223 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
224 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x6e S^(D&(P|~S)) */
225 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnand) }, /* 0x6f ~(P&~(S^D)) */
226 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand) }, /* 0x70 P&~(D&S) */
227 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
228 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
229 OP(TMP,DST,GXequiv) }, /* 0x71 ~S^((S^D)&(P^D))*/
230 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
231 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x72 S^(D|(P^S)) */
232 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXnand) },/* 0x73 ~(S&(D|~P)) */
233 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
234 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x74 D^(S|(P^D)) */
235 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXnand) },/* 0x75 ~(D&(S|~P)) */
236 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
237 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x76 S^(D|(P&~S)) */
238 { OP(SRC,DST,GXnand) }, /* 0x77 ~(S&D) */
239 { OP(SRC,DST,GXand), OP(PAT,DST,GXxor) }, /* 0x78 P^(D&S) */
240 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
241 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
242 OP(TMP,DST,GXequiv) }, /* 0x79 ~D^S^(P&(D|S)) */
243 { OP(DST,SRC,GXorInverted), OP(PAT,SRC,GXand),
244 OP(SRC,DST,GXxor) }, /* 0x7a D^(P&(S|~D)) */
245 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7b ~(S&~(D^P)) */
246 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
247 OP(SRC,DST,GXxor) }, /* 0x7c S^(P&(D|~S)) */
248 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7d ~(D&~(P^S)) */
249 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
250 OP(SRC,DST,GXor) }, /* 0x7e (S^P)|(S^D) */
251 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnand) }, /* 0x7f ~(D&P&S) */
252 { OP(PAT,SRC,GXand), OP(SRC,DST,GXand) }, /* 0x80 D&P&S */
253 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
254 OP(SRC,DST,GXnor) }, /* 0x81 ~((S^P)|(S^D)) */
255 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXand) }, /* 0x82 D&~(P^S) */
256 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
257 OP(SRC,DST,GXequiv) }, /* 0x83 ~S^(P&(D|~S)) */
258 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXand) }, /* 0x84 S&~(D^P) */
259 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand),
260 OP(PAT,DST,GXequiv) }, /* 0x85 ~P^(D&(S|~P)) */
261 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
262 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
263 OP(TMP,DST,GXxor) }, /* 0x86 D^S^(P&(D|S)) */
264 { OP(SRC,DST,GXand), OP(PAT,DST,GXequiv) }, /* 0x87 ~P^(D&S) */
265 { OP(SRC,DST,GXand) }, /* 0x88 S&D */
266 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
267 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x89 ~S^(D|(P&~S)) */
268 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8a D&(S|~P) */
269 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
270 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8b ~D^(S|(P^D)) */
271 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8c S&(D|~P) */
272 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
273 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8d ~S^(D|(P^S)) */
274 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
275 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
276 OP(TMP,DST,GXxor) }, /* 0x8e S^((S^D)&(P^D))*/
277 { OP(SRC,DST,GXnand), OP(PAT,DST,GXnand) }, /* 0x8f ~(P&~(D&S)) */
278 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXand) }, /* 0x90 P&~(D^S) */
279 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
280 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x91 ~S^(D&(P|~S)) */
281 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
282 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
283 OP(TMP,DST,GXxor) }, /* 0x92 D^P^(S&(D|P)) */
284 { OP(PAT,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x93 ~S^(P&D) */
285 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
286 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
287 OP(TMP,DST,GXxor) }, /* 0x94 S^P^(D&(P|S)) */
288 { OP(PAT,SRC,GXand), OP(SRC,DST,GXequiv) }, /* 0x95 ~D^(P&S) */
289 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXxor) }, /* 0x96 D^P^S */
290 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
291 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
292 OP(TMP,DST,GXxor) }, /* 0x97 S^P^(D|~(P|S)) */
293 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
294 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x98 ~S^(D|~(P|S)) */
295 { OP(SRC,DST,GXequiv) }, /* 0x99 ~S^D */
296 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9a D^(P&~S) */
297 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
298 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9b ~S^(D&(P|S)) */
299 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9c S^(P&~D) */
300 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
301 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9d ~D^(S&(P|D)) */
302 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
303 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
304 OP(TMP,DST,GXxor) }, /* 0x9e D^S^(P|(D&S)) */
305 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnand) }, /* 0x9f ~(P&(D^S)) */
306 { OP(PAT,DST,GXand) }, /* 0xa0 D&P */
307 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor),
308 OP(PAT,DST,GXequiv) }, /* 0xa1 ~P^(D|(S&~P)) */
309 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXand) }, /* 0xa2 D&(P|~S) */
310 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
311 OP(SRC,DST,GXequiv) }, /* 0xa3 ~D^(P|(S^D)) */
312 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor),
313 OP(PAT,DST,GXequiv) }, /* 0xa4 ~P^(D|~(S|P)) */
314 { OP(PAT,DST,GXequiv) }, /* 0xa5 ~P^D */
315 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXxor) },/* 0xa6 D^(S&~P) */
316 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
317 OP(PAT,DST,GXequiv) }, /* 0xa7 ~P^(D&(S|P)) */
318 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand) }, /* 0xa8 D&(P|S) */
319 { OP(PAT,SRC,GXor), OP(SRC,DST,GXequiv) }, /* 0xa9 ~D^(P|S) */
320 { OP(PAT,DST,GXnoop) }, /* 0xaa D */
321 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor) }, /* 0xab D|~(P|S) */
322 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
323 OP(SRC,DST,GXxor) }, /* 0xac S^(P&(D^S)) */
324 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
325 OP(SRC,DST,GXequiv) }, /* 0xad ~D^(P|(S&D)) */
326 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor) }, /* 0xae D|(S&~P) */
327 { OP(PAT,DST,GXorInverted) }, /* 0xaf D|~P */
328 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand) }, /* 0xb0 P&(D|~S) */
329 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
330 OP(PAT,DST,GXequiv) }, /* 0xb1 ~P^(D|(S^P)) */
331 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
332 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
333 OP(TMP,DST,GXxor) }, /* 0xb2 S^((S^P)|(S^D))*/
334 { OP(PAT,DST,GXnand), OP(SRC,DST,GXnand) }, /* 0xb3 ~(S&~(D&P)) */
335 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXxor) }, /* 0xb4 P^(S&~D) */
336 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
337 OP(SRC,DST,GXequiv) }, /* 0xb5 ~D^(P&(S|D)) */
338 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
339 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
340 OP(TMP,DST,GXxor) }, /* 0xb6 D^P^(S|(D&P)) */
341 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnand) }, /* 0xb7 ~(S&(D^P)) */
342 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
343 OP(PAT,DST,GXxor) }, /* 0xb8 P^(S&(D^P)) */
344 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
345 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xb9 ~D^(S|(P&D)) */
346 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXor) }, /* 0xba D|(P&~S) */
347 { OP(SRC,DST,GXorInverted) }, /* 0xbb ~S|D */
348 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
349 OP(SRC,DST,GXxor) }, /* 0xbc S^(P&~(D&S)) */
350 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
351 OP(SRC,DST,GXnand) }, /* 0xbd ~((S^D)&(P^D)) */
352 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor) }, /* 0xbe D|(P^S) */
353 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXor) }, /* 0xbf D|~(P&S) */
354 { OP(PAT,SRC,GXand) }, /* 0xc0 P&S */
355 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
356 OP(SRC,DST,GXequiv) }, /* 0xc1 ~S^(P|(D&~S)) */
357 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
358 OP(SRC,DST,GXequiv) }, /* 0xc2 ~S^(P|~(D|S)) */
359 { OP(PAT,SRC,GXequiv) }, /* 0xc3 ~P^S */
360 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXand) }, /* 0xc4 S&(P|~D) */
361 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
362 OP(SRC,DST,GXequiv) }, /* 0xc5 ~S^(P|(D^S)) */
363 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXxor) },/* 0xc6 S^(D&~P) */
364 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
365 OP(PAT,DST,GXequiv) }, /* 0xc7 ~P^(S&(D|P)) */
366 { OP(PAT,DST,GXor), OP(SRC,DST,GXand) }, /* 0xc8 S&(D|P) */
367 { OP(PAT,DST,GXor), OP(SRC,DST,GXequiv) }, /* 0xc9 ~S^(P|D) */
368 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXand),
369 OP(SRC,DST,GXxor) }, /* 0xca D^(P&(S^D)) */
370 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
371 OP(SRC,DST,GXequiv) }, /* 0xcb ~S^(P|(D&S)) */
372 { OP(SRC,DST,GXcopy) }, /* 0xcc S */
373 { OP(PAT,DST,GXnor), OP(SRC,DST,GXor) }, /* 0xcd S|~(D|P) */
374 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXor) }, /* 0xce S|(D&~P) */
375 { OP(PAT,SRC,GXorInverted) }, /* 0xcf S|~P */
376 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXand) }, /* 0xd0 P&(S|~D) */
377 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
378 OP(PAT,DST,GXequiv) }, /* 0xd1 ~P^(S|(D^P)) */
379 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXxor) },/* 0xd2 P^(D&~S) */
380 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
381 OP(SRC,DST,GXequiv) }, /* 0xd3 ~S^(P&(D|S)) */
382 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
383 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
384 OP(TMP,DST,GXxor) }, /* 0xd4 S^((S^P)&(D^P))*/
385 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXnand) }, /* 0xd5 ~(D&~(P&S)) */
386 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
387 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
388 OP(TMP,DST,GXxor) }, /* 0xd6 S^P^(D|(P&S)) */
389 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnand) }, /* 0xd7 ~(D&(P^S)) */
390 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
391 OP(PAT,DST,GXxor) }, /* 0xd8 P^(D&(S^P)) */
392 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
393 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xd9 ~S^(D|(P&S)) */
394 { OP(DST,SRC,GXnand), OP(PAT,SRC,GXand),
395 OP(SRC,DST,GXxor) }, /* 0xda D^(P&~(S&D)) */
396 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
397 OP(SRC,DST,GXnand) }, /* 0xdb ~((S^P)&(S^D)) */
398 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXor) }, /* 0xdc S|(P&~D) */
399 { OP(SRC,DST,GXorReverse) }, /* 0xdd S|~D */
400 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor) }, /* 0xde S|(D^P) */
401 { OP(PAT,DST,GXnand), OP(SRC,DST,GXor) }, /* 0xdf S|~(D&P) */
402 { OP(SRC,DST,GXor), OP(PAT,DST,GXand) }, /* 0xe0 P&(D|S) */
403 { OP(SRC,DST,GXor), OP(PAT,DST,GXequiv) }, /* 0xe1 ~P^(D|S) */
404 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
405 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe2 D^(S&(P^D)) */
406 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
407 OP(PAT,DST,GXequiv) }, /* 0xe3 ~P^(S|(D&P)) */
408 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
409 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe4 S^(D&(P^S)) */
410 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
411 OP(PAT,DST,GXequiv) }, /* 0xe5 ~P^(D|(S&P)) */
412 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
413 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe6 S^(D&~(P&S)) */
414 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
415 OP(SRC,DST,GXnand) }, /* 0xe7 ~((S^P)&(D^P)) */
416 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
417 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
418 OP(TMP,DST,GXxor) }, /* 0xe8 S^((S^P)&(S^D))*/
419 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnand),
420 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
421 OP(TMP,DST,GXequiv) }, /* 0xe9 ~D^S^(P&~(S&D))*/
422 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor) }, /* 0xea D|(P&S) */
423 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXor) }, /* 0xeb D|~(P^S) */
424 { OP(PAT,DST,GXand), OP(SRC,DST,GXor) }, /* 0xec S|(D&P) */
425 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXor) }, /* 0xed S|~(D^P) */
426 { OP(SRC,DST,GXor) }, /* 0xee S|D */
427 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXor) }, /* 0xef S|D|~P */
428 { OP(PAT,DST,GXcopy) }, /* 0xf0 P */
429 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor) }, /* 0xf1 P|~(D|S) */
430 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor) }, /* 0xf2 P|(D&~S) */
431 { OP(PAT,SRC,GXorReverse) }, /* 0xf3 P|~S */
432 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXor) }, /* 0xf4 P|(S&~D) */
433 { OP(PAT,DST,GXorReverse) }, /* 0xf5 P|~D */
434 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor) }, /* 0xf6 P|(D^S) */
435 { OP(SRC,DST,GXnand), OP(PAT,DST,GXor) }, /* 0xf7 P|~(S&D) */
436 { OP(SRC,DST,GXand), OP(PAT,DST,GXor) }, /* 0xf8 P|(D&S) */
437 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor) }, /* 0xf9 P|~(D^S) */
438 { OP(PAT,DST,GXor) }, /* 0xfa D|P */
439 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXor) }, /* 0xfb D|P|~S */
440 { OP(PAT,SRC,GXor) }, /* 0xfc P|S */
441 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXor) }, /* 0xfd P|S|~D */
442 { OP(SRC,DST,GXor), OP(PAT,DST,GXor) }, /* 0xfe P|D|S */
443 { OP(PAT,DST,GXset) } /* 0xff 1 */
447 #ifdef BITBLT_TEST /* Opcodes test */
449 static int do_bitop( int s, int d, int rop )
454 case GXclear: res = 0; break;
455 case GXand: res = s & d; break;
456 case GXandReverse: res = s & ~d; break;
457 case GXcopy: res = s; break;
458 case GXandInverted: res = ~s & d; break;
459 case GXnoop: res = d; break;
460 case GXxor: res = s ^ d; break;
461 case GXor: res = s | d; break;
462 case GXnor: res = ~(s | d); break;
463 case GXequiv: res = ~s ^ d; break;
464 case GXinvert: res = ~d; break;
465 case GXorReverse: res = s | ~d; break;
466 case GXcopyInverted: res = ~s; break;
467 case GXorInverted: res = ~s | d; break;
468 case GXnand: res = ~(s & d); break;
469 case GXset: res = 1; break;
476 int rop, i, res, src, dst, pat, tmp, dstUsed;
479 for (rop = 0; rop < 256; rop++)
482 for (i = 0; i < 8; i++)
487 for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
491 case OP_ARGS(DST,TMP):
492 tmp = do_bitop( dst, tmp, *opcode & 0xf );
494 case OP_ARGS(DST,SRC):
495 src = do_bitop( dst, src, *opcode & 0xf );
497 case OP_ARGS(SRC,TMP):
498 tmp = do_bitop( src, tmp, *opcode & 0xf );
500 case OP_ARGS(SRC,DST):
501 dst = do_bitop( src, dst, *opcode & 0xf );
504 case OP_ARGS(PAT,TMP):
505 tmp = do_bitop( pat, tmp, *opcode & 0xf );
507 case OP_ARGS(PAT,DST):
508 dst = do_bitop( pat, dst, *opcode & 0xf );
511 case OP_ARGS(PAT,SRC):
512 src = do_bitop( pat, src, *opcode & 0xf );
514 case OP_ARGS(TMP,DST):
515 dst = do_bitop( tmp, dst, *opcode & 0xf );
518 case OP_ARGS(TMP,SRC):
519 src = do_bitop( tmp, src, *opcode & 0xf );
522 printf( "Invalid opcode %x\n", *opcode );
525 if (!dstUsed) dst = src;
526 if (dst) res |= 1 << i;
528 if (res != rop) printf( "%02x: ERROR, res=%02x\n", rop, res );
534 #endif /* BITBLT_TEST */
537 static void get_colors(X11DRV_PDEVICE *physDevDst, X11DRV_PDEVICE *physDevSrc,
542 *fg = physDevDst->textPixel;
543 *bg = physDevDst->backgroundPixel;
544 if(physDevSrc->depth == 1) {
545 if(GetDIBColorTable(physDevSrc->hdc, 0, 2, rgb) == 2) {
547 logcolor = RGB(rgb[0].rgbRed, rgb[0].rgbGreen, rgb[0].rgbBlue);
548 *fg = X11DRV_PALETTE_ToPhysical( physDevDst, logcolor );
549 logcolor = RGB(rgb[1].rgbRed, rgb[1].rgbGreen,rgb[1].rgbBlue);
550 *bg = X11DRV_PALETTE_ToPhysical( physDevDst, logcolor );
555 /***********************************************************************
558 * Stretch a row of pixels. Helper function for BITBLT_StretchImage.
560 static void BITBLT_StretchRow( int *rowSrc, int *rowDst,
561 INT startDst, INT widthDst,
562 INT xinc, INT xoff, WORD mode )
564 register INT xsrc = xinc * startDst + xoff;
568 case STRETCH_ANDSCANS:
569 for(; widthDst > 0; widthDst--, xsrc += xinc)
570 *rowDst++ &= rowSrc[xsrc >> 16];
572 case STRETCH_ORSCANS:
573 for(; widthDst > 0; widthDst--, xsrc += xinc)
574 *rowDst++ |= rowSrc[xsrc >> 16];
576 case STRETCH_DELETESCANS:
577 for(; widthDst > 0; widthDst--, xsrc += xinc)
578 *rowDst++ = rowSrc[xsrc >> 16];
584 /***********************************************************************
587 * Shrink a row of pixels. Helper function for BITBLT_StretchImage.
589 static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst,
590 INT startSrc, INT widthSrc,
591 INT xinc, INT xoff, WORD mode )
593 register INT xdst = xinc * startSrc + xoff;
597 case STRETCH_ORSCANS:
598 for(; widthSrc > 0; widthSrc--, xdst += xinc)
599 rowDst[xdst >> 16] |= *rowSrc++;
601 case STRETCH_ANDSCANS:
602 for(; widthSrc > 0; widthSrc--, xdst += xinc)
603 rowDst[xdst >> 16] &= *rowSrc++;
605 case STRETCH_DELETESCANS:
606 for(; widthSrc > 0; widthSrc--, xdst += xinc)
607 rowDst[xdst >> 16] = *rowSrc++;
613 /***********************************************************************
616 * Retrieve a row from an image. Helper function for BITBLT_StretchImage.
618 static void BITBLT_GetRow( XImage *image, int *pdata, INT row,
619 INT start, INT width, INT depthDst,
620 int fg, int bg, BOOL swap)
624 assert( (row >= 0) && (row < image->height) );
625 assert( (start >= 0) && (width <= image->width) );
627 pdata += swap ? start+width-1 : start;
628 if (image->depth == depthDst) /* color -> color */
630 if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1))
631 if (swap) for (i = 0; i < width; i++)
632 *pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
633 else for (i = 0; i < width; i++)
634 *pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
636 if (swap) for (i = 0; i < width; i++)
637 *pdata-- = XGetPixel( image, i, row );
638 else for (i = 0; i < width; i++)
639 *pdata++ = XGetPixel( image, i, row );
643 if (image->depth == 1) /* monochrome -> color */
645 if (X11DRV_PALETTE_XPixelToPalette)
647 fg = X11DRV_PALETTE_XPixelToPalette[fg];
648 bg = X11DRV_PALETTE_XPixelToPalette[bg];
650 if (swap) for (i = 0; i < width; i++)
651 *pdata-- = XGetPixel( image, i, row ) ? bg : fg;
652 else for (i = 0; i < width; i++)
653 *pdata++ = XGetPixel( image, i, row ) ? bg : fg;
655 else /* color -> monochrome */
657 if (swap) for (i = 0; i < width; i++)
658 *pdata-- = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
659 else for (i = 0; i < width; i++)
660 *pdata++ = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
666 /***********************************************************************
667 * BITBLT_StretchImage
669 * Stretch an X image.
670 * FIXME: does not work for full 32-bit coordinates.
672 static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage,
673 INT widthSrc, INT heightSrc,
674 INT widthDst, INT heightDst,
675 RECT *visRectSrc, RECT *visRectDst,
676 int foreground, int background, WORD mode )
678 int *rowSrc, *rowDst, *pixel;
680 INT xinc, xoff, yinc, ysrc, ydst;
682 BOOL hstretch, vstretch, hswap, vswap;
684 hswap = widthSrc * widthDst < 0;
685 vswap = heightSrc * heightDst < 0;
686 widthSrc = abs(widthSrc);
687 heightSrc = abs(heightSrc);
688 widthDst = abs(widthDst);
689 heightDst = abs(heightDst);
691 if (!(rowSrc = HeapAlloc( GetProcessHeap(), 0,
692 (widthSrc+widthDst)*sizeof(int) ))) return;
693 rowDst = rowSrc + widthSrc;
695 /* When stretching, all modes are the same, and DELETESCANS is faster */
696 if ((widthSrc < widthDst) && (heightSrc < heightDst))
697 mode = STRETCH_DELETESCANS;
699 if (mode == STRETCH_HALFTONE) /* FIXME */
700 mode = STRETCH_DELETESCANS;
702 if (mode != STRETCH_DELETESCANS)
703 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
704 widthDst*sizeof(int) );
706 hstretch = (widthSrc < widthDst);
707 vstretch = (heightSrc < heightDst);
711 xinc = (widthSrc << 16) / widthDst;
712 xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
716 xinc = ((int)widthDst << 16) / widthSrc;
717 xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
723 yinc = (heightSrc << 16) / heightDst;
724 ydst = visRectDst->top;
727 ysrc = yinc * (heightDst - ydst - 1);
733 for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
735 if (((ysrc >> 16) < visRectSrc->top) ||
736 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
738 /* Retrieve a source row */
739 BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
740 hswap ? widthSrc - visRectSrc->right
742 visRectSrc->right - visRectSrc->left,
743 dstImage->depth, foreground, background, hswap );
745 /* Stretch or shrink it */
747 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
748 visRectDst->right - visRectDst->left,
750 else BITBLT_ShrinkRow( rowSrc, rowDst,
751 hswap ? widthSrc - visRectSrc->right
753 visRectSrc->right - visRectSrc->left,
756 /* Store the destination row */
757 pixel = rowDst + visRectDst->right - 1;
758 y = ydst - visRectDst->top;
759 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
760 XPutPixel( dstImage, x, y, *pixel-- );
761 if (mode != STRETCH_DELETESCANS)
762 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
763 widthDst*sizeof(int) );
765 /* Make copies of the destination row */
767 pdata = dstImage->data + dstImage->bytes_per_line * y;
768 while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
769 (ydst < visRectDst->bottom-1))
771 memcpy( pdata + dstImage->bytes_per_line, pdata,
772 dstImage->bytes_per_line );
773 pdata += dstImage->bytes_per_line;
781 yinc = (heightDst << 16) / heightSrc;
782 ysrc = visRectSrc->top;
783 ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
786 ydst += yinc * (heightSrc - ysrc - 1);
792 for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
794 if (((ydst >> 16) < visRectDst->top) ||
795 ((ydst >> 16) >= visRectDst->bottom)) continue;
797 /* Retrieve a source row */
798 BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
799 hswap ? widthSrc - visRectSrc->right
801 visRectSrc->right - visRectSrc->left,
802 dstImage->depth, foreground, background, hswap );
804 /* Stretch or shrink it */
806 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
807 visRectDst->right - visRectDst->left,
809 else BITBLT_ShrinkRow( rowSrc, rowDst,
810 hswap ? widthSrc - visRectSrc->right
812 visRectSrc->right - visRectSrc->left,
815 /* Merge several source rows into the destination */
816 if (mode == STRETCH_DELETESCANS)
818 /* Simply skip the overlapping rows */
819 while (((ydst + yinc) >> 16 == ydst >> 16) &&
820 (ysrc < visRectSrc->bottom-1))
826 else if (((ydst + yinc) >> 16 == ydst >> 16) &&
827 (ysrc < visRectSrc->bottom-1))
828 continue; /* Restart loop for next overlapping row */
830 /* Store the destination row */
831 pixel = rowDst + visRectDst->right - 1;
832 y = (ydst >> 16) - visRectDst->top;
833 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
834 XPutPixel( dstImage, x, y, *pixel-- );
835 if (mode != STRETCH_DELETESCANS)
836 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
837 widthDst*sizeof(int) );
841 HeapFree( GetProcessHeap(), 0, rowSrc );
845 /***********************************************************************
846 * BITBLT_GetSrcAreaStretch
848 * Retrieve an area from the source DC, stretching and mapping all the
849 * pixels to Windows colors.
851 static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
852 Pixmap pixmap, GC gc,
854 INT widthSrc, INT heightSrc,
856 INT widthDst, INT heightDst,
857 RECT *visRectSrc, RECT *visRectDst )
859 XImage *imageSrc, *imageDst;
860 RECT rectSrc = *visRectSrc;
861 RECT rectDst = *visRectDst;
864 if (widthSrc < 0) xSrc += widthSrc;
865 if (widthDst < 0) xDst += widthDst;
866 if (heightSrc < 0) ySrc += heightSrc;
867 if (heightDst < 0) yDst += heightDst;
868 rectSrc.left -= xSrc;
869 rectSrc.right -= xSrc;
871 rectSrc.bottom -= ySrc;
872 rectDst.left -= xDst;
873 rectDst.right -= xDst;
875 rectDst.bottom -= yDst;
877 get_colors(physDevDst, physDevSrc, &fg, &bg);
879 /* FIXME: avoid BadMatch errors */
880 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
881 physDevSrc->dc_rect.left + visRectSrc->left,
882 physDevSrc->dc_rect.top + visRectSrc->top,
883 visRectSrc->right - visRectSrc->left,
884 visRectSrc->bottom - visRectSrc->top,
885 AllPlanes, ZPixmap );
888 imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
889 rectDst.bottom - rectDst.top, physDevDst->depth );
890 BITBLT_StretchImage( imageSrc, imageDst, widthSrc, heightSrc,
891 widthDst, heightDst, &rectSrc, &rectDst,
892 fg, physDevDst->depth != 1 ?
893 bg : physDevSrc->backgroundPixel,
894 GetStretchBltMode(physDevDst->hdc) );
896 XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
897 rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
898 XDestroyImage( imageSrc );
899 X11DRV_DIB_DestroyXImage( imageDst );
901 return 0; /* no exposure events generated */
905 /***********************************************************************
908 * Retrieve an area from the source DC, mapping all the
909 * pixels to Windows colors.
911 static int BITBLT_GetSrcArea( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
912 Pixmap pixmap, GC gc, RECT *visRectSrc )
914 XImage *imageSrc, *imageDst;
917 INT width = visRectSrc->right - visRectSrc->left;
918 INT height = visRectSrc->bottom - visRectSrc->top;
920 BOOL memdc = (GetObjectType(physDevSrc->hdc) == OBJ_MEMDC);
922 if (physDevSrc->depth == physDevDst->depth)
925 if (!X11DRV_PALETTE_XPixelToPalette ||
926 (physDevDst->depth == 1)) /* monochrome -> monochrome */
928 if (physDevDst->depth == 1)
930 /* MSDN says if StretchBlt must convert a bitmap from monochrome
931 to color or vice versa, the foreground and background color of
932 the device context are used. In fact, it also applies to the
933 case when it is converted from mono to mono. */
934 XSetBackground( gdi_display, gc, physDevDst->textPixel );
935 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
936 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
937 physDevSrc->dc_rect.left + visRectSrc->left,
938 physDevSrc->dc_rect.top + visRectSrc->top,
939 width, height, 0, 0, 1);
942 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
943 physDevSrc->dc_rect.left + visRectSrc->left,
944 physDevSrc->dc_rect.top + visRectSrc->top,
945 width, height, 0, 0);
948 else /* color -> color */
951 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
952 physDevSrc->dc_rect.left + visRectSrc->left,
953 physDevSrc->dc_rect.top + visRectSrc->top,
954 width, height, AllPlanes, ZPixmap );
957 /* Make sure we don't get a BadMatch error */
958 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
959 physDevSrc->dc_rect.left + visRectSrc->left,
960 physDevSrc->dc_rect.top + visRectSrc->top,
961 width, height, 0, 0);
963 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
964 AllPlanes, ZPixmap );
966 for (y = 0; y < height; y++)
967 for (x = 0; x < width; x++)
968 XPutPixel(imageSrc, x, y,
969 X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
970 XPutImage( gdi_display, pixmap, gc, imageSrc,
971 0, 0, 0, 0, width, height );
972 XDestroyImage( imageSrc );
978 if (physDevSrc->depth == 1) /* monochrome -> color */
980 get_colors(physDevDst, physDevSrc, &fg, &bg);
983 if (X11DRV_PALETTE_XPixelToPalette)
985 XSetBackground( gdi_display, gc,
986 X11DRV_PALETTE_XPixelToPalette[fg] );
987 XSetForeground( gdi_display, gc,
988 X11DRV_PALETTE_XPixelToPalette[bg]);
992 XSetBackground( gdi_display, gc, fg );
993 XSetForeground( gdi_display, gc, bg );
995 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
996 physDevSrc->dc_rect.left + visRectSrc->left,
997 physDevSrc->dc_rect.top + visRectSrc->top,
998 width, height, 0, 0, 1 );
1000 wine_tsx11_unlock();
1002 else /* color -> monochrome */
1005 /* FIXME: avoid BadMatch error */
1006 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
1007 physDevSrc->dc_rect.left + visRectSrc->left,
1008 physDevSrc->dc_rect.top + visRectSrc->top,
1009 width, height, AllPlanes, ZPixmap );
1012 wine_tsx11_unlock();
1015 imageDst = X11DRV_DIB_CreateXImage( width, height, physDevDst->depth );
1018 XDestroyImage(imageSrc);
1019 wine_tsx11_unlock();
1022 for (y = 0; y < height; y++)
1023 for (x = 0; x < width; x++)
1024 XPutPixel(imageDst, x, y, (XGetPixel(imageSrc,x,y) ==
1025 physDevSrc->backgroundPixel) );
1026 XPutImage( gdi_display, pixmap, gc, imageDst,
1027 0, 0, 0, 0, width, height );
1028 XDestroyImage( imageSrc );
1029 X11DRV_DIB_DestroyXImage( imageDst );
1030 wine_tsx11_unlock();
1037 /***********************************************************************
1040 * Retrieve an area from the destination DC, mapping all the
1041 * pixels to Windows colors.
1043 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, RECT *visRectDst)
1046 INT width = visRectDst->right - visRectDst->left;
1047 INT height = visRectDst->bottom - visRectDst->top;
1048 BOOL memdc = (GetObjectType( physDev->hdc ) == OBJ_MEMDC);
1052 if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) ||
1053 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1055 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1056 physDev->dc_rect.left + visRectDst->left, physDev->dc_rect.top + visRectDst->top,
1057 width, height, 0, 0 );
1066 image = XGetImage( gdi_display, physDev->drawable,
1067 physDev->dc_rect.left + visRectDst->left,
1068 physDev->dc_rect.top + visRectDst->top,
1069 width, height, AllPlanes, ZPixmap );
1072 /* Make sure we don't get a BadMatch error */
1073 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1074 physDev->dc_rect.left + visRectDst->left,
1075 physDev->dc_rect.top + visRectDst->top,
1076 width, height, 0, 0);
1078 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1079 AllPlanes, ZPixmap );
1083 for (y = 0; y < height; y++)
1084 for (x = 0; x < width; x++)
1085 XPutPixel( image, x, y,
1086 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1087 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1088 XDestroyImage( image );
1092 wine_tsx11_unlock();
1097 /***********************************************************************
1100 * Put an area back into the destination DC, mapping the pixel
1101 * colors to X pixels.
1103 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, RECT *visRectDst)
1106 INT width = visRectDst->right - visRectDst->left;
1107 INT height = visRectDst->bottom - visRectDst->top;
1109 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1111 if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) ||
1112 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1114 XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1115 physDev->dc_rect.left + visRectDst->left,
1116 physDev->dc_rect.top + visRectDst->top );
1122 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1123 AllPlanes, ZPixmap );
1124 for (y = 0; y < height; y++)
1125 for (x = 0; x < width; x++)
1127 XPutPixel( image, x, y,
1128 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1130 XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1131 physDev->dc_rect.left + visRectDst->left,
1132 physDev->dc_rect.top + visRectDst->top, width, height );
1133 XDestroyImage( image );
1139 /***********************************************************************
1140 * BITBLT_GetVisRectangles
1142 * Get the source and destination visible rectangles for StretchBlt().
1143 * Return FALSE if one of the rectangles is empty.
1145 static BOOL BITBLT_GetVisRectangles( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1146 INT widthDst, INT heightDst,
1147 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1148 INT widthSrc, INT heightSrc,
1149 RECT *visRectSrc, RECT *visRectDst )
1151 RECT rect, clipRect;
1153 /* Get the destination visible rectangle */
1157 rect.right = xDst + widthDst;
1158 rect.bottom = yDst + heightDst;
1159 if (widthDst < 0) SWAP_INT32( &rect.left, &rect.right );
1160 if (heightDst < 0) SWAP_INT32( &rect.top, &rect.bottom );
1161 GetRgnBox( physDevDst->region, &clipRect );
1162 if (!IntersectRect( visRectDst, &rect, &clipRect )) return FALSE;
1164 /* Get the source visible rectangle */
1166 if (!physDevSrc) return TRUE;
1169 rect.right = xSrc + widthSrc;
1170 rect.bottom = ySrc + heightSrc;
1171 if (widthSrc < 0) SWAP_INT32( &rect.left, &rect.right );
1172 if (heightSrc < 0) SWAP_INT32( &rect.top, &rect.bottom );
1173 /* Apparently the clipping and visible regions are only for output,
1174 so just check against dc extent here to avoid BadMatch errors */
1175 clipRect = physDevSrc->drawable_rect;
1176 OffsetRect( &clipRect, -(physDevSrc->drawable_rect.left + physDevSrc->dc_rect.left),
1177 -(physDevSrc->drawable_rect.top + physDevSrc->dc_rect.top) );
1178 if (!IntersectRect( visRectSrc, &rect, &clipRect ))
1181 /* Intersect the rectangles */
1183 if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1185 visRectSrc->left += xDst - xSrc;
1186 visRectSrc->right += xDst - xSrc;
1187 visRectSrc->top += yDst - ySrc;
1188 visRectSrc->bottom += yDst - ySrc;
1189 if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1190 *visRectSrc = *visRectDst = rect;
1191 visRectSrc->left += xSrc - xDst;
1192 visRectSrc->right += xSrc - xDst;
1193 visRectSrc->top += ySrc - yDst;
1194 visRectSrc->bottom += ySrc - yDst;
1196 else /* stretching */
1198 /* Map source rectangle into destination coordinates */
1199 rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1200 rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1201 rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1202 rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1203 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1204 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1206 /* Avoid rounding errors */
1211 if (!IntersectRect( visRectDst, &rect, visRectDst )) return FALSE;
1213 /* Map destination rectangle back to source coordinates */
1215 rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1216 rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1217 rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1218 rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1219 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1220 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1222 /* Avoid rounding errors */
1227 if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1233 /***********************************************************************
1234 * client_side_dib_copy
1236 static BOOL client_side_dib_copy( X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1237 X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1238 INT width, INT height )
1240 DIBSECTION srcDib, dstDib;
1241 BYTE *srcPtr, *dstPtr;
1242 INT srcRowOffset, dstRowOffset;
1246 static RECT unusedRect;
1248 if (GetObjectW(physDevSrc->bitmap->hbitmap, sizeof(srcDib), &srcDib) != sizeof(srcDib))
1250 if (GetObjectW(physDevDst->bitmap->hbitmap, sizeof(dstDib), &dstDib) != sizeof(dstDib))
1253 /* check for oversized values, just like X11DRV_DIB_CopyDIBSection() */
1254 if (xSrc > srcDib.dsBm.bmWidth || ySrc > srcDib.dsBm.bmHeight)
1256 if (xSrc + width > srcDib.dsBm.bmWidth)
1257 width = srcDib.dsBm.bmWidth - xSrc;
1258 if (ySrc + height > srcDib.dsBm.bmHeight)
1259 height = srcDib.dsBm.bmHeight - ySrc;
1261 if (GetRgnBox(physDevDst->region, &unusedRect) == COMPLEXREGION)
1263 /* for simple regions, the clipping was already done by BITBLT_GetVisRectangles */
1264 FIXME("potential optimization: client-side complex region clipping\n");
1267 if (dstDib.dsBm.bmBitsPixel <= 8)
1269 FIXME("potential optimization: client-side color-index mode DIB copy\n");
1272 if (!(srcDib.dsBmih.biCompression == BI_BITFIELDS &&
1273 dstDib.dsBmih.biCompression == BI_BITFIELDS &&
1274 !memcmp(srcDib.dsBitfields, dstDib.dsBitfields, 3*sizeof(DWORD)))
1275 && !(srcDib.dsBmih.biCompression == BI_RGB &&
1276 dstDib.dsBmih.biCompression == BI_RGB))
1278 FIXME("potential optimization: client-side compressed DIB copy\n");
1281 if (srcDib.dsBm.bmBitsPixel != dstDib.dsBm.bmBitsPixel)
1283 FIXME("potential optimization: pixel format conversion\n");
1286 if (srcDib.dsBmih.biWidth < 0 || dstDib.dsBmih.biWidth < 0)
1288 FIXME("negative widths not yet implemented\n");
1292 switch (dstDib.dsBm.bmBitsPixel)
1305 FIXME("don't know how to work with a depth of %d\n", physDevSrc->depth);
1309 bytesToCopy = width * bytesPerPixel;
1311 if (srcDib.dsBmih.biHeight < 0)
1313 srcPtr = &physDevSrc->bitmap->base[ySrc*srcDib.dsBm.bmWidthBytes + xSrc*bytesPerPixel];
1314 srcRowOffset = srcDib.dsBm.bmWidthBytes;
1318 srcPtr = &physDevSrc->bitmap->base[(srcDib.dsBm.bmHeight-ySrc-1)*srcDib.dsBm.bmWidthBytes
1319 + xSrc*bytesPerPixel];
1320 srcRowOffset = -srcDib.dsBm.bmWidthBytes;
1322 if (dstDib.dsBmih.biHeight < 0)
1324 dstPtr = &physDevDst->bitmap->base[yDst*dstDib.dsBm.bmWidthBytes + xDst*bytesPerPixel];
1325 dstRowOffset = dstDib.dsBm.bmWidthBytes;
1329 dstPtr = &physDevDst->bitmap->base[(dstDib.dsBm.bmHeight-yDst-1)*dstDib.dsBm.bmWidthBytes
1330 + xDst*bytesPerPixel];
1331 dstRowOffset = -dstDib.dsBm.bmWidthBytes;
1334 /* Handle overlapping regions on the same DIB */
1335 if (physDevSrc == physDevDst && ySrc < yDst)
1337 srcPtr += srcRowOffset * (height - 1);
1338 srcRowOffset = -srcRowOffset;
1339 dstPtr += dstRowOffset * (height - 1);
1340 dstRowOffset = -dstRowOffset;
1343 for (y = yDst; y < yDst + height; ++y)
1345 memmove(dstPtr, srcPtr, bytesToCopy);
1346 srcPtr += srcRowOffset;
1347 dstPtr += dstRowOffset;
1353 static BOOL same_format(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst)
1355 if (physDevSrc->depth != physDevDst->depth) return FALSE;
1356 if (!physDevSrc->color_shifts && !physDevDst->color_shifts) return TRUE;
1357 if (physDevSrc->color_shifts && physDevDst->color_shifts)
1358 return !memcmp(physDevSrc->color_shifts, physDevDst->color_shifts, sizeof(ColorShifts));
1362 /***********************************************************************
1365 BOOL CDECL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1366 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1369 BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1370 RECT visRectDst, visRectSrc;
1372 INT sDst, sSrc = DIB_Status_None;
1374 Pixmap pixmaps[3] = { 0, 0, 0 }; /* pixmaps for DST, SRC, TMP */
1378 /* compensate for off-by-one shifting for negative widths and heights */
1388 usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1389 useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1390 useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1391 if (!physDevSrc && useSrc) return FALSE;
1393 /* Map the coordinates to device coords */
1397 pts[1].x = xDst + widthDst;
1398 pts[1].y = yDst + heightDst;
1399 LPtoDP(physDevDst->hdc, pts, 2);
1402 widthDst = pts[1].x - pts[0].x;
1403 heightDst = pts[1].y - pts[0].y;
1405 TRACE(" rectdst=%d,%d-%d,%d orgdst=%d,%d\n",
1406 xDst, yDst, widthDst, heightDst,
1407 physDevDst->dc_rect.left, physDevDst->dc_rect.top );
1413 pts[1].x = xSrc + widthSrc;
1414 pts[1].y = ySrc + heightSrc;
1415 LPtoDP(physDevSrc->hdc, pts, 2);
1418 widthSrc = pts[1].x - pts[0].x;
1419 heightSrc = pts[1].y - pts[0].y;
1421 fStretch = (widthSrc != widthDst) || (heightSrc != heightDst);
1422 TRACE(" rectsrc=%d,%d-%d,%d orgsrc=%d,%d\n",
1423 xSrc, ySrc, widthSrc, heightSrc,
1424 physDevSrc->dc_rect.left, physDevSrc->dc_rect.top );
1425 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1426 physDevSrc, xSrc, ySrc, widthSrc, heightSrc,
1427 &visRectSrc, &visRectDst ))
1429 TRACE(" vissrc=%d,%d-%d,%d visdst=%d,%d-%d,%d\n",
1430 visRectSrc.left, visRectSrc.top,
1431 visRectSrc.right, visRectSrc.bottom,
1432 visRectDst.left, visRectDst.top,
1433 visRectDst.right, visRectDst.bottom );
1434 if (physDevDst != physDevSrc)
1435 sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None );
1440 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1441 NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1443 TRACE(" vissrc=none visdst=%d,%d-%d,%d\n",
1444 visRectDst.left, visRectDst.top,
1445 visRectDst.right, visRectDst.bottom );
1448 width = visRectDst.right - visRectDst.left;
1449 height = visRectDst.bottom - visRectDst.top;
1451 sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None );
1452 if (physDevDst == physDevSrc) sSrc = sDst;
1454 /* try client-side DIB copy */
1455 if (!fStretch && rop == SRCCOPY &&
1456 sSrc == DIB_Status_AppMod && sDst == DIB_Status_AppMod &&
1457 same_format(physDevSrc, physDevDst))
1459 if (client_side_dib_copy( physDevSrc, visRectSrc.left, visRectSrc.top,
1460 physDevDst, visRectDst.left, visRectDst.top, width, height ))
1464 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod );
1466 opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1468 /* a few optimizations for single-op ROPs */
1469 if (!fStretch && !opcode[1])
1471 if (OP_SRCDST(*opcode) == OP_ARGS(PAT,DST))
1473 switch(rop) /* a few special cases */
1475 case BLACKNESS: /* 0x00 */
1476 case WHITENESS: /* 0xff */
1477 if ((physDevDst->depth != 1) && X11DRV_PALETTE_PaletteToXPixel)
1480 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1481 if (rop == BLACKNESS)
1482 XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1484 XSetForeground( gdi_display, physDevDst->gc,
1485 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1486 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1487 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1488 physDevDst->dc_rect.left + visRectDst.left,
1489 physDevDst->dc_rect.top + visRectDst.top,
1491 wine_tsx11_unlock();
1495 case DSTINVERT: /* 0x55 */
1496 if (!(X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL)))
1498 /* Xor is much better when we do not have full colormap. */
1499 /* Using white^black ensures that we invert at least black */
1501 unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1502 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1504 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1505 XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1506 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1507 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1508 physDevDst->dc_rect.left + visRectDst.left,
1509 physDevDst->dc_rect.top + visRectDst.top,
1511 wine_tsx11_unlock();
1516 if (!usePat || X11DRV_SetupGCForBrush( physDevDst ))
1519 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1520 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1521 physDevDst->dc_rect.left + visRectDst.left,
1522 physDevDst->dc_rect.top + visRectDst.top,
1524 wine_tsx11_unlock();
1528 else if (OP_SRCDST(*opcode) == OP_ARGS(SRC,DST))
1530 if (same_format(physDevSrc, physDevDst))
1533 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1534 wine_tsx11_unlock();
1536 if (physDevSrc != physDevDst)
1538 if (sSrc == DIB_Status_AppMod)
1540 X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, visRectSrc.left, visRectSrc.top,
1541 visRectDst.left, visRectDst.top, width, height );
1544 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1547 XCopyArea( gdi_display, physDevSrc->drawable,
1548 physDevDst->drawable, physDevDst->gc,
1549 physDevSrc->dc_rect.left + visRectSrc.left,
1550 physDevSrc->dc_rect.top + visRectSrc.top,
1552 physDevDst->dc_rect.left + visRectDst.left,
1553 physDevDst->dc_rect.top + visRectDst.top );
1554 physDevDst->exposures++;
1555 wine_tsx11_unlock();
1558 if (physDevSrc->depth == 1)
1562 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1563 get_colors(physDevDst, physDevSrc, &fg, &bg);
1565 XSetBackground( gdi_display, physDevDst->gc, fg );
1566 XSetForeground( gdi_display, physDevDst->gc, bg );
1567 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1568 XCopyPlane( gdi_display, physDevSrc->drawable,
1569 physDevDst->drawable, physDevDst->gc,
1570 physDevSrc->dc_rect.left + visRectSrc.left,
1571 physDevSrc->dc_rect.top + visRectSrc.top,
1573 physDevDst->dc_rect.left + visRectDst.left,
1574 physDevDst->dc_rect.top + visRectDst.top, 1 );
1575 physDevDst->exposures++;
1576 wine_tsx11_unlock();
1583 tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1584 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1585 XSetGraphicsExposures( gdi_display, tmpGC, False );
1586 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1587 physDevDst->depth );
1588 wine_tsx11_unlock();
1593 pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1594 physDevDst->depth );
1595 wine_tsx11_unlock();
1597 if (physDevDst != physDevSrc) X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1599 if(!X11DRV_XRender_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1600 widthSrc, heightSrc, widthDst, heightDst,
1601 &visRectSrc, &visRectDst))
1604 BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1605 xSrc, ySrc, widthSrc, heightSrc,
1606 xDst, yDst, widthDst, heightDst,
1607 &visRectSrc, &visRectDst );
1609 BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1614 if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &visRectDst );
1615 if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1616 else fNullBrush = FALSE;
1620 for ( ; *opcode; opcode++)
1622 if (OP_DST(*opcode) == DST) destUsed = TRUE;
1623 XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1624 switch(OP_SRCDST(*opcode))
1626 case OP_ARGS(DST,TMP):
1627 case OP_ARGS(SRC,TMP):
1629 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1630 width, height, physDevDst->depth );
1632 case OP_ARGS(DST,SRC):
1633 case OP_ARGS(SRC,DST):
1634 case OP_ARGS(TMP,SRC):
1635 case OP_ARGS(TMP,DST):
1637 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1638 pixmaps[OP_DST(*opcode)], tmpGC,
1639 0, 0, width, height, 0, 0 );
1642 case OP_ARGS(PAT,TMP):
1643 if (!pixmaps[TMP] && !fNullBrush)
1644 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1645 width, height, physDevDst->depth );
1647 case OP_ARGS(PAT,DST):
1648 case OP_ARGS(PAT,SRC):
1650 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1651 tmpGC, 0, 0, width, height );
1655 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1656 physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC],
1658 XFreePixmap( gdi_display, pixmaps[DST] );
1659 if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1660 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1661 XFreeGC( gdi_display, tmpGC );
1662 wine_tsx11_unlock();
1665 if (useSrc && physDevDst != physDevSrc) X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1666 X11DRV_UnlockDIBSection( physDevDst, TRUE );