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
27 #include <X11/Intrinsic.h>
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(bitblt
);
40 #define DST 0 /* Destination drawable */
41 #define SRC 1 /* Source drawable */
42 #define TMP 2 /* Temporary drawable */
43 #define PAT 3 /* Pattern (brush) in destination DC */
45 #define OP(src,dst,rop) (OP_ARGS(src,dst) << 4 | (rop))
46 #define OP_ARGS(src,dst) (((src) << 2) | (dst))
48 #define OP_SRC(opcode) ((opcode) >> 6)
49 #define OP_DST(opcode) (((opcode) >> 4) & 3)
50 #define OP_SRCDST(opcode) ((opcode) >> 4)
51 #define OP_ROP(opcode) ((opcode) & 0x0f)
53 #define MAX_OP_LEN 6 /* Longest opcode + 1 for the terminating 0 */
55 #define SWAP_INT32(i1,i2) \
56 do { INT __t = *(i1); *(i1) = *(i2); *(i2) = __t; } while(0)
58 static const unsigned char BITBLT_Opcodes
[256][MAX_OP_LEN
] =
60 { OP(PAT
,DST
,GXclear
) }, /* 0x00 0 */
61 { OP(PAT
,SRC
,GXor
), OP(SRC
,DST
,GXnor
) }, /* 0x01 ~(D|(P|S)) */
62 { OP(PAT
,SRC
,GXnor
), OP(SRC
,DST
,GXand
) }, /* 0x02 D&~(P|S) */
63 { OP(PAT
,SRC
,GXnor
) }, /* 0x03 ~(P|S) */
64 { OP(PAT
,DST
,GXnor
), OP(SRC
,DST
,GXand
) }, /* 0x04 S&~(D|P) */
65 { OP(PAT
,DST
,GXnor
) }, /* 0x05 ~(D|P) */
66 { OP(SRC
,DST
,GXequiv
), OP(PAT
,DST
,GXnor
), }, /* 0x06 ~(P|~(D^S)) */
67 { OP(SRC
,DST
,GXand
), OP(PAT
,DST
,GXnor
) }, /* 0x07 ~(P|(D&S)) */
68 { OP(PAT
,DST
,GXandInverted
), OP(SRC
,DST
,GXand
) },/* 0x08 S&D&~P */
69 { OP(SRC
,DST
,GXxor
), OP(PAT
,DST
,GXnor
) }, /* 0x09 ~(P|(D^S)) */
70 { OP(PAT
,DST
,GXandInverted
) }, /* 0x0a D&~P */
71 { OP(SRC
,DST
,GXandReverse
), OP(PAT
,DST
,GXnor
) }, /* 0x0b ~(P|(S&~D)) */
72 { OP(PAT
,SRC
,GXandInverted
) }, /* 0x0c S&~P */
73 { OP(SRC
,DST
,GXandInverted
), OP(PAT
,DST
,GXnor
) },/* 0x0d ~(P|(D&~S)) */
74 { OP(SRC
,DST
,GXnor
), OP(PAT
,DST
,GXnor
) }, /* 0x0e ~(P|~(D|S)) */
75 { OP(PAT
,DST
,GXcopyInverted
) }, /* 0x0f ~P */
76 { OP(SRC
,DST
,GXnor
), OP(PAT
,DST
,GXand
) }, /* 0x10 P&~(S|D) */
77 { OP(SRC
,DST
,GXnor
) }, /* 0x11 ~(D|S) */
78 { OP(PAT
,DST
,GXequiv
), OP(SRC
,DST
,GXnor
) }, /* 0x12 ~(S|~(D^P)) */
79 { OP(PAT
,DST
,GXand
), OP(SRC
,DST
,GXnor
) }, /* 0x13 ~(S|(D&P)) */
80 { OP(PAT
,SRC
,GXequiv
), OP(SRC
,DST
,GXnor
) }, /* 0x14 ~(D|~(P^S)) */
81 { OP(PAT
,SRC
,GXand
), OP(SRC
,DST
,GXnor
) }, /* 0x15 ~(D|(P&S)) */
82 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,TMP
,GXnand
),
83 OP(TMP
,DST
,GXand
), OP(SRC
,DST
,GXxor
),
84 OP(PAT
,DST
,GXxor
) }, /* 0x16 P^S^(D&~(P&S) */
85 { OP(SRC
,TMP
,GXcopy
), OP(SRC
,DST
,GXxor
),
86 OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXand
),
87 OP(TMP
,DST
,GXequiv
) }, /* 0x17 ~S^((S^P)&(S^D))*/
88 { OP(PAT
,SRC
,GXxor
), OP(PAT
,DST
,GXxor
),
89 OP(SRC
,DST
,GXand
) }, /* 0x18 (S^P)&(D^P) */
90 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,TMP
,GXnand
),
91 OP(TMP
,DST
,GXand
), OP(SRC
,DST
,GXequiv
) }, /* 0x19 ~S^(D&~(P&S)) */
92 { OP(PAT
,SRC
,GXand
), OP(SRC
,DST
,GXor
),
93 OP(PAT
,DST
,GXxor
) }, /* 0x1a P^(D|(S&P)) */
94 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,TMP
,GXxor
),
95 OP(TMP
,DST
,GXand
), OP(SRC
,DST
,GXequiv
) }, /* 0x1b ~S^(D&(P^S)) */
96 { OP(PAT
,DST
,GXand
), OP(SRC
,DST
,GXor
),
97 OP(PAT
,DST
,GXxor
) }, /* 0x1c P^(S|(D&P)) */
98 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXxor
),
99 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXequiv
) }, /* 0x1d ~D^(S&(D^P)) */
100 { OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXxor
) }, /* 0x1e P^(D|S) */
101 { OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXnand
) }, /* 0x1f ~(P&(D|S)) */
102 { OP(PAT
,SRC
,GXandReverse
), OP(SRC
,DST
,GXand
) }, /* 0x20 D&(P&~S) */
103 { OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXnor
) }, /* 0x21 ~(S|(D^P)) */
104 { OP(SRC
,DST
,GXandInverted
) }, /* 0x22 ~S&D */
105 { OP(PAT
,DST
,GXandReverse
), OP(SRC
,DST
,GXnor
) }, /* 0x23 ~(S|(P&~D)) */
106 { OP(SRC
,DST
,GXxor
), OP(PAT
,SRC
,GXxor
),
107 OP(SRC
,DST
,GXand
) }, /* 0x24 (S^P)&(S^D) */
108 { OP(PAT
,SRC
,GXnand
), OP(SRC
,DST
,GXand
),
109 OP(PAT
,DST
,GXequiv
) }, /* 0x25 ~P^(D&~(S&P)) */
110 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,TMP
,GXand
),
111 OP(TMP
,DST
,GXor
), OP(SRC
,DST
,GXxor
) }, /* 0x26 S^(D|(S&P)) */
112 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,TMP
,GXequiv
),
113 OP(TMP
,DST
,GXor
), OP(SRC
,DST
,GXxor
) }, /* 0x27 S^(D|~(P^S)) */
114 { OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXand
) }, /* 0x28 D&(P^S) */
115 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,TMP
,GXand
),
116 OP(TMP
,DST
,GXor
), OP(SRC
,DST
,GXxor
),
117 OP(PAT
,DST
,GXequiv
) }, /* 0x29 ~P^S^(D|(P&S)) */
118 { OP(PAT
,SRC
,GXnand
), OP(SRC
,DST
,GXand
) }, /* 0x2a D&~(P&S) */
119 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXxor
),
120 OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXand
),
121 OP(TMP
,DST
,GXequiv
) }, /* 0x2b ~S^((P^S)&(P^D))*/
122 { OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXand
),
123 OP(SRC
,DST
,GXxor
) }, /* 0x2c S^(P&(S|D)) */
124 { OP(SRC
,DST
,GXorReverse
), OP(PAT
,DST
,GXxor
) }, /* 0x2d P^(S|~D) */
125 { OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXor
),
126 OP(PAT
,DST
,GXxor
) }, /* 0x2e P^(S|(D^P)) */
127 { OP(SRC
,DST
,GXorReverse
), OP(PAT
,DST
,GXnand
) }, /* 0x2f ~(P&(S|~D)) */
128 { OP(PAT
,SRC
,GXandReverse
) }, /* 0x30 P&~S */
129 { OP(PAT
,DST
,GXandInverted
), OP(SRC
,DST
,GXnor
) },/* 0x31 ~(S|(D&~P)) */
130 { OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXor
),
131 OP(SRC
,DST
,GXxor
) }, /* 0x32 S^(D|P|S) */
132 { OP(SRC
,DST
,GXcopyInverted
) }, /* 0x33 ~S */
133 { OP(SRC
,DST
,GXand
), OP(PAT
,DST
,GXor
),
134 OP(SRC
,DST
,GXxor
) }, /* 0x34 S^(P|(D&S)) */
135 { OP(SRC
,DST
,GXequiv
), OP(PAT
,DST
,GXor
),
136 OP(SRC
,DST
,GXxor
) }, /* 0x35 S^(P|~(D^S)) */
137 { OP(PAT
,DST
,GXor
), OP(SRC
,DST
,GXxor
) }, /* 0x36 S^(D|P) */
138 { OP(PAT
,DST
,GXor
), OP(SRC
,DST
,GXnand
) }, /* 0x37 ~(S&(D|P)) */
139 { OP(PAT
,DST
,GXor
), OP(SRC
,DST
,GXand
),
140 OP(PAT
,DST
,GXxor
) }, /* 0x38 P^(S&(D|P)) */
141 { OP(PAT
,DST
,GXorReverse
), OP(SRC
,DST
,GXxor
) }, /* 0x39 S^(P|~D) */
142 { OP(SRC
,DST
,GXxor
), OP(PAT
,DST
,GXor
),
143 OP(SRC
,DST
,GXxor
) }, /* 0x3a S^(P|(D^S)) */
144 { OP(PAT
,DST
,GXorReverse
), OP(SRC
,DST
,GXnand
) }, /* 0x3b ~(S&(P|~D)) */
145 { OP(PAT
,SRC
,GXxor
) }, /* 0x3c P^S */
146 { OP(SRC
,DST
,GXnor
), OP(PAT
,DST
,GXor
),
147 OP(SRC
,DST
,GXxor
) }, /* 0x3d S^(P|~(D|S)) */
148 { OP(SRC
,DST
,GXandInverted
), OP(PAT
,DST
,GXor
),
149 OP(SRC
,DST
,GXxor
) }, /* 0x3e S^(P|(D&~S)) */
150 { OP(PAT
,SRC
,GXnand
) }, /* 0x3f ~(P&S) */
151 { OP(SRC
,DST
,GXandReverse
), OP(PAT
,DST
,GXand
) }, /* 0x40 P&S&~D */
152 { OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXnor
) }, /* 0x41 ~(D|(P^S)) */
153 { OP(DST
,SRC
,GXxor
), OP(PAT
,DST
,GXxor
),
154 OP(SRC
,DST
,GXand
) }, /* 0x42 (S^D)&(P^D) */
155 { OP(SRC
,DST
,GXnand
), OP(PAT
,DST
,GXand
),
156 OP(SRC
,DST
,GXequiv
) }, /* 0x43 ~S^(P&~(D&S)) */
157 { OP(SRC
,DST
,GXandReverse
) }, /* 0x44 S&~D */
158 { OP(PAT
,SRC
,GXandReverse
), OP(SRC
,DST
,GXnor
) }, /* 0x45 ~(D|(P&~S)) */
159 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXand
),
160 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXxor
) }, /* 0x46 D^(S|(P&D)) */
161 { OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXand
),
162 OP(PAT
,DST
,GXequiv
) }, /* 0x47 ~P^(S&(D^P)) */
163 { OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXand
) }, /* 0x48 S&(P^D) */
164 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXand
),
165 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXxor
),
166 OP(PAT
,DST
,GXequiv
) }, /* 0x49 ~P^D^(S|(P&D)) */
167 { OP(DST
,SRC
,GXor
), OP(PAT
,SRC
,GXand
),
168 OP(SRC
,DST
,GXxor
) }, /* 0x4a D^(P&(S|D)) */
169 { OP(SRC
,DST
,GXorInverted
), OP(PAT
,DST
,GXxor
) }, /* 0x4b P^(D|~S) */
170 { OP(PAT
,DST
,GXnand
), OP(SRC
,DST
,GXand
) }, /* 0x4c S&~(D&P) */
171 { OP(SRC
,TMP
,GXcopy
), OP(SRC
,DST
,GXxor
),
172 OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXor
),
173 OP(TMP
,DST
,GXequiv
) }, /* 0x4d ~S^((S^P)|(S^D))*/
174 { OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXor
),
175 OP(PAT
,DST
,GXxor
) }, /* 0x4e P^(D|(S^P)) */
176 { OP(SRC
,DST
,GXorInverted
), OP(PAT
,DST
,GXnand
) },/* 0x4f ~(P&(D|~S)) */
177 { OP(PAT
,DST
,GXandReverse
) }, /* 0x50 P&~D */
178 { OP(PAT
,SRC
,GXandInverted
), OP(SRC
,DST
,GXnor
) },/* 0x51 ~(D|(S&~P)) */
179 { OP(DST
,SRC
,GXand
), OP(PAT
,SRC
,GXor
),
180 OP(SRC
,DST
,GXxor
) }, /* 0x52 D^(P|(S&D)) */
181 { OP(SRC
,DST
,GXxor
), OP(PAT
,DST
,GXand
),
182 OP(SRC
,DST
,GXequiv
) }, /* 0x53 ~S^(P&(D^S)) */
183 { OP(PAT
,SRC
,GXnor
), OP(SRC
,DST
,GXnor
) }, /* 0x54 ~(D|~(P|S)) */
184 { OP(PAT
,DST
,GXinvert
) }, /* 0x55 ~D */
185 { OP(PAT
,SRC
,GXor
), OP(SRC
,DST
,GXxor
) }, /* 0x56 D^(P|S) */
186 { OP(PAT
,SRC
,GXor
), OP(SRC
,DST
,GXnand
) }, /* 0x57 ~(D&(P|S)) */
187 { OP(PAT
,SRC
,GXor
), OP(SRC
,DST
,GXand
),
188 OP(PAT
,DST
,GXxor
) }, /* 0x58 P^(D&(P|S)) */
189 { OP(PAT
,SRC
,GXorReverse
), OP(SRC
,DST
,GXxor
) }, /* 0x59 D^(P|~S) */
190 { OP(PAT
,DST
,GXxor
) }, /* 0x5a D^P */
191 { OP(DST
,SRC
,GXnor
), OP(PAT
,SRC
,GXor
),
192 OP(SRC
,DST
,GXxor
) }, /* 0x5b D^(P|~(S|D)) */
193 { OP(DST
,SRC
,GXxor
), OP(PAT
,SRC
,GXor
),
194 OP(SRC
,DST
,GXxor
) }, /* 0x5c D^(P|(S^D)) */
195 { OP(PAT
,SRC
,GXorReverse
), OP(SRC
,DST
,GXnand
) }, /* 0x5d ~(D&(P|~S)) */
196 { OP(DST
,SRC
,GXandInverted
), OP(PAT
,SRC
,GXor
),
197 OP(SRC
,DST
,GXxor
) }, /* 0x5e D^(P|(S&~D)) */
198 { OP(PAT
,DST
,GXnand
) }, /* 0x5f ~(D&P) */
199 { OP(SRC
,DST
,GXxor
), OP(PAT
,DST
,GXand
) }, /* 0x60 P&(D^S) */
200 { OP(DST
,TMP
,GXcopy
), OP(SRC
,DST
,GXand
),
201 OP(PAT
,DST
,GXor
), OP(SRC
,DST
,GXxor
),
202 OP(TMP
,DST
,GXequiv
) }, /* 0x61 ~D^S^(P|(D&S)) */
203 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXor
),
204 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXxor
) }, /* 0x62 D^(S&(P|D)) */
205 { OP(PAT
,DST
,GXorInverted
), OP(SRC
,DST
,GXxor
) }, /* 0x63 S^(D|~P) */
206 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXor
),
207 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXxor
) }, /* 0x64 S^(D&(P|S)) */
208 { OP(PAT
,SRC
,GXorInverted
), OP(SRC
,DST
,GXxor
) }, /* 0x65 D^(S|~P) */
209 { OP(SRC
,DST
,GXxor
) }, /* 0x66 S^D */
210 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXnor
),
211 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXxor
) }, /* 0x67 S^(D|~(S|P) */
212 { OP(DST
,TMP
,GXcopy
), OP(SRC
,DST
,GXnor
),
213 OP(PAT
,DST
,GXor
), OP(SRC
,DST
,GXxor
),
214 OP(TMP
,DST
,GXequiv
) }, /* 0x68 ~D^S^(P|~(D|S))*/
215 { OP(SRC
,DST
,GXxor
), OP(PAT
,DST
,GXequiv
) }, /* 0x69 ~P^(D^S) */
216 { OP(PAT
,SRC
,GXand
), OP(SRC
,DST
,GXxor
) }, /* 0x6a D^(P&S) */
217 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXor
),
218 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXxor
),
219 OP(PAT
,DST
,GXequiv
) }, /* 0x6b ~P^S^(D&(P|S)) */
220 { OP(PAT
,DST
,GXand
), OP(SRC
,DST
,GXxor
) }, /* 0x6c S^(D&P) */
221 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXor
),
222 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXxor
),
223 OP(PAT
,DST
,GXequiv
) }, /* 0x6d ~P^D^(S&(P|D)) */
224 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXorReverse
),
225 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXxor
) }, /* 0x6e S^(D&(P|~S)) */
226 { OP(SRC
,DST
,GXequiv
), OP(PAT
,DST
,GXnand
) }, /* 0x6f ~(P&~(S^D)) */
227 { OP(SRC
,DST
,GXnand
), OP(PAT
,DST
,GXand
) }, /* 0x70 P&~(D&S) */
228 { OP(SRC
,TMP
,GXcopy
), OP(DST
,SRC
,GXxor
),
229 OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXand
),
230 OP(TMP
,DST
,GXequiv
) }, /* 0x71 ~S^((S^D)&(P^D))*/
231 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXxor
),
232 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXxor
) }, /* 0x72 S^(D|(P^S)) */
233 { OP(PAT
,DST
,GXorInverted
), OP(SRC
,DST
,GXnand
) },/* 0x73 ~(S&(D|~P)) */
234 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXxor
),
235 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXxor
) }, /* 0x74 D^(S|(P^D)) */
236 { OP(PAT
,SRC
,GXorInverted
), OP(SRC
,DST
,GXnand
) },/* 0x75 ~(D&(S|~P)) */
237 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXandReverse
),
238 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXxor
) }, /* 0x76 S^(D|(P&~S)) */
239 { OP(SRC
,DST
,GXnand
) }, /* 0x77 ~(S&D) */
240 { OP(SRC
,DST
,GXand
), OP(PAT
,DST
,GXxor
) }, /* 0x78 P^(D&S) */
241 { OP(DST
,TMP
,GXcopy
), OP(SRC
,DST
,GXor
),
242 OP(PAT
,DST
,GXand
), OP(SRC
,DST
,GXxor
),
243 OP(TMP
,DST
,GXequiv
) }, /* 0x79 ~D^S^(P&(D|S)) */
244 { OP(DST
,SRC
,GXorInverted
), OP(PAT
,SRC
,GXand
),
245 OP(SRC
,DST
,GXxor
) }, /* 0x7a D^(P&(S|~D)) */
246 { OP(PAT
,DST
,GXequiv
), OP(SRC
,DST
,GXnand
) }, /* 0x7b ~(S&~(D^P)) */
247 { OP(SRC
,DST
,GXorInverted
), OP(PAT
,DST
,GXand
),
248 OP(SRC
,DST
,GXxor
) }, /* 0x7c S^(P&(D|~S)) */
249 { OP(PAT
,SRC
,GXequiv
), OP(SRC
,DST
,GXnand
) }, /* 0x7d ~(D&~(P^S)) */
250 { OP(SRC
,DST
,GXxor
), OP(PAT
,SRC
,GXxor
),
251 OP(SRC
,DST
,GXor
) }, /* 0x7e (S^P)|(S^D) */
252 { OP(PAT
,SRC
,GXand
), OP(SRC
,DST
,GXnand
) }, /* 0x7f ~(D&P&S) */
253 { OP(PAT
,SRC
,GXand
), OP(SRC
,DST
,GXand
) }, /* 0x80 D&P&S */
254 { OP(SRC
,DST
,GXxor
), OP(PAT
,SRC
,GXxor
),
255 OP(SRC
,DST
,GXnor
) }, /* 0x81 ~((S^P)|(S^D)) */
256 { OP(PAT
,SRC
,GXequiv
), OP(SRC
,DST
,GXand
) }, /* 0x82 D&~(P^S) */
257 { OP(SRC
,DST
,GXorInverted
), OP(PAT
,DST
,GXand
),
258 OP(SRC
,DST
,GXequiv
) }, /* 0x83 ~S^(P&(D|~S)) */
259 { OP(PAT
,DST
,GXequiv
), OP(SRC
,DST
,GXand
) }, /* 0x84 S&~(D^P) */
260 { OP(PAT
,SRC
,GXorInverted
), OP(SRC
,DST
,GXand
),
261 OP(PAT
,DST
,GXequiv
) }, /* 0x85 ~P^(D&(S|~P)) */
262 { OP(DST
,TMP
,GXcopy
), OP(SRC
,DST
,GXor
),
263 OP(PAT
,DST
,GXand
), OP(SRC
,DST
,GXxor
),
264 OP(TMP
,DST
,GXxor
) }, /* 0x86 D^S^(P&(D|S)) */
265 { OP(SRC
,DST
,GXand
), OP(PAT
,DST
,GXequiv
) }, /* 0x87 ~P^(D&S) */
266 { OP(SRC
,DST
,GXand
) }, /* 0x88 S&D */
267 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXandReverse
),
268 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXequiv
) }, /* 0x89 ~S^(D|(P&~S)) */
269 { OP(PAT
,SRC
,GXorInverted
), OP(SRC
,DST
,GXand
) }, /* 0x8a D&(S|~P) */
270 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXxor
),
271 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXequiv
) }, /* 0x8b ~D^(S|(P^D)) */
272 { OP(PAT
,DST
,GXorInverted
), OP(SRC
,DST
,GXand
) }, /* 0x8c S&(D|~P) */
273 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXxor
),
274 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXequiv
) }, /* 0x8d ~S^(D|(P^S)) */
275 { OP(SRC
,TMP
,GXcopy
), OP(DST
,SRC
,GXxor
),
276 OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXand
),
277 OP(TMP
,DST
,GXxor
) }, /* 0x8e S^((S^D)&(P^D))*/
278 { OP(SRC
,DST
,GXnand
), OP(PAT
,DST
,GXnand
) }, /* 0x8f ~(P&~(D&S)) */
279 { OP(SRC
,DST
,GXequiv
), OP(PAT
,DST
,GXand
) }, /* 0x90 P&~(D^S) */
280 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXorReverse
),
281 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXequiv
) }, /* 0x91 ~S^(D&(P|~S)) */
282 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXor
),
283 OP(SRC
,DST
,GXand
), OP(PAT
,DST
,GXxor
),
284 OP(TMP
,DST
,GXxor
) }, /* 0x92 D^P^(S&(D|P)) */
285 { OP(PAT
,DST
,GXand
), OP(SRC
,DST
,GXequiv
) }, /* 0x93 ~S^(P&D) */
286 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXor
),
287 OP(SRC
,DST
,GXand
), OP(PAT
,DST
,GXxor
),
288 OP(TMP
,DST
,GXxor
) }, /* 0x94 S^P^(D&(P|S)) */
289 { OP(PAT
,SRC
,GXand
), OP(SRC
,DST
,GXequiv
) }, /* 0x95 ~D^(P&S) */
290 { OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXxor
) }, /* 0x96 D^P^S */
291 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXnor
),
292 OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXxor
),
293 OP(TMP
,DST
,GXxor
) }, /* 0x97 S^P^(D|~(P|S)) */
294 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXnor
),
295 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXequiv
) }, /* 0x98 ~S^(D|~(P|S)) */
296 { OP(SRC
,DST
,GXequiv
) }, /* 0x99 ~S^D */
297 { OP(PAT
,SRC
,GXandReverse
), OP(SRC
,DST
,GXxor
) }, /* 0x9a D^(P&~S) */
298 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXor
),
299 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXequiv
) }, /* 0x9b ~S^(D&(P|S)) */
300 { OP(PAT
,DST
,GXandReverse
), OP(SRC
,DST
,GXxor
) }, /* 0x9c S^(P&~D) */
301 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXor
),
302 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXequiv
) }, /* 0x9d ~D^(S&(P|D)) */
303 { OP(DST
,TMP
,GXcopy
), OP(SRC
,DST
,GXand
),
304 OP(PAT
,DST
,GXor
), OP(SRC
,DST
,GXxor
),
305 OP(TMP
,DST
,GXxor
) }, /* 0x9e D^S^(P|(D&S)) */
306 { OP(SRC
,DST
,GXxor
), OP(PAT
,DST
,GXnand
) }, /* 0x9f ~(P&(D^S)) */
307 { OP(PAT
,DST
,GXand
) }, /* 0xa0 D&P */
308 { OP(PAT
,SRC
,GXandInverted
), OP(SRC
,DST
,GXor
),
309 OP(PAT
,DST
,GXequiv
) }, /* 0xa1 ~P^(D|(S&~P)) */
310 { OP(PAT
,SRC
,GXorReverse
), OP(SRC
,DST
,GXand
) }, /* 0xa2 D&(P|~S) */
311 { OP(DST
,SRC
,GXxor
), OP(PAT
,SRC
,GXor
),
312 OP(SRC
,DST
,GXequiv
) }, /* 0xa3 ~D^(P|(S^D)) */
313 { OP(PAT
,SRC
,GXnor
), OP(SRC
,DST
,GXor
),
314 OP(PAT
,DST
,GXequiv
) }, /* 0xa4 ~P^(D|~(S|P)) */
315 { OP(PAT
,DST
,GXequiv
) }, /* 0xa5 ~P^D */
316 { OP(PAT
,SRC
,GXandInverted
), OP(SRC
,DST
,GXxor
) },/* 0xa6 D^(S&~P) */
317 { OP(PAT
,SRC
,GXor
), OP(SRC
,DST
,GXand
),
318 OP(PAT
,DST
,GXequiv
) }, /* 0xa7 ~P^(D&(S|P)) */
319 { OP(PAT
,SRC
,GXor
), OP(SRC
,DST
,GXand
) }, /* 0xa8 D&(P|S) */
320 { OP(PAT
,SRC
,GXor
), OP(SRC
,DST
,GXequiv
) }, /* 0xa9 ~D^(P|S) */
321 { OP(SRC
,DST
,GXnoop
) }, /* 0xaa D */
322 { OP(PAT
,SRC
,GXnor
), OP(SRC
,DST
,GXor
) }, /* 0xab D|~(P|S) */
323 { OP(SRC
,DST
,GXxor
), OP(PAT
,DST
,GXand
),
324 OP(SRC
,DST
,GXxor
) }, /* 0xac S^(P&(D^S)) */
325 { OP(DST
,SRC
,GXand
), OP(PAT
,SRC
,GXor
),
326 OP(SRC
,DST
,GXequiv
) }, /* 0xad ~D^(P|(S&D)) */
327 { OP(PAT
,SRC
,GXandInverted
), OP(SRC
,DST
,GXor
) }, /* 0xae D|(S&~P) */
328 { OP(PAT
,DST
,GXorInverted
) }, /* 0xaf D|~P */
329 { OP(SRC
,DST
,GXorInverted
), OP(PAT
,DST
,GXand
) }, /* 0xb0 P&(D|~S) */
330 { OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXor
),
331 OP(PAT
,DST
,GXequiv
) }, /* 0xb1 ~P^(D|(S^P)) */
332 { OP(SRC
,TMP
,GXcopy
), OP(SRC
,DST
,GXxor
),
333 OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXor
),
334 OP(TMP
,DST
,GXxor
) }, /* 0xb2 S^((S^P)|(S^D))*/
335 { OP(PAT
,DST
,GXnand
), OP(SRC
,DST
,GXnand
) }, /* 0xb3 ~(S&~(D&P)) */
336 { OP(SRC
,DST
,GXandReverse
), OP(PAT
,DST
,GXxor
) }, /* 0xb4 P^(S&~D) */
337 { OP(DST
,SRC
,GXor
), OP(PAT
,SRC
,GXand
),
338 OP(SRC
,DST
,GXequiv
) }, /* 0xb5 ~D^(P&(S|D)) */
339 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXand
),
340 OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXxor
),
341 OP(TMP
,DST
,GXxor
) }, /* 0xb6 D^P^(S|(D&P)) */
342 { OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXnand
) }, /* 0xb7 ~(S&(D^P)) */
343 { OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXand
),
344 OP(PAT
,DST
,GXxor
) }, /* 0xb8 P^(S&(D^P)) */
345 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXand
),
346 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXequiv
) }, /* 0xb9 ~D^(S|(P&D)) */
347 { OP(PAT
,SRC
,GXandReverse
), OP(SRC
,DST
,GXor
) }, /* 0xba D|(P&~S) */
348 { OP(SRC
,DST
,GXorInverted
) }, /* 0xbb ~S|D */
349 { OP(SRC
,DST
,GXnand
), OP(PAT
,DST
,GXand
),
350 OP(SRC
,DST
,GXxor
) }, /* 0xbc S^(P&~(D&S)) */
351 { OP(DST
,SRC
,GXxor
), OP(PAT
,DST
,GXxor
),
352 OP(SRC
,DST
,GXnand
) }, /* 0xbd ~((S^D)&(P^D)) */
353 { OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXor
) }, /* 0xbe D|(P^S) */
354 { OP(PAT
,SRC
,GXnand
), OP(SRC
,DST
,GXor
) }, /* 0xbf D|~(P&S) */
355 { OP(PAT
,SRC
,GXand
) }, /* 0xc0 P&S */
356 { OP(SRC
,DST
,GXandInverted
), OP(PAT
,DST
,GXor
),
357 OP(SRC
,DST
,GXequiv
) }, /* 0xc1 ~S^(P|(D&~S)) */
358 { OP(SRC
,DST
,GXnor
), OP(PAT
,DST
,GXor
),
359 OP(SRC
,DST
,GXequiv
) }, /* 0xc2 ~S^(P|~(D|S)) */
360 { OP(PAT
,SRC
,GXequiv
) }, /* 0xc3 ~P^S */
361 { OP(PAT
,DST
,GXorReverse
), OP(SRC
,DST
,GXand
) }, /* 0xc4 S&(P|~D) */
362 { OP(SRC
,DST
,GXxor
), OP(PAT
,DST
,GXor
),
363 OP(SRC
,DST
,GXequiv
) }, /* 0xc5 ~S^(P|(D^S)) */
364 { OP(PAT
,DST
,GXandInverted
), OP(SRC
,DST
,GXxor
) },/* 0xc6 S^(D&~P) */
365 { OP(PAT
,DST
,GXor
), OP(SRC
,DST
,GXand
),
366 OP(PAT
,DST
,GXequiv
) }, /* 0xc7 ~P^(S&(D|P)) */
367 { OP(PAT
,DST
,GXor
), OP(SRC
,DST
,GXand
) }, /* 0xc8 S&(D|P) */
368 { OP(PAT
,DST
,GXor
), OP(SRC
,DST
,GXequiv
) }, /* 0xc9 ~S^(P|D) */
369 { OP(DST
,SRC
,GXxor
), OP(PAT
,SRC
,GXand
),
370 OP(SRC
,DST
,GXxor
) }, /* 0xca D^(P&(S^D)) */
371 { OP(SRC
,DST
,GXand
), OP(PAT
,DST
,GXor
),
372 OP(SRC
,DST
,GXequiv
) }, /* 0xcb ~S^(P|(D&S)) */
373 { OP(SRC
,DST
,GXcopy
) }, /* 0xcc S */
374 { OP(PAT
,DST
,GXnor
), OP(SRC
,DST
,GXor
) }, /* 0xcd S|~(D|P) */
375 { OP(PAT
,DST
,GXandInverted
), OP(SRC
,DST
,GXor
) }, /* 0xce S|(D&~P) */
376 { OP(PAT
,SRC
,GXorInverted
) }, /* 0xcf S|~P */
377 { OP(SRC
,DST
,GXorReverse
), OP(PAT
,DST
,GXand
) }, /* 0xd0 P&(S|~D) */
378 { OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXor
),
379 OP(PAT
,DST
,GXequiv
) }, /* 0xd1 ~P^(S|(D^P)) */
380 { OP(SRC
,DST
,GXandInverted
), OP(PAT
,DST
,GXxor
) },/* 0xd2 P^(D&~S) */
381 { OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXand
),
382 OP(SRC
,DST
,GXequiv
) }, /* 0xd3 ~S^(P&(D|S)) */
383 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXxor
),
384 OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXand
),
385 OP(TMP
,DST
,GXxor
) }, /* 0xd4 S^((S^P)&(D^P))*/
386 { OP(PAT
,SRC
,GXnand
), OP(SRC
,DST
,GXnand
) }, /* 0xd5 ~(D&~(P&S)) */
387 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXand
),
388 OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXxor
),
389 OP(TMP
,DST
,GXxor
) }, /* 0xd6 S^P^(D|(P&S)) */
390 { OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXnand
) }, /* 0xd7 ~(D&(P^S)) */
391 { OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXand
),
392 OP(PAT
,DST
,GXxor
) }, /* 0xd8 P^(D&(S^P)) */
393 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXand
),
394 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXequiv
) }, /* 0xd9 ~S^(D|(P&S)) */
395 { OP(DST
,SRC
,GXnand
), OP(PAT
,SRC
,GXand
),
396 OP(SRC
,DST
,GXxor
) }, /* 0xda D^(P&~(S&D)) */
397 { OP(SRC
,DST
,GXxor
), OP(PAT
,SRC
,GXxor
),
398 OP(SRC
,DST
,GXnand
) }, /* 0xdb ~((S^P)&(S^D)) */
399 { OP(PAT
,DST
,GXandReverse
), OP(SRC
,DST
,GXor
) }, /* 0xdc S|(P&~D) */
400 { OP(SRC
,DST
,GXorReverse
) }, /* 0xdd S|~D */
401 { OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXor
) }, /* 0xde S|(D^P) */
402 { OP(PAT
,DST
,GXnand
), OP(SRC
,DST
,GXor
) }, /* 0xdf S|~(D&P) */
403 { OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXand
) }, /* 0xe0 P&(D|S) */
404 { OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXequiv
) }, /* 0xe1 ~P^(D|S) */
405 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXxor
),
406 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXxor
) }, /* 0xe2 D^(S&(P^D)) */
407 { OP(PAT
,DST
,GXand
), OP(SRC
,DST
,GXor
),
408 OP(PAT
,DST
,GXequiv
) }, /* 0xe3 ~P^(S|(D&P)) */
409 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXxor
),
410 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXxor
) }, /* 0xe4 S^(D&(P^S)) */
411 { OP(PAT
,SRC
,GXand
), OP(SRC
,DST
,GXor
),
412 OP(PAT
,DST
,GXequiv
) }, /* 0xe5 ~P^(D|(S&P)) */
413 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXnand
),
414 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXxor
) }, /* 0xe6 S^(D&~(P&S)) */
415 { OP(PAT
,SRC
,GXxor
), OP(PAT
,DST
,GXxor
),
416 OP(SRC
,DST
,GXnand
) }, /* 0xe7 ~((S^P)&(D^P)) */
417 { OP(SRC
,TMP
,GXcopy
), OP(SRC
,DST
,GXxor
),
418 OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXand
),
419 OP(TMP
,DST
,GXxor
) }, /* 0xe8 S^((S^P)&(S^D))*/
420 { OP(DST
,TMP
,GXcopy
), OP(SRC
,DST
,GXnand
),
421 OP(PAT
,DST
,GXand
), OP(SRC
,DST
,GXxor
),
422 OP(TMP
,DST
,GXequiv
) }, /* 0xe9 ~D^S^(P&~(S&D))*/
423 { OP(PAT
,SRC
,GXand
), OP(SRC
,DST
,GXor
) }, /* 0xea D|(P&S) */
424 { OP(PAT
,SRC
,GXequiv
), OP(SRC
,DST
,GXor
) }, /* 0xeb D|~(P^S) */
425 { OP(PAT
,DST
,GXand
), OP(SRC
,DST
,GXor
) }, /* 0xec S|(D&P) */
426 { OP(PAT
,DST
,GXequiv
), OP(SRC
,DST
,GXor
) }, /* 0xed S|~(D^P) */
427 { OP(SRC
,DST
,GXor
) }, /* 0xee S|D */
428 { OP(PAT
,DST
,GXorInverted
), OP(SRC
,DST
,GXor
) }, /* 0xef S|D|~P */
429 { OP(PAT
,DST
,GXcopy
) }, /* 0xf0 P */
430 { OP(SRC
,DST
,GXnor
), OP(PAT
,DST
,GXor
) }, /* 0xf1 P|~(D|S) */
431 { OP(SRC
,DST
,GXandInverted
), OP(PAT
,DST
,GXor
) }, /* 0xf2 P|(D&~S) */
432 { OP(PAT
,SRC
,GXorReverse
) }, /* 0xf3 P|~S */
433 { OP(SRC
,DST
,GXandReverse
), OP(PAT
,DST
,GXor
) }, /* 0xf4 P|(S&~D) */
434 { OP(PAT
,DST
,GXorReverse
) }, /* 0xf5 P|~D */
435 { OP(SRC
,DST
,GXxor
), OP(PAT
,DST
,GXor
) }, /* 0xf6 P|(D^S) */
436 { OP(SRC
,DST
,GXnand
), OP(PAT
,DST
,GXor
) }, /* 0xf7 P|~(S&D) */
437 { OP(SRC
,DST
,GXand
), OP(PAT
,DST
,GXor
) }, /* 0xf8 P|(D&S) */
438 { OP(SRC
,DST
,GXequiv
), OP(PAT
,DST
,GXor
) }, /* 0xf9 P|~(D^S) */
439 { OP(PAT
,DST
,GXor
) }, /* 0xfa D|P */
440 { OP(PAT
,SRC
,GXorReverse
), OP(SRC
,DST
,GXor
) }, /* 0xfb D|P|~S */
441 { OP(PAT
,SRC
,GXor
) }, /* 0xfc P|S */
442 { OP(SRC
,DST
,GXorReverse
), OP(PAT
,DST
,GXor
) }, /* 0xfd P|S|~D */
443 { OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXor
) }, /* 0xfe P|D|S */
444 { OP(PAT
,DST
,GXset
) } /* 0xff 1 */
448 #ifdef BITBLT_TEST /* Opcodes test */
450 static int do_bitop( int s
, int d
, int rop
)
455 case GXclear
: res
= 0; break;
456 case GXand
: res
= s
& d
; break;
457 case GXandReverse
: res
= s
& ~d
; break;
458 case GXcopy
: res
= s
; break;
459 case GXandInverted
: res
= ~s
& d
; break;
460 case GXnoop
: res
= d
; break;
461 case GXxor
: res
= s
^ d
; break;
462 case GXor
: res
= s
| d
; break;
463 case GXnor
: res
= ~(s
| d
); break;
464 case GXequiv
: res
= ~s
^ d
; break;
465 case GXinvert
: res
= ~d
; break;
466 case GXorReverse
: res
= s
| ~d
; break;
467 case GXcopyInverted
: res
= ~s
; break;
468 case GXorInverted
: res
= ~s
| d
; break;
469 case GXnand
: res
= ~(s
& d
); break;
470 case GXset
: res
= 1; break;
477 int rop
, i
, res
, src
, dst
, pat
, tmp
, dstUsed
;
480 for (rop
= 0; rop
< 256; rop
++)
483 for (i
= 0; i
< 8; i
++)
488 for (opcode
= BITBLT_Opcodes
[rop
]; *opcode
; opcode
++)
492 case OP_ARGS(DST
,TMP
):
493 tmp
= do_bitop( dst
, tmp
, *opcode
& 0xf );
495 case OP_ARGS(DST
,SRC
):
496 src
= do_bitop( dst
, src
, *opcode
& 0xf );
498 case OP_ARGS(SRC
,TMP
):
499 tmp
= do_bitop( src
, tmp
, *opcode
& 0xf );
501 case OP_ARGS(SRC
,DST
):
502 dst
= do_bitop( src
, dst
, *opcode
& 0xf );
505 case OP_ARGS(PAT
,TMP
):
506 tmp
= do_bitop( pat
, tmp
, *opcode
& 0xf );
508 case OP_ARGS(PAT
,DST
):
509 dst
= do_bitop( pat
, dst
, *opcode
& 0xf );
512 case OP_ARGS(PAT
,SRC
):
513 src
= do_bitop( pat
, src
, *opcode
& 0xf );
515 case OP_ARGS(TMP
,DST
):
516 dst
= do_bitop( tmp
, dst
, *opcode
& 0xf );
519 case OP_ARGS(TMP
,SRC
):
520 src
= do_bitop( tmp
, src
, *opcode
& 0xf );
523 printf( "Invalid opcode %x\n", *opcode
);
526 if (!dstUsed
) dst
= src
;
527 if (dst
) res
|= 1 << i
;
529 if (res
!= rop
) printf( "%02x: ERROR, res=%02x\n", rop
, res
);
535 #endif /* BITBLT_TEST */
538 /***********************************************************************
541 * Favor correctness or speed?
543 static int perfect_graphics(void)
545 static int perfect
= -1;
552 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\x11drv", &hkey
))
554 DWORD type
, count
= sizeof(buffer
);
555 if(!RegQueryValueExA(hkey
, "PerfectGraphics", 0, &type
, buffer
, &count
))
558 perfect
= (ch
== 'y' || ch
== 'Y' || ch
== 't' || ch
== 'T' || ch
== '1');
566 static void get_colors(X11DRV_PDEVICE
*physDevDst
, X11DRV_PDEVICE
*physDevSrc
,
571 *fg
= physDevDst
->textPixel
;
572 *bg
= physDevDst
->backgroundPixel
;
573 if(physDevSrc
->depth
== 1) {
574 if(GetDIBColorTable(physDevSrc
->hdc
, 0, 2, rgb
) == 2) {
576 logcolor
= RGB(rgb
[0].rgbRed
, rgb
[0].rgbGreen
, rgb
[0].rgbBlue
);
577 *fg
= X11DRV_PALETTE_ToPhysical( physDevDst
, logcolor
);
578 logcolor
= RGB(rgb
[1].rgbRed
, rgb
[1].rgbGreen
,rgb
[1].rgbBlue
);
579 *bg
= X11DRV_PALETTE_ToPhysical( physDevDst
, logcolor
);
584 /***********************************************************************
587 * Stretch a row of pixels. Helper function for BITBLT_StretchImage.
589 static void BITBLT_StretchRow( int *rowSrc
, int *rowDst
,
590 INT startDst
, INT widthDst
,
591 INT xinc
, INT xoff
, WORD mode
)
593 register INT xsrc
= xinc
* startDst
+ xoff
;
597 case STRETCH_ANDSCANS
:
598 for(; widthDst
> 0; widthDst
--, xsrc
+= xinc
)
599 *rowDst
++ &= rowSrc
[xsrc
>> 16];
601 case STRETCH_ORSCANS
:
602 for(; widthDst
> 0; widthDst
--, xsrc
+= xinc
)
603 *rowDst
++ |= rowSrc
[xsrc
>> 16];
605 case STRETCH_DELETESCANS
:
606 for(; widthDst
> 0; widthDst
--, xsrc
+= xinc
)
607 *rowDst
++ = rowSrc
[xsrc
>> 16];
613 /***********************************************************************
616 * Shrink a row of pixels. Helper function for BITBLT_StretchImage.
618 static void BITBLT_ShrinkRow( int *rowSrc
, int *rowDst
,
619 INT startSrc
, INT widthSrc
,
620 INT xinc
, INT xoff
, WORD mode
)
622 register INT xdst
= xinc
* startSrc
+ xoff
;
626 case STRETCH_ORSCANS
:
627 for(; widthSrc
> 0; widthSrc
--, xdst
+= xinc
)
628 rowDst
[xdst
>> 16] |= *rowSrc
++;
630 case STRETCH_ANDSCANS
:
631 for(; widthSrc
> 0; widthSrc
--, xdst
+= xinc
)
632 rowDst
[xdst
>> 16] &= *rowSrc
++;
634 case STRETCH_DELETESCANS
:
635 for(; widthSrc
> 0; widthSrc
--, xdst
+= xinc
)
636 rowDst
[xdst
>> 16] = *rowSrc
++;
642 /***********************************************************************
645 * Retrieve a row from an image. Helper function for BITBLT_StretchImage.
647 static void BITBLT_GetRow( XImage
*image
, int *pdata
, INT row
,
648 INT start
, INT width
, INT depthDst
,
649 int fg
, int bg
, BOOL swap
)
653 assert( (row
>= 0) && (row
< image
->height
) );
654 assert( (start
>= 0) && (width
<= image
->width
) );
656 pdata
+= swap
? start
+width
-1 : start
;
657 if (image
->depth
== depthDst
) /* color -> color */
659 if (X11DRV_PALETTE_XPixelToPalette
&& (depthDst
!= 1))
660 if (swap
) for (i
= 0; i
< width
; i
++)
661 *pdata
-- = X11DRV_PALETTE_XPixelToPalette
[XGetPixel( image
, i
, row
)];
662 else for (i
= 0; i
< width
; i
++)
663 *pdata
++ = X11DRV_PALETTE_XPixelToPalette
[XGetPixel( image
, i
, row
)];
665 if (swap
) for (i
= 0; i
< width
; i
++)
666 *pdata
-- = XGetPixel( image
, i
, row
);
667 else for (i
= 0; i
< width
; i
++)
668 *pdata
++ = XGetPixel( image
, i
, row
);
672 if (image
->depth
== 1) /* monochrome -> color */
674 if (X11DRV_PALETTE_XPixelToPalette
)
676 fg
= X11DRV_PALETTE_XPixelToPalette
[fg
];
677 bg
= X11DRV_PALETTE_XPixelToPalette
[bg
];
679 if (swap
) for (i
= 0; i
< width
; i
++)
680 *pdata
-- = XGetPixel( image
, i
, row
) ? bg
: fg
;
681 else for (i
= 0; i
< width
; i
++)
682 *pdata
++ = XGetPixel( image
, i
, row
) ? bg
: fg
;
684 else /* color -> monochrome */
686 if (swap
) for (i
= 0; i
< width
; i
++)
687 *pdata
-- = (XGetPixel( image
, i
, row
) == bg
) ? 1 : 0;
688 else for (i
= 0; i
< width
; i
++)
689 *pdata
++ = (XGetPixel( image
, i
, row
) == bg
) ? 1 : 0;
695 /***********************************************************************
696 * BITBLT_StretchImage
698 * Stretch an X image.
699 * FIXME: does not work for full 32-bit coordinates.
701 static void BITBLT_StretchImage( XImage
*srcImage
, XImage
*dstImage
,
702 INT widthSrc
, INT heightSrc
,
703 INT widthDst
, INT heightDst
,
704 RECT
*visRectSrc
, RECT
*visRectDst
,
705 int foreground
, int background
, WORD mode
)
707 int *rowSrc
, *rowDst
, *pixel
;
709 INT xinc
, xoff
, yinc
, ysrc
, ydst
;
711 BOOL hstretch
, vstretch
, hswap
, vswap
;
713 hswap
= ((int)widthSrc
* widthDst
) < 0;
714 vswap
= ((int)heightSrc
* heightDst
) < 0;
715 widthSrc
= abs(widthSrc
);
716 heightSrc
= abs(heightSrc
);
717 widthDst
= abs(widthDst
);
718 heightDst
= abs(heightDst
);
720 if (!(rowSrc
= HeapAlloc( GetProcessHeap(), 0,
721 (widthSrc
+widthDst
)*sizeof(int) ))) return;
722 rowDst
= rowSrc
+ widthSrc
;
724 /* When stretching, all modes are the same, and DELETESCANS is faster */
725 if ((widthSrc
< widthDst
) && (heightSrc
< heightDst
))
726 mode
= STRETCH_DELETESCANS
;
728 if (mode
== STRETCH_HALFTONE
) /* FIXME */
729 mode
= STRETCH_DELETESCANS
;
731 if (mode
!= STRETCH_DELETESCANS
)
732 memset( rowDst
, (mode
== STRETCH_ANDSCANS
) ? 0xff : 0x00,
733 widthDst
*sizeof(int) );
735 hstretch
= (widthSrc
< widthDst
);
736 vstretch
= (heightSrc
< heightDst
);
740 xinc
= ((int)widthSrc
<< 16) / widthDst
;
741 xoff
= ((widthSrc
<< 16) - (xinc
* widthDst
)) / 2;
745 xinc
= ((int)widthDst
<< 16) / widthSrc
;
746 xoff
= ((widthDst
<< 16) - (xinc
* widthSrc
)) / 2;
751 yinc
= ((int)heightSrc
<< 16) / heightDst
;
752 ydst
= visRectDst
->top
;
755 ysrc
= yinc
* (heightDst
- ydst
- 1);
761 for ( ; (ydst
< visRectDst
->bottom
); ysrc
+= yinc
, ydst
++)
763 if (((ysrc
>> 16) < visRectSrc
->top
) ||
764 ((ysrc
>> 16) >= visRectSrc
->bottom
)) continue;
766 /* Retrieve a source row */
767 BITBLT_GetRow( srcImage
, rowSrc
, (ysrc
>> 16) - visRectSrc
->top
,
768 hswap
? widthSrc
- visRectSrc
->right
770 visRectSrc
->right
- visRectSrc
->left
,
771 dstImage
->depth
, foreground
, background
, hswap
);
773 /* Stretch or shrink it */
775 BITBLT_StretchRow( rowSrc
, rowDst
, visRectDst
->left
,
776 visRectDst
->right
- visRectDst
->left
,
778 else BITBLT_ShrinkRow( rowSrc
, rowDst
,
779 hswap
? widthSrc
- visRectSrc
->right
781 visRectSrc
->right
- visRectSrc
->left
,
784 /* Store the destination row */
785 pixel
= rowDst
+ visRectDst
->right
- 1;
786 y
= ydst
- visRectDst
->top
;
787 for (x
= visRectDst
->right
-visRectDst
->left
-1; x
>= 0; x
--)
788 XPutPixel( dstImage
, x
, y
, *pixel
-- );
789 if (mode
!= STRETCH_DELETESCANS
)
790 memset( rowDst
, (mode
== STRETCH_ANDSCANS
) ? 0xff : 0x00,
791 widthDst
*sizeof(int) );
793 /* Make copies of the destination row */
795 pdata
= dstImage
->data
+ dstImage
->bytes_per_line
* y
;
796 while (((ysrc
+ yinc
) >> 16 == ysrc
>> 16) &&
797 (ydst
< visRectDst
->bottom
-1))
799 memcpy( pdata
+ dstImage
->bytes_per_line
, pdata
,
800 dstImage
->bytes_per_line
);
801 pdata
+= dstImage
->bytes_per_line
;
809 yinc
= ((int)heightDst
<< 16) / heightSrc
;
810 ysrc
= visRectSrc
->top
;
811 ydst
= ((heightDst
<< 16) - (yinc
* heightSrc
)) / 2;
814 ydst
+= yinc
* (heightSrc
- ysrc
- 1);
820 for( ; (ysrc
< visRectSrc
->bottom
); ydst
+= yinc
, ysrc
++)
822 if (((ydst
>> 16) < visRectDst
->top
) ||
823 ((ydst
>> 16) >= visRectDst
->bottom
)) continue;
825 /* Retrieve a source row */
826 BITBLT_GetRow( srcImage
, rowSrc
, ysrc
- visRectSrc
->top
,
827 hswap
? widthSrc
- visRectSrc
->right
829 visRectSrc
->right
- visRectSrc
->left
,
830 dstImage
->depth
, foreground
, background
, hswap
);
832 /* Stretch or shrink it */
834 BITBLT_StretchRow( rowSrc
, rowDst
, visRectDst
->left
,
835 visRectDst
->right
- visRectDst
->left
,
837 else BITBLT_ShrinkRow( rowSrc
, rowDst
,
838 hswap
? widthSrc
- visRectSrc
->right
840 visRectSrc
->right
- visRectSrc
->left
,
843 /* Merge several source rows into the destination */
844 if (mode
== STRETCH_DELETESCANS
)
846 /* Simply skip the overlapping rows */
847 while (((ydst
+ yinc
) >> 16 == ydst
>> 16) &&
848 (ysrc
< visRectSrc
->bottom
-1))
854 else if (((ydst
+ yinc
) >> 16 == ydst
>> 16) &&
855 (ysrc
< visRectSrc
->bottom
-1))
856 continue; /* Restart loop for next overlapping row */
858 /* Store the destination row */
859 pixel
= rowDst
+ visRectDst
->right
- 1;
860 y
= (ydst
>> 16) - visRectDst
->top
;
861 for (x
= visRectDst
->right
-visRectDst
->left
-1; x
>= 0; x
--)
862 XPutPixel( dstImage
, x
, y
, *pixel
-- );
863 if (mode
!= STRETCH_DELETESCANS
)
864 memset( rowDst
, (mode
== STRETCH_ANDSCANS
) ? 0xff : 0x00,
865 widthDst
*sizeof(int) );
868 HeapFree( GetProcessHeap(), 0, rowSrc
);
872 /***********************************************************************
873 * BITBLT_GetSrcAreaStretch
875 * Retrieve an area from the source DC, stretching and mapping all the
876 * pixels to Windows colors.
878 static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE
*physDevSrc
, X11DRV_PDEVICE
*physDevDst
,
879 Pixmap pixmap
, GC gc
,
881 INT widthSrc
, INT heightSrc
,
883 INT widthDst
, INT heightDst
,
884 RECT
*visRectSrc
, RECT
*visRectDst
)
886 XImage
*imageSrc
, *imageDst
;
887 RECT rectSrc
= *visRectSrc
;
888 RECT rectDst
= *visRectDst
;
891 if (widthSrc
< 0) xSrc
+= widthSrc
;
892 if (widthDst
< 0) xDst
+= widthDst
;
893 if (heightSrc
< 0) ySrc
+= heightSrc
;
894 if (heightDst
< 0) yDst
+= heightDst
;
895 rectSrc
.left
-= xSrc
;
896 rectSrc
.right
-= xSrc
;
898 rectSrc
.bottom
-= ySrc
;
899 rectDst
.left
-= xDst
;
900 rectDst
.right
-= xDst
;
902 rectDst
.bottom
-= yDst
;
904 get_colors(physDevDst
, physDevSrc
, &fg
, &bg
);
905 /* FIXME: avoid BadMatch errors */
906 imageSrc
= XGetImage( gdi_display
, physDevSrc
->drawable
,
907 physDevSrc
->org
.x
+ visRectSrc
->left
,
908 physDevSrc
->org
.y
+ visRectSrc
->top
,
909 visRectSrc
->right
- visRectSrc
->left
,
910 visRectSrc
->bottom
- visRectSrc
->top
,
911 AllPlanes
, ZPixmap
);
912 imageDst
= X11DRV_DIB_CreateXImage( rectDst
.right
- rectDst
.left
,
913 rectDst
.bottom
- rectDst
.top
, physDevDst
->depth
);
914 BITBLT_StretchImage( imageSrc
, imageDst
, widthSrc
, heightSrc
,
915 widthDst
, heightDst
, &rectSrc
, &rectDst
,
916 fg
, physDevDst
->depth
!= 1 ?
917 bg
: physDevSrc
->backgroundPixel
,
918 GetStretchBltMode(physDevDst
->hdc
) );
919 XPutImage( gdi_display
, pixmap
, gc
, imageDst
, 0, 0, 0, 0,
920 rectDst
.right
- rectDst
.left
, rectDst
.bottom
- rectDst
.top
);
921 XDestroyImage( imageSrc
);
922 XDestroyImage( imageDst
);
923 return 0; /* no exposure events generated */
927 /***********************************************************************
930 * Retrieve an area from the source DC, mapping all the
931 * pixels to Windows colors.
933 static int BITBLT_GetSrcArea( X11DRV_PDEVICE
*physDevSrc
, X11DRV_PDEVICE
*physDevDst
,
934 Pixmap pixmap
, GC gc
, INT xSrc
, INT ySrc
, RECT
*visRectSrc
)
936 XImage
*imageSrc
, *imageDst
;
939 INT width
= visRectSrc
->right
- visRectSrc
->left
;
940 INT height
= visRectSrc
->bottom
- visRectSrc
->top
;
943 if (physDevSrc
->depth
== physDevDst
->depth
)
945 if (!X11DRV_PALETTE_XPixelToPalette
||
946 (physDevDst
->depth
== 1)) /* monochrome -> monochrome */
948 if (physDevDst
->depth
== 1)
950 /* MSDN says if StretchBlt must convert a bitmap from monochrome
951 to color or vice versa, the forground and background color of
952 the device context are used. In fact, it also applies to the
953 case when it is converted from mono to mono. */
954 XSetBackground( gdi_display
, gc
, physDevDst
->textPixel
);
955 XSetForeground( gdi_display
, gc
, physDevDst
->backgroundPixel
);
956 XCopyPlane( gdi_display
, physDevSrc
->drawable
, pixmap
, gc
,
957 physDevSrc
->org
.x
+ visRectSrc
->left
,
958 physDevSrc
->org
.y
+ visRectSrc
->top
,
959 width
, height
, 0, 0, 1);
962 XCopyArea( gdi_display
, physDevSrc
->drawable
, pixmap
, gc
,
963 physDevSrc
->org
.x
+ visRectSrc
->left
,
964 physDevSrc
->org
.y
+ visRectSrc
->top
,
965 width
, height
, 0, 0);
968 else /* color -> color */
970 if (GetObjectType(physDevSrc
->hdc
) == OBJ_MEMDC
)
971 imageSrc
= XGetImage( gdi_display
, physDevSrc
->drawable
,
972 physDevSrc
->org
.x
+ visRectSrc
->left
,
973 physDevSrc
->org
.y
+ visRectSrc
->top
,
974 width
, height
, AllPlanes
, ZPixmap
);
977 /* Make sure we don't get a BadMatch error */
978 XCopyArea( gdi_display
, physDevSrc
->drawable
, pixmap
, gc
,
979 physDevSrc
->org
.x
+ visRectSrc
->left
,
980 physDevSrc
->org
.y
+ visRectSrc
->top
,
981 width
, height
, 0, 0);
983 imageSrc
= XGetImage( gdi_display
, pixmap
, 0, 0, width
, height
,
984 AllPlanes
, ZPixmap
);
986 for (y
= 0; y
< height
; y
++)
987 for (x
= 0; x
< width
; x
++)
988 XPutPixel(imageSrc
, x
, y
,
989 X11DRV_PALETTE_XPixelToPalette
[XGetPixel(imageSrc
, x
, y
)]);
990 XPutImage( gdi_display
, pixmap
, gc
, imageSrc
,
991 0, 0, 0, 0, width
, height
);
992 XDestroyImage( imageSrc
);
997 if (physDevSrc
->depth
== 1) /* monochrome -> color */
999 get_colors(physDevDst
, physDevSrc
, &fg
, &bg
);
1001 if (X11DRV_PALETTE_XPixelToPalette
)
1003 XSetBackground( gdi_display
, gc
,
1004 X11DRV_PALETTE_XPixelToPalette
[fg
] );
1005 XSetForeground( gdi_display
, gc
,
1006 X11DRV_PALETTE_XPixelToPalette
[bg
]);
1010 XSetBackground( gdi_display
, gc
, fg
);
1011 XSetForeground( gdi_display
, gc
, bg
);
1013 XCopyPlane( gdi_display
, physDevSrc
->drawable
, pixmap
, gc
,
1014 physDevSrc
->org
.x
+ visRectSrc
->left
,
1015 physDevSrc
->org
.y
+ visRectSrc
->top
,
1016 width
, height
, 0, 0, 1 );
1019 else /* color -> monochrome */
1021 /* FIXME: avoid BadMatch error */
1022 imageSrc
= XGetImage( gdi_display
, physDevSrc
->drawable
,
1023 physDevSrc
->org
.x
+ visRectSrc
->left
,
1024 physDevSrc
->org
.y
+ visRectSrc
->top
,
1025 width
, height
, AllPlanes
, ZPixmap
);
1030 imageDst
= X11DRV_DIB_CreateXImage( width
, height
, physDevDst
->depth
);
1033 XDestroyImage(imageSrc
);
1036 for (y
= 0; y
< height
; y
++)
1037 for (x
= 0; x
< width
; x
++)
1038 XPutPixel(imageDst
, x
, y
, (XGetPixel(imageSrc
,x
,y
) ==
1039 physDevSrc
->backgroundPixel
) );
1040 XPutImage( gdi_display
, pixmap
, gc
, imageDst
,
1041 0, 0, 0, 0, width
, height
);
1042 XDestroyImage( imageSrc
);
1043 XDestroyImage( imageDst
);
1050 /***********************************************************************
1053 * Retrieve an area from the destination DC, mapping all the
1054 * pixels to Windows colors.
1056 static int BITBLT_GetDstArea(X11DRV_PDEVICE
*physDev
, Pixmap pixmap
, GC gc
, RECT
*visRectDst
)
1059 INT width
= visRectDst
->right
- visRectDst
->left
;
1060 INT height
= visRectDst
->bottom
- visRectDst
->top
;
1062 if (!X11DRV_PALETTE_XPixelToPalette
|| (physDev
->depth
== 1) ||
1063 (X11DRV_PALETTE_PaletteFlags
& X11DRV_PALETTE_VIRTUAL
) )
1065 XCopyArea( gdi_display
, physDev
->drawable
, pixmap
, gc
,
1066 physDev
->org
.x
+ visRectDst
->left
, physDev
->org
.y
+ visRectDst
->top
,
1067 width
, height
, 0, 0 );
1075 if (GetObjectType( physDev
->hdc
) == OBJ_MEMDC
)
1076 image
= XGetImage( gdi_display
, physDev
->drawable
,
1077 physDev
->org
.x
+ visRectDst
->left
,
1078 physDev
->org
.y
+ visRectDst
->top
,
1079 width
, height
, AllPlanes
, ZPixmap
);
1082 /* Make sure we don't get a BadMatch error */
1083 XCopyArea( gdi_display
, physDev
->drawable
, pixmap
, gc
,
1084 physDev
->org
.x
+ visRectDst
->left
,
1085 physDev
->org
.y
+ visRectDst
->top
,
1086 width
, height
, 0, 0);
1088 image
= XGetImage( gdi_display
, pixmap
, 0, 0, width
, height
,
1089 AllPlanes
, ZPixmap
);
1091 for (y
= 0; y
< height
; y
++)
1092 for (x
= 0; x
< width
; x
++)
1093 XPutPixel( image
, x
, y
,
1094 X11DRV_PALETTE_XPixelToPalette
[XGetPixel( image
, x
, y
)]);
1095 XPutImage( gdi_display
, pixmap
, gc
, image
, 0, 0, 0, 0, width
, height
);
1096 XDestroyImage( image
);
1102 /***********************************************************************
1105 * Put an area back into the destination DC, mapping the pixel
1106 * colors to X pixels.
1108 static int BITBLT_PutDstArea(X11DRV_PDEVICE
*physDev
, Pixmap pixmap
, RECT
*visRectDst
)
1111 INT width
= visRectDst
->right
- visRectDst
->left
;
1112 INT height
= visRectDst
->bottom
- visRectDst
->top
;
1114 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1116 if (!X11DRV_PALETTE_PaletteToXPixel
|| (physDev
->depth
== 1) ||
1117 (X11DRV_PALETTE_PaletteFlags
& X11DRV_PALETTE_VIRTUAL
) )
1119 XCopyArea( gdi_display
, pixmap
, physDev
->drawable
, physDev
->gc
, 0, 0, width
, height
,
1120 physDev
->org
.x
+ visRectDst
->left
,
1121 physDev
->org
.y
+ visRectDst
->top
);
1127 XImage
*image
= XGetImage( gdi_display
, pixmap
, 0, 0, width
, height
,
1128 AllPlanes
, ZPixmap
);
1129 for (y
= 0; y
< height
; y
++)
1130 for (x
= 0; x
< width
; x
++)
1132 XPutPixel( image
, x
, y
,
1133 X11DRV_PALETTE_PaletteToXPixel
[XGetPixel( image
, x
, y
)]);
1135 XPutImage( gdi_display
, physDev
->drawable
, physDev
->gc
, image
, 0, 0,
1136 physDev
->org
.x
+ visRectDst
->left
,
1137 physDev
->org
.y
+ visRectDst
->top
, width
, height
);
1138 XDestroyImage( image
);
1144 /***********************************************************************
1145 * BITBLT_GetVisRectangles
1147 * Get the source and destination visible rectangles for StretchBlt().
1148 * Return FALSE if one of the rectangles is empty.
1150 static BOOL
BITBLT_GetVisRectangles( X11DRV_PDEVICE
*physDevDst
, INT xDst
, INT yDst
,
1151 INT widthDst
, INT heightDst
,
1152 X11DRV_PDEVICE
*physDevSrc
, INT xSrc
, INT ySrc
,
1153 INT widthSrc
, INT heightSrc
,
1154 RECT
*visRectSrc
, RECT
*visRectDst
)
1156 RECT rect
, clipRect
;
1158 /* Get the destination visible rectangle */
1162 rect
.right
= xDst
+ widthDst
;
1163 rect
.bottom
= yDst
+ heightDst
;
1164 if (widthDst
< 0) SWAP_INT32( &rect
.left
, &rect
.right
);
1165 if (heightDst
< 0) SWAP_INT32( &rect
.top
, &rect
.bottom
);
1166 GetRgnBox( physDevDst
->region
, &clipRect
);
1167 if (!IntersectRect( visRectDst
, &rect
, &clipRect
)) return FALSE
;
1169 /* Get the source visible rectangle */
1171 if (!physDevSrc
) return TRUE
;
1174 rect
.right
= xSrc
+ widthSrc
;
1175 rect
.bottom
= ySrc
+ heightSrc
;
1176 if (widthSrc
< 0) SWAP_INT32( &rect
.left
, &rect
.right
);
1177 if (heightSrc
< 0) SWAP_INT32( &rect
.top
, &rect
.bottom
);
1178 /* Apparently the clipping and visible regions are only for output,
1179 so just check against dc extent here to avoid BadMatch errors */
1180 if (physDevSrc
->bitmap
)
1183 GetObjectW( physDevSrc
->bitmap
->hbitmap
, sizeof(bm
), &bm
);
1184 SetRect( &clipRect
, 0, 0, bm
.bmWidth
, bm
.bmHeight
);
1186 else SetRect( &clipRect
, 0, 0, screen_width
, screen_height
);
1187 if (!IntersectRect( visRectSrc
, &rect
, &clipRect
))
1190 /* Intersect the rectangles */
1192 if ((widthSrc
== widthDst
) && (heightSrc
== heightDst
)) /* no stretching */
1194 visRectSrc
->left
+= xDst
- xSrc
;
1195 visRectSrc
->right
+= xDst
- xSrc
;
1196 visRectSrc
->top
+= yDst
- ySrc
;
1197 visRectSrc
->bottom
+= yDst
- ySrc
;
1198 if (!IntersectRect( &rect
, visRectSrc
, visRectDst
)) return FALSE
;
1199 *visRectSrc
= *visRectDst
= rect
;
1200 visRectSrc
->left
+= xSrc
- xDst
;
1201 visRectSrc
->right
+= xSrc
- xDst
;
1202 visRectSrc
->top
+= ySrc
- yDst
;
1203 visRectSrc
->bottom
+= ySrc
- yDst
;
1205 else /* stretching */
1207 /* Map source rectangle into destination coordinates */
1208 rect
.left
= xDst
+ (visRectSrc
->left
- xSrc
)*widthDst
/widthSrc
;
1209 rect
.top
= yDst
+ (visRectSrc
->top
- ySrc
)*heightDst
/heightSrc
;
1210 rect
.right
= xDst
+ ((visRectSrc
->right
- xSrc
)*widthDst
)/widthSrc
;
1211 rect
.bottom
= yDst
+ ((visRectSrc
->bottom
- ySrc
)*heightDst
)/heightSrc
;
1212 if (rect
.left
> rect
.right
) SWAP_INT32( &rect
.left
, &rect
.right
);
1213 if (rect
.top
> rect
.bottom
) SWAP_INT32( &rect
.top
, &rect
.bottom
);
1215 /* Avoid rounding errors */
1220 if (!IntersectRect( visRectDst
, &rect
, visRectDst
)) return FALSE
;
1222 /* Map destination rectangle back to source coordinates */
1224 rect
.left
= xSrc
+ (visRectDst
->left
- xDst
)*widthSrc
/widthDst
;
1225 rect
.top
= ySrc
+ (visRectDst
->top
- yDst
)*heightSrc
/heightDst
;
1226 rect
.right
= xSrc
+ ((visRectDst
->right
- xDst
)*widthSrc
)/widthDst
;
1227 rect
.bottom
= ySrc
+ ((visRectDst
->bottom
- yDst
)*heightSrc
)/heightDst
;
1228 if (rect
.left
> rect
.right
) SWAP_INT32( &rect
.left
, &rect
.right
);
1229 if (rect
.top
> rect
.bottom
) SWAP_INT32( &rect
.top
, &rect
.bottom
);
1231 /* Avoid rounding errors */
1236 if (!IntersectRect( visRectSrc
, &rect
, visRectSrc
)) return FALSE
;
1242 /***********************************************************************
1243 * BITBLT_InternalStretchBlt
1245 * Implementation of PatBlt(), BitBlt() and StretchBlt().
1247 static BOOL
BITBLT_InternalStretchBlt( X11DRV_PDEVICE
*physDevDst
, INT xDst
, INT yDst
,
1248 INT widthDst
, INT heightDst
,
1249 X11DRV_PDEVICE
*physDevSrc
, INT xSrc
, INT ySrc
,
1250 INT widthSrc
, INT heightSrc
,
1253 BOOL usePat
, useSrc
, useDst
, destUsed
, fStretch
, fNullBrush
;
1254 RECT visRectDst
, visRectSrc
;
1257 Pixmap pixmaps
[3] = { 0, 0, 0 }; /* pixmaps for DST, SRC, TMP */
1261 /* compensate for off-by-one shifting for negative widths and heights */
1271 usePat
= (((rop
>> 4) & 0x0f0000) != (rop
& 0x0f0000));
1272 useSrc
= (((rop
>> 2) & 0x330000) != (rop
& 0x330000));
1273 useDst
= (((rop
>> 1) & 0x550000) != (rop
& 0x550000));
1274 if (!physDevSrc
&& useSrc
) return FALSE
;
1276 /* Map the coordinates to device coords */
1280 pts
[1].x
= xDst
+ widthDst
;
1281 pts
[1].y
= yDst
+ heightDst
;
1282 LPtoDP(physDevDst
->hdc
, pts
, 2);
1285 widthDst
= pts
[1].x
- pts
[0].x
;
1286 heightDst
= pts
[1].y
- pts
[0].y
;
1288 TRACE(" rectdst=%d,%d-%d,%d orgdst=%ld,%ld\n",
1289 xDst
, yDst
, widthDst
, heightDst
,
1290 physDevDst
->org
.x
, physDevDst
->org
.y
);
1296 pts
[1].x
= xSrc
+ widthSrc
;
1297 pts
[1].y
= ySrc
+ heightSrc
;
1298 LPtoDP(physDevSrc
->hdc
, pts
, 2);
1301 widthSrc
= pts
[1].x
- pts
[0].x
;
1302 heightSrc
= pts
[1].y
- pts
[0].y
;
1304 fStretch
= (widthSrc
!= widthDst
) || (heightSrc
!= heightDst
);
1305 TRACE(" rectsrc=%d,%d-%d,%d orgsrc=%ld,%ld\n",
1306 xSrc
, ySrc
, widthSrc
, heightSrc
,
1307 physDevSrc
->org
.x
, physDevSrc
->org
.y
);
1308 if (!BITBLT_GetVisRectangles( physDevDst
, xDst
, yDst
, widthDst
, heightDst
,
1309 physDevSrc
, xSrc
, ySrc
, widthSrc
, heightSrc
,
1310 &visRectSrc
, &visRectDst
))
1312 TRACE(" vissrc=%ld,%ld-%ld,%ld visdst=%ld,%ld-%ld,%ld\n",
1313 visRectSrc
.left
, visRectSrc
.top
,
1314 visRectSrc
.right
, visRectSrc
.bottom
,
1315 visRectDst
.left
, visRectDst
.top
,
1316 visRectDst
.right
, visRectDst
.bottom
);
1321 if (!BITBLT_GetVisRectangles( physDevDst
, xDst
, yDst
, widthDst
, heightDst
,
1322 NULL
, 0, 0, 0, 0, NULL
, &visRectDst
))
1324 TRACE(" vissrc=none visdst=%ld,%ld-%ld,%ld\n",
1325 visRectDst
.left
, visRectDst
.top
,
1326 visRectDst
.right
, visRectDst
.bottom
);
1329 width
= visRectDst
.right
- visRectDst
.left
;
1330 height
= visRectDst
.bottom
- visRectDst
.top
;
1332 if (!fStretch
) switch(rop
) /* A few optimisations */
1334 case BLACKNESS
: /* 0x00 */
1336 if ((physDevDst
->depth
== 1) || !X11DRV_PALETTE_PaletteToXPixel
)
1337 XSetFunction( gdi_display
, physDevDst
->gc
, GXclear
);
1340 XSetFunction( gdi_display
, physDevDst
->gc
, GXcopy
);
1341 XSetForeground( gdi_display
, physDevDst
->gc
, X11DRV_PALETTE_PaletteToXPixel
[0] );
1342 XSetFillStyle( gdi_display
, physDevDst
->gc
, FillSolid
);
1344 XFillRectangle( gdi_display
, physDevDst
->drawable
, physDevDst
->gc
,
1345 physDevDst
->org
.x
+ visRectDst
.left
,
1346 physDevDst
->org
.y
+ visRectDst
.top
,
1348 wine_tsx11_unlock();
1351 case DSTINVERT
: /* 0x55 */
1352 if ((physDevDst
->depth
== 1) || !X11DRV_PALETTE_PaletteToXPixel
||
1353 !perfect_graphics())
1356 XSetFunction( gdi_display
, physDevDst
->gc
, GXinvert
);
1358 if( X11DRV_PALETTE_PaletteFlags
& (X11DRV_PALETTE_PRIVATE
| X11DRV_PALETTE_VIRTUAL
) )
1359 XSetFunction( gdi_display
, physDevDst
->gc
, GXinvert
);
1362 /* Xor is much better when we do not have full colormap. */
1363 /* Using white^black ensures that we invert at least black */
1365 Pixel xor_pix
= (WhitePixel( gdi_display
, DefaultScreen(gdi_display
) ) ^
1366 BlackPixel( gdi_display
, DefaultScreen(gdi_display
) ));
1367 XSetFunction( gdi_display
, physDevDst
->gc
, GXxor
);
1368 XSetForeground( gdi_display
, physDevDst
->gc
, xor_pix
);
1369 XSetFillStyle( gdi_display
, physDevDst
->gc
, FillSolid
);
1371 XFillRectangle( gdi_display
, physDevDst
->drawable
, physDevDst
->gc
,
1372 physDevDst
->org
.x
+ visRectDst
.left
,
1373 physDevDst
->org
.y
+ visRectDst
.top
,
1375 wine_tsx11_unlock();
1380 case PATINVERT
: /* 0x5a */
1381 if (perfect_graphics()) break;
1382 if (X11DRV_SetupGCForBrush( physDevDst
))
1385 XSetFunction( gdi_display
, physDevDst
->gc
, GXxor
);
1386 XFillRectangle( gdi_display
, physDevDst
->drawable
, physDevDst
->gc
,
1387 physDevDst
->org
.x
+ visRectDst
.left
,
1388 physDevDst
->org
.y
+ visRectDst
.top
,
1390 wine_tsx11_unlock();
1395 if (perfect_graphics()) break;
1396 if (X11DRV_SetupGCForBrush( physDevDst
))
1399 XSetFunction( gdi_display
, physDevDst
->gc
, GXequiv
);
1400 XFillRectangle( gdi_display
, physDevDst
->drawable
, physDevDst
->gc
,
1401 physDevDst
->org
.x
+ visRectDst
.left
,
1402 physDevDst
->org
.y
+ visRectDst
.top
,
1404 wine_tsx11_unlock();
1408 case SRCCOPY
: /* 0xcc */
1409 if (physDevSrc
->depth
== physDevDst
->depth
)
1412 XSetFunction( gdi_display
, physDevDst
->gc
, GXcopy
);
1413 XCopyArea( gdi_display
, physDevSrc
->drawable
,
1414 physDevDst
->drawable
, physDevDst
->gc
,
1415 physDevSrc
->org
.x
+ visRectSrc
.left
,
1416 physDevSrc
->org
.y
+ visRectSrc
.top
,
1418 physDevDst
->org
.x
+ visRectDst
.left
,
1419 physDevDst
->org
.y
+ visRectDst
.top
);
1420 physDevDst
->exposures
++;
1421 wine_tsx11_unlock();
1425 if (physDevSrc
->depth
== 1)
1428 get_colors(physDevDst
, physDevSrc
, &fg
, &bg
);
1431 XSetBackground( gdi_display
, physDevDst
->gc
, fg
);
1432 XSetForeground( gdi_display
, physDevDst
->gc
, bg
);
1433 XSetFunction( gdi_display
, physDevDst
->gc
, GXcopy
);
1434 XCopyPlane( gdi_display
, physDevSrc
->drawable
,
1435 physDevDst
->drawable
, physDevDst
->gc
,
1436 physDevSrc
->org
.x
+ visRectSrc
.left
,
1437 physDevSrc
->org
.y
+ visRectSrc
.top
,
1439 physDevDst
->org
.x
+ visRectDst
.left
,
1440 physDevDst
->org
.y
+ visRectDst
.top
, 1 );
1441 physDevDst
->exposures
++;
1442 wine_tsx11_unlock();
1447 case PATCOPY
: /* 0xf0 */
1448 if (!X11DRV_SetupGCForBrush( physDevDst
)) return TRUE
;
1450 XSetFunction( gdi_display
, physDevDst
->gc
, GXcopy
);
1451 XFillRectangle( gdi_display
, physDevDst
->drawable
, physDevDst
->gc
,
1452 physDevDst
->org
.x
+ visRectDst
.left
,
1453 physDevDst
->org
.y
+ visRectDst
.top
,
1455 wine_tsx11_unlock();
1458 case WHITENESS
: /* 0xff */
1460 if ((physDevDst
->depth
== 1) || !X11DRV_PALETTE_PaletteToXPixel
)
1461 XSetFunction( gdi_display
, physDevDst
->gc
, GXset
);
1464 XSetFunction( gdi_display
, physDevDst
->gc
, GXcopy
);
1465 XSetForeground( gdi_display
, physDevDst
->gc
,
1466 WhitePixel( gdi_display
, DefaultScreen(gdi_display
) ));
1467 XSetFillStyle( gdi_display
, physDevDst
->gc
, FillSolid
);
1469 XFillRectangle( gdi_display
, physDevDst
->drawable
, physDevDst
->gc
,
1470 physDevDst
->org
.x
+ visRectDst
.left
,
1471 physDevDst
->org
.y
+ visRectDst
.top
,
1473 wine_tsx11_unlock();
1479 tmpGC
= XCreateGC( gdi_display
, physDevDst
->drawable
, 0, NULL
);
1480 XSetSubwindowMode( gdi_display
, tmpGC
, IncludeInferiors
);
1481 XSetGraphicsExposures( gdi_display
, tmpGC
, False
);
1482 pixmaps
[DST
] = XCreatePixmap( gdi_display
, root_window
, width
, height
,
1483 physDevDst
->depth
);
1486 pixmaps
[SRC
] = XCreatePixmap( gdi_display
, root_window
, width
, height
,
1487 physDevDst
->depth
);
1489 BITBLT_GetSrcAreaStretch( physDevSrc
, physDevDst
, pixmaps
[SRC
], tmpGC
,
1490 xSrc
, ySrc
, widthSrc
, heightSrc
,
1491 xDst
, yDst
, widthDst
, heightDst
,
1492 &visRectSrc
, &visRectDst
);
1494 BITBLT_GetSrcArea( physDevSrc
, physDevDst
, pixmaps
[SRC
], tmpGC
,
1495 xSrc
, ySrc
, &visRectSrc
);
1498 if (useDst
) BITBLT_GetDstArea( physDevDst
, pixmaps
[DST
], tmpGC
, &visRectDst
);
1499 if (usePat
) fNullBrush
= !X11DRV_SetupGCForPatBlt( physDevDst
, tmpGC
, TRUE
);
1500 else fNullBrush
= FALSE
;
1503 for (opcode
= BITBLT_Opcodes
[(rop
>> 16) & 0xff]; *opcode
; opcode
++)
1505 if (OP_DST(*opcode
) == DST
) destUsed
= TRUE
;
1506 XSetFunction( gdi_display
, tmpGC
, OP_ROP(*opcode
) );
1507 switch(OP_SRCDST(*opcode
))
1509 case OP_ARGS(DST
,TMP
):
1510 case OP_ARGS(SRC
,TMP
):
1512 pixmaps
[TMP
] = XCreatePixmap( gdi_display
, root_window
,
1513 width
, height
, physDevDst
->depth
);
1515 case OP_ARGS(DST
,SRC
):
1516 case OP_ARGS(SRC
,DST
):
1517 case OP_ARGS(TMP
,SRC
):
1518 case OP_ARGS(TMP
,DST
):
1520 XCopyArea( gdi_display
, pixmaps
[OP_SRC(*opcode
)],
1521 pixmaps
[OP_DST(*opcode
)], tmpGC
,
1522 0, 0, width
, height
, 0, 0 );
1525 case OP_ARGS(PAT
,TMP
):
1526 if (!pixmaps
[TMP
] && !fNullBrush
)
1527 pixmaps
[TMP
] = XCreatePixmap( gdi_display
, root_window
,
1528 width
, height
, physDevDst
->depth
);
1530 case OP_ARGS(PAT
,DST
):
1531 case OP_ARGS(PAT
,SRC
):
1533 XFillRectangle( gdi_display
, pixmaps
[OP_DST(*opcode
)],
1534 tmpGC
, 0, 0, width
, height
);
1538 XSetFunction( gdi_display
, physDevDst
->gc
, GXcopy
);
1539 physDevDst
->exposures
+= BITBLT_PutDstArea( physDevDst
, pixmaps
[destUsed
? DST
: SRC
],
1541 XFreePixmap( gdi_display
, pixmaps
[DST
] );
1542 if (pixmaps
[SRC
]) XFreePixmap( gdi_display
, pixmaps
[SRC
] );
1543 if (pixmaps
[TMP
]) XFreePixmap( gdi_display
, pixmaps
[TMP
] );
1544 XFreeGC( gdi_display
, tmpGC
);
1545 wine_tsx11_unlock();
1550 /***********************************************************************
1553 BOOL
X11DRV_PatBlt( X11DRV_PDEVICE
*physDev
, INT left
, INT top
, INT width
, INT height
, DWORD rop
)
1557 X11DRV_LockDIBSection( physDev
, DIB_Status_GdiMod
, FALSE
);
1558 result
= BITBLT_InternalStretchBlt( physDev
, left
, top
, width
, height
, NULL
, 0, 0, 0, 0, rop
);
1559 X11DRV_UnlockDIBSection( physDev
, TRUE
);
1564 /***********************************************************************
1567 BOOL
X11DRV_BitBlt( X11DRV_PDEVICE
*physDevDst
, INT xDst
, INT yDst
,
1568 INT width
, INT height
, X11DRV_PDEVICE
*physDevSrc
,
1569 INT xSrc
, INT ySrc
, DWORD rop
)
1571 BOOL result
= FALSE
;
1573 RECT visRectDst
, visRectSrc
;
1575 if (((rop
>> 16) & 0x55) == ((rop
>> 17) & 0x55)) {
1576 /* FIXME: seems the ROP doesn't include destination;
1577 * now if the destination area include the entire dcDst,
1578 * we can pass TRUE instead of FALSE to CoerceDIBSection(dcDst...),
1579 * which may avoid a copy in some situations */
1582 sDst
= X11DRV_LockDIBSection( physDevDst
, DIB_Status_None
, FALSE
);
1583 if (physDevDst
!= physDevSrc
)
1584 sSrc
= X11DRV_LockDIBSection( physDevSrc
, DIB_Status_None
, FALSE
);
1588 if ((sSrc
== DIB_Status_AppMod
) && (rop
== SRCCOPY
) &&
1589 (physDevSrc
->depth
== physDevDst
->depth
))
1592 /* do everything ourselves; map coordinates */
1596 pts
[1].x
= xSrc
+ width
;
1597 pts
[1].y
= ySrc
+ height
;
1599 LPtoDP(physDevSrc
->hdc
, pts
, 2);
1600 width
= pts
[1].x
- pts
[0].x
;
1601 height
= pts
[1].y
- pts
[0].y
;
1607 LPtoDP(physDevDst
->hdc
, pts
, 1);
1612 /* Perform basic clipping */
1613 if (!BITBLT_GetVisRectangles( physDevDst
, xDst
, yDst
, width
, height
,
1614 physDevSrc
, xSrc
, ySrc
, width
, height
,
1615 &visRectSrc
, &visRectDst
))
1618 xSrc
= visRectSrc
.left
;
1619 ySrc
= visRectSrc
.top
;
1620 xDst
= visRectDst
.left
;
1621 yDst
= visRectDst
.top
;
1622 width
= visRectDst
.right
- visRectDst
.left
;
1623 height
= visRectDst
.bottom
- visRectDst
.top
;
1625 if (sDst
== DIB_Status_AppMod
) {
1626 FIXME("potential optimization - client-side DIB copy\n");
1628 X11DRV_CoerceDIBSection( physDevDst
, DIB_Status_GdiMod
, FALSE
);
1630 X11DRV_DIB_CopyDIBSection( physDevSrc
, physDevDst
, xSrc
, ySrc
, xDst
, yDst
, width
, height
);
1635 X11DRV_CoerceDIBSection( physDevDst
, DIB_Status_GdiMod
, FALSE
);
1636 if (physDevDst
!= physDevSrc
)
1637 X11DRV_CoerceDIBSection( physDevSrc
, DIB_Status_GdiMod
, FALSE
);
1639 result
= BITBLT_InternalStretchBlt( physDevDst
, xDst
, yDst
, width
, height
,
1640 physDevSrc
, xSrc
, ySrc
, width
, height
, rop
);
1643 if (physDevDst
!= physDevSrc
)
1644 X11DRV_UnlockDIBSection( physDevSrc
, FALSE
);
1645 X11DRV_UnlockDIBSection( physDevDst
, TRUE
);
1651 /***********************************************************************
1654 BOOL
X11DRV_StretchBlt( X11DRV_PDEVICE
*physDevDst
, INT xDst
, INT yDst
,
1655 INT widthDst
, INT heightDst
,
1656 X11DRV_PDEVICE
*physDevSrc
, INT xSrc
, INT ySrc
,
1657 INT widthSrc
, INT heightSrc
, DWORD rop
)
1661 X11DRV_LockDIBSection( physDevDst
, DIB_Status_GdiMod
, FALSE
);
1662 if (physDevDst
!= physDevSrc
)
1663 X11DRV_LockDIBSection( physDevSrc
, DIB_Status_GdiMod
, FALSE
);
1665 result
= BITBLT_InternalStretchBlt( physDevDst
, xDst
, yDst
, widthDst
, heightDst
,
1666 physDevSrc
, xSrc
, ySrc
, widthSrc
, heightSrc
, rop
);
1668 if (physDevDst
!= physDevSrc
)
1669 X11DRV_UnlockDIBSection( physDevSrc
, FALSE
);
1670 X11DRV_UnlockDIBSection( physDevDst
, TRUE
);