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