From 44b4c7459b1d3e114f55b39aa8f8ee600ed7ae12 Mon Sep 17 00:00:00 2001 From: Frank Richter Date: Mon, 29 Aug 2005 21:47:26 +0000 Subject: [PATCH] Pass around what kind of transparency an image actually needs. Use alpha-blending for 32bpp images. --- dlls/uxtheme/draw.c | 199 ++++++++++++++++++++++++++++------------------ dlls/uxtheme/msstyles.c | 35 +++++++- dlls/uxtheme/uxthemedll.h | 9 ++- 3 files changed, 164 insertions(+), 79 deletions(-) diff --git a/dlls/uxtheme/draw.c b/dlls/uxtheme/draw.c index 32e90432422..b760bef4b44 100644 --- a/dlls/uxtheme/draw.c +++ b/dlls/uxtheme/draw.c @@ -236,21 +236,20 @@ static PTHEME_PROPERTY UXTHEME_SelectImage(HTHEME hTheme, HDC hdc, int iPartId, * Load image for part/state */ static HRESULT UXTHEME_LoadImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph, - HBITMAP *hBmp, RECT *bmpRect) + HBITMAP *hBmp, RECT *bmpRect, BOOL* hasImageAlpha) { int imagelayout = IL_HORIZONTAL; int imagecount = 1; int imagenum; BITMAP bmp; WCHAR szPath[MAX_PATH]; - BOOL hasAlpha; PTHEME_PROPERTY tp = UXTHEME_SelectImage(hTheme, hdc, iPartId, iStateId, pRect, glyph); if(!tp) { FIXME("Couldn't determine image for part/state %d/%d, invalid theme?\n", iPartId, iStateId); return E_PROP_ID_UNSUPPORTED; } lstrcpynW(szPath, tp->lpValue, min(tp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0]))); - *hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, &hasAlpha); + *hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, hasImageAlpha); if(!*hBmp) { TRACE("Failed to load bitmap %s\n", debugstr_w(szPath)); return HRESULT_FROM_WIN32(GetLastError()); @@ -285,18 +284,31 @@ static HRESULT UXTHEME_LoadImage(HTHEME hTheme, HDC hdc, int iPartId, int iState */ static inline BOOL UXTHEME_StretchBlt(HDC hdcDst, int nXOriginDst, int nYOriginDst, int nWidthDst, int nHeightDst, HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, - BOOL transparent, COLORREF transcolor) + INT transparent, COLORREF transcolor) { - if(transparent) { + static const BLENDFUNCTION blendFunc = + { + AC_SRC_OVER, /* BlendOp */ + 0, /* BlendFlag */ + 255, /* SourceConstantAlpha */ + AC_SRC_ALPHA /* AlphaFormat */ + }; + if (transparent == ALPHABLEND_BINARY) { /* Ensure we don't pass any negative values to TransparentBlt */ return TransparentBlt(hdcDst, nXOriginDst, nYOriginDst, abs(nWidthDst), abs(nHeightDst), hdcSrc, nXOriginSrc, nYOriginSrc, abs(nWidthSrc), abs(nHeightSrc), transcolor); } - /* This should be using AlphaBlend */ - return StretchBlt(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst, - hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, - SRCCOPY); + if ((transparent == ALPHABLEND_NONE) || + !AlphaBlend(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst, + hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, + blendFunc)) + { + return StretchBlt(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst, + hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, + SRCCOPY); + } + return TRUE; } /*********************************************************************** @@ -306,7 +318,7 @@ static inline BOOL UXTHEME_StretchBlt(HDC hdcDst, int nXOriginDst, int nYOriginD */ static inline BOOL UXTHEME_Blt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, - BOOL transparent, COLORREF transcolor) + INT transparent, COLORREF transcolor) { return UXTHEME_StretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, nWidthDest, nHeightDest, @@ -322,7 +334,8 @@ static inline BOOL UXTHEME_SizedBlt (HDC hdcDst, int nXOriginDst, int nYOriginDs int nWidthDst, int nHeightDst, HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, - int sizingtype) + int sizingtype, + INT transparent, COLORREF transcolor) { if (sizingtype == ST_TILE) { @@ -336,8 +349,9 @@ static inline BOOL UXTHEME_SizedBlt (HDC hdcDst, int nXOriginDst, int nYOriginDs while (xRemaining > 0) { int bltWidth = min (xRemaining, nWidthSrc); - if (!BitBlt (hdcDst, xOfs, yOfs, bltWidth, bltHeight, - hdcSrc, nXOriginSrc, nYOriginSrc, SRCCOPY)) + if (!UXTHEME_Blt (hdcDst, xOfs, yOfs, bltWidth, bltHeight, + hdcSrc, nXOriginSrc, nYOriginSrc, + transparent, transcolor)) return FALSE; xOfs += nWidthSrc; xRemaining -= nWidthSrc; @@ -349,9 +363,40 @@ static inline BOOL UXTHEME_SizedBlt (HDC hdcDst, int nXOriginDst, int nYOriginDs } else { - return StretchBlt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst, - hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, - SRCCOPY); + return UXTHEME_StretchBlt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst, + hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, + transparent, transcolor); + } +} + +/* Get transparency parameters passed to UXTHEME_StretchBlt() - the parameters + * depend on whether the image has full alpha or whether it is + * color-transparent or just opaque. */ +static inline void get_transparency (HTHEME hTheme, int iPartId, int iStateId, + BOOL hasImageAlpha, INT* transparent, + COLORREF* transparentcolor, BOOL glyph) +{ + if (hasImageAlpha) + { + *transparent = ALPHABLEND_FULL; + *transparentcolor = RGB (255, 0, 255); + } + else + { + BOOL trans = FALSE; + GetThemeBool(hTheme, iPartId, iStateId, + glyph ? TMT_GLYPHTRANSPARENT : TMT_TRANSPARENT, &trans); + if(trans) { + *transparent = ALPHABLEND_BINARY; + if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, + glyph ? TMT_GLYPHTRANSPARENTCOLOR : TMT_TRANSPARENTCOLOR, + transparentcolor))) { + /* If image is transparent, but no color was specified, use magenta */ + *transparentcolor = RGB(255, 0, 255); + } + } + else + *transparent = ALPHABLEND_NONE; } } @@ -369,15 +414,17 @@ static HRESULT UXTHEME_DrawImageGlyph(HTHEME hTheme, HDC hdc, int iPartId, HDC hdcSrc = NULL; HGDIOBJ oldSrc = NULL; RECT rcSrc; - BOOL transparent = FALSE; - COLORREF transparentcolor = 0; + INT transparent = FALSE; + COLORREF transparentcolor; int valign = VA_CENTER; int halign = HA_CENTER; POINT dstSize; POINT srcSize; POINT topleft; + BOOL hasAlpha; - hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, TRUE, &bmpSrc, &rcSrc); + hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, TRUE, + &bmpSrc, &rcSrc, &hasAlpha); if(FAILED(hr)) return hr; hdcSrc = CreateCompatibleDC(hdc); if(!hdcSrc) { @@ -392,13 +439,8 @@ static HRESULT UXTHEME_DrawImageGlyph(HTHEME hTheme, HDC hdc, int iPartId, srcSize.x = rcSrc.right-rcSrc.left; srcSize.y = rcSrc.bottom-rcSrc.top; - GetThemeBool(hTheme, iPartId, iStateId, TMT_GLYPHTRANSPARENT, &transparent); - if(transparent) { - if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_GLYPHTRANSPARENTCOLOR, &transparentcolor))) { - /* If image is transparent, but no color was specified, use magenta */ - transparentcolor = RGB(255, 0, 255); - } - } + get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent, + &transparentcolor, TRUE); GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign); GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign); @@ -456,8 +498,10 @@ static HRESULT get_image_part_size (HTHEME hTheme, HDC hdc, int iPartId, HRESULT hr = S_OK; HBITMAP bmpSrc; RECT rcSrc; + BOOL hasAlpha; - hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, prc, FALSE, &bmpSrc, &rcSrc); + hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, prc, FALSE, + &bmpSrc, &rcSrc, &hasAlpha); if (FAILED(hr)) return hr; switch (eSize) @@ -565,10 +609,12 @@ static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId, POINT srcSize; POINT drawSize; int sizingtype = ST_STRETCH; - BOOL transparent = FALSE; + INT transparent; COLORREF transparentcolor = 0; + BOOL hasAlpha; - hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, FALSE, &bmpSrc, &rcSrc); + hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, FALSE, + &bmpSrc, &rcSrc, &hasAlpha); if(FAILED(hr)) return hr; hdcSrc = CreateCompatibleDC(hdc); if(!hdcSrc) { @@ -580,13 +626,8 @@ static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId, CopyRect(&rcDst, pRect); - GetThemeBool(hTheme, iPartId, iStateId, TMT_TRANSPARENT, &transparent); - if(transparent) { - if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_TRANSPARENTCOLOR, &transparentcolor))) { - /* If image is transparent, but no color was specified, use magenta */ - transparentcolor = RGB(255, 0, 255); - } - } + get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent, + &transparentcolor, FALSE); dstSize.x = rcDst.right-rcDst.left; dstSize.y = rcDst.bottom-rcDst.top; @@ -618,48 +659,45 @@ static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId, } else { HDC hdcDst = NULL; - HBITMAP bmpDst = NULL; - HGDIOBJ oldDst = NULL; MARGINS sm; + POINT org; dstSize.x = abs(dstSize.x); dstSize.y = abs(dstSize.y); GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_SIZINGMARGINS, NULL, &sm); - hdcDst = CreateCompatibleDC(hdc); - if(!hdcDst) { - hr = HRESULT_FROM_WIN32(GetLastError()); - goto draw_error; - } - bmpDst = CreateCompatibleBitmap(hdc, dstSize.x, dstSize.y); - if(!bmpDst) { - hr = HRESULT_FROM_WIN32(GetLastError()); - goto draw_error; - } - oldDst = SelectObject(hdcDst, bmpDst); + hdcDst = hdc; + OffsetViewportOrgEx(hdcDst, rcDst.left, rcDst.top, &org); /* Upper left corner */ - if(!BitBlt(hdcDst, 0, 0, sm.cxLeftWidth, sm.cyTopHeight, - hdcSrc, rcSrc.left, rcSrc.top, SRCCOPY)) { + if(!UXTHEME_Blt(hdcDst, 0, 0, sm.cxLeftWidth, sm.cyTopHeight, + hdcSrc, rcSrc.left, rcSrc.top, + transparent, transparentcolor)) { hr = HRESULT_FROM_WIN32(GetLastError()); goto draw_error; } /* Upper right corner */ - if(!BitBlt(hdcDst, dstSize.x-sm.cxRightWidth, 0, sm.cxRightWidth, sm.cyTopHeight, - hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top, SRCCOPY)) { + if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, 0, + sm.cxRightWidth, sm.cyTopHeight, + hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top, + transparent, transparentcolor)) { hr = HRESULT_FROM_WIN32(GetLastError()); goto draw_error; } /* Lower left corner */ - if(!BitBlt(hdcDst, 0, dstSize.y-sm.cyBottomHeight, sm.cxLeftWidth, sm.cyBottomHeight, - hdcSrc, rcSrc.left, rcSrc.bottom-sm.cyBottomHeight, SRCCOPY)) { + if(!UXTHEME_Blt (hdcDst, 0, dstSize.y-sm.cyBottomHeight, + sm.cxLeftWidth, sm.cyBottomHeight, + hdcSrc, rcSrc.left, rcSrc.bottom-sm.cyBottomHeight, + transparent, transparentcolor)) { hr = HRESULT_FROM_WIN32(GetLastError()); goto draw_error; } /* Lower right corner */ - if(!BitBlt(hdcDst, dstSize.x-sm.cxRightWidth, dstSize.y-sm.cyBottomHeight, sm.cxRightWidth, sm.cyBottomHeight, - hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.bottom-sm.cyBottomHeight, SRCCOPY)) { + if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, dstSize.y-sm.cyBottomHeight, + sm.cxRightWidth, sm.cyBottomHeight, + hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.bottom-sm.cyBottomHeight, + transparent, transparentcolor)) { hr = HRESULT_FROM_WIN32(GetLastError()); goto draw_error; } @@ -672,28 +710,41 @@ static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId, if(destCenterWidth > 0) { /* Center top */ - if(!UXTHEME_SizedBlt(hdcDst, sm.cxLeftWidth, 0, destCenterWidth, sm.cyTopHeight, - hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top, srcCenterWidth, sm.cyTopHeight, sizingtype)) { + if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, 0, + destCenterWidth, sm.cyTopHeight, + hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top, + srcCenterWidth, sm.cyTopHeight, + sizingtype, transparent, transparentcolor)) { hr = HRESULT_FROM_WIN32(GetLastError()); goto draw_error; } /* Center bottom */ - if(!UXTHEME_SizedBlt(hdcDst, sm.cxLeftWidth, dstSize.y-sm.cyBottomHeight, destCenterWidth, sm.cyBottomHeight, - hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.bottom-sm.cyBottomHeight, srcCenterWidth, sm.cyTopHeight, sizingtype)) { + if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, dstSize.y-sm.cyBottomHeight, + destCenterWidth, sm.cyBottomHeight, + hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.bottom-sm.cyBottomHeight, + srcCenterWidth, sm.cyBottomHeight, + sizingtype, transparent, transparentcolor)) { hr = HRESULT_FROM_WIN32(GetLastError()); goto draw_error; } } if(destCenterHeight > 0) { /* Left center */ - if(!UXTHEME_SizedBlt(hdcDst, 0, sm.cyTopHeight, sm.cxLeftWidth, destCenterHeight, - hdcSrc, rcSrc.left, rcSrc.top+sm.cyTopHeight, sm.cxLeftWidth, srcCenterHeight, sizingtype)) { + if(!UXTHEME_SizedBlt (hdcDst, 0, sm.cyTopHeight, + sm.cxLeftWidth, destCenterHeight, + hdcSrc, rcSrc.left, rcSrc.top+sm.cyTopHeight, + sm.cxLeftWidth, srcCenterHeight, + sizingtype, + transparent, transparentcolor)) { hr = HRESULT_FROM_WIN32(GetLastError()); goto draw_error; } /* Right center */ - if(!UXTHEME_SizedBlt(hdcDst, dstSize.x-sm.cxRightWidth, sm.cyTopHeight, sm.cxRightWidth, destCenterHeight, - hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top+sm.cyTopHeight, sm.cxRightWidth, srcCenterHeight, sizingtype)) { + if(!UXTHEME_SizedBlt (hdcDst, dstSize.x-sm.cxRightWidth, sm.cyTopHeight, + sm.cxRightWidth, destCenterHeight, + hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top+sm.cyTopHeight, + sm.cxRightWidth, srcCenterHeight, + sizingtype, transparent, transparentcolor)) { hr = HRESULT_FROM_WIN32(GetLastError()); goto draw_error; } @@ -703,8 +754,11 @@ static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId, GetThemeBool(hTheme, iPartId, iStateId, TMT_BORDERONLY, &borderonly); if(!borderonly) { /* Center */ - if(!UXTHEME_SizedBlt(hdcDst, sm.cxLeftWidth, sm.cyTopHeight, destCenterWidth, destCenterHeight, - hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top+sm.cyTopHeight, srcCenterWidth, srcCenterHeight, sizingtype)) { + if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, sm.cyTopHeight, + destCenterWidth, destCenterHeight, + hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top+sm.cyTopHeight, + srcCenterWidth, srcCenterHeight, + sizingtype, transparent, transparentcolor)) { hr = HRESULT_FROM_WIN32(GetLastError()); goto draw_error; } @@ -712,17 +766,8 @@ static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId, } } - if(!UXTHEME_Blt(hdc, rcDst.left, rcDst.top, dstSize.x, dstSize.y, - hdcDst, 0, 0, - transparent, transparentcolor)) - hr = HRESULT_FROM_WIN32(GetLastError()); - draw_error: - if(hdcDst) { - SelectObject(hdcDst, oldDst); - DeleteDC(hdcDst); - } - if(bmpDst) DeleteObject(bmpDst); + SetViewportOrgEx (hdcDst, org.x, org.y, NULL); } SelectObject(hdcSrc, oldSrc); DeleteObject(bmpSrc); diff --git a/dlls/uxtheme/msstyles.c b/dlls/uxtheme/msstyles.c index f40a35e03aa..f65a8bac6b6 100644 --- a/dlls/uxtheme/msstyles.c +++ b/dlls/uxtheme/msstyles.c @@ -876,6 +876,38 @@ PTHEME_PROPERTY MSSTYLES_FindProperty(PTHEME_CLASS tc, int iPartId, int iStateId return NULL; } +/* Prepare a bitmap to be used for alpha blending */ +static BOOL prepare_alpha (HBITMAP bmp, BOOL* hasAlpha) +{ + DIBSECTION dib; + int n; + BYTE* p; + + *hasAlpha = FALSE; + + if (!bmp || GetObjectW( bmp, sizeof(dib), &dib ) != sizeof(dib)) + return FALSE; + + if(dib.dsBm.bmBitsPixel != 32) + /* nothing to do */ + return TRUE; + + *hasAlpha = TRUE; + p = (BYTE*)dib.dsBm.bmBits; + n = abs(dib.dsBmih.biHeight) * dib.dsBmih.biWidth; + /* AlphaBlend() wants premultiplied alpha, so do that now */ + while (n-- > 0) + { + int a = p[3]+1; + p[0] = (p[0] * a) >> 8; + p[1] = (p[1] * a) >> 8; + p[2] = (p[2] * a) >> 8; + p += 4; + } + + return TRUE; +} + HBITMAP MSSTYLES_LoadBitmap (PTHEME_CLASS tc, LPCWSTR lpFilename, BOOL* hasAlpha) { WCHAR szFile[MAX_PATH]; @@ -904,7 +936,8 @@ HBITMAP MSSTYLES_LoadBitmap (PTHEME_CLASS tc, LPCWSTR lpFilename, BOOL* hasAlpha /* Not found? Load from resources */ img = HeapAlloc (GetProcessHeap(), 0, sizeof (THEME_IMAGE)); img->image = LoadImageW(tc->hTheme, szFile, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); - img->hasAlpha = *hasAlpha = FALSE; /* TODO: real check */ + prepare_alpha (img->image, hasAlpha); + img->hasAlpha = *hasAlpha; /* ...and stow away for later reuse. */ lstrcpyW (img->name, szFile); img->next = tc->tf->images; diff --git a/dlls/uxtheme/uxthemedll.h b/dlls/uxtheme/uxthemedll.h index cfd80fb016b..2ac3873d1a6 100644 --- a/dlls/uxtheme/uxthemedll.h +++ b/dlls/uxtheme/uxthemedll.h @@ -87,4 +87,11 @@ HRESULT WINAPI ParseThemeIniFile(LPCWSTR pszIniFileName, LPWSTR pszUnknown, extern void UXTHEME_InitSystem(HINSTANCE hInst); -#endif +/* No alpha blending */ +#define ALPHABLEND_NONE 0 +/* "Cheap" binary alpha blending - but possibly faster */ +#define ALPHABLEND_BINARY 1 +/* Full alpha blending */ +#define ALPHABLEND_FULL 2 + +#endif /* __WINE_UXTHEMEDLL_H */ -- 2.11.4.GIT