Change RECT to use LONG to match win32 standard headers and fix format
[wine/multimedia.git] / graphics / x11drv / bitblt.c
blob4cb3889ee812eb32b7569f7911a138ef0dcce34f
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 <X11/Intrinsic.h>
25 #include "ts_xlib.h"
27 #include <assert.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winreg.h"
33 #include "winuser.h"
34 #include "bitmap.h"
35 #include "gdi.h"
36 #include "x11drv.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
42 #define DST 0 /* Destination drawable */
43 #define SRC 1 /* Source drawable */
44 #define TMP 2 /* Temporary drawable */
45 #define PAT 3 /* Pattern (brush) in destination DC */
47 #define OP(src,dst,rop) (OP_ARGS(src,dst) << 4 | (rop))
48 #define OP_ARGS(src,dst) (((src) << 2) | (dst))
50 #define OP_SRC(opcode) ((opcode) >> 6)
51 #define OP_DST(opcode) (((opcode) >> 4) & 3)
52 #define OP_SRCDST(opcode) ((opcode) >> 4)
53 #define OP_ROP(opcode) ((opcode) & 0x0f)
55 #define MAX_OP_LEN 6 /* Longest opcode + 1 for the terminating 0 */
57 #define SWAP_INT32(i1,i2) \
58 do { INT __t = *(i1); *(i1) = *(i2); *(i2) = __t; } while(0)
60 static const unsigned char BITBLT_Opcodes[256][MAX_OP_LEN] =
62 { OP(PAT,DST,GXclear) }, /* 0x00 0 */
63 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnor) }, /* 0x01 ~(D|(P|S)) */
64 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXand) }, /* 0x02 D&~(P|S) */
65 { OP(PAT,SRC,GXnor) }, /* 0x03 ~(P|S) */
66 { OP(PAT,DST,GXnor), OP(SRC,DST,GXand) }, /* 0x04 S&~(D|P) */
67 { OP(PAT,DST,GXnor) }, /* 0x05 ~(D|P) */
68 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnor), }, /* 0x06 ~(P|~(D^S)) */
69 { OP(SRC,DST,GXand), OP(PAT,DST,GXnor) }, /* 0x07 ~(P|(D&S)) */
70 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXand) },/* 0x08 S&D&~P */
71 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnor) }, /* 0x09 ~(P|(D^S)) */
72 { OP(PAT,DST,GXandInverted) }, /* 0x0a D&~P */
73 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXnor) }, /* 0x0b ~(P|(S&~D)) */
74 { OP(PAT,SRC,GXandInverted) }, /* 0x0c S&~P */
75 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXnor) },/* 0x0d ~(P|(D&~S)) */
76 { OP(SRC,DST,GXnor), OP(PAT,DST,GXnor) }, /* 0x0e ~(P|~(D|S)) */
77 { OP(PAT,DST,GXcopyInverted) }, /* 0x0f ~P */
78 { OP(SRC,DST,GXnor), OP(PAT,DST,GXand) }, /* 0x10 P&~(S|D) */
79 { OP(SRC,DST,GXnor) }, /* 0x11 ~(D|S) */
80 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnor) }, /* 0x12 ~(S|~(D^P)) */
81 { OP(PAT,DST,GXand), OP(SRC,DST,GXnor) }, /* 0x13 ~(S|(D&P)) */
82 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnor) }, /* 0x14 ~(D|~(P^S)) */
83 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnor) }, /* 0x15 ~(D|(P&S)) */
84 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
85 OP(TMP,DST,GXand), OP(SRC,DST,GXxor),
86 OP(PAT,DST,GXxor) }, /* 0x16 P^S^(D&~(P&S) */
87 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
88 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
89 OP(TMP,DST,GXequiv) }, /* 0x17 ~S^((S^P)&(S^D))*/
90 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
91 OP(SRC,DST,GXand) }, /* 0x18 (S^P)&(D^P) */
92 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
93 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x19 ~S^(D&~(P&S)) */
94 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
95 OP(PAT,DST,GXxor) }, /* 0x1a P^(D|(S&P)) */
96 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXxor),
97 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x1b ~S^(D&(P^S)) */
98 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
99 OP(PAT,DST,GXxor) }, /* 0x1c P^(S|(D&P)) */
100 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
101 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x1d ~D^(S&(D^P)) */
102 { OP(SRC,DST,GXor), OP(PAT,DST,GXxor) }, /* 0x1e P^(D|S) */
103 { OP(SRC,DST,GXor), OP(PAT,DST,GXnand) }, /* 0x1f ~(P&(D|S)) */
104 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXand) }, /* 0x20 D&(P&~S) */
105 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnor) }, /* 0x21 ~(S|(D^P)) */
106 { OP(SRC,DST,GXandInverted) }, /* 0x22 ~S&D */
107 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x23 ~(S|(P&~D)) */
108 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
109 OP(SRC,DST,GXand) }, /* 0x24 (S^P)&(S^D) */
110 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand),
111 OP(PAT,DST,GXequiv) }, /* 0x25 ~P^(D&~(S&P)) */
112 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
113 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x26 S^(D|(S&P)) */
114 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXequiv),
115 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x27 S^(D|~(P^S)) */
116 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand) }, /* 0x28 D&(P^S) */
117 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
118 OP(TMP,DST,GXor), OP(SRC,DST,GXxor),
119 OP(PAT,DST,GXequiv) }, /* 0x29 ~P^S^(D|(P&S)) */
120 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand) }, /* 0x2a D&~(P&S) */
121 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
122 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
123 OP(TMP,DST,GXequiv) }, /* 0x2b ~S^((P^S)&(P^D))*/
124 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
125 OP(SRC,DST,GXxor) }, /* 0x2c S^(P&(S|D)) */
126 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXxor) }, /* 0x2d P^(S|~D) */
127 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
128 OP(PAT,DST,GXxor) }, /* 0x2e P^(S|(D^P)) */
129 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXnand) }, /* 0x2f ~(P&(S|~D)) */
130 { OP(PAT,SRC,GXandReverse) }, /* 0x30 P&~S */
131 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXnor) },/* 0x31 ~(S|(D&~P)) */
132 { OP(SRC,DST,GXor), OP(PAT,DST,GXor),
133 OP(SRC,DST,GXxor) }, /* 0x32 S^(D|P|S) */
134 { OP(SRC,DST,GXcopyInverted) }, /* 0x33 ~S */
135 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
136 OP(SRC,DST,GXxor) }, /* 0x34 S^(P|(D&S)) */
137 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor),
138 OP(SRC,DST,GXxor) }, /* 0x35 S^(P|~(D^S)) */
139 { OP(PAT,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x36 S^(D|P) */
140 { OP(PAT,DST,GXor), OP(SRC,DST,GXnand) }, /* 0x37 ~(S&(D|P)) */
141 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
142 OP(PAT,DST,GXxor) }, /* 0x38 P^(S&(D|P)) */
143 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x39 S^(P|~D) */
144 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
145 OP(SRC,DST,GXxor) }, /* 0x3a S^(P|(D^S)) */
146 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x3b ~(S&(P|~D)) */
147 { OP(PAT,SRC,GXxor) }, /* 0x3c P^S */
148 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
149 OP(SRC,DST,GXxor) }, /* 0x3d S^(P|~(D|S)) */
150 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
151 OP(SRC,DST,GXxor) }, /* 0x3e S^(P|(D&~S)) */
152 { OP(PAT,SRC,GXnand) }, /* 0x3f ~(P&S) */
153 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXand) }, /* 0x40 P&S&~D */
154 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnor) }, /* 0x41 ~(D|(P^S)) */
155 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
156 OP(SRC,DST,GXand) }, /* 0x42 (S^D)&(P^D) */
157 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
158 OP(SRC,DST,GXequiv) }, /* 0x43 ~S^(P&~(D&S)) */
159 { OP(SRC,DST,GXandReverse) }, /* 0x44 S&~D */
160 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x45 ~(D|(P&~S)) */
161 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
162 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x46 D^(S|(P&D)) */
163 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
164 OP(PAT,DST,GXequiv) }, /* 0x47 ~P^(S&(D^P)) */
165 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand) }, /* 0x48 S&(P^D) */
166 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
167 OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
168 OP(PAT,DST,GXequiv) }, /* 0x49 ~P^D^(S|(P&D)) */
169 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
170 OP(SRC,DST,GXxor) }, /* 0x4a D^(P&(S|D)) */
171 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXxor) }, /* 0x4b P^(D|~S) */
172 { OP(PAT,DST,GXnand), OP(SRC,DST,GXand) }, /* 0x4c S&~(D&P) */
173 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
174 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
175 OP(TMP,DST,GXequiv) }, /* 0x4d ~S^((S^P)|(S^D))*/
176 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
177 OP(PAT,DST,GXxor) }, /* 0x4e P^(D|(S^P)) */
178 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXnand) },/* 0x4f ~(P&(D|~S)) */
179 { OP(PAT,DST,GXandReverse) }, /* 0x50 P&~D */
180 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXnor) },/* 0x51 ~(D|(S&~P)) */
181 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
182 OP(SRC,DST,GXxor) }, /* 0x52 D^(P|(S&D)) */
183 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
184 OP(SRC,DST,GXequiv) }, /* 0x53 ~S^(P&(D^S)) */
185 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXnor) }, /* 0x54 ~(D|~(P|S)) */
186 { OP(PAT,DST,GXinvert) }, /* 0x55 ~D */
187 { OP(PAT,SRC,GXor), OP(SRC,DST,GXxor) }, /* 0x56 D^(P|S) */
188 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnand) }, /* 0x57 ~(D&(P|S)) */
189 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
190 OP(PAT,DST,GXxor) }, /* 0x58 P^(D&(P|S)) */
191 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x59 D^(P|~S) */
192 { OP(PAT,DST,GXxor) }, /* 0x5a D^P */
193 { OP(DST,SRC,GXnor), OP(PAT,SRC,GXor),
194 OP(SRC,DST,GXxor) }, /* 0x5b D^(P|~(S|D)) */
195 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
196 OP(SRC,DST,GXxor) }, /* 0x5c D^(P|(S^D)) */
197 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x5d ~(D&(P|~S)) */
198 { OP(DST,SRC,GXandInverted), OP(PAT,SRC,GXor),
199 OP(SRC,DST,GXxor) }, /* 0x5e D^(P|(S&~D)) */
200 { OP(PAT,DST,GXnand) }, /* 0x5f ~(D&P) */
201 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand) }, /* 0x60 P&(D^S) */
202 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
203 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
204 OP(TMP,DST,GXequiv) }, /* 0x61 ~D^S^(P|(D&S)) */
205 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
206 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x62 D^(S&(P|D)) */
207 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x63 S^(D|~P) */
208 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
209 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x64 S^(D&(P|S)) */
210 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x65 D^(S|~P) */
211 { OP(SRC,DST,GXxor) }, /* 0x66 S^D */
212 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
213 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x67 S^(D|~(S|P) */
214 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnor),
215 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
216 OP(TMP,DST,GXequiv) }, /* 0x68 ~D^S^(P|~(D|S))*/
217 { OP(SRC,DST,GXxor), OP(PAT,DST,GXequiv) }, /* 0x69 ~P^(D^S) */
218 { OP(PAT,SRC,GXand), OP(SRC,DST,GXxor) }, /* 0x6a D^(P&S) */
219 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
220 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
221 OP(PAT,DST,GXequiv) }, /* 0x6b ~P^S^(D&(P|S)) */
222 { OP(PAT,DST,GXand), OP(SRC,DST,GXxor) }, /* 0x6c S^(D&P) */
223 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
224 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
225 OP(PAT,DST,GXequiv) }, /* 0x6d ~P^D^(S&(P|D)) */
226 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
227 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x6e S^(D&(P|~S)) */
228 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnand) }, /* 0x6f ~(P&~(S^D)) */
229 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand) }, /* 0x70 P&~(D&S) */
230 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
231 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
232 OP(TMP,DST,GXequiv) }, /* 0x71 ~S^((S^D)&(P^D))*/
233 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
234 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x72 S^(D|(P^S)) */
235 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXnand) },/* 0x73 ~(S&(D|~P)) */
236 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
237 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x74 D^(S|(P^D)) */
238 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXnand) },/* 0x75 ~(D&(S|~P)) */
239 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
240 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x76 S^(D|(P&~S)) */
241 { OP(SRC,DST,GXnand) }, /* 0x77 ~(S&D) */
242 { OP(SRC,DST,GXand), OP(PAT,DST,GXxor) }, /* 0x78 P^(D&S) */
243 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
244 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
245 OP(TMP,DST,GXequiv) }, /* 0x79 ~D^S^(P&(D|S)) */
246 { OP(DST,SRC,GXorInverted), OP(PAT,SRC,GXand),
247 OP(SRC,DST,GXxor) }, /* 0x7a D^(P&(S|~D)) */
248 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7b ~(S&~(D^P)) */
249 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
250 OP(SRC,DST,GXxor) }, /* 0x7c S^(P&(D|~S)) */
251 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7d ~(D&~(P^S)) */
252 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
253 OP(SRC,DST,GXor) }, /* 0x7e (S^P)|(S^D) */
254 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnand) }, /* 0x7f ~(D&P&S) */
255 { OP(PAT,SRC,GXand), OP(SRC,DST,GXand) }, /* 0x80 D&P&S */
256 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
257 OP(SRC,DST,GXnor) }, /* 0x81 ~((S^P)|(S^D)) */
258 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXand) }, /* 0x82 D&~(P^S) */
259 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
260 OP(SRC,DST,GXequiv) }, /* 0x83 ~S^(P&(D|~S)) */
261 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXand) }, /* 0x84 S&~(D^P) */
262 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand),
263 OP(PAT,DST,GXequiv) }, /* 0x85 ~P^(D&(S|~P)) */
264 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
265 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
266 OP(TMP,DST,GXxor) }, /* 0x86 D^S^(P&(D|S)) */
267 { OP(SRC,DST,GXand), OP(PAT,DST,GXequiv) }, /* 0x87 ~P^(D&S) */
268 { OP(SRC,DST,GXand) }, /* 0x88 S&D */
269 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
270 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x89 ~S^(D|(P&~S)) */
271 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8a D&(S|~P) */
272 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
273 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8b ~D^(S|(P^D)) */
274 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8c S&(D|~P) */
275 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
276 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8d ~S^(D|(P^S)) */
277 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
278 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
279 OP(TMP,DST,GXxor) }, /* 0x8e S^((S^D)&(P^D))*/
280 { OP(SRC,DST,GXnand), OP(PAT,DST,GXnand) }, /* 0x8f ~(P&~(D&S)) */
281 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXand) }, /* 0x90 P&~(D^S) */
282 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
283 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x91 ~S^(D&(P|~S)) */
284 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
285 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
286 OP(TMP,DST,GXxor) }, /* 0x92 D^P^(S&(D|P)) */
287 { OP(PAT,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x93 ~S^(P&D) */
288 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
289 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
290 OP(TMP,DST,GXxor) }, /* 0x94 S^P^(D&(P|S)) */
291 { OP(PAT,SRC,GXand), OP(SRC,DST,GXequiv) }, /* 0x95 ~D^(P&S) */
292 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXxor) }, /* 0x96 D^P^S */
293 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
294 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
295 OP(TMP,DST,GXxor) }, /* 0x97 S^P^(D|~(P|S)) */
296 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
297 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x98 ~S^(D|~(P|S)) */
298 { OP(SRC,DST,GXequiv) }, /* 0x99 ~S^D */
299 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9a D^(P&~S) */
300 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
301 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9b ~S^(D&(P|S)) */
302 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9c S^(P&~D) */
303 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
304 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9d ~D^(S&(P|D)) */
305 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
306 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
307 OP(TMP,DST,GXxor) }, /* 0x9e D^S^(P|(D&S)) */
308 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnand) }, /* 0x9f ~(P&(D^S)) */
309 { OP(PAT,DST,GXand) }, /* 0xa0 D&P */
310 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor),
311 OP(PAT,DST,GXequiv) }, /* 0xa1 ~P^(D|(S&~P)) */
312 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXand) }, /* 0xa2 D&(P|~S) */
313 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
314 OP(SRC,DST,GXequiv) }, /* 0xa3 ~D^(P|(S^D)) */
315 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor),
316 OP(PAT,DST,GXequiv) }, /* 0xa4 ~P^(D|~(S|P)) */
317 { OP(PAT,DST,GXequiv) }, /* 0xa5 ~P^D */
318 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXxor) },/* 0xa6 D^(S&~P) */
319 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
320 OP(PAT,DST,GXequiv) }, /* 0xa7 ~P^(D&(S|P)) */
321 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand) }, /* 0xa8 D&(P|S) */
322 { OP(PAT,SRC,GXor), OP(SRC,DST,GXequiv) }, /* 0xa9 ~D^(P|S) */
323 { OP(SRC,DST,GXnoop) }, /* 0xaa D */
324 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor) }, /* 0xab D|~(P|S) */
325 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
326 OP(SRC,DST,GXxor) }, /* 0xac S^(P&(D^S)) */
327 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
328 OP(SRC,DST,GXequiv) }, /* 0xad ~D^(P|(S&D)) */
329 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor) }, /* 0xae D|(S&~P) */
330 { OP(PAT,DST,GXorInverted) }, /* 0xaf D|~P */
331 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand) }, /* 0xb0 P&(D|~S) */
332 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
333 OP(PAT,DST,GXequiv) }, /* 0xb1 ~P^(D|(S^P)) */
334 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
335 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
336 OP(TMP,DST,GXxor) }, /* 0xb2 S^((S^P)|(S^D))*/
337 { OP(PAT,DST,GXnand), OP(SRC,DST,GXnand) }, /* 0xb3 ~(S&~(D&P)) */
338 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXxor) }, /* 0xb4 P^(S&~D) */
339 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
340 OP(SRC,DST,GXequiv) }, /* 0xb5 ~D^(P&(S|D)) */
341 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
342 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
343 OP(TMP,DST,GXxor) }, /* 0xb6 D^P^(S|(D&P)) */
344 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnand) }, /* 0xb7 ~(S&(D^P)) */
345 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
346 OP(PAT,DST,GXxor) }, /* 0xb8 P^(S&(D^P)) */
347 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
348 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xb9 ~D^(S|(P&D)) */
349 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXor) }, /* 0xba D|(P&~S) */
350 { OP(SRC,DST,GXorInverted) }, /* 0xbb ~S|D */
351 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
352 OP(SRC,DST,GXxor) }, /* 0xbc S^(P&~(D&S)) */
353 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
354 OP(SRC,DST,GXnand) }, /* 0xbd ~((S^D)&(P^D)) */
355 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor) }, /* 0xbe D|(P^S) */
356 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXor) }, /* 0xbf D|~(P&S) */
357 { OP(PAT,SRC,GXand) }, /* 0xc0 P&S */
358 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
359 OP(SRC,DST,GXequiv) }, /* 0xc1 ~S^(P|(D&~S)) */
360 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
361 OP(SRC,DST,GXequiv) }, /* 0xc2 ~S^(P|~(D|S)) */
362 { OP(PAT,SRC,GXequiv) }, /* 0xc3 ~P^S */
363 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXand) }, /* 0xc4 S&(P|~D) */
364 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
365 OP(SRC,DST,GXequiv) }, /* 0xc5 ~S^(P|(D^S)) */
366 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXxor) },/* 0xc6 S^(D&~P) */
367 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
368 OP(PAT,DST,GXequiv) }, /* 0xc7 ~P^(S&(D|P)) */
369 { OP(PAT,DST,GXor), OP(SRC,DST,GXand) }, /* 0xc8 S&(D|P) */
370 { OP(PAT,DST,GXor), OP(SRC,DST,GXequiv) }, /* 0xc9 ~S^(P|D) */
371 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXand),
372 OP(SRC,DST,GXxor) }, /* 0xca D^(P&(S^D)) */
373 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
374 OP(SRC,DST,GXequiv) }, /* 0xcb ~S^(P|(D&S)) */
375 { OP(SRC,DST,GXcopy) }, /* 0xcc S */
376 { OP(PAT,DST,GXnor), OP(SRC,DST,GXor) }, /* 0xcd S|~(D|P) */
377 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXor) }, /* 0xce S|(D&~P) */
378 { OP(PAT,SRC,GXorInverted) }, /* 0xcf S|~P */
379 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXand) }, /* 0xd0 P&(S|~D) */
380 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
381 OP(PAT,DST,GXequiv) }, /* 0xd1 ~P^(S|(D^P)) */
382 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXxor) },/* 0xd2 P^(D&~S) */
383 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
384 OP(SRC,DST,GXequiv) }, /* 0xd3 ~S^(P&(D|S)) */
385 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
386 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
387 OP(TMP,DST,GXxor) }, /* 0xd4 S^((S^P)&(D^P))*/
388 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXnand) }, /* 0xd5 ~(D&~(P&S)) */
389 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
390 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
391 OP(TMP,DST,GXxor) }, /* 0xd6 S^P^(D|(P&S)) */
392 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnand) }, /* 0xd7 ~(D&(P^S)) */
393 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
394 OP(PAT,DST,GXxor) }, /* 0xd8 P^(D&(S^P)) */
395 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
396 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xd9 ~S^(D|(P&S)) */
397 { OP(DST,SRC,GXnand), OP(PAT,SRC,GXand),
398 OP(SRC,DST,GXxor) }, /* 0xda D^(P&~(S&D)) */
399 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
400 OP(SRC,DST,GXnand) }, /* 0xdb ~((S^P)&(S^D)) */
401 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXor) }, /* 0xdc S|(P&~D) */
402 { OP(SRC,DST,GXorReverse) }, /* 0xdd S|~D */
403 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor) }, /* 0xde S|(D^P) */
404 { OP(PAT,DST,GXnand), OP(SRC,DST,GXor) }, /* 0xdf S|~(D&P) */
405 { OP(SRC,DST,GXor), OP(PAT,DST,GXand) }, /* 0xe0 P&(D|S) */
406 { OP(SRC,DST,GXor), OP(PAT,DST,GXequiv) }, /* 0xe1 ~P^(D|S) */
407 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
408 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe2 D^(S&(P^D)) */
409 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
410 OP(PAT,DST,GXequiv) }, /* 0xe3 ~P^(S|(D&P)) */
411 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
412 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe4 S^(D&(P^S)) */
413 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
414 OP(PAT,DST,GXequiv) }, /* 0xe5 ~P^(D|(S&P)) */
415 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
416 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe6 S^(D&~(P&S)) */
417 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
418 OP(SRC,DST,GXnand) }, /* 0xe7 ~((S^P)&(D^P)) */
419 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
420 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
421 OP(TMP,DST,GXxor) }, /* 0xe8 S^((S^P)&(S^D))*/
422 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnand),
423 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
424 OP(TMP,DST,GXequiv) }, /* 0xe9 ~D^S^(P&~(S&D))*/
425 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor) }, /* 0xea D|(P&S) */
426 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXor) }, /* 0xeb D|~(P^S) */
427 { OP(PAT,DST,GXand), OP(SRC,DST,GXor) }, /* 0xec S|(D&P) */
428 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXor) }, /* 0xed S|~(D^P) */
429 { OP(SRC,DST,GXor) }, /* 0xee S|D */
430 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXor) }, /* 0xef S|D|~P */
431 { OP(PAT,DST,GXcopy) }, /* 0xf0 P */
432 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor) }, /* 0xf1 P|~(D|S) */
433 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor) }, /* 0xf2 P|(D&~S) */
434 { OP(PAT,SRC,GXorReverse) }, /* 0xf3 P|~S */
435 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXor) }, /* 0xf4 P|(S&~D) */
436 { OP(PAT,DST,GXorReverse) }, /* 0xf5 P|~D */
437 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor) }, /* 0xf6 P|(D^S) */
438 { OP(SRC,DST,GXnand), OP(PAT,DST,GXor) }, /* 0xf7 P|~(S&D) */
439 { OP(SRC,DST,GXand), OP(PAT,DST,GXor) }, /* 0xf8 P|(D&S) */
440 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor) }, /* 0xf9 P|~(D^S) */
441 { OP(PAT,DST,GXor) }, /* 0xfa D|P */
442 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXor) }, /* 0xfb D|P|~S */
443 { OP(PAT,SRC,GXor) }, /* 0xfc P|S */
444 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXor) }, /* 0xfd P|S|~D */
445 { OP(SRC,DST,GXor), OP(PAT,DST,GXor) }, /* 0xfe P|D|S */
446 { OP(PAT,DST,GXset) } /* 0xff 1 */
450 #ifdef BITBLT_TEST /* Opcodes test */
452 static int do_bitop( int s, int d, int rop )
454 int res;
455 switch(rop)
457 case GXclear: res = 0; break;
458 case GXand: res = s & d; break;
459 case GXandReverse: res = s & ~d; break;
460 case GXcopy: res = s; break;
461 case GXandInverted: res = ~s & d; break;
462 case GXnoop: res = d; break;
463 case GXxor: res = s ^ d; break;
464 case GXor: res = s | d; break;
465 case GXnor: res = ~(s | d); break;
466 case GXequiv: res = ~s ^ d; break;
467 case GXinvert: res = ~d; break;
468 case GXorReverse: res = s | ~d; break;
469 case GXcopyInverted: res = ~s; break;
470 case GXorInverted: res = ~s | d; break;
471 case GXnand: res = ~(s & d); break;
472 case GXset: res = 1; break;
474 return res & 1;
477 int main()
479 int rop, i, res, src, dst, pat, tmp, dstUsed;
480 const BYTE *opcode;
482 for (rop = 0; rop < 256; rop++)
484 res = dstUsed = 0;
485 for (i = 0; i < 8; i++)
487 pat = (i >> 2) & 1;
488 src = (i >> 1) & 1;
489 dst = i & 1;
490 for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
492 switch(*opcode >> 4)
494 case OP_ARGS(DST,TMP):
495 tmp = do_bitop( dst, tmp, *opcode & 0xf );
496 break;
497 case OP_ARGS(DST,SRC):
498 src = do_bitop( dst, src, *opcode & 0xf );
499 break;
500 case OP_ARGS(SRC,TMP):
501 tmp = do_bitop( src, tmp, *opcode & 0xf );
502 break;
503 case OP_ARGS(SRC,DST):
504 dst = do_bitop( src, dst, *opcode & 0xf );
505 dstUsed = 1;
506 break;
507 case OP_ARGS(PAT,TMP):
508 tmp = do_bitop( pat, tmp, *opcode & 0xf );
509 break;
510 case OP_ARGS(PAT,DST):
511 dst = do_bitop( pat, dst, *opcode & 0xf );
512 dstUsed = 1;
513 break;
514 case OP_ARGS(PAT,SRC):
515 src = do_bitop( pat, src, *opcode & 0xf );
516 break;
517 case OP_ARGS(TMP,DST):
518 dst = do_bitop( tmp, dst, *opcode & 0xf );
519 dstUsed = 1;
520 break;
521 case OP_ARGS(TMP,SRC):
522 src = do_bitop( tmp, src, *opcode & 0xf );
523 break;
524 default:
525 printf( "Invalid opcode %x\n", *opcode );
528 if (!dstUsed) dst = src;
529 if (dst) res |= 1 << i;
531 if (res != rop) printf( "%02x: ERROR, res=%02x\n", rop, res );
534 return 0;
537 #endif /* BITBLT_TEST */
540 /***********************************************************************
541 * perfect_graphics
543 * Favor correctness or speed?
545 static int perfect_graphics(void)
547 static int perfect = -1;
548 if (perfect == -1)
550 HKEY hkey;
551 char buffer[20];
552 /* default value */
553 perfect = 0;
554 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
556 DWORD type, count = sizeof(buffer);
557 if(!RegQueryValueExA(hkey, "PerfectGraphics", 0, &type, buffer, &count))
559 char ch = buffer[0];
560 perfect = (ch == 'y' || ch == 'Y' || ch == 't' || ch == 'T' || ch == '1');
562 RegCloseKey(hkey);
565 return perfect;
568 /***********************************************************************
569 * BITBLT_StretchRow
571 * Stretch a row of pixels. Helper function for BITBLT_StretchImage.
573 static void BITBLT_StretchRow( int *rowSrc, int *rowDst,
574 INT startDst, INT widthDst,
575 INT xinc, INT xoff, WORD mode )
577 register INT xsrc = xinc * startDst + xoff;
578 rowDst += startDst;
579 switch(mode)
581 case STRETCH_ANDSCANS:
582 for(; widthDst > 0; widthDst--, xsrc += xinc)
583 *rowDst++ &= rowSrc[xsrc >> 16];
584 break;
585 case STRETCH_ORSCANS:
586 for(; widthDst > 0; widthDst--, xsrc += xinc)
587 *rowDst++ |= rowSrc[xsrc >> 16];
588 break;
589 case STRETCH_DELETESCANS:
590 for(; widthDst > 0; widthDst--, xsrc += xinc)
591 *rowDst++ = rowSrc[xsrc >> 16];
592 break;
597 /***********************************************************************
598 * BITBLT_ShrinkRow
600 * Shrink a row of pixels. Helper function for BITBLT_StretchImage.
602 static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst,
603 INT startSrc, INT widthSrc,
604 INT xinc, INT xoff, WORD mode )
606 register INT xdst = xinc * startSrc + xoff;
607 rowSrc += startSrc;
608 switch(mode)
610 case STRETCH_ORSCANS:
611 for(; widthSrc > 0; widthSrc--, xdst += xinc)
612 rowDst[xdst >> 16] |= *rowSrc++;
613 break;
614 case STRETCH_ANDSCANS:
615 for(; widthSrc > 0; widthSrc--, xdst += xinc)
616 rowDst[xdst >> 16] &= *rowSrc++;
617 break;
618 case STRETCH_DELETESCANS:
619 for(; widthSrc > 0; widthSrc--, xdst += xinc)
620 rowDst[xdst >> 16] = *rowSrc++;
621 break;
626 /***********************************************************************
627 * BITBLT_GetRow
629 * Retrieve a row from an image. Helper function for BITBLT_StretchImage.
631 static void BITBLT_GetRow( XImage *image, int *pdata, INT row,
632 INT start, INT width, INT depthDst,
633 int fg, int bg, BOOL swap)
635 register INT i;
637 assert( (row >= 0) && (row < image->height) );
638 assert( (start >= 0) && (width <= image->width) );
640 pdata += swap ? start+width-1 : start;
641 if (image->depth == depthDst) /* color -> color */
643 if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1))
644 if (swap) for (i = 0; i < width; i++)
645 *pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
646 else for (i = 0; i < width; i++)
647 *pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
648 else
649 if (swap) for (i = 0; i < width; i++)
650 *pdata-- = XGetPixel( image, i, row );
651 else for (i = 0; i < width; i++)
652 *pdata++ = XGetPixel( image, i, row );
654 else
656 if (image->depth == 1) /* monochrome -> color */
658 if (X11DRV_PALETTE_XPixelToPalette)
660 fg = X11DRV_PALETTE_XPixelToPalette[fg];
661 bg = X11DRV_PALETTE_XPixelToPalette[bg];
663 if (swap) for (i = 0; i < width; i++)
664 *pdata-- = XGetPixel( image, i, row ) ? bg : fg;
665 else for (i = 0; i < width; i++)
666 *pdata++ = XGetPixel( image, i, row ) ? bg : fg;
668 else /* color -> monochrome */
670 if (swap) for (i = 0; i < width; i++)
671 *pdata-- = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
672 else for (i = 0; i < width; i++)
673 *pdata++ = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
679 /***********************************************************************
680 * BITBLT_StretchImage
682 * Stretch an X image.
683 * FIXME: does not work for full 32-bit coordinates.
685 static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage,
686 INT widthSrc, INT heightSrc,
687 INT widthDst, INT heightDst,
688 RECT *visRectSrc, RECT *visRectDst,
689 int foreground, int background, WORD mode )
691 int *rowSrc, *rowDst, *pixel;
692 char *pdata;
693 INT xinc, xoff, yinc, ysrc, ydst;
694 register INT x, y;
695 BOOL hstretch, vstretch, hswap, vswap;
697 hswap = ((int)widthSrc * widthDst) < 0;
698 vswap = ((int)heightSrc * heightDst) < 0;
699 widthSrc = abs(widthSrc);
700 heightSrc = abs(heightSrc);
701 widthDst = abs(widthDst);
702 heightDst = abs(heightDst);
704 if (!(rowSrc = (int *)HeapAlloc( GetProcessHeap(), 0,
705 (widthSrc+widthDst)*sizeof(int) ))) return;
706 rowDst = rowSrc + widthSrc;
708 /* When stretching, all modes are the same, and DELETESCANS is faster */
709 if ((widthSrc < widthDst) && (heightSrc < heightDst))
710 mode = STRETCH_DELETESCANS;
712 if (mode == STRETCH_HALFTONE) /* FIXME */
713 mode = STRETCH_DELETESCANS;
715 if (mode != STRETCH_DELETESCANS)
716 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
717 widthDst*sizeof(int) );
719 hstretch = (widthSrc < widthDst);
720 vstretch = (heightSrc < heightDst);
722 if (hstretch)
724 xinc = ((int)widthSrc << 16) / widthDst;
725 xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
727 else
729 xinc = ((int)widthDst << 16) / widthSrc;
730 xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
733 if (vstretch)
735 yinc = ((int)heightSrc << 16) / heightDst;
736 ydst = visRectDst->top;
737 if (vswap)
739 ysrc = yinc * (heightDst - ydst - 1);
740 yinc = -yinc;
742 else
743 ysrc = yinc * ydst;
745 for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
747 if (((ysrc >> 16) < visRectSrc->top) ||
748 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
750 /* Retrieve a source row */
751 BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
752 hswap ? widthSrc - visRectSrc->right
753 : visRectSrc->left,
754 visRectSrc->right - visRectSrc->left,
755 dstImage->depth, foreground, background, hswap );
757 /* Stretch or shrink it */
758 if (hstretch)
759 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
760 visRectDst->right - visRectDst->left,
761 xinc, xoff, mode );
762 else BITBLT_ShrinkRow( rowSrc, rowDst,
763 hswap ? widthSrc - visRectSrc->right
764 : visRectSrc->left,
765 visRectSrc->right - visRectSrc->left,
766 xinc, xoff, mode );
768 /* Store the destination row */
769 pixel = rowDst + visRectDst->right - 1;
770 y = ydst - visRectDst->top;
771 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
772 XPutPixel( dstImage, x, y, *pixel-- );
773 if (mode != STRETCH_DELETESCANS)
774 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
775 widthDst*sizeof(int) );
777 /* Make copies of the destination row */
779 pdata = dstImage->data + dstImage->bytes_per_line * y;
780 while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
781 (ydst < visRectDst->bottom-1))
783 memcpy( pdata + dstImage->bytes_per_line, pdata,
784 dstImage->bytes_per_line );
785 pdata += dstImage->bytes_per_line;
786 ysrc += yinc;
787 ydst++;
791 else /* Shrinking */
793 yinc = ((int)heightDst << 16) / heightSrc;
794 ysrc = visRectSrc->top;
795 ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
796 if (vswap)
798 ydst += yinc * (heightSrc - ysrc - 1);
799 yinc = -yinc;
801 else
802 ydst += yinc * ysrc;
804 for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
806 if (((ydst >> 16) < visRectDst->top) ||
807 ((ydst >> 16) >= visRectDst->bottom)) continue;
809 /* Retrieve a source row */
810 BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
811 hswap ? widthSrc - visRectSrc->right
812 : visRectSrc->left,
813 visRectSrc->right - visRectSrc->left,
814 dstImage->depth, foreground, background, hswap );
816 /* Stretch or shrink it */
817 if (hstretch)
818 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
819 visRectDst->right - visRectDst->left,
820 xinc, xoff, mode );
821 else BITBLT_ShrinkRow( rowSrc, rowDst,
822 hswap ? widthSrc - visRectSrc->right
823 : visRectSrc->left,
824 visRectSrc->right - visRectSrc->left,
825 xinc, xoff, mode );
827 /* Merge several source rows into the destination */
828 if (mode == STRETCH_DELETESCANS)
830 /* Simply skip the overlapping rows */
831 while (((ydst + yinc) >> 16 == ydst >> 16) &&
832 (ysrc < visRectSrc->bottom-1))
834 ydst += yinc;
835 ysrc++;
838 else if (((ydst + yinc) >> 16 == ydst >> 16) &&
839 (ysrc < visRectSrc->bottom-1))
840 continue; /* Restart loop for next overlapping row */
842 /* Store the destination row */
843 pixel = rowDst + visRectDst->right - 1;
844 y = (ydst >> 16) - visRectDst->top;
845 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
846 XPutPixel( dstImage, x, y, *pixel-- );
847 if (mode != STRETCH_DELETESCANS)
848 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
849 widthDst*sizeof(int) );
852 HeapFree( GetProcessHeap(), 0, rowSrc );
856 /***********************************************************************
857 * BITBLT_GetSrcAreaStretch
859 * Retrieve an area from the source DC, stretching and mapping all the
860 * pixels to Windows colors.
862 static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
863 Pixmap pixmap, GC gc,
864 INT xSrc, INT ySrc,
865 INT widthSrc, INT heightSrc,
866 INT xDst, INT yDst,
867 INT widthDst, INT heightDst,
868 RECT *visRectSrc, RECT *visRectDst )
870 XImage *imageSrc, *imageDst;
871 DC *dcDst = physDevDst->dc;
873 RECT rectSrc = *visRectSrc;
874 RECT rectDst = *visRectDst;
876 if (widthSrc < 0) xSrc += widthSrc;
877 if (widthDst < 0) xDst += widthDst;
878 if (heightSrc < 0) ySrc += heightSrc;
879 if (heightDst < 0) yDst += heightDst;
880 rectSrc.left -= xSrc;
881 rectSrc.right -= xSrc;
882 rectSrc.top -= ySrc;
883 rectSrc.bottom -= ySrc;
884 rectDst.left -= xDst;
885 rectDst.right -= xDst;
886 rectDst.top -= yDst;
887 rectDst.bottom -= yDst;
889 /* FIXME: avoid BadMatch errors */
890 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
891 physDevSrc->org.x + visRectSrc->left,
892 physDevSrc->org.y + visRectSrc->top,
893 visRectSrc->right - visRectSrc->left,
894 visRectSrc->bottom - visRectSrc->top,
895 AllPlanes, ZPixmap );
896 imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
897 rectDst.bottom - rectDst.top, dcDst->bitsPerPixel );
898 BITBLT_StretchImage( imageSrc, imageDst, widthSrc, heightSrc,
899 widthDst, heightDst, &rectSrc, &rectDst,
900 physDevDst->textPixel, dcDst->bitsPerPixel != 1 ?
901 physDevDst->backgroundPixel :
902 physDevSrc->backgroundPixel,
903 dcDst->stretchBltMode );
904 XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
905 rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
906 XDestroyImage( imageSrc );
907 XDestroyImage( imageDst );
908 return 0; /* no exposure events generated */
912 /***********************************************************************
913 * BITBLT_GetSrcArea
915 * Retrieve an area from the source DC, mapping all the
916 * pixels to Windows colors.
918 static int BITBLT_GetSrcArea( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
919 Pixmap pixmap, GC gc, INT xSrc, INT ySrc, RECT *visRectSrc )
921 XImage *imageSrc, *imageDst;
922 register INT x, y;
923 int exposures = 0;
924 INT width = visRectSrc->right - visRectSrc->left;
925 INT height = visRectSrc->bottom - visRectSrc->top;
926 DC *dcSrc = physDevSrc->dc;
927 DC *dcDst = physDevDst->dc;
929 if (dcSrc->bitsPerPixel == dcDst->bitsPerPixel)
931 if (!X11DRV_PALETTE_XPixelToPalette ||
932 (dcDst->bitsPerPixel == 1)) /* monochrome -> monochrome */
934 if (dcDst->bitsPerPixel == 1)
936 /* MSDN says if StretchBlt must convert a bitmap from monochrome
937 to color or vice versa, the forground and background color of
938 the device context are used. In fact, it also applies to the
939 case when it is converted from mono to mono. */
940 XSetBackground( gdi_display, gc, physDevDst->textPixel );
941 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
942 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
943 physDevSrc->org.x + visRectSrc->left,
944 physDevSrc->org.y + visRectSrc->top,
945 width, height, 0, 0, 1);
947 else
948 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
949 physDevSrc->org.x + visRectSrc->left,
950 physDevSrc->org.y + visRectSrc->top,
951 width, height, 0, 0);
952 exposures++;
954 else /* color -> color */
956 if (dcSrc->flags & DC_MEMORY)
957 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
958 physDevSrc->org.x + visRectSrc->left,
959 physDevSrc->org.y + visRectSrc->top,
960 width, height, AllPlanes, ZPixmap );
961 else
963 /* Make sure we don't get a BadMatch error */
964 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
965 physDevSrc->org.x + visRectSrc->left,
966 physDevSrc->org.y + visRectSrc->top,
967 width, height, 0, 0);
968 exposures++;
969 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
970 AllPlanes, ZPixmap );
972 for (y = 0; y < height; y++)
973 for (x = 0; x < width; x++)
974 XPutPixel(imageSrc, x, y,
975 X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
976 XPutImage( gdi_display, pixmap, gc, imageSrc,
977 0, 0, 0, 0, width, height );
978 XDestroyImage( imageSrc );
981 else
983 if (dcSrc->bitsPerPixel == 1) /* monochrome -> color */
985 if (X11DRV_PALETTE_XPixelToPalette)
987 XSetBackground( gdi_display, gc,
988 X11DRV_PALETTE_XPixelToPalette[physDevDst->textPixel] );
989 XSetForeground( gdi_display, gc,
990 X11DRV_PALETTE_XPixelToPalette[physDevDst->backgroundPixel]);
992 else
994 XSetBackground( gdi_display, gc, physDevDst->textPixel );
995 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
997 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
998 physDevSrc->org.x + visRectSrc->left,
999 physDevSrc->org.y + visRectSrc->top,
1000 width, height, 0, 0, 1 );
1001 exposures++;
1003 else /* color -> monochrome */
1005 /* FIXME: avoid BadMatch error */
1006 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
1007 physDevSrc->org.x + visRectSrc->left,
1008 physDevSrc->org.y + visRectSrc->top,
1009 width, height, AllPlanes, ZPixmap );
1010 imageDst = X11DRV_DIB_CreateXImage( width, height, dcDst->bitsPerPixel );
1011 for (y = 0; y < height; y++)
1012 for (x = 0; x < width; x++)
1013 XPutPixel(imageDst, x, y, (XGetPixel(imageSrc,x,y) ==
1014 physDevSrc->backgroundPixel) );
1015 XPutImage( gdi_display, pixmap, gc, imageDst,
1016 0, 0, 0, 0, width, height );
1017 XDestroyImage( imageSrc );
1018 XDestroyImage( imageDst );
1021 return exposures;
1025 /***********************************************************************
1026 * BITBLT_GetDstArea
1028 * Retrieve an area from the destination DC, mapping all the
1029 * pixels to Windows colors.
1031 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, RECT *visRectDst)
1033 int exposures = 0;
1034 INT width = visRectDst->right - visRectDst->left;
1035 INT height = visRectDst->bottom - visRectDst->top;
1037 if (!X11DRV_PALETTE_XPixelToPalette || (physDev->dc->bitsPerPixel == 1) ||
1038 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1040 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1041 physDev->org.x + visRectDst->left, physDev->org.y + visRectDst->top,
1042 width, height, 0, 0 );
1043 exposures++;
1045 else
1047 register INT x, y;
1048 XImage *image;
1050 if (physDev->dc->flags & DC_MEMORY)
1051 image = XGetImage( gdi_display, physDev->drawable,
1052 physDev->org.x + visRectDst->left,
1053 physDev->org.y + visRectDst->top,
1054 width, height, AllPlanes, ZPixmap );
1055 else
1057 /* Make sure we don't get a BadMatch error */
1058 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1059 physDev->org.x + visRectDst->left,
1060 physDev->org.y + visRectDst->top,
1061 width, height, 0, 0);
1062 exposures++;
1063 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1064 AllPlanes, ZPixmap );
1066 for (y = 0; y < height; y++)
1067 for (x = 0; x < width; x++)
1068 XPutPixel( image, x, y,
1069 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1070 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1071 XDestroyImage( image );
1073 return exposures;
1077 /***********************************************************************
1078 * BITBLT_PutDstArea
1080 * Put an area back into the destination DC, mapping the pixel
1081 * colors to X pixels.
1083 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, RECT *visRectDst)
1085 int exposures = 0;
1086 INT width = visRectDst->right - visRectDst->left;
1087 INT height = visRectDst->bottom - visRectDst->top;
1089 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1091 if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->dc->bitsPerPixel == 1) ||
1092 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1094 XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1095 physDev->org.x + visRectDst->left,
1096 physDev->org.y + visRectDst->top );
1097 exposures++;
1099 else
1101 register INT x, y;
1102 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1103 AllPlanes, ZPixmap );
1104 for (y = 0; y < height; y++)
1105 for (x = 0; x < width; x++)
1107 XPutPixel( image, x, y,
1108 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1110 XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1111 physDev->org.x + visRectDst->left,
1112 physDev->org.y + visRectDst->top, width, height );
1113 XDestroyImage( image );
1115 return exposures;
1119 /***********************************************************************
1120 * BITBLT_GetVisRectangles
1122 * Get the source and destination visible rectangles for StretchBlt().
1123 * Return FALSE if one of the rectangles is empty.
1125 static BOOL BITBLT_GetVisRectangles( DC *dcDst, INT xDst, INT yDst,
1126 INT widthDst, INT heightDst,
1127 DC *dcSrc, INT xSrc, INT ySrc,
1128 INT widthSrc, INT heightSrc,
1129 RECT *visRectSrc, RECT *visRectDst )
1131 RECT rect, clipRect;
1133 /* Get the destination visible rectangle */
1135 rect.left = xDst;
1136 rect.top = yDst;
1137 rect.right = xDst + widthDst;
1138 rect.bottom = yDst + heightDst;
1139 if (widthDst < 0) SWAP_INT32( &rect.left, &rect.right );
1140 if (heightDst < 0) SWAP_INT32( &rect.top, &rect.bottom );
1141 GetRgnBox( dcDst->hGCClipRgn, &clipRect );
1142 if (!IntersectRect( visRectDst, &rect, &clipRect )) return FALSE;
1144 /* Get the source visible rectangle */
1146 if (!dcSrc) return TRUE;
1147 rect.left = xSrc;
1148 rect.top = ySrc;
1149 rect.right = xSrc + widthSrc;
1150 rect.bottom = ySrc + heightSrc;
1151 if (widthSrc < 0) SWAP_INT32( &rect.left, &rect.right );
1152 if (heightSrc < 0) SWAP_INT32( &rect.top, &rect.bottom );
1153 /* Apparently the clipping and visible regions are only for output,
1154 so just check against totalExtent here to avoid BadMatch errors */
1155 if (!IntersectRect( visRectSrc, &rect, &dcSrc->totalExtent ))
1156 return FALSE;
1158 /* Intersect the rectangles */
1160 if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1162 visRectSrc->left += xDst - xSrc;
1163 visRectSrc->right += xDst - xSrc;
1164 visRectSrc->top += yDst - ySrc;
1165 visRectSrc->bottom += yDst - ySrc;
1166 if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1167 *visRectSrc = *visRectDst = rect;
1168 visRectSrc->left += xSrc - xDst;
1169 visRectSrc->right += xSrc - xDst;
1170 visRectSrc->top += ySrc - yDst;
1171 visRectSrc->bottom += ySrc - yDst;
1173 else /* stretching */
1175 /* Map source rectangle into destination coordinates */
1176 rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1177 rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1178 rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1179 rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1180 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1181 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1183 /* Avoid rounding errors */
1184 rect.left--;
1185 rect.top--;
1186 rect.right++;
1187 rect.bottom++;
1188 if (!IntersectRect( visRectDst, &rect, visRectDst )) return FALSE;
1190 /* Map destination rectangle back to source coordinates */
1191 rect = *visRectDst;
1192 rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1193 rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1194 rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1195 rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1196 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1197 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1199 /* Avoid rounding errors */
1200 rect.left--;
1201 rect.top--;
1202 rect.right++;
1203 rect.bottom++;
1204 if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1206 return TRUE;
1210 /***********************************************************************
1211 * BITBLT_InternalStretchBlt
1213 * Implementation of PatBlt(), BitBlt() and StretchBlt().
1215 static BOOL BITBLT_InternalStretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1216 INT widthDst, INT heightDst,
1217 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1218 INT widthSrc, INT heightSrc,
1219 DWORD rop )
1221 BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1222 RECT visRectDst, visRectSrc;
1223 INT width, height;
1224 const BYTE *opcode;
1225 Pixmap pixmaps[3] = { 0, 0, 0 }; /* pixmaps for DST, SRC, TMP */
1226 GC tmpGC = 0;
1227 POINT pts[2];
1228 DC *dcSrc = physDevSrc ? physDevSrc->dc : NULL;
1229 DC *dcDst = physDevDst->dc;
1231 /* compensate for off-by-one shifting for negative widths and heights */
1232 if (widthDst < 0)
1233 ++xDst;
1234 if (heightDst < 0)
1235 ++yDst;
1236 if (widthSrc < 0)
1237 ++xSrc;
1238 if (heightSrc < 0)
1239 ++ySrc;
1241 usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1242 useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1243 useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1244 if (!dcSrc && useSrc) return FALSE;
1246 /* Map the coordinates to device coords */
1248 pts[0].x = xDst;
1249 pts[0].y = yDst;
1250 pts[1].x = xDst + widthDst;
1251 pts[1].y = yDst + heightDst;
1252 LPtoDP(physDevDst->hdc, pts, 2);
1253 xDst = pts[0].x;
1254 yDst = pts[0].y;
1255 widthDst = pts[1].x - pts[0].x;
1256 heightDst = pts[1].y - pts[0].y;
1258 TRACE(" vportdst=%d,%d-%d,%d wnddst=%d,%d-%d,%d\n",
1259 dcDst->vportOrgX, dcDst->vportOrgY,
1260 dcDst->vportExtX, dcDst->vportExtY,
1261 dcDst->wndOrgX, dcDst->wndOrgY,
1262 dcDst->wndExtX, dcDst->wndExtY );
1263 TRACE(" rectdst=%d,%d-%d,%d orgdst=%ld,%ld\n",
1264 xDst, yDst, widthDst, heightDst,
1265 physDevDst->org.x, physDevDst->org.y );
1267 if (useSrc)
1269 pts[0].x = xSrc;
1270 pts[0].y = ySrc;
1271 pts[1].x = xSrc + widthSrc;
1272 pts[1].y = ySrc + heightSrc;
1273 LPtoDP(physDevSrc->hdc, pts, 2);
1274 xSrc = pts[0].x;
1275 ySrc = pts[0].y;
1276 widthSrc = pts[1].x - pts[0].x;
1277 heightSrc = pts[1].y - pts[0].y;
1279 fStretch = (widthSrc != widthDst) || (heightSrc != heightDst);
1280 TRACE(" vportsrc=%d,%d-%d,%d wndsrc=%d,%d-%d,%d\n",
1281 dcSrc->vportOrgX, dcSrc->vportOrgY,
1282 dcSrc->vportExtX, dcSrc->vportExtY,
1283 dcSrc->wndOrgX, dcSrc->wndOrgY,
1284 dcSrc->wndExtX, dcSrc->wndExtY );
1285 TRACE(" rectsrc=%d,%d-%d,%d orgsrc=%ld,%ld\n",
1286 xSrc, ySrc, widthSrc, heightSrc,
1287 physDevSrc->org.x, physDevSrc->org.y );
1288 if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1289 dcSrc, xSrc, ySrc, widthSrc, heightSrc,
1290 &visRectSrc, &visRectDst ))
1291 return TRUE;
1292 TRACE(" vissrc=%ld,%ld-%ld,%ld visdst=%ld,%ld-%ld,%ld\n",
1293 visRectSrc.left, visRectSrc.top,
1294 visRectSrc.right, visRectSrc.bottom,
1295 visRectDst.left, visRectDst.top,
1296 visRectDst.right, visRectDst.bottom );
1298 else
1300 fStretch = FALSE;
1301 if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1302 NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1303 return TRUE;
1304 TRACE(" vissrc=none visdst=%ld,%ld-%ld,%ld\n",
1305 visRectDst.left, visRectDst.top,
1306 visRectDst.right, visRectDst.bottom );
1309 width = visRectDst.right - visRectDst.left;
1310 height = visRectDst.bottom - visRectDst.top;
1312 if (!fStretch) switch(rop) /* A few optimisations */
1314 case BLACKNESS: /* 0x00 */
1315 wine_tsx11_lock();
1316 if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1317 XSetFunction( gdi_display, physDevDst->gc, GXclear );
1318 else
1320 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1321 XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1322 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1324 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1325 physDevDst->org.x + visRectDst.left,
1326 physDevDst->org.y + visRectDst.top,
1327 width, height );
1328 wine_tsx11_unlock();
1329 return TRUE;
1331 case DSTINVERT: /* 0x55 */
1332 if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel ||
1333 !perfect_graphics())
1335 wine_tsx11_lock();
1336 XSetFunction( gdi_display, physDevDst->gc, GXinvert );
1338 if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1339 XSetFunction( gdi_display, physDevDst->gc, GXinvert);
1340 else
1342 /* Xor is much better when we do not have full colormap. */
1343 /* Using white^black ensures that we invert at least black */
1344 /* and white. */
1345 Pixel xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1346 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1347 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1348 XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1349 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
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();
1356 return TRUE;
1358 break;
1360 case PATINVERT: /* 0x5a */
1361 if (perfect_graphics()) break;
1362 if (X11DRV_SetupGCForBrush( physDevDst ))
1364 wine_tsx11_lock();
1365 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1366 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1367 physDevDst->org.x + visRectDst.left,
1368 physDevDst->org.y + visRectDst.top,
1369 width, height );
1370 wine_tsx11_unlock();
1372 return TRUE;
1374 case 0xa50065:
1375 if (perfect_graphics()) break;
1376 if (X11DRV_SetupGCForBrush( physDevDst ))
1378 wine_tsx11_lock();
1379 XSetFunction( gdi_display, physDevDst->gc, GXequiv );
1380 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1381 physDevDst->org.x + visRectDst.left,
1382 physDevDst->org.y + visRectDst.top,
1383 width, height );
1384 wine_tsx11_unlock();
1386 return TRUE;
1388 case SRCCOPY: /* 0xcc */
1389 if (dcSrc->bitsPerPixel == dcDst->bitsPerPixel)
1391 wine_tsx11_lock();
1392 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1393 XCopyArea( gdi_display, physDevSrc->drawable,
1394 physDevDst->drawable, physDevDst->gc,
1395 physDevSrc->org.x + visRectSrc.left,
1396 physDevSrc->org.y + visRectSrc.top,
1397 width, height,
1398 physDevDst->org.x + visRectDst.left,
1399 physDevDst->org.y + visRectDst.top );
1400 physDevDst->exposures++;
1401 wine_tsx11_unlock();
1402 return TRUE;
1404 if (dcSrc->bitsPerPixel == 1)
1406 wine_tsx11_lock();
1407 XSetBackground( gdi_display, physDevDst->gc, physDevDst->textPixel );
1408 XSetForeground( gdi_display, physDevDst->gc, physDevDst->backgroundPixel );
1409 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1410 XCopyPlane( gdi_display, physDevSrc->drawable,
1411 physDevDst->drawable, physDevDst->gc,
1412 physDevSrc->org.x + visRectSrc.left,
1413 physDevSrc->org.y + visRectSrc.top,
1414 width, height,
1415 physDevDst->org.x + visRectDst.left,
1416 physDevDst->org.y + visRectDst.top, 1 );
1417 physDevDst->exposures++;
1418 wine_tsx11_unlock();
1419 return TRUE;
1421 break;
1423 case PATCOPY: /* 0xf0 */
1424 if (!X11DRV_SetupGCForBrush( physDevDst )) return TRUE;
1425 wine_tsx11_lock();
1426 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1427 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1428 physDevDst->org.x + visRectDst.left,
1429 physDevDst->org.y + visRectDst.top,
1430 width, height );
1431 wine_tsx11_unlock();
1432 return TRUE;
1434 case WHITENESS: /* 0xff */
1435 wine_tsx11_lock();
1436 if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1437 XSetFunction( gdi_display, physDevDst->gc, GXset );
1438 else
1440 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1441 XSetForeground( gdi_display, physDevDst->gc,
1442 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1443 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1445 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1446 physDevDst->org.x + visRectDst.left,
1447 physDevDst->org.y + visRectDst.top,
1448 width, height );
1449 wine_tsx11_unlock();
1450 return TRUE;
1453 wine_tsx11_lock();
1455 tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1456 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1457 XSetGraphicsExposures( gdi_display, tmpGC, False );
1458 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1459 dcDst->bitsPerPixel );
1460 if (useSrc)
1462 pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1463 dcDst->bitsPerPixel );
1464 if (fStretch)
1465 BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1466 xSrc, ySrc, widthSrc, heightSrc,
1467 xDst, yDst, widthDst, heightDst,
1468 &visRectSrc, &visRectDst );
1469 else
1470 BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1471 xSrc, ySrc, &visRectSrc );
1474 if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &visRectDst );
1475 if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1476 else fNullBrush = FALSE;
1477 destUsed = FALSE;
1479 for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1481 if (OP_DST(*opcode) == DST) destUsed = TRUE;
1482 XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1483 switch(OP_SRCDST(*opcode))
1485 case OP_ARGS(DST,TMP):
1486 case OP_ARGS(SRC,TMP):
1487 if (!pixmaps[TMP])
1488 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1489 width, height,
1490 dcDst->bitsPerPixel );
1491 /* fall through */
1492 case OP_ARGS(DST,SRC):
1493 case OP_ARGS(SRC,DST):
1494 case OP_ARGS(TMP,SRC):
1495 case OP_ARGS(TMP,DST):
1496 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1497 pixmaps[OP_DST(*opcode)], tmpGC,
1498 0, 0, width, height, 0, 0 );
1499 break;
1501 case OP_ARGS(PAT,TMP):
1502 if (!pixmaps[TMP] && !fNullBrush)
1503 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1504 width, height,
1505 dcDst->bitsPerPixel );
1506 /* fall through */
1507 case OP_ARGS(PAT,DST):
1508 case OP_ARGS(PAT,SRC):
1509 if (!fNullBrush)
1510 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1511 tmpGC, 0, 0, width, height );
1512 break;
1515 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1516 physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC],
1517 &visRectDst );
1518 XFreePixmap( gdi_display, pixmaps[DST] );
1519 if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1520 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1521 XFreeGC( gdi_display, tmpGC );
1522 wine_tsx11_unlock();
1523 return TRUE;
1527 /***********************************************************************
1528 * X11DRV_PatBlt
1530 BOOL X11DRV_PatBlt( X11DRV_PDEVICE *physDev, INT left, INT top, INT width, INT height, DWORD rop )
1532 BOOL result;
1534 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1535 result = BITBLT_InternalStretchBlt( physDev, left, top, width, height, NULL, 0, 0, 0, 0, rop );
1536 X11DRV_UnlockDIBSection( physDev, TRUE );
1537 return result;
1541 /***********************************************************************
1542 * X11DRV_BitBlt
1544 BOOL X11DRV_BitBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1545 INT width, INT height, X11DRV_PDEVICE *physDevSrc,
1546 INT xSrc, INT ySrc, DWORD rop )
1548 BOOL result = FALSE;
1549 INT sSrc, sDst;
1550 RECT visRectDst, visRectSrc;
1551 DC *dcSrc = physDevSrc ? physDevSrc->dc : NULL;
1552 DC *dcDst = physDevDst->dc;
1554 if (((rop >> 16) & 0x55) == ((rop >> 17) & 0x55)) {
1555 /* FIXME: seems the ROP doesn't include destination;
1556 * now if the destination area include the entire dcDst,
1557 * we can pass TRUE instead of FALSE to CoerceDIBSection(dcDst...),
1558 * which may avoid a copy in some situations */
1560 sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None, FALSE );
1561 sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None, FALSE );
1563 if ((sSrc == DIB_Status_AppMod) && (rop == SRCCOPY) &&
1564 (dcSrc->bitsPerPixel == dcDst->bitsPerPixel))
1566 POINT pts[2];
1567 /* do everything ourselves; map coordinates */
1569 pts[0].x = xSrc;
1570 pts[0].y = ySrc;
1571 pts[1].x = xSrc + width;
1572 pts[1].y = ySrc + height;
1574 LPtoDP(physDevSrc->hdc, pts, 2);
1575 width = pts[1].x - pts[0].x;
1576 height = pts[1].y - pts[0].y;
1577 xSrc = pts[0].x;
1578 ySrc = pts[0].y;
1580 pts[0].x = xDst;
1581 pts[0].y = yDst;
1582 LPtoDP(physDevDst->hdc, pts, 1);
1584 xDst = pts[0].x;
1585 yDst = pts[0].y;
1587 /* Perform basic clipping */
1588 if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, width, height,
1589 dcSrc, xSrc, ySrc, width, height,
1590 &visRectSrc, &visRectDst ))
1591 goto END;
1593 xSrc = visRectSrc.left;
1594 ySrc = visRectSrc.top;
1595 xDst = visRectDst.left;
1596 yDst = visRectDst.top;
1597 width = visRectDst.right - visRectDst.left;
1598 height = visRectDst.bottom - visRectDst.top;
1600 if (sDst == DIB_Status_AppMod) {
1601 FIXME("potential optimization - client-side DIB copy\n");
1603 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1605 X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, xSrc, ySrc, xDst, yDst, width, height );
1606 result = TRUE;
1607 goto END;
1610 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1611 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1613 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, width, height,
1614 physDevSrc, xSrc, ySrc, width, height, rop );
1616 END:
1617 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1618 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1620 return result;
1624 /***********************************************************************
1625 * X11DRV_StretchBlt
1627 BOOL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1628 INT widthDst, INT heightDst,
1629 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1630 INT widthSrc, INT heightSrc, DWORD rop )
1632 BOOL result;
1634 X11DRV_LockDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1635 X11DRV_LockDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1637 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, widthDst, heightDst,
1638 physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop );
1640 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1641 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1642 return result;