wined3d: Check more thoroughly if a stage references a texture.
[wine/hacks.git] / dlls / winex11.drv / bitblt.c
blob06c6ba160f231c25520776d25aa28cb7c32f7239
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 "winuser.h"
33 #include "x11drv.h"
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(SRC,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 )
451 int res;
452 switch(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;
471 return res & 1;
474 int main()
476 int rop, i, res, src, dst, pat, tmp, dstUsed;
477 const BYTE *opcode;
479 for (rop = 0; rop < 256; rop++)
481 res = dstUsed = 0;
482 for (i = 0; i < 8; i++)
484 pat = (i >> 2) & 1;
485 src = (i >> 1) & 1;
486 dst = i & 1;
487 for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
489 switch(*opcode >> 4)
491 case OP_ARGS(DST,TMP):
492 tmp = do_bitop( dst, tmp, *opcode & 0xf );
493 break;
494 case OP_ARGS(DST,SRC):
495 src = do_bitop( dst, src, *opcode & 0xf );
496 break;
497 case OP_ARGS(SRC,TMP):
498 tmp = do_bitop( src, tmp, *opcode & 0xf );
499 break;
500 case OP_ARGS(SRC,DST):
501 dst = do_bitop( src, dst, *opcode & 0xf );
502 dstUsed = 1;
503 break;
504 case OP_ARGS(PAT,TMP):
505 tmp = do_bitop( pat, tmp, *opcode & 0xf );
506 break;
507 case OP_ARGS(PAT,DST):
508 dst = do_bitop( pat, dst, *opcode & 0xf );
509 dstUsed = 1;
510 break;
511 case OP_ARGS(PAT,SRC):
512 src = do_bitop( pat, src, *opcode & 0xf );
513 break;
514 case OP_ARGS(TMP,DST):
515 dst = do_bitop( tmp, dst, *opcode & 0xf );
516 dstUsed = 1;
517 break;
518 case OP_ARGS(TMP,SRC):
519 src = do_bitop( tmp, src, *opcode & 0xf );
520 break;
521 default:
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 );
531 return 0;
534 #endif /* BITBLT_TEST */
537 static void get_colors(X11DRV_PDEVICE *physDevDst, X11DRV_PDEVICE *physDevSrc,
538 int *fg, int *bg)
540 RGBQUAD rgb[2];
542 *fg = physDevDst->textPixel;
543 *bg = physDevDst->backgroundPixel;
544 if(physDevSrc->depth == 1) {
545 if(GetDIBColorTable(physDevSrc->hdc, 0, 2, rgb) == 2) {
546 DWORD logcolor;
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 /***********************************************************************
556 * BITBLT_StretchRow
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;
565 rowDst += startDst;
566 switch(mode)
568 case STRETCH_ANDSCANS:
569 for(; widthDst > 0; widthDst--, xsrc += xinc)
570 *rowDst++ &= rowSrc[xsrc >> 16];
571 break;
572 case STRETCH_ORSCANS:
573 for(; widthDst > 0; widthDst--, xsrc += xinc)
574 *rowDst++ |= rowSrc[xsrc >> 16];
575 break;
576 case STRETCH_DELETESCANS:
577 for(; widthDst > 0; widthDst--, xsrc += xinc)
578 *rowDst++ = rowSrc[xsrc >> 16];
579 break;
584 /***********************************************************************
585 * BITBLT_ShrinkRow
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;
594 rowSrc += startSrc;
595 switch(mode)
597 case STRETCH_ORSCANS:
598 for(; widthSrc > 0; widthSrc--, xdst += xinc)
599 rowDst[xdst >> 16] |= *rowSrc++;
600 break;
601 case STRETCH_ANDSCANS:
602 for(; widthSrc > 0; widthSrc--, xdst += xinc)
603 rowDst[xdst >> 16] &= *rowSrc++;
604 break;
605 case STRETCH_DELETESCANS:
606 for(; widthSrc > 0; widthSrc--, xdst += xinc)
607 rowDst[xdst >> 16] = *rowSrc++;
608 break;
613 /***********************************************************************
614 * BITBLT_GetRow
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)
622 register INT i;
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 )];
635 else
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 );
641 else
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;
679 char *pdata;
680 INT xinc, xoff, yinc, ysrc, ydst;
681 register INT x, y;
682 BOOL hstretch, vstretch, hswap, vswap;
684 hswap = ((int)widthSrc * widthDst) < 0;
685 vswap = ((int)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);
709 if (hstretch)
711 xinc = ((int)widthSrc << 16) / widthDst;
712 xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
714 else
716 xinc = ((int)widthDst << 16) / widthSrc;
717 xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
720 if (vstretch)
722 yinc = ((int)heightSrc << 16) / heightDst;
723 ydst = visRectDst->top;
724 if (vswap)
726 ysrc = yinc * (heightDst - ydst - 1);
727 yinc = -yinc;
729 else
730 ysrc = yinc * ydst;
732 for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
734 if (((ysrc >> 16) < visRectSrc->top) ||
735 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
737 /* Retrieve a source row */
738 BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
739 hswap ? widthSrc - visRectSrc->right
740 : visRectSrc->left,
741 visRectSrc->right - visRectSrc->left,
742 dstImage->depth, foreground, background, hswap );
744 /* Stretch or shrink it */
745 if (hstretch)
746 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
747 visRectDst->right - visRectDst->left,
748 xinc, xoff, mode );
749 else BITBLT_ShrinkRow( rowSrc, rowDst,
750 hswap ? widthSrc - visRectSrc->right
751 : visRectSrc->left,
752 visRectSrc->right - visRectSrc->left,
753 xinc, xoff, mode );
755 /* Store the destination row */
756 pixel = rowDst + visRectDst->right - 1;
757 y = ydst - visRectDst->top;
758 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
759 XPutPixel( dstImage, x, y, *pixel-- );
760 if (mode != STRETCH_DELETESCANS)
761 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
762 widthDst*sizeof(int) );
764 /* Make copies of the destination row */
766 pdata = dstImage->data + dstImage->bytes_per_line * y;
767 while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
768 (ydst < visRectDst->bottom-1))
770 memcpy( pdata + dstImage->bytes_per_line, pdata,
771 dstImage->bytes_per_line );
772 pdata += dstImage->bytes_per_line;
773 ysrc += yinc;
774 ydst++;
778 else /* Shrinking */
780 yinc = ((int)heightDst << 16) / heightSrc;
781 ysrc = visRectSrc->top;
782 ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
783 if (vswap)
785 ydst += yinc * (heightSrc - ysrc - 1);
786 yinc = -yinc;
788 else
789 ydst += yinc * ysrc;
791 for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
793 if (((ydst >> 16) < visRectDst->top) ||
794 ((ydst >> 16) >= visRectDst->bottom)) continue;
796 /* Retrieve a source row */
797 BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
798 hswap ? widthSrc - visRectSrc->right
799 : visRectSrc->left,
800 visRectSrc->right - visRectSrc->left,
801 dstImage->depth, foreground, background, hswap );
803 /* Stretch or shrink it */
804 if (hstretch)
805 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
806 visRectDst->right - visRectDst->left,
807 xinc, xoff, mode );
808 else BITBLT_ShrinkRow( rowSrc, rowDst,
809 hswap ? widthSrc - visRectSrc->right
810 : visRectSrc->left,
811 visRectSrc->right - visRectSrc->left,
812 xinc, xoff, mode );
814 /* Merge several source rows into the destination */
815 if (mode == STRETCH_DELETESCANS)
817 /* Simply skip the overlapping rows */
818 while (((ydst + yinc) >> 16 == ydst >> 16) &&
819 (ysrc < visRectSrc->bottom-1))
821 ydst += yinc;
822 ysrc++;
825 else if (((ydst + yinc) >> 16 == ydst >> 16) &&
826 (ysrc < visRectSrc->bottom-1))
827 continue; /* Restart loop for next overlapping row */
829 /* Store the destination row */
830 pixel = rowDst + visRectDst->right - 1;
831 y = (ydst >> 16) - visRectDst->top;
832 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
833 XPutPixel( dstImage, x, y, *pixel-- );
834 if (mode != STRETCH_DELETESCANS)
835 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
836 widthDst*sizeof(int) );
839 HeapFree( GetProcessHeap(), 0, rowSrc );
843 /***********************************************************************
844 * BITBLT_GetSrcAreaStretch
846 * Retrieve an area from the source DC, stretching and mapping all the
847 * pixels to Windows colors.
849 static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
850 Pixmap pixmap, GC gc,
851 INT xSrc, INT ySrc,
852 INT widthSrc, INT heightSrc,
853 INT xDst, INT yDst,
854 INT widthDst, INT heightDst,
855 RECT *visRectSrc, RECT *visRectDst )
857 XImage *imageSrc, *imageDst;
858 RECT rectSrc = *visRectSrc;
859 RECT rectDst = *visRectDst;
860 int fg, bg;
862 if (widthSrc < 0) xSrc += widthSrc;
863 if (widthDst < 0) xDst += widthDst;
864 if (heightSrc < 0) ySrc += heightSrc;
865 if (heightDst < 0) yDst += heightDst;
866 rectSrc.left -= xSrc;
867 rectSrc.right -= xSrc;
868 rectSrc.top -= ySrc;
869 rectSrc.bottom -= ySrc;
870 rectDst.left -= xDst;
871 rectDst.right -= xDst;
872 rectDst.top -= yDst;
873 rectDst.bottom -= yDst;
875 get_colors(physDevDst, physDevSrc, &fg, &bg);
876 /* FIXME: avoid BadMatch errors */
877 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
878 physDevSrc->dc_rect.left + visRectSrc->left,
879 physDevSrc->dc_rect.top + visRectSrc->top,
880 visRectSrc->right - visRectSrc->left,
881 visRectSrc->bottom - visRectSrc->top,
882 AllPlanes, ZPixmap );
883 imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
884 rectDst.bottom - rectDst.top, physDevDst->depth );
885 BITBLT_StretchImage( imageSrc, imageDst, widthSrc, heightSrc,
886 widthDst, heightDst, &rectSrc, &rectDst,
887 fg, physDevDst->depth != 1 ?
888 bg : physDevSrc->backgroundPixel,
889 GetStretchBltMode(physDevDst->hdc) );
890 XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
891 rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
892 XDestroyImage( imageSrc );
893 XDestroyImage( imageDst );
894 return 0; /* no exposure events generated */
898 /***********************************************************************
899 * BITBLT_GetSrcArea
901 * Retrieve an area from the source DC, mapping all the
902 * pixels to Windows colors.
904 static int BITBLT_GetSrcArea( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
905 Pixmap pixmap, GC gc, INT xSrc, INT ySrc, RECT *visRectSrc )
907 XImage *imageSrc, *imageDst;
908 register INT x, y;
909 int exposures = 0;
910 INT width = visRectSrc->right - visRectSrc->left;
911 INT height = visRectSrc->bottom - visRectSrc->top;
912 int fg, bg;
914 if (physDevSrc->depth == physDevDst->depth)
916 if (!X11DRV_PALETTE_XPixelToPalette ||
917 (physDevDst->depth == 1)) /* monochrome -> monochrome */
919 if (physDevDst->depth == 1)
921 /* MSDN says if StretchBlt must convert a bitmap from monochrome
922 to color or vice versa, the forground and background color of
923 the device context are used. In fact, it also applies to the
924 case when it is converted from mono to mono. */
925 XSetBackground( gdi_display, gc, physDevDst->textPixel );
926 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
927 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
928 physDevSrc->dc_rect.left + visRectSrc->left,
929 physDevSrc->dc_rect.top + visRectSrc->top,
930 width, height, 0, 0, 1);
932 else
933 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
934 physDevSrc->dc_rect.left + visRectSrc->left,
935 physDevSrc->dc_rect.top + visRectSrc->top,
936 width, height, 0, 0);
937 exposures++;
939 else /* color -> color */
941 if (GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
942 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
943 physDevSrc->dc_rect.left + visRectSrc->left,
944 physDevSrc->dc_rect.top + visRectSrc->top,
945 width, height, AllPlanes, ZPixmap );
946 else
948 /* Make sure we don't get a BadMatch error */
949 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
950 physDevSrc->dc_rect.left + visRectSrc->left,
951 physDevSrc->dc_rect.top + visRectSrc->top,
952 width, height, 0, 0);
953 exposures++;
954 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
955 AllPlanes, ZPixmap );
957 for (y = 0; y < height; y++)
958 for (x = 0; x < width; x++)
959 XPutPixel(imageSrc, x, y,
960 X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
961 XPutImage( gdi_display, pixmap, gc, imageSrc,
962 0, 0, 0, 0, width, height );
963 XDestroyImage( imageSrc );
966 else
968 if (physDevSrc->depth == 1) /* monochrome -> color */
970 get_colors(physDevDst, physDevSrc, &fg, &bg);
972 if (X11DRV_PALETTE_XPixelToPalette)
974 XSetBackground( gdi_display, gc,
975 X11DRV_PALETTE_XPixelToPalette[fg] );
976 XSetForeground( gdi_display, gc,
977 X11DRV_PALETTE_XPixelToPalette[bg]);
979 else
981 XSetBackground( gdi_display, gc, fg );
982 XSetForeground( gdi_display, gc, bg );
984 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
985 physDevSrc->dc_rect.left + visRectSrc->left,
986 physDevSrc->dc_rect.top + visRectSrc->top,
987 width, height, 0, 0, 1 );
988 exposures++;
990 else /* color -> monochrome */
992 /* FIXME: avoid BadMatch error */
993 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
994 physDevSrc->dc_rect.left + visRectSrc->left,
995 physDevSrc->dc_rect.top + visRectSrc->top,
996 width, height, AllPlanes, ZPixmap );
997 if (!imageSrc)
999 return exposures;
1001 imageDst = X11DRV_DIB_CreateXImage( width, height, physDevDst->depth );
1002 if (!imageDst)
1004 XDestroyImage(imageSrc);
1005 return exposures;
1007 for (y = 0; y < height; y++)
1008 for (x = 0; x < width; x++)
1009 XPutPixel(imageDst, x, y, (XGetPixel(imageSrc,x,y) ==
1010 physDevSrc->backgroundPixel) );
1011 XPutImage( gdi_display, pixmap, gc, imageDst,
1012 0, 0, 0, 0, width, height );
1013 XDestroyImage( imageSrc );
1014 XDestroyImage( imageDst );
1017 return exposures;
1021 /***********************************************************************
1022 * BITBLT_GetDstArea
1024 * Retrieve an area from the destination DC, mapping all the
1025 * pixels to Windows colors.
1027 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, RECT *visRectDst)
1029 int exposures = 0;
1030 INT width = visRectDst->right - visRectDst->left;
1031 INT height = visRectDst->bottom - visRectDst->top;
1033 if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) ||
1034 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1036 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1037 physDev->dc_rect.left + visRectDst->left, physDev->dc_rect.top + visRectDst->top,
1038 width, height, 0, 0 );
1039 exposures++;
1041 else
1043 register INT x, y;
1044 XImage *image;
1046 if (GetObjectType( physDev->hdc ) == OBJ_MEMDC)
1047 image = XGetImage( gdi_display, physDev->drawable,
1048 physDev->dc_rect.left + visRectDst->left,
1049 physDev->dc_rect.top + visRectDst->top,
1050 width, height, AllPlanes, ZPixmap );
1051 else
1053 /* Make sure we don't get a BadMatch error */
1054 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1055 physDev->dc_rect.left + visRectDst->left,
1056 physDev->dc_rect.top + visRectDst->top,
1057 width, height, 0, 0);
1058 exposures++;
1059 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1060 AllPlanes, ZPixmap );
1062 for (y = 0; y < height; y++)
1063 for (x = 0; x < width; x++)
1064 XPutPixel( image, x, y,
1065 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1066 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1067 XDestroyImage( image );
1069 return exposures;
1073 /***********************************************************************
1074 * BITBLT_PutDstArea
1076 * Put an area back into the destination DC, mapping the pixel
1077 * colors to X pixels.
1079 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, RECT *visRectDst)
1081 int exposures = 0;
1082 INT width = visRectDst->right - visRectDst->left;
1083 INT height = visRectDst->bottom - visRectDst->top;
1085 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1087 if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) ||
1088 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1090 XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1091 physDev->dc_rect.left + visRectDst->left,
1092 physDev->dc_rect.top + visRectDst->top );
1093 exposures++;
1095 else
1097 register INT x, y;
1098 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1099 AllPlanes, ZPixmap );
1100 for (y = 0; y < height; y++)
1101 for (x = 0; x < width; x++)
1103 XPutPixel( image, x, y,
1104 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1106 XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1107 physDev->dc_rect.left + visRectDst->left,
1108 physDev->dc_rect.top + visRectDst->top, width, height );
1109 XDestroyImage( image );
1111 return exposures;
1115 /***********************************************************************
1116 * BITBLT_GetVisRectangles
1118 * Get the source and destination visible rectangles for StretchBlt().
1119 * Return FALSE if one of the rectangles is empty.
1121 static BOOL BITBLT_GetVisRectangles( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1122 INT widthDst, INT heightDst,
1123 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1124 INT widthSrc, INT heightSrc,
1125 RECT *visRectSrc, RECT *visRectDst )
1127 RECT rect, clipRect;
1129 /* Get the destination visible rectangle */
1131 rect.left = xDst;
1132 rect.top = yDst;
1133 rect.right = xDst + widthDst;
1134 rect.bottom = yDst + heightDst;
1135 if (widthDst < 0) SWAP_INT32( &rect.left, &rect.right );
1136 if (heightDst < 0) SWAP_INT32( &rect.top, &rect.bottom );
1137 GetRgnBox( physDevDst->region, &clipRect );
1138 if (!IntersectRect( visRectDst, &rect, &clipRect )) return FALSE;
1140 /* Get the source visible rectangle */
1142 if (!physDevSrc) return TRUE;
1143 rect.left = xSrc;
1144 rect.top = ySrc;
1145 rect.right = xSrc + widthSrc;
1146 rect.bottom = ySrc + heightSrc;
1147 if (widthSrc < 0) SWAP_INT32( &rect.left, &rect.right );
1148 if (heightSrc < 0) SWAP_INT32( &rect.top, &rect.bottom );
1149 /* Apparently the clipping and visible regions are only for output,
1150 so just check against dc extent here to avoid BadMatch errors */
1151 clipRect = physDevSrc->drawable_rect;
1152 OffsetRect( &clipRect, -(physDevSrc->drawable_rect.left + physDevSrc->dc_rect.left),
1153 -(physDevSrc->drawable_rect.top + physDevSrc->dc_rect.top) );
1154 if (!IntersectRect( visRectSrc, &rect, &clipRect ))
1155 return FALSE;
1157 /* Intersect the rectangles */
1159 if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1161 visRectSrc->left += xDst - xSrc;
1162 visRectSrc->right += xDst - xSrc;
1163 visRectSrc->top += yDst - ySrc;
1164 visRectSrc->bottom += yDst - ySrc;
1165 if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1166 *visRectSrc = *visRectDst = rect;
1167 visRectSrc->left += xSrc - xDst;
1168 visRectSrc->right += xSrc - xDst;
1169 visRectSrc->top += ySrc - yDst;
1170 visRectSrc->bottom += ySrc - yDst;
1172 else /* stretching */
1174 /* Map source rectangle into destination coordinates */
1175 rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1176 rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1177 rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1178 rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1179 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1180 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1182 /* Avoid rounding errors */
1183 rect.left--;
1184 rect.top--;
1185 rect.right++;
1186 rect.bottom++;
1187 if (!IntersectRect( visRectDst, &rect, visRectDst )) return FALSE;
1189 /* Map destination rectangle back to source coordinates */
1190 rect = *visRectDst;
1191 rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1192 rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1193 rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1194 rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1195 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1196 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1198 /* Avoid rounding errors */
1199 rect.left--;
1200 rect.top--;
1201 rect.right++;
1202 rect.bottom++;
1203 if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1205 return TRUE;
1209 /***********************************************************************
1210 * BITBLT_InternalStretchBlt
1212 * Implementation of PatBlt(), BitBlt() and StretchBlt().
1214 static BOOL BITBLT_InternalStretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1215 INT widthDst, INT heightDst,
1216 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1217 INT widthSrc, INT heightSrc,
1218 DWORD rop )
1220 BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1221 RECT visRectDst, visRectSrc;
1222 INT width, height;
1223 const BYTE *opcode;
1224 Pixmap pixmaps[3] = { 0, 0, 0 }; /* pixmaps for DST, SRC, TMP */
1225 GC tmpGC = 0;
1226 POINT pts[2];
1228 /* compensate for off-by-one shifting for negative widths and heights */
1229 if (widthDst < 0)
1230 ++xDst;
1231 if (heightDst < 0)
1232 ++yDst;
1233 if (widthSrc < 0)
1234 ++xSrc;
1235 if (heightSrc < 0)
1236 ++ySrc;
1238 usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1239 useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1240 useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1241 if (!physDevSrc && useSrc) return FALSE;
1243 /* Map the coordinates to device coords */
1245 pts[0].x = xDst;
1246 pts[0].y = yDst;
1247 pts[1].x = xDst + widthDst;
1248 pts[1].y = yDst + heightDst;
1249 LPtoDP(physDevDst->hdc, pts, 2);
1250 xDst = pts[0].x;
1251 yDst = pts[0].y;
1252 widthDst = pts[1].x - pts[0].x;
1253 heightDst = pts[1].y - pts[0].y;
1255 TRACE(" rectdst=%d,%d-%d,%d orgdst=%d,%d\n",
1256 xDst, yDst, widthDst, heightDst,
1257 physDevDst->dc_rect.left, physDevDst->dc_rect.top );
1259 if (useSrc)
1261 pts[0].x = xSrc;
1262 pts[0].y = ySrc;
1263 pts[1].x = xSrc + widthSrc;
1264 pts[1].y = ySrc + heightSrc;
1265 LPtoDP(physDevSrc->hdc, pts, 2);
1266 xSrc = pts[0].x;
1267 ySrc = pts[0].y;
1268 widthSrc = pts[1].x - pts[0].x;
1269 heightSrc = pts[1].y - pts[0].y;
1271 fStretch = (widthSrc != widthDst) || (heightSrc != heightDst);
1272 TRACE(" rectsrc=%d,%d-%d,%d orgsrc=%d,%d\n",
1273 xSrc, ySrc, widthSrc, heightSrc,
1274 physDevSrc->dc_rect.left, physDevSrc->dc_rect.top );
1275 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1276 physDevSrc, xSrc, ySrc, widthSrc, heightSrc,
1277 &visRectSrc, &visRectDst ))
1278 return TRUE;
1279 TRACE(" vissrc=%d,%d-%d,%d visdst=%d,%d-%d,%d\n",
1280 visRectSrc.left, visRectSrc.top,
1281 visRectSrc.right, visRectSrc.bottom,
1282 visRectDst.left, visRectDst.top,
1283 visRectDst.right, visRectDst.bottom );
1285 else
1287 fStretch = FALSE;
1288 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1289 NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1290 return TRUE;
1291 TRACE(" vissrc=none visdst=%d,%d-%d,%d\n",
1292 visRectDst.left, visRectDst.top,
1293 visRectDst.right, visRectDst.bottom );
1296 width = visRectDst.right - visRectDst.left;
1297 height = visRectDst.bottom - visRectDst.top;
1299 if (!fStretch) switch(rop) /* A few optimisations */
1301 case BLACKNESS: /* 0x00 */
1302 wine_tsx11_lock();
1303 if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1304 XSetFunction( gdi_display, physDevDst->gc, GXclear );
1305 else
1307 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1308 XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1309 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1311 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1312 physDevDst->dc_rect.left + visRectDst.left,
1313 physDevDst->dc_rect.top + visRectDst.top,
1314 width, height );
1315 wine_tsx11_unlock();
1316 return TRUE;
1318 case DSTINVERT: /* 0x55 */
1319 wine_tsx11_lock();
1320 XSetFunction( gdi_display, physDevDst->gc, GXinvert );
1322 if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1323 XSetFunction( gdi_display, physDevDst->gc, GXinvert);
1324 else
1326 /* Xor is much better when we do not have full colormap. */
1327 /* Using white^black ensures that we invert at least black */
1328 /* and white. */
1329 unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1330 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1331 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1332 XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1333 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1335 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1336 physDevDst->dc_rect.left + visRectDst.left,
1337 physDevDst->dc_rect.top + visRectDst.top,
1338 width, height );
1339 wine_tsx11_unlock();
1340 return TRUE;
1342 case PATINVERT: /* 0x5a */
1343 if (X11DRV_SetupGCForBrush( physDevDst ))
1345 wine_tsx11_lock();
1346 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1347 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1348 physDevDst->dc_rect.left + visRectDst.left,
1349 physDevDst->dc_rect.top + visRectDst.top,
1350 width, height );
1351 wine_tsx11_unlock();
1353 return TRUE;
1355 case 0xa50065:
1356 if (X11DRV_SetupGCForBrush( physDevDst ))
1358 wine_tsx11_lock();
1359 XSetFunction( gdi_display, physDevDst->gc, GXequiv );
1360 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1361 physDevDst->dc_rect.left + visRectDst.left,
1362 physDevDst->dc_rect.top + visRectDst.top,
1363 width, height );
1364 wine_tsx11_unlock();
1366 return TRUE;
1368 case SRCCOPY: /* 0xcc */
1369 if (physDevSrc->depth == physDevDst->depth)
1371 wine_tsx11_lock();
1372 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1373 XCopyArea( gdi_display, physDevSrc->drawable,
1374 physDevDst->drawable, physDevDst->gc,
1375 physDevSrc->dc_rect.left + visRectSrc.left,
1376 physDevSrc->dc_rect.top + visRectSrc.top,
1377 width, height,
1378 physDevDst->dc_rect.left + visRectDst.left,
1379 physDevDst->dc_rect.top + visRectDst.top );
1380 physDevDst->exposures++;
1381 wine_tsx11_unlock();
1382 return TRUE;
1385 if (physDevSrc->depth == 1)
1387 int fg, bg;
1388 get_colors(physDevDst, physDevSrc, &fg, &bg);
1389 wine_tsx11_lock();
1391 XSetBackground( gdi_display, physDevDst->gc, fg );
1392 XSetForeground( gdi_display, physDevDst->gc, bg );
1393 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1394 XCopyPlane( gdi_display, physDevSrc->drawable,
1395 physDevDst->drawable, physDevDst->gc,
1396 physDevSrc->dc_rect.left + visRectSrc.left,
1397 physDevSrc->dc_rect.top + visRectSrc.top,
1398 width, height,
1399 physDevDst->dc_rect.left + visRectDst.left,
1400 physDevDst->dc_rect.top + visRectDst.top, 1 );
1401 physDevDst->exposures++;
1402 wine_tsx11_unlock();
1403 return TRUE;
1405 break;
1407 case PATCOPY: /* 0xf0 */
1408 if (!X11DRV_SetupGCForBrush( physDevDst )) return TRUE;
1409 wine_tsx11_lock();
1410 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1411 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1412 physDevDst->dc_rect.left + visRectDst.left,
1413 physDevDst->dc_rect.top + visRectDst.top,
1414 width, height );
1415 wine_tsx11_unlock();
1416 return TRUE;
1418 case WHITENESS: /* 0xff */
1419 wine_tsx11_lock();
1420 if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1421 XSetFunction( gdi_display, physDevDst->gc, GXset );
1422 else
1424 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1425 XSetForeground( gdi_display, physDevDst->gc,
1426 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1427 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1429 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1430 physDevDst->dc_rect.left + visRectDst.left,
1431 physDevDst->dc_rect.top + visRectDst.top,
1432 width, height );
1433 wine_tsx11_unlock();
1434 return TRUE;
1437 wine_tsx11_lock();
1439 tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1440 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1441 XSetGraphicsExposures( gdi_display, tmpGC, False );
1442 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1443 physDevDst->depth );
1444 if (useSrc)
1446 pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1447 physDevDst->depth );
1448 if (fStretch)
1449 BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1450 xSrc, ySrc, widthSrc, heightSrc,
1451 xDst, yDst, widthDst, heightDst,
1452 &visRectSrc, &visRectDst );
1453 else
1454 BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1455 xSrc, ySrc, &visRectSrc );
1458 if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &visRectDst );
1459 if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1460 else fNullBrush = FALSE;
1461 destUsed = FALSE;
1463 for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1465 if (OP_DST(*opcode) == DST) destUsed = TRUE;
1466 XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1467 switch(OP_SRCDST(*opcode))
1469 case OP_ARGS(DST,TMP):
1470 case OP_ARGS(SRC,TMP):
1471 if (!pixmaps[TMP])
1472 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1473 width, height, physDevDst->depth );
1474 /* fall through */
1475 case OP_ARGS(DST,SRC):
1476 case OP_ARGS(SRC,DST):
1477 case OP_ARGS(TMP,SRC):
1478 case OP_ARGS(TMP,DST):
1479 if (useSrc)
1480 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1481 pixmaps[OP_DST(*opcode)], tmpGC,
1482 0, 0, width, height, 0, 0 );
1483 break;
1485 case OP_ARGS(PAT,TMP):
1486 if (!pixmaps[TMP] && !fNullBrush)
1487 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1488 width, height, physDevDst->depth );
1489 /* fall through */
1490 case OP_ARGS(PAT,DST):
1491 case OP_ARGS(PAT,SRC):
1492 if (!fNullBrush)
1493 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1494 tmpGC, 0, 0, width, height );
1495 break;
1498 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1499 physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC],
1500 &visRectDst );
1501 XFreePixmap( gdi_display, pixmaps[DST] );
1502 if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1503 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1504 XFreeGC( gdi_display, tmpGC );
1505 wine_tsx11_unlock();
1506 return TRUE;
1510 /***********************************************************************
1511 * X11DRV_PatBlt
1513 BOOL X11DRV_PatBlt( X11DRV_PDEVICE *physDev, INT left, INT top, INT width, INT height, DWORD rop )
1515 BOOL result;
1517 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1518 result = BITBLT_InternalStretchBlt( physDev, left, top, width, height, NULL, 0, 0, 0, 0, rop );
1519 X11DRV_UnlockDIBSection( physDev, TRUE );
1520 return result;
1524 /***********************************************************************
1525 * X11DRV_ClientSideDIBCopy
1527 static BOOL X11DRV_ClientSideDIBCopy( X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1528 X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1529 INT width, INT height )
1531 DIBSECTION srcDib, dstDib;
1532 BYTE *srcPtr, *dstPtr;
1533 INT srcRowOffset, dstRowOffset;
1534 INT bytesPerPixel;
1535 INT bytesToCopy;
1536 INT y;
1537 static RECT unusedRect;
1539 if (GetObjectW(physDevSrc->bitmap->hbitmap, sizeof(srcDib), &srcDib) != sizeof(srcDib))
1540 return FALSE;
1541 if (GetObjectW(physDevDst->bitmap->hbitmap, sizeof(dstDib), &dstDib) != sizeof(dstDib))
1542 return FALSE;
1544 /* check for oversized values, just like X11DRV_DIB_CopyDIBSection() */
1545 if (xSrc > srcDib.dsBm.bmWidth || ySrc > srcDib.dsBm.bmHeight)
1546 return FALSE;
1547 if (xSrc + width > srcDib.dsBm.bmWidth)
1548 width = srcDib.dsBm.bmWidth - xSrc;
1549 if (ySrc + height > srcDib.dsBm.bmHeight)
1550 height = srcDib.dsBm.bmHeight - ySrc;
1552 if (GetRgnBox(physDevSrc->region, &unusedRect) == COMPLEXREGION ||
1553 GetRgnBox(physDevDst->region, &unusedRect) == COMPLEXREGION)
1555 /* for simple regions, the clipping was already done by BITBLT_GetVisRectangles */
1556 FIXME("potential optimization: client-side complex region clipping\n");
1557 return FALSE;
1559 if (dstDib.dsBm.bmBitsPixel <= 8)
1561 FIXME("potential optimization: client-side color-index mode DIB copy\n");
1562 return FALSE;
1564 if (!(srcDib.dsBmih.biCompression == BI_BITFIELDS &&
1565 dstDib.dsBmih.biCompression == BI_BITFIELDS &&
1566 !memcmp(srcDib.dsBitfields, dstDib.dsBitfields, 3*sizeof(DWORD)))
1567 && !(srcDib.dsBmih.biCompression == BI_RGB &&
1568 dstDib.dsBmih.biCompression == BI_RGB))
1570 FIXME("potential optimization: client-side compressed DIB copy\n");
1571 return FALSE;
1573 if (srcDib.dsBm.bmBitsPixel != dstDib.dsBm.bmBitsPixel)
1575 FIXME("potential optimization: pixel format conversion\n");
1576 return FALSE;
1578 if (srcDib.dsBmih.biWidth < 0 || dstDib.dsBmih.biWidth < 0)
1580 FIXME("negative widths not yet implemented\n");
1581 return FALSE;
1584 switch (dstDib.dsBm.bmBitsPixel)
1586 case 15:
1587 case 16:
1588 bytesPerPixel = 2;
1589 break;
1590 case 24:
1591 bytesPerPixel = 3;
1592 break;
1593 case 32:
1594 bytesPerPixel = 4;
1595 break;
1596 default:
1597 FIXME("don't know how to work with a depth of %d\n", physDevSrc->depth);
1598 return FALSE;
1601 bytesToCopy = width * bytesPerPixel;
1603 if (srcDib.dsBmih.biHeight < 0)
1605 srcPtr = &physDevSrc->bitmap->base[ySrc*srcDib.dsBm.bmWidthBytes + xSrc*bytesPerPixel];
1606 srcRowOffset = srcDib.dsBm.bmWidthBytes;
1608 else
1610 srcPtr = &physDevSrc->bitmap->base[(srcDib.dsBm.bmHeight-ySrc-1)*srcDib.dsBm.bmWidthBytes
1611 + xSrc*bytesPerPixel];
1612 srcRowOffset = -srcDib.dsBm.bmWidthBytes;
1614 if (dstDib.dsBmih.biHeight < 0)
1616 dstPtr = &physDevDst->bitmap->base[yDst*dstDib.dsBm.bmWidthBytes + xDst*bytesPerPixel];
1617 dstRowOffset = dstDib.dsBm.bmWidthBytes;
1619 else
1621 dstPtr = &physDevDst->bitmap->base[(dstDib.dsBm.bmHeight-yDst-1)*dstDib.dsBm.bmWidthBytes
1622 + xDst*bytesPerPixel];
1623 dstRowOffset = -dstDib.dsBm.bmWidthBytes;
1626 for (y = yDst; y < yDst + height; ++y)
1628 memcpy(dstPtr, srcPtr, bytesToCopy);
1629 srcPtr += srcRowOffset;
1630 dstPtr += dstRowOffset;
1633 return TRUE;
1637 /***********************************************************************
1638 * X11DRV_BitBlt
1640 BOOL X11DRV_BitBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1641 INT width, INT height, X11DRV_PDEVICE *physDevSrc,
1642 INT xSrc, INT ySrc, DWORD rop )
1644 BOOL result = FALSE;
1645 INT sSrc, sDst;
1646 RECT visRectDst, visRectSrc;
1648 if (((rop >> 16) & 0x55) == ((rop >> 17) & 0x55)) {
1649 /* FIXME: seems the ROP doesn't include destination;
1650 * now if the destination area include the entire dcDst,
1651 * we can pass TRUE instead of FALSE to CoerceDIBSection(dcDst...),
1652 * which may avoid a copy in some situations */
1655 sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None, FALSE );
1656 if (physDevDst != physDevSrc)
1657 sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None, FALSE );
1658 else
1659 sSrc = sDst;
1661 if ((sSrc == DIB_Status_AppMod) && (rop == SRCCOPY) &&
1662 (physDevSrc->depth == physDevDst->depth))
1664 POINT pts[2];
1665 /* do everything ourselves; map coordinates */
1667 pts[0].x = xSrc;
1668 pts[0].y = ySrc;
1669 pts[1].x = xSrc + width;
1670 pts[1].y = ySrc + height;
1672 LPtoDP(physDevSrc->hdc, pts, 2);
1673 width = pts[1].x - pts[0].x;
1674 height = pts[1].y - pts[0].y;
1675 xSrc = pts[0].x;
1676 ySrc = pts[0].y;
1678 pts[0].x = xDst;
1679 pts[0].y = yDst;
1680 LPtoDP(physDevDst->hdc, pts, 1);
1682 xDst = pts[0].x;
1683 yDst = pts[0].y;
1685 /* Perform basic clipping */
1686 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, width, height,
1687 physDevSrc, xSrc, ySrc, width, height,
1688 &visRectSrc, &visRectDst ))
1689 goto END;
1691 xSrc = visRectSrc.left;
1692 ySrc = visRectSrc.top;
1693 xDst = visRectDst.left;
1694 yDst = visRectDst.top;
1695 width = visRectDst.right - visRectDst.left;
1696 height = visRectDst.bottom - visRectDst.top;
1698 if (sDst == DIB_Status_AppMod) {
1699 result = X11DRV_ClientSideDIBCopy( physDevSrc, xSrc, ySrc,
1700 physDevDst, xDst, yDst,
1701 width, height );
1702 if (result)
1703 goto END;
1704 /* fall back to X server copying */
1706 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1708 wine_tsx11_lock();
1709 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1710 wine_tsx11_unlock();
1712 X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, xSrc, ySrc, xDst, yDst, width, height );
1713 result = TRUE;
1714 goto END;
1717 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1718 if (physDevDst != physDevSrc)
1719 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1721 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, width, height,
1722 physDevSrc, xSrc, ySrc, width, height, rop );
1724 END:
1725 if (physDevDst != physDevSrc)
1726 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1727 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1729 return result;
1733 /***********************************************************************
1734 * X11DRV_StretchBlt
1736 BOOL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1737 INT widthDst, INT heightDst,
1738 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1739 INT widthSrc, INT heightSrc, DWORD rop )
1741 BOOL result;
1743 X11DRV_LockDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1744 if (physDevDst != physDevSrc)
1745 X11DRV_LockDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1747 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, widthDst, heightDst,
1748 physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop );
1750 if (physDevDst != physDevSrc)
1751 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1752 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1753 return result;