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