mshtml: Don't test the contents of an output parameter.
[wine/multimedia.git] / dlls / winex11.drv / bitblt.c
blob00bf37502c15743c23209676ba6486eed6063461
1 /*
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
22 #include "config.h"
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winreg.h"
33 #include "winuser.h"
34 #include "x11drv.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
40 #define DST 0 /* Destination drawable */
41 #define SRC 1 /* Source drawable */
42 #define TMP 2 /* Temporary drawable */
43 #define PAT 3 /* Pattern (brush) in destination DC */
45 #define OP(src,dst,rop) (OP_ARGS(src,dst) << 4 | (rop))
46 #define OP_ARGS(src,dst) (((src) << 2) | (dst))
48 #define OP_SRC(opcode) ((opcode) >> 6)
49 #define OP_DST(opcode) (((opcode) >> 4) & 3)
50 #define OP_SRCDST(opcode) ((opcode) >> 4)
51 #define OP_ROP(opcode) ((opcode) & 0x0f)
53 #define MAX_OP_LEN 6 /* Longest opcode + 1 for the terminating 0 */
55 #define SWAP_INT32(i1,i2) \
56 do { INT __t = *(i1); *(i1) = *(i2); *(i2) = __t; } while(0)
58 static const unsigned char BITBLT_Opcodes[256][MAX_OP_LEN] =
60 { OP(PAT,DST,GXclear) }, /* 0x00 0 */
61 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnor) }, /* 0x01 ~(D|(P|S)) */
62 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXand) }, /* 0x02 D&~(P|S) */
63 { OP(PAT,SRC,GXnor) }, /* 0x03 ~(P|S) */
64 { OP(PAT,DST,GXnor), OP(SRC,DST,GXand) }, /* 0x04 S&~(D|P) */
65 { OP(PAT,DST,GXnor) }, /* 0x05 ~(D|P) */
66 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnor), }, /* 0x06 ~(P|~(D^S)) */
67 { OP(SRC,DST,GXand), OP(PAT,DST,GXnor) }, /* 0x07 ~(P|(D&S)) */
68 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXand) },/* 0x08 S&D&~P */
69 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnor) }, /* 0x09 ~(P|(D^S)) */
70 { OP(PAT,DST,GXandInverted) }, /* 0x0a D&~P */
71 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXnor) }, /* 0x0b ~(P|(S&~D)) */
72 { OP(PAT,SRC,GXandInverted) }, /* 0x0c S&~P */
73 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXnor) },/* 0x0d ~(P|(D&~S)) */
74 { OP(SRC,DST,GXnor), OP(PAT,DST,GXnor) }, /* 0x0e ~(P|~(D|S)) */
75 { OP(PAT,DST,GXcopyInverted) }, /* 0x0f ~P */
76 { OP(SRC,DST,GXnor), OP(PAT,DST,GXand) }, /* 0x10 P&~(S|D) */
77 { OP(SRC,DST,GXnor) }, /* 0x11 ~(D|S) */
78 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnor) }, /* 0x12 ~(S|~(D^P)) */
79 { OP(PAT,DST,GXand), OP(SRC,DST,GXnor) }, /* 0x13 ~(S|(D&P)) */
80 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnor) }, /* 0x14 ~(D|~(P^S)) */
81 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnor) }, /* 0x15 ~(D|(P&S)) */
82 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
83 OP(TMP,DST,GXand), OP(SRC,DST,GXxor),
84 OP(PAT,DST,GXxor) }, /* 0x16 P^S^(D&~(P&S) */
85 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
86 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
87 OP(TMP,DST,GXequiv) }, /* 0x17 ~S^((S^P)&(S^D))*/
88 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
89 OP(SRC,DST,GXand) }, /* 0x18 (S^P)&(D^P) */
90 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
91 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x19 ~S^(D&~(P&S)) */
92 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
93 OP(PAT,DST,GXxor) }, /* 0x1a P^(D|(S&P)) */
94 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXxor),
95 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x1b ~S^(D&(P^S)) */
96 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
97 OP(PAT,DST,GXxor) }, /* 0x1c P^(S|(D&P)) */
98 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
99 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x1d ~D^(S&(D^P)) */
100 { OP(SRC,DST,GXor), OP(PAT,DST,GXxor) }, /* 0x1e P^(D|S) */
101 { OP(SRC,DST,GXor), OP(PAT,DST,GXnand) }, /* 0x1f ~(P&(D|S)) */
102 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXand) }, /* 0x20 D&(P&~S) */
103 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnor) }, /* 0x21 ~(S|(D^P)) */
104 { OP(SRC,DST,GXandInverted) }, /* 0x22 ~S&D */
105 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x23 ~(S|(P&~D)) */
106 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
107 OP(SRC,DST,GXand) }, /* 0x24 (S^P)&(S^D) */
108 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand),
109 OP(PAT,DST,GXequiv) }, /* 0x25 ~P^(D&~(S&P)) */
110 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
111 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x26 S^(D|(S&P)) */
112 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXequiv),
113 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x27 S^(D|~(P^S)) */
114 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand) }, /* 0x28 D&(P^S) */
115 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
116 OP(TMP,DST,GXor), OP(SRC,DST,GXxor),
117 OP(PAT,DST,GXequiv) }, /* 0x29 ~P^S^(D|(P&S)) */
118 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand) }, /* 0x2a D&~(P&S) */
119 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
120 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
121 OP(TMP,DST,GXequiv) }, /* 0x2b ~S^((P^S)&(P^D))*/
122 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
123 OP(SRC,DST,GXxor) }, /* 0x2c S^(P&(S|D)) */
124 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXxor) }, /* 0x2d P^(S|~D) */
125 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
126 OP(PAT,DST,GXxor) }, /* 0x2e P^(S|(D^P)) */
127 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXnand) }, /* 0x2f ~(P&(S|~D)) */
128 { OP(PAT,SRC,GXandReverse) }, /* 0x30 P&~S */
129 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXnor) },/* 0x31 ~(S|(D&~P)) */
130 { OP(SRC,DST,GXor), OP(PAT,DST,GXor),
131 OP(SRC,DST,GXxor) }, /* 0x32 S^(D|P|S) */
132 { OP(SRC,DST,GXcopyInverted) }, /* 0x33 ~S */
133 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
134 OP(SRC,DST,GXxor) }, /* 0x34 S^(P|(D&S)) */
135 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor),
136 OP(SRC,DST,GXxor) }, /* 0x35 S^(P|~(D^S)) */
137 { OP(PAT,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x36 S^(D|P) */
138 { OP(PAT,DST,GXor), OP(SRC,DST,GXnand) }, /* 0x37 ~(S&(D|P)) */
139 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
140 OP(PAT,DST,GXxor) }, /* 0x38 P^(S&(D|P)) */
141 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x39 S^(P|~D) */
142 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
143 OP(SRC,DST,GXxor) }, /* 0x3a S^(P|(D^S)) */
144 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x3b ~(S&(P|~D)) */
145 { OP(PAT,SRC,GXxor) }, /* 0x3c P^S */
146 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
147 OP(SRC,DST,GXxor) }, /* 0x3d S^(P|~(D|S)) */
148 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
149 OP(SRC,DST,GXxor) }, /* 0x3e S^(P|(D&~S)) */
150 { OP(PAT,SRC,GXnand) }, /* 0x3f ~(P&S) */
151 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXand) }, /* 0x40 P&S&~D */
152 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnor) }, /* 0x41 ~(D|(P^S)) */
153 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
154 OP(SRC,DST,GXand) }, /* 0x42 (S^D)&(P^D) */
155 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
156 OP(SRC,DST,GXequiv) }, /* 0x43 ~S^(P&~(D&S)) */
157 { OP(SRC,DST,GXandReverse) }, /* 0x44 S&~D */
158 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x45 ~(D|(P&~S)) */
159 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
160 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x46 D^(S|(P&D)) */
161 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
162 OP(PAT,DST,GXequiv) }, /* 0x47 ~P^(S&(D^P)) */
163 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand) }, /* 0x48 S&(P^D) */
164 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
165 OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
166 OP(PAT,DST,GXequiv) }, /* 0x49 ~P^D^(S|(P&D)) */
167 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
168 OP(SRC,DST,GXxor) }, /* 0x4a D^(P&(S|D)) */
169 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXxor) }, /* 0x4b P^(D|~S) */
170 { OP(PAT,DST,GXnand), OP(SRC,DST,GXand) }, /* 0x4c S&~(D&P) */
171 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
172 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
173 OP(TMP,DST,GXequiv) }, /* 0x4d ~S^((S^P)|(S^D))*/
174 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
175 OP(PAT,DST,GXxor) }, /* 0x4e P^(D|(S^P)) */
176 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXnand) },/* 0x4f ~(P&(D|~S)) */
177 { OP(PAT,DST,GXandReverse) }, /* 0x50 P&~D */
178 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXnor) },/* 0x51 ~(D|(S&~P)) */
179 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
180 OP(SRC,DST,GXxor) }, /* 0x52 D^(P|(S&D)) */
181 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
182 OP(SRC,DST,GXequiv) }, /* 0x53 ~S^(P&(D^S)) */
183 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXnor) }, /* 0x54 ~(D|~(P|S)) */
184 { OP(PAT,DST,GXinvert) }, /* 0x55 ~D */
185 { OP(PAT,SRC,GXor), OP(SRC,DST,GXxor) }, /* 0x56 D^(P|S) */
186 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnand) }, /* 0x57 ~(D&(P|S)) */
187 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
188 OP(PAT,DST,GXxor) }, /* 0x58 P^(D&(P|S)) */
189 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x59 D^(P|~S) */
190 { OP(PAT,DST,GXxor) }, /* 0x5a D^P */
191 { OP(DST,SRC,GXnor), OP(PAT,SRC,GXor),
192 OP(SRC,DST,GXxor) }, /* 0x5b D^(P|~(S|D)) */
193 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
194 OP(SRC,DST,GXxor) }, /* 0x5c D^(P|(S^D)) */
195 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x5d ~(D&(P|~S)) */
196 { OP(DST,SRC,GXandInverted), OP(PAT,SRC,GXor),
197 OP(SRC,DST,GXxor) }, /* 0x5e D^(P|(S&~D)) */
198 { OP(PAT,DST,GXnand) }, /* 0x5f ~(D&P) */
199 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand) }, /* 0x60 P&(D^S) */
200 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
201 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
202 OP(TMP,DST,GXequiv) }, /* 0x61 ~D^S^(P|(D&S)) */
203 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
204 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x62 D^(S&(P|D)) */
205 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x63 S^(D|~P) */
206 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
207 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x64 S^(D&(P|S)) */
208 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x65 D^(S|~P) */
209 { OP(SRC,DST,GXxor) }, /* 0x66 S^D */
210 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
211 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x67 S^(D|~(S|P) */
212 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnor),
213 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
214 OP(TMP,DST,GXequiv) }, /* 0x68 ~D^S^(P|~(D|S))*/
215 { OP(SRC,DST,GXxor), OP(PAT,DST,GXequiv) }, /* 0x69 ~P^(D^S) */
216 { OP(PAT,SRC,GXand), OP(SRC,DST,GXxor) }, /* 0x6a D^(P&S) */
217 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
218 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
219 OP(PAT,DST,GXequiv) }, /* 0x6b ~P^S^(D&(P|S)) */
220 { OP(PAT,DST,GXand), OP(SRC,DST,GXxor) }, /* 0x6c S^(D&P) */
221 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
222 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
223 OP(PAT,DST,GXequiv) }, /* 0x6d ~P^D^(S&(P|D)) */
224 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
225 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x6e S^(D&(P|~S)) */
226 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnand) }, /* 0x6f ~(P&~(S^D)) */
227 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand) }, /* 0x70 P&~(D&S) */
228 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
229 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
230 OP(TMP,DST,GXequiv) }, /* 0x71 ~S^((S^D)&(P^D))*/
231 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
232 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x72 S^(D|(P^S)) */
233 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXnand) },/* 0x73 ~(S&(D|~P)) */
234 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
235 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x74 D^(S|(P^D)) */
236 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXnand) },/* 0x75 ~(D&(S|~P)) */
237 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
238 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x76 S^(D|(P&~S)) */
239 { OP(SRC,DST,GXnand) }, /* 0x77 ~(S&D) */
240 { OP(SRC,DST,GXand), OP(PAT,DST,GXxor) }, /* 0x78 P^(D&S) */
241 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
242 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
243 OP(TMP,DST,GXequiv) }, /* 0x79 ~D^S^(P&(D|S)) */
244 { OP(DST,SRC,GXorInverted), OP(PAT,SRC,GXand),
245 OP(SRC,DST,GXxor) }, /* 0x7a D^(P&(S|~D)) */
246 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7b ~(S&~(D^P)) */
247 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
248 OP(SRC,DST,GXxor) }, /* 0x7c S^(P&(D|~S)) */
249 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7d ~(D&~(P^S)) */
250 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
251 OP(SRC,DST,GXor) }, /* 0x7e (S^P)|(S^D) */
252 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnand) }, /* 0x7f ~(D&P&S) */
253 { OP(PAT,SRC,GXand), OP(SRC,DST,GXand) }, /* 0x80 D&P&S */
254 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
255 OP(SRC,DST,GXnor) }, /* 0x81 ~((S^P)|(S^D)) */
256 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXand) }, /* 0x82 D&~(P^S) */
257 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
258 OP(SRC,DST,GXequiv) }, /* 0x83 ~S^(P&(D|~S)) */
259 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXand) }, /* 0x84 S&~(D^P) */
260 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand),
261 OP(PAT,DST,GXequiv) }, /* 0x85 ~P^(D&(S|~P)) */
262 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
263 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
264 OP(TMP,DST,GXxor) }, /* 0x86 D^S^(P&(D|S)) */
265 { OP(SRC,DST,GXand), OP(PAT,DST,GXequiv) }, /* 0x87 ~P^(D&S) */
266 { OP(SRC,DST,GXand) }, /* 0x88 S&D */
267 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
268 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x89 ~S^(D|(P&~S)) */
269 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8a D&(S|~P) */
270 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
271 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8b ~D^(S|(P^D)) */
272 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8c S&(D|~P) */
273 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
274 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8d ~S^(D|(P^S)) */
275 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
276 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
277 OP(TMP,DST,GXxor) }, /* 0x8e S^((S^D)&(P^D))*/
278 { OP(SRC,DST,GXnand), OP(PAT,DST,GXnand) }, /* 0x8f ~(P&~(D&S)) */
279 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXand) }, /* 0x90 P&~(D^S) */
280 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
281 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x91 ~S^(D&(P|~S)) */
282 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
283 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
284 OP(TMP,DST,GXxor) }, /* 0x92 D^P^(S&(D|P)) */
285 { OP(PAT,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x93 ~S^(P&D) */
286 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
287 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
288 OP(TMP,DST,GXxor) }, /* 0x94 S^P^(D&(P|S)) */
289 { OP(PAT,SRC,GXand), OP(SRC,DST,GXequiv) }, /* 0x95 ~D^(P&S) */
290 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXxor) }, /* 0x96 D^P^S */
291 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
292 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
293 OP(TMP,DST,GXxor) }, /* 0x97 S^P^(D|~(P|S)) */
294 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
295 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x98 ~S^(D|~(P|S)) */
296 { OP(SRC,DST,GXequiv) }, /* 0x99 ~S^D */
297 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9a D^(P&~S) */
298 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
299 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9b ~S^(D&(P|S)) */
300 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9c S^(P&~D) */
301 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
302 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9d ~D^(S&(P|D)) */
303 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
304 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
305 OP(TMP,DST,GXxor) }, /* 0x9e D^S^(P|(D&S)) */
306 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnand) }, /* 0x9f ~(P&(D^S)) */
307 { OP(PAT,DST,GXand) }, /* 0xa0 D&P */
308 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor),
309 OP(PAT,DST,GXequiv) }, /* 0xa1 ~P^(D|(S&~P)) */
310 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXand) }, /* 0xa2 D&(P|~S) */
311 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
312 OP(SRC,DST,GXequiv) }, /* 0xa3 ~D^(P|(S^D)) */
313 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor),
314 OP(PAT,DST,GXequiv) }, /* 0xa4 ~P^(D|~(S|P)) */
315 { OP(PAT,DST,GXequiv) }, /* 0xa5 ~P^D */
316 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXxor) },/* 0xa6 D^(S&~P) */
317 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
318 OP(PAT,DST,GXequiv) }, /* 0xa7 ~P^(D&(S|P)) */
319 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand) }, /* 0xa8 D&(P|S) */
320 { OP(PAT,SRC,GXor), OP(SRC,DST,GXequiv) }, /* 0xa9 ~D^(P|S) */
321 { OP(SRC,DST,GXnoop) }, /* 0xaa D */
322 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor) }, /* 0xab D|~(P|S) */
323 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
324 OP(SRC,DST,GXxor) }, /* 0xac S^(P&(D^S)) */
325 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
326 OP(SRC,DST,GXequiv) }, /* 0xad ~D^(P|(S&D)) */
327 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor) }, /* 0xae D|(S&~P) */
328 { OP(PAT,DST,GXorInverted) }, /* 0xaf D|~P */
329 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand) }, /* 0xb0 P&(D|~S) */
330 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
331 OP(PAT,DST,GXequiv) }, /* 0xb1 ~P^(D|(S^P)) */
332 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
333 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
334 OP(TMP,DST,GXxor) }, /* 0xb2 S^((S^P)|(S^D))*/
335 { OP(PAT,DST,GXnand), OP(SRC,DST,GXnand) }, /* 0xb3 ~(S&~(D&P)) */
336 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXxor) }, /* 0xb4 P^(S&~D) */
337 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
338 OP(SRC,DST,GXequiv) }, /* 0xb5 ~D^(P&(S|D)) */
339 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
340 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
341 OP(TMP,DST,GXxor) }, /* 0xb6 D^P^(S|(D&P)) */
342 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnand) }, /* 0xb7 ~(S&(D^P)) */
343 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
344 OP(PAT,DST,GXxor) }, /* 0xb8 P^(S&(D^P)) */
345 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
346 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xb9 ~D^(S|(P&D)) */
347 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXor) }, /* 0xba D|(P&~S) */
348 { OP(SRC,DST,GXorInverted) }, /* 0xbb ~S|D */
349 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
350 OP(SRC,DST,GXxor) }, /* 0xbc S^(P&~(D&S)) */
351 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
352 OP(SRC,DST,GXnand) }, /* 0xbd ~((S^D)&(P^D)) */
353 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor) }, /* 0xbe D|(P^S) */
354 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXor) }, /* 0xbf D|~(P&S) */
355 { OP(PAT,SRC,GXand) }, /* 0xc0 P&S */
356 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
357 OP(SRC,DST,GXequiv) }, /* 0xc1 ~S^(P|(D&~S)) */
358 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
359 OP(SRC,DST,GXequiv) }, /* 0xc2 ~S^(P|~(D|S)) */
360 { OP(PAT,SRC,GXequiv) }, /* 0xc3 ~P^S */
361 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXand) }, /* 0xc4 S&(P|~D) */
362 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
363 OP(SRC,DST,GXequiv) }, /* 0xc5 ~S^(P|(D^S)) */
364 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXxor) },/* 0xc6 S^(D&~P) */
365 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
366 OP(PAT,DST,GXequiv) }, /* 0xc7 ~P^(S&(D|P)) */
367 { OP(PAT,DST,GXor), OP(SRC,DST,GXand) }, /* 0xc8 S&(D|P) */
368 { OP(PAT,DST,GXor), OP(SRC,DST,GXequiv) }, /* 0xc9 ~S^(P|D) */
369 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXand),
370 OP(SRC,DST,GXxor) }, /* 0xca D^(P&(S^D)) */
371 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
372 OP(SRC,DST,GXequiv) }, /* 0xcb ~S^(P|(D&S)) */
373 { OP(SRC,DST,GXcopy) }, /* 0xcc S */
374 { OP(PAT,DST,GXnor), OP(SRC,DST,GXor) }, /* 0xcd S|~(D|P) */
375 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXor) }, /* 0xce S|(D&~P) */
376 { OP(PAT,SRC,GXorInverted) }, /* 0xcf S|~P */
377 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXand) }, /* 0xd0 P&(S|~D) */
378 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
379 OP(PAT,DST,GXequiv) }, /* 0xd1 ~P^(S|(D^P)) */
380 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXxor) },/* 0xd2 P^(D&~S) */
381 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
382 OP(SRC,DST,GXequiv) }, /* 0xd3 ~S^(P&(D|S)) */
383 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
384 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
385 OP(TMP,DST,GXxor) }, /* 0xd4 S^((S^P)&(D^P))*/
386 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXnand) }, /* 0xd5 ~(D&~(P&S)) */
387 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
388 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
389 OP(TMP,DST,GXxor) }, /* 0xd6 S^P^(D|(P&S)) */
390 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnand) }, /* 0xd7 ~(D&(P^S)) */
391 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
392 OP(PAT,DST,GXxor) }, /* 0xd8 P^(D&(S^P)) */
393 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
394 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xd9 ~S^(D|(P&S)) */
395 { OP(DST,SRC,GXnand), OP(PAT,SRC,GXand),
396 OP(SRC,DST,GXxor) }, /* 0xda D^(P&~(S&D)) */
397 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
398 OP(SRC,DST,GXnand) }, /* 0xdb ~((S^P)&(S^D)) */
399 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXor) }, /* 0xdc S|(P&~D) */
400 { OP(SRC,DST,GXorReverse) }, /* 0xdd S|~D */
401 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor) }, /* 0xde S|(D^P) */
402 { OP(PAT,DST,GXnand), OP(SRC,DST,GXor) }, /* 0xdf S|~(D&P) */
403 { OP(SRC,DST,GXor), OP(PAT,DST,GXand) }, /* 0xe0 P&(D|S) */
404 { OP(SRC,DST,GXor), OP(PAT,DST,GXequiv) }, /* 0xe1 ~P^(D|S) */
405 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
406 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe2 D^(S&(P^D)) */
407 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
408 OP(PAT,DST,GXequiv) }, /* 0xe3 ~P^(S|(D&P)) */
409 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
410 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe4 S^(D&(P^S)) */
411 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
412 OP(PAT,DST,GXequiv) }, /* 0xe5 ~P^(D|(S&P)) */
413 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
414 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe6 S^(D&~(P&S)) */
415 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
416 OP(SRC,DST,GXnand) }, /* 0xe7 ~((S^P)&(D^P)) */
417 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
418 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
419 OP(TMP,DST,GXxor) }, /* 0xe8 S^((S^P)&(S^D))*/
420 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnand),
421 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
422 OP(TMP,DST,GXequiv) }, /* 0xe9 ~D^S^(P&~(S&D))*/
423 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor) }, /* 0xea D|(P&S) */
424 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXor) }, /* 0xeb D|~(P^S) */
425 { OP(PAT,DST,GXand), OP(SRC,DST,GXor) }, /* 0xec S|(D&P) */
426 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXor) }, /* 0xed S|~(D^P) */
427 { OP(SRC,DST,GXor) }, /* 0xee S|D */
428 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXor) }, /* 0xef S|D|~P */
429 { OP(PAT,DST,GXcopy) }, /* 0xf0 P */
430 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor) }, /* 0xf1 P|~(D|S) */
431 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor) }, /* 0xf2 P|(D&~S) */
432 { OP(PAT,SRC,GXorReverse) }, /* 0xf3 P|~S */
433 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXor) }, /* 0xf4 P|(S&~D) */
434 { OP(PAT,DST,GXorReverse) }, /* 0xf5 P|~D */
435 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor) }, /* 0xf6 P|(D^S) */
436 { OP(SRC,DST,GXnand), OP(PAT,DST,GXor) }, /* 0xf7 P|~(S&D) */
437 { OP(SRC,DST,GXand), OP(PAT,DST,GXor) }, /* 0xf8 P|(D&S) */
438 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor) }, /* 0xf9 P|~(D^S) */
439 { OP(PAT,DST,GXor) }, /* 0xfa D|P */
440 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXor) }, /* 0xfb D|P|~S */
441 { OP(PAT,SRC,GXor) }, /* 0xfc P|S */
442 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXor) }, /* 0xfd P|S|~D */
443 { OP(SRC,DST,GXor), OP(PAT,DST,GXor) }, /* 0xfe P|D|S */
444 { OP(PAT,DST,GXset) } /* 0xff 1 */
448 #ifdef BITBLT_TEST /* Opcodes test */
450 static int do_bitop( int s, int d, int rop )
452 int res;
453 switch(rop)
455 case GXclear: res = 0; break;
456 case GXand: res = s & d; break;
457 case GXandReverse: res = s & ~d; break;
458 case GXcopy: res = s; break;
459 case GXandInverted: res = ~s & d; break;
460 case GXnoop: res = d; break;
461 case GXxor: res = s ^ d; break;
462 case GXor: res = s | d; break;
463 case GXnor: res = ~(s | d); break;
464 case GXequiv: res = ~s ^ d; break;
465 case GXinvert: res = ~d; break;
466 case GXorReverse: res = s | ~d; break;
467 case GXcopyInverted: res = ~s; break;
468 case GXorInverted: res = ~s | d; break;
469 case GXnand: res = ~(s & d); break;
470 case GXset: res = 1; break;
472 return res & 1;
475 int main()
477 int rop, i, res, src, dst, pat, tmp, dstUsed;
478 const BYTE *opcode;
480 for (rop = 0; rop < 256; rop++)
482 res = dstUsed = 0;
483 for (i = 0; i < 8; i++)
485 pat = (i >> 2) & 1;
486 src = (i >> 1) & 1;
487 dst = i & 1;
488 for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
490 switch(*opcode >> 4)
492 case OP_ARGS(DST,TMP):
493 tmp = do_bitop( dst, tmp, *opcode & 0xf );
494 break;
495 case OP_ARGS(DST,SRC):
496 src = do_bitop( dst, src, *opcode & 0xf );
497 break;
498 case OP_ARGS(SRC,TMP):
499 tmp = do_bitop( src, tmp, *opcode & 0xf );
500 break;
501 case OP_ARGS(SRC,DST):
502 dst = do_bitop( src, dst, *opcode & 0xf );
503 dstUsed = 1;
504 break;
505 case OP_ARGS(PAT,TMP):
506 tmp = do_bitop( pat, tmp, *opcode & 0xf );
507 break;
508 case OP_ARGS(PAT,DST):
509 dst = do_bitop( pat, dst, *opcode & 0xf );
510 dstUsed = 1;
511 break;
512 case OP_ARGS(PAT,SRC):
513 src = do_bitop( pat, src, *opcode & 0xf );
514 break;
515 case OP_ARGS(TMP,DST):
516 dst = do_bitop( tmp, dst, *opcode & 0xf );
517 dstUsed = 1;
518 break;
519 case OP_ARGS(TMP,SRC):
520 src = do_bitop( tmp, src, *opcode & 0xf );
521 break;
522 default:
523 printf( "Invalid opcode %x\n", *opcode );
526 if (!dstUsed) dst = src;
527 if (dst) res |= 1 << i;
529 if (res != rop) printf( "%02x: ERROR, res=%02x\n", rop, res );
532 return 0;
535 #endif /* BITBLT_TEST */
538 static void get_colors(X11DRV_PDEVICE *physDevDst, X11DRV_PDEVICE *physDevSrc,
539 int *fg, int *bg)
541 RGBQUAD rgb[2];
543 *fg = physDevDst->textPixel;
544 *bg = physDevDst->backgroundPixel;
545 if(physDevSrc->depth == 1) {
546 if(GetDIBColorTable(physDevSrc->hdc, 0, 2, rgb) == 2) {
547 DWORD logcolor;
548 logcolor = RGB(rgb[0].rgbRed, rgb[0].rgbGreen, rgb[0].rgbBlue);
549 *fg = X11DRV_PALETTE_ToPhysical( physDevDst, logcolor );
550 logcolor = RGB(rgb[1].rgbRed, rgb[1].rgbGreen,rgb[1].rgbBlue);
551 *bg = X11DRV_PALETTE_ToPhysical( physDevDst, logcolor );
556 /***********************************************************************
557 * BITBLT_StretchRow
559 * Stretch a row of pixels. Helper function for BITBLT_StretchImage.
561 static void BITBLT_StretchRow( int *rowSrc, int *rowDst,
562 INT startDst, INT widthDst,
563 INT xinc, INT xoff, WORD mode )
565 register INT xsrc = xinc * startDst + xoff;
566 rowDst += startDst;
567 switch(mode)
569 case STRETCH_ANDSCANS:
570 for(; widthDst > 0; widthDst--, xsrc += xinc)
571 *rowDst++ &= rowSrc[xsrc >> 16];
572 break;
573 case STRETCH_ORSCANS:
574 for(; widthDst > 0; widthDst--, xsrc += xinc)
575 *rowDst++ |= rowSrc[xsrc >> 16];
576 break;
577 case STRETCH_DELETESCANS:
578 for(; widthDst > 0; widthDst--, xsrc += xinc)
579 *rowDst++ = rowSrc[xsrc >> 16];
580 break;
585 /***********************************************************************
586 * BITBLT_ShrinkRow
588 * Shrink a row of pixels. Helper function for BITBLT_StretchImage.
590 static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst,
591 INT startSrc, INT widthSrc,
592 INT xinc, INT xoff, WORD mode )
594 register INT xdst = xinc * startSrc + xoff;
595 rowSrc += startSrc;
596 switch(mode)
598 case STRETCH_ORSCANS:
599 for(; widthSrc > 0; widthSrc--, xdst += xinc)
600 rowDst[xdst >> 16] |= *rowSrc++;
601 break;
602 case STRETCH_ANDSCANS:
603 for(; widthSrc > 0; widthSrc--, xdst += xinc)
604 rowDst[xdst >> 16] &= *rowSrc++;
605 break;
606 case STRETCH_DELETESCANS:
607 for(; widthSrc > 0; widthSrc--, xdst += xinc)
608 rowDst[xdst >> 16] = *rowSrc++;
609 break;
614 /***********************************************************************
615 * BITBLT_GetRow
617 * Retrieve a row from an image. Helper function for BITBLT_StretchImage.
619 static void BITBLT_GetRow( XImage *image, int *pdata, INT row,
620 INT start, INT width, INT depthDst,
621 int fg, int bg, BOOL swap)
623 register INT i;
625 assert( (row >= 0) && (row < image->height) );
626 assert( (start >= 0) && (width <= image->width) );
628 pdata += swap ? start+width-1 : start;
629 if (image->depth == depthDst) /* color -> color */
631 if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1))
632 if (swap) for (i = 0; i < width; i++)
633 *pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
634 else for (i = 0; i < width; i++)
635 *pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
636 else
637 if (swap) for (i = 0; i < width; i++)
638 *pdata-- = XGetPixel( image, i, row );
639 else for (i = 0; i < width; i++)
640 *pdata++ = XGetPixel( image, i, row );
642 else
644 if (image->depth == 1) /* monochrome -> color */
646 if (X11DRV_PALETTE_XPixelToPalette)
648 fg = X11DRV_PALETTE_XPixelToPalette[fg];
649 bg = X11DRV_PALETTE_XPixelToPalette[bg];
651 if (swap) for (i = 0; i < width; i++)
652 *pdata-- = XGetPixel( image, i, row ) ? bg : fg;
653 else for (i = 0; i < width; i++)
654 *pdata++ = XGetPixel( image, i, row ) ? bg : fg;
656 else /* color -> monochrome */
658 if (swap) for (i = 0; i < width; i++)
659 *pdata-- = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
660 else for (i = 0; i < width; i++)
661 *pdata++ = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
667 /***********************************************************************
668 * BITBLT_StretchImage
670 * Stretch an X image.
671 * FIXME: does not work for full 32-bit coordinates.
673 static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage,
674 INT widthSrc, INT heightSrc,
675 INT widthDst, INT heightDst,
676 RECT *visRectSrc, RECT *visRectDst,
677 int foreground, int background, WORD mode )
679 int *rowSrc, *rowDst, *pixel;
680 char *pdata;
681 INT xinc, xoff, yinc, ysrc, ydst;
682 register INT x, y;
683 BOOL hstretch, vstretch, hswap, vswap;
685 hswap = ((int)widthSrc * widthDst) < 0;
686 vswap = ((int)heightSrc * heightDst) < 0;
687 widthSrc = abs(widthSrc);
688 heightSrc = abs(heightSrc);
689 widthDst = abs(widthDst);
690 heightDst = abs(heightDst);
692 if (!(rowSrc = HeapAlloc( GetProcessHeap(), 0,
693 (widthSrc+widthDst)*sizeof(int) ))) return;
694 rowDst = rowSrc + widthSrc;
696 /* When stretching, all modes are the same, and DELETESCANS is faster */
697 if ((widthSrc < widthDst) && (heightSrc < heightDst))
698 mode = STRETCH_DELETESCANS;
700 if (mode == STRETCH_HALFTONE) /* FIXME */
701 mode = STRETCH_DELETESCANS;
703 if (mode != STRETCH_DELETESCANS)
704 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
705 widthDst*sizeof(int) );
707 hstretch = (widthSrc < widthDst);
708 vstretch = (heightSrc < heightDst);
710 if (hstretch)
712 xinc = ((int)widthSrc << 16) / widthDst;
713 xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
715 else
717 xinc = ((int)widthDst << 16) / widthSrc;
718 xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
721 if (vstretch)
723 yinc = ((int)heightSrc << 16) / heightDst;
724 ydst = visRectDst->top;
725 if (vswap)
727 ysrc = yinc * (heightDst - ydst - 1);
728 yinc = -yinc;
730 else
731 ysrc = yinc * ydst;
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
741 : visRectSrc->left,
742 visRectSrc->right - visRectSrc->left,
743 dstImage->depth, foreground, background, hswap );
745 /* Stretch or shrink it */
746 if (hstretch)
747 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
748 visRectDst->right - visRectDst->left,
749 xinc, xoff, mode );
750 else BITBLT_ShrinkRow( rowSrc, rowDst,
751 hswap ? widthSrc - visRectSrc->right
752 : visRectSrc->left,
753 visRectSrc->right - visRectSrc->left,
754 xinc, xoff, mode );
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;
774 ysrc += yinc;
775 ydst++;
779 else /* Shrinking */
781 yinc = ((int)heightDst << 16) / heightSrc;
782 ysrc = visRectSrc->top;
783 ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
784 if (vswap)
786 ydst += yinc * (heightSrc - ysrc - 1);
787 yinc = -yinc;
789 else
790 ydst += yinc * ysrc;
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
800 : visRectSrc->left,
801 visRectSrc->right - visRectSrc->left,
802 dstImage->depth, foreground, background, hswap );
804 /* Stretch or shrink it */
805 if (hstretch)
806 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
807 visRectDst->right - visRectDst->left,
808 xinc, xoff, mode );
809 else BITBLT_ShrinkRow( rowSrc, rowDst,
810 hswap ? widthSrc - visRectSrc->right
811 : visRectSrc->left,
812 visRectSrc->right - visRectSrc->left,
813 xinc, xoff, mode );
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))
822 ydst += yinc;
823 ysrc++;
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) );
840 HeapFree( GetProcessHeap(), 0, rowSrc );
844 /***********************************************************************
845 * BITBLT_GetSrcAreaStretch
847 * Retrieve an area from the source DC, stretching and mapping all the
848 * pixels to Windows colors.
850 static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
851 Pixmap pixmap, GC gc,
852 INT xSrc, INT ySrc,
853 INT widthSrc, INT heightSrc,
854 INT xDst, INT yDst,
855 INT widthDst, INT heightDst,
856 RECT *visRectSrc, RECT *visRectDst )
858 XImage *imageSrc, *imageDst;
859 RECT rectSrc = *visRectSrc;
860 RECT rectDst = *visRectDst;
861 int fg, bg;
863 if (widthSrc < 0) xSrc += widthSrc;
864 if (widthDst < 0) xDst += widthDst;
865 if (heightSrc < 0) ySrc += heightSrc;
866 if (heightDst < 0) yDst += heightDst;
867 rectSrc.left -= xSrc;
868 rectSrc.right -= xSrc;
869 rectSrc.top -= ySrc;
870 rectSrc.bottom -= ySrc;
871 rectDst.left -= xDst;
872 rectDst.right -= xDst;
873 rectDst.top -= yDst;
874 rectDst.bottom -= yDst;
876 get_colors(physDevDst, physDevSrc, &fg, &bg);
877 /* FIXME: avoid BadMatch errors */
878 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
879 physDevSrc->dc_rect.left + visRectSrc->left,
880 physDevSrc->dc_rect.top + visRectSrc->top,
881 visRectSrc->right - visRectSrc->left,
882 visRectSrc->bottom - visRectSrc->top,
883 AllPlanes, ZPixmap );
884 imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
885 rectDst.bottom - rectDst.top, physDevDst->depth );
886 BITBLT_StretchImage( imageSrc, imageDst, widthSrc, heightSrc,
887 widthDst, heightDst, &rectSrc, &rectDst,
888 fg, physDevDst->depth != 1 ?
889 bg : physDevSrc->backgroundPixel,
890 GetStretchBltMode(physDevDst->hdc) );
891 XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
892 rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
893 XDestroyImage( imageSrc );
894 XDestroyImage( imageDst );
895 return 0; /* no exposure events generated */
899 /***********************************************************************
900 * BITBLT_GetSrcArea
902 * Retrieve an area from the source DC, mapping all the
903 * pixels to Windows colors.
905 static int BITBLT_GetSrcArea( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
906 Pixmap pixmap, GC gc, INT xSrc, INT ySrc, RECT *visRectSrc )
908 XImage *imageSrc, *imageDst;
909 register INT x, y;
910 int exposures = 0;
911 INT width = visRectSrc->right - visRectSrc->left;
912 INT height = visRectSrc->bottom - visRectSrc->top;
913 int fg, bg;
915 if (physDevSrc->depth == physDevDst->depth)
917 if (!X11DRV_PALETTE_XPixelToPalette ||
918 (physDevDst->depth == 1)) /* monochrome -> monochrome */
920 if (physDevDst->depth == 1)
922 /* MSDN says if StretchBlt must convert a bitmap from monochrome
923 to color or vice versa, the forground and background color of
924 the device context are used. In fact, it also applies to the
925 case when it is converted from mono to mono. */
926 XSetBackground( gdi_display, gc, physDevDst->textPixel );
927 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
928 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
929 physDevSrc->dc_rect.left + visRectSrc->left,
930 physDevSrc->dc_rect.top + visRectSrc->top,
931 width, height, 0, 0, 1);
933 else
934 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
935 physDevSrc->dc_rect.left + visRectSrc->left,
936 physDevSrc->dc_rect.top + visRectSrc->top,
937 width, height, 0, 0);
938 exposures++;
940 else /* color -> color */
942 if (GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
943 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
944 physDevSrc->dc_rect.left + visRectSrc->left,
945 physDevSrc->dc_rect.top + visRectSrc->top,
946 width, height, AllPlanes, ZPixmap );
947 else
949 /* Make sure we don't get a BadMatch error */
950 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
951 physDevSrc->dc_rect.left + visRectSrc->left,
952 physDevSrc->dc_rect.top + visRectSrc->top,
953 width, height, 0, 0);
954 exposures++;
955 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
956 AllPlanes, ZPixmap );
958 for (y = 0; y < height; y++)
959 for (x = 0; x < width; x++)
960 XPutPixel(imageSrc, x, y,
961 X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
962 XPutImage( gdi_display, pixmap, gc, imageSrc,
963 0, 0, 0, 0, width, height );
964 XDestroyImage( imageSrc );
967 else
969 if (physDevSrc->depth == 1) /* monochrome -> color */
971 get_colors(physDevDst, physDevSrc, &fg, &bg);
973 if (X11DRV_PALETTE_XPixelToPalette)
975 XSetBackground( gdi_display, gc,
976 X11DRV_PALETTE_XPixelToPalette[fg] );
977 XSetForeground( gdi_display, gc,
978 X11DRV_PALETTE_XPixelToPalette[bg]);
980 else
982 XSetBackground( gdi_display, gc, fg );
983 XSetForeground( gdi_display, gc, bg );
985 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
986 physDevSrc->dc_rect.left + visRectSrc->left,
987 physDevSrc->dc_rect.top + visRectSrc->top,
988 width, height, 0, 0, 1 );
989 exposures++;
991 else /* color -> monochrome */
993 /* FIXME: avoid BadMatch error */
994 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
995 physDevSrc->dc_rect.left + visRectSrc->left,
996 physDevSrc->dc_rect.top + visRectSrc->top,
997 width, height, AllPlanes, ZPixmap );
998 if (!imageSrc)
1000 return exposures;
1002 imageDst = X11DRV_DIB_CreateXImage( width, height, physDevDst->depth );
1003 if (!imageDst)
1005 XDestroyImage(imageSrc);
1006 return exposures;
1008 for (y = 0; y < height; y++)
1009 for (x = 0; x < width; x++)
1010 XPutPixel(imageDst, x, y, (XGetPixel(imageSrc,x,y) ==
1011 physDevSrc->backgroundPixel) );
1012 XPutImage( gdi_display, pixmap, gc, imageDst,
1013 0, 0, 0, 0, width, height );
1014 XDestroyImage( imageSrc );
1015 XDestroyImage( imageDst );
1018 return exposures;
1022 /***********************************************************************
1023 * BITBLT_GetDstArea
1025 * Retrieve an area from the destination DC, mapping all the
1026 * pixels to Windows colors.
1028 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, RECT *visRectDst)
1030 int exposures = 0;
1031 INT width = visRectDst->right - visRectDst->left;
1032 INT height = visRectDst->bottom - visRectDst->top;
1034 if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) ||
1035 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1037 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1038 physDev->dc_rect.left + visRectDst->left, physDev->dc_rect.top + visRectDst->top,
1039 width, height, 0, 0 );
1040 exposures++;
1042 else
1044 register INT x, y;
1045 XImage *image;
1047 if (GetObjectType( physDev->hdc ) == OBJ_MEMDC)
1048 image = XGetImage( gdi_display, physDev->drawable,
1049 physDev->dc_rect.left + visRectDst->left,
1050 physDev->dc_rect.top + visRectDst->top,
1051 width, height, AllPlanes, ZPixmap );
1052 else
1054 /* Make sure we don't get a BadMatch error */
1055 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1056 physDev->dc_rect.left + visRectDst->left,
1057 physDev->dc_rect.top + visRectDst->top,
1058 width, height, 0, 0);
1059 exposures++;
1060 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1061 AllPlanes, ZPixmap );
1063 for (y = 0; y < height; y++)
1064 for (x = 0; x < width; x++)
1065 XPutPixel( image, x, y,
1066 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1067 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1068 XDestroyImage( image );
1070 return exposures;
1074 /***********************************************************************
1075 * BITBLT_PutDstArea
1077 * Put an area back into the destination DC, mapping the pixel
1078 * colors to X pixels.
1080 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, RECT *visRectDst)
1082 int exposures = 0;
1083 INT width = visRectDst->right - visRectDst->left;
1084 INT height = visRectDst->bottom - visRectDst->top;
1086 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1088 if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) ||
1089 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1091 XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1092 physDev->dc_rect.left + visRectDst->left,
1093 physDev->dc_rect.top + visRectDst->top );
1094 exposures++;
1096 else
1098 register INT x, y;
1099 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1100 AllPlanes, ZPixmap );
1101 for (y = 0; y < height; y++)
1102 for (x = 0; x < width; x++)
1104 XPutPixel( image, x, y,
1105 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1107 XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1108 physDev->dc_rect.left + visRectDst->left,
1109 physDev->dc_rect.top + visRectDst->top, width, height );
1110 XDestroyImage( image );
1112 return exposures;
1116 /***********************************************************************
1117 * BITBLT_GetVisRectangles
1119 * Get the source and destination visible rectangles for StretchBlt().
1120 * Return FALSE if one of the rectangles is empty.
1122 static BOOL BITBLT_GetVisRectangles( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1123 INT widthDst, INT heightDst,
1124 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1125 INT widthSrc, INT heightSrc,
1126 RECT *visRectSrc, RECT *visRectDst )
1128 RECT rect, clipRect;
1130 /* Get the destination visible rectangle */
1132 rect.left = xDst;
1133 rect.top = yDst;
1134 rect.right = xDst + widthDst;
1135 rect.bottom = yDst + heightDst;
1136 if (widthDst < 0) SWAP_INT32( &rect.left, &rect.right );
1137 if (heightDst < 0) SWAP_INT32( &rect.top, &rect.bottom );
1138 GetRgnBox( physDevDst->region, &clipRect );
1139 if (!IntersectRect( visRectDst, &rect, &clipRect )) return FALSE;
1141 /* Get the source visible rectangle */
1143 if (!physDevSrc) return TRUE;
1144 rect.left = xSrc;
1145 rect.top = ySrc;
1146 rect.right = xSrc + widthSrc;
1147 rect.bottom = ySrc + heightSrc;
1148 if (widthSrc < 0) SWAP_INT32( &rect.left, &rect.right );
1149 if (heightSrc < 0) SWAP_INT32( &rect.top, &rect.bottom );
1150 /* Apparently the clipping and visible regions are only for output,
1151 so just check against dc extent here to avoid BadMatch errors */
1152 clipRect = physDevSrc->drawable_rect;
1153 OffsetRect( &clipRect, -(physDevSrc->drawable_rect.left + physDevSrc->dc_rect.left),
1154 -(physDevSrc->drawable_rect.top + physDevSrc->dc_rect.top) );
1155 if (!IntersectRect( visRectSrc, &rect, &clipRect ))
1156 return FALSE;
1158 /* Intersect the rectangles */
1160 if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1162 visRectSrc->left += xDst - xSrc;
1163 visRectSrc->right += xDst - xSrc;
1164 visRectSrc->top += yDst - ySrc;
1165 visRectSrc->bottom += yDst - ySrc;
1166 if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1167 *visRectSrc = *visRectDst = rect;
1168 visRectSrc->left += xSrc - xDst;
1169 visRectSrc->right += xSrc - xDst;
1170 visRectSrc->top += ySrc - yDst;
1171 visRectSrc->bottom += ySrc - yDst;
1173 else /* stretching */
1175 /* Map source rectangle into destination coordinates */
1176 rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1177 rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1178 rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1179 rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1180 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1181 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1183 /* Avoid rounding errors */
1184 rect.left--;
1185 rect.top--;
1186 rect.right++;
1187 rect.bottom++;
1188 if (!IntersectRect( visRectDst, &rect, visRectDst )) return FALSE;
1190 /* Map destination rectangle back to source coordinates */
1191 rect = *visRectDst;
1192 rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1193 rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1194 rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1195 rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1196 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1197 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1199 /* Avoid rounding errors */
1200 rect.left--;
1201 rect.top--;
1202 rect.right++;
1203 rect.bottom++;
1204 if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1206 return TRUE;
1210 /***********************************************************************
1211 * BITBLT_InternalStretchBlt
1213 * Implementation of PatBlt(), BitBlt() and StretchBlt().
1215 static BOOL BITBLT_InternalStretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1216 INT widthDst, INT heightDst,
1217 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1218 INT widthSrc, INT heightSrc,
1219 DWORD rop )
1221 BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1222 RECT visRectDst, visRectSrc;
1223 INT width, height;
1224 const BYTE *opcode;
1225 Pixmap pixmaps[3] = { 0, 0, 0 }; /* pixmaps for DST, SRC, TMP */
1226 GC tmpGC = 0;
1227 POINT pts[2];
1229 /* compensate for off-by-one shifting for negative widths and heights */
1230 if (widthDst < 0)
1231 ++xDst;
1232 if (heightDst < 0)
1233 ++yDst;
1234 if (widthSrc < 0)
1235 ++xSrc;
1236 if (heightSrc < 0)
1237 ++ySrc;
1239 usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1240 useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1241 useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1242 if (!physDevSrc && useSrc) return FALSE;
1244 /* Map the coordinates to device coords */
1246 pts[0].x = xDst;
1247 pts[0].y = yDst;
1248 pts[1].x = xDst + widthDst;
1249 pts[1].y = yDst + heightDst;
1250 LPtoDP(physDevDst->hdc, pts, 2);
1251 xDst = pts[0].x;
1252 yDst = pts[0].y;
1253 widthDst = pts[1].x - pts[0].x;
1254 heightDst = pts[1].y - pts[0].y;
1256 TRACE(" rectdst=%d,%d-%d,%d orgdst=%d,%d\n",
1257 xDst, yDst, widthDst, heightDst,
1258 physDevDst->dc_rect.left, physDevDst->dc_rect.top );
1260 if (useSrc)
1262 pts[0].x = xSrc;
1263 pts[0].y = ySrc;
1264 pts[1].x = xSrc + widthSrc;
1265 pts[1].y = ySrc + heightSrc;
1266 LPtoDP(physDevSrc->hdc, pts, 2);
1267 xSrc = pts[0].x;
1268 ySrc = pts[0].y;
1269 widthSrc = pts[1].x - pts[0].x;
1270 heightSrc = pts[1].y - pts[0].y;
1272 fStretch = (widthSrc != widthDst) || (heightSrc != heightDst);
1273 TRACE(" rectsrc=%d,%d-%d,%d orgsrc=%d,%d\n",
1274 xSrc, ySrc, widthSrc, heightSrc,
1275 physDevSrc->dc_rect.left, physDevSrc->dc_rect.top );
1276 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1277 physDevSrc, xSrc, ySrc, widthSrc, heightSrc,
1278 &visRectSrc, &visRectDst ))
1279 return TRUE;
1280 TRACE(" vissrc=%d,%d-%d,%d visdst=%d,%d-%d,%d\n",
1281 visRectSrc.left, visRectSrc.top,
1282 visRectSrc.right, visRectSrc.bottom,
1283 visRectDst.left, visRectDst.top,
1284 visRectDst.right, visRectDst.bottom );
1286 else
1288 fStretch = FALSE;
1289 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1290 NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1291 return TRUE;
1292 TRACE(" vissrc=none visdst=%d,%d-%d,%d\n",
1293 visRectDst.left, visRectDst.top,
1294 visRectDst.right, visRectDst.bottom );
1297 width = visRectDst.right - visRectDst.left;
1298 height = visRectDst.bottom - visRectDst.top;
1300 if (!fStretch) switch(rop) /* A few optimisations */
1302 case BLACKNESS: /* 0x00 */
1303 wine_tsx11_lock();
1304 if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1305 XSetFunction( gdi_display, physDevDst->gc, GXclear );
1306 else
1308 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1309 XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1310 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1312 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1313 physDevDst->dc_rect.left + visRectDst.left,
1314 physDevDst->dc_rect.top + visRectDst.top,
1315 width, height );
1316 wine_tsx11_unlock();
1317 return TRUE;
1319 case DSTINVERT: /* 0x55 */
1320 wine_tsx11_lock();
1321 XSetFunction( gdi_display, physDevDst->gc, GXinvert );
1323 if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1324 XSetFunction( gdi_display, physDevDst->gc, GXinvert);
1325 else
1327 /* Xor is much better when we do not have full colormap. */
1328 /* Using white^black ensures that we invert at least black */
1329 /* and white. */
1330 unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1331 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1332 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1333 XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1334 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1336 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1337 physDevDst->dc_rect.left + visRectDst.left,
1338 physDevDst->dc_rect.top + visRectDst.top,
1339 width, height );
1340 wine_tsx11_unlock();
1341 return TRUE;
1343 case PATINVERT: /* 0x5a */
1344 if (X11DRV_SetupGCForBrush( physDevDst ))
1346 wine_tsx11_lock();
1347 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1348 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1349 physDevDst->dc_rect.left + visRectDst.left,
1350 physDevDst->dc_rect.top + visRectDst.top,
1351 width, height );
1352 wine_tsx11_unlock();
1354 return TRUE;
1356 case 0xa50065:
1357 if (X11DRV_SetupGCForBrush( physDevDst ))
1359 wine_tsx11_lock();
1360 XSetFunction( gdi_display, physDevDst->gc, GXequiv );
1361 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1362 physDevDst->dc_rect.left + visRectDst.left,
1363 physDevDst->dc_rect.top + visRectDst.top,
1364 width, height );
1365 wine_tsx11_unlock();
1367 return TRUE;
1369 case SRCCOPY: /* 0xcc */
1370 if (physDevSrc->depth == physDevDst->depth)
1372 wine_tsx11_lock();
1373 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1374 XCopyArea( gdi_display, physDevSrc->drawable,
1375 physDevDst->drawable, physDevDst->gc,
1376 physDevSrc->dc_rect.left + visRectSrc.left,
1377 physDevSrc->dc_rect.top + visRectSrc.top,
1378 width, height,
1379 physDevDst->dc_rect.left + visRectDst.left,
1380 physDevDst->dc_rect.top + visRectDst.top );
1381 physDevDst->exposures++;
1382 wine_tsx11_unlock();
1383 return TRUE;
1386 if (physDevSrc->depth == 1)
1388 int fg, bg;
1389 get_colors(physDevDst, physDevSrc, &fg, &bg);
1390 wine_tsx11_lock();
1392 XSetBackground( gdi_display, physDevDst->gc, fg );
1393 XSetForeground( gdi_display, physDevDst->gc, bg );
1394 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1395 XCopyPlane( gdi_display, physDevSrc->drawable,
1396 physDevDst->drawable, physDevDst->gc,
1397 physDevSrc->dc_rect.left + visRectSrc.left,
1398 physDevSrc->dc_rect.top + visRectSrc.top,
1399 width, height,
1400 physDevDst->dc_rect.left + visRectDst.left,
1401 physDevDst->dc_rect.top + visRectDst.top, 1 );
1402 physDevDst->exposures++;
1403 wine_tsx11_unlock();
1404 return TRUE;
1406 break;
1408 case PATCOPY: /* 0xf0 */
1409 if (!X11DRV_SetupGCForBrush( physDevDst )) return TRUE;
1410 wine_tsx11_lock();
1411 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1412 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1413 physDevDst->dc_rect.left + visRectDst.left,
1414 physDevDst->dc_rect.top + visRectDst.top,
1415 width, height );
1416 wine_tsx11_unlock();
1417 return TRUE;
1419 case WHITENESS: /* 0xff */
1420 wine_tsx11_lock();
1421 if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1422 XSetFunction( gdi_display, physDevDst->gc, GXset );
1423 else
1425 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1426 XSetForeground( gdi_display, physDevDst->gc,
1427 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1428 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1430 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1431 physDevDst->dc_rect.left + visRectDst.left,
1432 physDevDst->dc_rect.top + visRectDst.top,
1433 width, height );
1434 wine_tsx11_unlock();
1435 return TRUE;
1438 wine_tsx11_lock();
1440 tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1441 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1442 XSetGraphicsExposures( gdi_display, tmpGC, False );
1443 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1444 physDevDst->depth );
1445 if (useSrc)
1447 pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1448 physDevDst->depth );
1449 if (fStretch)
1450 BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1451 xSrc, ySrc, widthSrc, heightSrc,
1452 xDst, yDst, widthDst, heightDst,
1453 &visRectSrc, &visRectDst );
1454 else
1455 BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1456 xSrc, ySrc, &visRectSrc );
1459 if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &visRectDst );
1460 if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1461 else fNullBrush = FALSE;
1462 destUsed = FALSE;
1464 for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1466 if (OP_DST(*opcode) == DST) destUsed = TRUE;
1467 XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1468 switch(OP_SRCDST(*opcode))
1470 case OP_ARGS(DST,TMP):
1471 case OP_ARGS(SRC,TMP):
1472 if (!pixmaps[TMP])
1473 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1474 width, height, physDevDst->depth );
1475 /* fall through */
1476 case OP_ARGS(DST,SRC):
1477 case OP_ARGS(SRC,DST):
1478 case OP_ARGS(TMP,SRC):
1479 case OP_ARGS(TMP,DST):
1480 if (useSrc)
1481 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1482 pixmaps[OP_DST(*opcode)], tmpGC,
1483 0, 0, width, height, 0, 0 );
1484 break;
1486 case OP_ARGS(PAT,TMP):
1487 if (!pixmaps[TMP] && !fNullBrush)
1488 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1489 width, height, physDevDst->depth );
1490 /* fall through */
1491 case OP_ARGS(PAT,DST):
1492 case OP_ARGS(PAT,SRC):
1493 if (!fNullBrush)
1494 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1495 tmpGC, 0, 0, width, height );
1496 break;
1499 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1500 physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC],
1501 &visRectDst );
1502 XFreePixmap( gdi_display, pixmaps[DST] );
1503 if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1504 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1505 XFreeGC( gdi_display, tmpGC );
1506 wine_tsx11_unlock();
1507 return TRUE;
1511 /***********************************************************************
1512 * X11DRV_PatBlt
1514 BOOL X11DRV_PatBlt( X11DRV_PDEVICE *physDev, INT left, INT top, INT width, INT height, DWORD rop )
1516 BOOL result;
1518 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1519 result = BITBLT_InternalStretchBlt( physDev, left, top, width, height, NULL, 0, 0, 0, 0, rop );
1520 X11DRV_UnlockDIBSection( physDev, TRUE );
1521 return result;
1525 /***********************************************************************
1526 * X11DRV_ClientSideDIBCopy
1528 static BOOL X11DRV_ClientSideDIBCopy( X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1529 X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1530 INT width, INT height )
1532 DIBSECTION srcDib, dstDib;
1533 BYTE *srcPtr, *dstPtr;
1534 INT srcRowOffset, dstRowOffset;
1535 INT bytesPerPixel;
1536 INT bytesToCopy;
1537 INT y;
1538 static RECT unusedRect;
1540 if (GetObjectW(physDevSrc->bitmap->hbitmap, sizeof(srcDib), &srcDib) != sizeof(srcDib))
1541 return FALSE;
1542 if (GetObjectW(physDevDst->bitmap->hbitmap, sizeof(dstDib), &dstDib) != sizeof(dstDib))
1543 return FALSE;
1545 /* check for oversized values, just like X11DRV_DIB_CopyDIBSection() */
1546 if (xSrc > srcDib.dsBm.bmWidth || ySrc > srcDib.dsBm.bmHeight)
1547 return FALSE;
1548 if (xSrc + width > srcDib.dsBm.bmWidth)
1549 width = srcDib.dsBm.bmWidth - xSrc;
1550 if (ySrc + height > srcDib.dsBm.bmHeight)
1551 height = srcDib.dsBm.bmHeight - ySrc;
1553 if (GetRgnBox(physDevSrc->region, &unusedRect) == COMPLEXREGION ||
1554 GetRgnBox(physDevDst->region, &unusedRect) == COMPLEXREGION)
1556 /* for simple regions, the clipping was already done by BITBLT_GetVisRectangles */
1557 FIXME("potential optimization: client-side complex region clipping\n");
1558 return FALSE;
1560 if (dstDib.dsBm.bmBitsPixel <= 8)
1562 FIXME("potential optimization: client-side color-index mode DIB copy\n");
1563 return FALSE;
1565 if (!(srcDib.dsBmih.biCompression == BI_BITFIELDS &&
1566 dstDib.dsBmih.biCompression == BI_BITFIELDS &&
1567 !memcmp(srcDib.dsBitfields, dstDib.dsBitfields, 3*sizeof(DWORD)))
1568 && !(srcDib.dsBmih.biCompression == BI_RGB &&
1569 dstDib.dsBmih.biCompression == BI_RGB))
1571 FIXME("potential optimization: client-side compressed DIB copy\n");
1572 return FALSE;
1574 if (srcDib.dsBm.bmBitsPixel != dstDib.dsBm.bmBitsPixel)
1576 FIXME("potential optimization: pixel format conversion\n");
1577 return FALSE;
1579 if (srcDib.dsBmih.biWidth < 0 || dstDib.dsBmih.biWidth < 0)
1581 FIXME("negative widths not yet implemented\n");
1582 return FALSE;
1585 switch (dstDib.dsBm.bmBitsPixel)
1587 case 15:
1588 case 16:
1589 bytesPerPixel = 2;
1590 break;
1591 case 24:
1592 bytesPerPixel = 3;
1593 break;
1594 case 32:
1595 bytesPerPixel = 4;
1596 break;
1597 default:
1598 FIXME("don't know how to work with a depth of %d\n", physDevSrc->depth);
1599 return FALSE;
1602 bytesToCopy = width * bytesPerPixel;
1604 if (srcDib.dsBmih.biHeight < 0)
1606 srcPtr = &physDevSrc->bitmap->base[ySrc*srcDib.dsBm.bmWidthBytes + xSrc*bytesPerPixel];
1607 srcRowOffset = srcDib.dsBm.bmWidthBytes;
1609 else
1611 srcPtr = &physDevSrc->bitmap->base[(srcDib.dsBm.bmHeight-ySrc-1)*srcDib.dsBm.bmWidthBytes
1612 + xSrc*bytesPerPixel];
1613 srcRowOffset = -srcDib.dsBm.bmWidthBytes;
1615 if (dstDib.dsBmih.biHeight < 0)
1617 dstPtr = &physDevDst->bitmap->base[yDst*dstDib.dsBm.bmWidthBytes + xDst*bytesPerPixel];
1618 dstRowOffset = dstDib.dsBm.bmWidthBytes;
1620 else
1622 dstPtr = &physDevDst->bitmap->base[(dstDib.dsBm.bmHeight-yDst-1)*dstDib.dsBm.bmWidthBytes
1623 + xDst*bytesPerPixel];
1624 dstRowOffset = -dstDib.dsBm.bmWidthBytes;
1627 for (y = yDst; y < yDst + height; ++y)
1629 memcpy(dstPtr, srcPtr, bytesToCopy);
1630 srcPtr += srcRowOffset;
1631 dstPtr += dstRowOffset;
1634 return TRUE;
1638 /***********************************************************************
1639 * X11DRV_BitBlt
1641 BOOL X11DRV_BitBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1642 INT width, INT height, X11DRV_PDEVICE *physDevSrc,
1643 INT xSrc, INT ySrc, DWORD rop )
1645 BOOL result = FALSE;
1646 INT sSrc, sDst;
1647 RECT visRectDst, visRectSrc;
1649 if (((rop >> 16) & 0x55) == ((rop >> 17) & 0x55)) {
1650 /* FIXME: seems the ROP doesn't include destination;
1651 * now if the destination area include the entire dcDst,
1652 * we can pass TRUE instead of FALSE to CoerceDIBSection(dcDst...),
1653 * which may avoid a copy in some situations */
1656 sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None, FALSE );
1657 if (physDevDst != physDevSrc)
1658 sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None, FALSE );
1659 else
1660 sSrc = sDst;
1662 if ((sSrc == DIB_Status_AppMod) && (rop == SRCCOPY) &&
1663 (physDevSrc->depth == physDevDst->depth))
1665 POINT pts[2];
1666 /* do everything ourselves; map coordinates */
1668 pts[0].x = xSrc;
1669 pts[0].y = ySrc;
1670 pts[1].x = xSrc + width;
1671 pts[1].y = ySrc + height;
1673 LPtoDP(physDevSrc->hdc, pts, 2);
1674 width = pts[1].x - pts[0].x;
1675 height = pts[1].y - pts[0].y;
1676 xSrc = pts[0].x;
1677 ySrc = pts[0].y;
1679 pts[0].x = xDst;
1680 pts[0].y = yDst;
1681 LPtoDP(physDevDst->hdc, pts, 1);
1683 xDst = pts[0].x;
1684 yDst = pts[0].y;
1686 /* Perform basic clipping */
1687 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, width, height,
1688 physDevSrc, xSrc, ySrc, width, height,
1689 &visRectSrc, &visRectDst ))
1690 goto END;
1692 xSrc = visRectSrc.left;
1693 ySrc = visRectSrc.top;
1694 xDst = visRectDst.left;
1695 yDst = visRectDst.top;
1696 width = visRectDst.right - visRectDst.left;
1697 height = visRectDst.bottom - visRectDst.top;
1699 if (sDst == DIB_Status_AppMod) {
1700 result = X11DRV_ClientSideDIBCopy( physDevSrc, xSrc, ySrc,
1701 physDevDst, xDst, yDst,
1702 width, height );
1703 if (result)
1704 goto END;
1705 /* fall back to X server copying */
1707 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1709 wine_tsx11_lock();
1710 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1711 wine_tsx11_unlock();
1713 X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, xSrc, ySrc, xDst, yDst, width, height );
1714 result = TRUE;
1715 goto END;
1718 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1719 if (physDevDst != physDevSrc)
1720 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1722 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, width, height,
1723 physDevSrc, xSrc, ySrc, width, height, rop );
1725 END:
1726 if (physDevDst != physDevSrc)
1727 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1728 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1730 return result;
1734 /***********************************************************************
1735 * X11DRV_StretchBlt
1737 BOOL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1738 INT widthDst, INT heightDst,
1739 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1740 INT widthSrc, INT heightSrc, DWORD rop )
1742 BOOL result;
1744 X11DRV_LockDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1745 if (physDevDst != physDevSrc)
1746 X11DRV_LockDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1748 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, widthDst, heightDst,
1749 physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop );
1751 if (physDevDst != physDevSrc)
1752 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1753 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1754 return result;