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