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