xref: /reactos/dll/win32/uxtheme/draw.c (revision 8a978a17)
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  *      DrawThemeText                                       (UXTHEME.@)
1376  */
1377 HRESULT WINAPI DrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1378                              LPCWSTR pszText, int iCharCount, DWORD dwTextFlags,
1379                              DWORD dwTextFlags2, const RECT *pRect)
1380 {
1381     HRESULT hr;
1382     HFONT hFont = NULL;
1383     HGDIOBJ oldFont = NULL;
1384     LOGFONTW logfont;
1385     COLORREF textColor;
1386     COLORREF oldTextColor;
1387     COLORREF shadowColor;
1388     POINT ptShadowOffset;
1389     int oldBkMode;
1390     RECT rt;
1391     int iShadowType;
1392 
1393     TRACE("%d %d: stub\n", iPartId, iStateId);
1394     if(!hTheme)
1395         return E_HANDLE;
1396 
1397     hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1398     if(SUCCEEDED(hr))
1399     {
1400         hFont = CreateFontIndirectW(&logfont);
1401         if(!hFont)
1402         {
1403             ERR("Failed to create font\n");
1404         }
1405     }
1406 
1407     CopyRect(&rt, pRect);
1408     if(hFont)
1409         oldFont = SelectObject(hdc, hFont);
1410 
1411     oldBkMode = SetBkMode(hdc, TRANSPARENT);
1412 
1413     if(dwTextFlags2 & DTT_GRAYED)
1414         textColor = GetSysColor(COLOR_GRAYTEXT);
1415     else {
1416         if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTCOLOR, &textColor)))
1417             textColor = GetTextColor(hdc);
1418     }
1419 
1420     hr = GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_TEXTSHADOWTYPE, &iShadowType);
1421     if (SUCCEEDED(hr))
1422     {
1423         hr = GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTSHADOWCOLOR, &shadowColor);
1424         if (FAILED(hr))
1425         {
1426             ERR("GetThemeColor failed\n");
1427         }
1428 
1429         hr = GetThemePosition(hTheme, iPartId, iStateId, TMT_TEXTSHADOWOFFSET, &ptShadowOffset);
1430         if (FAILED(hr))
1431         {
1432             ERR("GetThemePosition failed\n");
1433         }
1434 
1435         if (iShadowType == TST_SINGLE)
1436         {
1437             oldTextColor = SetTextColor(hdc, shadowColor);
1438             OffsetRect(&rt, ptShadowOffset.x, ptShadowOffset.y);
1439             DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
1440             OffsetRect(&rt, -ptShadowOffset.x, -ptShadowOffset.y);
1441             SetTextColor(hdc, oldTextColor);
1442         }
1443         else if (iShadowType == TST_CONTINUOUS)
1444         {
1445             HANDLE hcomctl32 = GetModuleHandleW(L"comctl32.dll");
1446             DRAWSHADOWTEXT pDrawShadowText;
1447             if (!hcomctl32)
1448             {
1449                 hcomctl32 = LoadLibraryW(L"comctl32.dll");
1450                 if (!hcomctl32)
1451                     ERR("Failed to load comctl32\n");
1452             }
1453 
1454             pDrawShadowText = (DRAWSHADOWTEXT)GetProcAddress(hcomctl32, "DrawShadowText");
1455             if (pDrawShadowText)
1456             {
1457                 pDrawShadowText(hdc, pszText, iCharCount, &rt, dwTextFlags, textColor, shadowColor, ptShadowOffset.x, ptShadowOffset.y);
1458                 goto cleanup;
1459             }
1460         }
1461     }
1462 
1463     oldTextColor = SetTextColor(hdc, textColor);
1464     DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
1465     SetTextColor(hdc, oldTextColor);
1466 cleanup:
1467     SetBkMode(hdc, oldBkMode);
1468 
1469     if(hFont) {
1470         SelectObject(hdc, oldFont);
1471         DeleteObject(hFont);
1472     }
1473     return S_OK;
1474 }
1475 
1476 /***********************************************************************
1477  *      GetThemeBackgroundContentRect                       (UXTHEME.@)
1478  */
1479 HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId,
1480                                              int iStateId,
1481                                              const RECT *pBoundingRect,
1482                                              RECT *pContentRect)
1483 {
1484     MARGINS margin;
1485     HRESULT hr;
1486 
1487     TRACE("(%d,%d)\n", iPartId, iStateId);
1488     if(!hTheme)
1489         return E_HANDLE;
1490 
1491     /* try content margins property... */
1492     hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1493     if(SUCCEEDED(hr)) {
1494         pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1495         pContentRect->top  = pBoundingRect->top + margin.cyTopHeight;
1496         pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1497         pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1498     } else {
1499         /* otherwise, try to determine content rect from the background type and props */
1500         int bgtype = BT_BORDERFILL;
1501         *pContentRect = *pBoundingRect;
1502 
1503         GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1504         if(bgtype == BT_BORDERFILL) {
1505             int bordersize = 1;
1506 
1507             GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1508             InflateRect(pContentRect, -bordersize, -bordersize);
1509         } else if ((bgtype == BT_IMAGEFILE)
1510                 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1511                 TMT_SIZINGMARGINS, NULL, &margin)))) {
1512             pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1513             pContentRect->top  = pBoundingRect->top + margin.cyTopHeight;
1514             pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1515             pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1516         }
1517         /* If nothing was found, leave unchanged */
1518     }
1519 
1520     TRACE("%s\n", wine_dbgstr_rect(pContentRect));
1521 
1522     return S_OK;
1523 }
1524 
1525 /***********************************************************************
1526  *      GetThemeBackgroundExtent                            (UXTHEME.@)
1527  */
1528 HRESULT WINAPI GetThemeBackgroundExtent(HTHEME hTheme, HDC hdc, int iPartId,
1529                                         int iStateId, const RECT *pContentRect,
1530                                         RECT *pExtentRect)
1531 {
1532     MARGINS margin;
1533     HRESULT hr;
1534 
1535     TRACE("(%d,%d)\n", iPartId, iStateId);
1536     if(!hTheme)
1537         return E_HANDLE;
1538 
1539     /* try content margins property... */
1540     hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1541     if(SUCCEEDED(hr)) {
1542         pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1543         pExtentRect->top  = pContentRect->top - margin.cyTopHeight;
1544         pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1545         pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1546     } else {
1547         /* otherwise, try to determine content rect from the background type and props */
1548         int bgtype = BT_BORDERFILL;
1549         *pExtentRect = *pContentRect;
1550 
1551         GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1552         if(bgtype == BT_BORDERFILL) {
1553             int bordersize = 1;
1554 
1555             GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1556             InflateRect(pExtentRect, bordersize, bordersize);
1557         } else if ((bgtype == BT_IMAGEFILE)
1558                 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1559                 TMT_SIZINGMARGINS, NULL, &margin)))) {
1560             pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1561             pExtentRect->top  = pContentRect->top - margin.cyTopHeight;
1562             pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1563             pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1564         }
1565         /* If nothing was found, leave unchanged */
1566     }
1567 
1568     TRACE("%s\n", wine_dbgstr_rect(pExtentRect));
1569 
1570     return S_OK;
1571 }
1572 
1573 
1574 static HBITMAP UXTHEME_DrawThemePartToDib(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCRECT pRect)
1575 {
1576     HDC hdcMem;
1577     BITMAPINFO bmi;
1578     HBITMAP hbmp, hbmpOld;
1579     HBRUSH hbrBack;
1580 
1581     hdcMem = CreateCompatibleDC(0);
1582 
1583     memset(&bmi, 0, sizeof(bmi));
1584     bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
1585     bmi.bmiHeader.biWidth = pRect->right;
1586     bmi.bmiHeader.biHeight = -pRect->bottom;
1587     bmi.bmiHeader.biPlanes = 1;
1588     bmi.bmiHeader.biBitCount = 32;
1589     hbmp = CreateDIBSection(hdcMem, &bmi, DIB_RGB_COLORS , NULL, 0, 0);
1590 
1591     hbmpOld = (HBITMAP)SelectObject(hdcMem, hbmp);
1592 
1593     /* FIXME: use an internal function that doesn't do transparent blt */
1594     hbrBack = CreateSolidBrush(RGB(255,0,255));
1595 
1596     FillRect(hdcMem, pRect, hbrBack);
1597 
1598     DrawThemeBackground(hTheme, hdcMem, iPartId, iStateId, pRect, NULL);
1599 
1600     DeleteObject(hbrBack);
1601     SelectObject(hdcMem, hbmpOld);
1602     DeleteObject(hdcMem);
1603 
1604     return hbmp;
1605 }
1606 
1607 #define PT_IN_RECT(lprc,x,y) ( x >= lprc->left && x < lprc->right && \
1608                                y >= lprc->top  && y < lprc->bottom)
1609 
1610 static HRGN UXTHEME_RegionFromDibBits(RGBQUAD* pBuffer, RGBQUAD* pclrTransparent, LPCRECT pRect)
1611 {
1612     int x, y, xstart;
1613     int cMaxRgnRects, cRgnDataSize, cRgnRects;
1614     RECT* prcCurrent;
1615     PRGNDATA prgnData;
1616     ULONG clrTransparent, *pclrCurrent;
1617     HRGN hrgnRet;
1618 
1619     pclrCurrent = (PULONG)pBuffer;
1620     clrTransparent = *(PULONG)pclrTransparent;
1621 
1622     /* Create a region and pre-allocate memory enough for 3 spaces in one row*/
1623     cRgnRects = 0;
1624     cMaxRgnRects = 4* (pRect->bottom-pRect->top);
1625     cRgnDataSize = sizeof(RGNDATA) + cMaxRgnRects * sizeof(RECT);
1626 
1627     /* Allocate the region data */
1628     prgnData = (PRGNDATA)HeapAlloc(GetProcessHeap(), 0, cRgnDataSize);
1629 
1630     prcCurrent = (PRECT)prgnData->Buffer;
1631 
1632     /* Calculate the region rects */
1633     y=0;
1634     /* Scan each line of the bitmap */
1635     while(y<pRect->bottom)
1636     {
1637         x=0;
1638         /* Scan each pixel */
1639         while (x<pRect->right)
1640         {
1641             /* Check if the pixel is not transparent and it is in the requested rect */
1642             if(*pclrCurrent != clrTransparent && PT_IN_RECT(pRect,x,y))
1643             {
1644                 xstart = x;
1645                 /* Find the end of the opaque row of pixels */
1646                 while (x<pRect->right)
1647                 {
1648                     if(*pclrCurrent == clrTransparent || !PT_IN_RECT(pRect,x,y))
1649                         break;
1650                     x++;
1651                     pclrCurrent++;
1652                 }
1653 
1654                 /* Add the scaned line to the region */
1655                 SetRect(prcCurrent, xstart, y,x,y+1);
1656                 prcCurrent++;
1657                 cRgnRects++;
1658 
1659                 /* Increase the size of the buffer if it is full */
1660                 if(cRgnRects == cMaxRgnRects)
1661                 {
1662                     cMaxRgnRects *=2;
1663                     cRgnDataSize = sizeof(RGNDATA) + cMaxRgnRects * sizeof(RECT);
1664                     prgnData = (PRGNDATA)HeapReAlloc(GetProcessHeap(),
1665                                                      0,
1666                                                      prgnData,
1667                                                      cRgnDataSize);
1668                     prcCurrent = (RECT*)prgnData->Buffer + cRgnRects;
1669                 }
1670             }
1671             else
1672             {
1673                 x++;
1674                 pclrCurrent++;
1675             }
1676         }
1677         y++;
1678     }
1679 
1680     /* Fill the region data header */
1681     prgnData->rdh.dwSize = sizeof(prgnData->rdh);
1682     prgnData->rdh.iType = RDH_RECTANGLES;
1683     prgnData->rdh.nCount = cRgnRects;
1684     prgnData->rdh.nRgnSize = cRgnDataSize;
1685     prgnData->rdh.rcBound = *pRect;
1686 
1687     /* Create the region*/
1688     hrgnRet = ExtCreateRegion (NULL, cRgnDataSize, prgnData);
1689 
1690     /* Free the region data*/
1691     HeapFree(GetProcessHeap(),0,prgnData);
1692 
1693     /* return the region*/
1694     return hrgnRet;
1695 }
1696 
1697 HRESULT UXTHEME_GetImageBackBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCRECT pRect, HRGN *pRegion)
1698 {
1699     HBITMAP hbmp;
1700     DIBSECTION dib;
1701     RGBQUAD clrTransparent = {0xFF,0x0, 0xFF,0x0};
1702 
1703     /* Draw the theme part to a dib */
1704     hbmp = UXTHEME_DrawThemePartToDib(hTheme, hdc, iPartId, iStateId, pRect);
1705 
1706     /* Retrieve the info of the dib section */
1707     GetObjectW(hbmp, sizeof (DIBSECTION), &dib);
1708 
1709     /* Convert the bits of the dib section to a region */
1710     *pRegion = UXTHEME_RegionFromDibBits((RGBQUAD*)dib.dsBm.bmBits, &clrTransparent, pRect);
1711 
1712     /* Free the temp bitmap */
1713     DeleteObject(hbmp);
1714 
1715     return S_OK;
1716 }
1717 
1718 /***********************************************************************
1719  *      GetThemeBackgroundRegion                            (UXTHEME.@)
1720  *
1721  * Calculate the background region, taking into consideration transparent areas
1722  * of the background image.
1723  */
1724 HRESULT WINAPI GetThemeBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId,
1725                                         int iStateId, const RECT *pRect,
1726                                         HRGN *pRegion)
1727 {
1728     HRESULT hr = S_OK;
1729     int bgtype = BT_BORDERFILL;
1730 
1731     TRACE("(%p,%p,%d,%d)\n", hTheme, hdc, iPartId, iStateId);
1732     if(!hTheme)
1733         return E_HANDLE;
1734     if(!pRect || !pRegion)
1735         return E_POINTER;
1736 
1737     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1738     if(bgtype == BT_IMAGEFILE) {
1739         hr = UXTHEME_GetImageBackBackgroundRegion(hTheme, hdc, iPartId, iStateId, pRect, pRegion);
1740     }
1741     else if(bgtype == BT_BORDERFILL) {
1742         *pRegion = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
1743         if(!*pRegion)
1744             hr = HRESULT_FROM_WIN32(GetLastError());
1745     }
1746     else {
1747         FIXME("Unknown background type\n");
1748         /* This should never happen, and hence I don't know what to return */
1749         hr = E_FAIL;
1750     }
1751     return hr;
1752 }
1753 
1754 /* compute part size for "borderfill" backgrounds */
1755 static HRESULT get_border_background_size (HTHEME hTheme, int iPartId,
1756                                            int iStateId, THEMESIZE eSize, POINT* psz)
1757 {
1758     HRESULT hr = S_OK;
1759     int bordersize = 1;
1760 
1761     if (SUCCEEDED (hr = GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE,
1762         &bordersize)))
1763     {
1764         psz->x = psz->y = 2*bordersize;
1765         if (eSize != TS_MIN)
1766         {
1767             psz->x++;
1768             psz->y++;
1769         }
1770     }
1771     return hr;
1772 }
1773 
1774 /***********************************************************************
1775  *      GetThemePartSize                                    (UXTHEME.@)
1776  */
1777 HRESULT WINAPI GetThemePartSize(HTHEME hTheme, HDC hdc, int iPartId,
1778                                 int iStateId, RECT *prc, THEMESIZE eSize,
1779                                 SIZE *psz)
1780 {
1781     int bgtype = BT_BORDERFILL;
1782     HRESULT hr = S_OK;
1783     POINT size = {1, 1};
1784 
1785     if(!hTheme)
1786         return E_HANDLE;
1787 
1788     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1789     if (bgtype == BT_NONE)
1790         /* do nothing */;
1791     else if(bgtype == BT_IMAGEFILE)
1792         hr = get_image_part_size (hTheme, hdc, iPartId, iStateId, prc, eSize, &size);
1793     else if(bgtype == BT_BORDERFILL)
1794         hr = get_border_background_size (hTheme, iPartId, iStateId, eSize, &size);
1795     else {
1796         FIXME("Unknown background type\n");
1797         /* This should never happen, and hence I don't know what to return */
1798         hr = E_FAIL;
1799     }
1800     psz->cx = size.x;
1801     psz->cy = size.y;
1802     return hr;
1803 }
1804 
1805 
1806 /***********************************************************************
1807  *      GetThemeTextExtent                                  (UXTHEME.@)
1808  */
1809 HRESULT WINAPI GetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId,
1810                                   int iStateId, LPCWSTR pszText, int iCharCount,
1811                                   DWORD dwTextFlags, const RECT *pBoundingRect,
1812                                   RECT *pExtentRect)
1813 {
1814     HRESULT hr;
1815     HFONT hFont = NULL;
1816     HGDIOBJ oldFont = NULL;
1817     LOGFONTW logfont;
1818     RECT rt = {0,0,0xFFFF,0xFFFF};
1819 
1820     TRACE("%d %d: stub\n", iPartId, iStateId);
1821     if(!hTheme)
1822         return E_HANDLE;
1823 
1824     if(pBoundingRect)
1825         rt = *pBoundingRect;
1826 
1827     hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1828     if(SUCCEEDED(hr)) {
1829         hFont = CreateFontIndirectW(&logfont);
1830         if(!hFont)
1831             TRACE("Failed to create font\n");
1832     }
1833     if(hFont)
1834         oldFont = SelectObject(hdc, hFont);
1835 
1836     DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags|DT_CALCRECT);
1837     *pExtentRect = rt;
1838 
1839     if(hFont) {
1840         SelectObject(hdc, oldFont);
1841         DeleteObject(hFont);
1842     }
1843     return S_OK;
1844 }
1845 
1846 /***********************************************************************
1847  *      GetThemeTextMetrics                                 (UXTHEME.@)
1848  */
1849 HRESULT WINAPI GetThemeTextMetrics(HTHEME hTheme, HDC hdc, int iPartId,
1850                                    int iStateId, TEXTMETRICW *ptm)
1851 {
1852     HRESULT hr;
1853     HFONT hFont = NULL;
1854     HGDIOBJ oldFont = NULL;
1855     LOGFONTW logfont;
1856 
1857     TRACE("(%p, %p, %d, %d)\n", hTheme, hdc, iPartId, iStateId);
1858     if(!hTheme)
1859         return E_HANDLE;
1860 
1861     hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1862     if(SUCCEEDED(hr)) {
1863         hFont = CreateFontIndirectW(&logfont);
1864         if(!hFont)
1865             TRACE("Failed to create font\n");
1866     }
1867     if(hFont)
1868         oldFont = SelectObject(hdc, hFont);
1869 
1870     if(!GetTextMetricsW(hdc, ptm))
1871         hr = HRESULT_FROM_WIN32(GetLastError());
1872 
1873     if(hFont) {
1874         SelectObject(hdc, oldFont);
1875         DeleteObject(hFont);
1876     }
1877     return hr;
1878 }
1879 
1880 /***********************************************************************
1881  *      IsThemeBackgroundPartiallyTransparent               (UXTHEME.@)
1882  */
1883 BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId,
1884                                                   int iStateId)
1885 {
1886     int bgtype = BT_BORDERFILL;
1887     RECT rect = {0, 0, 0, 0};
1888     HBITMAP bmpSrc;
1889     RECT rcSrc;
1890     BOOL hasAlpha;
1891     INT transparent;
1892     COLORREF transparentcolor;
1893 
1894     TRACE("(%d,%d)\n", iPartId, iStateId);
1895 
1896     if(!hTheme)
1897         return FALSE;
1898 
1899     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1900 
1901 #ifdef __REACTOS__
1902     if (bgtype == BT_NONE) return TRUE;
1903 #endif
1904     if (bgtype != BT_IMAGEFILE) return FALSE;
1905 
1906     if(FAILED (UXTHEME_LoadImage (hTheme, 0, iPartId, iStateId, &rect, FALSE,
1907                                   &bmpSrc, &rcSrc, &hasAlpha)))
1908         return FALSE;
1909 
1910     get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
1911         &transparentcolor, FALSE);
1912     return (transparent != ALPHABLEND_NONE);
1913 }
1914