2 * GDI bit-blit operations
4 * Copyright 1993, 1994, 2011 Alexandre Julliard
5 * Copyright 2006 Damjan Jovanovic
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
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 static const unsigned char BITBLT_Opcodes
[256][MAX_OP_LEN
] =
57 { OP(PAT
,DST
,GXclear
) }, /* 0x00 0 */
58 { OP(PAT
,SRC
,GXor
), OP(SRC
,DST
,GXnor
) }, /* 0x01 ~(D|(P|S)) */
59 { OP(PAT
,SRC
,GXnor
), OP(SRC
,DST
,GXand
) }, /* 0x02 D&~(P|S) */
60 { OP(PAT
,SRC
,GXnor
) }, /* 0x03 ~(P|S) */
61 { OP(PAT
,DST
,GXnor
), OP(SRC
,DST
,GXand
) }, /* 0x04 S&~(D|P) */
62 { OP(PAT
,DST
,GXnor
) }, /* 0x05 ~(D|P) */
63 { OP(SRC
,DST
,GXequiv
), OP(PAT
,DST
,GXnor
), }, /* 0x06 ~(P|~(D^S)) */
64 { OP(SRC
,DST
,GXand
), OP(PAT
,DST
,GXnor
) }, /* 0x07 ~(P|(D&S)) */
65 { OP(PAT
,DST
,GXandInverted
), OP(SRC
,DST
,GXand
) },/* 0x08 S&D&~P */
66 { OP(SRC
,DST
,GXxor
), OP(PAT
,DST
,GXnor
) }, /* 0x09 ~(P|(D^S)) */
67 { OP(PAT
,DST
,GXandInverted
) }, /* 0x0a D&~P */
68 { OP(SRC
,DST
,GXandReverse
), OP(PAT
,DST
,GXnor
) }, /* 0x0b ~(P|(S&~D)) */
69 { OP(PAT
,SRC
,GXandInverted
) }, /* 0x0c S&~P */
70 { OP(SRC
,DST
,GXandInverted
), OP(PAT
,DST
,GXnor
) },/* 0x0d ~(P|(D&~S)) */
71 { OP(SRC
,DST
,GXnor
), OP(PAT
,DST
,GXnor
) }, /* 0x0e ~(P|~(D|S)) */
72 { OP(PAT
,DST
,GXcopyInverted
) }, /* 0x0f ~P */
73 { OP(SRC
,DST
,GXnor
), OP(PAT
,DST
,GXand
) }, /* 0x10 P&~(S|D) */
74 { OP(SRC
,DST
,GXnor
) }, /* 0x11 ~(D|S) */
75 { OP(PAT
,DST
,GXequiv
), OP(SRC
,DST
,GXnor
) }, /* 0x12 ~(S|~(D^P)) */
76 { OP(PAT
,DST
,GXand
), OP(SRC
,DST
,GXnor
) }, /* 0x13 ~(S|(D&P)) */
77 { OP(PAT
,SRC
,GXequiv
), OP(SRC
,DST
,GXnor
) }, /* 0x14 ~(D|~(P^S)) */
78 { OP(PAT
,SRC
,GXand
), OP(SRC
,DST
,GXnor
) }, /* 0x15 ~(D|(P&S)) */
79 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXnand
),
80 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXxor
),
81 OP(PAT
,DST
,GXxor
) }, /* 0x16 P^S^(D&~(P&S) */
82 { OP(SRC
,TMP
,GXcopy
), OP(SRC
,DST
,GXxor
),
83 OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXand
),
84 OP(TMP
,DST
,GXequiv
) }, /* 0x17 ~S^((S^P)&(S^D))*/
85 { OP(PAT
,SRC
,GXxor
), OP(PAT
,DST
,GXxor
),
86 OP(SRC
,DST
,GXand
) }, /* 0x18 (S^P)&(D^P) */
87 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXnand
),
88 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXequiv
) }, /* 0x19 ~S^(D&~(P&S)) */
89 { OP(PAT
,SRC
,GXand
), OP(SRC
,DST
,GXor
),
90 OP(PAT
,DST
,GXxor
) }, /* 0x1a P^(D|(S&P)) */
91 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXxor
),
92 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXequiv
) }, /* 0x1b ~S^(D&(P^S)) */
93 { OP(PAT
,DST
,GXand
), OP(SRC
,DST
,GXor
),
94 OP(PAT
,DST
,GXxor
) }, /* 0x1c P^(S|(D&P)) */
95 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXxor
),
96 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXequiv
) }, /* 0x1d ~D^(S&(D^P)) */
97 { OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXxor
) }, /* 0x1e P^(D|S) */
98 { OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXnand
) }, /* 0x1f ~(P&(D|S)) */
99 { OP(PAT
,SRC
,GXandReverse
), OP(SRC
,DST
,GXand
) }, /* 0x20 D&(P&~S) */
100 { OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXnor
) }, /* 0x21 ~(S|(D^P)) */
101 { OP(SRC
,DST
,GXandInverted
) }, /* 0x22 ~S&D */
102 { OP(PAT
,DST
,GXandReverse
), OP(SRC
,DST
,GXnor
) }, /* 0x23 ~(S|(P&~D)) */
103 { OP(SRC
,DST
,GXxor
), OP(PAT
,SRC
,GXxor
),
104 OP(SRC
,DST
,GXand
) }, /* 0x24 (S^P)&(S^D) */
105 { OP(PAT
,SRC
,GXnand
), OP(SRC
,DST
,GXand
),
106 OP(PAT
,DST
,GXequiv
) }, /* 0x25 ~P^(D&~(S&P)) */
107 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXand
),
108 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXxor
) }, /* 0x26 S^(D|(S&P)) */
109 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXequiv
),
110 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXxor
) }, /* 0x27 S^(D|~(P^S)) */
111 { OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXand
) }, /* 0x28 D&(P^S) */
112 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXand
),
113 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXxor
),
114 OP(PAT
,DST
,GXequiv
) }, /* 0x29 ~P^S^(D|(P&S)) */
115 { OP(PAT
,SRC
,GXnand
), OP(SRC
,DST
,GXand
) }, /* 0x2a D&~(P&S) */
116 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXxor
),
117 OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXand
),
118 OP(TMP
,DST
,GXequiv
) }, /* 0x2b ~S^((P^S)&(P^D))*/
119 { OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXand
),
120 OP(SRC
,DST
,GXxor
) }, /* 0x2c S^(P&(S|D)) */
121 { OP(SRC
,DST
,GXorReverse
), OP(PAT
,DST
,GXxor
) }, /* 0x2d P^(S|~D) */
122 { OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXor
),
123 OP(PAT
,DST
,GXxor
) }, /* 0x2e P^(S|(D^P)) */
124 { OP(SRC
,DST
,GXorReverse
), OP(PAT
,DST
,GXnand
) }, /* 0x2f ~(P&(S|~D)) */
125 { OP(PAT
,SRC
,GXandReverse
) }, /* 0x30 P&~S */
126 { OP(PAT
,DST
,GXandInverted
), OP(SRC
,DST
,GXnor
) },/* 0x31 ~(S|(D&~P)) */
127 { OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXor
),
128 OP(SRC
,DST
,GXxor
) }, /* 0x32 S^(D|P|S) */
129 { OP(SRC
,DST
,GXcopyInverted
) }, /* 0x33 ~S */
130 { OP(SRC
,DST
,GXand
), OP(PAT
,DST
,GXor
),
131 OP(SRC
,DST
,GXxor
) }, /* 0x34 S^(P|(D&S)) */
132 { OP(SRC
,DST
,GXequiv
), OP(PAT
,DST
,GXor
),
133 OP(SRC
,DST
,GXxor
) }, /* 0x35 S^(P|~(D^S)) */
134 { OP(PAT
,DST
,GXor
), OP(SRC
,DST
,GXxor
) }, /* 0x36 S^(D|P) */
135 { OP(PAT
,DST
,GXor
), OP(SRC
,DST
,GXnand
) }, /* 0x37 ~(S&(D|P)) */
136 { OP(PAT
,DST
,GXor
), OP(SRC
,DST
,GXand
),
137 OP(PAT
,DST
,GXxor
) }, /* 0x38 P^(S&(D|P)) */
138 { OP(PAT
,DST
,GXorReverse
), OP(SRC
,DST
,GXxor
) }, /* 0x39 S^(P|~D) */
139 { OP(SRC
,DST
,GXxor
), OP(PAT
,DST
,GXor
),
140 OP(SRC
,DST
,GXxor
) }, /* 0x3a S^(P|(D^S)) */
141 { OP(PAT
,DST
,GXorReverse
), OP(SRC
,DST
,GXnand
) }, /* 0x3b ~(S&(P|~D)) */
142 { OP(PAT
,SRC
,GXxor
) }, /* 0x3c P^S */
143 { OP(SRC
,DST
,GXnor
), OP(PAT
,DST
,GXor
),
144 OP(SRC
,DST
,GXxor
) }, /* 0x3d S^(P|~(D|S)) */
145 { OP(SRC
,DST
,GXandInverted
), OP(PAT
,DST
,GXor
),
146 OP(SRC
,DST
,GXxor
) }, /* 0x3e S^(P|(D&~S)) */
147 { OP(PAT
,SRC
,GXnand
) }, /* 0x3f ~(P&S) */
148 { OP(SRC
,DST
,GXandReverse
), OP(PAT
,DST
,GXand
) }, /* 0x40 P&S&~D */
149 { OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXnor
) }, /* 0x41 ~(D|(P^S)) */
150 { OP(DST
,SRC
,GXxor
), OP(PAT
,DST
,GXxor
),
151 OP(SRC
,DST
,GXand
) }, /* 0x42 (S^D)&(P^D) */
152 { OP(SRC
,DST
,GXnand
), OP(PAT
,DST
,GXand
),
153 OP(SRC
,DST
,GXequiv
) }, /* 0x43 ~S^(P&~(D&S)) */
154 { OP(SRC
,DST
,GXandReverse
) }, /* 0x44 S&~D */
155 { OP(PAT
,SRC
,GXandReverse
), OP(SRC
,DST
,GXnor
) }, /* 0x45 ~(D|(P&~S)) */
156 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXand
),
157 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXxor
) }, /* 0x46 D^(S|(P&D)) */
158 { OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXand
),
159 OP(PAT
,DST
,GXequiv
) }, /* 0x47 ~P^(S&(D^P)) */
160 { OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXand
) }, /* 0x48 S&(P^D) */
161 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXand
),
162 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXxor
),
163 OP(PAT
,DST
,GXequiv
) }, /* 0x49 ~P^D^(S|(P&D)) */
164 { OP(DST
,SRC
,GXor
), OP(PAT
,SRC
,GXand
),
165 OP(SRC
,DST
,GXxor
) }, /* 0x4a D^(P&(S|D)) */
166 { OP(SRC
,DST
,GXorInverted
), OP(PAT
,DST
,GXxor
) }, /* 0x4b P^(D|~S) */
167 { OP(PAT
,DST
,GXnand
), OP(SRC
,DST
,GXand
) }, /* 0x4c S&~(D&P) */
168 { OP(SRC
,TMP
,GXcopy
), OP(SRC
,DST
,GXxor
),
169 OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXor
),
170 OP(TMP
,DST
,GXequiv
) }, /* 0x4d ~S^((S^P)|(S^D))*/
171 { OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXor
),
172 OP(PAT
,DST
,GXxor
) }, /* 0x4e P^(D|(S^P)) */
173 { OP(SRC
,DST
,GXorInverted
), OP(PAT
,DST
,GXnand
) },/* 0x4f ~(P&(D|~S)) */
174 { OP(PAT
,DST
,GXandReverse
) }, /* 0x50 P&~D */
175 { OP(PAT
,SRC
,GXandInverted
), OP(SRC
,DST
,GXnor
) },/* 0x51 ~(D|(S&~P)) */
176 { OP(DST
,SRC
,GXand
), OP(PAT
,SRC
,GXor
),
177 OP(SRC
,DST
,GXxor
) }, /* 0x52 D^(P|(S&D)) */
178 { OP(SRC
,DST
,GXxor
), OP(PAT
,DST
,GXand
),
179 OP(SRC
,DST
,GXequiv
) }, /* 0x53 ~S^(P&(D^S)) */
180 { OP(PAT
,SRC
,GXnor
), OP(SRC
,DST
,GXnor
) }, /* 0x54 ~(D|~(P|S)) */
181 { OP(PAT
,DST
,GXinvert
) }, /* 0x55 ~D */
182 { OP(PAT
,SRC
,GXor
), OP(SRC
,DST
,GXxor
) }, /* 0x56 D^(P|S) */
183 { OP(PAT
,SRC
,GXor
), OP(SRC
,DST
,GXnand
) }, /* 0x57 ~(D&(P|S)) */
184 { OP(PAT
,SRC
,GXor
), OP(SRC
,DST
,GXand
),
185 OP(PAT
,DST
,GXxor
) }, /* 0x58 P^(D&(P|S)) */
186 { OP(PAT
,SRC
,GXorReverse
), OP(SRC
,DST
,GXxor
) }, /* 0x59 D^(P|~S) */
187 { OP(PAT
,DST
,GXxor
) }, /* 0x5a D^P */
188 { OP(DST
,SRC
,GXnor
), OP(PAT
,SRC
,GXor
),
189 OP(SRC
,DST
,GXxor
) }, /* 0x5b D^(P|~(S|D)) */
190 { OP(DST
,SRC
,GXxor
), OP(PAT
,SRC
,GXor
),
191 OP(SRC
,DST
,GXxor
) }, /* 0x5c D^(P|(S^D)) */
192 { OP(PAT
,SRC
,GXorReverse
), OP(SRC
,DST
,GXnand
) }, /* 0x5d ~(D&(P|~S)) */
193 { OP(DST
,SRC
,GXandInverted
), OP(PAT
,SRC
,GXor
),
194 OP(SRC
,DST
,GXxor
) }, /* 0x5e D^(P|(S&~D)) */
195 { OP(PAT
,DST
,GXnand
) }, /* 0x5f ~(D&P) */
196 { OP(SRC
,DST
,GXxor
), OP(PAT
,DST
,GXand
) }, /* 0x60 P&(D^S) */
197 { OP(DST
,TMP
,GXcopy
), OP(SRC
,DST
,GXand
),
198 OP(PAT
,DST
,GXor
), OP(SRC
,DST
,GXxor
),
199 OP(TMP
,DST
,GXequiv
) }, /* 0x61 ~D^S^(P|(D&S)) */
200 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXor
),
201 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXxor
) }, /* 0x62 D^(S&(P|D)) */
202 { OP(PAT
,DST
,GXorInverted
), OP(SRC
,DST
,GXxor
) }, /* 0x63 S^(D|~P) */
203 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXor
),
204 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXxor
) }, /* 0x64 S^(D&(P|S)) */
205 { OP(PAT
,SRC
,GXorInverted
), OP(SRC
,DST
,GXxor
) }, /* 0x65 D^(S|~P) */
206 { OP(SRC
,DST
,GXxor
) }, /* 0x66 S^D */
207 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXnor
),
208 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXxor
) }, /* 0x67 S^(D|~(S|P) */
209 { OP(DST
,TMP
,GXcopy
), OP(SRC
,DST
,GXnor
),
210 OP(PAT
,DST
,GXor
), OP(SRC
,DST
,GXxor
),
211 OP(TMP
,DST
,GXequiv
) }, /* 0x68 ~D^S^(P|~(D|S))*/
212 { OP(SRC
,DST
,GXxor
), OP(PAT
,DST
,GXequiv
) }, /* 0x69 ~P^(D^S) */
213 { OP(PAT
,SRC
,GXand
), OP(SRC
,DST
,GXxor
) }, /* 0x6a D^(P&S) */
214 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXor
),
215 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXxor
),
216 OP(PAT
,DST
,GXequiv
) }, /* 0x6b ~P^S^(D&(P|S)) */
217 { OP(PAT
,DST
,GXand
), OP(SRC
,DST
,GXxor
) }, /* 0x6c S^(D&P) */
218 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXor
),
219 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXxor
),
220 OP(PAT
,DST
,GXequiv
) }, /* 0x6d ~P^D^(S&(P|D)) */
221 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXorReverse
),
222 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXxor
) }, /* 0x6e S^(D&(P|~S)) */
223 { OP(SRC
,DST
,GXequiv
), OP(PAT
,DST
,GXnand
) }, /* 0x6f ~(P&~(S^D)) */
224 { OP(SRC
,DST
,GXnand
), OP(PAT
,DST
,GXand
) }, /* 0x70 P&~(D&S) */
225 { OP(SRC
,TMP
,GXcopy
), OP(DST
,SRC
,GXxor
),
226 OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXand
),
227 OP(TMP
,DST
,GXequiv
) }, /* 0x71 ~S^((S^D)&(P^D))*/
228 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXxor
),
229 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXxor
) }, /* 0x72 S^(D|(P^S)) */
230 { OP(PAT
,DST
,GXorInverted
), OP(SRC
,DST
,GXnand
) },/* 0x73 ~(S&(D|~P)) */
231 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXxor
),
232 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXxor
) }, /* 0x74 D^(S|(P^D)) */
233 { OP(PAT
,SRC
,GXorInverted
), OP(SRC
,DST
,GXnand
) },/* 0x75 ~(D&(S|~P)) */
234 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXandReverse
),
235 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXxor
) }, /* 0x76 S^(D|(P&~S)) */
236 { OP(SRC
,DST
,GXnand
) }, /* 0x77 ~(S&D) */
237 { OP(SRC
,DST
,GXand
), OP(PAT
,DST
,GXxor
) }, /* 0x78 P^(D&S) */
238 { OP(DST
,TMP
,GXcopy
), OP(SRC
,DST
,GXor
),
239 OP(PAT
,DST
,GXand
), OP(SRC
,DST
,GXxor
),
240 OP(TMP
,DST
,GXequiv
) }, /* 0x79 ~D^S^(P&(D|S)) */
241 { OP(DST
,SRC
,GXorInverted
), OP(PAT
,SRC
,GXand
),
242 OP(SRC
,DST
,GXxor
) }, /* 0x7a D^(P&(S|~D)) */
243 { OP(PAT
,DST
,GXequiv
), OP(SRC
,DST
,GXnand
) }, /* 0x7b ~(S&~(D^P)) */
244 { OP(SRC
,DST
,GXorInverted
), OP(PAT
,DST
,GXand
),
245 OP(SRC
,DST
,GXxor
) }, /* 0x7c S^(P&(D|~S)) */
246 { OP(PAT
,SRC
,GXequiv
), OP(SRC
,DST
,GXnand
) }, /* 0x7d ~(D&~(P^S)) */
247 { OP(SRC
,DST
,GXxor
), OP(PAT
,SRC
,GXxor
),
248 OP(SRC
,DST
,GXor
) }, /* 0x7e (S^P)|(S^D) */
249 { OP(PAT
,SRC
,GXand
), OP(SRC
,DST
,GXnand
) }, /* 0x7f ~(D&P&S) */
250 { OP(PAT
,SRC
,GXand
), OP(SRC
,DST
,GXand
) }, /* 0x80 D&P&S */
251 { OP(SRC
,DST
,GXxor
), OP(PAT
,SRC
,GXxor
),
252 OP(SRC
,DST
,GXnor
) }, /* 0x81 ~((S^P)|(S^D)) */
253 { OP(PAT
,SRC
,GXequiv
), OP(SRC
,DST
,GXand
) }, /* 0x82 D&~(P^S) */
254 { OP(SRC
,DST
,GXorInverted
), OP(PAT
,DST
,GXand
),
255 OP(SRC
,DST
,GXequiv
) }, /* 0x83 ~S^(P&(D|~S)) */
256 { OP(PAT
,DST
,GXequiv
), OP(SRC
,DST
,GXand
) }, /* 0x84 S&~(D^P) */
257 { OP(PAT
,SRC
,GXorInverted
), OP(SRC
,DST
,GXand
),
258 OP(PAT
,DST
,GXequiv
) }, /* 0x85 ~P^(D&(S|~P)) */
259 { OP(DST
,TMP
,GXcopy
), OP(SRC
,DST
,GXor
),
260 OP(PAT
,DST
,GXand
), OP(SRC
,DST
,GXxor
),
261 OP(TMP
,DST
,GXxor
) }, /* 0x86 D^S^(P&(D|S)) */
262 { OP(SRC
,DST
,GXand
), OP(PAT
,DST
,GXequiv
) }, /* 0x87 ~P^(D&S) */
263 { OP(SRC
,DST
,GXand
) }, /* 0x88 S&D */
264 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXandReverse
),
265 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXequiv
) }, /* 0x89 ~S^(D|(P&~S)) */
266 { OP(PAT
,SRC
,GXorInverted
), OP(SRC
,DST
,GXand
) }, /* 0x8a D&(S|~P) */
267 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXxor
),
268 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXequiv
) }, /* 0x8b ~D^(S|(P^D)) */
269 { OP(PAT
,DST
,GXorInverted
), OP(SRC
,DST
,GXand
) }, /* 0x8c S&(D|~P) */
270 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXxor
),
271 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXequiv
) }, /* 0x8d ~S^(D|(P^S)) */
272 { OP(SRC
,TMP
,GXcopy
), OP(DST
,SRC
,GXxor
),
273 OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXand
),
274 OP(TMP
,DST
,GXxor
) }, /* 0x8e S^((S^D)&(P^D))*/
275 { OP(SRC
,DST
,GXnand
), OP(PAT
,DST
,GXnand
) }, /* 0x8f ~(P&~(D&S)) */
276 { OP(SRC
,DST
,GXequiv
), OP(PAT
,DST
,GXand
) }, /* 0x90 P&~(D^S) */
277 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXorReverse
),
278 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXequiv
) }, /* 0x91 ~S^(D&(P|~S)) */
279 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXor
),
280 OP(SRC
,DST
,GXand
), OP(PAT
,DST
,GXxor
),
281 OP(TMP
,DST
,GXxor
) }, /* 0x92 D^P^(S&(D|P)) */
282 { OP(PAT
,DST
,GXand
), OP(SRC
,DST
,GXequiv
) }, /* 0x93 ~S^(P&D) */
283 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXor
),
284 OP(SRC
,DST
,GXand
), OP(PAT
,DST
,GXxor
),
285 OP(TMP
,DST
,GXxor
) }, /* 0x94 S^P^(D&(P|S)) */
286 { OP(PAT
,SRC
,GXand
), OP(SRC
,DST
,GXequiv
) }, /* 0x95 ~D^(P&S) */
287 { OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXxor
) }, /* 0x96 D^P^S */
288 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXnor
),
289 OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXxor
),
290 OP(TMP
,DST
,GXxor
) }, /* 0x97 S^P^(D|~(P|S)) */
291 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXnor
),
292 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXequiv
) }, /* 0x98 ~S^(D|~(P|S)) */
293 { OP(SRC
,DST
,GXequiv
) }, /* 0x99 ~S^D */
294 { OP(PAT
,SRC
,GXandReverse
), OP(SRC
,DST
,GXxor
) }, /* 0x9a D^(P&~S) */
295 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXor
),
296 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXequiv
) }, /* 0x9b ~S^(D&(P|S)) */
297 { OP(PAT
,DST
,GXandReverse
), OP(SRC
,DST
,GXxor
) }, /* 0x9c S^(P&~D) */
298 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXor
),
299 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXequiv
) }, /* 0x9d ~D^(S&(P|D)) */
300 { OP(DST
,TMP
,GXcopy
), OP(SRC
,DST
,GXand
),
301 OP(PAT
,DST
,GXor
), OP(SRC
,DST
,GXxor
),
302 OP(TMP
,DST
,GXxor
) }, /* 0x9e D^S^(P|(D&S)) */
303 { OP(SRC
,DST
,GXxor
), OP(PAT
,DST
,GXnand
) }, /* 0x9f ~(P&(D^S)) */
304 { OP(PAT
,DST
,GXand
) }, /* 0xa0 D&P */
305 { OP(PAT
,SRC
,GXandInverted
), OP(SRC
,DST
,GXor
),
306 OP(PAT
,DST
,GXequiv
) }, /* 0xa1 ~P^(D|(S&~P)) */
307 { OP(PAT
,SRC
,GXorReverse
), OP(SRC
,DST
,GXand
) }, /* 0xa2 D&(P|~S) */
308 { OP(DST
,SRC
,GXxor
), OP(PAT
,SRC
,GXor
),
309 OP(SRC
,DST
,GXequiv
) }, /* 0xa3 ~D^(P|(S^D)) */
310 { OP(PAT
,SRC
,GXnor
), OP(SRC
,DST
,GXor
),
311 OP(PAT
,DST
,GXequiv
) }, /* 0xa4 ~P^(D|~(S|P)) */
312 { OP(PAT
,DST
,GXequiv
) }, /* 0xa5 ~P^D */
313 { OP(PAT
,SRC
,GXandInverted
), OP(SRC
,DST
,GXxor
) },/* 0xa6 D^(S&~P) */
314 { OP(PAT
,SRC
,GXor
), OP(SRC
,DST
,GXand
),
315 OP(PAT
,DST
,GXequiv
) }, /* 0xa7 ~P^(D&(S|P)) */
316 { OP(PAT
,SRC
,GXor
), OP(SRC
,DST
,GXand
) }, /* 0xa8 D&(P|S) */
317 { OP(PAT
,SRC
,GXor
), OP(SRC
,DST
,GXequiv
) }, /* 0xa9 ~D^(P|S) */
318 { OP(PAT
,DST
,GXnoop
) }, /* 0xaa D */
319 { OP(PAT
,SRC
,GXnor
), OP(SRC
,DST
,GXor
) }, /* 0xab D|~(P|S) */
320 { OP(SRC
,DST
,GXxor
), OP(PAT
,DST
,GXand
),
321 OP(SRC
,DST
,GXxor
) }, /* 0xac S^(P&(D^S)) */
322 { OP(DST
,SRC
,GXand
), OP(PAT
,SRC
,GXor
),
323 OP(SRC
,DST
,GXequiv
) }, /* 0xad ~D^(P|(S&D)) */
324 { OP(PAT
,SRC
,GXandInverted
), OP(SRC
,DST
,GXor
) }, /* 0xae D|(S&~P) */
325 { OP(PAT
,DST
,GXorInverted
) }, /* 0xaf D|~P */
326 { OP(SRC
,DST
,GXorInverted
), OP(PAT
,DST
,GXand
) }, /* 0xb0 P&(D|~S) */
327 { OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXor
),
328 OP(PAT
,DST
,GXequiv
) }, /* 0xb1 ~P^(D|(S^P)) */
329 { OP(SRC
,TMP
,GXcopy
), OP(SRC
,DST
,GXxor
),
330 OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXor
),
331 OP(TMP
,DST
,GXxor
) }, /* 0xb2 S^((S^P)|(S^D))*/
332 { OP(PAT
,DST
,GXnand
), OP(SRC
,DST
,GXnand
) }, /* 0xb3 ~(S&~(D&P)) */
333 { OP(SRC
,DST
,GXandReverse
), OP(PAT
,DST
,GXxor
) }, /* 0xb4 P^(S&~D) */
334 { OP(DST
,SRC
,GXor
), OP(PAT
,SRC
,GXand
),
335 OP(SRC
,DST
,GXequiv
) }, /* 0xb5 ~D^(P&(S|D)) */
336 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXand
),
337 OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXxor
),
338 OP(TMP
,DST
,GXxor
) }, /* 0xb6 D^P^(S|(D&P)) */
339 { OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXnand
) }, /* 0xb7 ~(S&(D^P)) */
340 { OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXand
),
341 OP(PAT
,DST
,GXxor
) }, /* 0xb8 P^(S&(D^P)) */
342 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXand
),
343 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXequiv
) }, /* 0xb9 ~D^(S|(P&D)) */
344 { OP(PAT
,SRC
,GXandReverse
), OP(SRC
,DST
,GXor
) }, /* 0xba D|(P&~S) */
345 { OP(SRC
,DST
,GXorInverted
) }, /* 0xbb ~S|D */
346 { OP(SRC
,DST
,GXnand
), OP(PAT
,DST
,GXand
),
347 OP(SRC
,DST
,GXxor
) }, /* 0xbc S^(P&~(D&S)) */
348 { OP(DST
,SRC
,GXxor
), OP(PAT
,DST
,GXxor
),
349 OP(SRC
,DST
,GXnand
) }, /* 0xbd ~((S^D)&(P^D)) */
350 { OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXor
) }, /* 0xbe D|(P^S) */
351 { OP(PAT
,SRC
,GXnand
), OP(SRC
,DST
,GXor
) }, /* 0xbf D|~(P&S) */
352 { OP(PAT
,SRC
,GXand
) }, /* 0xc0 P&S */
353 { OP(SRC
,DST
,GXandInverted
), OP(PAT
,DST
,GXor
),
354 OP(SRC
,DST
,GXequiv
) }, /* 0xc1 ~S^(P|(D&~S)) */
355 { OP(SRC
,DST
,GXnor
), OP(PAT
,DST
,GXor
),
356 OP(SRC
,DST
,GXequiv
) }, /* 0xc2 ~S^(P|~(D|S)) */
357 { OP(PAT
,SRC
,GXequiv
) }, /* 0xc3 ~P^S */
358 { OP(PAT
,DST
,GXorReverse
), OP(SRC
,DST
,GXand
) }, /* 0xc4 S&(P|~D) */
359 { OP(SRC
,DST
,GXxor
), OP(PAT
,DST
,GXor
),
360 OP(SRC
,DST
,GXequiv
) }, /* 0xc5 ~S^(P|(D^S)) */
361 { OP(PAT
,DST
,GXandInverted
), OP(SRC
,DST
,GXxor
) },/* 0xc6 S^(D&~P) */
362 { OP(PAT
,DST
,GXor
), OP(SRC
,DST
,GXand
),
363 OP(PAT
,DST
,GXequiv
) }, /* 0xc7 ~P^(S&(D|P)) */
364 { OP(PAT
,DST
,GXor
), OP(SRC
,DST
,GXand
) }, /* 0xc8 S&(D|P) */
365 { OP(PAT
,DST
,GXor
), OP(SRC
,DST
,GXequiv
) }, /* 0xc9 ~S^(P|D) */
366 { OP(DST
,SRC
,GXxor
), OP(PAT
,SRC
,GXand
),
367 OP(SRC
,DST
,GXxor
) }, /* 0xca D^(P&(S^D)) */
368 { OP(SRC
,DST
,GXand
), OP(PAT
,DST
,GXor
),
369 OP(SRC
,DST
,GXequiv
) }, /* 0xcb ~S^(P|(D&S)) */
370 { OP(SRC
,DST
,GXcopy
) }, /* 0xcc S */
371 { OP(PAT
,DST
,GXnor
), OP(SRC
,DST
,GXor
) }, /* 0xcd S|~(D|P) */
372 { OP(PAT
,DST
,GXandInverted
), OP(SRC
,DST
,GXor
) }, /* 0xce S|(D&~P) */
373 { OP(PAT
,SRC
,GXorInverted
) }, /* 0xcf S|~P */
374 { OP(SRC
,DST
,GXorReverse
), OP(PAT
,DST
,GXand
) }, /* 0xd0 P&(S|~D) */
375 { OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXor
),
376 OP(PAT
,DST
,GXequiv
) }, /* 0xd1 ~P^(S|(D^P)) */
377 { OP(SRC
,DST
,GXandInverted
), OP(PAT
,DST
,GXxor
) },/* 0xd2 P^(D&~S) */
378 { OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXand
),
379 OP(SRC
,DST
,GXequiv
) }, /* 0xd3 ~S^(P&(D|S)) */
380 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXxor
),
381 OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXand
),
382 OP(TMP
,DST
,GXxor
) }, /* 0xd4 S^((S^P)&(D^P))*/
383 { OP(PAT
,SRC
,GXnand
), OP(SRC
,DST
,GXnand
) }, /* 0xd5 ~(D&~(P&S)) */
384 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXand
),
385 OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXxor
),
386 OP(TMP
,DST
,GXxor
) }, /* 0xd6 S^P^(D|(P&S)) */
387 { OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXnand
) }, /* 0xd7 ~(D&(P^S)) */
388 { OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXand
),
389 OP(PAT
,DST
,GXxor
) }, /* 0xd8 P^(D&(S^P)) */
390 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXand
),
391 OP(SRC
,DST
,GXor
), OP(TMP
,DST
,GXequiv
) }, /* 0xd9 ~S^(D|(P&S)) */
392 { OP(DST
,SRC
,GXnand
), OP(PAT
,SRC
,GXand
),
393 OP(SRC
,DST
,GXxor
) }, /* 0xda D^(P&~(S&D)) */
394 { OP(SRC
,DST
,GXxor
), OP(PAT
,SRC
,GXxor
),
395 OP(SRC
,DST
,GXnand
) }, /* 0xdb ~((S^P)&(S^D)) */
396 { OP(PAT
,DST
,GXandReverse
), OP(SRC
,DST
,GXor
) }, /* 0xdc S|(P&~D) */
397 { OP(SRC
,DST
,GXorReverse
) }, /* 0xdd S|~D */
398 { OP(PAT
,DST
,GXxor
), OP(SRC
,DST
,GXor
) }, /* 0xde S|(D^P) */
399 { OP(PAT
,DST
,GXnand
), OP(SRC
,DST
,GXor
) }, /* 0xdf S|~(D&P) */
400 { OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXand
) }, /* 0xe0 P&(D|S) */
401 { OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXequiv
) }, /* 0xe1 ~P^(D|S) */
402 { OP(DST
,TMP
,GXcopy
), OP(PAT
,DST
,GXxor
),
403 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXxor
) }, /* 0xe2 D^(S&(P^D)) */
404 { OP(PAT
,DST
,GXand
), OP(SRC
,DST
,GXor
),
405 OP(PAT
,DST
,GXequiv
) }, /* 0xe3 ~P^(S|(D&P)) */
406 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXxor
),
407 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXxor
) }, /* 0xe4 S^(D&(P^S)) */
408 { OP(PAT
,SRC
,GXand
), OP(SRC
,DST
,GXor
),
409 OP(PAT
,DST
,GXequiv
) }, /* 0xe5 ~P^(D|(S&P)) */
410 { OP(SRC
,TMP
,GXcopy
), OP(PAT
,SRC
,GXnand
),
411 OP(SRC
,DST
,GXand
), OP(TMP
,DST
,GXxor
) }, /* 0xe6 S^(D&~(P&S)) */
412 { OP(PAT
,SRC
,GXxor
), OP(PAT
,DST
,GXxor
),
413 OP(SRC
,DST
,GXnand
) }, /* 0xe7 ~((S^P)&(D^P)) */
414 { OP(SRC
,TMP
,GXcopy
), OP(SRC
,DST
,GXxor
),
415 OP(PAT
,SRC
,GXxor
), OP(SRC
,DST
,GXand
),
416 OP(TMP
,DST
,GXxor
) }, /* 0xe8 S^((S^P)&(S^D))*/
417 { OP(DST
,TMP
,GXcopy
), OP(SRC
,DST
,GXnand
),
418 OP(PAT
,DST
,GXand
), OP(SRC
,DST
,GXxor
),
419 OP(TMP
,DST
,GXequiv
) }, /* 0xe9 ~D^S^(P&~(S&D))*/
420 { OP(PAT
,SRC
,GXand
), OP(SRC
,DST
,GXor
) }, /* 0xea D|(P&S) */
421 { OP(PAT
,SRC
,GXequiv
), OP(SRC
,DST
,GXor
) }, /* 0xeb D|~(P^S) */
422 { OP(PAT
,DST
,GXand
), OP(SRC
,DST
,GXor
) }, /* 0xec S|(D&P) */
423 { OP(PAT
,DST
,GXequiv
), OP(SRC
,DST
,GXor
) }, /* 0xed S|~(D^P) */
424 { OP(SRC
,DST
,GXor
) }, /* 0xee S|D */
425 { OP(PAT
,DST
,GXorInverted
), OP(SRC
,DST
,GXor
) }, /* 0xef S|D|~P */
426 { OP(PAT
,DST
,GXcopy
) }, /* 0xf0 P */
427 { OP(SRC
,DST
,GXnor
), OP(PAT
,DST
,GXor
) }, /* 0xf1 P|~(D|S) */
428 { OP(SRC
,DST
,GXandInverted
), OP(PAT
,DST
,GXor
) }, /* 0xf2 P|(D&~S) */
429 { OP(PAT
,SRC
,GXorReverse
) }, /* 0xf3 P|~S */
430 { OP(SRC
,DST
,GXandReverse
), OP(PAT
,DST
,GXor
) }, /* 0xf4 P|(S&~D) */
431 { OP(PAT
,DST
,GXorReverse
) }, /* 0xf5 P|~D */
432 { OP(SRC
,DST
,GXxor
), OP(PAT
,DST
,GXor
) }, /* 0xf6 P|(D^S) */
433 { OP(SRC
,DST
,GXnand
), OP(PAT
,DST
,GXor
) }, /* 0xf7 P|~(S&D) */
434 { OP(SRC
,DST
,GXand
), OP(PAT
,DST
,GXor
) }, /* 0xf8 P|(D&S) */
435 { OP(SRC
,DST
,GXequiv
), OP(PAT
,DST
,GXor
) }, /* 0xf9 P|~(D^S) */
436 { OP(PAT
,DST
,GXor
) }, /* 0xfa D|P */
437 { OP(PAT
,SRC
,GXorReverse
), OP(SRC
,DST
,GXor
) }, /* 0xfb D|P|~S */
438 { OP(PAT
,SRC
,GXor
) }, /* 0xfc P|S */
439 { OP(SRC
,DST
,GXorReverse
), OP(PAT
,DST
,GXor
) }, /* 0xfd P|S|~D */
440 { OP(SRC
,DST
,GXor
), OP(PAT
,DST
,GXor
) }, /* 0xfe P|D|S */
441 { OP(PAT
,DST
,GXset
) } /* 0xff 1 */
444 static const unsigned char bit_swap
[256] =
446 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
447 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
448 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
449 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
450 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
451 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
452 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
453 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
454 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
455 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
456 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
457 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
458 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
459 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
460 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
461 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
462 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
463 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
464 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
465 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
466 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
467 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
468 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
469 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
470 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
471 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
472 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
473 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
474 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
475 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
476 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
477 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
480 #ifdef WORDS_BIGENDIAN
481 static const unsigned int zeropad_masks
[32] =
483 0xffffffff, 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xf8000000, 0xfc000000, 0xfe000000,
484 0xff000000, 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000,
485 0xffff0000, 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00,
486 0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 0xfffffff8, 0xfffffffc, 0xfffffffe
489 static const unsigned int zeropad_masks
[32] =
491 0xffffffff, 0x00000080, 0x000000c0, 0x000000e0, 0x000000f0, 0x000000f8, 0x000000fc, 0x000000fe,
492 0x000000ff, 0x000080ff, 0x0000c0ff, 0x0000e0ff, 0x0000f0ff, 0x0000f8ff, 0x0000fcff, 0x0000feff,
493 0x0000ffff, 0x0080ffff, 0x00c0ffff, 0x00e0ffff, 0x00f0ffff, 0x00f8ffff, 0x00fcffff, 0x00feffff,
494 0x00ffffff, 0x80ffffff, 0xc0ffffff, 0xe0ffffff, 0xf0ffffff, 0xf8ffffff, 0xfcffffff, 0xfeffffff
498 #ifdef BITBLT_TEST /* Opcodes test */
500 static int do_bitop( int s
, int d
, int rop
)
505 case GXclear
: res
= 0; break;
506 case GXand
: res
= s
& d
; break;
507 case GXandReverse
: res
= s
& ~d
; break;
508 case GXcopy
: res
= s
; break;
509 case GXandInverted
: res
= ~s
& d
; break;
510 case GXnoop
: res
= d
; break;
511 case GXxor
: res
= s
^ d
; break;
512 case GXor
: res
= s
| d
; break;
513 case GXnor
: res
= ~(s
| d
); break;
514 case GXequiv
: res
= ~s
^ d
; break;
515 case GXinvert
: res
= ~d
; break;
516 case GXorReverse
: res
= s
| ~d
; break;
517 case GXcopyInverted
: res
= ~s
; break;
518 case GXorInverted
: res
= ~s
| d
; break;
519 case GXnand
: res
= ~(s
& d
); break;
520 case GXset
: res
= 1; break;
527 int rop
, i
, res
, src
, dst
, pat
, tmp
, dstUsed
;
528 const unsigned char *opcode
;
530 for (rop
= 0; rop
< 256; rop
++)
533 for (i
= 0; i
< 8; i
++)
538 for (opcode
= BITBLT_Opcodes
[rop
]; *opcode
; opcode
++)
542 case OP_ARGS(DST
,TMP
):
543 tmp
= do_bitop( dst
, tmp
, *opcode
& 0xf );
545 case OP_ARGS(DST
,SRC
):
546 src
= do_bitop( dst
, src
, *opcode
& 0xf );
548 case OP_ARGS(SRC
,TMP
):
549 tmp
= do_bitop( src
, tmp
, *opcode
& 0xf );
551 case OP_ARGS(SRC
,DST
):
552 dst
= do_bitop( src
, dst
, *opcode
& 0xf );
555 case OP_ARGS(PAT
,DST
):
556 dst
= do_bitop( pat
, dst
, *opcode
& 0xf );
559 case OP_ARGS(PAT
,SRC
):
560 src
= do_bitop( pat
, src
, *opcode
& 0xf );
562 case OP_ARGS(TMP
,DST
):
563 dst
= do_bitop( tmp
, dst
, *opcode
& 0xf );
566 case OP_ARGS(TMP
,SRC
):
567 src
= do_bitop( tmp
, src
, *opcode
& 0xf );
570 printf( "Invalid opcode %x\n", *opcode
);
573 if (!dstUsed
) dst
= src
;
574 if (dst
) res
|= 1 << i
;
576 if (res
!= rop
) printf( "%02x: ERROR, res=%02x\n", rop
, res
);
582 #endif /* BITBLT_TEST */
585 /* handler for XGetImage BadMatch errors */
586 static int XGetImage_handler( Display
*dpy
, XErrorEvent
*event
, void *arg
)
588 return (event
->request_code
== X_GetImage
&& event
->error_code
== BadMatch
);
591 /***********************************************************************
594 * Retrieve an area from the destination DC, mapping all the
595 * pixels to Windows colors.
597 static int BITBLT_GetDstArea(X11DRV_PDEVICE
*physDev
, Pixmap pixmap
, GC gc
, const RECT
*visRectDst
)
600 INT width
= visRectDst
->right
- visRectDst
->left
;
601 INT height
= visRectDst
->bottom
- visRectDst
->top
;
602 BOOL memdc
= (GetObjectType( physDev
->dev
.hdc
) == OBJ_MEMDC
);
606 if (!X11DRV_PALETTE_XPixelToPalette
|| (physDev
->depth
== 1) ||
607 (X11DRV_PALETTE_PaletteFlags
& X11DRV_PALETTE_VIRTUAL
) )
609 XCopyArea( gdi_display
, physDev
->drawable
, pixmap
, gc
,
610 physDev
->dc_rect
.left
+ visRectDst
->left
, physDev
->dc_rect
.top
+ visRectDst
->top
,
611 width
, height
, 0, 0 );
620 image
= XGetImage( gdi_display
, physDev
->drawable
,
621 physDev
->dc_rect
.left
+ visRectDst
->left
,
622 physDev
->dc_rect
.top
+ visRectDst
->top
,
623 width
, height
, AllPlanes
, ZPixmap
);
626 /* Make sure we don't get a BadMatch error */
627 XCopyArea( gdi_display
, physDev
->drawable
, pixmap
, gc
,
628 physDev
->dc_rect
.left
+ visRectDst
->left
,
629 physDev
->dc_rect
.top
+ visRectDst
->top
,
630 width
, height
, 0, 0);
632 image
= XGetImage( gdi_display
, pixmap
, 0, 0, width
, height
,
633 AllPlanes
, ZPixmap
);
637 for (y
= 0; y
< height
; y
++)
638 for (x
= 0; x
< width
; x
++)
639 XPutPixel( image
, x
, y
,
640 X11DRV_PALETTE_XPixelToPalette
[XGetPixel( image
, x
, y
)]);
641 XPutImage( gdi_display
, pixmap
, gc
, image
, 0, 0, 0, 0, width
, height
);
642 XDestroyImage( image
);
651 /***********************************************************************
654 * Put an area back into the destination DC, mapping the pixel
655 * colors to X pixels.
657 static int BITBLT_PutDstArea(X11DRV_PDEVICE
*physDev
, Pixmap pixmap
, const RECT
*visRectDst
)
660 INT width
= visRectDst
->right
- visRectDst
->left
;
661 INT height
= visRectDst
->bottom
- visRectDst
->top
;
663 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
665 if (!X11DRV_PALETTE_PaletteToXPixel
|| (physDev
->depth
== 1) ||
666 (X11DRV_PALETTE_PaletteFlags
& X11DRV_PALETTE_VIRTUAL
) )
668 XCopyArea( gdi_display
, pixmap
, physDev
->drawable
, physDev
->gc
, 0, 0, width
, height
,
669 physDev
->dc_rect
.left
+ visRectDst
->left
,
670 physDev
->dc_rect
.top
+ visRectDst
->top
);
676 XImage
*image
= XGetImage( gdi_display
, pixmap
, 0, 0, width
, height
,
677 AllPlanes
, ZPixmap
);
678 for (y
= 0; y
< height
; y
++)
679 for (x
= 0; x
< width
; x
++)
681 XPutPixel( image
, x
, y
,
682 X11DRV_PALETTE_PaletteToXPixel
[XGetPixel( image
, x
, y
)]);
684 XPutImage( gdi_display
, physDev
->drawable
, physDev
->gc
, image
, 0, 0,
685 physDev
->dc_rect
.left
+ visRectDst
->left
,
686 physDev
->dc_rect
.top
+ visRectDst
->top
, width
, height
);
687 XDestroyImage( image
);
692 static BOOL
same_format(X11DRV_PDEVICE
*physDevSrc
, X11DRV_PDEVICE
*physDevDst
)
694 if (physDevSrc
->depth
!= physDevDst
->depth
) return FALSE
;
695 if (!physDevSrc
->color_shifts
&& !physDevDst
->color_shifts
) return TRUE
;
696 if (physDevSrc
->color_shifts
&& physDevDst
->color_shifts
)
697 return !memcmp(physDevSrc
->color_shifts
, physDevDst
->color_shifts
, sizeof(ColorShifts
));
701 void execute_rop( X11DRV_PDEVICE
*physdev
, Pixmap src_pixmap
, GC gc
, const RECT
*visrect
, DWORD rop
)
704 Pixmap result
= src_pixmap
;
706 const BYTE
*opcode
= BITBLT_Opcodes
[(rop
>> 16) & 0xff];
707 BOOL use_pat
= (((rop
>> 4) & 0x0f0000) != (rop
& 0x0f0000));
708 BOOL use_dst
= (((rop
>> 1) & 0x550000) != (rop
& 0x550000));
709 int width
= visrect
->right
- visrect
->left
;
710 int height
= visrect
->bottom
- visrect
->top
;
712 pixmaps
[SRC
] = src_pixmap
;
715 pixmaps
[DST
] = XCreatePixmap( gdi_display
, root_window
, width
, height
, physdev
->depth
);
718 if (use_dst
) BITBLT_GetDstArea( physdev
, pixmaps
[DST
], gc
, visrect
);
719 null_brush
= use_pat
&& !X11DRV_SetupGCForPatBlt( physdev
, gc
, TRUE
);
722 for ( ; *opcode
; opcode
++)
724 if (OP_DST(*opcode
) == DST
) result
= pixmaps
[DST
];
725 XSetFunction( gdi_display
, gc
, OP_ROP(*opcode
) );
726 switch(OP_SRCDST(*opcode
))
728 case OP_ARGS(DST
,TMP
):
729 case OP_ARGS(SRC
,TMP
):
731 pixmaps
[TMP
] = XCreatePixmap( gdi_display
, root_window
, width
, height
, physdev
->depth
);
733 case OP_ARGS(DST
,SRC
):
734 case OP_ARGS(SRC
,DST
):
735 case OP_ARGS(TMP
,SRC
):
736 case OP_ARGS(TMP
,DST
):
737 XCopyArea( gdi_display
, pixmaps
[OP_SRC(*opcode
)], pixmaps
[OP_DST(*opcode
)], gc
,
738 0, 0, width
, height
, 0, 0 );
740 case OP_ARGS(PAT
,DST
):
741 case OP_ARGS(PAT
,SRC
):
743 XFillRectangle( gdi_display
, pixmaps
[OP_DST(*opcode
)], gc
, 0, 0, width
, height
);
747 XSetFunction( gdi_display
, physdev
->gc
, GXcopy
);
748 physdev
->exposures
+= BITBLT_PutDstArea( physdev
, result
, visrect
);
749 XFreePixmap( gdi_display
, pixmaps
[DST
] );
750 if (pixmaps
[TMP
]) XFreePixmap( gdi_display
, pixmaps
[TMP
] );
754 /***********************************************************************
757 BOOL
X11DRV_PatBlt( PHYSDEV dev
, struct bitblt_coords
*dst
, DWORD rop
)
759 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
760 BOOL usePat
= (((rop
>> 4) & 0x0f0000) != (rop
& 0x0f0000));
761 const BYTE
*opcode
= BITBLT_Opcodes
[(rop
>> 16) & 0xff];
763 if (usePat
&& !X11DRV_SetupGCForBrush( physDev
)) return TRUE
;
766 XSetFunction( gdi_display
, physDev
->gc
, OP_ROP(*opcode
) );
768 switch(rop
) /* a few special cases */
770 case BLACKNESS
: /* 0x00 */
771 case WHITENESS
: /* 0xff */
772 if ((physDev
->depth
!= 1) && X11DRV_PALETTE_PaletteToXPixel
)
774 XSetFunction( gdi_display
, physDev
->gc
, GXcopy
);
775 if (rop
== BLACKNESS
)
776 XSetForeground( gdi_display
, physDev
->gc
, X11DRV_PALETTE_PaletteToXPixel
[0] );
778 XSetForeground( gdi_display
, physDev
->gc
,
779 WhitePixel( gdi_display
, DefaultScreen(gdi_display
) ));
780 XSetFillStyle( gdi_display
, physDev
->gc
, FillSolid
);
783 case DSTINVERT
: /* 0x55 */
784 if (!(X11DRV_PALETTE_PaletteFlags
& (X11DRV_PALETTE_PRIVATE
| X11DRV_PALETTE_VIRTUAL
)))
786 /* Xor is much better when we do not have full colormap. */
787 /* Using white^black ensures that we invert at least black */
789 unsigned long xor_pix
= (WhitePixel( gdi_display
, DefaultScreen(gdi_display
) ) ^
790 BlackPixel( gdi_display
, DefaultScreen(gdi_display
) ));
791 XSetFunction( gdi_display
, physDev
->gc
, GXxor
);
792 XSetForeground( gdi_display
, physDev
->gc
, xor_pix
);
793 XSetFillStyle( gdi_display
, physDev
->gc
, FillSolid
);
797 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
798 physDev
->dc_rect
.left
+ dst
->visrect
.left
,
799 physDev
->dc_rect
.top
+ dst
->visrect
.top
,
800 dst
->visrect
.right
- dst
->visrect
.left
,
801 dst
->visrect
.bottom
- dst
->visrect
.top
);
807 /***********************************************************************
810 BOOL
X11DRV_StretchBlt( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
811 PHYSDEV src_dev
, struct bitblt_coords
*src
, DWORD rop
)
813 X11DRV_PDEVICE
*physDevDst
= get_x11drv_dev( dst_dev
);
814 X11DRV_PDEVICE
*physDevSrc
= get_x11drv_dev( src_dev
);
820 if (src_dev
->funcs
!= dst_dev
->funcs
||
821 src
->width
!= dst
->width
|| src
->height
!= dst
->height
|| /* no stretching with core X11 */
822 (physDevDst
->depth
== 1 && physDevSrc
->depth
!= 1) || /* color -> mono done by hand */
823 (X11DRV_PALETTE_XPixelToPalette
&& physDevSrc
->depth
!= 1)) /* needs palette mapping */
825 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pStretchBlt
);
826 return dst_dev
->funcs
->pStretchBlt( dst_dev
, dst
, src_dev
, src
, rop
);
829 width
= dst
->visrect
.right
- dst
->visrect
.left
;
830 height
= dst
->visrect
.bottom
- dst
->visrect
.top
;
831 opcode
= BITBLT_Opcodes
[(rop
>> 16) & 0xff];
833 /* a few optimizations for single-op ROPs */
834 if (!opcode
[1] && OP_SRCDST(opcode
[0]) == OP_ARGS(SRC
,DST
))
836 if (same_format(physDevSrc
, physDevDst
))
839 XSetFunction( gdi_display
, physDevDst
->gc
, OP_ROP(*opcode
) );
840 XCopyArea( gdi_display
, physDevSrc
->drawable
,
841 physDevDst
->drawable
, physDevDst
->gc
,
842 physDevSrc
->dc_rect
.left
+ src
->visrect
.left
,
843 physDevSrc
->dc_rect
.top
+ src
->visrect
.top
,
845 physDevDst
->dc_rect
.left
+ dst
->visrect
.left
,
846 physDevDst
->dc_rect
.top
+ dst
->visrect
.top
);
847 physDevDst
->exposures
++;
851 if (physDevSrc
->depth
== 1)
854 XSetBackground( gdi_display
, physDevDst
->gc
, physDevDst
->textPixel
);
855 XSetForeground( gdi_display
, physDevDst
->gc
, physDevDst
->backgroundPixel
);
856 XSetFunction( gdi_display
, physDevDst
->gc
, OP_ROP(*opcode
) );
857 XCopyPlane( gdi_display
, physDevSrc
->drawable
,
858 physDevDst
->drawable
, physDevDst
->gc
,
859 physDevSrc
->dc_rect
.left
+ src
->visrect
.left
,
860 physDevSrc
->dc_rect
.top
+ src
->visrect
.top
,
862 physDevDst
->dc_rect
.left
+ dst
->visrect
.left
,
863 physDevDst
->dc_rect
.top
+ dst
->visrect
.top
, 1 );
864 physDevDst
->exposures
++;
871 gc
= XCreateGC( gdi_display
, physDevDst
->drawable
, 0, NULL
);
872 XSetSubwindowMode( gdi_display
, gc
, IncludeInferiors
);
873 XSetGraphicsExposures( gdi_display
, gc
, False
);
875 /* retrieve the source */
877 src_pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
, physDevDst
->depth
);
878 if (physDevSrc
->depth
== 1)
880 /* MSDN says if StretchBlt must convert a bitmap from monochrome
881 to color or vice versa, the foreground and background color of
882 the device context are used. In fact, it also applies to the
883 case when it is converted from mono to mono. */
884 if (X11DRV_PALETTE_XPixelToPalette
&& physDevDst
->depth
!= 1)
886 XSetBackground( gdi_display
, gc
, X11DRV_PALETTE_XPixelToPalette
[physDevDst
->textPixel
] );
887 XSetForeground( gdi_display
, gc
, X11DRV_PALETTE_XPixelToPalette
[physDevDst
->backgroundPixel
]);
891 XSetBackground( gdi_display
, gc
, physDevDst
->textPixel
);
892 XSetForeground( gdi_display
, gc
, physDevDst
->backgroundPixel
);
894 XCopyPlane( gdi_display
, physDevSrc
->drawable
, src_pixmap
, gc
,
895 physDevSrc
->dc_rect
.left
+ src
->visrect
.left
,
896 physDevSrc
->dc_rect
.top
+ src
->visrect
.top
,
897 width
, height
, 0, 0, 1 );
899 else /* color -> color */
901 XCopyArea( gdi_display
, physDevSrc
->drawable
, src_pixmap
, gc
,
902 physDevSrc
->dc_rect
.left
+ src
->visrect
.left
,
903 physDevSrc
->dc_rect
.top
+ src
->visrect
.top
,
904 width
, height
, 0, 0 );
908 execute_rop( physDevDst
, src_pixmap
, gc
, &dst
->visrect
, rop
);
911 XFreePixmap( gdi_display
, src_pixmap
);
912 XFreeGC( gdi_display
, gc
);
918 static void free_heap_bits( struct gdi_image_bits
*bits
)
920 HeapFree( GetProcessHeap(), 0, bits
->ptr
);
923 static void free_ximage_bits( struct gdi_image_bits
*bits
)
930 /* store the palette or color mask data in the bitmap info structure */
931 static void set_color_info( PHYSDEV dev
, const ColorShifts
*color_shifts
, BITMAPINFO
*info
)
933 DWORD
*colors
= (DWORD
*)((char *)info
+ info
->bmiHeader
.biSize
);
935 info
->bmiHeader
.biCompression
= BI_RGB
;
936 info
->bmiHeader
.biClrUsed
= 0;
938 switch (info
->bmiHeader
.biBitCount
)
943 RGBQUAD
*rgb
= (RGBQUAD
*)colors
;
944 PALETTEENTRY palette
[256];
947 info
->bmiHeader
.biClrUsed
= 1 << info
->bmiHeader
.biBitCount
;
948 count
= X11DRV_GetSystemPaletteEntries( dev
, 0, info
->bmiHeader
.biClrUsed
, palette
);
949 for (i
= 0; i
< count
; i
++)
951 rgb
[i
].rgbRed
= palette
[i
].peRed
;
952 rgb
[i
].rgbGreen
= palette
[i
].peGreen
;
953 rgb
[i
].rgbBlue
= palette
[i
].peBlue
;
954 rgb
[i
].rgbReserved
= 0;
956 memset( &rgb
[count
], 0, (info
->bmiHeader
.biClrUsed
- count
) * sizeof(*rgb
) );
960 colors
[0] = color_shifts
->logicalRed
.max
<< color_shifts
->logicalRed
.shift
;
961 colors
[1] = color_shifts
->logicalGreen
.max
<< color_shifts
->logicalGreen
.shift
;
962 colors
[2] = color_shifts
->logicalBlue
.max
<< color_shifts
->logicalBlue
.shift
;
963 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
966 colors
[0] = color_shifts
->logicalRed
.max
<< color_shifts
->logicalRed
.shift
;
967 colors
[1] = color_shifts
->logicalGreen
.max
<< color_shifts
->logicalGreen
.shift
;
968 colors
[2] = color_shifts
->logicalBlue
.max
<< color_shifts
->logicalBlue
.shift
;
969 if (colors
[0] != 0xff0000 || colors
[1] != 0x00ff00 || colors
[2] != 0x0000ff)
970 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
975 /* check if the specified color info is suitable for PutImage */
976 static BOOL
matching_color_info( PHYSDEV dev
, const ColorShifts
*color_shifts
, const BITMAPINFO
*info
)
978 DWORD
*colors
= (DWORD
*)((char *)info
+ info
->bmiHeader
.biSize
);
980 switch (info
->bmiHeader
.biBitCount
)
983 if (info
->bmiHeader
.biCompression
!= BI_RGB
) return FALSE
;
984 return !info
->bmiHeader
.biClrUsed
; /* color map not allowed */
988 RGBQUAD
*rgb
= (RGBQUAD
*)colors
;
989 PALETTEENTRY palette
[256];
992 if (info
->bmiHeader
.biCompression
!= BI_RGB
) return FALSE
;
993 count
= X11DRV_GetSystemPaletteEntries( dev
, 0, 1 << info
->bmiHeader
.biBitCount
, palette
);
994 if (count
!= info
->bmiHeader
.biClrUsed
) return FALSE
;
995 for (i
= 0; i
< count
; i
++)
997 if (rgb
[i
].rgbRed
!= palette
[i
].peRed
||
998 rgb
[i
].rgbGreen
!= palette
[i
].peGreen
||
999 rgb
[i
].rgbBlue
!= palette
[i
].peBlue
) return FALSE
;
1004 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
)
1005 return (color_shifts
->logicalRed
.max
<< color_shifts
->logicalRed
.shift
== colors
[0] &&
1006 color_shifts
->logicalGreen
.max
<< color_shifts
->logicalGreen
.shift
== colors
[1] &&
1007 color_shifts
->logicalBlue
.max
<< color_shifts
->logicalBlue
.shift
== colors
[2]);
1008 if (info
->bmiHeader
.biCompression
== BI_RGB
)
1009 return (color_shifts
->logicalRed
.max
<< color_shifts
->logicalRed
.shift
== 0x7c00 &&
1010 color_shifts
->logicalGreen
.max
<< color_shifts
->logicalGreen
.shift
== 0x03e0 &&
1011 color_shifts
->logicalBlue
.max
<< color_shifts
->logicalBlue
.shift
== 0x001f);
1014 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
)
1015 return (color_shifts
->logicalRed
.max
<< color_shifts
->logicalRed
.shift
== colors
[0] &&
1016 color_shifts
->logicalGreen
.max
<< color_shifts
->logicalGreen
.shift
== colors
[1] &&
1017 color_shifts
->logicalBlue
.max
<< color_shifts
->logicalBlue
.shift
== colors
[2]);
1020 if (info
->bmiHeader
.biCompression
== BI_RGB
)
1021 return (color_shifts
->logicalRed
.max
<< color_shifts
->logicalRed
.shift
== 0xff0000 &&
1022 color_shifts
->logicalGreen
.max
<< color_shifts
->logicalGreen
.shift
== 0x00ff00 &&
1023 color_shifts
->logicalBlue
.max
<< color_shifts
->logicalBlue
.shift
== 0x0000ff);
1029 static inline BOOL
is_r8g8b8( int depth
, const ColorShifts
*color_shifts
)
1031 return depth
== 24 && color_shifts
->logicalBlue
.shift
== 0 && color_shifts
->logicalRed
.shift
== 16;
1034 /* copy the image bits, fixing up alignment and byte swapping as necessary */
1035 DWORD
copy_image_bits( BITMAPINFO
*info
, BOOL is_r8g8b8
, XImage
*image
,
1036 const struct gdi_image_bits
*src_bits
, struct gdi_image_bits
*dst_bits
,
1037 struct bitblt_coords
*coords
, const int *mapping
, unsigned int zeropad_mask
)
1039 #ifdef WORDS_BIGENDIAN
1040 static const int client_byte_order
= MSBFirst
;
1042 static const int client_byte_order
= LSBFirst
;
1045 int x
, y
, height
= coords
->visrect
.bottom
- coords
->visrect
.top
;
1046 int width_bytes
= image
->bytes_per_line
;
1048 unsigned char *src
, *dst
;
1050 switch (info
->bmiHeader
.biBitCount
)
1053 need_byteswap
= (image
->bitmap_bit_order
!= MSBFirst
);
1056 need_byteswap
= (image
->byte_order
!= MSBFirst
);
1060 need_byteswap
= (image
->byte_order
!= client_byte_order
);
1063 need_byteswap
= (image
->byte_order
== MSBFirst
) ^ !is_r8g8b8
;
1066 need_byteswap
= FALSE
;
1070 src
= src_bits
->ptr
;
1071 if (info
->bmiHeader
.biHeight
> 0)
1072 src
+= (info
->bmiHeader
.biHeight
- coords
->visrect
.bottom
) * width_bytes
;
1074 src
+= coords
->visrect
.top
* width_bytes
;
1076 if ((need_byteswap
&& !src_bits
->is_copy
) || /* need to swap bytes */
1077 (zeropad_mask
!= ~0u && !src_bits
->is_copy
) || /* need to clear padding bytes */
1078 (mapping
&& !src_bits
->is_copy
) || /* need to remap pixels */
1079 (width_bytes
& 3) || /* need to fixup line alignment */
1080 (info
->bmiHeader
.biHeight
> 0)) /* need to flip vertically */
1082 width_bytes
= (width_bytes
+ 3) & ~3;
1083 info
->bmiHeader
.biSizeImage
= height
* width_bytes
;
1084 if (!(dst_bits
->ptr
= HeapAlloc( GetProcessHeap(), 0, info
->bmiHeader
.biSizeImage
)))
1085 return ERROR_OUTOFMEMORY
;
1086 dst_bits
->is_copy
= TRUE
;
1087 dst_bits
->free
= free_heap_bits
;
1091 /* swap bits in place */
1092 dst_bits
->ptr
= src
;
1093 dst_bits
->is_copy
= src_bits
->is_copy
;
1094 dst_bits
->free
= NULL
;
1095 if (!need_byteswap
&& zeropad_mask
== ~0u && !mapping
) return ERROR_SUCCESS
; /* nothing to do */
1098 dst
= dst_bits
->ptr
;
1099 padding_pos
= width_bytes
/sizeof(unsigned int) - 1;
1101 if (info
->bmiHeader
.biHeight
> 0)
1103 dst
+= (height
- 1) * width_bytes
;
1104 width_bytes
= -width_bytes
;
1107 if (need_byteswap
|| mapping
)
1109 switch (info
->bmiHeader
.biBitCount
)
1112 for (y
= 0; y
< height
; y
++, src
+= image
->bytes_per_line
, dst
+= width_bytes
)
1114 for (x
= 0; x
< image
->bytes_per_line
; x
++)
1115 dst
[x
] = bit_swap
[src
[x
]];
1116 ((unsigned int *)dst
)[padding_pos
] &= zeropad_mask
;
1120 for (y
= 0; y
< height
; y
++, src
+= image
->bytes_per_line
, dst
+= width_bytes
)
1123 for (x
= 0; x
< image
->bytes_per_line
; x
++)
1124 dst
[x
] = (mapping
[src
[x
] & 0x0f] << 4) | mapping
[src
[x
] >> 4];
1126 for (x
= 0; x
< image
->bytes_per_line
; x
++)
1127 dst
[x
] = (src
[x
] << 4) | (src
[x
] >> 4);
1128 ((unsigned int *)dst
)[padding_pos
] &= zeropad_mask
;
1132 for (y
= 0; y
< height
; y
++, src
+= image
->bytes_per_line
, dst
+= width_bytes
)
1134 for (x
= 0; x
< image
->bytes_per_line
; x
++)
1135 dst
[x
] = mapping
[src
[x
]];
1136 ((unsigned int *)dst
)[padding_pos
] &= zeropad_mask
;
1140 for (y
= 0; y
< height
; y
++, src
+= image
->bytes_per_line
, dst
+= width_bytes
)
1142 for (x
= 0; x
< info
->bmiHeader
.biWidth
; x
++)
1143 ((USHORT
*)dst
)[x
] = RtlUshortByteSwap( ((const USHORT
*)src
)[x
] );
1144 ((unsigned int *)dst
)[padding_pos
] &= zeropad_mask
;
1148 for (y
= 0; y
< height
; y
++, src
+= image
->bytes_per_line
, dst
+= width_bytes
)
1150 for (x
= 0; x
< info
->bmiHeader
.biWidth
; x
++)
1152 unsigned char tmp
= src
[3 * x
];
1153 dst
[3 * x
] = src
[3 * x
+ 2];
1154 dst
[3 * x
+ 1] = src
[3 * x
+ 1];
1155 dst
[3 * x
+ 2] = tmp
;
1157 ((unsigned int *)dst
)[padding_pos
] &= zeropad_mask
;
1161 for (y
= 0; y
< height
; y
++, src
+= image
->bytes_per_line
, dst
+= width_bytes
)
1162 for (x
= 0; x
< info
->bmiHeader
.biWidth
; x
++)
1163 ((ULONG
*)dst
)[x
] = RtlUlongByteSwap( ((const ULONG
*)src
)[x
] );
1167 else if (src
!= dst
)
1169 for (y
= 0; y
< height
; y
++, src
+= image
->bytes_per_line
, dst
+= width_bytes
)
1171 memcpy( dst
, src
, image
->bytes_per_line
);
1172 ((unsigned int *)dst
)[padding_pos
] &= zeropad_mask
;
1175 else /* only need to clear the padding */
1177 for (y
= 0; y
< height
; y
++, dst
+= width_bytes
)
1178 ((unsigned int *)dst
)[padding_pos
] &= zeropad_mask
;
1180 return ERROR_SUCCESS
;
1183 /***********************************************************************
1186 DWORD
X11DRV_PutImage( PHYSDEV dev
, HBITMAP hbitmap
, HRGN clip
, BITMAPINFO
*info
,
1187 const struct gdi_image_bits
*bits
, struct bitblt_coords
*src
,
1188 struct bitblt_coords
*dst
, DWORD rop
)
1190 X11DRV_PDEVICE
*physdev
;
1191 X_PHYSBITMAP
*bitmap
;
1195 struct gdi_image_bits dst_bits
;
1196 const XPixmapFormatValues
*format
;
1197 const ColorShifts
*color_shifts
;
1198 const BYTE
*opcode
= BITBLT_Opcodes
[(rop
>> 16) & 0xff];
1199 const int *mapping
= NULL
;
1203 if (!(bitmap
= X11DRV_get_phys_bitmap( hbitmap
))) return ERROR_INVALID_HANDLE
;
1205 depth
= bitmap
->depth
;
1206 color_shifts
= &bitmap
->color_shifts
;
1210 physdev
= get_x11drv_dev( dev
);
1212 depth
= physdev
->depth
;
1213 color_shifts
= physdev
->color_shifts
;
1215 format
= pixmap_formats
[depth
];
1217 if (info
->bmiHeader
.biPlanes
!= 1) goto update_format
;
1218 if (info
->bmiHeader
.biBitCount
!= format
->bits_per_pixel
) goto update_format
;
1219 /* FIXME: could try to handle 1-bpp using XCopyPlane */
1220 if (!matching_color_info( dev
, color_shifts
, info
)) goto update_format
;
1221 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
1222 if ((src
->width
!= dst
->width
) || (src
->height
!= dst
->height
)) return ERROR_TRANSFORM_NOT_SUPPORTED
;
1225 image
= XCreateImage( gdi_display
, visual
, depth
, ZPixmap
, 0, NULL
,
1226 info
->bmiHeader
.biWidth
, src
->visrect
.bottom
- src
->visrect
.top
, 32, 0 );
1227 wine_tsx11_unlock();
1228 if (!image
) return ERROR_OUTOFMEMORY
;
1230 if (image
->bits_per_pixel
== 4 || image
->bits_per_pixel
== 8)
1232 if (bitmap
|| (!opcode
[1] && OP_SRCDST(opcode
[0]) == OP_ARGS(SRC
,DST
)))
1233 mapping
= X11DRV_PALETTE_PaletteToXPixel
;
1236 ret
= copy_image_bits( info
, is_r8g8b8(depth
,color_shifts
), image
, bits
, &dst_bits
, src
, mapping
, ~0u );
1240 int width
= dst
->visrect
.right
- dst
->visrect
.left
;
1241 int height
= dst
->visrect
.bottom
- dst
->visrect
.top
;
1243 image
->data
= dst_bits
.ptr
;
1244 /* hack: make sure the bits are readable if we are reading from a DIB section */
1245 /* to be removed once we get rid of DIB access protections */
1246 if (!dst_bits
.is_copy
) IsBadReadPtr( dst_bits
.ptr
, height
* image
->bytes_per_line
);
1250 RGNDATA
*clip_data
= NULL
;
1253 if (clip
) clip_data
= X11DRV_GetRegionData( clip
, 0 );
1256 gc
= XCreateGC( gdi_display
, bitmap
->pixmap
, 0, NULL
);
1257 XSetGraphicsExposures( gdi_display
, gc
, False
);
1258 if (clip_data
) XSetClipRectangles( gdi_display
, gc
, 0, 0, (XRectangle
*)clip_data
->Buffer
,
1259 clip_data
->rdh
.nCount
, YXBanded
);
1260 XPutImage( gdi_display
, bitmap
->pixmap
, gc
, image
, src
->visrect
.left
, 0,
1261 dst
->visrect
.left
, dst
->visrect
.top
, width
, height
);
1262 XFreeGC( gdi_display
, gc
);
1263 wine_tsx11_unlock();
1264 HeapFree( GetProcessHeap(), 0, clip_data
);
1268 BOOL restore_region
= add_extra_clipping_region( physdev
, clip
);
1270 /* optimization for single-op ROPs */
1271 if (!opcode
[1] && OP_SRCDST(opcode
[0]) == OP_ARGS(SRC
,DST
))
1274 XSetFunction( gdi_display
, physdev
->gc
, OP_ROP(*opcode
) );
1275 XPutImage( gdi_display
, physdev
->drawable
, physdev
->gc
, image
, src
->visrect
.left
, 0,
1276 physdev
->dc_rect
.left
+ dst
->visrect
.left
,
1277 physdev
->dc_rect
.top
+ dst
->visrect
.top
, width
, height
);
1278 wine_tsx11_unlock();
1286 gc
= XCreateGC( gdi_display
, physdev
->drawable
, 0, NULL
);
1287 XSetSubwindowMode( gdi_display
, gc
, IncludeInferiors
);
1288 XSetGraphicsExposures( gdi_display
, gc
, False
);
1289 src_pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
, depth
);
1290 XPutImage( gdi_display
, src_pixmap
, gc
, image
, src
->visrect
.left
, 0, 0, 0, width
, height
);
1291 wine_tsx11_unlock();
1293 execute_rop( physdev
, src_pixmap
, gc
, &dst
->visrect
, rop
);
1296 XFreePixmap( gdi_display
, src_pixmap
);
1297 XFreeGC( gdi_display
, gc
);
1298 wine_tsx11_unlock();
1301 if (restore_region
) restore_clipping_region( physdev
);
1307 XDestroyImage( image
);
1308 wine_tsx11_unlock();
1309 if (dst_bits
.free
) dst_bits
.free( &dst_bits
);
1313 info
->bmiHeader
.biPlanes
= 1;
1314 info
->bmiHeader
.biBitCount
= format
->bits_per_pixel
;
1315 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
1316 set_color_info( dev
, color_shifts
, info
);
1317 return ERROR_BAD_FORMAT
;
1320 /***********************************************************************
1323 DWORD
X11DRV_GetImage( PHYSDEV dev
, HBITMAP hbitmap
, BITMAPINFO
*info
,
1324 struct gdi_image_bits
*bits
, struct bitblt_coords
*src
)
1326 X11DRV_PDEVICE
*physdev
;
1327 X_PHYSBITMAP
*bitmap
;
1328 DWORD ret
= ERROR_SUCCESS
;
1330 UINT align
, x
, y
, width
, height
;
1332 struct gdi_image_bits src_bits
;
1333 const XPixmapFormatValues
*format
;
1334 const ColorShifts
*color_shifts
;
1335 const int *mapping
= NULL
;
1339 if (!(bitmap
= X11DRV_get_phys_bitmap( hbitmap
))) return ERROR_INVALID_HANDLE
;
1341 depth
= bitmap
->depth
;
1342 color_shifts
= &bitmap
->color_shifts
;
1346 physdev
= get_x11drv_dev( dev
);
1348 depth
= physdev
->depth
;
1349 color_shifts
= physdev
->color_shifts
;
1351 format
= pixmap_formats
[depth
];
1353 /* align start and width to 32-bit boundary */
1354 switch (format
->bits_per_pixel
)
1356 case 1: align
= 32; break;
1357 case 4: align
= 8; mapping
= X11DRV_PALETTE_XPixelToPalette
; break;
1358 case 8: align
= 4; mapping
= X11DRV_PALETTE_XPixelToPalette
; break;
1359 case 16: align
= 2; break;
1360 case 24: align
= 4; break;
1361 case 32: align
= 1; break;
1363 FIXME( "depth %u bpp %u not supported yet\n", depth
, format
->bits_per_pixel
);
1364 return ERROR_BAD_FORMAT
;
1367 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
1368 info
->bmiHeader
.biPlanes
= 1;
1369 info
->bmiHeader
.biBitCount
= format
->bits_per_pixel
;
1370 info
->bmiHeader
.biXPelsPerMeter
= 0;
1371 info
->bmiHeader
.biYPelsPerMeter
= 0;
1372 info
->bmiHeader
.biClrImportant
= 0;
1373 set_color_info( dev
, color_shifts
, info
);
1375 if (!bits
) return ERROR_SUCCESS
; /* just querying the color information */
1377 x
= src
->visrect
.left
& ~(align
- 1);
1378 y
= src
->visrect
.top
;
1379 width
= src
->visrect
.right
- x
;
1380 height
= src
->visrect
.bottom
- src
->visrect
.top
;
1381 if (format
->scanline_pad
!= 32) width
= (width
+ (align
- 1)) & ~(align
- 1);
1382 /* make the source rectangle relative to the returned bits */
1385 OffsetRect( &src
->visrect
, -x
, -y
);
1390 GetObjectW( hbitmap
, sizeof(bm
), &bm
);
1391 width
= min( width
, bm
.bmWidth
- x
);
1392 height
= min( height
, bm
.bmHeight
- y
);
1394 image
= XGetImage( gdi_display
, bitmap
->pixmap
, x
, y
, width
, height
, AllPlanes
, ZPixmap
);
1395 wine_tsx11_unlock();
1397 else if (GetObjectType( dev
->hdc
) == OBJ_MEMDC
)
1399 width
= min( width
, physdev
->dc_rect
.right
- physdev
->dc_rect
.left
- x
);
1400 height
= min( height
, physdev
->dc_rect
.bottom
- physdev
->dc_rect
.top
- y
);
1402 image
= XGetImage( gdi_display
, physdev
->drawable
,
1403 physdev
->dc_rect
.left
+ x
, physdev
->dc_rect
.top
+ y
,
1404 width
, height
, AllPlanes
, ZPixmap
);
1405 wine_tsx11_unlock();
1409 X11DRV_expect_error( gdi_display
, XGetImage_handler
, NULL
);
1410 image
= XGetImage( gdi_display
, physdev
->drawable
,
1411 physdev
->dc_rect
.left
+ x
, physdev
->dc_rect
.top
+ y
,
1412 width
, height
, AllPlanes
, ZPixmap
);
1413 if (X11DRV_check_error())
1415 /* use a temporary pixmap to avoid the BadMatch error */
1419 pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
, depth
);
1420 XCopyArea( gdi_display
, physdev
->drawable
, pixmap
, get_bitmap_gc(depth
),
1421 physdev
->dc_rect
.left
+ x
, physdev
->dc_rect
.top
+ y
, width
, height
, 0, 0 );
1422 image
= XGetImage( gdi_display
, pixmap
, 0, 0, width
, height
, AllPlanes
, ZPixmap
);
1423 XFreePixmap( gdi_display
, pixmap
);
1424 wine_tsx11_unlock();
1427 if (!image
) return ERROR_OUTOFMEMORY
;
1429 info
->bmiHeader
.biWidth
= width
;
1430 info
->bmiHeader
.biHeight
= -height
;
1431 info
->bmiHeader
.biSizeImage
= height
* image
->bytes_per_line
;
1433 src_bits
.ptr
= image
->data
;
1434 src_bits
.is_copy
= TRUE
;
1435 ret
= copy_image_bits( info
, is_r8g8b8(depth
,color_shifts
), image
, &src_bits
, bits
, src
, mapping
,
1436 zeropad_masks
[(width
* image
->bits_per_pixel
) & 31] );
1438 if (!ret
&& bits
->ptr
== image
->data
)
1440 bits
->free
= free_ximage_bits
;
1444 XDestroyImage( image
);
1445 wine_tsx11_unlock();