xref: /reactos/win32ss/user/user32/windows/draw.c (revision c2c66aff)
1 /*
2  * ReactOS User32 Library
3  * - Various drawing functions
4  *
5  * Copyright 2001 Casper S. Hournstroup
6  * Copyright 2003 Andrew Greenwood
7  * Copyright 2003 Filip Navara
8  * Copyright 2009 Matthias Kupfer
9  * Copyright 2017 Katayama Hirofumi MZ
10  *
11  * Based on Wine code.
12  *
13  * Copyright 1993, 1994 Alexandre Julliard
14  * Copyright 2002 Bill Medland
15  *
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 2 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29  */
30 
31 /* INCLUDES *******************************************************************/
32 
33 #include <user32.h>
34 
35 #include <wine/debug.h>
36 
37 WINE_DEFAULT_DEBUG_CHANNEL(user32);
38 
39 /* GLOBALS *******************************************************************/
40 
41 /* These tables are used in:
42  * UITOOLS_DrawDiagEdge()
43  * UITOOLS_DrawRectEdge()
44  */
45 static const signed char LTInnerNormal[] = {
46             -1,           -1,                 -1,                 -1,
47             -1,           COLOR_BTNHIGHLIGHT, COLOR_BTNHIGHLIGHT, -1,
48             -1,           COLOR_3DDKSHADOW,   COLOR_3DDKSHADOW,   -1,
49             -1,           -1,                 -1,                 -1
50 };
51 
52 static const signed char LTOuterNormal[] = {
53             -1,                 COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1,
54             COLOR_BTNHIGHLIGHT, COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1,
55             COLOR_3DDKSHADOW,   COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1,
56             -1,                 COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1
57 };
58 
59 static const signed char RBInnerNormal[] = {
60             -1,           -1,                -1,              -1,
61             -1,           COLOR_BTNSHADOW,   COLOR_BTNSHADOW, -1,
62             -1,           COLOR_3DLIGHT,     COLOR_3DLIGHT,   -1,
63             -1,           -1,                -1,              -1
64 };
65 
66 static const signed char RBOuterNormal[] = {
67             -1,              COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1,
68             COLOR_BTNSHADOW, COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1,
69             COLOR_3DLIGHT,   COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1,
70             -1,              COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1
71 };
72 
73 static const signed char LTInnerSoft[] = {
74             -1,                  -1,                -1,              -1,
75             -1,                  COLOR_3DLIGHT,     COLOR_3DLIGHT,   -1,
76             -1,                  COLOR_BTNSHADOW,   COLOR_BTNSHADOW, -1,
77             -1,                  -1,                -1,              -1
78 };
79 
80 static const signed char LTOuterSoft[] = {
81             -1,              COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
82             COLOR_3DLIGHT,   COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
83             COLOR_BTNSHADOW, COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
84             -1,              COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1
85 };
86 
87 #define RBInnerSoft RBInnerNormal   /* These are the same */
88 #define RBOuterSoft RBOuterNormal
89 
90 static const signed char LTRBOuterMono[] = {
91             -1,           COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
92             COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
93             COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
94             COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
95 };
96 
97 static const signed char LTRBInnerMono[] = {
98             -1, -1,           -1,           -1,
99             -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
100             -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
101             -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
102 };
103 
104 static const signed char LTRBOuterFlat[] = {
105             -1,                COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
106             COLOR_BTNFACE,     COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
107             COLOR_BTNFACE,     COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
108             COLOR_BTNFACE,     COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
109 };
110 
111 static const signed char LTRBInnerFlat[] = {
112             -1, -1,              -1,              -1,
113             -1, COLOR_BTNFACE,     COLOR_BTNFACE,     COLOR_BTNFACE,
114             -1, COLOR_BTNFACE,     COLOR_BTNFACE,     COLOR_BTNFACE,
115             -1, COLOR_BTNFACE,     COLOR_BTNFACE,     COLOR_BTNFACE,
116 };
117 /* FUNCTIONS *****************************************************************/
118 
119 
120 HBRUSH WINAPI GetSysColorBrush(int nIndex);
121 
122 /* Ported from WINE20020904 */
123 /* Same as DrawEdge invoked with BF_DIAGONAL */
124 static BOOL IntDrawDiagEdge(HDC hdc, LPRECT rc, UINT uType, UINT uFlags)
125 {
126     POINT Points[4];
127     signed char InnerI, OuterI;
128     HPEN InnerPen, OuterPen;
129     POINT SavePoint;
130     HPEN SavePen;
131     int spx, spy;
132     int epx, epy;
133     int Width = rc->right - rc->left;
134     int Height= rc->bottom - rc->top;
135     int SmallDiam = Width > Height ? Height : Width;
136     BOOL retval = !(   ((uType & BDR_INNER) == BDR_INNER
137                         || (uType & BDR_OUTER) == BDR_OUTER)
138                        && !(uFlags & (BF_FLAT|BF_MONO)) );
139     int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
140             + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
141 
142     /* Init some vars */
143     OuterPen = InnerPen = (HPEN)GetStockObject(NULL_PEN);
144     SavePen = (HPEN)SelectObject(hdc, InnerPen);
145     spx = spy = epx = epy = 0; /* Satisfy the compiler... */
146 
147     /* Determine the colors of the edges */
148     if(uFlags & BF_MONO)
149     {
150         InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
151         OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
152     }
153     else if(uFlags & BF_FLAT)
154     {
155         InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
156         OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
157     }
158     else if(uFlags & BF_SOFT)
159     {
160         if(uFlags & BF_BOTTOM)
161         {
162             InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
163             OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
164         }
165         else
166         {
167             InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
168             OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
169         }
170     }
171     else
172     {
173         if(uFlags & BF_BOTTOM)
174         {
175             InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
176             OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
177         }
178         else
179         {
180             InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
181             OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
182         }
183     }
184 
185     if(InnerI != -1) InnerPen = GetStockObject(DC_PEN);
186     if(OuterI != -1) OuterPen = GetStockObject(DC_PEN);
187 
188     MoveToEx(hdc, 0, 0, &SavePoint);
189 
190     /* Don't ask me why, but this is what is visible... */
191     /* This must be possible to do much simpler, but I fail to */
192     /* see the logic in the MS implementation (sigh...). */
193     /* So, this might look a bit brute force here (and it is), but */
194     /* it gets the job done;) */
195 
196     switch(uFlags & BF_RECT)
197     {
198         case 0:
199         case BF_LEFT:
200         case BF_BOTTOM:
201         case BF_BOTTOMLEFT:
202             /* Left bottom endpoint */
203             epx = rc->left-1;
204             spx = epx + SmallDiam;
205             epy = rc->bottom;
206             spy = epy - SmallDiam;
207             break;
208 
209         case BF_TOPLEFT:
210         case BF_BOTTOMRIGHT:
211             /* Left top endpoint */
212             epx = rc->left-1;
213             spx = epx + SmallDiam;
214             epy = rc->top-1;
215             spy = epy + SmallDiam;
216             break;
217 
218         case BF_TOP:
219         case BF_RIGHT:
220         case BF_TOPRIGHT:
221         case BF_RIGHT|BF_LEFT:
222         case BF_RIGHT|BF_LEFT|BF_TOP:
223         case BF_BOTTOM|BF_TOP:
224         case BF_BOTTOM|BF_TOP|BF_LEFT:
225         case BF_BOTTOMRIGHT|BF_LEFT:
226         case BF_BOTTOMRIGHT|BF_TOP:
227         case BF_RECT:
228             /* Right top endpoint */
229             spx = rc->left;
230             epx = spx + SmallDiam;
231             spy = rc->bottom-1;
232             epy = spy - SmallDiam;
233             break;
234     }
235 
236     MoveToEx(hdc, spx, spy, NULL);
237     SelectObject(hdc, OuterPen);
238     SetDCPenColor(hdc, GetSysColor(OuterI));
239     LineTo(hdc, epx, epy);
240 
241     SelectObject(hdc, InnerPen);
242     SetDCPenColor(hdc, GetSysColor(InnerI));
243 
244     switch(uFlags & (BF_RECT|BF_DIAGONAL))
245     {
246         case BF_DIAGONAL_ENDBOTTOMLEFT:
247         case (BF_DIAGONAL|BF_BOTTOM):
248         case BF_DIAGONAL:
249         case (BF_DIAGONAL|BF_LEFT):
250             MoveToEx(hdc, spx-1, spy, NULL);
251             LineTo(hdc, epx, epy-1);
252             Points[0].x = spx-add;
253             Points[0].y = spy;
254             Points[1].x = rc->left;
255             Points[1].y = rc->top;
256             Points[2].x = epx+1;
257             Points[2].y = epy-1-add;
258             Points[3] = Points[2];
259             break;
260 
261         case BF_DIAGONAL_ENDBOTTOMRIGHT:
262             MoveToEx(hdc, spx-1, spy, NULL);
263             LineTo(hdc, epx, epy+1);
264             Points[0].x = spx-add;
265             Points[0].y = spy;
266             Points[1].x = rc->left;
267             Points[1].y = rc->bottom-1;
268             Points[2].x = epx+1;
269             Points[2].y = epy+1+add;
270             Points[3] = Points[2];
271             break;
272 
273         case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP):
274         case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
275         case BF_DIAGONAL_ENDTOPRIGHT:
276         case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
277             MoveToEx(hdc, spx+1, spy, NULL);
278             LineTo(hdc, epx, epy+1);
279             Points[0].x = epx-1;
280             Points[0].y = epy+1+add;
281             Points[1].x = rc->right-1;
282             Points[1].y = rc->top+add;
283             Points[2].x = rc->right-1;
284             Points[2].y = rc->bottom-1;
285             Points[3].x = spx+add;
286             Points[3].y = spy;
287             break;
288 
289         case BF_DIAGONAL_ENDTOPLEFT:
290             MoveToEx(hdc, spx, spy-1, NULL);
291             LineTo(hdc, epx+1, epy);
292             Points[0].x = epx+1+add;
293             Points[0].y = epy+1;
294             Points[1].x = rc->right-1;
295             Points[1].y = rc->top;
296             Points[2].x = rc->right-1;
297             Points[2].y = rc->bottom-1-add;
298             Points[3].x = spx;
299             Points[3].y = spy-add;
300             break;
301 
302         case (BF_DIAGONAL|BF_TOP):
303         case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
304         case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
305             MoveToEx(hdc, spx+1, spy-1, NULL);
306             LineTo(hdc, epx, epy);
307             Points[0].x = epx-1;
308             Points[0].y = epy+1;
309             Points[1].x = rc->right-1;
310             Points[1].y = rc->top;
311             Points[2].x = rc->right-1;
312             Points[2].y = rc->bottom-1-add;
313             Points[3].x = spx+add;
314             Points[3].y = spy-add;
315             break;
316 
317         case (BF_DIAGONAL|BF_RIGHT):
318         case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
319         case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
320             MoveToEx(hdc, spx, spy, NULL);
321             LineTo(hdc, epx-1, epy+1);
322             Points[0].x = spx;
323             Points[0].y = spy;
324             Points[1].x = rc->left;
325             Points[1].y = rc->top+add;
326             Points[2].x = epx-1-add;
327             Points[2].y = epy+1+add;
328             Points[3] = Points[2];
329             break;
330     }
331 
332     /* Fill the interior if asked */
333     if((uFlags & BF_MIDDLE) && retval)
334     {
335         HBRUSH hbsave;
336         HPEN hpsave;
337         hbsave = (HBRUSH)SelectObject(hdc, GetStockObject(DC_BRUSH));
338         hpsave = (HPEN)SelectObject(hdc, GetStockObject(DC_PEN));
339         SetDCBrushColor(hdc, GetSysColor(uFlags & BF_MONO ? COLOR_WINDOW : COLOR_BTNFACE));
340         SetDCPenColor(hdc, GetSysColor(uFlags & BF_MONO ? COLOR_WINDOW : COLOR_BTNFACE));
341         Polygon(hdc, Points, 4);
342         SelectObject(hdc, hbsave);
343         SelectObject(hdc, hpsave);
344     }
345 
346     /* Adjust rectangle if asked */
347     if(uFlags & BF_ADJUST)
348     {
349         if(uFlags & BF_LEFT)   rc->left   += add;
350         if(uFlags & BF_RIGHT)  rc->right  -= add;
351         if(uFlags & BF_TOP)    rc->top    += add;
352         if(uFlags & BF_BOTTOM) rc->bottom -= add;
353     }
354 
355     /* Cleanup */
356     SelectObject(hdc, SavePen);
357     MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
358 
359     return retval;
360 }
361 
362 /* Ported from WINE20020904 */
363 /* Same as DrawEdge invoked without BF_DIAGONAL
364  *
365  * 23-Nov-1997: Changed by Bertho Stultiens
366  * The width parameter sets the width of each outer and inner edge.
367  *
368  * Well, I started testing this and found out that there are a few things
369  * that weren't quite as win95. The following rewrite should reproduce
370  * win95 results completely.
371  * The colorselection is table-driven to avoid awfull if-statements.
372  * The table below show the color settings.
373  *
374  * Pen selection table for uFlags = 0
375  *
376  * uType |  LTI  |  LTO  |  RBI  |  RBO
377  * ------+-------+-------+-------+-------
378  *  0000 |   x   |   x   |   x   |   x
379  *  0001 |   x   |  22   |   x   |  21
380  *  0010 |   x   |  16   |   x   |  20
381  *  0011 |   x   |   x   |   x   |   x
382  * ------+-------+-------+-------+-------
383  *  0100 |   x   |  20   |   x   |  16
384  *  0101 |  20   |  22   |  16   |  21
385  *  0110 |  20   |  16   |  16   |  20
386  *  0111 |   x   |   x   |   x   |   x
387  * ------+-------+-------+-------+-------
388  *  1000 |   x   |  21   |   x   |  22
389  *  1001 |  21   |  22   |  22   |  21
390  *  1010 |  21   |  16   |  22   |  20
391  *  1011 |   x   |   x   |   x   |   x
392  * ------+-------+-------+-------+-------
393  *  1100 |   x   |   x   |   x   |   x
394  *  1101 |   x   | x (22)|   x   | x (21)
395  *  1110 |   x   | x (16)|   x   | x (20)
396  *  1111 |   x   |   x   |   x   |   x
397  *
398  * Pen selection table for uFlags = BF_SOFT
399  *
400  * uType |  LTI  |  LTO  |  RBI  |  RBO
401  * ------+-------+-------+-------+-------
402  *  0000 |   x   |   x   |   x   |   x
403  *  0001 |   x   |  20   |   x   |  21
404  *  0010 |   x   |  21   |   x   |  20
405  *  0011 |   x   |   x   |   x   |   x
406  * ------+-------+-------+-------+-------
407  *  0100 |   x   |  22   |   x   |  16
408  *  0101 |  22   |  20   |  16   |  21
409  *  0110 |  22   |  21   |  16   |  20
410  *  0111 |   x   |   x   |   x   |   x
411  * ------+-------+-------+-------+-------
412  *  1000 |   x   |  16   |   x   |  22
413  *  1001 |  16   |  20   |  22   |  21
414  *  1010 |  16   |  21   |  22   |  20
415  *  1011 |   x   |   x   |   x   |   x
416  * ------+-------+-------+-------+-------
417  *  1100 |   x   |   x   |   x   |   x
418  *  1101 |   x   | x (20)|   x   | x (21)
419  *  1110 |   x   | x (21)|   x   | x (20)
420  *  1111 |   x   |   x   |   x   |   x
421  *
422  * x = don't care; (n) = is what win95 actually uses
423  * LTI = left Top Inner line
424  * LTO = left Top Outer line
425  * RBI = Right Bottom Inner line
426  * RBO = Right Bottom Outer line
427  * 15 = COLOR_BTNFACE
428  * 16 = COLOR_BTNSHADOW
429  * 20 = COLOR_BTNHIGHLIGHT
430  * 21 = COLOR_3DDKSHADOW
431  * 22 = COLOR_3DLIGHT
432  */
433 static BOOL IntDrawRectEdge(HDC hdc, LPRECT rc, UINT uType, UINT uFlags, UINT width)
434 {
435     signed char LTInnerI, LTOuterI;
436     signed char RBInnerI, RBOuterI;
437     HBRUSH lti_brush, lto_brush, rbi_brush, rbo_brush;
438     RECT InnerRect = *rc, fill_rect;
439     int lbi_offset = 0, lti_offset = 0, rti_offset = 0, rbi_offset = 0;
440     BOOL retval = !(   ((uType & BDR_INNER) == BDR_INNER
441                        || (uType & BDR_OUTER) == BDR_OUTER)
442                       && !(uFlags & (BF_FLAT|BF_MONO)) );
443 
444     lti_brush = lto_brush = rbi_brush = rbo_brush = GetStockObject(NULL_BRUSH);
445 
446     /* Determine the colors of the edges */
447     if(uFlags & BF_MONO)
448     {
449         LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
450         LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
451     }
452     else if(uFlags & BF_FLAT)
453     {
454         LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
455         LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
456 
457         /* Bertho Stultiens states above that this function exactly matches win95
458          * In win98 BF_FLAT rectangles have an inner border same color as the
459         * middle (COLOR_BTNFACE). I believe it's the same for win95 but since
460         * I don't know I go with Bertho and just sets it for win98 until proven
461         * otherwise.
462         *                                          Dennis Björklund, 10 June, 99
463         */
464 	if( LTInnerI != -1 ) LTInnerI = RBInnerI = COLOR_BTNFACE;
465     }
466     else if(uFlags & BF_SOFT)
467     {
468         LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
469         LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
470         RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
471         RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
472     }
473     else
474     {
475         LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
476         LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
477         RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
478         RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
479     }
480 
481     if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT)   lbi_offset = width;
482     if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT)       rti_offset = width;
483     if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) rbi_offset = width;
484     if((uFlags & BF_TOPLEFT) == BF_TOPLEFT)         lti_offset = width;
485 
486     if(LTInnerI != -1) lti_brush = GetSysColorBrush(LTInnerI);
487     if(LTOuterI != -1) lto_brush = GetSysColorBrush(LTOuterI);
488     if(RBInnerI != -1) rbi_brush = GetSysColorBrush(RBInnerI);
489     if(RBOuterI != -1) rbo_brush = GetSysColorBrush(RBOuterI);
490 
491     /* Draw the outer edge */
492     if(uFlags & BF_TOP)
493     {
494         fill_rect = InnerRect;
495         fill_rect.bottom = fill_rect.top + width;
496         FillRect( hdc, &fill_rect, lto_brush );
497     }
498     if(uFlags & BF_LEFT)
499     {
500         fill_rect = InnerRect;
501         fill_rect.right = fill_rect.left + width;
502         FillRect( hdc, &fill_rect, lto_brush );
503     }
504     if(uFlags & BF_BOTTOM)
505     {
506         fill_rect = InnerRect;
507         fill_rect.top = fill_rect.bottom - width;
508         FillRect( hdc, &fill_rect, rbo_brush );
509     }
510     if(uFlags & BF_RIGHT)
511     {
512         fill_rect = InnerRect;
513         fill_rect.left = fill_rect.right - width;
514         FillRect( hdc, &fill_rect, rbo_brush );
515     }
516 
517     /* Draw the inner edge */
518     if(uFlags & BF_TOP)
519     {
520         SetRect( &fill_rect, InnerRect.left + lti_offset, InnerRect.top + width,
521                  InnerRect.right - rti_offset, InnerRect.top + 2 * width );
522         FillRect( hdc, &fill_rect, lti_brush );
523     }
524     if(uFlags & BF_LEFT)
525     {
526         SetRect( &fill_rect, InnerRect.left + width, InnerRect.top + lti_offset,
527                  InnerRect.left + 2 * width, InnerRect.bottom - lbi_offset );
528         FillRect( hdc, &fill_rect, lti_brush );
529     }
530     if(uFlags & BF_BOTTOM)
531     {
532         SetRect( &fill_rect, InnerRect.left + lbi_offset, InnerRect.bottom - 2 * width,
533                  InnerRect.right - rbi_offset, InnerRect.bottom - width );
534         FillRect( hdc, &fill_rect, rbi_brush );
535     }
536     if(uFlags & BF_RIGHT)
537     {
538         SetRect( &fill_rect, InnerRect.right - 2 * width, InnerRect.top + rti_offset,
539                  InnerRect.right - width, InnerRect.bottom - rbi_offset );
540         FillRect( hdc, &fill_rect, rbi_brush );
541     }
542 
543     if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
544     {
545         int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? width : 0)
546                 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? width : 0);
547 
548         if(uFlags & BF_LEFT)   InnerRect.left   += add;
549         if(uFlags & BF_RIGHT)  InnerRect.right  -= add;
550         if(uFlags & BF_TOP)    InnerRect.top    += add;
551         if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
552 
553         if((uFlags & BF_MIDDLE) && retval)
554 	{
555             FillRect(hdc, &InnerRect, GetSysColorBrush(uFlags & BF_MONO ?
556 						       COLOR_WINDOW : COLOR_BTNFACE));
557 	}
558 
559 	if(uFlags & BF_ADJUST)
560 	    *rc = InnerRect;
561     }
562 
563     return retval;
564 }
565 
566 /* Ported from WINE20020904 */
567 /* Utility to create a square rectangle and returning the width */
568 static int UITOOLS_MakeSquareRect(LPRECT src, LPRECT dst)
569 {
570     int Width  = src->right - src->left;
571     int Height = src->bottom - src->top;
572     int SmallDiam = Width > Height ? Height : Width;
573 
574     *dst = *src;
575 
576     /* Make it a square box */
577     if(Width < Height)      /* SmallDiam == Width */
578     {
579         dst->top += (Height-Width)/2;
580         dst->bottom = dst->top + SmallDiam;
581     }
582     else if(Width > Height) /* SmallDiam == Height */
583     {
584         dst->left += (Width-Height)/2;
585         dst->right = dst->left + SmallDiam;
586     }
587 
588     return SmallDiam;
589 }
590 
591 /* Ported from WINE20020904 */
592 static void UITOOLS_DrawCheckedRect( HDC dc, LPRECT rect )
593 {
594     if(GetSysColor(COLOR_BTNHIGHLIGHT) == RGB(255, 255, 255))
595     {
596         HBRUSH hbsave;
597         COLORREF bg;
598 
599         FillRect(dc, rect, GetSysColorBrush(COLOR_BTNFACE));
600         bg = SetBkColor(dc, RGB(255, 255, 255));
601         hbsave = (HBRUSH)SelectObject(dc, gpsi->hbrGray);
602         PatBlt(dc, rect->left, rect->top, rect->right-rect->left, rect->bottom-rect->top, 0x00FA0089);
603         SelectObject(dc, hbsave);
604         SetBkColor(dc, bg);
605     }
606     else
607     {
608         FillRect(dc, rect, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
609     }
610 }
611 
612 /* Ported from WINE20020904 */
613 /* Draw a push button coming from DrawFrameControl()
614  *
615  * Does a pretty good job in emulating MS behavior. Some quirks are
616  * however there because MS uses a TrueType font (Marlett) to draw
617  * the buttons.
618  *
619  * FIXME: This looks a little bit strange, needs to be rewritten completely
620  * (several quirks with adjust, DFCS_CHECKED aso)
621  */
622 static BOOL UITOOLS95_DFC_ButtonPush(HDC dc, LPRECT r, UINT uFlags)
623 {
624     UINT edge;
625     RECT myr = *r;
626 
627     if(uFlags & (DFCS_PUSHED | DFCS_CHECKED | DFCS_FLAT))
628         edge = EDGE_SUNKEN;
629     else
630         edge = EDGE_RAISED;
631 
632     if(uFlags & DFCS_CHECKED)
633     {
634         if(uFlags & DFCS_MONO)
635             IntDrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST, 1);
636         else
637             IntDrawRectEdge(dc, &myr, edge, (uFlags&DFCS_FLAT)|BF_RECT|BF_SOFT|BF_ADJUST, 1);
638 
639         UITOOLS_DrawCheckedRect( dc, &myr );
640     }
641     else
642     {
643         if(uFlags & DFCS_MONO)
644         {
645             IntDrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST, 1);
646             FillRect(dc, &myr, GetSysColorBrush(COLOR_BTNFACE));
647         }
648         else
649         {
650             IntDrawRectEdge(dc, r, edge, (uFlags&DFCS_FLAT) | BF_MIDDLE | BF_RECT | BF_SOFT, 1);
651         }
652     }
653 
654     /* Adjust rectangle if asked */
655     if(uFlags & DFCS_ADJUSTRECT)
656         InflateRect(r, -2, -2);
657 
658     return TRUE;
659 }
660 
661 static BOOL UITOOLS95_DFC_ButtonCheckRadio(HDC dc, LPRECT r, UINT uFlags, BOOL Radio)
662 {
663     LOGFONTW lf;
664     HFONT hFont, hOldFont;
665     int i;
666     TCHAR OutRight, OutLeft, InRight, InLeft, Center;
667     INT X, Y, Width, Height, Shorter;
668     INT BkMode = GetBkMode(dc);
669     COLORREF TextColor = GetTextColor(dc);
670 
671     Width = r->right - r->left;
672     Height = r->bottom - r->top;
673     Shorter = (Width < Height) ? Width : Height;
674     X = r->left + (Width - Shorter) / 2;
675     Y = r->top + (Height - Shorter) / 2;
676 
677     if (Radio)
678     {
679         OutRight = 'j'; // Outer right
680         OutLeft  = 'k'; // Outer left
681         InRight  = 'l'; // inner left
682         InLeft   = 'm'; // inner right
683         Center   = 'n'; // center
684     }
685     else
686     {
687         OutRight = 'c'; // Outer right
688         OutLeft  = 'd'; // Outer left
689         InRight  = 'e'; // inner left
690         InLeft   = 'f'; // inner right
691         Center   = 'g'; // center
692     }
693 
694     ZeroMemory(&lf, sizeof(LOGFONTW));
695     lf.lfHeight = Shorter;
696     lf.lfCharSet = DEFAULT_CHARSET;
697     lstrcpy(lf.lfFaceName, TEXT("Marlett"));
698     if (Radio && ((uFlags & 0xFF) == DFCS_BUTTONRADIOMASK))
699     {
700         lf.lfQuality = NONANTIALIASED_QUALITY;
701     }
702     hFont = CreateFontIndirect(&lf);
703     hOldFont = SelectObject(dc, hFont);
704 
705     if (Radio && ((uFlags & 0xFF) == DFCS_BUTTONRADIOMASK))
706     {
707 #if 1
708         // FIXME: improve font rendering
709         RECT Rect;
710         HGDIOBJ hbrOld, hpenOld;
711         FillRect(dc, r, (HBRUSH)GetStockObject(WHITE_BRUSH));
712         SetRect(&Rect, X, Y, X + Shorter, Y + Shorter);
713         InflateRect(&Rect, -(Shorter * 8) / 54, -(Shorter * 8) / 54);
714         hbrOld = SelectObject(dc, GetStockObject(BLACK_BRUSH));
715         hpenOld = SelectObject(dc, GetStockObject(NULL_PEN));
716         Ellipse(dc, Rect.left, Rect.top, Rect.right, Rect.bottom);
717         SelectObject(dc, hbrOld);
718         SelectObject(dc, hpenOld);
719 #else
720         SetBkMode(dc, OPAQUE);
721         SetBkColor(dc, RGB(255, 255, 255));
722         SetTextColor(dc, RGB(0, 0, 0));
723         TextOut(dc, X, Y, &Center, 1);
724         SetBkMode(dc, TRANSPARENT);
725         TextOut(dc, X, Y, &OutRight, 1);
726         TextOut(dc, X, Y, &OutLeft, 1);
727         TextOut(dc, X, Y, &InRight, 1);
728         TextOut(dc, X, Y, &InLeft, 1);
729 #endif
730     }
731     else
732     {
733         SetBkMode(dc, TRANSPARENT);
734 
735         /* Center section, white for active, grey for inactive */
736         if ((uFlags & (DFCS_INACTIVE | DFCS_PUSHED)))
737             i = COLOR_BTNFACE;
738         else
739             i = COLOR_WINDOW;
740         SetTextColor(dc, GetSysColor(i));
741         TextOut(dc, X, Y, &Center, 1);
742 
743         if (uFlags & (DFCS_FLAT | DFCS_MONO))
744         {
745             SetTextColor(dc, GetSysColor(COLOR_WINDOWFRAME));
746             TextOut(dc, X, Y, &OutRight, 1);
747             TextOut(dc, X, Y, &OutLeft, 1);
748             TextOut(dc, X, Y, &InRight, 1);
749             TextOut(dc, X, Y, &InLeft, 1);
750         }
751         else
752         {
753             SetTextColor(dc, GetSysColor(COLOR_BTNSHADOW));
754             TextOut(dc, X, Y, &OutRight, 1);
755             SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
756             TextOut(dc, X, Y, &OutLeft, 1);
757             SetTextColor(dc, GetSysColor(COLOR_3DDKSHADOW));
758             TextOut(dc, X, Y, &InRight, 1);
759             SetTextColor(dc, GetSysColor(COLOR_3DLIGHT));
760             TextOut(dc, X, Y, &InLeft, 1);
761         }
762 
763         if (uFlags & DFCS_CHECKED)
764         {
765             TCHAR Check = (Radio) ? 'i' : 'b';
766 
767             SetTextColor(dc, GetSysColor(COLOR_WINDOWTEXT));
768             TextOut(dc, X, Y, &Check, 1);
769         }
770     }
771 
772     SelectObject(dc, hOldFont);
773     DeleteObject(hFont);
774 
775     SetTextColor(dc, TextColor);
776     SetBkMode(dc, BkMode);
777 
778     return TRUE;
779 }
780 
781 /* Ported from WINE20020904 */
782 static BOOL UITOOLS95_DrawFrameButton(HDC hdc, LPRECT rc, UINT uState)
783 {
784     switch(uState & 0xff)
785     {
786         case DFCS_BUTTONPUSH:
787             return UITOOLS95_DFC_ButtonPush(hdc, rc, uState);
788 
789         case DFCS_BUTTONCHECK:
790         case DFCS_BUTTON3STATE:
791             return UITOOLS95_DFC_ButtonCheckRadio(hdc, rc, uState, FALSE);
792 
793         case DFCS_BUTTONRADIOIMAGE:
794         case DFCS_BUTTONRADIOMASK:
795         case DFCS_BUTTONRADIO:
796             return UITOOLS95_DFC_ButtonCheckRadio(hdc, rc, uState, TRUE);
797 
798 /*
799         default:
800             DbgPrint("Invalid button state=0x%04x\n", uState);
801 */
802     }
803 
804     return FALSE;
805 }
806 
807 static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
808 {
809     LOGFONTW lf;
810     HFONT hFont, hOldFont;
811     COLORREF clrsave;
812     RECT myr;
813     INT bkmode;
814     TCHAR Symbol;
815     switch(uFlags & 0xff)
816     {
817         case DFCS_CAPTIONCLOSE:
818 		Symbol = 'r';
819 		break;
820         case DFCS_CAPTIONHELP:
821 		Symbol = 's';
822 		break;
823         case DFCS_CAPTIONMIN:
824 		Symbol = '0';
825 		break;
826         case DFCS_CAPTIONMAX:
827 		Symbol = '1';
828 		break;
829         case DFCS_CAPTIONRESTORE:
830 		Symbol = '2';
831 		break;
832         default:
833              WARN("Invalid caption; flags=0x%04x\n", uFlags);
834              return FALSE;
835     }
836     IntDrawRectEdge(dc,r,(uFlags&DFCS_PUSHED) ? EDGE_SUNKEN : EDGE_RAISED, BF_RECT | BF_MIDDLE | BF_SOFT, 1);
837     ZeroMemory(&lf, sizeof(LOGFONTW));
838     UITOOLS_MakeSquareRect(r, &myr);
839     myr.left += 1;
840     myr.top += 1;
841     myr.right -= 1;
842     myr.bottom -= 1;
843     if(uFlags & DFCS_PUSHED)
844        OffsetRect(&myr,1,1);
845     lf.lfHeight = myr.bottom - myr.top;
846     lf.lfWidth = 0;
847     lf.lfWeight = FW_NORMAL;
848     lf.lfCharSet = DEFAULT_CHARSET;
849     lstrcpy(lf.lfFaceName, TEXT("Marlett"));
850     hFont = CreateFontIndirect(&lf);
851     /* save font and text color */
852     hOldFont = SelectObject(dc, hFont);
853     clrsave = GetTextColor(dc);
854     bkmode = GetBkMode(dc);
855     /* set color and drawing mode */
856     SetBkMode(dc, TRANSPARENT);
857     if(uFlags & DFCS_INACTIVE)
858     {
859         /* draw shadow */
860         SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
861         TextOut(dc, myr.left + 1, myr.top + 1, &Symbol, 1);
862     }
863     SetTextColor(dc, GetSysColor((uFlags & DFCS_INACTIVE) ? COLOR_BTNSHADOW : COLOR_BTNTEXT));
864     /* draw selected symbol */
865     TextOut(dc, myr.left, myr.top, &Symbol, 1);
866     /* restore previous settings */
867     SetTextColor(dc, clrsave);
868     SelectObject(dc, hOldFont);
869     SetBkMode(dc, bkmode);
870     DeleteObject(hFont);
871     return TRUE;
872 }
873 
874 static BOOL UITOOLS95_DrawFrameScroll(HDC dc, LPRECT r, UINT uFlags)
875 {
876     LOGFONTW lf;
877     HFONT hFont, hOldFont;
878     COLORREF clrsave;
879     RECT myr;
880     INT bkmode;
881     TCHAR Symbol;
882     switch(uFlags & 0xff)
883     {
884         case DFCS_SCROLLCOMBOBOX:
885         case DFCS_SCROLLDOWN:
886 		Symbol = '6';
887 		break;
888 
889 	case DFCS_SCROLLUP:
890 		Symbol = '5';
891 		break;
892 
893 	case DFCS_SCROLLLEFT:
894 		Symbol = '3';
895 		break;
896 
897 	case DFCS_SCROLLRIGHT:
898 		Symbol = '4';
899 		break;
900 
901 	case DFCS_SCROLLSIZEGRIP:
902 	case DFCS_SCROLLSIZEGRIPRIGHT:
903 		ZeroMemory(&lf, sizeof(LOGFONTW));
904 		UITOOLS_MakeSquareRect(r, &myr);
905 		lf.lfHeight = myr.bottom - myr.top;
906 		lf.lfWidth = 0;
907 		lf.lfWeight = FW_NORMAL;
908 		lf.lfCharSet = DEFAULT_CHARSET;
909 		lstrcpy(lf.lfFaceName, TEXT("Marlett"));
910 		hFont = CreateFontIndirect(&lf);
911 		/* save font and text color */
912 		hOldFont = SelectObject(dc, hFont);
913 		clrsave = GetTextColor(dc);
914 		bkmode = GetBkMode(dc);
915 		/* set color and drawing mode */
916 		SetBkMode(dc, TRANSPARENT);
917 		if (!(uFlags & (DFCS_MONO | DFCS_FLAT)))
918 		{
919 			SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
920 			/* draw selected symbol */
921 			Symbol = ((uFlags & 0xff) == DFCS_SCROLLSIZEGRIP) ? 'o' : 'x';
922 			TextOut(dc, myr.left, myr.top, &Symbol, 1);
923 			SetTextColor(dc, GetSysColor(COLOR_BTNSHADOW));
924 		} else
925 			SetTextColor(dc, GetSysColor(COLOR_WINDOWFRAME));
926 		/* draw selected symbol */
927 		Symbol = ((uFlags & 0xff) == DFCS_SCROLLSIZEGRIP) ? 'p' : 'y';
928 		TextOut(dc, myr.left, myr.top, &Symbol, 1);
929 		/* restore previous settings */
930 		SetTextColor(dc, clrsave);
931 		SelectObject(dc, hOldFont);
932 		SetBkMode(dc, bkmode);
933 		DeleteObject(hFont);
934             return TRUE;
935 	default:
936 	    WARN("Invalid scroll; flags=0x%04x\n", uFlags);
937             return FALSE;
938     }
939     IntDrawRectEdge(dc, r, (uFlags & DFCS_PUSHED) ? EDGE_SUNKEN : EDGE_RAISED, (uFlags&DFCS_FLAT) | BF_MIDDLE | BF_RECT, 1);
940     ZeroMemory(&lf, sizeof(LOGFONTW));
941     UITOOLS_MakeSquareRect(r, &myr);
942     myr.left += 1;
943     myr.top += 1;
944     myr.right -= 1;
945     myr.bottom -= 1;
946     if(uFlags & DFCS_PUSHED)
947        OffsetRect(&myr,1,1);
948     lf.lfHeight = myr.bottom - myr.top;
949     lf.lfWidth = 0;
950     lf.lfWeight = FW_NORMAL;
951     lf.lfCharSet = DEFAULT_CHARSET;
952     lstrcpy(lf.lfFaceName, TEXT("Marlett"));
953     hFont = CreateFontIndirect(&lf);
954     /* save font and text color */
955     hOldFont = SelectObject(dc, hFont);
956     clrsave = GetTextColor(dc);
957     bkmode = GetBkMode(dc);
958     /* set color and drawing mode */
959     SetBkMode(dc, TRANSPARENT);
960     if(uFlags & DFCS_INACTIVE)
961     {
962         /* draw shadow */
963         SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
964         TextOut(dc, myr.left + 1, myr.top + 1, &Symbol, 1);
965     }
966     SetTextColor(dc, GetSysColor((uFlags & DFCS_INACTIVE) ? COLOR_BTNSHADOW : COLOR_BTNTEXT));
967     /* draw selected symbol */
968     TextOut(dc, myr.left, myr.top, &Symbol, 1);
969     /* restore previous settings */
970     SetTextColor(dc, clrsave);
971     SelectObject(dc, hOldFont);
972     SetBkMode(dc, bkmode);
973     DeleteObject(hFont);
974     return TRUE;
975 }
976 
977 static BOOL UITOOLS95_DrawFrameMenu(HDC dc, LPRECT r, UINT uFlags)
978 {
979     LOGFONTW lf;
980     HFONT hFont, hOldFont;
981     TCHAR Symbol;
982     switch(uFlags & 0xff)
983     {
984         case DFCS_MENUARROWUP:
985             Symbol = '5';
986             break;
987 
988         case DFCS_MENUARROWDOWN:
989             Symbol = '6';
990             break;
991 
992         case DFCS_MENUARROW:
993             Symbol = '8';
994             break;
995 
996         case DFCS_MENUARROWRIGHT:
997 	    Symbol = 'w'; // FIXME: needs to confirm
998 	    break;
999 
1000         case DFCS_MENUBULLET:
1001             Symbol = 'h';
1002             break;
1003 
1004         case DFCS_MENUCHECK:
1005             Symbol = 'a';
1006             break;
1007 
1008         default:
1009             WARN("Invalid menu; flags=0x%04x\n", uFlags);
1010             return FALSE;
1011     }
1012     /* acquire ressources only if valid menu */
1013     ZeroMemory(&lf, sizeof(LOGFONTW));
1014     lf.lfHeight = r->bottom - r->top;
1015     lf.lfWidth = 0;
1016     lf.lfWeight = FW_NORMAL;
1017     lf.lfCharSet = DEFAULT_CHARSET;
1018     lstrcpy(lf.lfFaceName, TEXT("Marlett"));
1019     hFont = CreateFontIndirect(&lf);
1020     /* save font */
1021     hOldFont = SelectObject(dc, hFont);
1022 
1023     if ((uFlags & 0xff) == DFCS_MENUARROWUP ||
1024         (uFlags & 0xff) == DFCS_MENUARROWDOWN )
1025     {
1026 #if 0
1027        if (uFlags & DFCS_INACTIVE)
1028        {
1029            /* draw shadow */
1030            SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
1031            TextOut(dc, r->left + 1, r->top + 1, &Symbol, 1);
1032        }
1033 #endif
1034        SetTextColor(dc, GetSysColor((uFlags & DFCS_INACTIVE) ? COLOR_BTNSHADOW : COLOR_BTNTEXT));
1035     }
1036     /* draw selected symbol */
1037     TextOut(dc, r->left, r->top, &Symbol, 1);
1038     /* restore previous settings */
1039     SelectObject(dc, hOldFont);
1040     DeleteObject(hFont);
1041     return TRUE;
1042 }
1043 
1044 BOOL
1045 WINAPI
1046 IntGrayString(
1047     HDC hDC,
1048     HBRUSH hBrush,
1049     GRAYSTRINGPROC lpOutputFunc,
1050     LPARAM lpData,
1051     int nCount,
1052     int X,
1053     int Y,
1054     int nWidth,
1055     int nHeight,
1056     BOOL unicode)
1057 {
1058     // AG: Mostly implemented, but probably won't work properly or return
1059     // correct error codes. I doubt it grays strings either... Untested!
1060 
1061     BOOL    success = FALSE;
1062     HBRUSH  hbsave;
1063     HDC     MemDC = NULL;
1064     HBITMAP MemBMP = NULL, OldBMP = NULL;
1065     HBRUSH  OldBrush = NULL;
1066     HFONT   OldFont = NULL;
1067     RECT    r;
1068     COLORREF ForeColor, BackColor;
1069 
1070     ForeColor = SetTextColor(hDC, RGB(0, 0, 0));
1071     BackColor = SetBkColor(hDC, RGB(255, 255, 255));
1072 
1073     if (! hBrush)
1074     {
1075         // The documentation is a little vague on what exactly should happen
1076         // here. Something about using the same brush for window text???
1077         hBrush = (HBRUSH) GetCurrentObject(hDC, OBJ_BRUSH);
1078     }
1079 
1080     if ((nCount == -1) && (! lpOutputFunc))
1081         return FALSE;
1082 
1083     if (! nCount)
1084     {
1085         // TODO: calculate the length (easy enough)
1086 
1087         if (unicode)
1088             nCount = lstrlenW((WCHAR*)lpData);
1089         else
1090             nCount = lstrlenA((CHAR*)lpData);
1091     }
1092 
1093     if (! nWidth || ! nHeight)
1094     {
1095         SIZE s;
1096         // TODO: calculate the rect
1097 
1098         if (unicode)
1099             success = GetTextExtentPoint32W(hDC, (WCHAR*) lpData, nCount, &s);
1100         else
1101             success = GetTextExtentPoint32A(hDC, (CHAR*) lpData, nCount, &s);
1102 
1103         if (! success) goto cleanup;
1104 
1105         if (! nWidth)   nWidth = s.cx;
1106         if (! nHeight)  nHeight = s.cy;
1107     }
1108 
1109     SetRect(&r, X, Y, X + nWidth, Y + nHeight);
1110 
1111     MemDC = CreateCompatibleDC(hDC);
1112     if (! MemDC) goto cleanup;
1113     MemBMP = CreateBitmap(nWidth, nHeight, 1, 1, NULL);
1114     if (! MemBMP) goto cleanup;
1115     OldBMP = SelectObject(MemDC, MemBMP);
1116     if (! OldBMP) goto cleanup;
1117     OldFont = SelectObject(MemDC, GetCurrentObject(hDC, OBJ_FONT));
1118     if (! OldFont) goto cleanup;
1119     OldBrush = SelectObject(MemDC, hBrush);
1120     if (! OldBrush) goto cleanup;
1121 
1122     if (! BitBlt(MemDC, 0, 0, nWidth, nHeight, hDC, X, Y, SRCCOPY)) goto cleanup;
1123 
1124     SetTextColor(MemDC, RGB(255, 255, 255));
1125     SetBkColor(MemDC, RGB(0, 0, 0));
1126 
1127     if (lpOutputFunc)
1128     {
1129         success = lpOutputFunc(MemDC, lpData, nCount); // Set brush etc first?
1130 
1131         if ((nCount == -1) && (! success))
1132         {
1133             // Don't gray (documented behaviour)
1134             success = (BOOL) BitBlt(hDC, X, Y, nWidth, nHeight, MemDC, 0, 0, SRCCOPY);
1135             goto cleanup;
1136         }
1137     }
1138     else
1139     {
1140         if (unicode)
1141             success = TextOutW(MemDC, 0, 0, (WCHAR*) lpData, nCount);
1142         else
1143             success = TextOutA(MemDC, 0, 0, (CHAR*) lpData, nCount);
1144 
1145         if (! success) goto cleanup;
1146 
1147         hbsave = (HBRUSH)SelectObject(MemDC, gpsi->hbrGray);
1148         PatBlt(MemDC, 0, 0, nWidth, nHeight, 0x000A0329);
1149         SelectObject(MemDC, hbsave);
1150     }
1151 
1152     if (! BitBlt(hDC, X, Y, nWidth, nHeight, MemDC, 0, 0, SRCCOPY)) goto cleanup;
1153 
1154 cleanup:
1155     SetTextColor(hDC, ForeColor);
1156     SetBkColor(hDC, BackColor);
1157 
1158     if (MemDC)
1159     {
1160         if (OldFont) SelectObject(MemDC, OldFont);
1161         if (OldBrush) SelectObject(MemDC, OldBrush);
1162         if (OldBMP) SelectObject(MemDC, OldBMP);
1163         if (MemBMP) DeleteObject(MemBMP);
1164         DeleteDC(MemDC);
1165     }
1166 
1167     return success;
1168 }
1169 
1170 /**********************************************************************
1171  *          PAINTING_DrawStateJam
1172  *
1173  * Jams in the requested type in the dc
1174  */
1175 static BOOL PAINTING_DrawStateJam(HDC hdc, UINT opcode,
1176                                   DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
1177                                   LPRECT rc, UINT dtflags, BOOL unicode )
1178 {
1179     HDC memdc;
1180     HBITMAP hbmsave;
1181     BOOL retval;
1182     INT cx = rc->right - rc->left;
1183     INT cy = rc->bottom - rc->top;
1184 
1185     switch(opcode)
1186     {
1187         case DST_TEXT:
1188         case DST_PREFIXTEXT:
1189             if(unicode)
1190                 return DrawTextW(hdc, (LPWSTR)lp, (INT)wp, rc, dtflags);
1191             else
1192                 return DrawTextA(hdc, (LPSTR)lp, (INT)wp, rc, dtflags);
1193 
1194         case DST_ICON:
1195             return DrawIconEx(hdc, rc->left, rc->top, (HICON)lp, cx, cy, 0, NULL, DI_NORMAL);
1196 
1197         case DST_BITMAP:
1198             memdc = CreateCompatibleDC(hdc);
1199             if(!memdc)
1200                 return FALSE;
1201             hbmsave = (HBITMAP)SelectObject(memdc, (HBITMAP)lp);
1202             if(!hbmsave)
1203             {
1204                 DeleteDC(memdc);
1205                 return FALSE;
1206             }
1207             retval = BitBlt(hdc, rc->left, rc->top, cx, cy, memdc, 0, 0, SRCCOPY);
1208             SelectObject(memdc, hbmsave);
1209             DeleteDC(memdc);
1210             return retval;
1211 
1212         case DST_COMPLEX:
1213             if(func)
1214             {
1215                 BOOL bRet;
1216                 /* DRAWSTATEPROC assumes that it draws at the center of coordinates  */
1217 
1218                 OffsetViewportOrgEx(hdc, rc->left, rc->top, NULL);
1219                 bRet = func(hdc, lp, wp, cx, cy);
1220                 /* Restore origin */
1221                 OffsetViewportOrgEx(hdc, -rc->left, -rc->top, NULL);
1222                 return bRet;
1223             }
1224             else
1225             {
1226                 return FALSE;
1227             }
1228     }
1229     return FALSE;
1230 }
1231 
1232 static BOOL
1233 IntDrawState(HDC hdc, HBRUSH hbr, DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
1234              INT x, INT y, INT cx, INT cy, UINT flags, BOOL unicode)
1235 {
1236     HBITMAP hbm, hbmsave;
1237     HFONT hfsave;
1238     HBRUSH hbsave, hbrtmp = 0;
1239     HDC memdc;
1240     RECT rc;
1241     UINT dtflags = DT_NOCLIP;
1242     COLORREF fg, bg;
1243     UINT opcode = flags & 0xf;
1244     INT len = wp;
1245     BOOL retval, tmp;
1246     LOGFONTW lf;
1247     HFONT hFontOriginal, hNaaFont = NULL;
1248 
1249     if((opcode == DST_TEXT || opcode == DST_PREFIXTEXT) && !len)    /* The string is '\0' terminated */
1250     {
1251         if(unicode)
1252             len = lstrlenW((LPWSTR)lp);
1253         else
1254             len = lstrlenA((LPSTR)lp);
1255     }
1256 
1257     hFontOriginal = GetCurrentObject(hdc, OBJ_FONT);
1258     if (flags & (DSS_MONO | DSS_DISABLED))
1259     {
1260         /* Create a non-antialiased font */
1261         GetObjectW(hFontOriginal, sizeof(lf), &lf);
1262         lf.lfQuality = NONANTIALIASED_QUALITY;
1263         hNaaFont = CreateFontIndirectW(&lf);
1264     }
1265 
1266     /* Find out what size the image has if not given by caller */
1267     if(!cx || !cy)
1268     {
1269         SIZE s;
1270         BITMAP bm;
1271 
1272         switch(opcode)
1273         {
1274             case DST_TEXT:
1275             case DST_PREFIXTEXT:
1276                 if(unicode)
1277                     retval = GetTextExtentPoint32W(hdc, (LPWSTR)lp, len, &s);
1278                 else
1279                     retval = GetTextExtentPoint32A(hdc, (LPSTR)lp, len, &s);
1280                 if(!retval)
1281                     return FALSE;
1282                 break;
1283 
1284             case DST_ICON:
1285                 if(!get_icon_size((HICON)lp, &s))
1286                     return FALSE;
1287                 break;
1288 
1289             case DST_BITMAP:
1290                 if(!GetObjectW((HBITMAP)lp, sizeof(bm), &bm))
1291                     return FALSE;
1292                 s.cx = bm.bmWidth;
1293                 s.cy = bm.bmHeight;
1294                 break;
1295 
1296             case DST_COMPLEX: /* cx and cy must be set in this mode */
1297                 return FALSE;
1298 
1299             default:
1300                 ERR("Invalid opcode: %u\n", opcode);
1301                 return FALSE;
1302         }
1303 
1304         if(!cx) cx = s.cx;
1305         if(!cy) cy = s.cy;
1306     }
1307 
1308     SetRect(&rc, x, y, x + cx, y + cy);
1309 
1310     if(flags & DSS_RIGHT)    /* This one is not documented in the win32.hlp file */
1311         dtflags |= DT_RIGHT;
1312     if(opcode == DST_TEXT)
1313         dtflags |= DT_NOPREFIX;
1314     else if(opcode == DST_PREFIXTEXT)
1315     {
1316         if (flags & DSS_HIDEPREFIX)
1317             dtflags |= DT_HIDEPREFIX;
1318         if (flags & DSS_PREFIXONLY)
1319             dtflags |= DT_PREFIXONLY;
1320     }
1321 
1322     /* For DSS_NORMAL we just jam in the image and return */
1323     if((flags & 0x79f0) == DSS_NORMAL)
1324     {
1325         return PAINTING_DrawStateJam(hdc, opcode, func, lp, len, &rc, dtflags, unicode);
1326     }
1327 
1328     /* For all other states we need to convert the image to B/W in a local bitmap */
1329     /* before it is displayed */
1330     fg = SetTextColor(hdc, RGB(0, 0, 0));
1331     bg = SetBkColor(hdc, RGB(255, 255, 255));
1332     hbm = NULL; hbmsave = NULL;
1333     memdc = NULL; hbsave = NULL;
1334     retval = FALSE; /* assume failure */
1335 
1336     /* From here on we must use "goto cleanup" when something goes wrong */
1337     hbm     = CreateBitmap(cx, cy, 1, 1, NULL);
1338     if(!hbm) goto cleanup;
1339     memdc   = CreateCompatibleDC(hdc);
1340     if(!memdc) goto cleanup;
1341     hbmsave = (HBITMAP)SelectObject(memdc, hbm);
1342     if(!hbmsave) goto cleanup;
1343     SetRect(&rc, 0, 0, cx, cy);
1344     if(!FillRect(memdc, &rc, (HBRUSH)GetStockObject(WHITE_BRUSH))) goto cleanup;
1345     SetBkColor(memdc, RGB(255, 255, 255));
1346     SetTextColor(memdc, RGB(0, 0, 0));
1347     if (hNaaFont)
1348         hfsave  = (HFONT)SelectObject(memdc, hNaaFont);
1349     else
1350         hfsave  = (HFONT)SelectObject(memdc, hFontOriginal);
1351     SetLayout( memdc, GetLayout( hdc ));
1352 
1353     /* DST_COMPLEX may draw text as well,
1354      * so we must be sure that correct font is selected
1355      */
1356     if(!hfsave && (opcode <= DST_PREFIXTEXT)) goto cleanup;
1357     tmp = PAINTING_DrawStateJam(memdc, opcode, func, lp, len, &rc, dtflags, unicode);
1358     if(hfsave) SelectObject(memdc, hfsave);
1359     if (hNaaFont) DeleteObject(hNaaFont);
1360     if(!tmp) goto cleanup;
1361 
1362     /* This state cause the image to be dithered */
1363     if(flags & DSS_UNION)
1364     {
1365         hbsave = (HBRUSH)SelectObject(memdc, gpsi->hbrGray);
1366         if(!hbsave) goto cleanup;
1367         tmp = PatBlt(memdc, 0, 0, cx, cy, 0x00FA0089);
1368         SelectObject(memdc, hbsave);
1369         if(!tmp) goto cleanup;
1370     }
1371 
1372     if (flags & DSS_DISABLED)
1373         hbrtmp = GetSysColorBrush(COLOR_3DHILIGHT);
1374     else if (flags & DSS_DEFAULT)
1375         hbrtmp = GetSysColorBrush(COLOR_3DSHADOW);
1376 
1377     /* Draw light or dark shadow */
1378     if (flags & (DSS_DISABLED|DSS_DEFAULT))
1379     {
1380         if(!hbrtmp) goto cleanup;
1381         hbsave = (HBRUSH)SelectObject(hdc, hbrtmp);
1382         if(!hbsave) goto cleanup;
1383         if(!BitBlt(hdc, x+1, y+1, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup;
1384         SelectObject(hdc, hbsave);
1385     }
1386 
1387     if (flags & DSS_DISABLED)
1388     {
1389         hbr = hbrtmp = GetSysColorBrush(COLOR_3DSHADOW);
1390         if(!hbrtmp) goto cleanup;
1391     }
1392     else if (!hbr)
1393     {
1394         hbr = (HBRUSH)GetStockObject(BLACK_BRUSH);
1395     }
1396 
1397     hbsave = (HBRUSH)SelectObject(hdc, hbr);
1398 
1399     if(!BitBlt(hdc, x, y, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup;
1400 
1401     retval = TRUE; /* We succeeded */
1402 
1403 cleanup:
1404     SetTextColor(hdc, fg);
1405     SetBkColor(hdc, bg);
1406 
1407     if(hbsave) SelectObject(hdc, hbsave);
1408     if(hbmsave) SelectObject(memdc, hbmsave);
1409     if(hbm) DeleteObject(hbm);
1410     if(memdc) DeleteDC(memdc);
1411 
1412     return retval;
1413 }
1414 
1415 /*
1416  * @implemented
1417  */
1418 BOOL WINAPI
1419 RealDrawFrameControl(HDC hDC, LPRECT rc, UINT uType, UINT uState)
1420 {
1421     if (GetMapMode(hDC) != MM_TEXT)
1422         return FALSE;
1423 
1424     switch(uType)
1425     {
1426         case DFC_BUTTON:
1427             return UITOOLS95_DrawFrameButton(hDC, rc, uState);
1428         case DFC_CAPTION:
1429             return UITOOLS95_DrawFrameCaption(hDC, rc, uState);
1430         case DFC_MENU:
1431             return UITOOLS95_DrawFrameMenu(hDC, rc, uState);
1432 #if 0
1433         case DFC_POPUPMENU:
1434             UNIMPLEMENTED;
1435             break;
1436 #endif
1437         case DFC_SCROLL:
1438             return UITOOLS95_DrawFrameScroll(hDC, rc, uState);
1439     }
1440     return FALSE;
1441 }
1442 
1443 BOOL WINAPI
1444 DrawFrameControl(HDC hDC, LPRECT rc, UINT uType, UINT uState)
1445 {
1446    BOOL Hook, Ret = FALSE;
1447 
1448    LoadUserApiHook();
1449 
1450    Hook = BeginIfHookedUserApiHook();
1451 
1452    /* Bypass SEH and go direct. */
1453    if (!Hook) return RealDrawFrameControl(hDC, rc, uType, uState);
1454 
1455    _SEH2_TRY
1456    {
1457       Ret = guah.DrawFrameControl(hDC, rc, uType, uState);
1458    }
1459    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1460    {
1461    }
1462    _SEH2_END;
1463 
1464    EndUserApiHook();
1465 
1466    return Ret;
1467 }
1468 
1469 /*
1470  * @implemented
1471  */
1472 BOOL WINAPI
1473 DrawEdge(HDC hDC, LPRECT rc, UINT edge, UINT flags)
1474 {
1475     if (flags & BF_DIAGONAL)
1476         return IntDrawDiagEdge(hDC, rc, edge, flags);
1477     else
1478         return IntDrawRectEdge(hDC, rc, edge, flags, 1);
1479 }
1480 
1481 /*
1482  * @implemented
1483  */
1484 BOOL WINAPI
1485 GrayStringA(HDC hDC, HBRUSH hBrush, GRAYSTRINGPROC lpOutputFunc, LPARAM lpData,
1486             int nCount, int X, int Y, int nWidth, int nHeight)
1487 {
1488     return IntGrayString(hDC, hBrush, lpOutputFunc, lpData, nCount, X, Y, nWidth, nHeight, FALSE);
1489 }
1490 
1491 /*
1492  * @implemented
1493  */
1494 BOOL WINAPI
1495 GrayStringW(HDC hDC, HBRUSH hBrush, GRAYSTRINGPROC lpOutputFunc, LPARAM lpData,
1496             int nCount, int X, int Y, int nWidth, int nHeight)
1497 {
1498     return IntGrayString(hDC, hBrush, lpOutputFunc, lpData, nCount, X, Y, nWidth, nHeight, TRUE);
1499 }
1500 
1501 /*
1502  * @implemented
1503  */
1504 BOOL WINAPI
1505 InvertRect(HDC hDC, CONST RECT *lprc)
1506 {
1507     return PatBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left,
1508                   lprc->bottom - lprc->top, DSTINVERT);
1509 }
1510 
1511 /*
1512  * @implemented
1513  */
1514 INT WINAPI
1515 FrameRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
1516 {
1517     HBRUSH oldbrush;
1518     RECT r = *lprc;
1519 
1520     if (IsRectEmpty(&r)) return 0;
1521     if (!(oldbrush = SelectObject(hDC, hbr))) return 0;
1522 
1523     PatBlt(hDC, r.left, r.top, 1, r.bottom - r.top, PATCOPY);
1524     PatBlt(hDC, r.right - 1, r.top, 1, r.bottom - r.top, PATCOPY);
1525     PatBlt(hDC, r.left, r.top, r.right - r.left, 1, PATCOPY);
1526     PatBlt(hDC, r.left, r.bottom - 1, r.right - r.left, 1, PATCOPY);
1527 
1528     SelectObject(hDC, oldbrush);
1529     return TRUE;
1530 }
1531 
1532 /*
1533  * @implemented
1534  */
1535 BOOL WINAPI
1536 FlashWindow(HWND hWnd, BOOL bInvert)
1537 {
1538     FLASHWINFO FlashWndInfo;
1539 
1540     FlashWndInfo.cbSize = sizeof(FLASHWINFO);
1541     FlashWndInfo.hwnd = hWnd;
1542     FlashWndInfo.dwFlags = !bInvert ? 0 : (FLASHW_TRAY | FLASHW_CAPTION);
1543     FlashWndInfo.uCount = 1;
1544     FlashWndInfo.dwTimeout = 0;
1545 
1546     return NtUserFlashWindowEx(&FlashWndInfo);
1547 }
1548 
1549 /*
1550  * @implemented
1551  */
1552 INT WINAPI
1553 FillRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
1554 {
1555     BOOL Ret;
1556     HBRUSH prevhbr = NULL;
1557 
1558     /* Select brush if specified */
1559     if (hbr)
1560     {
1561         /* Handle system colors */
1562         if (hbr <= (HBRUSH)(COLOR_MENUBAR + 1))
1563             hbr = GetSysColorBrush(PtrToUlong(hbr) - 1);
1564 
1565         prevhbr = SelectObject(hDC, hbr);
1566         if (prevhbr == NULL)
1567             return (INT)FALSE;
1568     }
1569 
1570     Ret = PatBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left,
1571                  lprc->bottom - lprc->top, PATCOPY);
1572 
1573     /* Select old brush */
1574     if (prevhbr)
1575         SelectObject(hDC, prevhbr);
1576 
1577     return (INT)Ret;
1578 }
1579 
1580 /*
1581  * @implemented
1582  */
1583 BOOL WINAPI
1584 DrawFocusRect(HDC hdc, CONST RECT *rect)
1585 {
1586     HGDIOBJ OldObj;
1587     UINT cx, cy;
1588 
1589     NtUserSystemParametersInfo(SPI_GETFOCUSBORDERWIDTH, 0, &cx, 0);
1590     NtUserSystemParametersInfo(SPI_GETFOCUSBORDERHEIGHT, 0, &cy, 0);
1591 
1592     OldObj = SelectObject(hdc, gpsi->hbrGray);
1593 
1594     /* top */
1595     PatBlt(hdc, rect->left, rect->top, rect->right - rect->left, cy, PATINVERT);
1596     /* bottom */
1597     PatBlt(hdc, rect->left, rect->bottom - cy, rect->right - rect->left, cy, PATINVERT);
1598     /* left */
1599     PatBlt(hdc, rect->left, rect->top + cy, cx, rect->bottom - rect->top - (2 * cy), PATINVERT);
1600     /* right */
1601     PatBlt(hdc, rect->right - cx, rect->top + cy, cx, rect->bottom - rect->top - (2 * cy), PATINVERT);
1602 
1603     SelectObject(hdc, OldObj);
1604     return TRUE;
1605 }
1606 
1607 /*
1608  * @implemented
1609  */
1610 BOOL WINAPI
1611 DrawStateA(HDC hDC, HBRUSH hBrush, DRAWSTATEPROC lpOutputFunc, LPARAM lData,
1612            WPARAM wData, int x, int y, int cx, int cy, UINT fuFlags)
1613 {
1614     return IntDrawState(hDC, hBrush, lpOutputFunc, lData, wData, x, y, cx, cy, fuFlags, FALSE);
1615 }
1616 
1617 /*
1618  * @implemented
1619  */
1620 BOOL WINAPI
1621 DrawStateW(HDC hDC, HBRUSH hBrush, DRAWSTATEPROC lpOutputFunc, LPARAM lData,
1622            WPARAM wData, int x, int y, int cx, int cy, UINT fuFlags)
1623 {
1624     return IntDrawState(hDC, hBrush, lpOutputFunc, lData, wData, x, y, cx, cy, fuFlags, TRUE);
1625 }
1626