Avoid including X11/Intrinsic.h.
[wine/multimedia.git] / dlls / x11drv / bitblt.c
blob23de307e118666679cde3862e6013a1a6b563367
1 /*
2 * GDI bit-blit operations
4 * Copyright 1993, 1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winreg.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->org.x + visRectSrc->left,
879 physDevSrc->org.y + 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->org.x + visRectSrc->left,
929 physDevSrc->org.y + visRectSrc->top,
930 width, height, 0, 0, 1);
932 else
933 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
934 physDevSrc->org.x + visRectSrc->left,
935 physDevSrc->org.y + 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->org.x + visRectSrc->left,
944 physDevSrc->org.y + 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->org.x + visRectSrc->left,
951 physDevSrc->org.y + 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->org.x + visRectSrc->left,
986 physDevSrc->org.y + 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->org.x + visRectSrc->left,
995 physDevSrc->org.y + 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->org.x + visRectDst->left, physDev->org.y + 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->org.x + visRectDst->left,
1049 physDev->org.y + 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->org.x + visRectDst->left,
1056 physDev->org.y + 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->org.x + visRectDst->left,
1092 physDev->org.y + 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->org.x + visRectDst->left,
1108 physDev->org.y + 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 if (physDevSrc->bitmap)
1153 BITMAP bm;
1154 GetObjectW( physDevSrc->bitmap->hbitmap, sizeof(bm), &bm );
1155 SetRect( &clipRect, 0, 0, bm.bmWidth, bm.bmHeight );
1157 else SetRect( &clipRect, 0, 0, screen_width, screen_height );
1158 if (!IntersectRect( visRectSrc, &rect, &clipRect ))
1159 return FALSE;
1161 /* Intersect the rectangles */
1163 if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1165 visRectSrc->left += xDst - xSrc;
1166 visRectSrc->right += xDst - xSrc;
1167 visRectSrc->top += yDst - ySrc;
1168 visRectSrc->bottom += yDst - ySrc;
1169 if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1170 *visRectSrc = *visRectDst = rect;
1171 visRectSrc->left += xSrc - xDst;
1172 visRectSrc->right += xSrc - xDst;
1173 visRectSrc->top += ySrc - yDst;
1174 visRectSrc->bottom += ySrc - yDst;
1176 else /* stretching */
1178 /* Map source rectangle into destination coordinates */
1179 rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1180 rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1181 rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1182 rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1183 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1184 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1186 /* Avoid rounding errors */
1187 rect.left--;
1188 rect.top--;
1189 rect.right++;
1190 rect.bottom++;
1191 if (!IntersectRect( visRectDst, &rect, visRectDst )) return FALSE;
1193 /* Map destination rectangle back to source coordinates */
1194 rect = *visRectDst;
1195 rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1196 rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1197 rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1198 rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1199 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1200 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1202 /* Avoid rounding errors */
1203 rect.left--;
1204 rect.top--;
1205 rect.right++;
1206 rect.bottom++;
1207 if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1209 return TRUE;
1213 /***********************************************************************
1214 * BITBLT_InternalStretchBlt
1216 * Implementation of PatBlt(), BitBlt() and StretchBlt().
1218 static BOOL BITBLT_InternalStretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1219 INT widthDst, INT heightDst,
1220 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1221 INT widthSrc, INT heightSrc,
1222 DWORD rop )
1224 BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1225 RECT visRectDst, visRectSrc;
1226 INT width, height;
1227 const BYTE *opcode;
1228 Pixmap pixmaps[3] = { 0, 0, 0 }; /* pixmaps for DST, SRC, TMP */
1229 GC tmpGC = 0;
1230 POINT pts[2];
1232 /* compensate for off-by-one shifting for negative widths and heights */
1233 if (widthDst < 0)
1234 ++xDst;
1235 if (heightDst < 0)
1236 ++yDst;
1237 if (widthSrc < 0)
1238 ++xSrc;
1239 if (heightSrc < 0)
1240 ++ySrc;
1242 usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1243 useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1244 useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1245 if (!physDevSrc && useSrc) return FALSE;
1247 /* Map the coordinates to device coords */
1249 pts[0].x = xDst;
1250 pts[0].y = yDst;
1251 pts[1].x = xDst + widthDst;
1252 pts[1].y = yDst + heightDst;
1253 LPtoDP(physDevDst->hdc, pts, 2);
1254 xDst = pts[0].x;
1255 yDst = pts[0].y;
1256 widthDst = pts[1].x - pts[0].x;
1257 heightDst = pts[1].y - pts[0].y;
1259 TRACE(" rectdst=%d,%d-%d,%d orgdst=%ld,%ld\n",
1260 xDst, yDst, widthDst, heightDst,
1261 physDevDst->org.x, physDevDst->org.y );
1263 if (useSrc)
1265 pts[0].x = xSrc;
1266 pts[0].y = ySrc;
1267 pts[1].x = xSrc + widthSrc;
1268 pts[1].y = ySrc + heightSrc;
1269 LPtoDP(physDevSrc->hdc, pts, 2);
1270 xSrc = pts[0].x;
1271 ySrc = pts[0].y;
1272 widthSrc = pts[1].x - pts[0].x;
1273 heightSrc = pts[1].y - pts[0].y;
1275 fStretch = (widthSrc != widthDst) || (heightSrc != heightDst);
1276 TRACE(" rectsrc=%d,%d-%d,%d orgsrc=%ld,%ld\n",
1277 xSrc, ySrc, widthSrc, heightSrc,
1278 physDevSrc->org.x, physDevSrc->org.y );
1279 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1280 physDevSrc, xSrc, ySrc, widthSrc, heightSrc,
1281 &visRectSrc, &visRectDst ))
1282 return TRUE;
1283 TRACE(" vissrc=%ld,%ld-%ld,%ld visdst=%ld,%ld-%ld,%ld\n",
1284 visRectSrc.left, visRectSrc.top,
1285 visRectSrc.right, visRectSrc.bottom,
1286 visRectDst.left, visRectDst.top,
1287 visRectDst.right, visRectDst.bottom );
1289 else
1291 fStretch = FALSE;
1292 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1293 NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1294 return TRUE;
1295 TRACE(" vissrc=none visdst=%ld,%ld-%ld,%ld\n",
1296 visRectDst.left, visRectDst.top,
1297 visRectDst.right, visRectDst.bottom );
1300 width = visRectDst.right - visRectDst.left;
1301 height = visRectDst.bottom - visRectDst.top;
1303 if (!fStretch) switch(rop) /* A few optimisations */
1305 case BLACKNESS: /* 0x00 */
1306 wine_tsx11_lock();
1307 if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1308 XSetFunction( gdi_display, physDevDst->gc, GXclear );
1309 else
1311 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1312 XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1313 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1315 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1316 physDevDst->org.x + visRectDst.left,
1317 physDevDst->org.y + visRectDst.top,
1318 width, height );
1319 wine_tsx11_unlock();
1320 return TRUE;
1322 case DSTINVERT: /* 0x55 */
1323 wine_tsx11_lock();
1324 XSetFunction( gdi_display, physDevDst->gc, GXinvert );
1326 if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1327 XSetFunction( gdi_display, physDevDst->gc, GXinvert);
1328 else
1330 /* Xor is much better when we do not have full colormap. */
1331 /* Using white^black ensures that we invert at least black */
1332 /* and white. */
1333 unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1334 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1335 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1336 XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1337 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1339 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1340 physDevDst->org.x + visRectDst.left,
1341 physDevDst->org.y + visRectDst.top,
1342 width, height );
1343 wine_tsx11_unlock();
1344 return TRUE;
1346 case PATINVERT: /* 0x5a */
1347 if (X11DRV_SetupGCForBrush( physDevDst ))
1349 wine_tsx11_lock();
1350 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1351 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1352 physDevDst->org.x + visRectDst.left,
1353 physDevDst->org.y + visRectDst.top,
1354 width, height );
1355 wine_tsx11_unlock();
1357 return TRUE;
1359 case 0xa50065:
1360 if (X11DRV_SetupGCForBrush( physDevDst ))
1362 wine_tsx11_lock();
1363 XSetFunction( gdi_display, physDevDst->gc, GXequiv );
1364 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1365 physDevDst->org.x + visRectDst.left,
1366 physDevDst->org.y + visRectDst.top,
1367 width, height );
1368 wine_tsx11_unlock();
1370 return TRUE;
1372 case SRCCOPY: /* 0xcc */
1373 if (physDevSrc->depth == physDevDst->depth)
1375 wine_tsx11_lock();
1376 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1377 XCopyArea( gdi_display, physDevSrc->drawable,
1378 physDevDst->drawable, physDevDst->gc,
1379 physDevSrc->org.x + visRectSrc.left,
1380 physDevSrc->org.y + visRectSrc.top,
1381 width, height,
1382 physDevDst->org.x + visRectDst.left,
1383 physDevDst->org.y + visRectDst.top );
1384 physDevDst->exposures++;
1385 wine_tsx11_unlock();
1386 return TRUE;
1389 if (physDevSrc->depth == 1)
1391 int fg, bg;
1392 get_colors(physDevDst, physDevSrc, &fg, &bg);
1393 wine_tsx11_lock();
1395 XSetBackground( gdi_display, physDevDst->gc, fg );
1396 XSetForeground( gdi_display, physDevDst->gc, bg );
1397 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1398 XCopyPlane( gdi_display, physDevSrc->drawable,
1399 physDevDst->drawable, physDevDst->gc,
1400 physDevSrc->org.x + visRectSrc.left,
1401 physDevSrc->org.y + visRectSrc.top,
1402 width, height,
1403 physDevDst->org.x + visRectDst.left,
1404 physDevDst->org.y + visRectDst.top, 1 );
1405 physDevDst->exposures++;
1406 wine_tsx11_unlock();
1407 return TRUE;
1409 break;
1411 case PATCOPY: /* 0xf0 */
1412 if (!X11DRV_SetupGCForBrush( physDevDst )) return TRUE;
1413 wine_tsx11_lock();
1414 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1415 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1416 physDevDst->org.x + visRectDst.left,
1417 physDevDst->org.y + visRectDst.top,
1418 width, height );
1419 wine_tsx11_unlock();
1420 return TRUE;
1422 case WHITENESS: /* 0xff */
1423 wine_tsx11_lock();
1424 if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1425 XSetFunction( gdi_display, physDevDst->gc, GXset );
1426 else
1428 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1429 XSetForeground( gdi_display, physDevDst->gc,
1430 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1431 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1433 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1434 physDevDst->org.x + visRectDst.left,
1435 physDevDst->org.y + visRectDst.top,
1436 width, height );
1437 wine_tsx11_unlock();
1438 return TRUE;
1441 wine_tsx11_lock();
1443 tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1444 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1445 XSetGraphicsExposures( gdi_display, tmpGC, False );
1446 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1447 physDevDst->depth );
1448 if (useSrc)
1450 pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1451 physDevDst->depth );
1452 if (fStretch)
1453 BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1454 xSrc, ySrc, widthSrc, heightSrc,
1455 xDst, yDst, widthDst, heightDst,
1456 &visRectSrc, &visRectDst );
1457 else
1458 BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1459 xSrc, ySrc, &visRectSrc );
1462 if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &visRectDst );
1463 if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1464 else fNullBrush = FALSE;
1465 destUsed = FALSE;
1467 for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1469 if (OP_DST(*opcode) == DST) destUsed = TRUE;
1470 XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1471 switch(OP_SRCDST(*opcode))
1473 case OP_ARGS(DST,TMP):
1474 case OP_ARGS(SRC,TMP):
1475 if (!pixmaps[TMP])
1476 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1477 width, height, physDevDst->depth );
1478 /* fall through */
1479 case OP_ARGS(DST,SRC):
1480 case OP_ARGS(SRC,DST):
1481 case OP_ARGS(TMP,SRC):
1482 case OP_ARGS(TMP,DST):
1483 if (useSrc)
1484 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1485 pixmaps[OP_DST(*opcode)], tmpGC,
1486 0, 0, width, height, 0, 0 );
1487 break;
1489 case OP_ARGS(PAT,TMP):
1490 if (!pixmaps[TMP] && !fNullBrush)
1491 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1492 width, height, physDevDst->depth );
1493 /* fall through */
1494 case OP_ARGS(PAT,DST):
1495 case OP_ARGS(PAT,SRC):
1496 if (!fNullBrush)
1497 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1498 tmpGC, 0, 0, width, height );
1499 break;
1502 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1503 physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC],
1504 &visRectDst );
1505 XFreePixmap( gdi_display, pixmaps[DST] );
1506 if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1507 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1508 XFreeGC( gdi_display, tmpGC );
1509 wine_tsx11_unlock();
1510 return TRUE;
1514 /***********************************************************************
1515 * X11DRV_PatBlt
1517 BOOL X11DRV_PatBlt( X11DRV_PDEVICE *physDev, INT left, INT top, INT width, INT height, DWORD rop )
1519 BOOL result;
1521 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1522 result = BITBLT_InternalStretchBlt( physDev, left, top, width, height, NULL, 0, 0, 0, 0, rop );
1523 X11DRV_UnlockDIBSection( physDev, TRUE );
1524 return result;
1528 /***********************************************************************
1529 * X11DRV_BitBlt
1531 BOOL X11DRV_BitBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1532 INT width, INT height, X11DRV_PDEVICE *physDevSrc,
1533 INT xSrc, INT ySrc, DWORD rop )
1535 BOOL result = FALSE;
1536 INT sSrc, sDst;
1537 RECT visRectDst, visRectSrc;
1539 if (((rop >> 16) & 0x55) == ((rop >> 17) & 0x55)) {
1540 /* FIXME: seems the ROP doesn't include destination;
1541 * now if the destination area include the entire dcDst,
1542 * we can pass TRUE instead of FALSE to CoerceDIBSection(dcDst...),
1543 * which may avoid a copy in some situations */
1546 sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None, FALSE );
1547 if (physDevDst != physDevSrc)
1548 sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None, FALSE );
1549 else
1550 sSrc = sDst;
1552 if ((sSrc == DIB_Status_AppMod) && (rop == SRCCOPY) &&
1553 (physDevSrc->depth == physDevDst->depth))
1555 POINT pts[2];
1556 /* do everything ourselves; map coordinates */
1558 pts[0].x = xSrc;
1559 pts[0].y = ySrc;
1560 pts[1].x = xSrc + width;
1561 pts[1].y = ySrc + height;
1563 LPtoDP(physDevSrc->hdc, pts, 2);
1564 width = pts[1].x - pts[0].x;
1565 height = pts[1].y - pts[0].y;
1566 xSrc = pts[0].x;
1567 ySrc = pts[0].y;
1569 pts[0].x = xDst;
1570 pts[0].y = yDst;
1571 LPtoDP(physDevDst->hdc, pts, 1);
1573 xDst = pts[0].x;
1574 yDst = pts[0].y;
1576 /* Perform basic clipping */
1577 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, width, height,
1578 physDevSrc, xSrc, ySrc, width, height,
1579 &visRectSrc, &visRectDst ))
1580 goto END;
1582 xSrc = visRectSrc.left;
1583 ySrc = visRectSrc.top;
1584 xDst = visRectDst.left;
1585 yDst = visRectDst.top;
1586 width = visRectDst.right - visRectDst.left;
1587 height = visRectDst.bottom - visRectDst.top;
1589 if (sDst == DIB_Status_AppMod) {
1590 FIXME("potential optimization - client-side DIB copy\n");
1592 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1594 X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, xSrc, ySrc, xDst, yDst, width, height );
1595 result = TRUE;
1596 goto END;
1599 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1600 if (physDevDst != physDevSrc)
1601 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1603 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, width, height,
1604 physDevSrc, xSrc, ySrc, width, height, rop );
1606 END:
1607 if (physDevDst != physDevSrc)
1608 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1609 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1611 return result;
1615 /***********************************************************************
1616 * X11DRV_StretchBlt
1618 BOOL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1619 INT widthDst, INT heightDst,
1620 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1621 INT widthSrc, INT heightSrc, DWORD rop )
1623 BOOL result;
1625 X11DRV_LockDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1626 if (physDevDst != physDevSrc)
1627 X11DRV_LockDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1629 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, widthDst, heightDst,
1630 physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop );
1632 if (physDevDst != physDevSrc)
1633 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1634 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1635 return result;