Do filename postprocessing in GetDisplayNameOf (Hide filename
[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 DWORD dwDialogTextureFlags;
45
46 /***********************************************************************/
47
48 /***********************************************************************
49  *      EnableThemeDialogTexture                            (UXTHEME.@)
50  */
51 HRESULT WINAPI EnableThemeDialogTexture(HWND hwnd, DWORD dwFlags)
52 {
53     TRACE("(%p,0x%08lx\n", hwnd, dwFlags);
54     dwDialogTextureFlags = dwFlags;
55     return S_OK;
56  }
57
58 /***********************************************************************
59  *      IsThemeDialogTextureEnabled                         (UXTHEME.@)
60  */
61 BOOL WINAPI IsThemeDialogTextureEnabled(HWND hwnd)
62 {
63     TRACE("(%p)\n", hwnd);
64     return (dwDialogTextureFlags & ETDT_ENABLE) && !(dwDialogTextureFlags & ETDT_DISABLE);
65 }
66
67 /***********************************************************************
68  *      DrawThemeParentBackground                           (UXTHEME.@)
69  */
70 HRESULT WINAPI DrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc)
71 {
72     RECT rt;
73     POINT org;
74     HWND hParent;
75     HRGN clip = NULL;
76     int hasClip = -1;
77     
78     TRACE("(%p,%p,%p)\n", hwnd, hdc, prc);
79     hParent = GetParent(hwnd);
80     if(!hParent)
81         hParent = hwnd;
82     if(prc) {
83         CopyRect(&rt, prc);
84         MapWindowPoints(hwnd, NULL, (LPPOINT)&rt, 2);
85         
86         clip = CreateRectRgn(0,0,1,1);
87         hasClip = GetClipRgn(hdc, clip);
88         if(hasClip == -1)
89             TRACE("Failed to get original clipping region\n");
90         else
91             IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
92     }
93     else {
94         GetClientRect(hParent, &rt);
95         MapWindowPoints(hParent, NULL, (LPPOINT)&rt, 2);
96     }
97
98     OffsetViewportOrgEx(hdc, -rt.left, -rt.top, &org);
99
100     SendMessageW(hParent, WM_ERASEBKGND, (WPARAM)hdc, 0);
101     SendMessageW(hParent, WM_PRINTCLIENT, (WPARAM)hdc, PRF_CLIENT);
102
103     SetViewportOrgEx(hdc, org.x, org.y, NULL);
104     if(prc) {
105         if(hasClip == 0)
106             SelectClipRgn(hdc, NULL);
107         else if(hasClip == 1)
108             SelectClipRgn(hdc, clip);
109         DeleteObject(clip);
110     }
111     return S_OK;
112 }
113
114
115 /***********************************************************************
116  *      DrawThemeBackground                                 (UXTHEME.@)
117  */
118 HRESULT WINAPI DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId,
119                                    int iStateId, const RECT *pRect,
120                                    const RECT *pClipRect)
121 {
122     DTBGOPTS opts;
123     opts.dwSize = sizeof(DTBGOPTS);
124     opts.dwFlags = 0;
125     if(pClipRect) {
126         opts.dwFlags |= DTBG_CLIPRECT;
127         CopyRect(&opts.rcClip, pClipRect);
128     }
129     return DrawThemeBackgroundEx(hTheme, hdc, iPartId, iStateId, pRect, &opts);
130 }
131
132 /***********************************************************************
133  *      UXTHEME_SelectImage
134  *
135  * Select the image to use
136  */
137 static PTHEME_PROPERTY UXTHEME_SelectImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph)
138 {
139     PTHEME_PROPERTY tp;
140     int imageselecttype = IST_NONE;
141     int i;
142     int image;
143     if(glyph)
144         image = TMT_GLYPHIMAGEFILE;
145     else
146         image = TMT_IMAGEFILE;
147
148     if((tp=MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, image)))
149         return tp;
150     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGESELECTTYPE, &imageselecttype);
151
152     if(imageselecttype == IST_DPI) {
153         int reqdpi = 0;
154         int screendpi = GetDeviceCaps(hdc, LOGPIXELSX);
155         for(i=4; i>=0; i--) {
156             reqdpi = 0;
157             if(SUCCEEDED(GetThemeInt(hTheme, iPartId, iStateId, i + TMT_MINDPI1, &reqdpi))) {
158                 if(reqdpi != 0 && screendpi >= reqdpi) {
159                     TRACE("Using %d DPI, image %d\n", reqdpi, i + TMT_IMAGEFILE1);
160                     return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
161                 }
162             }
163         }
164         /* If an image couldnt be selected, choose the first one */
165         return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
166     }
167     else if(imageselecttype == IST_SIZE) {
168         POINT size = {pRect->right-pRect->left, pRect->bottom-pRect->top};
169         POINT reqsize;
170         for(i=4; i>=0; i--) {
171             if(SUCCEEDED(GetThemePosition(hTheme, iPartId, iStateId, i + TMT_MINSIZE1, &reqsize))) {
172                 if(reqsize.x >= size.x && reqsize.y >= size.y) {
173                     TRACE("Using image size %ldx%ld, image %d\n", reqsize.x, reqsize.y, i + TMT_IMAGEFILE1);
174                     return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
175                 }
176             }
177         }
178         /* If an image couldnt be selected, choose the smallest one */
179         return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
180     }
181     return NULL;
182 }
183
184 /***********************************************************************
185  *      UXTHEME_LoadImage
186  *
187  * Load image for part/state
188  */
189 static HRESULT UXTHEME_LoadImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph,
190                           HBITMAP *hBmp, RECT *bmpRect)
191 {
192     int imagelayout = IL_VERTICAL;
193     int imagecount = 1;
194     BITMAP bmp;
195     WCHAR szPath[MAX_PATH];
196     PTHEME_PROPERTY tp = UXTHEME_SelectImage(hTheme, hdc, iPartId, iStateId, pRect, glyph);
197     if(!tp) {
198         FIXME("Couldn't determine image for part/state %d/%d, invalid theme?\n", iPartId, iStateId);
199         return E_PROP_ID_UNSUPPORTED;
200     }
201     lstrcpynW(szPath, tp->lpValue, min(tp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
202     *hBmp = MSSTYLES_LoadBitmap(hdc, hTheme, szPath);
203     if(!*hBmp) {
204         TRACE("Failed to load bitmap %s\n", debugstr_w(szPath));
205         return HRESULT_FROM_WIN32(GetLastError());
206     }
207     
208     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
209     GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
210
211     GetObjectW(*hBmp, sizeof(bmp), &bmp);
212     if(imagelayout == IL_VERTICAL) {
213         int height = bmp.bmHeight/imagecount;
214         bmpRect->left = 0;
215         bmpRect->right = bmp.bmWidth;
216         bmpRect->top = (max(min(imagecount, iStateId), 1)-1) * height;
217         bmpRect->bottom = bmpRect->top + height;
218     }
219     else {
220         int width = bmp.bmWidth/imagecount;
221         bmpRect->left = (max(min(imagecount, iStateId), 1)-1) * width;
222         bmpRect->right = bmpRect->left + width;
223         bmpRect->top = 0;
224         bmpRect->bottom = bmp.bmHeight;
225     }
226     return S_OK;
227 }
228
229 /***********************************************************************
230  *      UXTHEME_StretchBlt
231  *
232  * Psudo TransparentBlt/StretchBlt
233  */
234 static inline BOOL UXTHEME_StretchBlt(HDC hdcDst, int nXOriginDst, int nYOriginDst, int nWidthDst, int nHeightDst,
235                                       HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
236                                       BOOL transparent, COLORREF transcolor)
237 {
238     if(transparent) {
239         /* Ensure we don't pass any negative values to TransparentBlt */
240         return TransparentBlt(hdcDst, nXOriginDst, nYOriginDst, abs(nWidthDst), abs(nHeightDst),
241                               hdcSrc, nXOriginSrc, nYOriginSrc, abs(nWidthSrc), abs(nHeightSrc),
242                               transcolor);
243     }
244     /* This should be using AlphaBlend */
245     return StretchBlt(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
246                         hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
247                         SRCCOPY);
248 }
249
250 /***********************************************************************
251  *      UXTHEME_Blt
252  *
253  * Simplify sending same width/height for both source and dest
254  */
255 static inline BOOL UXTHEME_Blt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
256                                HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
257                                BOOL transparent, COLORREF transcolor)
258 {
259     return UXTHEME_StretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
260                               hdcSrc, nXOriginSrc, nYOriginSrc, nWidthDest, nHeightDest,
261                               transparent, transcolor);
262 }
263
264
265 /***********************************************************************
266  *      UXTHEME_DrawImageGlyph
267  *
268  * Draw an imagefile glyph
269  */
270 static HRESULT UXTHEME_DrawImageGlyph(HTHEME hTheme, HDC hdc, int iPartId,
271                                int iStateId, RECT *pRect,
272                                const DTBGOPTS *pOptions)
273 {
274     HRESULT hr;
275     HBITMAP bmpSrc = NULL;
276     HDC hdcSrc = NULL;
277     HGDIOBJ oldSrc = NULL;
278     RECT rcSrc;
279     BOOL transparent = FALSE;
280     COLORREF transparentcolor = 0;
281     int valign = VA_CENTER;
282     int halign = HA_CENTER;
283     POINT dstSize;
284     POINT srcSize;
285     POINT topleft;
286
287     hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, TRUE, &bmpSrc, &rcSrc);
288     if(FAILED(hr)) return hr;
289     hdcSrc = CreateCompatibleDC(hdc);
290     if(!hdcSrc) {
291         hr = HRESULT_FROM_WIN32(GetLastError());
292         DeleteObject(bmpSrc);
293         return hr;
294     }
295     oldSrc = SelectObject(hdcSrc, bmpSrc);
296
297     dstSize.x = pRect->right-pRect->left;
298     dstSize.y = pRect->bottom-pRect->top;
299     srcSize.x = rcSrc.right-rcSrc.left;
300     srcSize.y = rcSrc.bottom-rcSrc.top;
301
302     GetThemeBool(hTheme, iPartId, iStateId, TMT_GLYPHTRANSPARENT, &transparent);
303     if(transparent) {
304         if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_GLYPHTRANSPARENTCOLOR, &transparentcolor))) {
305             /* If image is transparent, but no color was specified, use magenta */
306             transparentcolor = RGB(255, 0, 255);
307         }
308     }
309     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
310     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
311
312     topleft.x = pRect->left;
313     topleft.y = pRect->top;
314     if(halign == HA_CENTER)      topleft.x += (dstSize.x/2)-(srcSize.x/2);
315     else if(halign == HA_RIGHT)  topleft.x += dstSize.x-srcSize.x;
316     if(valign == VA_CENTER)      topleft.y += (dstSize.y/2)-(srcSize.y/2);
317     else if(valign == VA_BOTTOM) topleft.y += dstSize.y-srcSize.y;
318
319     if(!UXTHEME_Blt(hdc, topleft.x, topleft.y, srcSize.x, srcSize.y,
320                     hdcSrc, rcSrc.left, rcSrc.top,
321                     transparent, transparentcolor)) {
322         hr = HRESULT_FROM_WIN32(GetLastError());
323     }
324
325     SelectObject(hdcSrc, oldSrc);
326     DeleteDC(hdcSrc);
327     DeleteObject(bmpSrc);
328     return hr;
329 }
330
331 /***********************************************************************
332  *      UXTHEME_DrawImageGlyph
333  *
334  * Draw glyph on top of background, if appropriate
335  */
336 static HRESULT UXTHEME_DrawGlyph(HTHEME hTheme, HDC hdc, int iPartId,
337                                     int iStateId, RECT *pRect,
338                                     const DTBGOPTS *pOptions)
339 {
340     int glyphtype = GT_NONE;
341
342     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_GLYPHTYPE, &glyphtype);
343
344     if(glyphtype == GT_IMAGEGLYPH) {
345         return UXTHEME_DrawImageGlyph(hTheme, hdc, iPartId, iStateId, pRect, pOptions);
346     }
347     else if(glyphtype == GT_FONTGLYPH) {
348         /* I don't know what a font glyph is, I've never seen it used in any themes */
349         FIXME("Font glyph\n");
350     }
351     return S_OK;
352 }
353
354 /***********************************************************************
355  *      UXTHEME_DrawImageBackground
356  *
357  * Draw an imagefile background
358  */
359 static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId,
360                                     int iStateId, RECT *pRect,
361                                     const DTBGOPTS *pOptions)
362 {
363     HRESULT hr = S_OK;
364     HBITMAP bmpSrc;
365     HGDIOBJ oldSrc;
366     HDC hdcSrc;
367     RECT rcSrc;
368     RECT rcDst;
369     POINT dstSize;
370     POINT srcSize;
371     int sizingtype = ST_TRUESIZE;
372     BOOL uniformsizing = FALSE;
373     BOOL transparent = FALSE;
374     COLORREF transparentcolor = 0;
375
376     hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, FALSE, &bmpSrc, &rcSrc);
377     if(FAILED(hr)) return hr;
378     hdcSrc = CreateCompatibleDC(hdc);
379     if(!hdcSrc) {
380         hr = HRESULT_FROM_WIN32(GetLastError());
381         DeleteObject(bmpSrc);
382         return hr;
383     }
384     oldSrc = SelectObject(hdcSrc, bmpSrc);
385
386     CopyRect(&rcDst, pRect);
387     
388     GetThemeBool(hTheme, iPartId, iStateId, TMT_TRANSPARENT, &transparent);
389     if(transparent) {
390         if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_TRANSPARENTCOLOR, &transparentcolor))) {
391             /* If image is transparent, but no color was specified, get the color of the upper left corner */
392             transparentcolor = GetPixel(hdcSrc, 0, 0);
393         }
394     }
395
396     dstSize.x = rcDst.right-rcDst.left;
397     dstSize.y = rcDst.bottom-rcDst.top;
398     srcSize.x = rcSrc.right-rcSrc.left;
399     srcSize.y = rcSrc.bottom-rcSrc.top;
400
401     GetThemeBool(hTheme, iPartId, iStateId, TMT_UNIFORMSIZING, &uniformsizing);
402     if(uniformsizing) {
403         /* Scale height and width equally */
404         int widthDiff = abs(srcSize.x-dstSize.x);
405         int heightDiff = abs(srcSize.y-dstSize.x);
406         if(widthDiff > heightDiff) {
407             dstSize.y -= widthDiff-heightDiff;
408             rcDst.bottom = rcDst.top + dstSize.y;
409         }
410         else if(heightDiff > widthDiff) {
411             dstSize.x -= heightDiff-widthDiff;
412             rcDst.right = rcDst.left + dstSize.x;
413         }
414     }
415
416     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
417     if(sizingtype == ST_TRUESIZE) {
418         int truesizestretchmark = 0;
419
420         if(dstSize.x < 0 || dstSize.y < 0) {
421             BOOL mirrorimage = TRUE;
422             GetThemeBool(hTheme, iPartId, iStateId, TMT_MIRRORIMAGE, &mirrorimage);
423             if(mirrorimage) {
424                 if(dstSize.x < 0) {
425                     rcDst.left += dstSize.x;
426                     rcDst.right += dstSize.x;
427                 }
428                 if(dstSize.y < 0) {
429                     rcDst.top += dstSize.y;
430                     rcDst.bottom += dstSize.y;
431                 }
432             }
433         }
434         /* Only stretch when target exceeds source by truesizestretchmark percent */
435         GetThemeInt(hTheme, iPartId, iStateId, TMT_TRUESIZESTRETCHMARK, &truesizestretchmark);
436         if(dstSize.x < 0 || dstSize.y < 0 ||
437            MulDiv(srcSize.x, 100, dstSize.x) > truesizestretchmark ||
438            MulDiv(srcSize.y, 100, dstSize.y) > truesizestretchmark) {
439             if(!UXTHEME_StretchBlt(hdc, rcDst.left, rcDst.top, dstSize.x, dstSize.y,
440                                    hdcSrc, rcSrc.left, rcSrc.top, srcSize.x, srcSize.y,
441                                    transparent, transparentcolor))
442                 hr = HRESULT_FROM_WIN32(GetLastError());
443         }
444         else {
445             rcDst.left += (dstSize.x/2)-(srcSize.x/2);
446             rcDst.top  += (dstSize.y/2)-(srcSize.y/2);
447             rcDst.right = rcDst.left + srcSize.x;
448             rcDst.bottom = rcDst.top + srcSize.y;
449             if(!UXTHEME_Blt(hdc, rcDst.left, rcDst.top, srcSize.x, srcSize.y,
450                             hdcSrc, rcSrc.left, rcSrc.top,
451                             transparent, transparentcolor))
452                 hr = HRESULT_FROM_WIN32(GetLastError());
453         }
454     }
455     else {
456         HDC hdcDst = NULL;
457         HBITMAP bmpDst = NULL;
458         HGDIOBJ oldDst = NULL;
459         MARGINS sm;
460
461         dstSize.x = abs(dstSize.x);
462         dstSize.y = abs(dstSize.y);
463
464         GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_SIZINGMARGINS, NULL, &sm);
465
466         hdcDst = CreateCompatibleDC(hdc);
467         if(!hdcDst) {
468             hr = HRESULT_FROM_WIN32(GetLastError());
469             goto draw_error; 
470         }
471         bmpDst = CreateCompatibleBitmap(hdc, dstSize.x, dstSize.y);
472         if(!bmpDst) {
473             hr = HRESULT_FROM_WIN32(GetLastError());
474             goto draw_error; 
475         }
476         oldDst = SelectObject(hdcDst, bmpDst);
477
478         /* Upper left corner */
479         if(!BitBlt(hdcDst, 0, 0, sm.cxLeftWidth, sm.cyTopHeight,
480                    hdcSrc, rcSrc.left, rcSrc.top, SRCCOPY)) {
481             hr = HRESULT_FROM_WIN32(GetLastError());
482             goto draw_error; 
483         }
484         /* Upper right corner */
485         if(!BitBlt(hdcDst, dstSize.x-sm.cxRightWidth, 0, sm.cxRightWidth, sm.cyTopHeight,
486                    hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top, SRCCOPY)) {
487             hr = HRESULT_FROM_WIN32(GetLastError());
488             goto draw_error; 
489         }
490         /* Lower left corner */
491         if(!BitBlt(hdcDst, 0, dstSize.y-sm.cyBottomHeight, sm.cxLeftWidth, sm.cyBottomHeight,
492                    hdcSrc, rcSrc.left, rcSrc.bottom-sm.cyBottomHeight, SRCCOPY)) {
493             hr = HRESULT_FROM_WIN32(GetLastError());
494             goto draw_error; 
495         }
496         /* Lower right corner */
497         if(!BitBlt(hdcDst, dstSize.x-sm.cxRightWidth, dstSize.y-sm.cyBottomHeight, sm.cxRightWidth, sm.cyBottomHeight,
498                    hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.bottom-sm.cyBottomHeight, SRCCOPY)) {
499             hr = HRESULT_FROM_WIN32(GetLastError());
500             goto draw_error; 
501         }
502
503         if(sizingtype == ST_TILE) {
504             FIXME("Tile\n");
505             sizingtype = ST_STRETCH; /* Just use stretch for now */
506         }
507         if(sizingtype == ST_STRETCH) {
508             int destCenterWidth  = dstSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
509             int srcCenterWidth   = srcSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
510             int destCenterHeight = dstSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
511             int srcCenterHeight  = srcSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
512
513             if(destCenterWidth > 0) {
514                 /* Center top */
515                 if(!StretchBlt(hdcDst, sm.cxLeftWidth, 0, destCenterWidth, sm.cyTopHeight,
516                                hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top, srcCenterWidth, sm.cyTopHeight, SRCCOPY)) {
517                     hr = HRESULT_FROM_WIN32(GetLastError());
518                     goto draw_error; 
519                 }
520                 /* Center bottom */
521                 if(!StretchBlt(hdcDst, sm.cxLeftWidth, dstSize.y-sm.cyBottomHeight, destCenterWidth, sm.cyBottomHeight,
522                                hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.bottom-sm.cyBottomHeight, srcCenterWidth, sm.cyTopHeight, SRCCOPY)) {
523                     hr = HRESULT_FROM_WIN32(GetLastError());
524                     goto draw_error; 
525                 }
526             }
527             if(destCenterHeight > 0) {
528                 /* Left center */
529                 if(!StretchBlt(hdcDst, 0, sm.cyTopHeight, sm.cxLeftWidth, destCenterHeight,
530                            hdcSrc, rcSrc.left, rcSrc.top+sm.cyTopHeight, sm.cxLeftWidth, srcCenterHeight, SRCCOPY)) {
531                     hr = HRESULT_FROM_WIN32(GetLastError());
532                     goto draw_error; 
533                 }
534                 /* Right center */
535                 if(!StretchBlt(hdcDst, dstSize.x-sm.cxRightWidth, sm.cyTopHeight, sm.cxRightWidth, destCenterHeight,
536                                hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top+sm.cyTopHeight, sm.cxRightWidth, srcCenterHeight, SRCCOPY)) {
537                     hr = HRESULT_FROM_WIN32(GetLastError());
538                     goto draw_error; 
539                 }
540             }
541             if(destCenterHeight > 0 && destCenterWidth > 0) {
542                 BOOL borderonly = FALSE;
543                 GetThemeBool(hTheme, iPartId, iStateId, TMT_BORDERONLY, &borderonly);
544                 if(!borderonly) {
545                     /* Center */
546                     if(!StretchBlt(hdcDst, sm.cxLeftWidth, sm.cyTopHeight, destCenterWidth, destCenterHeight,
547                                    hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top+sm.cyTopHeight, srcCenterWidth, srcCenterHeight, SRCCOPY)) {
548                         hr = HRESULT_FROM_WIN32(GetLastError());
549                         goto draw_error; 
550                     }
551                 }
552             }
553         }
554
555         if(!UXTHEME_Blt(hdc, rcDst.left, rcDst.top, dstSize.x, dstSize.y,
556                         hdcDst, 0, 0,
557                         transparent, transparentcolor))
558             hr = HRESULT_FROM_WIN32(GetLastError());
559
560 draw_error:
561         if(hdcDst) {
562             SelectObject(hdcDst, oldDst);
563             DeleteDC(hdcDst);
564         }
565         if(bmpDst) DeleteObject(bmpDst);
566     }
567     SelectObject(hdcSrc, oldSrc);
568     DeleteObject(bmpSrc);
569     DeleteDC(hdcSrc);
570     CopyRect(pRect, &rcDst);
571     return hr;
572 }
573
574 /***********************************************************************
575  *      UXTHEME_DrawBorderRectangle
576  *
577  * Draw the bounding rectangle for a borderfill background
578  */
579 static HRESULT UXTHEME_DrawBorderRectangle(HTHEME hTheme, HDC hdc, int iPartId,
580                                     int iStateId, RECT *pRect,
581                                     const DTBGOPTS *pOptions)
582 {
583     HRESULT hr = S_OK;
584     HPEN hPen;
585     HGDIOBJ oldPen;
586     COLORREF bordercolor = RGB(0,0,0);
587     int bordersize = 1;
588
589     GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
590     if(bordersize > 0) {
591         POINT ptCorners[5];
592         ptCorners[0].x = pRect->left;
593         ptCorners[0].y = pRect->top;
594         ptCorners[1].x = pRect->right-1;
595         ptCorners[1].y = pRect->top;
596         ptCorners[2].x = pRect->right-1;
597         ptCorners[2].y = pRect->bottom-1;
598         ptCorners[3].x = pRect->left;
599         ptCorners[3].y = pRect->bottom-1;
600         ptCorners[4].x = pRect->left;
601         ptCorners[4].y = pRect->top;
602
603         InflateRect(pRect, -bordersize, -bordersize);
604         if(pOptions->dwFlags & DTBG_OMITBORDER)
605             return S_OK;
606         GetThemeColor(hTheme, iPartId, iStateId, TMT_BORDERCOLOR, &bordercolor);
607         hPen = CreatePen(PS_SOLID, bordersize, bordercolor);
608         if(!hPen)
609             return HRESULT_FROM_WIN32(GetLastError());
610         oldPen = SelectObject(hdc, hPen);
611
612         if(!Polyline(hdc, ptCorners, 5))
613             hr = HRESULT_FROM_WIN32(GetLastError());
614
615         SelectObject(hdc, oldPen);
616         DeleteObject(hPen);
617     }
618     return hr;
619 }
620
621 /***********************************************************************
622  *      UXTHEME_DrawBackgroundFill
623  *
624  * Fill a borderfill background rectangle
625  */
626 static HRESULT UXTHEME_DrawBackgroundFill(HTHEME hTheme, HDC hdc, int iPartId,
627                                    int iStateId, RECT *pRect,
628                                    const DTBGOPTS *pOptions)
629 {
630     HRESULT hr = S_OK;
631     int filltype = FT_SOLID;
632
633     TRACE("(%d,%d,%ld)\n", iPartId, iStateId, pOptions->dwFlags);
634
635     if(pOptions->dwFlags & DTBG_OMITCONTENT)
636         return S_OK;
637
638     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_FILLTYPE, &filltype);
639
640     if(filltype == FT_SOLID) {
641         HBRUSH hBrush;
642         COLORREF fillcolor = RGB(255,255,255);
643
644         GetThemeColor(hTheme, iPartId, iStateId, TMT_FILLCOLOR, &fillcolor);
645         hBrush = CreateSolidBrush(fillcolor);
646         if(!FillRect(hdc, pRect, hBrush))
647             hr = HRESULT_FROM_WIN32(GetLastError());
648         DeleteObject(hBrush);
649     }
650     else if(filltype == FT_VERTGRADIENT || filltype == FT_HORZGRADIENT) {
651         /* FIXME: This only accounts for 2 gradient colors (out of 5) and ignores
652             the gradient ratios (no idea how those work)
653             Few themes use this, and the ones I've seen only use 2 colors with
654             a gradient ratio of 0 and 255 respectivly
655         */
656
657         COLORREF gradient1 = RGB(0,0,0);
658         COLORREF gradient2 = RGB(255,255,255);
659         TRIVERTEX vert[2];
660         GRADIENT_RECT gRect;
661
662         FIXME("Gradient implementation not complete\n");
663
664         GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR1, &gradient1);
665         GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR2, &gradient2);
666
667         vert[0].x     = pRect->left;
668         vert[0].y     = pRect->top;
669         vert[0].Red   = GetRValue(gradient1) << 8;
670         vert[0].Green = GetGValue(gradient1) << 8;
671         vert[0].Blue  = GetBValue(gradient1) << 8;
672         vert[0].Alpha = 0x0000;
673
674         vert[1].x     = pRect->right;
675         vert[1].y     = pRect->bottom;
676         vert[1].Red   = GetRValue(gradient2) << 8;
677         vert[1].Green = GetGValue(gradient2) << 8;
678         vert[1].Blue  = GetBValue(gradient2) << 8;
679         vert[1].Alpha = 0x0000;
680
681         gRect.UpperLeft  = 0;
682         gRect.LowerRight = 1;
683         GradientFill(hdc,vert,2,&gRect,1,filltype==FT_HORZGRADIENT?GRADIENT_FILL_RECT_H:GRADIENT_FILL_RECT_V);
684     }
685     else if(filltype == FT_RADIALGRADIENT) {
686         /* I've never seen this used in a theme */
687         FIXME("Radial gradient\n");
688     }
689     else if(filltype == FT_TILEIMAGE) {
690         /* I've never seen this used in a theme */
691         FIXME("Tile image\n");
692     }
693     return hr;
694 }
695
696 /***********************************************************************
697  *      UXTHEME_DrawBorderBackground
698  *
699  * Draw an imagefile background
700  */
701 static HRESULT UXTHEME_DrawBorderBackground(HTHEME hTheme, HDC hdc, int iPartId,
702                                      int iStateId, const RECT *pRect,
703                                      const DTBGOPTS *pOptions)
704 {
705     HRESULT hr;
706     RECT rt;
707
708     CopyRect(&rt, pRect);
709
710     hr = UXTHEME_DrawBorderRectangle(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
711     if(FAILED(hr))
712         return hr;
713     return UXTHEME_DrawBackgroundFill(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
714 }
715
716 /***********************************************************************
717  *      DrawThemeBackgroundEx                               (UXTHEME.@)
718  */
719 HRESULT WINAPI DrawThemeBackgroundEx(HTHEME hTheme, HDC hdc, int iPartId,
720                                      int iStateId, const RECT *pRect,
721                                      const DTBGOPTS *pOptions)
722 {
723     HRESULT hr;
724     const DTBGOPTS defaultOpts = {sizeof(DTBGOPTS), 0, {0,0,0,0}};
725     const DTBGOPTS *opts;
726     HRGN clip = NULL;
727     int hasClip = -1;
728     int bgtype = BT_BORDERFILL;
729     RECT rt;
730
731     TRACE("(%p,%p,%d,%d,%ld,%ld)\n", hTheme, hdc, iPartId, iStateId,pRect->left,pRect->top);
732     if(!hTheme)
733         return E_HANDLE;
734
735     /* Ensure we have a DTBGOPTS structure available, simplifies some of the code */
736     opts = pOptions;
737     if(!opts) opts = &defaultOpts;
738
739     if(opts->dwFlags & DTBG_CLIPRECT) {
740         clip = CreateRectRgn(0,0,1,1);
741         hasClip = GetClipRgn(hdc, clip);
742         if(hasClip == -1)
743             TRACE("Failed to get original clipping region\n");
744         else
745             IntersectClipRect(hdc, opts->rcClip.left, opts->rcClip.top, opts->rcClip.right, opts->rcClip.bottom);
746     }
747     CopyRect(&rt, pRect);
748
749     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
750     if(bgtype == BT_IMAGEFILE)
751         hr = UXTHEME_DrawImageBackground(hTheme, hdc, iPartId, iStateId, &rt, opts);
752     else if(bgtype == BT_BORDERFILL)
753         hr = UXTHEME_DrawBorderBackground(hTheme, hdc, iPartId, iStateId, pRect, opts);
754     else {
755         FIXME("Unknown background type\n");
756         /* This should never happen, and hence I don't know what to return */
757         hr = E_FAIL;
758     }
759     if(SUCCEEDED(hr))
760         hr = UXTHEME_DrawGlyph(hTheme, hdc, iPartId, iStateId, &rt, opts);
761     if(opts->dwFlags & DTBG_CLIPRECT) {
762         if(hasClip == 0)
763             SelectClipRgn(hdc, NULL);
764         else if(hasClip == 1)
765             SelectClipRgn(hdc, clip);
766         DeleteObject(clip);
767     }
768     return hr;
769 }
770
771 /***********************************************************************
772  *      DrawThemeEdge                                       (UXTHEME.@)
773  */
774 HRESULT WINAPI DrawThemeEdge(HTHEME hTheme, HDC hdc, int iPartId,
775                              int iStateId, const RECT *pDestRect, UINT uEdge,
776                              UINT uFlags, RECT *pContentRect)
777 {
778     FIXME("%d %d 0x%08x 0x%08x: stub\n", iPartId, iStateId, uEdge, uFlags);
779     if(!hTheme)
780         return E_HANDLE;
781     return ERROR_CALL_NOT_IMPLEMENTED;
782 }
783
784 /***********************************************************************
785  *      DrawThemeIcon                                       (UXTHEME.@)
786  */
787 HRESULT WINAPI DrawThemeIcon(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
788                              const RECT *pRect, HIMAGELIST himl, int iImageIndex)
789 {
790     FIXME("%d %d: stub\n", iPartId, iStateId);
791     if(!hTheme)
792         return E_HANDLE;
793     return ERROR_CALL_NOT_IMPLEMENTED;
794 }
795
796 /***********************************************************************
797  *      DrawThemeText                                       (UXTHEME.@)
798  */
799 HRESULT WINAPI DrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
800                              LPCWSTR pszText, int iCharCount, DWORD dwTextFlags,
801                              DWORD dwTextFlags2, const RECT *pRect)
802 {
803     HRESULT hr;
804     HFONT hFont = NULL;
805     HGDIOBJ oldFont = NULL;
806     LOGFONTW logfont;
807     COLORREF textColor;
808     COLORREF oldTextColor;
809     int oldBkMode;
810     RECT rt;
811     
812     TRACE("%d %d: stub\n", iPartId, iStateId);
813     if(!hTheme)
814         return E_HANDLE;
815     
816     hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
817     if(SUCCEEDED(hr)) {
818         hFont = CreateFontIndirectW(&logfont);
819         if(!hFont)
820             TRACE("Failed to create font\n");
821     }
822     CopyRect(&rt, pRect);
823     if(hFont)
824         oldFont = SelectObject(hdc, hFont);
825         
826     if(dwTextFlags2 & DTT_GRAYED)
827         textColor = GetSysColor(COLOR_GRAYTEXT);
828     else {
829         if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTCOLOR, &textColor)))
830             textColor = GetTextColor(hdc);
831     }
832     oldTextColor = SetTextColor(hdc, textColor);
833     oldBkMode = SetBkMode(hdc, TRANSPARENT);
834     DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
835     SetBkMode(hdc, oldBkMode);
836     SetTextColor(hdc, oldTextColor);
837
838     if(hFont) {
839         SelectObject(hdc, oldFont);
840         DeleteObject(hFont);
841     }
842     return S_OK;
843 }
844
845 /***********************************************************************
846  *      GetThemeBackgroundContentRect                       (UXTHEME.@)
847  */
848 HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId,
849                                              int iStateId,
850                                              const RECT *pBoundingRect,
851                                              RECT *pContentRect)
852 {
853     MARGINS margin;
854     HRESULT hr;
855
856     TRACE("(%d,%d)\n", iPartId, iStateId);
857     if(!hTheme)
858         return E_HANDLE;
859
860     hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
861     if(FAILED(hr)) {
862         TRACE("Margins not found\n");
863         return hr;
864     }
865     pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
866     pContentRect->top  = pBoundingRect->top + margin.cyTopHeight;
867     pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
868     pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
869
870     TRACE("left:%ld,top:%ld,right:%ld,bottom:%ld\n", pContentRect->left, pContentRect->top, pContentRect->right, pContentRect->bottom);
871
872     return S_OK;
873 }
874
875 /***********************************************************************
876  *      GetThemeBackgroundExtent                            (UXTHEME.@)
877  */
878 HRESULT WINAPI GetThemeBackgroundExtent(HTHEME hTheme, HDC hdc, int iPartId,
879                                         int iStateId, const RECT *pContentRect,
880                                         RECT *pExtentRect)
881 {
882     MARGINS margin;
883     HRESULT hr;
884
885     TRACE("(%d,%d)\n", iPartId, iStateId);
886     if(!hTheme)
887         return E_HANDLE;
888
889     hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
890     if(FAILED(hr)) {
891         TRACE("Margins not found\n");
892         return hr;
893     }
894     pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
895     pExtentRect->top  = pContentRect->top - margin.cyTopHeight;
896     pExtentRect->right = pContentRect->right + margin.cxRightWidth;
897     pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
898
899     TRACE("left:%ld,top:%ld,right:%ld,bottom:%ld\n", pExtentRect->left, pExtentRect->top, pExtentRect->right, pExtentRect->bottom);
900
901     return S_OK;
902 }
903
904 /***********************************************************************
905  *      GetThemeBackgroundRegion                            (UXTHEME.@)
906  *
907  * Calculate the background region, taking into consideration transparent areas
908  * of the background image.
909  */
910 HRESULT WINAPI GetThemeBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId,
911                                         int iStateId, const RECT *pRect,
912                                         HRGN *pRegion)
913 {
914     HRESULT hr = S_OK;
915     int bgtype = BT_BORDERFILL;
916
917     TRACE("(%p,%p,%d,%d)\n", hTheme, hdc, iPartId, iStateId);
918     if(!hTheme)
919         return E_HANDLE;
920     if(!pRect || !pRegion)
921         return E_POINTER;
922
923     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
924     if(bgtype == BT_IMAGEFILE) {
925         FIXME("Images not handled yet\n");
926         hr = ERROR_CALL_NOT_IMPLEMENTED;
927     }
928     else if(bgtype == BT_BORDERFILL) {
929         *pRegion = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
930         if(!*pRegion)
931             hr = HRESULT_FROM_WIN32(GetLastError());
932     }
933     else {
934         FIXME("Unknown background type\n");
935         /* This should never happen, and hence I don't know what to return */
936         hr = E_FAIL;
937     }
938     return hr;
939 }
940
941 /***********************************************************************
942  *      GetThemePartSize                                    (UXTHEME.@)
943  */
944 HRESULT WINAPI GetThemePartSize(HTHEME hTheme, HDC hdc, int iPartId,
945                                 int iStateId, RECT *prc, THEMESIZE eSize,
946                                 SIZE *psz)
947 {
948     FIXME("%d %d %d: stub\n", iPartId, iStateId, eSize);
949     if(!hTheme)
950         return E_HANDLE;
951     return ERROR_CALL_NOT_IMPLEMENTED;
952 }
953
954
955 /***********************************************************************
956  *      GetThemeTextExtent                                  (UXTHEME.@)
957  */
958 HRESULT WINAPI GetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId,
959                                   int iStateId, LPCWSTR pszText, int iCharCount,
960                                   DWORD dwTextFlags, const RECT *pBoundingRect,
961                                   RECT *pExtentRect)
962 {
963     HRESULT hr;
964     HFONT hFont = NULL;
965     HGDIOBJ oldFont = NULL;
966     LOGFONTW logfont;
967     RECT rt = {0,0,0xFFFF,0xFFFF};
968     
969     TRACE("%d %d: stub\n", iPartId, iStateId);
970     if(!hTheme)
971         return E_HANDLE;
972
973     if(pBoundingRect)
974         CopyRect(&rt, pBoundingRect);
975             
976     hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
977     if(SUCCEEDED(hr)) {
978         hFont = CreateFontIndirectW(&logfont);
979         if(!hFont)
980             TRACE("Failed to create font\n");
981     }
982     if(hFont)
983         oldFont = SelectObject(hdc, hFont);
984         
985     DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags|DT_CALCRECT);
986     CopyRect(pExtentRect, &rt);
987
988     if(hFont) {
989         SelectObject(hdc, oldFont);
990         DeleteObject(hFont);
991     }
992     return S_OK;
993 }
994
995 /***********************************************************************
996  *      GetThemeTextMetrics                                 (UXTHEME.@)
997  */
998 HRESULT WINAPI GetThemeTextMetrics(HTHEME hTheme, HDC hdc, int iPartId,
999                                    int iStateId, TEXTMETRICW *ptm)
1000 {
1001     HRESULT hr;
1002     HFONT hFont = NULL;
1003     HGDIOBJ oldFont = NULL;
1004     LOGFONTW logfont;
1005
1006     TRACE("(%p, %p, %d, %d)\n", hTheme, hdc, iPartId, iStateId);
1007     if(!hTheme)
1008         return E_HANDLE;
1009
1010     hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1011     if(SUCCEEDED(hr)) {
1012         hFont = CreateFontIndirectW(&logfont);
1013         if(!hFont)
1014             TRACE("Failed to create font\n");
1015     }
1016     if(hFont)
1017         oldFont = SelectObject(hdc, hFont);
1018
1019     if(!GetTextMetricsW(hdc, ptm))
1020         hr = HRESULT_FROM_WIN32(GetLastError());
1021
1022     if(hFont) {
1023         SelectObject(hdc, oldFont);
1024         DeleteObject(hFont);
1025     }
1026     return hr;
1027 }
1028
1029 /***********************************************************************
1030  *      IsThemeBackgroundPartiallyTransparent               (UXTHEME.@)
1031  */
1032 BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId,
1033                                                   int iStateId)
1034 {
1035     BOOL transparent = FALSE;
1036     TRACE("(%d,%d)\n", iPartId, iStateId);
1037     GetThemeBool(hTheme, iPartId, iStateId, TMT_TRANSPARENT, &transparent);
1038     return transparent;
1039 }