windows-nt/Source/XPSP1/NT/shell/themes/uxtheme/textfade.cpp
2020-09-26 16:20:57 +08:00

229 lines
8.1 KiB
C++

//---------------------------------------------------------------------------
// TextFade.cpp - text fading code (removed from taskbar)
//---------------------------------------------------------------------------
// BEGIN fade-text drawing functions and friends
//---------------------------------------------------------------------------
#include "stdafx.h"
//---------------------------------------------------------------------------
static HBITMAP CreateDibSection32Bit(int w, int h, void** ppv)
{
HBITMAP bitmap;
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = w;
bmi.bmiHeader.biHeight = h;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = 0;
bitmap = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, ppv, NULL, 0);
if (bitmap)
memset(*ppv, 0xff, w*h*4); //32bpp=4bytes
return bitmap;
}
//---------------------------------------------------------------------------
static void SetupAlphaChannel(DWORD* pdw, int w, int h, BYTE bstart, BYTE bend, int nExtra)
{
//nExtra is extra space that we want to fill with the final value
int i,j;
w -= nExtra;
if (bstart > bend)
{
BYTE bdiff = bstart - bend;
for (j=0;j<h;j++)
{
for (i=0;i<w;i++)
{
BYTE a = bstart - bdiff * i/w; //alpha
BYTE r = (GetRValue(*pdw)*a)/256;
BYTE g = (GetGValue(*pdw)*a)/256;
BYTE b = (GetBValue(*pdw)*a)/256;
*pdw = (a<<24)|RGB(r,g,b);
pdw++;
}
for (i=w;i<w+nExtra;i++)
{
BYTE a = bend; //alpha
BYTE r = (GetRValue(*pdw)*a)/256;
BYTE g = (GetGValue(*pdw)*a)/256;
BYTE b = (GetBValue(*pdw)*a)/256;
*pdw = (a<<24)|RGB(r,g,b);
pdw++;
}
}
}
else
{
BYTE bdiff = bend - bstart;
for (j=0;j<h;j++)
{
for (i=0;i<w;i++)
{
BYTE a = bstart + bdiff * i/w; //alpha
BYTE r = (GetRValue(*pdw)*a)/256;
BYTE g = (GetGValue(*pdw)*a)/256;
BYTE b = (GetBValue(*pdw)*a)/256;
*pdw = (a<<24)|RGB(r,g,b);
pdw++;
}
for (i=w;i<w+nExtra;i++)
{
BYTE a = bend; //alpha
BYTE r = (GetRValue(*pdw)*a)/256;
BYTE g = (GetGValue(*pdw)*a)/256;
BYTE b = (GetBValue(*pdw)*a)/256;
*pdw = (a<<24)|RGB(r,g,b);
pdw++;
}
}
}
}
//---------------------------------------------------------------------------
int ExtTextOutAlpha(HDC dc, int X, int Y, UINT fuOptions, CONST RECT *lprc,
LPCTSTR lpsz, UINT nCount, CONST INT *lpDx)
{
BOOL bEffects = FALSE;
SystemParametersInfo(SPI_GETUIEFFECTS, 0, (void*)&bEffects, 0);
// don't alpha blend if ui effects off or number of colors <= 256
if (!bEffects ||
(GetDeviceCaps(dc, BITSPIXEL) * GetDeviceCaps(dc, PLANES) <= 8))
{
return ExtTextOut(dc, X, Y, fuOptions, lprc, lpsz, nCount, lpDx);
}
if (lprc == NULL)
return ExtTextOut(dc, X, Y, fuOptions, lprc, lpsz, nCount, lpDx);
RECT rc = *lprc;
int nwidth = rc.right -rc.left;
int nheight = rc.bottom - rc.top;
int nLen = (nCount == -1) ? lstrlen(lpsz) : nCount;
int nFit=0;
int* pFit = new int[nLen];
if (pFit == NULL)
return 0;
pFit[0] = 0;
SIZE size;
GetTextExtentExPoint(dc, lpsz, nLen, nwidth, &nFit, pFit, &size);
if (nFit >= nLen)
return ExtTextOut(dc, X, Y, fuOptions, lprc, lpsz, nCount, lpDx);
// too small, let's alpha blend it
if ((nwidth <= 0) || (nheight <= 0))
return 1;
TEXTMETRIC tm;
GetTextMetrics(dc, &tm);
int nPix = tm.tmAveCharWidth*5;
//don't fade out more than half the text
if (nPix > nwidth)
nPix = nwidth/2;
//Create a 32bpp dibsection to store the background
void* pv = NULL;
HDC dcbitmap = CreateCompatibleDC(dc);
int nRet = 0;
if (dcbitmap != NULL)
{
HBITMAP bitmap = CreateDibSection32Bit(nPix, nheight, &pv);
if (bitmap != NULL)
{
HBITMAP tmpbmp = (HBITMAP) SelectObject(dcbitmap, bitmap);
BitBlt(dcbitmap, 0, 0, nPix, nheight, dc, rc.right-nPix, rc.top, SRCCOPY);
//Setup the per-pixel alpha blending values
SetupAlphaChannel((DWORD*)pv, nPix, nheight, 0x00, 0xdf, 0);
//Draw the text onto the display DC
ExtTextOut(dc, X, Y, fuOptions, lprc, lpsz, nLen, lpDx);
//Blend the background back into the display
BLENDFUNCTION blend = {AC_SRC_OVER, 0, 0xff, AC_SRC_ALPHA};
GdiAlphaBlend(dc, rc.right-nPix, rc.top, nPix, nheight, dcbitmap, 0, 0, nPix, nheight, blend);
::SelectObject(dcbitmap, tmpbmp);
DeleteObject(bitmap);
nRet = 1;
}
DeleteDC(dcbitmap);
}
return nRet;
}
//---------------------------------------------------------------------------
int DrawTextAlpha(HDC hdc, LPCTSTR lpsz, int nCount, RECT* prc, UINT uFormat)
{
BOOL bEffects = FALSE;
SystemParametersInfo(SPI_GETUIEFFECTS, 0, (void*)&bEffects, 0);
// don't alpha blend if ui effects off or number of colors <= 256
if (!bEffects ||
(GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES) <= 8))
{
return DrawText(hdc, lpsz, nCount, prc, uFormat);
}
UINT nEllipsis = (DT_END_ELLIPSIS|DT_WORD_ELLIPSIS|DT_WORD_ELLIPSIS);
if (!(uFormat & DT_SINGLELINE) || !(uFormat & DT_END_ELLIPSIS) || (uFormat & DT_CALCRECT))
return ::DrawText(hdc, lpsz, nCount, prc, uFormat);
//we are single line and ellipses are requested
//we are going to alpha blend though
uFormat &= ~nEllipsis; //turn all ellipsis flags off
if (nCount == -1)
nCount = lstrlen(lpsz);
RECT rc;
CopyRect(&rc, prc);
::DrawText(hdc, (TCHAR*)lpsz, nCount, &rc, uFormat | DT_CALCRECT);
if (rc.right <= prc->right) //not truncated
return ::DrawText(hdc, lpsz, nCount, prc, uFormat);
// DT_CENTER is effectively ignored when ellipses flags are on,
// because text is clipped to fit in rectangle. With fading, we
// need to justify the text.
uFormat &= ~DT_CENTER;
CopyRect(&rc, prc);
int nwidth = RECTWIDTH(&rc);
int nheight = RECTHEIGHT(&rc);
if ((nwidth <= 0) || (nheight <= 0))
return 1;
// Figure out how much of the background to stash away
TEXTMETRIC tm;
GetTextMetrics(hdc, &tm);
int nPix = tm.tmAveCharWidth*5; //five characters worth
if (nPix > nwidth/2)
nPix = nwidth/2;
//Adjust by one max char width because DrawText can draw up to
//one extra character outside the clip rect.
nPix += tm.tmMaxCharWidth;
rc.right += tm.tmMaxCharWidth;
//Create a 32bpp dibsection to store the background
void* pv = NULL;
HDC dcbitmap = CreateCompatibleDC(hdc);
int nRet = 0;
if (dcbitmap != NULL)
{
HBITMAP bitmap = CreateDibSection32Bit(nPix, nheight, &pv);
if (bitmap != NULL)
{
HBITMAP tmpbmp = (HBITMAP) SelectObject(dcbitmap, bitmap);
BitBlt(dcbitmap, 0, 0, nPix, nheight, hdc, rc.right-nPix, rc.top, SRCCOPY);
//Setup the per-pixel alpha blending values
SetupAlphaChannel((DWORD*)pv, nPix, nheight, 0x00, 0xdf, tm.tmMaxCharWidth);
//Draw the text onto the display DC
::DrawText(hdc, lpsz, nCount, prc, uFormat);
//Blend the background back into the display
BLENDFUNCTION blend = {AC_SRC_OVER, 0, 0xff, AC_SRC_ALPHA};
GdiAlphaBlend(hdc, rc.right-nPix, rc.top, nPix, nheight, dcbitmap, 0, 0, nPix, nheight, blend);
::SelectObject(dcbitmap, tmpbmp);
DeleteObject(bitmap);
nRet = 1;
}
DeleteDC(dcbitmap);
}
return nRet;
}
//---------------------------------------------------------------------------