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