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