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