Make lcms support depend on headers _and_ libraries, not just the
[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_VERTICAL;
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  * Psudo 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 /***********************************************************************
285  *      UXTHEME_DrawImageGlyph
286  *
287  * Draw an imagefile glyph
288  */
289 static HRESULT UXTHEME_DrawImageGlyph(HTHEME hTheme, HDC hdc, int iPartId,
290                                int iStateId, RECT *pRect,
291                                const DTBGOPTS *pOptions)
292 {
293     HRESULT hr;
294     HBITMAP bmpSrc = NULL;
295     HDC hdcSrc = NULL;
296     HGDIOBJ oldSrc = NULL;
297     RECT rcSrc;
298     BOOL transparent = FALSE;
299     COLORREF transparentcolor = 0;
300     int valign = VA_CENTER;
301     int halign = HA_CENTER;
302     POINT dstSize;
303     POINT srcSize;
304     POINT topleft;
305
306     hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, TRUE, &bmpSrc, &rcSrc);
307     if(FAILED(hr)) return hr;
308     hdcSrc = CreateCompatibleDC(hdc);
309     if(!hdcSrc) {
310         hr = HRESULT_FROM_WIN32(GetLastError());
311         DeleteObject(bmpSrc);
312         return hr;
313     }
314     oldSrc = SelectObject(hdcSrc, bmpSrc);
315
316     dstSize.x = pRect->right-pRect->left;
317     dstSize.y = pRect->bottom-pRect->top;
318     srcSize.x = rcSrc.right-rcSrc.left;
319     srcSize.y = rcSrc.bottom-rcSrc.top;
320
321     GetThemeBool(hTheme, iPartId, iStateId, TMT_GLYPHTRANSPARENT, &transparent);
322     if(transparent) {
323         if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_GLYPHTRANSPARENTCOLOR, &transparentcolor))) {
324             /* If image is transparent, but no color was specified, use magenta */
325             transparentcolor = RGB(255, 0, 255);
326         }
327     }
328     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
329     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
330
331     topleft.x = pRect->left;
332     topleft.y = pRect->top;
333     if(halign == HA_CENTER)      topleft.x += (dstSize.x/2)-(srcSize.x/2);
334     else if(halign == HA_RIGHT)  topleft.x += dstSize.x-srcSize.x;
335     if(valign == VA_CENTER)      topleft.y += (dstSize.y/2)-(srcSize.y/2);
336     else if(valign == VA_BOTTOM) topleft.y += dstSize.y-srcSize.y;
337
338     if(!UXTHEME_Blt(hdc, topleft.x, topleft.y, srcSize.x, srcSize.y,
339                     hdcSrc, rcSrc.left, rcSrc.top,
340                     transparent, transparentcolor)) {
341         hr = HRESULT_FROM_WIN32(GetLastError());
342     }
343
344     SelectObject(hdcSrc, oldSrc);
345     DeleteDC(hdcSrc);
346     DeleteObject(bmpSrc);
347     return hr;
348 }
349
350 /***********************************************************************
351  *      UXTHEME_DrawImageGlyph
352  *
353  * Draw glyph on top of background, if appropriate
354  */
355 static HRESULT UXTHEME_DrawGlyph(HTHEME hTheme, HDC hdc, int iPartId,
356                                     int iStateId, RECT *pRect,
357                                     const DTBGOPTS *pOptions)
358 {
359     int glyphtype = GT_NONE;
360
361     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_GLYPHTYPE, &glyphtype);
362
363     if(glyphtype == GT_IMAGEGLYPH) {
364         return UXTHEME_DrawImageGlyph(hTheme, hdc, iPartId, iStateId, pRect, pOptions);
365     }
366     else if(glyphtype == GT_FONTGLYPH) {
367         /* I don't know what a font glyph is, I've never seen it used in any themes */
368         FIXME("Font glyph\n");
369     }
370     return S_OK;
371 }
372
373 /***********************************************************************
374  *      UXTHEME_DrawImageBackground
375  *
376  * Draw an imagefile background
377  */
378 static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId,
379                                     int iStateId, RECT *pRect,
380                                     const DTBGOPTS *pOptions)
381 {
382     HRESULT hr = S_OK;
383     HBITMAP bmpSrc;
384     HGDIOBJ oldSrc;
385     HDC hdcSrc;
386     RECT rcSrc;
387     RECT rcDst;
388     POINT dstSize;
389     POINT srcSize;
390     int sizingtype = ST_TRUESIZE;
391     BOOL uniformsizing = FALSE;
392     BOOL transparent = FALSE;
393     COLORREF transparentcolor = 0;
394
395     hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, FALSE, &bmpSrc, &rcSrc);
396     if(FAILED(hr)) return hr;
397     hdcSrc = CreateCompatibleDC(hdc);
398     if(!hdcSrc) {
399         hr = HRESULT_FROM_WIN32(GetLastError());
400         DeleteObject(bmpSrc);
401         return hr;
402     }
403     oldSrc = SelectObject(hdcSrc, bmpSrc);
404
405     CopyRect(&rcDst, pRect);
406     
407     GetThemeBool(hTheme, iPartId, iStateId, TMT_TRANSPARENT, &transparent);
408     if(transparent) {
409         if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_TRANSPARENTCOLOR, &transparentcolor))) {
410             /* If image is transparent, but no color was specified, get the color of the upper left corner */
411             transparentcolor = GetPixel(hdcSrc, 0, 0);
412         }
413     }
414
415     dstSize.x = rcDst.right-rcDst.left;
416     dstSize.y = rcDst.bottom-rcDst.top;
417     srcSize.x = rcSrc.right-rcSrc.left;
418     srcSize.y = rcSrc.bottom-rcSrc.top;
419
420     GetThemeBool(hTheme, iPartId, iStateId, TMT_UNIFORMSIZING, &uniformsizing);
421     if(uniformsizing) {
422         /* Scale height and width equally */
423         int widthDiff = abs(srcSize.x-dstSize.x);
424         int heightDiff = abs(srcSize.y-dstSize.x);
425         if(widthDiff > heightDiff) {
426             dstSize.y -= widthDiff-heightDiff;
427             rcDst.bottom = rcDst.top + dstSize.y;
428         }
429         else if(heightDiff > widthDiff) {
430             dstSize.x -= heightDiff-widthDiff;
431             rcDst.right = rcDst.left + dstSize.x;
432         }
433     }
434
435     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
436     if(sizingtype == ST_TRUESIZE) {
437         int truesizestretchmark = 0;
438
439         if(dstSize.x < 0 || dstSize.y < 0) {
440             BOOL mirrorimage = TRUE;
441             GetThemeBool(hTheme, iPartId, iStateId, TMT_MIRRORIMAGE, &mirrorimage);
442             if(mirrorimage) {
443                 if(dstSize.x < 0) {
444                     rcDst.left += dstSize.x;
445                     rcDst.right += dstSize.x;
446                 }
447                 if(dstSize.y < 0) {
448                     rcDst.top += dstSize.y;
449                     rcDst.bottom += dstSize.y;
450                 }
451             }
452         }
453         /* Only stretch when target exceeds source by truesizestretchmark percent */
454         GetThemeInt(hTheme, iPartId, iStateId, TMT_TRUESIZESTRETCHMARK, &truesizestretchmark);
455         if(dstSize.x < 0 || dstSize.y < 0 ||
456            MulDiv(srcSize.x, 100, dstSize.x) > truesizestretchmark ||
457            MulDiv(srcSize.y, 100, dstSize.y) > truesizestretchmark) {
458             if(!UXTHEME_StretchBlt(hdc, rcDst.left, rcDst.top, dstSize.x, dstSize.y,
459                                    hdcSrc, rcSrc.left, rcSrc.top, srcSize.x, srcSize.y,
460                                    transparent, transparentcolor))
461                 hr = HRESULT_FROM_WIN32(GetLastError());
462         }
463         else {
464             rcDst.left += (dstSize.x/2)-(srcSize.x/2);
465             rcDst.top  += (dstSize.y/2)-(srcSize.y/2);
466             rcDst.right = rcDst.left + srcSize.x;
467             rcDst.bottom = rcDst.top + srcSize.y;
468             if(!UXTHEME_Blt(hdc, rcDst.left, rcDst.top, srcSize.x, srcSize.y,
469                             hdcSrc, rcSrc.left, rcSrc.top,
470                             transparent, transparentcolor))
471                 hr = HRESULT_FROM_WIN32(GetLastError());
472         }
473     }
474     else {
475         HDC hdcDst = NULL;
476         HBITMAP bmpDst = NULL;
477         HGDIOBJ oldDst = NULL;
478         MARGINS sm;
479
480         dstSize.x = abs(dstSize.x);
481         dstSize.y = abs(dstSize.y);
482
483         GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_SIZINGMARGINS, NULL, &sm);
484
485         hdcDst = CreateCompatibleDC(hdc);
486         if(!hdcDst) {
487             hr = HRESULT_FROM_WIN32(GetLastError());
488             goto draw_error; 
489         }
490         bmpDst = CreateCompatibleBitmap(hdc, dstSize.x, dstSize.y);
491         if(!bmpDst) {
492             hr = HRESULT_FROM_WIN32(GetLastError());
493             goto draw_error; 
494         }
495         oldDst = SelectObject(hdcDst, bmpDst);
496
497         /* Upper left corner */
498         if(!BitBlt(hdcDst, 0, 0, sm.cxLeftWidth, sm.cyTopHeight,
499                    hdcSrc, rcSrc.left, rcSrc.top, SRCCOPY)) {
500             hr = HRESULT_FROM_WIN32(GetLastError());
501             goto draw_error; 
502         }
503         /* Upper right corner */
504         if(!BitBlt(hdcDst, dstSize.x-sm.cxRightWidth, 0, sm.cxRightWidth, sm.cyTopHeight,
505                    hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top, SRCCOPY)) {
506             hr = HRESULT_FROM_WIN32(GetLastError());
507             goto draw_error; 
508         }
509         /* Lower left corner */
510         if(!BitBlt(hdcDst, 0, dstSize.y-sm.cyBottomHeight, sm.cxLeftWidth, sm.cyBottomHeight,
511                    hdcSrc, rcSrc.left, rcSrc.bottom-sm.cyBottomHeight, SRCCOPY)) {
512             hr = HRESULT_FROM_WIN32(GetLastError());
513             goto draw_error; 
514         }
515         /* Lower right corner */
516         if(!BitBlt(hdcDst, dstSize.x-sm.cxRightWidth, dstSize.y-sm.cyBottomHeight, sm.cxRightWidth, sm.cyBottomHeight,
517                    hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.bottom-sm.cyBottomHeight, SRCCOPY)) {
518             hr = HRESULT_FROM_WIN32(GetLastError());
519             goto draw_error; 
520         }
521
522         if(sizingtype == ST_TILE) {
523             FIXME("Tile\n");
524             sizingtype = ST_STRETCH; /* Just use stretch for now */
525         }
526         if(sizingtype == ST_STRETCH) {
527             int destCenterWidth  = dstSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
528             int srcCenterWidth   = srcSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
529             int destCenterHeight = dstSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
530             int srcCenterHeight  = srcSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
531
532             if(destCenterWidth > 0) {
533                 /* Center top */
534                 if(!StretchBlt(hdcDst, sm.cxLeftWidth, 0, destCenterWidth, sm.cyTopHeight,
535                                hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top, srcCenterWidth, sm.cyTopHeight, SRCCOPY)) {
536                     hr = HRESULT_FROM_WIN32(GetLastError());
537                     goto draw_error; 
538                 }
539                 /* Center bottom */
540                 if(!StretchBlt(hdcDst, sm.cxLeftWidth, dstSize.y-sm.cyBottomHeight, destCenterWidth, sm.cyBottomHeight,
541                                hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.bottom-sm.cyBottomHeight, srcCenterWidth, sm.cyTopHeight, SRCCOPY)) {
542                     hr = HRESULT_FROM_WIN32(GetLastError());
543                     goto draw_error; 
544                 }
545             }
546             if(destCenterHeight > 0) {
547                 /* Left center */
548                 if(!StretchBlt(hdcDst, 0, sm.cyTopHeight, sm.cxLeftWidth, destCenterHeight,
549                            hdcSrc, rcSrc.left, rcSrc.top+sm.cyTopHeight, sm.cxLeftWidth, srcCenterHeight, SRCCOPY)) {
550                     hr = HRESULT_FROM_WIN32(GetLastError());
551                     goto draw_error; 
552                 }
553                 /* Right center */
554                 if(!StretchBlt(hdcDst, dstSize.x-sm.cxRightWidth, sm.cyTopHeight, sm.cxRightWidth, destCenterHeight,
555                                hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top+sm.cyTopHeight, sm.cxRightWidth, srcCenterHeight, SRCCOPY)) {
556                     hr = HRESULT_FROM_WIN32(GetLastError());
557                     goto draw_error; 
558                 }
559             }
560             if(destCenterHeight > 0 && destCenterWidth > 0) {
561                 BOOL borderonly = FALSE;
562                 GetThemeBool(hTheme, iPartId, iStateId, TMT_BORDERONLY, &borderonly);
563                 if(!borderonly) {
564                     /* Center */
565                     if(!StretchBlt(hdcDst, sm.cxLeftWidth, sm.cyTopHeight, destCenterWidth, destCenterHeight,
566                                    hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top+sm.cyTopHeight, srcCenterWidth, srcCenterHeight, SRCCOPY)) {
567                         hr = HRESULT_FROM_WIN32(GetLastError());
568                         goto draw_error; 
569                     }
570                 }
571             }
572         }
573
574         if(!UXTHEME_Blt(hdc, rcDst.left, rcDst.top, dstSize.x, dstSize.y,
575                         hdcDst, 0, 0,
576                         transparent, transparentcolor))
577             hr = HRESULT_FROM_WIN32(GetLastError());
578
579 draw_error:
580         if(hdcDst) {
581             SelectObject(hdcDst, oldDst);
582             DeleteDC(hdcDst);
583         }
584         if(bmpDst) DeleteObject(bmpDst);
585     }
586     SelectObject(hdcSrc, oldSrc);
587     DeleteObject(bmpSrc);
588     DeleteDC(hdcSrc);
589     CopyRect(pRect, &rcDst);
590     return hr;
591 }
592
593 /***********************************************************************
594  *      UXTHEME_DrawBorderRectangle
595  *
596  * Draw the bounding rectangle for a borderfill background
597  */
598 static HRESULT UXTHEME_DrawBorderRectangle(HTHEME hTheme, HDC hdc, int iPartId,
599                                     int iStateId, RECT *pRect,
600                                     const DTBGOPTS *pOptions)
601 {
602     HRESULT hr = S_OK;
603     HPEN hPen;
604     HGDIOBJ oldPen;
605     COLORREF bordercolor = RGB(0,0,0);
606     int bordersize = 1;
607
608     GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
609     if(bordersize > 0) {
610         POINT ptCorners[5];
611         ptCorners[0].x = pRect->left;
612         ptCorners[0].y = pRect->top;
613         ptCorners[1].x = pRect->right-1;
614         ptCorners[1].y = pRect->top;
615         ptCorners[2].x = pRect->right-1;
616         ptCorners[2].y = pRect->bottom-1;
617         ptCorners[3].x = pRect->left;
618         ptCorners[3].y = pRect->bottom-1;
619         ptCorners[4].x = pRect->left;
620         ptCorners[4].y = pRect->top;
621
622         InflateRect(pRect, -bordersize, -bordersize);
623         if(pOptions->dwFlags & DTBG_OMITBORDER)
624             return S_OK;
625         GetThemeColor(hTheme, iPartId, iStateId, TMT_BORDERCOLOR, &bordercolor);
626         hPen = CreatePen(PS_SOLID, bordersize, bordercolor);
627         if(!hPen)
628             return HRESULT_FROM_WIN32(GetLastError());
629         oldPen = SelectObject(hdc, hPen);
630
631         if(!Polyline(hdc, ptCorners, 5))
632             hr = HRESULT_FROM_WIN32(GetLastError());
633
634         SelectObject(hdc, oldPen);
635         DeleteObject(hPen);
636     }
637     return hr;
638 }
639
640 /***********************************************************************
641  *      UXTHEME_DrawBackgroundFill
642  *
643  * Fill a borderfill background rectangle
644  */
645 static HRESULT UXTHEME_DrawBackgroundFill(HTHEME hTheme, HDC hdc, int iPartId,
646                                    int iStateId, RECT *pRect,
647                                    const DTBGOPTS *pOptions)
648 {
649     HRESULT hr = S_OK;
650     int filltype = FT_SOLID;
651
652     TRACE("(%d,%d,%ld)\n", iPartId, iStateId, pOptions->dwFlags);
653
654     if(pOptions->dwFlags & DTBG_OMITCONTENT)
655         return S_OK;
656
657     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_FILLTYPE, &filltype);
658
659     if(filltype == FT_SOLID) {
660         HBRUSH hBrush;
661         COLORREF fillcolor = RGB(255,255,255);
662
663         GetThemeColor(hTheme, iPartId, iStateId, TMT_FILLCOLOR, &fillcolor);
664         hBrush = CreateSolidBrush(fillcolor);
665         if(!FillRect(hdc, pRect, hBrush))
666             hr = HRESULT_FROM_WIN32(GetLastError());
667         DeleteObject(hBrush);
668     }
669     else if(filltype == FT_VERTGRADIENT || filltype == FT_HORZGRADIENT) {
670         /* FIXME: This only accounts for 2 gradient colors (out of 5) and ignores
671             the gradient ratios (no idea how those work)
672             Few themes use this, and the ones I've seen only use 2 colors with
673             a gradient ratio of 0 and 255 respectivly
674         */
675
676         COLORREF gradient1 = RGB(0,0,0);
677         COLORREF gradient2 = RGB(255,255,255);
678         TRIVERTEX vert[2];
679         GRADIENT_RECT gRect;
680
681         FIXME("Gradient implementation not complete\n");
682
683         GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR1, &gradient1);
684         GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR2, &gradient2);
685
686         vert[0].x     = pRect->left;
687         vert[0].y     = pRect->top;
688         vert[0].Red   = GetRValue(gradient1) << 8;
689         vert[0].Green = GetGValue(gradient1) << 8;
690         vert[0].Blue  = GetBValue(gradient1) << 8;
691         vert[0].Alpha = 0x0000;
692
693         vert[1].x     = pRect->right;
694         vert[1].y     = pRect->bottom;
695         vert[1].Red   = GetRValue(gradient2) << 8;
696         vert[1].Green = GetGValue(gradient2) << 8;
697         vert[1].Blue  = GetBValue(gradient2) << 8;
698         vert[1].Alpha = 0x0000;
699
700         gRect.UpperLeft  = 0;
701         gRect.LowerRight = 1;
702         GradientFill(hdc,vert,2,&gRect,1,filltype==FT_HORZGRADIENT?GRADIENT_FILL_RECT_H:GRADIENT_FILL_RECT_V);
703     }
704     else if(filltype == FT_RADIALGRADIENT) {
705         /* I've never seen this used in a theme */
706         FIXME("Radial gradient\n");
707     }
708     else if(filltype == FT_TILEIMAGE) {
709         /* I've never seen this used in a theme */
710         FIXME("Tile image\n");
711     }
712     return hr;
713 }
714
715 /***********************************************************************
716  *      UXTHEME_DrawBorderBackground
717  *
718  * Draw an imagefile background
719  */
720 static HRESULT UXTHEME_DrawBorderBackground(HTHEME hTheme, HDC hdc, int iPartId,
721                                      int iStateId, const RECT *pRect,
722                                      const DTBGOPTS *pOptions)
723 {
724     HRESULT hr;
725     RECT rt;
726
727     CopyRect(&rt, pRect);
728
729     hr = UXTHEME_DrawBorderRectangle(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
730     if(FAILED(hr))
731         return hr;
732     return UXTHEME_DrawBackgroundFill(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
733 }
734
735 /***********************************************************************
736  *      DrawThemeBackgroundEx                               (UXTHEME.@)
737  */
738 HRESULT WINAPI DrawThemeBackgroundEx(HTHEME hTheme, HDC hdc, int iPartId,
739                                      int iStateId, const RECT *pRect,
740                                      const DTBGOPTS *pOptions)
741 {
742     HRESULT hr;
743     const DTBGOPTS defaultOpts = {sizeof(DTBGOPTS), 0, {0,0,0,0}};
744     const DTBGOPTS *opts;
745     HRGN clip = NULL;
746     int hasClip = -1;
747     int bgtype = BT_BORDERFILL;
748     RECT rt;
749
750     TRACE("(%p,%p,%d,%d,%ld,%ld)\n", hTheme, hdc, iPartId, iStateId,pRect->left,pRect->top);
751     if(!hTheme)
752         return E_HANDLE;
753
754     /* Ensure we have a DTBGOPTS structure available, simplifies some of the code */
755     opts = pOptions;
756     if(!opts) opts = &defaultOpts;
757
758     if(opts->dwFlags & DTBG_CLIPRECT) {
759         clip = CreateRectRgn(0,0,1,1);
760         hasClip = GetClipRgn(hdc, clip);
761         if(hasClip == -1)
762             TRACE("Failed to get original clipping region\n");
763         else
764             IntersectClipRect(hdc, opts->rcClip.left, opts->rcClip.top, opts->rcClip.right, opts->rcClip.bottom);
765     }
766     CopyRect(&rt, pRect);
767
768     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
769     if(bgtype == BT_IMAGEFILE)
770         hr = UXTHEME_DrawImageBackground(hTheme, hdc, iPartId, iStateId, &rt, opts);
771     else if(bgtype == BT_BORDERFILL)
772         hr = UXTHEME_DrawBorderBackground(hTheme, hdc, iPartId, iStateId, pRect, opts);
773     else {
774         FIXME("Unknown background type\n");
775         /* This should never happen, and hence I don't know what to return */
776         hr = E_FAIL;
777     }
778     if(SUCCEEDED(hr))
779         hr = UXTHEME_DrawGlyph(hTheme, hdc, iPartId, iStateId, &rt, opts);
780     if(opts->dwFlags & DTBG_CLIPRECT) {
781         if(hasClip == 0)
782             SelectClipRgn(hdc, NULL);
783         else if(hasClip == 1)
784             SelectClipRgn(hdc, clip);
785         DeleteObject(clip);
786     }
787     return hr;
788 }
789
790 /***********************************************************************
791  *      DrawThemeEdge                                       (UXTHEME.@)
792  */
793 HRESULT WINAPI DrawThemeEdge(HTHEME hTheme, HDC hdc, int iPartId,
794                              int iStateId, const RECT *pDestRect, UINT uEdge,
795                              UINT uFlags, RECT *pContentRect)
796 {
797     FIXME("%d %d 0x%08x 0x%08x: stub\n", iPartId, iStateId, uEdge, uFlags);
798     if(!hTheme)
799         return E_HANDLE;
800     return ERROR_CALL_NOT_IMPLEMENTED;
801 }
802
803 /***********************************************************************
804  *      DrawThemeIcon                                       (UXTHEME.@)
805  */
806 HRESULT WINAPI DrawThemeIcon(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
807                              const RECT *pRect, HIMAGELIST himl, int iImageIndex)
808 {
809     FIXME("%d %d: stub\n", iPartId, iStateId);
810     if(!hTheme)
811         return E_HANDLE;
812     return ERROR_CALL_NOT_IMPLEMENTED;
813 }
814
815 /***********************************************************************
816  *      DrawThemeText                                       (UXTHEME.@)
817  */
818 HRESULT WINAPI DrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
819                              LPCWSTR pszText, int iCharCount, DWORD dwTextFlags,
820                              DWORD dwTextFlags2, const RECT *pRect)
821 {
822     HRESULT hr;
823     HFONT hFont = NULL;
824     HGDIOBJ oldFont = NULL;
825     LOGFONTW logfont;
826     COLORREF textColor;
827     COLORREF oldTextColor;
828     int oldBkMode;
829     RECT rt;
830     
831     TRACE("%d %d: stub\n", iPartId, iStateId);
832     if(!hTheme)
833         return E_HANDLE;
834     
835     hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
836     if(SUCCEEDED(hr)) {
837         hFont = CreateFontIndirectW(&logfont);
838         if(!hFont)
839             TRACE("Failed to create font\n");
840     }
841     CopyRect(&rt, pRect);
842     if(hFont)
843         oldFont = SelectObject(hdc, hFont);
844         
845     if(dwTextFlags2 & DTT_GRAYED)
846         textColor = GetSysColor(COLOR_GRAYTEXT);
847     else {
848         if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTCOLOR, &textColor)))
849             textColor = GetTextColor(hdc);
850     }
851     oldTextColor = SetTextColor(hdc, textColor);
852     oldBkMode = SetBkMode(hdc, TRANSPARENT);
853     DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
854     SetBkMode(hdc, oldBkMode);
855     SetTextColor(hdc, oldTextColor);
856
857     if(hFont) {
858         SelectObject(hdc, oldFont);
859         DeleteObject(hFont);
860     }
861     return S_OK;
862 }
863
864 /***********************************************************************
865  *      GetThemeBackgroundContentRect                       (UXTHEME.@)
866  */
867 HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId,
868                                              int iStateId,
869                                              const RECT *pBoundingRect,
870                                              RECT *pContentRect)
871 {
872     MARGINS margin;
873     HRESULT hr;
874
875     TRACE("(%d,%d)\n", iPartId, iStateId);
876     if(!hTheme)
877         return E_HANDLE;
878
879     hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
880     if(FAILED(hr)) {
881         TRACE("Margins not found\n");
882         return hr;
883     }
884     pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
885     pContentRect->top  = pBoundingRect->top + margin.cyTopHeight;
886     pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
887     pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
888
889     TRACE("left:%ld,top:%ld,right:%ld,bottom:%ld\n", pContentRect->left, pContentRect->top, pContentRect->right, pContentRect->bottom);
890
891     return S_OK;
892 }
893
894 /***********************************************************************
895  *      GetThemeBackgroundExtent                            (UXTHEME.@)
896  */
897 HRESULT WINAPI GetThemeBackgroundExtent(HTHEME hTheme, HDC hdc, int iPartId,
898                                         int iStateId, const RECT *pContentRect,
899                                         RECT *pExtentRect)
900 {
901     MARGINS margin;
902     HRESULT hr;
903
904     TRACE("(%d,%d)\n", iPartId, iStateId);
905     if(!hTheme)
906         return E_HANDLE;
907
908     hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
909     if(FAILED(hr)) {
910         TRACE("Margins not found\n");
911         return hr;
912     }
913     pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
914     pExtentRect->top  = pContentRect->top - margin.cyTopHeight;
915     pExtentRect->right = pContentRect->right + margin.cxRightWidth;
916     pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
917
918     TRACE("left:%ld,top:%ld,right:%ld,bottom:%ld\n", pExtentRect->left, pExtentRect->top, pExtentRect->right, pExtentRect->bottom);
919
920     return S_OK;
921 }
922
923 /***********************************************************************
924  *      GetThemeBackgroundRegion                            (UXTHEME.@)
925  *
926  * Calculate the background region, taking into consideration transparent areas
927  * of the background image.
928  */
929 HRESULT WINAPI GetThemeBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId,
930                                         int iStateId, const RECT *pRect,
931                                         HRGN *pRegion)
932 {
933     HRESULT hr = S_OK;
934     int bgtype = BT_BORDERFILL;
935
936     TRACE("(%p,%p,%d,%d)\n", hTheme, hdc, iPartId, iStateId);
937     if(!hTheme)
938         return E_HANDLE;
939     if(!pRect || !pRegion)
940         return E_POINTER;
941
942     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
943     if(bgtype == BT_IMAGEFILE) {
944         FIXME("Images not handled yet\n");
945         hr = ERROR_CALL_NOT_IMPLEMENTED;
946     }
947     else if(bgtype == BT_BORDERFILL) {
948         *pRegion = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
949         if(!*pRegion)
950             hr = HRESULT_FROM_WIN32(GetLastError());
951     }
952     else {
953         FIXME("Unknown background type\n");
954         /* This should never happen, and hence I don't know what to return */
955         hr = E_FAIL;
956     }
957     return hr;
958 }
959
960 /***********************************************************************
961  *      GetThemePartSize                                    (UXTHEME.@)
962  */
963 HRESULT WINAPI GetThemePartSize(HTHEME hTheme, HDC hdc, int iPartId,
964                                 int iStateId, RECT *prc, THEMESIZE eSize,
965                                 SIZE *psz)
966 {
967     FIXME("%d %d %d: stub\n", iPartId, iStateId, eSize);
968     if(!hTheme)
969         return E_HANDLE;
970     return ERROR_CALL_NOT_IMPLEMENTED;
971 }
972
973
974 /***********************************************************************
975  *      GetThemeTextExtent                                  (UXTHEME.@)
976  */
977 HRESULT WINAPI GetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId,
978                                   int iStateId, LPCWSTR pszText, int iCharCount,
979                                   DWORD dwTextFlags, const RECT *pBoundingRect,
980                                   RECT *pExtentRect)
981 {
982     HRESULT hr;
983     HFONT hFont = NULL;
984     HGDIOBJ oldFont = NULL;
985     LOGFONTW logfont;
986     RECT rt = {0,0,0xFFFF,0xFFFF};
987     
988     TRACE("%d %d: stub\n", iPartId, iStateId);
989     if(!hTheme)
990         return E_HANDLE;
991
992     if(pBoundingRect)
993         CopyRect(&rt, pBoundingRect);
994             
995     hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
996     if(SUCCEEDED(hr)) {
997         hFont = CreateFontIndirectW(&logfont);
998         if(!hFont)
999             TRACE("Failed to create font\n");
1000     }
1001     if(hFont)
1002         oldFont = SelectObject(hdc, hFont);
1003         
1004     DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags|DT_CALCRECT);
1005     CopyRect(pExtentRect, &rt);
1006
1007     if(hFont) {
1008         SelectObject(hdc, oldFont);
1009         DeleteObject(hFont);
1010     }
1011     return S_OK;
1012 }
1013
1014 /***********************************************************************
1015  *      GetThemeTextMetrics                                 (UXTHEME.@)
1016  */
1017 HRESULT WINAPI GetThemeTextMetrics(HTHEME hTheme, HDC hdc, int iPartId,
1018                                    int iStateId, TEXTMETRICW *ptm)
1019 {
1020     HRESULT hr;
1021     HFONT hFont = NULL;
1022     HGDIOBJ oldFont = NULL;
1023     LOGFONTW logfont;
1024
1025     TRACE("(%p, %p, %d, %d)\n", hTheme, hdc, iPartId, iStateId);
1026     if(!hTheme)
1027         return E_HANDLE;
1028
1029     hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1030     if(SUCCEEDED(hr)) {
1031         hFont = CreateFontIndirectW(&logfont);
1032         if(!hFont)
1033             TRACE("Failed to create font\n");
1034     }
1035     if(hFont)
1036         oldFont = SelectObject(hdc, hFont);
1037
1038     if(!GetTextMetricsW(hdc, ptm))
1039         hr = HRESULT_FROM_WIN32(GetLastError());
1040
1041     if(hFont) {
1042         SelectObject(hdc, oldFont);
1043         DeleteObject(hFont);
1044     }
1045     return hr;
1046 }
1047
1048 /***********************************************************************
1049  *      IsThemeBackgroundPartiallyTransparent               (UXTHEME.@)
1050  */
1051 BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId,
1052                                                   int iStateId)
1053 {
1054     BOOL transparent = FALSE;
1055     TRACE("(%d,%d)\n", iPartId, iStateId);
1056     GetThemeBool(hTheme, iPartId, iStateId, TMT_TRANSPARENT, &transparent);
1057     return transparent;
1058 }