xref: /reactos/dll/win32/uxtheme/draw.c (revision 0c2cdcae)
1 /*
2  * Win32 5.1 Theme drawing
3  *
4  * Copyright (C) 2003 Kevin Koltzau
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include "uxthemep.h"
22 
23 #include <stdlib.h>
24 
25 /***********************************************************************
26  * Defines and global variables
27  */
28 
29 extern ATOM atDialogThemeEnabled;
30 
31 /***********************************************************************/
32 
33 /***********************************************************************
34  *      EnableThemeDialogTexture                            (UXTHEME.@)
35  */
36 HRESULT WINAPI EnableThemeDialogTexture(HWND hwnd, DWORD dwFlags)
37 {
38     static const WCHAR szTab[] = { 'T','a','b',0 };
39     BOOL res;
40 
41     TRACE("(%p,0x%08x\n", hwnd, dwFlags);
42     res = SetPropW (hwnd, (LPCWSTR)MAKEINTATOM(atDialogThemeEnabled),
43                     UlongToHandle(dwFlags|0x80000000));
44         /* 0x80000000 serves as a "flags set" flag */
45     if (!res)
46           return HRESULT_FROM_WIN32(GetLastError());
47     if (dwFlags & ETDT_USETABTEXTURE)
48         return SetWindowTheme (hwnd, NULL, szTab);
49     else
50         return S_OK;
51 }
52 
53 /***********************************************************************
54  *      IsThemeDialogTextureEnabled                         (UXTHEME.@)
55  */
56 BOOL WINAPI IsThemeDialogTextureEnabled(HWND hwnd)
57 {
58     DWORD dwDialogTextureFlags;
59     TRACE("(%p)\n", hwnd);
60 
61     dwDialogTextureFlags = HandleToUlong( GetPropW( hwnd, (LPCWSTR)MAKEINTATOM(atDialogThemeEnabled) ));
62     if (dwDialogTextureFlags == 0)
63         /* Means EnableThemeDialogTexture wasn't called for this dialog */
64         return FALSE;
65 
66     return (dwDialogTextureFlags & ETDT_ENABLE) && !(dwDialogTextureFlags & ETDT_DISABLE);
67 }
68 
69 /***********************************************************************
70  *      DrawThemeParentBackground                           (UXTHEME.@)
71  */
72 HRESULT WINAPI DrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc)
73 {
74     RECT rt;
75     POINT org;
76     HWND hParent;
77     HRGN clip = NULL;
78     int hasClip = -1;
79 
80     TRACE("(%p,%p,%p)\n", hwnd, hdc, prc);
81 
82     if (!IsWindow(hwnd) || !hdc)
83         return E_HANDLE;
84 
85     if (prc && IsBadReadPtr (prc, sizeof(RECT)))
86         return E_POINTER;
87 
88     hParent = GetParent(hwnd);
89     if(!hParent)
90         return S_OK;
91 
92     if(prc) {
93         rt = *prc;
94         MapWindowPoints(hwnd, hParent, (LPPOINT)&rt, 2);
95 
96         clip = CreateRectRgn(0,0,1,1);
97         hasClip = GetClipRgn(hdc, clip);
98         if(hasClip == -1)
99             TRACE("Failed to get original clipping region\n");
100         else
101             IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
102     }
103     else {
104         GetClientRect(hwnd, &rt);
105         MapWindowPoints(hwnd, hParent, (LPPOINT)&rt, 2);
106     }
107 
108     OffsetViewportOrgEx(hdc, -rt.left, -rt.top, &org);
109 
110     SendMessageW(hParent, WM_ERASEBKGND, (WPARAM)hdc, 0);
111     SendMessageW(hParent, WM_PRINTCLIENT, (WPARAM)hdc, PRF_CLIENT);
112 
113     SetViewportOrgEx(hdc, org.x, org.y, NULL);
114     if(prc) {
115         if(hasClip == 0)
116             SelectClipRgn(hdc, NULL);
117         else if(hasClip == 1)
118             SelectClipRgn(hdc, clip);
119         DeleteObject(clip);
120     }
121     return S_OK;
122 }
123 
124 
125 /***********************************************************************
126  *      DrawThemeBackground                                 (UXTHEME.@)
127  */
128 HRESULT WINAPI DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId,
129                                    int iStateId, const RECT *pRect,
130                                    const RECT *pClipRect)
131 {
132     DTBGOPTS opts;
133     opts.dwSize = sizeof(DTBGOPTS);
134     opts.dwFlags = 0;
135     if(pClipRect) {
136         opts.dwFlags |= DTBG_CLIPRECT;
137         opts.rcClip = *pClipRect;
138     }
139     return DrawThemeBackgroundEx(hTheme, hdc, iPartId, iStateId, pRect, &opts);
140 }
141 
142 /***********************************************************************
143  *      UXTHEME_SelectImage
144  *
145  * Select the image to use
146  */
147 static PTHEME_PROPERTY UXTHEME_SelectImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph)
148 {
149     PTHEME_CLASS pClass;
150     PTHEME_PROPERTY tp;
151     int imageselecttype = IST_NONE;
152     int i;
153     int image;
154 
155     if(glyph)
156         image = TMT_GLYPHIMAGEFILE;
157     else
158         image = TMT_IMAGEFILE;
159 
160     pClass = ValidateHandle(hTheme);
161     if((tp=MSSTYLES_FindProperty(pClass, iPartId, iStateId, TMT_FILENAME, image)))
162         return tp;
163     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGESELECTTYPE, &imageselecttype);
164 
165     if(imageselecttype == IST_DPI) {
166         int reqdpi = 0;
167         int screendpi = GetDeviceCaps(hdc, LOGPIXELSX);
168         for(i=4; i>=0; i--) {
169             reqdpi = 0;
170             if(SUCCEEDED(GetThemeInt(hTheme, iPartId, iStateId, i + TMT_MINDPI1, &reqdpi))) {
171                 if(reqdpi != 0 && screendpi >= reqdpi) {
172                     TRACE("Using %d DPI, image %d\n", reqdpi, i + TMT_IMAGEFILE1);
173                     return MSSTYLES_FindProperty(pClass, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
174                 }
175             }
176         }
177         /* If an image couldn't be selected, choose the first one */
178         return MSSTYLES_FindProperty(pClass, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
179     }
180     else if(imageselecttype == IST_SIZE) {
181         POINT size = {pRect->right-pRect->left, pRect->bottom-pRect->top};
182         POINT reqsize;
183         for(i=4; i>=0; i--) {
184             PTHEME_PROPERTY fileProp =
185                 MSSTYLES_FindProperty(pClass, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
186             if (!fileProp) continue;
187             if(FAILED(GetThemePosition(hTheme, iPartId, iStateId, i + TMT_MINSIZE1, &reqsize))) {
188                 /* fall back to size of Nth image */
189                 WCHAR szPath[MAX_PATH];
190                 int imagelayout = IL_HORIZONTAL;
191                 int imagecount = 1;
192                 BITMAP bmp;
193                 HBITMAP hBmp;
194                 BOOL hasAlpha;
195 
196                 lstrcpynW(szPath, fileProp->lpValue,
197                     min(fileProp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
198                 hBmp = MSSTYLES_LoadBitmap(pClass, szPath, &hasAlpha);
199                 if(!hBmp) continue;
200 
201                 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
202                 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
203 
204                 GetObjectW(hBmp, sizeof(bmp), &bmp);
205                 if(imagelayout == IL_VERTICAL) {
206                     reqsize.x = bmp.bmWidth;
207                     reqsize.y = bmp.bmHeight/imagecount;
208                 }
209                 else {
210                     reqsize.x = bmp.bmWidth/imagecount;
211                     reqsize.y = bmp.bmHeight;
212                 }
213             }
214             if(reqsize.x <= size.x && reqsize.y <= size.y) {
215                 TRACE("Using image size %dx%d, image %d\n", reqsize.x, reqsize.y, i + TMT_IMAGEFILE1);
216                 return fileProp;
217             }
218         }
219         /* If an image couldn't be selected, choose the smallest one */
220         return MSSTYLES_FindProperty(pClass, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
221     }
222     return NULL;
223 }
224 
225 /***********************************************************************
226  *      UXTHEME_LoadImage
227  *
228  * Load image for part/state
229  */
230 HRESULT UXTHEME_LoadImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph,
231                           HBITMAP *hBmp, RECT *bmpRect, BOOL* hasImageAlpha)
232 {
233     int imagelayout = IL_HORIZONTAL;
234     int imagecount = 1;
235     int imagenum;
236     BITMAP bmp;
237     WCHAR szPath[MAX_PATH];
238     PTHEME_PROPERTY tp;
239     PTHEME_CLASS pClass;
240 
241     pClass = ValidateHandle(hTheme);
242     if (!pClass)
243             return E_HANDLE;
244 
245     tp = UXTHEME_SelectImage(hTheme, hdc, iPartId, iStateId, pRect, glyph);
246     if(!tp) {
247         FIXME("Couldn't determine image for part/state %d/%d, invalid theme?\n", iPartId, iStateId);
248         return E_PROP_ID_UNSUPPORTED;
249     }
250     lstrcpynW(szPath, tp->lpValue, min(tp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
251     *hBmp = MSSTYLES_LoadBitmap(pClass, szPath, hasImageAlpha);
252     if(!*hBmp) {
253         TRACE("Failed to load bitmap %s\n", debugstr_w(szPath));
254         return HRESULT_FROM_WIN32(GetLastError());
255     }
256 
257     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
258     GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
259 
260     imagenum = max (min (imagecount, iStateId), 1) - 1;
261     GetObjectW(*hBmp, sizeof(bmp), &bmp);
262 
263     if(imagecount < 1) imagecount = 1;
264 
265     if(imagelayout == IL_VERTICAL) {
266         int height = bmp.bmHeight/imagecount;
267         bmpRect->left = 0;
268         bmpRect->right = bmp.bmWidth;
269         bmpRect->top = imagenum * height;
270         bmpRect->bottom = bmpRect->top + height;
271     }
272     else {
273         int width = bmp.bmWidth/imagecount;
274         bmpRect->left = imagenum * width;
275         bmpRect->right = bmpRect->left + width;
276         bmpRect->top = 0;
277         bmpRect->bottom = bmp.bmHeight;
278     }
279     return S_OK;
280 }
281 
282 /* Get transparency parameters passed to UXTHEME_StretchBlt() - the parameters
283  * depend on whether the image has full alpha  or whether it is
284  * color-transparent or just opaque. */
285 static inline void get_transparency (HTHEME hTheme, int iPartId, int iStateId,
286                                      BOOL hasImageAlpha, INT* transparent,
287                                      COLORREF* transparentcolor, BOOL glyph)
288 {
289     if (hasImageAlpha)
290     {
291         *transparent = ALPHABLEND_FULL;
292         *transparentcolor = RGB (255, 0, 255);
293     }
294     else
295     {
296         BOOL trans = FALSE;
297         GetThemeBool(hTheme, iPartId, iStateId,
298             glyph ? TMT_GLYPHTRANSPARENT : TMT_TRANSPARENT, &trans);
299         if(trans) {
300             *transparent = ALPHABLEND_BINARY;
301             if(FAILED(GetThemeColor(hTheme, iPartId, iStateId,
302                 glyph ? TMT_GLYPHTRANSPARENTCOLOR : TMT_TRANSPARENTCOLOR,
303                 transparentcolor))) {
304                 /* If image is transparent, but no color was specified, use magenta */
305                 *transparentcolor = RGB(255, 0, 255);
306             }
307         }
308         else
309             *transparent = ALPHABLEND_NONE;
310     }
311 }
312 
313 /***********************************************************************
314  *      UXTHEME_DrawImageGlyph
315  *
316  * Draw an imagefile glyph
317  */
318 static HRESULT UXTHEME_DrawImageGlyph(HTHEME hTheme, HDC hdc, int iPartId,
319                                int iStateId, RECT *pRect,
320                                const DTBGOPTS *pOptions)
321 {
322     HRESULT hr;
323     HBITMAP bmpSrc = NULL;
324     RECT rcSrc;
325     INT transparent = 0;
326     COLORREF transparentcolor;
327     int valign = VA_CENTER;
328     int halign = HA_CENTER;
329     POINT dstSize;
330     POINT srcSize;
331     BOOL hasAlpha;
332     RECT rcDst;
333     GDI_DRAW_STREAM DrawStream;
334 
335     hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, TRUE,
336         &bmpSrc, &rcSrc, &hasAlpha);
337     if(FAILED(hr)) return hr;
338 
339     dstSize.x = pRect->right-pRect->left;
340     dstSize.y = pRect->bottom-pRect->top;
341     srcSize.x = rcSrc.right-rcSrc.left;
342     srcSize.y = rcSrc.bottom-rcSrc.top;
343 
344     get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
345         &transparentcolor, TRUE);
346     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
347     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
348 
349     rcDst = *pRect;
350     if(halign == HA_CENTER)      rcDst.left += (dstSize.x/2)-(srcSize.x/2);
351     else if(halign == HA_RIGHT)  rcDst.left += dstSize.x-srcSize.x;
352     if(valign == VA_CENTER)      rcDst.top += (dstSize.y/2)-(srcSize.y/2);
353     else if(valign == VA_BOTTOM) rcDst.top += dstSize.y-srcSize.y;
354 
355     rcDst.right = rcDst.left + srcSize.x;
356     rcDst.bottom = rcDst.top + srcSize.y;
357 
358     DrawStream.signature = 0x44727753;
359     DrawStream.reserved = 0;
360     DrawStream.unknown1 = 1;
361     DrawStream.unknown2 = 9;
362     DrawStream.hDC = hdc;
363     DrawStream.hImage = bmpSrc;
364     DrawStream.crTransparent = transparentcolor;
365     DrawStream.rcSrc = rcSrc;
366     DrawStream.rcDest = rcDst;
367     DrawStream.leftSizingMargin = 0;
368     DrawStream.rightSizingMargin = 0;
369     DrawStream.topSizingMargin = 0;
370     DrawStream.bottomSizingMargin = 0;
371     DrawStream.drawOption = DS_TRUESIZE;
372 
373     if (transparent == ALPHABLEND_FULL)
374         DrawStream.drawOption |= DS_TRANSPARENTALPHA;
375     else if (transparent == ALPHABLEND_BINARY)
376         DrawStream.drawOption |= DS_TRANSPARENTCLR;
377 
378     GdiDrawStream(hdc, sizeof(DrawStream), &DrawStream);
379     return HRESULT_FROM_WIN32(GetLastError());
380 }
381 
382 /***********************************************************************
383  *      UXTHEME_DrawImageGlyph
384  *
385  * Draw glyph on top of background, if appropriate
386  */
387 static HRESULT UXTHEME_DrawGlyph(HTHEME hTheme, HDC hdc, int iPartId,
388                                     int iStateId, RECT *pRect,
389                                     const DTBGOPTS *pOptions)
390 {
391     int glyphtype = GT_NONE;
392 
393     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_GLYPHTYPE, &glyphtype);
394 
395     if(glyphtype == GT_IMAGEGLYPH) {
396         return UXTHEME_DrawImageGlyph(hTheme, hdc, iPartId, iStateId, pRect, pOptions);
397     }
398     else if(glyphtype == GT_FONTGLYPH) {
399         /* I don't know what a font glyph is, I've never seen it used in any themes */
400         FIXME("Font glyph\n");
401     }
402     return S_OK;
403 }
404 
405 /***********************************************************************
406  * get_image_part_size
407  *
408  * Used by GetThemePartSize and UXTHEME_DrawImageBackground
409  */
410 static HRESULT get_image_part_size (HTHEME hTheme, HDC hdc, int iPartId,
411                                     int iStateId, RECT *prc, THEMESIZE eSize,
412                                     POINT *psz)
413 {
414     HRESULT hr = S_OK;
415     HBITMAP bmpSrc;
416     RECT rcSrc;
417     BOOL hasAlpha;
418 
419     hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, prc, FALSE,
420         &bmpSrc, &rcSrc, &hasAlpha);
421     if (FAILED(hr)) return hr;
422 
423     switch (eSize)
424     {
425         case TS_DRAW:
426             if (prc != NULL)
427             {
428                 RECT rcDst;
429                 POINT dstSize;
430                 POINT srcSize;
431                 int sizingtype = ST_STRETCH;
432                 BOOL uniformsizing = FALSE;
433 
434                 rcDst = *prc;
435 
436                 dstSize.x = rcDst.right-rcDst.left;
437                 dstSize.y = rcDst.bottom-rcDst.top;
438                 srcSize.x = rcSrc.right-rcSrc.left;
439                 srcSize.y = rcSrc.bottom-rcSrc.top;
440 
441                 GetThemeBool(hTheme, iPartId, iStateId, TMT_UNIFORMSIZING, &uniformsizing);
442                 if(uniformsizing) {
443                     /* Scale height and width equally */
444                     if (dstSize.x*srcSize.y < dstSize.y*srcSize.x)
445                     {
446                         dstSize.y = MulDiv (srcSize.y, dstSize.x, srcSize.x);
447                         rcDst.bottom = rcDst.top + dstSize.y;
448                     }
449                     else
450                     {
451                         dstSize.x = MulDiv (srcSize.x, dstSize.y, srcSize.y);
452                         rcDst.right = rcDst.left + dstSize.x;
453                     }
454                 }
455 
456                 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
457                 if(sizingtype == ST_TRUESIZE) {
458                     int truesizestretchmark = 100;
459 
460                     if(dstSize.x < 0 || dstSize.y < 0) {
461                         BOOL mirrorimage = TRUE;
462                         GetThemeBool(hTheme, iPartId, iStateId, TMT_MIRRORIMAGE, &mirrorimage);
463                         if(mirrorimage) {
464                             if(dstSize.x < 0) {
465                                 rcDst.left += dstSize.x;
466                                 rcDst.right += dstSize.x;
467                             }
468                             if(dstSize.y < 0) {
469                                 rcDst.top += dstSize.y;
470                                 rcDst.bottom += dstSize.y;
471                             }
472                         }
473                     }
474                     /* Whatever TrueSizeStretchMark does - it does not seem to
475                      * be what's outlined below. It appears as if native
476                      * uxtheme always stretches if dest is smaller than source
477                      * (ie as if TrueSizeStretchMark==100 with the code below) */
478 #if 0
479                     /* Only stretch when target exceeds source by truesizestretchmark percent */
480                     GetThemeInt(hTheme, iPartId, iStateId, TMT_TRUESIZESTRETCHMARK, &truesizestretchmark);
481 #endif
482                     if(dstSize.x < 0 || dstSize.y < 0 ||
483                       (MulDiv(srcSize.x, 100, dstSize.x) > truesizestretchmark &&
484                       MulDiv(srcSize.y, 100, dstSize.y) > truesizestretchmark)) {
485                         memcpy (psz, &dstSize, sizeof (SIZE));
486                     }
487                     else {
488                         memcpy (psz, &srcSize, sizeof (SIZE));
489                     }
490                 }
491                 else
492                 {
493                     psz->x = abs(dstSize.x);
494                     psz->y = abs(dstSize.y);
495                 }
496                 break;
497             }
498             /* else fall through */
499         case TS_MIN:
500             /* FIXME: couldn't figure how native uxtheme computes min size */
501         case TS_TRUE:
502             psz->x = rcSrc.right - rcSrc.left;
503             psz->y = rcSrc.bottom - rcSrc.top;
504             break;
505     }
506     return hr;
507 }
508 
509 /***********************************************************************
510  *      UXTHEME_DrawImageBackground
511  *
512  * Draw an imagefile background
513  */
514 static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId,
515                                     int iStateId, RECT *pRect,
516                                     const DTBGOPTS *pOptions)
517 {
518     HRESULT hr = S_OK;
519     HBITMAP bmpSrc;
520     RECT rcSrc;
521     RECT rcDst;
522     POINT dstSize;
523     POINT drawSize;
524     int sizingtype = ST_STRETCH;
525     INT transparent;
526     COLORREF transparentcolor = 0;
527     BOOL hasAlpha;
528     MARGINS sm;
529     GDI_DRAW_STREAM DrawStream;
530 
531     hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, FALSE, &bmpSrc, &rcSrc, &hasAlpha);
532     if(FAILED(hr))
533         return hr;
534     get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent, &transparentcolor, FALSE);
535 
536     rcDst = *pRect;
537     dstSize.x = rcDst.right-rcDst.left;
538     dstSize.y = rcDst.bottom-rcDst.top;
539 
540     GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_SIZINGMARGINS, NULL, &sm);
541     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
542 
543     /*FIXME: Is this ever used? */
544     /*GetThemeBool(hTheme, iPartId, iStateId, TMT_BORDERONLY, &borderonly);*/
545 
546     if(sizingtype == ST_TRUESIZE) {
547         int valign = VA_CENTER, halign = HA_CENTER;
548 
549         get_image_part_size (hTheme, hdc, iPartId, iStateId, pRect, TS_DRAW, &drawSize);
550         GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
551         GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
552 
553         if (halign == HA_CENTER)
554             rcDst.left += (dstSize.x/2)-(drawSize.x/2);
555         else if (halign == HA_RIGHT)
556             rcDst.left = rcDst.right - drawSize.x;
557         if (valign == VA_CENTER)
558             rcDst.top  += (dstSize.y/2)-(drawSize.y/2);
559         else if (valign == VA_BOTTOM)
560             rcDst.top = rcDst.bottom - drawSize.y;
561         rcDst.right = rcDst.left + drawSize.x;
562         rcDst.bottom = rcDst.top + drawSize.y;
563         *pRect = rcDst;
564     }
565 
566     DrawStream.signature = 0x44727753;
567     DrawStream.reserved = 0;
568     DrawStream.unknown1 = 1;
569     DrawStream.unknown2 = 9;
570     DrawStream.hDC = hdc;
571     DrawStream.hImage = bmpSrc;
572     DrawStream.crTransparent = transparentcolor;
573     DrawStream.rcSrc = rcSrc;
574     DrawStream.rcDest = rcDst;
575     DrawStream.leftSizingMargin = sm.cxLeftWidth;
576     DrawStream.rightSizingMargin = sm.cxRightWidth;
577     DrawStream.topSizingMargin = sm.cyTopHeight;
578     DrawStream.bottomSizingMargin = sm.cyBottomHeight;
579     DrawStream.drawOption = 0;
580 
581     if (transparent == ALPHABLEND_FULL)
582         DrawStream.drawOption |= DS_TRANSPARENTALPHA;
583     else if (transparent == ALPHABLEND_BINARY)
584         DrawStream.drawOption |= DS_TRANSPARENTCLR;
585 
586     if (sizingtype == ST_TILE)
587         DrawStream.drawOption |= DS_TILE;
588     else if (sizingtype == ST_TRUESIZE)
589         DrawStream.drawOption |= DS_TRUESIZE;
590 
591     GdiDrawStream(hdc, sizeof(DrawStream), &DrawStream);
592     return HRESULT_FROM_WIN32(GetLastError());
593 }
594 
595 /***********************************************************************
596  *      UXTHEME_DrawBorderRectangle
597  *
598  * Draw the bounding rectangle for a borderfill background
599  */
600 static HRESULT UXTHEME_DrawBorderRectangle(HTHEME hTheme, HDC hdc, int iPartId,
601                                     int iStateId, RECT *pRect,
602                                     const DTBGOPTS *pOptions)
603 {
604     HRESULT hr = S_OK;
605     HPEN hPen;
606     HGDIOBJ oldPen;
607     COLORREF bordercolor = RGB(0,0,0);
608     int bordersize = 1;
609 
610     GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
611     if(bordersize > 0) {
612         POINT ptCorners[5];
613         ptCorners[0].x = pRect->left;
614         ptCorners[0].y = pRect->top;
615         ptCorners[1].x = pRect->right-1;
616         ptCorners[1].y = pRect->top;
617         ptCorners[2].x = pRect->right-1;
618         ptCorners[2].y = pRect->bottom-1;
619         ptCorners[3].x = pRect->left;
620         ptCorners[3].y = pRect->bottom-1;
621         ptCorners[4].x = pRect->left;
622         ptCorners[4].y = pRect->top;
623 
624         InflateRect(pRect, -bordersize, -bordersize);
625         if(pOptions->dwFlags & DTBG_OMITBORDER)
626             return S_OK;
627         GetThemeColor(hTheme, iPartId, iStateId, TMT_BORDERCOLOR, &bordercolor);
628         hPen = CreatePen(PS_SOLID, bordersize, bordercolor);
629         if(!hPen)
630             return HRESULT_FROM_WIN32(GetLastError());
631         oldPen = SelectObject(hdc, hPen);
632 
633         if(!Polyline(hdc, ptCorners, 5))
634             hr = HRESULT_FROM_WIN32(GetLastError());
635 
636         SelectObject(hdc, oldPen);
637         DeleteObject(hPen);
638     }
639     return hr;
640 }
641 
642 /***********************************************************************
643  *      UXTHEME_DrawBackgroundFill
644  *
645  * Fill a borderfill background rectangle
646  */
647 static HRESULT UXTHEME_DrawBackgroundFill(HTHEME hTheme, HDC hdc, int iPartId,
648                                    int iStateId, RECT *pRect,
649                                    const DTBGOPTS *pOptions)
650 {
651     HRESULT hr = S_OK;
652     int filltype = FT_SOLID;
653 
654     TRACE("(%d,%d,%d)\n", iPartId, iStateId, pOptions->dwFlags);
655 
656     if(pOptions->dwFlags & DTBG_OMITCONTENT)
657         return S_OK;
658 
659     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_FILLTYPE, &filltype);
660 
661     if(filltype == FT_SOLID) {
662         HBRUSH hBrush;
663         COLORREF fillcolor = RGB(255,255,255);
664 
665         GetThemeColor(hTheme, iPartId, iStateId, TMT_FILLCOLOR, &fillcolor);
666         hBrush = CreateSolidBrush(fillcolor);
667         if(!FillRect(hdc, pRect, hBrush))
668             hr = HRESULT_FROM_WIN32(GetLastError());
669         DeleteObject(hBrush);
670     }
671     else if(filltype == FT_VERTGRADIENT || filltype == FT_HORZGRADIENT) {
672         /* FIXME: This only accounts for 2 gradient colors (out of 5) and ignores
673             the gradient ratios (no idea how those work)
674             Few themes use this, and the ones I've seen only use 2 colors with
675             a gradient ratio of 0 and 255 respectively
676         */
677 
678         COLORREF gradient1 = RGB(0,0,0);
679         COLORREF gradient2 = RGB(255,255,255);
680         TRIVERTEX vert[2];
681         GRADIENT_RECT gRect;
682 
683         FIXME("Gradient implementation not complete\n");
684 
685         GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR1, &gradient1);
686         GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR2, &gradient2);
687 
688         vert[0].x     = pRect->left;
689         vert[0].y     = pRect->top;
690         vert[0].Red   = GetRValue(gradient1) << 8;
691         vert[0].Green = GetGValue(gradient1) << 8;
692         vert[0].Blue  = GetBValue(gradient1) << 8;
693         vert[0].Alpha = 0xff00;
694 
695         vert[1].x     = pRect->right;
696         vert[1].y     = pRect->bottom;
697         vert[1].Red   = GetRValue(gradient2) << 8;
698         vert[1].Green = GetGValue(gradient2) << 8;
699         vert[1].Blue  = GetBValue(gradient2) << 8;
700         vert[1].Alpha = 0xff00;
701 
702         gRect.UpperLeft  = 0;
703         gRect.LowerRight = 1;
704         GradientFill(hdc,vert,2,&gRect,1,filltype==FT_HORZGRADIENT?GRADIENT_FILL_RECT_H:GRADIENT_FILL_RECT_V);
705     }
706     else if(filltype == FT_RADIALGRADIENT) {
707         /* I've never seen this used in a theme */
708         FIXME("Radial gradient\n");
709     }
710     else if(filltype == FT_TILEIMAGE) {
711         /* I've never seen this used in a theme */
712         FIXME("Tile image\n");
713     }
714     return hr;
715 }
716 
717 /***********************************************************************
718  *      UXTHEME_DrawBorderBackground
719  *
720  * Draw an imagefile background
721  */
722 static HRESULT UXTHEME_DrawBorderBackground(HTHEME hTheme, HDC hdc, int iPartId,
723                                      int iStateId, const RECT *pRect,
724                                      const DTBGOPTS *pOptions)
725 {
726     HRESULT hr;
727     RECT rt;
728 
729     rt = *pRect;
730 
731     hr = UXTHEME_DrawBorderRectangle(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
732     if(FAILED(hr))
733         return hr;
734     return UXTHEME_DrawBackgroundFill(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
735 }
736 
737 /***********************************************************************
738  *      DrawThemeBackgroundEx                               (UXTHEME.@)
739  */
740 HRESULT WINAPI DrawThemeBackgroundEx(HTHEME hTheme, HDC hdc, int iPartId,
741                                      int iStateId, const RECT *pRect,
742                                      const DTBGOPTS *pOptions)
743 {
744     HRESULT hr;
745     const DTBGOPTS defaultOpts = {sizeof(DTBGOPTS), 0, {0,0,0,0}};
746     const DTBGOPTS *opts;
747     HRGN clip = NULL;
748     int hasClip = -1;
749     int bgtype = BT_BORDERFILL;
750     RECT rt;
751 
752     TRACE("(%p,%p,%d,%d,%d,%d)\n", hTheme, hdc, iPartId, iStateId,pRect->left,pRect->top);
753     if(!hTheme)
754         return E_HANDLE;
755 
756     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
757     if (bgtype == BT_NONE) return S_OK;
758 
759     /* Ensure we have a DTBGOPTS structure available, simplifies some of the code */
760     opts = pOptions;
761     if(!opts) opts = &defaultOpts;
762 
763     if(opts->dwFlags & DTBG_CLIPRECT) {
764         clip = CreateRectRgn(0,0,1,1);
765         hasClip = GetClipRgn(hdc, clip);
766         if(hasClip == -1)
767             TRACE("Failed to get original clipping region\n");
768         else
769             IntersectClipRect(hdc, opts->rcClip.left, opts->rcClip.top, opts->rcClip.right, opts->rcClip.bottom);
770     }
771     rt = *pRect;
772 
773     if(bgtype == BT_IMAGEFILE)
774         hr = UXTHEME_DrawImageBackground(hTheme, hdc, iPartId, iStateId, &rt, opts);
775     else if(bgtype == BT_BORDERFILL)
776         hr = UXTHEME_DrawBorderBackground(hTheme, hdc, iPartId, iStateId, pRect, opts);
777     else {
778         FIXME("Unknown background type\n");
779         /* This should never happen, and hence I don't know what to return */
780         hr = E_FAIL;
781     }
782 #if 0
783     if(SUCCEEDED(hr))
784 #endif
785     {
786         RECT rcGlyph = *pRect;
787         MARGINS margin;
788         hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
789         if(SUCCEEDED(hr))
790         {
791             rcGlyph.left += margin.cxLeftWidth;
792             rcGlyph.right -= margin.cxRightWidth;
793             rcGlyph.top += margin.cyTopHeight;
794             rcGlyph.bottom -= margin.cyBottomHeight;
795         }
796         hr = UXTHEME_DrawGlyph(hTheme, hdc, iPartId, iStateId, &rcGlyph, opts);
797     }
798     if(opts->dwFlags & DTBG_CLIPRECT) {
799         if(hasClip == 0)
800             SelectClipRgn(hdc, NULL);
801         else if(hasClip == 1)
802             SelectClipRgn(hdc, clip);
803         DeleteObject(clip);
804     }
805     return hr;
806 }
807 
808 /*
809  * DrawThemeEdge() implementation
810  *
811  * Since it basically is DrawEdge() with different colors, I copied its code
812  * from user32's uitools.c.
813  */
814 
815 enum
816 {
817     EDGE_LIGHT,
818     EDGE_HIGHLIGHT,
819     EDGE_SHADOW,
820     EDGE_DARKSHADOW,
821     EDGE_FILL,
822 
823     EDGE_WINDOW,
824     EDGE_WINDOWFRAME,
825 
826     EDGE_NUMCOLORS
827 };
828 
829 static const struct
830 {
831     int themeProp;
832     int sysColor;
833 } EdgeColorMap[EDGE_NUMCOLORS] = {
834     {TMT_EDGELIGHTCOLOR,                  COLOR_3DLIGHT},
835     {TMT_EDGEHIGHLIGHTCOLOR,              COLOR_BTNHIGHLIGHT},
836     {TMT_EDGESHADOWCOLOR,                 COLOR_BTNSHADOW},
837     {TMT_EDGEDKSHADOWCOLOR,               COLOR_3DDKSHADOW},
838     {TMT_EDGEFILLCOLOR,                   COLOR_BTNFACE},
839     {-1,                                  COLOR_WINDOW},
840     {-1,                                  COLOR_WINDOWFRAME}
841 };
842 
843 static const signed char LTInnerNormal[] = {
844     -1,           -1,                 -1,                 -1,
845     -1,           EDGE_HIGHLIGHT,     EDGE_HIGHLIGHT,     -1,
846     -1,           EDGE_DARKSHADOW,    EDGE_DARKSHADOW,    -1,
847     -1,           -1,                 -1,                 -1
848 };
849 
850 static const signed char LTOuterNormal[] = {
851     -1,                 EDGE_LIGHT,     EDGE_SHADOW, -1,
852     EDGE_HIGHLIGHT,     EDGE_LIGHT,     EDGE_SHADOW, -1,
853     EDGE_DARKSHADOW,    EDGE_LIGHT,     EDGE_SHADOW, -1,
854     -1,                 EDGE_LIGHT,     EDGE_SHADOW, -1
855 };
856 
857 static const signed char RBInnerNormal[] = {
858     -1,           -1,                 -1,               -1,
859     -1,           EDGE_SHADOW,        EDGE_SHADOW,      -1,
860     -1,           EDGE_LIGHT,         EDGE_LIGHT,       -1,
861     -1,           -1,                 -1,               -1
862 };
863 
864 static const signed char RBOuterNormal[] = {
865     -1,               EDGE_DARKSHADOW,  EDGE_HIGHLIGHT, -1,
866     EDGE_SHADOW,      EDGE_DARKSHADOW,  EDGE_HIGHLIGHT, -1,
867     EDGE_LIGHT,       EDGE_DARKSHADOW,  EDGE_HIGHLIGHT, -1,
868     -1,               EDGE_DARKSHADOW,  EDGE_HIGHLIGHT, -1
869 };
870 
871 static const signed char LTInnerSoft[] = {
872     -1,                  -1,                -1,               -1,
873     -1,                  EDGE_LIGHT,        EDGE_LIGHT,       -1,
874     -1,                  EDGE_SHADOW,       EDGE_SHADOW,      -1,
875     -1,                  -1,                -1,               -1
876 };
877 
878 static const signed char LTOuterSoft[] = {
879     -1,               EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
880     EDGE_LIGHT,       EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
881     EDGE_SHADOW,      EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
882     -1,               EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1
883 };
884 
885 #define RBInnerSoft RBInnerNormal   /* These are the same */
886 #define RBOuterSoft RBOuterNormal
887 
888 static const signed char LTRBOuterMono[] = {
889     -1,           EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
890     EDGE_WINDOW,  EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
891     EDGE_WINDOW,  EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
892     EDGE_WINDOW,  EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
893 };
894 
895 static const signed char LTRBInnerMono[] = {
896     -1, -1,           -1,           -1,
897     -1, EDGE_WINDOW,  EDGE_WINDOW,  EDGE_WINDOW,
898     -1, EDGE_WINDOW,  EDGE_WINDOW,  EDGE_WINDOW,
899     -1, EDGE_WINDOW,  EDGE_WINDOW,  EDGE_WINDOW,
900 };
901 
902 static const signed char LTRBOuterFlat[] = {
903     -1,                 EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
904     EDGE_FILL,          EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
905     EDGE_FILL,          EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
906     EDGE_FILL,          EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
907 };
908 
909 static const signed char LTRBInnerFlat[] = {
910     -1, -1,               -1,               -1,
911     -1, EDGE_FILL,        EDGE_FILL,        EDGE_FILL,
912     -1, EDGE_FILL,        EDGE_FILL,        EDGE_FILL,
913     -1, EDGE_FILL,        EDGE_FILL,        EDGE_FILL,
914 };
915 
916 static COLORREF get_edge_color (int edgeType, HTHEME theme, int part, int state)
917 {
918     COLORREF col;
919     if ((EdgeColorMap[edgeType].themeProp == -1)
920         || FAILED (GetThemeColor (theme, part, state,
921             EdgeColorMap[edgeType].themeProp, &col)))
922         col = GetSysColor (EdgeColorMap[edgeType].sysColor);
923     return col;
924 }
925 
926 static inline HPEN get_edge_pen (int edgeType, HTHEME theme, int part, int state)
927 {
928     return CreatePen (PS_SOLID, 1, get_edge_color (edgeType, theme, part, state));
929 }
930 
931 static inline HBRUSH get_edge_brush (int edgeType, HTHEME theme, int part, int state)
932 {
933     return CreateSolidBrush (get_edge_color (edgeType, theme, part, state));
934 }
935 
936 /***********************************************************************
937  *           draw_diag_edge
938  *
939  * Same as DrawEdge invoked with BF_DIAGONAL
940  */
941 static HRESULT draw_diag_edge (HDC hdc, HTHEME theme, int part, int state,
942                                const RECT* rc, UINT uType,
943                                UINT uFlags, LPRECT contentsRect)
944 {
945     POINT Points[4];
946     signed char InnerI, OuterI;
947     HPEN InnerPen, OuterPen;
948     POINT SavePoint;
949     HPEN SavePen;
950     int spx, spy;
951     int epx, epy;
952     int Width = rc->right - rc->left;
953     int Height= rc->bottom - rc->top;
954     int SmallDiam = Width > Height ? Height : Width;
955     HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
956                        || (uType & BDR_OUTER) == BDR_OUTER)
957                       && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
958     int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
959             + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
960 
961     /* Init some vars */
962     OuterPen = InnerPen = GetStockObject(NULL_PEN);
963     SavePen = SelectObject(hdc, InnerPen);
964     spx = spy = epx = epy = 0; /* Satisfy the compiler... */
965 
966     /* Determine the colors of the edges */
967     if(uFlags & BF_MONO)
968     {
969         InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
970         OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
971     }
972     else if(uFlags & BF_FLAT)
973     {
974         InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
975         OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
976     }
977     else if(uFlags & BF_SOFT)
978     {
979         if(uFlags & BF_BOTTOM)
980         {
981             InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
982             OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
983         }
984         else
985         {
986             InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
987             OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
988         }
989     }
990     else
991     {
992         if(uFlags & BF_BOTTOM)
993         {
994             InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
995             OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
996         }
997         else
998         {
999             InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1000             OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1001         }
1002     }
1003 
1004     if(InnerI != -1) InnerPen = get_edge_pen (InnerI, theme, part, state);
1005     if(OuterI != -1) OuterPen = get_edge_pen (OuterI, theme, part, state);
1006 
1007     MoveToEx(hdc, 0, 0, &SavePoint);
1008 
1009     /* Don't ask me why, but this is what is visible... */
1010     /* This must be possible to do much simpler, but I fail to */
1011     /* see the logic in the MS implementation (sigh...). */
1012     /* So, this might look a bit brute force here (and it is), but */
1013     /* it gets the job done;) */
1014 
1015     switch(uFlags & BF_RECT)
1016     {
1017     case 0:
1018     case BF_LEFT:
1019     case BF_BOTTOM:
1020     case BF_BOTTOMLEFT:
1021         /* Left bottom endpoint */
1022         epx = rc->left-1;
1023         spx = epx + SmallDiam;
1024         epy = rc->bottom;
1025         spy = epy - SmallDiam;
1026         break;
1027 
1028     case BF_TOPLEFT:
1029     case BF_BOTTOMRIGHT:
1030         /* Left top endpoint */
1031         epx = rc->left-1;
1032         spx = epx + SmallDiam;
1033         epy = rc->top-1;
1034         spy = epy + SmallDiam;
1035         break;
1036 
1037     case BF_TOP:
1038     case BF_RIGHT:
1039     case BF_TOPRIGHT:
1040     case BF_RIGHT|BF_LEFT:
1041     case BF_RIGHT|BF_LEFT|BF_TOP:
1042     case BF_BOTTOM|BF_TOP:
1043     case BF_BOTTOM|BF_TOP|BF_LEFT:
1044     case BF_BOTTOMRIGHT|BF_LEFT:
1045     case BF_BOTTOMRIGHT|BF_TOP:
1046     case BF_RECT:
1047         /* Right top endpoint */
1048         spx = rc->left;
1049         epx = spx + SmallDiam;
1050         spy = rc->bottom-1;
1051         epy = spy - SmallDiam;
1052         break;
1053     }
1054 
1055     MoveToEx(hdc, spx, spy, NULL);
1056     SelectObject(hdc, OuterPen);
1057     LineTo(hdc, epx, epy);
1058 
1059     SelectObject(hdc, InnerPen);
1060 
1061     switch(uFlags & (BF_RECT|BF_DIAGONAL))
1062     {
1063     case BF_DIAGONAL_ENDBOTTOMLEFT:
1064     case (BF_DIAGONAL|BF_BOTTOM):
1065     case BF_DIAGONAL:
1066     case (BF_DIAGONAL|BF_LEFT):
1067         MoveToEx(hdc, spx-1, spy, NULL);
1068         LineTo(hdc, epx, epy-1);
1069         Points[0].x = spx-add;
1070         Points[0].y = spy;
1071         Points[1].x = rc->left;
1072         Points[1].y = rc->top;
1073         Points[2].x = epx+1;
1074         Points[2].y = epy-1-add;
1075         Points[3] = Points[2];
1076         break;
1077 
1078     case BF_DIAGONAL_ENDBOTTOMRIGHT:
1079         MoveToEx(hdc, spx-1, spy, NULL);
1080         LineTo(hdc, epx, epy+1);
1081         Points[0].x = spx-add;
1082         Points[0].y = spy;
1083         Points[1].x = rc->left;
1084         Points[1].y = rc->bottom-1;
1085         Points[2].x = epx+1;
1086         Points[2].y = epy+1+add;
1087         Points[3] = Points[2];
1088         break;
1089 
1090     case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP):
1091     case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
1092     case BF_DIAGONAL_ENDTOPRIGHT:
1093     case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
1094         MoveToEx(hdc, spx+1, spy, NULL);
1095         LineTo(hdc, epx, epy+1);
1096         Points[0].x = epx-1;
1097         Points[0].y = epy+1+add;
1098         Points[1].x = rc->right-1;
1099         Points[1].y = rc->top+add;
1100         Points[2].x = rc->right-1;
1101         Points[2].y = rc->bottom-1;
1102         Points[3].x = spx+add;
1103         Points[3].y = spy;
1104         break;
1105 
1106     case BF_DIAGONAL_ENDTOPLEFT:
1107         MoveToEx(hdc, spx, spy-1, NULL);
1108         LineTo(hdc, epx+1, epy);
1109         Points[0].x = epx+1+add;
1110         Points[0].y = epy+1;
1111         Points[1].x = rc->right-1;
1112         Points[1].y = rc->top;
1113         Points[2].x = rc->right-1;
1114         Points[2].y = rc->bottom-1-add;
1115         Points[3].x = spx;
1116         Points[3].y = spy-add;
1117         break;
1118 
1119     case (BF_DIAGONAL|BF_TOP):
1120     case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
1121     case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
1122         MoveToEx(hdc, spx+1, spy-1, NULL);
1123         LineTo(hdc, epx, epy);
1124         Points[0].x = epx-1;
1125         Points[0].y = epy+1;
1126         Points[1].x = rc->right-1;
1127         Points[1].y = rc->top;
1128         Points[2].x = rc->right-1;
1129         Points[2].y = rc->bottom-1-add;
1130         Points[3].x = spx+add;
1131         Points[3].y = spy-add;
1132         break;
1133 
1134     case (BF_DIAGONAL|BF_RIGHT):
1135     case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
1136     case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
1137         MoveToEx(hdc, spx, spy, NULL);
1138         LineTo(hdc, epx-1, epy+1);
1139         Points[0].x = spx;
1140         Points[0].y = spy;
1141         Points[1].x = rc->left;
1142         Points[1].y = rc->top+add;
1143         Points[2].x = epx-1-add;
1144         Points[2].y = epy+1+add;
1145         Points[3] = Points[2];
1146         break;
1147     }
1148 
1149     /* Fill the interior if asked */
1150     if((uFlags & BF_MIDDLE) && retval)
1151     {
1152         HBRUSH hbsave;
1153         HBRUSH hb = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1154             theme, part, state);
1155         HPEN hpsave;
1156         HPEN hp = get_edge_pen ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1157             theme, part, state);
1158         hbsave = SelectObject(hdc, hb);
1159         hpsave = SelectObject(hdc, hp);
1160         Polygon(hdc, Points, 4);
1161         SelectObject(hdc, hbsave);
1162         SelectObject(hdc, hpsave);
1163         DeleteObject (hp);
1164         DeleteObject (hb);
1165     }
1166 
1167     /* Adjust rectangle if asked */
1168     if(uFlags & BF_ADJUST)
1169     {
1170         *contentsRect = *rc;
1171         if(uFlags & BF_LEFT)   contentsRect->left   += add;
1172         if(uFlags & BF_RIGHT)  contentsRect->right  -= add;
1173         if(uFlags & BF_TOP)    contentsRect->top    += add;
1174         if(uFlags & BF_BOTTOM) contentsRect->bottom -= add;
1175     }
1176 
1177     /* Cleanup */
1178     SelectObject(hdc, SavePen);
1179     MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1180     if(InnerI != -1) DeleteObject (InnerPen);
1181     if(OuterI != -1) DeleteObject (OuterPen);
1182 
1183     return retval;
1184 }
1185 
1186 /***********************************************************************
1187  *           draw_rect_edge
1188  *
1189  * Same as DrawEdge invoked without BF_DIAGONAL
1190  */
1191 static HRESULT draw_rect_edge (HDC hdc, HTHEME theme, int part, int state,
1192                                const RECT* rc, UINT uType,
1193                                UINT uFlags, LPRECT contentsRect)
1194 {
1195     signed char LTInnerI, LTOuterI;
1196     signed char RBInnerI, RBOuterI;
1197     HPEN LTInnerPen, LTOuterPen;
1198     HPEN RBInnerPen, RBOuterPen;
1199     RECT InnerRect = *rc;
1200     POINT SavePoint;
1201     HPEN SavePen;
1202     int LBpenplus = 0;
1203     int LTpenplus = 0;
1204     int RTpenplus = 0;
1205     int RBpenplus = 0;
1206     HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1207                        || (uType & BDR_OUTER) == BDR_OUTER)
1208                       && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1209 
1210     /* Init some vars */
1211     LTInnerPen = LTOuterPen = RBInnerPen = RBOuterPen = GetStockObject(NULL_PEN);
1212     SavePen = SelectObject(hdc, LTInnerPen);
1213 
1214     /* Determine the colors of the edges */
1215     if(uFlags & BF_MONO)
1216     {
1217         LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1218         LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1219     }
1220     else if(uFlags & BF_FLAT)
1221     {
1222         LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1223         LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1224 
1225         if( LTInnerI != -1 ) LTInnerI = RBInnerI = EDGE_FILL;
1226     }
1227     else if(uFlags & BF_SOFT)
1228     {
1229         LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1230         LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1231         RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1232         RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1233     }
1234     else
1235     {
1236         LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1237         LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1238         RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1239         RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1240     }
1241 
1242     if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT)   LBpenplus = 1;
1243     if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT)       RTpenplus = 1;
1244     if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) RBpenplus = 1;
1245     if((uFlags & BF_TOPLEFT) == BF_TOPLEFT)         LTpenplus = 1;
1246 
1247     if(LTInnerI != -1) LTInnerPen = get_edge_pen (LTInnerI, theme, part, state);
1248     if(LTOuterI != -1) LTOuterPen = get_edge_pen (LTOuterI, theme, part, state);
1249     if(RBInnerI != -1) RBInnerPen = get_edge_pen (RBInnerI, theme, part, state);
1250     if(RBOuterI != -1) RBOuterPen = get_edge_pen (RBOuterI, theme, part, state);
1251 
1252     MoveToEx(hdc, 0, 0, &SavePoint);
1253 
1254     /* Draw the outer edge */
1255     SelectObject(hdc, LTOuterPen);
1256     if(uFlags & BF_TOP)
1257     {
1258         MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1259         LineTo(hdc, InnerRect.right, InnerRect.top);
1260     }
1261     if(uFlags & BF_LEFT)
1262     {
1263         MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1264         LineTo(hdc, InnerRect.left, InnerRect.bottom);
1265     }
1266     SelectObject(hdc, RBOuterPen);
1267     if(uFlags & BF_BOTTOM)
1268     {
1269         MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1270         LineTo(hdc, InnerRect.left-1, InnerRect.bottom-1);
1271     }
1272     if(uFlags & BF_RIGHT)
1273     {
1274         MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1275         LineTo(hdc, InnerRect.right-1, InnerRect.top-1);
1276     }
1277 
1278     /* Draw the inner edge */
1279     SelectObject(hdc, LTInnerPen);
1280     if(uFlags & BF_TOP)
1281     {
1282         MoveToEx(hdc, InnerRect.left+LTpenplus, InnerRect.top+1, NULL);
1283         LineTo(hdc, InnerRect.right-RTpenplus, InnerRect.top+1);
1284     }
1285     if(uFlags & BF_LEFT)
1286     {
1287         MoveToEx(hdc, InnerRect.left+1, InnerRect.top+LTpenplus, NULL);
1288         LineTo(hdc, InnerRect.left+1, InnerRect.bottom-LBpenplus);
1289     }
1290     SelectObject(hdc, RBInnerPen);
1291     if(uFlags & BF_BOTTOM)
1292     {
1293         MoveToEx(hdc, InnerRect.right-1-RBpenplus, InnerRect.bottom-2, NULL);
1294         LineTo(hdc, InnerRect.left-1+LBpenplus, InnerRect.bottom-2);
1295     }
1296     if(uFlags & BF_RIGHT)
1297     {
1298         MoveToEx(hdc, InnerRect.right-2, InnerRect.bottom-1-RBpenplus, NULL);
1299         LineTo(hdc, InnerRect.right-2, InnerRect.top-1+RTpenplus);
1300     }
1301 
1302     if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
1303     {
1304         int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1305                 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1306 
1307         if(uFlags & BF_LEFT)   InnerRect.left   += add;
1308         if(uFlags & BF_RIGHT)  InnerRect.right  -= add;
1309         if(uFlags & BF_TOP)    InnerRect.top    += add;
1310         if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
1311 
1312         if((uFlags & BF_MIDDLE) && retval)
1313         {
1314             HBRUSH br = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1315                 theme, part, state);
1316             FillRect(hdc, &InnerRect, br);
1317             DeleteObject (br);
1318         }
1319 
1320         if(uFlags & BF_ADJUST)
1321             *contentsRect = InnerRect;
1322     }
1323 
1324     /* Cleanup */
1325     SelectObject(hdc, SavePen);
1326     MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1327     if(LTInnerI != -1) DeleteObject (LTInnerPen);
1328     if(LTOuterI != -1) DeleteObject (LTOuterPen);
1329     if(RBInnerI != -1) DeleteObject (RBInnerPen);
1330     if(RBOuterI != -1) DeleteObject (RBOuterPen);
1331     return retval;
1332 }
1333 
1334 
1335 /***********************************************************************
1336  *      DrawThemeEdge                                       (UXTHEME.@)
1337  *
1338  * DrawThemeEdge() is pretty similar to the vanilla DrawEdge() - the
1339  * difference is that it does not rely on the system colors alone, but
1340  * also allows color specification in the theme.
1341  */
1342 HRESULT WINAPI DrawThemeEdge(HTHEME hTheme, HDC hdc, int iPartId,
1343                              int iStateId, const RECT *pDestRect, UINT uEdge,
1344                              UINT uFlags, RECT *pContentRect)
1345 {
1346     TRACE("%d %d 0x%08x 0x%08x\n", iPartId, iStateId, uEdge, uFlags);
1347     if(!hTheme)
1348         return E_HANDLE;
1349 
1350     if(uFlags & BF_DIAGONAL)
1351         return draw_diag_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1352             uEdge, uFlags, pContentRect);
1353     else
1354         return draw_rect_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1355             uEdge, uFlags, pContentRect);
1356 }
1357 
1358 
1359 /***********************************************************************
1360  *      DrawThemeIcon                                       (UXTHEME.@)
1361  */
1362 HRESULT WINAPI DrawThemeIcon(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1363                              const RECT *pRect, HIMAGELIST himl, int iImageIndex)
1364 {
1365     FIXME("%d %d: stub\n", iPartId, iStateId);
1366     if(!hTheme)
1367         return E_HANDLE;
1368     return E_NOTIMPL;
1369 }
1370 
1371 typedef int (WINAPI * DRAWSHADOWTEXT)(HDC hdc, LPCWSTR pszText, UINT cch, RECT *prc, DWORD dwFlags,
1372                           COLORREF crText, COLORREF crShadow, int ixOffset, int iyOffset);
1373 
1374 /***********************************************************************
1375  *      DrawThemeTextEx                                     (UXTHEME.@)
1376  */
1377 HRESULT
1378 WINAPI
1379 DrawThemeTextEx(
1380     _In_ HTHEME hTheme,
1381     _In_ HDC hdc,
1382     _In_ int iPartId,
1383     _In_ int iStateId,
1384     _In_ LPCWSTR pszText,
1385     _In_ int iCharCount,
1386     _In_ DWORD dwTextFlags,
1387     _Inout_ LPRECT pRect,
1388     _In_ const DTTOPTS *options
1389 )
1390 {
1391     HRESULT hr;
1392     HFONT hFont = NULL;
1393     HGDIOBJ oldFont = NULL;
1394     LOGFONTW logfont;
1395     COLORREF textColor;
1396     COLORREF oldTextColor;
1397     COLORREF shadowColor;
1398     POINT ptShadowOffset;
1399     int oldBkMode;
1400     RECT rt;
1401     int iShadowType;
1402     DWORD optFlags;
1403 
1404     if(!hTheme)
1405         return E_HANDLE;
1406     if (!options)
1407         return E_NOTIMPL;
1408 
1409     optFlags = options->dwFlags;
1410 
1411     hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1412     if(SUCCEEDED(hr))
1413     {
1414         hFont = CreateFontIndirectW(&logfont);
1415         if(!hFont)
1416         {
1417             ERR("Failed to create font\n");
1418         }
1419     }
1420 
1421     CopyRect(&rt, pRect);
1422     if(hFont)
1423         oldFont = SelectObject(hdc, hFont);
1424 
1425     oldBkMode = SetBkMode(hdc, TRANSPARENT);
1426 
1427     if (optFlags & DTT_TEXTCOLOR)
1428     {
1429         textColor = options->crText;
1430     }
1431     else
1432     {
1433         int textColorProp = TMT_TEXTCOLOR;
1434         if (optFlags & DTT_COLORPROP)
1435             textColorProp = options->iColorPropId;
1436 
1437         if (FAILED(GetThemeColor(hTheme, iPartId, iStateId, textColorProp, &textColor)))
1438             textColor = GetTextColor(hdc);
1439     }
1440 
1441     hr = GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_TEXTSHADOWTYPE, &iShadowType);
1442     if (SUCCEEDED(hr))
1443     {
1444         hr = GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTSHADOWCOLOR, &shadowColor);
1445         if (FAILED(hr))
1446         {
1447             ERR("GetThemeColor failed\n");
1448         }
1449 
1450         hr = GetThemePosition(hTheme, iPartId, iStateId, TMT_TEXTSHADOWOFFSET, &ptShadowOffset);
1451         if (FAILED(hr))
1452         {
1453             ERR("GetThemePosition failed\n");
1454         }
1455 
1456         if (iShadowType == TST_SINGLE)
1457         {
1458             oldTextColor = SetTextColor(hdc, shadowColor);
1459             OffsetRect(&rt, ptShadowOffset.x, ptShadowOffset.y);
1460             DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
1461             OffsetRect(&rt, -ptShadowOffset.x, -ptShadowOffset.y);
1462             SetTextColor(hdc, oldTextColor);
1463         }
1464         else if (iShadowType == TST_CONTINUOUS)
1465         {
1466             HANDLE hcomctl32 = GetModuleHandleW(L"comctl32.dll");
1467             DRAWSHADOWTEXT pDrawShadowText;
1468             if (!hcomctl32)
1469             {
1470                 hcomctl32 = LoadLibraryW(L"comctl32.dll");
1471                 if (!hcomctl32)
1472                     ERR("Failed to load comctl32\n");
1473             }
1474 
1475             pDrawShadowText = (DRAWSHADOWTEXT)GetProcAddress(hcomctl32, "DrawShadowText");
1476             if (pDrawShadowText)
1477             {
1478                 pDrawShadowText(hdc, pszText, iCharCount, &rt, dwTextFlags, textColor, shadowColor, ptShadowOffset.x, ptShadowOffset.y);
1479                 goto cleanup;
1480             }
1481         }
1482     }
1483 
1484     oldTextColor = SetTextColor(hdc, textColor);
1485     DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
1486     SetTextColor(hdc, oldTextColor);
1487 cleanup:
1488     SetBkMode(hdc, oldBkMode);
1489 
1490     if(hFont) {
1491         SelectObject(hdc, oldFont);
1492         DeleteObject(hFont);
1493     }
1494     return S_OK;
1495 }
1496 
1497 /***********************************************************************
1498  *      DrawThemeText                                       (UXTHEME.@)
1499  */
1500 HRESULT WINAPI DrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1501                              LPCWSTR pszText, int iCharCount, DWORD dwTextFlags,
1502                              DWORD dwTextFlags2, const RECT *pRect)
1503 {
1504     DTTOPTS opts = { 0 };
1505     RECT rt = *pRect;
1506 
1507     TRACE("(%p %p %d %d %s:%d 0x%08lx 0x%08lx %p)\n", hTheme, hdc, iPartId, iStateId,
1508         debugstr_wn(pszText, iCharCount), iCharCount, dwTextFlags, dwTextFlags2, pRect);
1509 
1510     if (dwTextFlags2 & DTT_GRAYED)
1511     {
1512         opts.dwFlags = DTT_TEXTCOLOR;
1513         opts.crText = GetSysColor(COLOR_GRAYTEXT);
1514     }
1515     opts.dwSize = sizeof(opts);
1516 
1517     return DrawThemeTextEx(hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, &rt, &opts);
1518 }
1519 
1520 /***********************************************************************
1521  *      GetThemeBackgroundContentRect                       (UXTHEME.@)
1522  */
1523 HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId,
1524                                              int iStateId,
1525                                              const RECT *pBoundingRect,
1526                                              RECT *pContentRect)
1527 {
1528     MARGINS margin;
1529     HRESULT hr;
1530 
1531     TRACE("(%d,%d)\n", iPartId, iStateId);
1532     if(!hTheme)
1533         return E_HANDLE;
1534 
1535     /* try content margins property... */
1536     hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1537     if(SUCCEEDED(hr)) {
1538         pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1539         pContentRect->top  = pBoundingRect->top + margin.cyTopHeight;
1540         pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1541         pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1542     } else {
1543         /* otherwise, try to determine content rect from the background type and props */
1544         int bgtype = BT_BORDERFILL;
1545         *pContentRect = *pBoundingRect;
1546 
1547         GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1548         if(bgtype == BT_BORDERFILL) {
1549             int bordersize = 1;
1550 
1551             GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1552             InflateRect(pContentRect, -bordersize, -bordersize);
1553         } else if ((bgtype == BT_IMAGEFILE)
1554                 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1555                 TMT_SIZINGMARGINS, NULL, &margin)))) {
1556             pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1557             pContentRect->top  = pBoundingRect->top + margin.cyTopHeight;
1558             pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1559             pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1560         }
1561         /* If nothing was found, leave unchanged */
1562     }
1563 
1564     TRACE("%s\n", wine_dbgstr_rect(pContentRect));
1565 
1566     return S_OK;
1567 }
1568 
1569 /***********************************************************************
1570  *      GetThemeBackgroundExtent                            (UXTHEME.@)
1571  */
1572 HRESULT WINAPI GetThemeBackgroundExtent(HTHEME hTheme, HDC hdc, int iPartId,
1573                                         int iStateId, const RECT *pContentRect,
1574                                         RECT *pExtentRect)
1575 {
1576     MARGINS margin;
1577     HRESULT hr;
1578 
1579     TRACE("(%d,%d)\n", iPartId, iStateId);
1580     if(!hTheme)
1581         return E_HANDLE;
1582 
1583     /* try content margins property... */
1584     hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1585     if(SUCCEEDED(hr)) {
1586         pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1587         pExtentRect->top  = pContentRect->top - margin.cyTopHeight;
1588         pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1589         pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1590     } else {
1591         /* otherwise, try to determine content rect from the background type and props */
1592         int bgtype = BT_BORDERFILL;
1593         *pExtentRect = *pContentRect;
1594 
1595         GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1596         if(bgtype == BT_BORDERFILL) {
1597             int bordersize = 1;
1598 
1599             GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1600             InflateRect(pExtentRect, bordersize, bordersize);
1601         } else if ((bgtype == BT_IMAGEFILE)
1602                 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1603                 TMT_SIZINGMARGINS, NULL, &margin)))) {
1604             pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1605             pExtentRect->top  = pContentRect->top - margin.cyTopHeight;
1606             pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1607             pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1608         }
1609         /* If nothing was found, leave unchanged */
1610     }
1611 
1612     TRACE("%s\n", wine_dbgstr_rect(pExtentRect));
1613 
1614     return S_OK;
1615 }
1616 
1617 
1618 static HBITMAP UXTHEME_DrawThemePartToDib(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCRECT pRect)
1619 {
1620     HDC hdcMem;
1621     BITMAPINFO bmi;
1622     HBITMAP hbmp, hbmpOld;
1623     HBRUSH hbrBack;
1624 
1625     hdcMem = CreateCompatibleDC(0);
1626 
1627     memset(&bmi, 0, sizeof(bmi));
1628     bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
1629     bmi.bmiHeader.biWidth = pRect->right;
1630     bmi.bmiHeader.biHeight = -pRect->bottom;
1631     bmi.bmiHeader.biPlanes = 1;
1632     bmi.bmiHeader.biBitCount = 32;
1633     hbmp = CreateDIBSection(hdcMem, &bmi, DIB_RGB_COLORS , NULL, 0, 0);
1634 
1635     hbmpOld = (HBITMAP)SelectObject(hdcMem, hbmp);
1636 
1637     /* FIXME: use an internal function that doesn't do transparent blt */
1638     hbrBack = CreateSolidBrush(RGB(255,0,255));
1639 
1640     FillRect(hdcMem, pRect, hbrBack);
1641 
1642     DrawThemeBackground(hTheme, hdcMem, iPartId, iStateId, pRect, NULL);
1643 
1644     DeleteObject(hbrBack);
1645     SelectObject(hdcMem, hbmpOld);
1646     DeleteObject(hdcMem);
1647 
1648     return hbmp;
1649 }
1650 
1651 #define PT_IN_RECT(lprc,x,y) ( x >= lprc->left && x < lprc->right && \
1652                                y >= lprc->top  && y < lprc->bottom)
1653 
1654 static HRGN UXTHEME_RegionFromDibBits(RGBQUAD* pBuffer, RGBQUAD* pclrTransparent, LPCRECT pRect)
1655 {
1656     int x, y, xstart;
1657     int cMaxRgnRects, cRgnDataSize, cRgnRects;
1658     RECT* prcCurrent;
1659     PRGNDATA prgnData;
1660     ULONG clrTransparent, *pclrCurrent;
1661     HRGN hrgnRet;
1662 
1663     pclrCurrent = (PULONG)pBuffer;
1664     clrTransparent = *(PULONG)pclrTransparent;
1665 
1666     /* Create a region and pre-allocate memory enough for 3 spaces in one row*/
1667     cRgnRects = 0;
1668     cMaxRgnRects = 4* (pRect->bottom-pRect->top);
1669     cRgnDataSize = sizeof(RGNDATA) + cMaxRgnRects * sizeof(RECT);
1670 
1671     /* Allocate the region data */
1672     prgnData = (PRGNDATA)HeapAlloc(GetProcessHeap(), 0, cRgnDataSize);
1673 
1674     prcCurrent = (PRECT)prgnData->Buffer;
1675 
1676     /* Calculate the region rects */
1677     y=0;
1678     /* Scan each line of the bitmap */
1679     while(y<pRect->bottom)
1680     {
1681         x=0;
1682         /* Scan each pixel */
1683         while (x<pRect->right)
1684         {
1685             /* Check if the pixel is not transparent and it is in the requested rect */
1686             if(*pclrCurrent != clrTransparent && PT_IN_RECT(pRect,x,y))
1687             {
1688                 xstart = x;
1689                 /* Find the end of the opaque row of pixels */
1690                 while (x<pRect->right)
1691                 {
1692                     if(*pclrCurrent == clrTransparent || !PT_IN_RECT(pRect,x,y))
1693                         break;
1694                     x++;
1695                     pclrCurrent++;
1696                 }
1697 
1698                 /* Add the scaned line to the region */
1699                 SetRect(prcCurrent, xstart, y,x,y+1);
1700                 prcCurrent++;
1701                 cRgnRects++;
1702 
1703                 /* Increase the size of the buffer if it is full */
1704                 if(cRgnRects == cMaxRgnRects)
1705                 {
1706                     cMaxRgnRects *=2;
1707                     cRgnDataSize = sizeof(RGNDATA) + cMaxRgnRects * sizeof(RECT);
1708                     prgnData = (PRGNDATA)HeapReAlloc(GetProcessHeap(),
1709                                                      0,
1710                                                      prgnData,
1711                                                      cRgnDataSize);
1712                     prcCurrent = (RECT*)prgnData->Buffer + cRgnRects;
1713                 }
1714             }
1715             else
1716             {
1717                 x++;
1718                 pclrCurrent++;
1719             }
1720         }
1721         y++;
1722     }
1723 
1724     /* Fill the region data header */
1725     prgnData->rdh.dwSize = sizeof(prgnData->rdh);
1726     prgnData->rdh.iType = RDH_RECTANGLES;
1727     prgnData->rdh.nCount = cRgnRects;
1728     prgnData->rdh.nRgnSize = cRgnDataSize;
1729     prgnData->rdh.rcBound = *pRect;
1730 
1731     /* Create the region*/
1732     hrgnRet = ExtCreateRegion (NULL, cRgnDataSize, prgnData);
1733 
1734     /* Free the region data*/
1735     HeapFree(GetProcessHeap(),0,prgnData);
1736 
1737     /* return the region*/
1738     return hrgnRet;
1739 }
1740 
1741 HRESULT UXTHEME_GetImageBackBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCRECT pRect, HRGN *pRegion)
1742 {
1743     HBITMAP hbmp;
1744     DIBSECTION dib;
1745     RGBQUAD clrTransparent = {0xFF,0x0, 0xFF,0x0};
1746 
1747     /* Draw the theme part to a dib */
1748     hbmp = UXTHEME_DrawThemePartToDib(hTheme, hdc, iPartId, iStateId, pRect);
1749 
1750     /* Retrieve the info of the dib section */
1751     GetObjectW(hbmp, sizeof (DIBSECTION), &dib);
1752 
1753     /* Convert the bits of the dib section to a region */
1754     *pRegion = UXTHEME_RegionFromDibBits((RGBQUAD*)dib.dsBm.bmBits, &clrTransparent, pRect);
1755 
1756     /* Free the temp bitmap */
1757     DeleteObject(hbmp);
1758 
1759     return S_OK;
1760 }
1761 
1762 /***********************************************************************
1763  *      GetThemeBackgroundRegion                            (UXTHEME.@)
1764  *
1765  * Calculate the background region, taking into consideration transparent areas
1766  * of the background image.
1767  */
1768 HRESULT WINAPI GetThemeBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId,
1769                                         int iStateId, const RECT *pRect,
1770                                         HRGN *pRegion)
1771 {
1772     HRESULT hr = S_OK;
1773     int bgtype = BT_BORDERFILL;
1774 
1775     TRACE("(%p,%p,%d,%d)\n", hTheme, hdc, iPartId, iStateId);
1776     if(!hTheme)
1777         return E_HANDLE;
1778     if(!pRect || !pRegion)
1779         return E_POINTER;
1780 
1781     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1782     if(bgtype == BT_IMAGEFILE) {
1783         hr = UXTHEME_GetImageBackBackgroundRegion(hTheme, hdc, iPartId, iStateId, pRect, pRegion);
1784     }
1785     else if(bgtype == BT_BORDERFILL) {
1786         *pRegion = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
1787         if(!*pRegion)
1788             hr = HRESULT_FROM_WIN32(GetLastError());
1789     }
1790     else {
1791         FIXME("Unknown background type\n");
1792         /* This should never happen, and hence I don't know what to return */
1793         hr = E_FAIL;
1794     }
1795     return hr;
1796 }
1797 
1798 /* compute part size for "borderfill" backgrounds */
1799 static HRESULT get_border_background_size (HTHEME hTheme, int iPartId,
1800                                            int iStateId, THEMESIZE eSize, POINT* psz)
1801 {
1802     HRESULT hr = S_OK;
1803     int bordersize = 1;
1804 
1805     if (SUCCEEDED (hr = GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE,
1806         &bordersize)))
1807     {
1808         psz->x = psz->y = 2*bordersize;
1809         if (eSize != TS_MIN)
1810         {
1811             psz->x++;
1812             psz->y++;
1813         }
1814     }
1815     return hr;
1816 }
1817 
1818 /***********************************************************************
1819  *      GetThemePartSize                                    (UXTHEME.@)
1820  */
1821 HRESULT WINAPI GetThemePartSize(HTHEME hTheme, HDC hdc, int iPartId,
1822                                 int iStateId, RECT *prc, THEMESIZE eSize,
1823                                 SIZE *psz)
1824 {
1825     int bgtype = BT_BORDERFILL;
1826     HRESULT hr = S_OK;
1827     POINT size = {1, 1};
1828 
1829     if(!hTheme)
1830         return E_HANDLE;
1831 
1832     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1833     if (bgtype == BT_NONE)
1834         /* do nothing */;
1835     else if(bgtype == BT_IMAGEFILE)
1836         hr = get_image_part_size (hTheme, hdc, iPartId, iStateId, prc, eSize, &size);
1837     else if(bgtype == BT_BORDERFILL)
1838         hr = get_border_background_size (hTheme, iPartId, iStateId, eSize, &size);
1839     else {
1840         FIXME("Unknown background type\n");
1841         /* This should never happen, and hence I don't know what to return */
1842         hr = E_FAIL;
1843     }
1844     psz->cx = size.x;
1845     psz->cy = size.y;
1846     return hr;
1847 }
1848 
1849 
1850 /***********************************************************************
1851  *      GetThemeTextExtent                                  (UXTHEME.@)
1852  */
1853 HRESULT WINAPI GetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId,
1854                                   int iStateId, LPCWSTR pszText, int iCharCount,
1855                                   DWORD dwTextFlags, const RECT *pBoundingRect,
1856                                   RECT *pExtentRect)
1857 {
1858     HRESULT hr;
1859     HFONT hFont = NULL;
1860     HGDIOBJ oldFont = NULL;
1861     LOGFONTW logfont;
1862     RECT rt = {0,0,0xFFFF,0xFFFF};
1863 
1864     TRACE("%d %d: stub\n", iPartId, iStateId);
1865     if(!hTheme)
1866         return E_HANDLE;
1867 
1868     if(pBoundingRect)
1869         rt = *pBoundingRect;
1870 
1871     hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1872     if(SUCCEEDED(hr)) {
1873         hFont = CreateFontIndirectW(&logfont);
1874         if(!hFont)
1875             TRACE("Failed to create font\n");
1876     }
1877     if(hFont)
1878         oldFont = SelectObject(hdc, hFont);
1879 
1880     DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags|DT_CALCRECT);
1881     *pExtentRect = rt;
1882 
1883     if(hFont) {
1884         SelectObject(hdc, oldFont);
1885         DeleteObject(hFont);
1886     }
1887     return S_OK;
1888 }
1889 
1890 /***********************************************************************
1891  *      GetThemeTextMetrics                                 (UXTHEME.@)
1892  */
1893 HRESULT WINAPI GetThemeTextMetrics(HTHEME hTheme, HDC hdc, int iPartId,
1894                                    int iStateId, TEXTMETRICW *ptm)
1895 {
1896     HRESULT hr;
1897     HFONT hFont = NULL;
1898     HGDIOBJ oldFont = NULL;
1899     LOGFONTW logfont;
1900 
1901     TRACE("(%p, %p, %d, %d)\n", hTheme, hdc, iPartId, iStateId);
1902     if(!hTheme)
1903         return E_HANDLE;
1904 
1905     hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1906     if(SUCCEEDED(hr)) {
1907         hFont = CreateFontIndirectW(&logfont);
1908         if(!hFont)
1909             TRACE("Failed to create font\n");
1910     }
1911     if(hFont)
1912         oldFont = SelectObject(hdc, hFont);
1913 
1914     if(!GetTextMetricsW(hdc, ptm))
1915         hr = HRESULT_FROM_WIN32(GetLastError());
1916 
1917     if(hFont) {
1918         SelectObject(hdc, oldFont);
1919         DeleteObject(hFont);
1920     }
1921     return hr;
1922 }
1923 
1924 /***********************************************************************
1925  *      IsThemeBackgroundPartiallyTransparent               (UXTHEME.@)
1926  */
1927 BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId,
1928                                                   int iStateId)
1929 {
1930     int bgtype = BT_BORDERFILL;
1931     RECT rect = {0, 0, 0, 0};
1932     HBITMAP bmpSrc;
1933     RECT rcSrc;
1934     BOOL hasAlpha;
1935     INT transparent;
1936     COLORREF transparentcolor;
1937 
1938     TRACE("(%d,%d)\n", iPartId, iStateId);
1939 
1940     if(!hTheme)
1941         return FALSE;
1942 
1943     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1944 
1945 #ifdef __REACTOS__
1946     if (bgtype == BT_NONE) return TRUE;
1947 #endif
1948     if (bgtype != BT_IMAGEFILE) return FALSE;
1949 
1950     if(FAILED (UXTHEME_LoadImage (hTheme, 0, iPartId, iStateId, &rect, FALSE,
1951                                   &bmpSrc, &rcSrc, &hasAlpha)))
1952         return FALSE;
1953 
1954     get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
1955         &transparentcolor, FALSE);
1956     return (transparent != ALPHABLEND_NONE);
1957 }
1958