/* ** CUTILS.C ** ** Common utilities for common controls ** */ #include "ctlspriv.h" #include #define ARGB(a,r,g,b) ((COLORREF)(( \ ((BYTE)(r)) | \ ((WORD) ((BYTE)(g))<< 8)) | \ (((DWORD)((BYTE)(b))<<16)) | \ (((DWORD)((BYTE)(a))<<24)))) #define PREMULTIPLY(c, alpha) ((( ((c) * (alpha)) + 128) >> 8) + 1) typedef struct tagCCBUFFER { HDC hdc; HBITMAP hbmp; HBITMAP hbmpOld; RGBQUAD* prgb; } CCBUFFER; BOOL Buffer_CreateBuffer(HDC hdc, int cx, int cy, CCBUFFER* pbuf) { BOOL fRet = FALSE; BITMAPINFO bi = {0}; bi.bmiHeader.biSize = sizeof(bi.bmiHeader); bi.bmiHeader.biWidth = cx; bi.bmiHeader.biHeight = cy; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = 32; bi.bmiHeader.biCompression = BI_RGB; pbuf->hdc = CreateCompatibleDC(hdc); if (pbuf->hdc) { pbuf->hbmp = CreateDIBSection(pbuf->hdc, &bi, DIB_RGB_COLORS, (VOID**)&pbuf->prgb, NULL, 0); if (!pbuf->hbmp) { DeleteDC(pbuf->hdc); ZeroMemory(pbuf, sizeof(CCBUFFER)); } else { pbuf->hbmpOld = (HBITMAP)SelectObject(pbuf->hdc, pbuf->hbmp); fRet = TRUE; } } return fRet; } void Buffer_DestroyBuffer(CCBUFFER* pbuf) { if (pbuf->hdc) { SelectObject(pbuf->hdc, pbuf->hbmpOld); DeleteDC(pbuf->hdc); DeleteObject(pbuf->hbmp); } } void BlurBitmapNormal(ULONG* prgb, int cx, int cy, COLORREF crFill) { BYTE r = GetRValue(crFill); BYTE g = GetGValue(crFill); BYTE b = GetBValue(crFill); int cxMax = cx - 5; int cyMax = cy - 5; int iOffset; int y; for (y=0, iOffset = 0; y < cy; y++, iOffset += cx) { ULONG* p = &prgb[iOffset]; int Accum = ((*p)) + ((*(p + 1))) + ((*(p + 2))) + ((*(p + 3))); for (int x=0; x< cxMax; x++) { Accum = Accum - ((*p)) + ((*(p + 4))); *p++ = (Accum >> 2); } } int cx2 = cx << 1; int cx3 = cx + cx + cx; int cx4 = cx << 2; for (iOffset = 0, y=0; y < cyMax; y++, iOffset += cx) { ULONG* p = &prgb[iOffset]; for (int x=0; x < cx; x++) { DWORD Alpha = (((*p) ) + (*(p + cx) ) + (*(p + cx2) ) + (*(p + cx3) ) + (*(p + cx4) )) >> 2; if (Alpha > 255) Alpha = 255; *p = (ULONG)ARGB(Alpha, PREMULTIPLY(r, Alpha), PREMULTIPLY(g, Alpha), PREMULTIPLY(b, Alpha)); p++; } } } #ifdef _X86_ QWORD qw128 = 0x0000008000800080; QWORD qw1 = 0x0000000100010001; void BlurBitmapMMX(ULONG* prgb, int cx, int cy, COLORREF crFill) { RGBQUAD rgbFill; // ColorRef is opposite of RGBQUAD rgbFill.rgbRed = GetRValue(crFill); rgbFill.rgbGreen = GetGValue(crFill); rgbFill.rgbBlue = GetBValue(crFill); int cxMax = cx - 5; int cyMax = cy - 5; int iOffset; int y; for (y=0, iOffset = 0; y < cy; y++, iOffset += cx) { ULONG* p = &prgb[iOffset]; int Accum = ((*p)) + ((*(p + 1))) + ((*(p + 2))) + ((*(p + 3))); for (int x=0; x< cxMax; x++) { Accum = Accum - ((*p)) + ((*(p + 4))); *p++ = (Accum >> 2); } } int cx2 = cx << 1; int cx3 = cx + cx + cx; int cx4 = cx << 2; _asm { pxor mm0, mm0 pxor mm1, mm1 pxor mm5, mm5 movd mm4, dword ptr [rgbFill] movq mm6, qw128 // mm6 is filled with 128 movq mm7, qw1 // mm7 is filled with 1 } for (iOffset = 0, y=0; y < cyMax; y++, iOffset += cx) { ULONG* p = &prgb[iOffset]; for (int x=0; x < cx; x++) { DWORD Alpha = (((*p) ) + (*(p + cx) ) + (*(p + cx2) ) + (*(p + cx3) ) + (*(p + cx4) )) >> 2; if (Alpha > 255) Alpha = 255; *p = ((BYTE)Alpha); _asm { mov edx, dword ptr [p] mov ebx, dword ptr [edx] mov eax, ebx // a -> b or eax, eax jz EarlyOut shl ebx, 8 // b << 8 or eax, ebx // a |= b shl ebx, 8 // b << 8 or eax, ebx // a |= b shl ebx, 8 // b << 8 // Note high byte of alpha is zero. movd mm0, eax // a -> mm0 movq mm1, mm4 // Load the pixel punpcklbw mm0,mm5 // mm0 -> Expands <- mm0 Contains the Alpha channel for this multiply punpcklbw mm1, mm5 // Unpack the pixel pmullw mm1, mm0 // Multiply by the alpha channel <- mm1 contains c * alpha paddusw mm1, mm6 // perform the (c * alpha) + 128 psrlw mm1, 8 // Divide by 255 paddusw mm1, mm7 // Add 1 to finish the divide by 255 packuswb mm1, mm5 movd eax, mm1 or eax, ebx // Transfer alpha channel EarlyOut: mov dword ptr [edx], eax } p++; } } _asm emms } void BlurBitmap(ULONG* plBitmapBits, int cx, int cy, COLORREF crFill) { if (IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE)) BlurBitmapMMX(plBitmapBits, cx, cy, crFill); else BlurBitmapNormal(plBitmapBits, cx, cy, crFill); } #else void BlurBitmap(ULONG* plBitmapBits, int cx, int cy, COLORREF crFill) { BlurBitmapNormal(plBitmapBits, cx, cy, crFill); } #endif int DrawShadowText(HDC hdc, LPCTSTR pszText, UINT cch, RECT* prc, DWORD dwFlags, COLORREF crText, COLORREF crShadow, int ixOffset, int iyOffset) { int iRet = -1; if (dwFlags & DT_CALCRECT) { iRet = DrawText(hdc, pszText, cch, prc, dwFlags | DT_CALCRECT); } else { if (GetLayout(hdc) == LAYOUT_RTL) { COLORREF crTextSave = SetTextColor(hdc, crShadow); int iMode = SetBkMode(hdc, TRANSPARENT); RECT rc = *prc; OffsetRect(&rc, ixOffset, iyOffset); DrawText(hdc, pszText, cch, &rc, dwFlags); SetBkMode(hdc, iMode); SetTextColor(hdc, crTextSave); } else { RECT rc = *prc; CCBUFFER buf; int cx = RECTWIDTH(rc) + 10; int cy = RECTHEIGHT(rc) + 10; if (Buffer_CreateBuffer(hdc, cx, cy, &buf)) { OffsetRect(&rc, 5, 5); RECT rcMem = {5, 5, RECTWIDTH(rc) + 5, RECTHEIGHT(rc) + 5}; HFONT hFontOldhdc = (HFONT)SelectObject(hdc, GetStockObject(SYSTEM_FONT)); HFONT hFontOldhdcMem = (HFONT)SelectObject(buf.hdc, hFontOldhdc); SetTextColor(buf.hdc, crText); SetBkColor(buf.hdc, crShadow); SetBkMode(buf.hdc, TRANSPARENT); DrawText(buf.hdc, pszText, cch, &rcMem, dwFlags); int Total = cx * cy; for (int z = 0; z < Total; z++) { if (((PULONG)buf.prgb)[z] != 0) ((PULONG)buf.prgb)[z] = 0x000000ff; } BlurBitmap((ULONG*)buf.prgb, cx, cy, crShadow); BLENDFUNCTION bf = {0}; bf.BlendOp = AC_SRC_OVER; bf.SourceConstantAlpha = 255; bf.AlphaFormat = AC_SRC_ALPHA; GdiAlphaBlend(hdc, prc->left - 4 + ixOffset, prc->top - 8 + iyOffset, cx, cy, buf.hdc, 0, 0, cx, cy, bf); SelectObject(buf.hdc, hFontOldhdcMem); SelectObject(hdc, hFontOldhdc); Buffer_DestroyBuffer(&buf); } } int iMode = SetBkMode(hdc, TRANSPARENT); COLORREF crTextSave = SetTextColor(hdc, crText); iRet = DrawText(hdc, pszText, cch, prc, dwFlags); SetTextColor(hdc, crTextSave); SetBkMode(hdc, iMode); } return iRet; }