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