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