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