/* Miranda NG: the free IM client for Microsoft* Windows* Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), Copyright (c) 2000-08 Miranda ICQ/IM project, all portions of this codebase are copyrighted to the people listed in contributors.txt. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ //Include #include "hdr/modern_commonheaders.h" #include #include "m_api/m_skin_eng.h" #include "hdr/modern_skinselector.h" #include "CLUIFrames/cluiframes.h" #define _EFFECTENUM_FULL_H #include "hdr/modern_effectenum.h" #undef _EFFECTENUM_FULL_H #include "hdr/modern_skinengine.h" #include "hdr/modern_commonprototypes.h" #include "hdr/modern_sync.h" //Implementation /* Global variables */ SKINOBJECTSLIST g_SkinObjectList = {0}; CURRWNDIMAGEDATA *g_pCachedWindow = NULL; BOOL g_flag_bPostWasCanceled = FALSE; BOOL g_flag_bFullRepaint = FALSE; BOOL g_mutex_bLockUpdating = FALSE; SortedList *gl_plGlyphTexts = NULL; SortedList *gl_plSkinFonts = NULL; /* Private module variables */ static HANDLE hSkinLoadedEvent; static GLYPHIMAGE *pLoadedImages = NULL; static DWORD dwLoadedImagesCount = 0; static DWORD dwLoadedImagesAlocated = 0; static BOOL flag_bUpdateQueued = FALSE; static BOOL flag_bJustDrawNonFramedObjects = FALSE; static BOOL mutex_bLockUpdate = FALSE; static LIST arEffectStack(10, HandleKeySortT); static SKINOBJECTSLIST *pCurrentSkin = NULL; static char **pszSettingName = NULL; static int nArrayLen = 0; static BYTE pbGammaWeight[256] = {0}; static BYTE pbGammaWeightAdv[256] = {0}; static BOOL bGammaWeightFilled = FALSE; static CRITICAL_SECTION cs_SkinChanging = {0}; static LISTMODERNMASK *MainModernMaskList = NULL; /* Private module procedures */ static BOOL ske_GetMaskBit(BYTE *line, int x); static INT_PTR ske_Service_AlphaTextOut(WPARAM wParam,LPARAM lParam); static INT_PTR ske_Service_DrawIconEx(WPARAM wParam,LPARAM lParam); static int ske_AlphaTextOut (HDC hDC, LPCTSTR lpString, int nCount, RECT *lpRect, UINT format, DWORD ARGBcolor); static void ske_AddParseTextGlyphObject(char * szGlyphTextID,char * szDefineString,SKINOBJECTSLIST *Skin); static void ske_AddParseSkinFont(char * szFontID,char * szDefineString,SKINOBJECTSLIST *Skin); static int ske_DeleteAllSettingInSection(char * SectionName); static int ske_GetSkinFromDB(char * szSection, SKINOBJECTSLIST * Skin); static LPSKINOBJECTDESCRIPTOR ske_FindObject(const char * szName, BYTE objType,SKINOBJECTSLIST* Skin); static int ske_LoadSkinFromResource(BOOL bOnlyObjects); static void ske_PreMultiplyChanells(HBITMAP hbmp,BYTE Mult); static int ske_ValidateSingleFrameImage(FRAMEWND * Frame, BOOL SkipBkgBlitting); static INT_PTR ske_Service_UpdateFrameImage(WPARAM wParam, LPARAM lParam); static INT_PTR ske_Service_InvalidateFrameImage(WPARAM wParam, LPARAM lParam); static INT_PTR ske_Service_DrawTextWithEffect(WPARAM wParam, LPARAM lParam); static MODERNEFFECT meCurrentEffect = {-1,{0}, 0, 0}; ////////////////////////////////////////////////////////////////////////// // Ini file parser ////////////////////////////////////////////////////////////////////////// IniParser::IniParser(TCHAR * tcsFileName, BYTE flags) : _Flags(flags) { _DoInit(); if (!tcsFileName) return; if (tcsFileName[0] == _T('%')) { //TODO: Add parser of resource filename here _LoadResourceIni(g_hInst, MAKEINTRESOURCEA(IDR_MSF_DEFAULT_SKIN), "MSF"); return; } _hFile = _tfopen(tcsFileName, _T("r")); if (_hFile != NULL) { _eType = IT_FILE; _isValid = true; } } IniParser::IniParser(HINSTANCE hInst, const char * resourceName, const char * resourceType, BYTE flags) : _Flags(flags) { _DoInit(); _LoadResourceIni(hInst, resourceName, resourceType); } IniParser::~IniParser() { mir_free(_szSection); if (_hFile) fclose(_hFile); if (_hGlobalRes) { UnlockResource(_hGlobalRes); FreeResource(_hGlobalRes); } _szSection = NULL; _hGlobalRes = NULL; _hFile = NULL; _isValid = false; _eType = IT_UNKNOWN; } HRESULT IniParser::Parse(ParserCallback_t pLineCallBackProc, LPARAM SecCheck) { if (_isValid && pLineCallBackProc) { _pLineCallBackProc = pLineCallBackProc; _SecCheck = SecCheck; switch (_eType) { case IT_FILE: return _DoParseFile(); case IT_RESOURCE: return _DoParseResource(); } } return E_FAIL; } HRESULT IniParser::WriteStrToDb( const char * szSection, const char * szName, const char * szValue, IniParser * This ) { if ( This->_SecCheck) { //TODO check security here if ( wildcmp( szSection,"Skin_Description_Section")) return S_OK; } if (( This->_Flags == IniParser::FLAG_ONLY_OBJECTS ) && !wildcmp( szSection, DEFAULTSKINSECTION)) return S_OK; // skip not objects switch (szValue[0]) { case 'b': db_set_b(NULL, szSection, szName, (BYTE)atoi(szValue + 1)); break; case 'w': db_set_w(NULL, szSection, szName, (WORD)atoi(szValue + 1)); break; case 'd': db_set_dw(NULL, szSection, szName, (DWORD)atoi(szValue + 1)); break; case 's': db_set_s(NULL, szSection, szName, szValue + 1); break; } return S_OK; } int IniParser::GetSkinFolder( IN const TCHAR * szFileName, OUT TCHAR * pszFolderName ) { TCHAR *szBuff = mir_tstrdup(szFileName); TCHAR *pszPos = szBuff + _tcslen(szBuff); while ( pszPos > szBuff && *pszPos != _T('.')) { pszPos--; } *pszPos = _T('\0'); _tcscpy( pszFolderName, szBuff ); TCHAR custom_folder[MAX_PATH]; TCHAR cus[MAX_PATH]; TCHAR *b3; _tcscpy( custom_folder, pszFolderName ); b3 = custom_folder + _tcslen( custom_folder ); while ( b3 > custom_folder && *b3 != _T('\\')) { b3--; } *b3 = _T('\0'); GetPrivateProfileString(_T("Skin_Description_Section"),_T("SkinFolder"),_T(""),cus,SIZEOF(custom_folder),szFileName); if (cus[0] != 0) mir_sntprintf(pszFolderName, MAX_PATH, _T("%s\\%s"), custom_folder, cus); mir_free(szBuff); PathToRelativeT(pszFolderName, pszFolderName); return 0; } void IniParser::_DoInit() { _isValid = false; _eType = IT_UNKNOWN; _szSection = NULL; _hFile = NULL; _hGlobalRes = NULL; _dwSizeOfRes = 0; _pPosition = NULL; _pLineCallBackProc = NULL; _SecCheck = 0; } void IniParser::_LoadResourceIni( HINSTANCE hInst, const char * resourceName, const char * resourceType ) { if (_eType != IT_UNKNOWN) return; HRSRC hRSrc = FindResourceA(hInst, resourceName, resourceType); if (!hRSrc) return; _hGlobalRes = LoadResource(hInst, hRSrc); if (!_hGlobalRes) return; _dwSizeOfRes = SizeofResource(hInst, hRSrc); _pPosition = (char*)LockResource(_hGlobalRes); _isValid = true; _eType = IT_RESOURCE; } HRESULT IniParser::_DoParseFile() { char szLine[MAX_LINE_LEN]; _nLine = 0; while (fgets(szLine, SIZEOF(szLine), _hFile) != NULL) { size_t len = 0; char * pLine = (char*)_RemoveTailings(szLine, len); if (len > 0) { pLine[len] = '\0'; if (!_DoParseLine(pLine)) return E_FAIL; } else _nLine++; }; return S_OK; } HRESULT IniParser::_DoParseResource() { _nLine = 0; char szLine[MAX_LINE_LEN]; char * pos = (char*)_pPosition; while (pos < _pPosition + _dwSizeOfRes) { int i = 0; while (pos < _pPosition + _dwSizeOfRes && *pos != '\n' && *pos != '\0' && i < MAX_LINE_LEN - 1) { if ((*pos) != '\r') szLine[i++] = *pos; pos++; } szLine[i] = '\0'; pos++; size_t len = 0; char * pLine = (char*)_RemoveTailings(szLine, len); if (len > 0) { pLine[len] = '\0'; if (!_DoParseLine(pLine)) return E_FAIL; } else _nLine++; } return S_OK; } const char * IniParser::_RemoveTailings( const char * szLine, size_t& len ) { const char * pStart = szLine; while (*pStart == ' ' || *pStart == '\t') pStart++; //skip spaces at begin const char * pEnd = pStart + strlen(pStart); while (pEnd > pStart && (*pEnd == ' ' || *pEnd == '\t' || *pEnd == '\n' || *pEnd == '\r')) pEnd--; len = pEnd - pStart; return pStart; } BOOL IniParser::_DoParseLine( char * szLine ) { _nLine++; DWORD len = strlen( szLine ); if (len == 0) return TRUE; switch( szLine[0] ) { case ';': return TRUE; // start of comment is found case '[': //New section start here mir_free(_szSection); _szSection = NULL; { char *tbuf = szLine + 1; // skip [ char *ebuf = tbuf; while (*ebuf != ']' && *ebuf != '\0') ebuf++; if (*ebuf == '\0') return FALSE; // no close bracket DWORD sectionLen = ebuf - tbuf; _szSection = (char*)mir_alloc(sectionLen + 1); strncpy(_szSection, tbuf, sectionLen); _szSection[sectionLen] = '\0'; } return TRUE; default: if (!_szSection ) return TRUE; //param found out of section char *keyName = szLine; char *keyValue = szLine; DWORD eqPlace = 0; DWORD len2 = strlen(keyName); while ( eqPlace < len2 && keyName[ eqPlace ] != '=' ) eqPlace++; //find '=' if (eqPlace == 0 || eqPlace == len2) return TRUE; // = not found or no key name //say false keyName[eqPlace] = '\0'; keyValue = keyName + eqPlace + 1; //remove tail spaces in Name { DWORD len3 = strlen(keyName); int j = len3-1; while (j>0 && (keyName[j] == ' ' || keyName[j] == '\t')) j--; if (j >= 0) keyName[j+1] = '\0'; } //remove start spaces in Value { DWORD len3 = strlen(keyValue); DWORD j = 0; while (j < len3 && (keyValue[j] == ' ' || keyValue[j] == '\t')) j++; if (j < len3) keyValue += j; } //remove tail spaces in Value { DWORD len3 = strlen(keyValue); int j = len3-1; while (j>0 && (keyValue[j] == ' ' || keyValue[j] == '\t' || keyValue[j] == '\n')) j--; if (j >= 0) keyValue[j+1] = '\0'; } _pLineCallBackProc( _szSection, keyName, keyValue, this ); } return TRUE; } ////////////////////////////////////////////////////////////////////////// // End of IniParser ////////////////////////////////////////////////////////////////////////// HRESULT SkinEngineLoadModule() { ModernSkinButtonLoadModule(); InitializeCriticalSection(&cs_SkinChanging); MainModernMaskList = (LISTMODERNMASK*)mir_calloc(sizeof(LISTMODERNMASK)); //init variables g_SkinObjectList.dwObjLPAlocated = 0; g_SkinObjectList.dwObjLPReserved = 0; g_SkinObjectList.pObjects = NULL; // Initialize GDI+ InitGdiPlus(); AniAva_InitModule(); //create services CreateServiceFunction(MS_SKIN_DRAWGLYPH,ske_Service_DrawGlyph); CreateServiceFunction(MS_SKINENG_UPTATEFRAMEIMAGE,ske_Service_UpdateFrameImage); CreateServiceFunction(MS_SKINENG_INVALIDATEFRAMEIMAGE,ske_Service_InvalidateFrameImage); CreateServiceFunction(MS_SKINENG_ALPHATEXTOUT,ske_Service_AlphaTextOut); CreateServiceFunction(MS_SKINENG_DRAWICONEXFIX,ske_Service_DrawIconEx); CreateServiceFunction(MS_DRAW_TEXT_WITH_EFFECT,ske_Service_DrawTextWithEffect); //create event handle hSkinLoadedEvent = HookEvent(ME_SKIN_SERVICESCREATED,CLUI_OnSkinLoad); NotifyEventHooks(g_CluiData.hEventSkinServicesCreated, 0, 0); return S_OK; } int SkinEngineUnloadModule() { //unload services ModernSkinButtonUnloadModule(0, 0); ske_UnloadSkin(&g_SkinObjectList); mir_free_and_nil(g_SkinObjectList.pObjects); mir_free_and_nil(g_SkinObjectList.pMaskList); mir_free_and_nil(MainModernMaskList); for (int i=0; i < arEffectStack.getCount(); i++) mir_free(arEffectStack[i]); arEffectStack.destroy(); if (g_pCachedWindow) { SelectObject(g_pCachedWindow->hBackDC,g_pCachedWindow->hBackOld); SelectObject(g_pCachedWindow->hImageDC,g_pCachedWindow->hImageOld); DeleteObject(g_pCachedWindow->hBackDIB); DeleteObject(g_pCachedWindow->hImageDIB); DeleteDC(g_pCachedWindow->hBackDC); DeleteDC(g_pCachedWindow->hImageDC); ReleaseDC(NULL,g_pCachedWindow->hScreenDC); mir_free_and_nil(g_pCachedWindow); } DeleteCriticalSection(&cs_SkinChanging); GdiFlush(); DestroyHookableEvent(g_CluiData.hEventSkinServicesCreated); AniAva_UnloadModule(); ShutdownGdiPlus(); //free variables return 1; } BOOL ske_AlphaBlend(HDC hdcDest,int nXOriginDest,int nYOriginDest,int nWidthDest,int nHeightDest,HDC hdcSrc,int nXOriginSrc,int nYOriginSrc,int nWidthSrc,int nHeightSrc,BLENDFUNCTION blendFunction) { if (g_CluiData.fDisableSkinEngine && !(blendFunction.BlendFlags&128)) { if (nWidthDest != nWidthSrc || nHeightDest != nHeightSrc) return StretchBlt(hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest,hdcSrc,nXOriginSrc,nYOriginSrc,nWidthSrc,nHeightSrc, SRCCOPY); else return BitBlt(hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest,hdcSrc,nXOriginSrc,nYOriginSrc, SRCCOPY); } if (blendFunction.BlendFlags&128) //Use gdi+ engine { return GDIPlus_AlphaBlend( hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest, hdcSrc,nXOriginSrc,nYOriginSrc,nWidthSrc,nHeightSrc, &blendFunction); } blendFunction.BlendFlags &= ~128; return AlphaBlend(hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest,hdcSrc,nXOriginSrc,nYOriginSrc,nWidthSrc,nHeightSrc,blendFunction); } static int ske_LockSkin() { EnterCriticalSection(&cs_SkinChanging); return 0; } static int ske_UnlockSkin() { LeaveCriticalSection(&cs_SkinChanging); return 0; } struct DCBUFFER { HDC hdcOwnedBy; int nUsageID; int width; int height; void* pImage; HDC hDC; HBITMAP oldBitmap; HBITMAP hBitmap; DWORD dwDestroyAfterTime; }; static int SortBufferList(const DCBUFFER *buf1, const DCBUFFER *buf2) { if (buf1->hdcOwnedBy != buf2->hdcOwnedBy) return (int)(buf1->hdcOwnedBy < buf2->hdcOwnedBy); else if (buf1->nUsageID != buf2->nUsageID) return (int)(buf1->nUsageID < buf2->nUsageID); else return (int)(buf1->hDC < buf2->hDC); } LIST BufferList(2, SortBufferList); CRITICAL_SECTION BufferListCS = {0}; enum { BUFFER_DRAWICON = 0, BUFFER_DRAWIMAGE }; HDC ske_RequestBufferDC(HDC hdcOwner, int dcID, int width, int height, BOOL fClear) { mir_cslock lck(BufferListCS); //Try to find DC in buffer list DCBUFFER buf; buf.hdcOwnedBy = hdcOwner; buf.nUsageID = dcID; buf.hDC = NULL; DCBUFFER *pBuf = BufferList.find(&buf); if (!pBuf) { //if not found - allocate it pBuf = (DCBUFFER *)mir_alloc(sizeof(DCBUFFER)); *pBuf = buf; pBuf->width = width; pBuf->height = height; pBuf->hBitmap = ske_CreateDIB32Point(width,height,&(pBuf->pImage)); pBuf->hDC = CreateCompatibleDC(hdcOwner); pBuf->oldBitmap = (HBITMAP)SelectObject(pBuf->hDC,pBuf->hBitmap); pBuf->dwDestroyAfterTime = 0; BufferList.insert(pBuf); } else { if (pBuf->width != width || pBuf->height != height) { //resize SelectObject(pBuf->hDC,pBuf->oldBitmap); DeleteObject(pBuf->hBitmap); pBuf->width = width; pBuf->height = height; pBuf->hBitmap = ske_CreateDIB32Point(width,height,&(pBuf->pImage)); pBuf->oldBitmap = (HBITMAP)SelectObject(pBuf->hDC,pBuf->hBitmap); } else if (fClear) memset(pBuf->pImage, 0, width*height*sizeof(DWORD)); } pBuf->dwDestroyAfterTime = 0; return pBuf->hDC; } int ske_ReleaseBufferDC(HDC hDC, int keepTime) { DWORD dwCurrentTime = GetTickCount(); //Try to find DC in buffer list - set flag to be release after time; mir_cslock lck(BufferListCS); for (int i=0; i < BufferList.getCount(); i++) { DCBUFFER *pBuf = BufferList[i]; if (pBuf) { if (hDC != NULL && pBuf->hDC == hDC) { pBuf->dwDestroyAfterTime = dwCurrentTime+keepTime; break; } if ((pBuf->dwDestroyAfterTime && pBuf->dwDestroyAfterTime < dwCurrentTime) || keepTime == -1) { SelectObject(pBuf->hDC,pBuf->oldBitmap); DeleteObject(pBuf->hBitmap); DeleteDC(pBuf->hDC); mir_free(pBuf); BufferList.remove(i); i--; } } } return 0; } BOOL ske_SetRgnOpaque(HDC memdc,HRGN hrgn, BOOL force) { RGNDATA * rdata; DWORD rgnsz; DWORD d; RECT *rect; if (g_CluiData.fDisableSkinEngine && !force) return TRUE; rgnsz = GetRegionData(hrgn, 0, NULL); rdata = (RGNDATA *) mir_alloc(rgnsz); GetRegionData(hrgn,rgnsz,rdata); rect = (RECT *)rdata->Buffer; for (d = 0; d < rdata->rdh.nCount; d++) { ske_SetRectOpaque(memdc,&rect[d], force); } mir_free(rdata); return TRUE; } BOOL ske_SetRectOpaque(HDC memdc,RECT *fr, BOOL force) { int f = 0; BYTE * bits; BITMAP bmp; HBITMAP hbmp; if ( g_CluiData.fDisableSkinEngine && !force ) return TRUE; hbmp = (HBITMAP)GetCurrentObject( memdc,OBJ_BITMAP ); GetObject( hbmp, sizeof(bmp), &bmp ); if ( bmp.bmPlanes != 1 ) return FALSE; if (!bmp.bmBits) { f = 1; bits = (BYTE*)malloc(bmp.bmWidthBytes*bmp.bmHeight); GetBitmapBits(hbmp,bmp.bmWidthBytes*bmp.bmHeight,bits); } else bits = (BYTE*)bmp.bmBits; int sx = ( fr->left > 0 ) ? fr->left : 0; int sy = ( fr->top > 0 ) ? fr->top : 0; int ex = ( fr->right < bmp.bmWidth ) ? fr->right : bmp.bmWidth; int ey = ( fr->bottom < bmp.bmHeight) ? fr->bottom : bmp.bmHeight; int width = ex-sx; BYTE* pLine = ((BYTE*)bits) + (bmp.bmHeight-sy-1)*bmp.bmWidthBytes + (sx << 2) + 3; for ( int y = 0; y < (ey - sy); y++ ) { BYTE * pColumn = pLine; for ( int x = 0; x < width; x++ ) { *pColumn = 255; pColumn += 4; } pLine -= bmp.bmWidthBytes; } if (f) { SetBitmapBits(hbmp,bmp.bmWidthBytes*bmp.bmHeight,bits); free(bits); } // DeleteObject(hbmp); return 1; } static BOOL ske_SkinFillRectByGlyph(HDC hDest, HDC hSource, RECT *rFill, RECT *rGlyph, RECT *rClip, BYTE mode, BYTE drawMode, int depth) { int destw = 0, desth = 0; int xstart = 0, xmax = 0; int ystart = 0, ymax = 0; BLENDFUNCTION bfa = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; //initializations if (mode == FM_STRETCH) { HDC mem2dc; HBITMAP mem2bmp, oldbmp; RECT wr; IntersectRect(&wr,rClip,rFill); if ((wr.bottom-wr.top)*(wr.right-wr.left) == 0) return 0; if (drawMode != 2) { mem2dc = CreateCompatibleDC(hDest); mem2bmp = ske_CreateDIB32(wr.right-wr.left,wr.bottom-wr.top); oldbmp = (HBITMAP)SelectObject(mem2dc,mem2bmp); } if (drawMode == 0 || drawMode == 2) { if (drawMode == 0) { ske_AlphaBlend(mem2dc,rFill->left-wr.left,rFill->top-wr.top,rFill->right-rFill->left,rFill->bottom-rFill->top, hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,rGlyph->bottom-rGlyph->top,bf); ske_AlphaBlend(hDest,wr.left,wr.top,wr.right-wr.left, wr.bottom -wr.top,mem2dc, 0, 0, wr.right-wr.left, wr.bottom -wr.top,bf); } else { ske_AlphaBlend(hDest,rFill->left,rFill->top,rFill->right-rFill->left,rFill->bottom-rFill->top, hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,rGlyph->bottom-rGlyph->top,bf); } } else { // BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 }; ske_AlphaBlend(mem2dc,rFill->left-wr.left,rFill->top-wr.top,rFill->right-rFill->left,rFill->bottom-rFill->top, hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,rGlyph->bottom-rGlyph->top,bf); ske_AlphaBlend(hDest,wr.left,wr.top,wr.right-wr.left, wr.bottom -wr.top,mem2dc, 0, 0, wr.right-wr.left, wr.bottom -wr.top,bf); } if (drawMode != 2) { SelectObject(mem2dc,oldbmp); DeleteObject(mem2bmp); DeleteDC(mem2dc); } return 1; } else if (mode == FM_TILE_VERT && (rGlyph->bottom-rGlyph->top>0) && (rGlyph->right-rGlyph->left>0)) { HDC mem2dc; HBITMAP mem2bmp,oldbmp; RECT wr; IntersectRect(&wr,rClip,rFill); if ((wr.bottom-wr.top)*(wr.right-wr.left) == 0) return 0; mem2dc = CreateCompatibleDC(hDest); //SetStretchBltMode(mem2dc, HALFTONE); mem2bmp = ske_CreateDIB32(wr.right-wr.left, rGlyph->bottom-rGlyph->top); oldbmp = (HBITMAP)SelectObject(mem2dc,mem2bmp); if (!oldbmp) return 0; /// draw here { int y = 0, sy = 0, maxy = 0; int w = rFill->right-rFill->left; int h = rGlyph->bottom-rGlyph->top; if (h>0 && (wr.bottom-wr.top)*(wr.right-wr.left) != 0) { w = wr.right-wr.left; { // BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 }; ske_AlphaBlend(mem2dc,-(wr.left-rFill->left), 0, rFill->right-rFill->left,h,hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,h,bf); //StretchBlt(mem2dc,-(wr.left-rFill->left), 0, rFill->right-rFill->left,h,hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,h,SRCCOPY); } if (drawMode == 0 || drawMode == 2) { if (drawMode == 0 ) { int dy; dy = (wr.top-rFill->top)%h; if (dy >= 0) { int ht; y = wr.top; ht = (y+h-dy <= wr.bottom)?(h-dy):(wr.bottom-wr.top); BitBlt(hDest,wr.left,y,w,ht,mem2dc, 0, dy,SRCCOPY); } y = wr.top+h-dy; while (y < wr.bottom-h){ BitBlt(hDest,wr.left,y,w,h,mem2dc, 0, 0, SRCCOPY); y += h; } if (y <= wr.bottom) BitBlt(hDest,wr.left,y,w,wr.bottom-y, mem2dc, 0, 0, SRCCOPY); } else { y = wr.top; while (y < wr.bottom-h) { // BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 }; ske_AlphaBlend(hDest,wr.left,y,w,h, mem2dc, 0, 0, w,h,bf); y += h; } if (y <= wr.bottom) { // BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 }; ske_AlphaBlend(hDest,wr.left,y,w,wr.bottom-y, mem2dc, 0, 0, w,wr.bottom-y,bf); } } } else { int dy; BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; dy = (wr.top-rFill->top)%h; if (dy >= 0) { int ht; y = wr.top; ht = (y+h-dy <= wr.bottom)?(h-dy):(wr.bottom-wr.top); ske_AlphaBlend(hDest,wr.left,y,w,ht,mem2dc, 0, dy,w,ht,bf); } y = wr.top+h-dy; while (y < wr.bottom-h) { ske_AlphaBlend(hDest,wr.left,y,w,h,mem2dc, 0, 0, w,h,bf); y += h; } if (y <= wr.bottom) ske_AlphaBlend(hDest,wr.left,y,w,wr.bottom-y, mem2dc, 0, 0, w,wr.bottom-y,bf); } } } SelectObject(mem2dc,oldbmp); DeleteObject(mem2bmp); DeleteDC(mem2dc); } else if (mode == FM_TILE_HORZ && (rGlyph->right-rGlyph->left>0) && (rGlyph->bottom-rGlyph->top>0) && (rFill->bottom-rFill->top)>0 && (rFill->right-rFill->left)>0) { HDC mem2dc; RECT wr; HBITMAP mem2bmp,oldbmp; int w = rGlyph->right-rGlyph->left; int h = rFill->bottom-rFill->top; IntersectRect(&wr,rClip,rFill); if ((wr.bottom-wr.top)*(wr.right-wr.left) == 0) return 0; h = wr.bottom-wr.top; mem2dc = CreateCompatibleDC(hDest); mem2bmp = ske_CreateDIB32(w,h); oldbmp = (HBITMAP)SelectObject(mem2dc,mem2bmp); if (!oldbmp) return 0; /// draw here { int x = 0, sy = 0, maxy = 0; { //SetStretchBltMode(mem2dc, HALFTONE); //StretchBlt(mem2dc, 0, 0, w,h,hSource,rGlyph->left+(wr.left-rFill->left),rGlyph->top,w,h,SRCCOPY); // BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 }; ske_AlphaBlend(mem2dc, 0, -(wr.top-rFill->top),w,rFill->bottom-rFill->top,hSource,rGlyph->left,rGlyph->top,w,rGlyph->bottom-rGlyph->top,bf); if (drawMode == 0 || drawMode == 2) { if (drawMode == 0) { int dx; dx = (wr.left-rFill->left)%w; if (dx >= 0) { int wt; x = wr.left; wt = (x+w-dx <= wr.right)?(w-dx):(wr.right-wr.left); BitBlt(hDest,x,wr.top,wt,h,mem2dc,dx, 0, SRCCOPY); } x = wr.left+w-dx; while (x < wr.right-w){ BitBlt(hDest,x,wr.top,w,h,mem2dc, 0, 0, SRCCOPY); x += w; } if (x <= wr.right) BitBlt(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, SRCCOPY); } else { int dx; dx = (wr.left-rFill->left)%w; x = wr.left-dx; while (x < wr.right-w){ ske_AlphaBlend(hDest,x,wr.top,w,h,mem2dc, 0, 0, w,h,bf); x += w; } if (x <= wr.right) ske_AlphaBlend(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, wr.right-x,h,bf); } } else { BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; int dx; dx = (wr.left-rFill->left)%w; if (dx >= 0) { int wt; x = wr.left; wt = (x+w-dx <= wr.right)?(w-dx):(wr.right-wr.left); ske_AlphaBlend(hDest,x,wr.top,wt,h,mem2dc,dx, 0, wt,h,bf); } x = wr.left+w-dx; while (x < wr.right-w){ ske_AlphaBlend(hDest,x,wr.top,w,h,mem2dc, 0, 0, w,h,bf); x += w; } if (x <= wr.right) ske_AlphaBlend(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, wr.right-x,h,bf); } } } SelectObject(mem2dc,oldbmp); DeleteObject(mem2bmp); DeleteDC(mem2dc); } else if (mode == FM_TILE_BOTH && (rGlyph->right-rGlyph->left>0) && (rGlyph->bottom-rGlyph->top>0)) { HDC mem2dc; int w = rGlyph->right-rGlyph->left; int x = 0, sy = 0, maxy = 0; int h = rFill->bottom-rFill->top; HBITMAP mem2bmp,oldbmp; RECT wr; IntersectRect(&wr,rClip,rFill); if ((wr.bottom-wr.top)*(wr.right-wr.left) == 0) return 0; mem2dc = CreateCompatibleDC(hDest); mem2bmp = ske_CreateDIB32(w,wr.bottom-wr.top); h = wr.bottom-wr.top; oldbmp = (HBITMAP)SelectObject(mem2dc,mem2bmp); #ifdef _DEBUG if (!oldbmp) (NULL,"Tile bitmap not selected","ERROR", MB_OK); #endif /// draw here { //fill temp bitmap { int y; int dy; dy = (wr.top-rFill->top)%(rGlyph->bottom-rGlyph->top); y = -dy; while (y < wr.bottom-wr.top) { ske_AlphaBlend(mem2dc, 0, y,w,rGlyph->bottom-rGlyph->top, hSource,rGlyph->left,rGlyph->top,w,rGlyph->bottom-rGlyph->top,bf); y += rGlyph->bottom-rGlyph->top; } //-- //end temp bitmap if (drawMode == 0 || drawMode == 2) { if (drawMode == 0) { int dx; dx = (wr.left-rFill->left)%w; if (dx >= 0) { int wt; x = wr.left; wt = (x+w-dx <= wr.right)?(w-dx):(wr.right-wr.left); BitBlt(hDest,x,wr.top,wt,h,mem2dc,dx, 0, SRCCOPY); } x = wr.left+w-dx; while (x < wr.right-w){ BitBlt(hDest,x,wr.top,w,h,mem2dc, 0, 0, SRCCOPY); x += w; } if (x <= wr.right) BitBlt(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, SRCCOPY); } else { int dx; dx = (wr.left-rFill->left)%w; x = wr.left-dx; while (x < wr.right-w){ ske_AlphaBlend(hDest,x,wr.top,w,h,mem2dc, 0, 0, w,h,bf); x += w; } if (x <= wr.right) ske_AlphaBlend(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, wr.right-x,h,bf); } } else { BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; int dx; dx = (wr.left-rFill->left)%w; if (dx >= 0) { int wt; x = wr.left; wt = (x+w-dx <= wr.right)?(w-dx):(wr.right-wr.left); ske_AlphaBlend(hDest,x,wr.top,wt,h,mem2dc,dx, 0, wt,h,bf); } x = wr.left+w-dx; while (x < wr.right-w){ ske_AlphaBlend(hDest,x,wr.top,w,h,mem2dc, 0, 0, w,h,bf); x += w; } if (x <= wr.right) ske_AlphaBlend(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, wr.right-x,h,bf); } } } SelectObject(mem2dc,oldbmp); DeleteObject(mem2bmp); DeleteDC(mem2dc); } return 1; } HBITMAP ske_CreateDIB32(int cx, int cy) { return ske_CreateDIB32Point(cx,cy,NULL); } HBITMAP ske_CreateDIB32Point(int cx, int cy, void ** bits) { if (cx < 0 || cy < 0) return NULL; BITMAPINFO RGB32BitsBITMAPINFO = { 0 }; RGB32BitsBITMAPINFO.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); RGB32BitsBITMAPINFO.bmiHeader.biWidth = cx;//bm.bmWidth; RGB32BitsBITMAPINFO.bmiHeader.biHeight = cy;//bm.bmHeight; RGB32BitsBITMAPINFO.bmiHeader.biPlanes = 1; RGB32BitsBITMAPINFO.bmiHeader.biBitCount = 32; // pointer used for direct Bitmap pixels access UINT *ptPixels; HBITMAP DirectBitmap = CreateDIBSection(NULL, (BITMAPINFO *)&RGB32BitsBITMAPINFO, DIB_RGB_COLORS, (void **)&ptPixels, NULL, 0); if ((DirectBitmap == NULL || ptPixels == NULL) && cx != 0 && cy != 0) { #ifdef _DEBUG MessageBoxA(NULL,"Object not allocated. Check GDI object count","ERROR",MB_OK|MB_ICONERROR); DebugBreak(); #endif ; } else memset(ptPixels, 0, cx*cy*4); if (bits != NULL) *bits = ptPixels; return DirectBitmap; } HRGN ske_CreateOpaqueRgn(BYTE Level, bool Opaque) { if (!g_pCachedWindow) return NULL; RGBQUAD * buf = (RGBQUAD *) g_pCachedWindow->hImageDIBByte; int x,y; unsigned int cRect = 64; PRGNDATA pRgnData = (PRGNDATA)malloc(sizeof(RGNDATAHEADER) + (cRect)*sizeof(RECT)); memset(pRgnData, 0, sizeof(RGNDATAHEADER)); pRgnData->rdh.dwSize = sizeof(RGNDATAHEADER); pRgnData->rdh.iType = RDH_RECTANGLES; for (y = 0; y < g_pCachedWindow->Height; ++y) { bool inside = false; bool lastin = false; unsigned int entry = 0; for (x = 0; x < g_pCachedWindow->Width; ++x) { inside = Opaque ? (buf->rgbReserved > Level) : (buf->rgbReserved < Level); ++buf; if (inside != lastin) { if (inside) { lastin = true; entry = x; } else { if (pRgnData->rdh.nCount == cRect) { cRect = cRect + 64; pRgnData = (PRGNDATA)realloc(pRgnData, sizeof(RGNDATAHEADER) + (cRect)*sizeof(RECT)); } SetRect(((LPRECT)pRgnData->Buffer) + pRgnData->rdh.nCount, entry, g_pCachedWindow->Height - y, x, g_pCachedWindow->Height - y + 1); pRgnData->rdh.nCount++; lastin = false; } } } if (lastin) { if (pRgnData->rdh.nCount == cRect) { cRect = cRect + 64; pRgnData = (PRGNDATA)realloc(pRgnData, sizeof(RGNDATAHEADER) + (cRect)*sizeof(RECT)); } SetRect(((LPRECT)pRgnData->Buffer) + pRgnData->rdh.nCount, entry, g_pCachedWindow->Height - y, x, g_pCachedWindow->Height - y + 1); pRgnData->rdh.nCount++; } } HRGN hRgn = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount*sizeof(RECT), (LPRGNDATA)pRgnData); free(pRgnData); return hRgn; } static int ske_DrawSkinObject(SKINDRAWREQUEST * preq, GLYPHOBJECT * pobj) { HDC memdc = NULL, glyphdc = NULL; int k = 0; //BITMAP bmp = {0}; HBITMAP membmp = 0, oldbmp = 0, oldglyph = 0; BYTE Is32Bit = 0; RECT PRect; POINT mode2offset = {0}; int depth = 0; int mode = 0; //0-FastDraw, 1-DirectAlphaDraw, 2-BufferedAlphaDraw if (!(preq && pobj)) return -1; if ((!pobj->hGlyph || pobj->hGlyph == (HBITMAP)-1) && ((pobj->Style&7) == ST_IMAGE || (pobj->Style&7) == ST_FRAGMENT || (pobj->Style&7) == ST_SOLARIZE)) return 0; // Determine painting mode depth = GetDeviceCaps(preq->hDC,BITSPIXEL); depth = depth < 16?16:depth; Is32Bit = pobj->bmBitsPixel == 32; if ((!Is32Bit && pobj->dwAlpha == 255) && pobj->Style != ST_BRUSH) mode = 0; else if (pobj->dwAlpha == 255 && pobj->Style != ST_BRUSH) mode = 1; else mode = 2; // End painting mode //force mode if (preq->rcClipRect.bottom-preq->rcClipRect.top*preq->rcClipRect.right-preq->rcClipRect.left == 0) preq->rcClipRect = preq->rcDestRect; IntersectRect(&PRect,&preq->rcDestRect,&preq->rcClipRect); if (IsRectEmpty(&PRect)) { return 0; } if (mode == 2) { memdc = CreateCompatibleDC(preq->hDC); membmp = ske_CreateDIB32(PRect.right-PRect.left,PRect.bottom-PRect.top); oldbmp = (HBITMAP)SelectObject(memdc,membmp); if (oldbmp == NULL) { if (mode == 2) { SelectObject(memdc,oldbmp); DeleteDC(memdc); DeleteObject(membmp); } return 0; } } if (mode != 2) memdc = preq->hDC; { if (pobj->hGlyph && pobj->hGlyph != (HBITMAP)-1) { glyphdc = CreateCompatibleDC(preq->hDC); if (!oldglyph) oldglyph = (HBITMAP)SelectObject(glyphdc,pobj->hGlyph); else SelectObject(glyphdc,pobj->hGlyph); } // Drawing { RECT rFill, rGlyph, rClip; if ((pobj->Style&7) == ST_BRUSH) { HBRUSH br = CreateSolidBrush(pobj->dwColor); RECT fr; if (mode == 2) { SetRect(&fr, 0, 0, PRect.right-PRect.left,PRect.bottom-PRect.top); FillRect(memdc,&fr,br); ske_SetRectOpaque(memdc,&fr); // FillRectAlpha(memdc,&fr,pobj->dwColor|0xFF000000); } else { fr = PRect; // SetRect(&fr, 0, 0, PRect.right-PRect.left,PRect.bottom-PRect.top); FillRect(preq->hDC,&fr,br); } DeleteObject(br); k = -1; } else { if (mode == 2) { mode2offset.x = PRect.left; mode2offset.y = PRect.top; OffsetRect(&PRect,-mode2offset.x,-mode2offset.y); } rClip = (preq->rcClipRect); { int lft = 0; int top = 0; int rgh = pobj->bmWidth; int btm = pobj->bmHeight; if ((pobj->Style&7) == ST_FRAGMENT) { lft = pobj->clipArea.x; top = pobj->clipArea.y; rgh = min(rgh,lft+pobj->szclipArea.cx); btm = min(btm,top+pobj->szclipArea.cy); } // Draw center... if (1) { rFill.top = preq->rcDestRect.top+pobj->dwTop; rFill.bottom = preq->rcDestRect.bottom-pobj->dwBottom; rFill.left = preq->rcDestRect.left+pobj->dwLeft; rFill.right = preq->rcDestRect.right-pobj->dwRight; if (mode == 2) OffsetRect(&rFill,-mode2offset.x,-mode2offset.y); rGlyph.top = top+pobj->dwTop; rGlyph.left = lft+pobj->dwLeft; rGlyph.right = rgh-pobj->dwRight; rGlyph.bottom = btm-pobj->dwBottom; k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode,mode,depth); } // Draw top side... if (1) { rFill.top = preq->rcDestRect.top; rFill.bottom = preq->rcDestRect.top+pobj->dwTop; rFill.left = preq->rcDestRect.left+pobj->dwLeft; rFill.right = preq->rcDestRect.right-pobj->dwRight; if (mode == 2) OffsetRect(&rFill,-mode2offset.x,-mode2offset.y); rGlyph.top = top+0; rGlyph.left = lft+pobj->dwLeft; rGlyph.right = rgh-pobj->dwRight; rGlyph.bottom = top+pobj->dwTop; k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode&FM_TILE_HORZ,mode,depth); } // Draw bottom side... if (1) { rFill.top = preq->rcDestRect.bottom-pobj->dwBottom; rFill.bottom = preq->rcDestRect.bottom; rFill.left = preq->rcDestRect.left+pobj->dwLeft; rFill.right = preq->rcDestRect.right-pobj->dwRight; if (mode == 2) OffsetRect(&rFill,-mode2offset.x,-mode2offset.y); rGlyph.top = btm-pobj->dwBottom; rGlyph.left = lft+pobj->dwLeft; rGlyph.right = rgh-pobj->dwRight; rGlyph.bottom = btm; k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode&FM_TILE_HORZ,mode,depth); } // Draw left side... if (1) { rFill.top = preq->rcDestRect.top+pobj->dwTop; rFill.bottom = preq->rcDestRect.bottom-pobj->dwBottom; rFill.left = preq->rcDestRect.left; rFill.right = preq->rcDestRect.left+pobj->dwLeft; if (mode == 2) OffsetRect(&rFill,-mode2offset.x,-mode2offset.y); rGlyph.top = top+pobj->dwTop; rGlyph.left = lft; rGlyph.right = lft+pobj->dwLeft; rGlyph.bottom = btm-pobj->dwBottom; k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode&FM_TILE_VERT,mode,depth); } // Draw right side... if (1) { rFill.top = preq->rcDestRect.top+pobj->dwTop; rFill.bottom = preq->rcDestRect.bottom-pobj->dwBottom; rFill.left = preq->rcDestRect.right-pobj->dwRight; rFill.right = preq->rcDestRect.right; if (mode == 2) OffsetRect(&rFill,-mode2offset.x,-mode2offset.y); rGlyph.top = top+pobj->dwTop; rGlyph.left = rgh-pobj->dwRight; rGlyph.right = rgh; rGlyph.bottom = btm-pobj->dwBottom; k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode&FM_TILE_VERT,mode,depth); } // Draw Top-Left corner... if (1) { rFill.top = preq->rcDestRect.top; rFill.bottom = preq->rcDestRect.top+pobj->dwTop; rFill.left = preq->rcDestRect.left; rFill.right = preq->rcDestRect.left+pobj->dwLeft; if (mode == 2) OffsetRect(&rFill,-mode2offset.x,-mode2offset.y); rGlyph.top = top; rGlyph.left = lft; rGlyph.right = lft+pobj->dwLeft; rGlyph.bottom = top+pobj->dwTop; k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect, 0, mode,depth); } // Draw Top-Right corner... if (1) { rFill.top = preq->rcDestRect.top; rFill.bottom = preq->rcDestRect.top+pobj->dwTop; rFill.left = preq->rcDestRect.right-pobj->dwRight; rFill.right = preq->rcDestRect.right; if (mode == 2) OffsetRect(&rFill,-mode2offset.x,-mode2offset.y); rGlyph.top = top; rGlyph.left = rgh-pobj->dwRight; rGlyph.right = rgh; rGlyph.bottom = top+pobj->dwTop; k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect, 0, mode,depth); } // Draw Bottom-Left corner... if (1) { rFill.top = preq->rcDestRect.bottom-pobj->dwBottom; rFill.bottom = preq->rcDestRect.bottom; rFill.left = preq->rcDestRect.left; rFill.right = preq->rcDestRect.left+pobj->dwLeft; if (mode == 2) OffsetRect(&rFill,-mode2offset.x,-mode2offset.y); rGlyph.left = lft; rGlyph.right = lft+pobj->dwLeft; rGlyph.top = btm-pobj->dwBottom; rGlyph.bottom = btm; k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect, 0, mode,depth); } // Draw Bottom-Right corner... if (1) { rFill.top = preq->rcDestRect.bottom-pobj->dwBottom; rFill.bottom = preq->rcDestRect.bottom; rFill.left = preq->rcDestRect.right-pobj->dwRight; rFill.right = preq->rcDestRect.right; if (mode == 2) OffsetRect(&rFill,-mode2offset.x,-mode2offset.y); rGlyph.left = rgh-pobj->dwRight; rGlyph.right = rgh; rGlyph.top = btm-pobj->dwBottom; rGlyph.bottom = btm; k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect, 0, mode,depth); } } } if ((k>0 || k == -1) && mode == 2) { { BLENDFUNCTION bf = {AC_SRC_OVER, 0, /*(bm.bmBitsPixel == 32)?255:*/pobj->dwAlpha, (pobj->bmBitsPixel == 32 && pobj->Style != ST_BRUSH)?AC_SRC_ALPHA:0}; if (mode == 2) OffsetRect(&PRect,mode2offset.x,mode2offset.y); ske_AlphaBlend( preq->hDC,PRect.left,PRect.top,PRect.right-PRect.left,PRect.bottom-PRect.top, memdc, 0, 0, PRect.right-PRect.left,PRect.bottom-PRect.top,bf); } } } //free GDI resources //--++-- //free GDI resources { if (oldglyph) SelectObject(glyphdc,oldglyph); if (glyphdc) DeleteDC(glyphdc); } if (mode == 2) { SelectObject(memdc,oldbmp); DeleteDC(memdc); DeleteObject(membmp); } } if (pobj->plTextList && pobj->plTextList->realCount>0) { int i; HFONT hOldFont; for (i=0; i < pobj->plTextList->realCount; i++) { GLYPHTEXT * gt = (GLYPHTEXT *)pobj->plTextList->items[i]; if (!gt->hFont) { if (gl_plSkinFonts && gl_plSkinFonts->realCount>0) { int j = 0; for (j = 0; j < gl_plSkinFonts->realCount; j++) { SKINFONT * sf; sf = (SKINFONT*)gl_plSkinFonts->items[j]; if (sf->szFontID && !strcmp(sf->szFontID,gt->szFontID)) { gt->hFont = sf->hFont; break; } } } if (!gt->hFont) gt->hFont = (HFONT)-1; } if (gt->hFont != (HFONT)-1) { RECT rc = {0}; hOldFont = (HFONT)SelectObject(preq->hDC,gt->hFont); if (gt->RelativeFlags&2) rc.left = preq->rcDestRect.right+gt->iLeft; else if (gt->RelativeFlags&1) rc.left = ((preq->rcDestRect.right-preq->rcDestRect.left)>>1)+gt->iLeft; else rc.left = preq->rcDestRect.left+gt->iLeft; if (gt->RelativeFlags&8) rc.top = preq->rcDestRect.bottom+gt->iTop; else if (gt->RelativeFlags&4) rc.top = ((preq->rcDestRect.bottom-preq->rcDestRect.top)>>1)+gt->iTop; else rc.top = preq->rcDestRect.top+gt->iTop; if (gt->RelativeFlags&32) rc.right = preq->rcDestRect.right+gt->iRight; else if (gt->RelativeFlags&16) rc.right = ((preq->rcDestRect.right-preq->rcDestRect.left)>>1)+gt->iRight; else rc.right = preq->rcDestRect.left+gt->iRight; if (gt->RelativeFlags&128) rc.bottom = preq->rcDestRect.bottom+gt->iBottom; else if (gt->RelativeFlags&64) rc.bottom = ((preq->rcDestRect.bottom-preq->rcDestRect.top)>>1)+gt->iBottom; else rc.bottom = preq->rcDestRect.top+gt->iBottom; ske_AlphaTextOut(preq->hDC, gt->stText, -1, &rc,gt->dwFlags, gt->dwColor); SelectObject(preq->hDC,hOldFont); } } } return 0; } int ske_AddDescriptorToSkinObjectList (LPSKINOBJECTDESCRIPTOR lpDescr, SKINOBJECTSLIST* Skin) { SKINOBJECTSLIST *sk; if (Skin) sk = Skin; else sk = &g_SkinObjectList; if (!sk) return 0; if (mir_bool_strcmpi(lpDescr->szObjectID,"_HEADER_")) return 0; {//check if new object allready presents. DWORD i=0; for (i=0; i < sk->dwObjLPAlocated; i++) if (!mir_strcmp(sk->pObjects[i].szObjectID,lpDescr->szObjectID)) return 0; } if (sk->dwObjLPAlocated+1>sk->dwObjLPReserved) { // Realocated list to add space for new object sk->pObjects = (SKINOBJECTDESCRIPTOR*)mir_realloc(sk->pObjects,sizeof(SKINOBJECTDESCRIPTOR)*(sk->dwObjLPReserved+1)/*alloc step*/); sk->dwObjLPReserved++; } { //filling new objects field sk->pObjects[sk->dwObjLPAlocated].bType = lpDescr->bType; sk->pObjects[sk->dwObjLPAlocated].Data = NULL; sk->pObjects[sk->dwObjLPAlocated].szObjectID = mir_strdup(lpDescr->szObjectID); // sk->Objects[sk->dwObjLPAlocated].szObjectName = mir_strdup(lpDescr->szObjectName); if (lpDescr->Data != NULL) { //Copy defaults values switch (lpDescr->bType) { case OT_GLYPHOBJECT: { GLYPHOBJECT * obdat; GLYPHOBJECT * gl = (GLYPHOBJECT*)lpDescr->Data; sk->pObjects[sk->dwObjLPAlocated].Data = mir_alloc(sizeof(GLYPHOBJECT)); obdat = (GLYPHOBJECT*)sk->pObjects[sk->dwObjLPAlocated].Data; memcpy(obdat,gl,sizeof(GLYPHOBJECT)); if (gl->szFileName != NULL) { obdat->szFileName = mir_strdup(gl->szFileName); mir_free_and_nil(gl->szFileName); } else obdat->szFileName = NULL; obdat->hGlyph = NULL; break; } } } } sk->dwObjLPAlocated++; return 1; } static LPSKINOBJECTDESCRIPTOR ske_FindObject(const char * szName, BYTE objType, SKINOBJECTSLIST* Skin) { // DWORD i; SKINOBJECTSLIST* sk; sk = (Skin == NULL)?(&g_SkinObjectList):Skin; return skin_FindObjectByRequest((char *)szName,sk->pMaskList); } static LPSKINOBJECTDESCRIPTOR ske_FindObjectByMask(MODERNMASK *pModernMask, BYTE objType, SKINOBJECTSLIST* Skin) { // DWORD i; SKINOBJECTSLIST* sk; sk = (Skin == NULL)?(&g_SkinObjectList):Skin; if (!sk->pMaskList) return NULL; return skin_FindObjectByMask(pModernMask,sk->pMaskList); } LPSKINOBJECTDESCRIPTOR ske_FindObjectByName(const char * szName, BYTE objType, SKINOBJECTSLIST* Skin) { DWORD i; SKINOBJECTSLIST* sk; sk = (Skin == NULL)?(&g_SkinObjectList):Skin; for (i=0; i < sk->dwObjLPAlocated; i++) { if (sk->pObjects[i].bType == objType || objType == OT_ANY) { if (!mir_strcmp(sk->pObjects[i].szObjectID,szName)) return &(sk->pObjects[i]); } } return NULL; } ////////////////////////////////////////////////////////////////////////// // Paint glyph // wParam - LPSKINDRAWREQUEST // lParam - possible direct pointer to modern mask ////////////////////////////////////////////////////////////////////////// INT_PTR ske_Service_DrawGlyph(WPARAM wParam,LPARAM lParam) { LPSKINDRAWREQUEST preq; LPSKINOBJECTDESCRIPTOR pgl; LPGLYPHOBJECT gl; if (!wParam) return -1; ske_LockSkin(); __try { preq = (LPSKINDRAWREQUEST)wParam; if (lParam) pgl = ske_FindObjectByMask((MODERNMASK*)lParam, OT_GLYPHOBJECT,NULL); else pgl = ske_FindObject(preq->szObjectID, OT_GLYPHOBJECT,NULL); if (pgl == NULL) return -1; if (pgl->Data == NULL) return -1; gl = (LPGLYPHOBJECT)pgl->Data; int iStyle = gl->Style & 7; if (iStyle == ST_SKIP) return ST_SKIP; if (gl->hGlyph == NULL && gl->hGlyph != (HBITMAP)-1 && (iStyle == ST_IMAGE || iStyle == ST_FRAGMENT || iStyle == ST_SOLARIZE)) if (gl->szFileName) { gl->hGlyph = ske_LoadGlyphImage( _A2T(gl->szFileName)); if (gl->hGlyph) { BITMAP bmp = {0}; GetObject(gl->hGlyph,sizeof(BITMAP),&bmp); gl->bmBitsPixel = (BYTE)bmp.bmBitsPixel; gl->bmHeight = bmp.bmHeight; gl->bmWidth = bmp.bmWidth; } else gl->hGlyph = (HBITMAP)-1; //invalid } return ske_DrawSkinObject(preq,gl); } __finally { ske_UnlockSkin(); } return -1; } void ske_PreMultiplyChanells(HBITMAP hbmp,BYTE Mult) { BITMAP bmp; BOOL flag = FALSE; BYTE * pBitmapBits; DWORD Len; int bh,bw,y,x; GetObject(hbmp, sizeof(BITMAP), (LPSTR)&bmp); bh = bmp.bmHeight; bw = bmp.bmWidth; Len = bh*bw*4; flag = (bmp.bmBits == NULL); if (flag) { pBitmapBits = (LPBYTE)malloc(Len); GetBitmapBits(hbmp,Len,pBitmapBits); } else pBitmapBits = (BYTE*)bmp.bmBits; for (y = 0; y < bh; ++y) { BYTE *pPixel = pBitmapBits + bw * 4 * y; for (x = 0; x < bw ; ++x) { if (Mult) { pPixel[0] = pPixel[0]*pPixel[3]/255; pPixel[1] = pPixel[1]*pPixel[3]/255; pPixel[2] = pPixel[2]*pPixel[3]/255; } else { pPixel[3] = 255; } pPixel += 4; } } if (flag) { Len = SetBitmapBits(hbmp,Len,pBitmapBits); free (pBitmapBits); } return; } int ske_GetFullFilename(TCHAR *buf, const TCHAR *file, TCHAR *skinfolder, BOOL madeAbsolute) { TCHAR *SkinPlace = db_get_tsa(NULL,SKIN,"SkinFolder"); if (SkinPlace == NULL) SkinPlace = mir_tstrdup( _T("\\Skin\\default")); TCHAR b2[MAX_PATH]; if (file[0] != '\\' && file[1] != ':') mir_sntprintf(b2, MAX_PATH, _T("%s\\%s"), (skinfolder == NULL) ? SkinPlace : ((INT_PTR)skinfolder != -1) ? skinfolder : _T(""), file); else _tcsncpy(b2, file, SIZEOF(b2)); if (madeAbsolute) { if (b2[0] == '\\' && b2[1] != '\\') PathToAbsoluteT(b2+1, buf); else PathToAbsoluteT(b2, buf); } else _tcsncpy(buf, b2, MAX_PATH); mir_free(SkinPlace); return 0; } /* This function is required to load TGA to dib buffer myself Major part of routines is from http://tfcduke.developpez.com/tutoriel/format/tga/fichiers/tga.c */ static BOOL ske_ReadTGAImageData(void * From, DWORD fromSize, BYTE * destBuf, DWORD bufSize, BOOL RLE) { BYTE * pos = destBuf; BYTE * from = fromSize?(BYTE*)From:NULL; FILE * fp = !fromSize?(FILE*)From:NULL; DWORD destCount = 0; DWORD fromCount = 0; if (!RLE) { while (((from && fromCount < fromSize) || (fp && fromCount < bufSize)) && (destCount < bufSize)) { BYTE r = from?from[fromCount++]:(BYTE)fgetc(fp); BYTE g = from?from[fromCount++]:(BYTE)fgetc(fp); BYTE b = from?from[fromCount++]:(BYTE)fgetc(fp); BYTE a = from?from[fromCount++]:(BYTE)fgetc(fp); pos[destCount++] = r; pos[destCount++] = g; pos[destCount++] = b; pos[destCount++] = a; if (destCount>bufSize) break; if (from) if (fromCount < fromSize) break; } } else { BYTE rgba[4]; BYTE packet_header; BYTE *ptr = pos; BYTE size; int i; while (ptr < pos + bufSize) { /* read first byte */ packet_header = from?from[fromCount]:(BYTE)fgetc(fp); if (from) from++; size = 1 + (packet_header & 0x7f); if (packet_header & 0x80) { /* run-length packet */ if (from) { *((DWORD*)rgba) = *((DWORD*)(from+fromCount)); fromCount += 4; } else fread (rgba, sizeof (BYTE), 4, fp); for (i=0; i < size; ++i, ptr += 4) { ptr[2] = rgba[2]; ptr[1] = rgba[1]; ptr[0] = rgba[0]; ptr[3] = rgba[3]; } } else { /* not run-length packet */ for (i=0; i < size; ++i, ptr += 4) { ptr[0] = from? from[fromCount++]:(BYTE)fgetc (fp); ptr[1] = from? from[fromCount++]:(BYTE)fgetc (fp); ptr[2] = from? from[fromCount++]:(BYTE)fgetc (fp); ptr[3] = from? from[fromCount++]:(BYTE)fgetc (fp); } } } } return TRUE; } static HBITMAP ske_LoadGlyphImage_TGA(const TCHAR *szFilename) { BYTE *colormap = NULL; int cx = 0, cy = 0; BOOL err = FALSE; tga_header_t header; if (!szFilename) return NULL; if (!wildcmpit(szFilename, _T("*\\*%.tga"))) { //Loading TGA image from file FILE *fp = _tfopen (szFilename, _T("rb")); if (!fp) { TRACEVAR("error: couldn't open \"%s\"!\n", szFilename); return NULL; } /* read header */ fread (&header, sizeof (tga_header_t), 1, fp); if ((header.pixel_depth != 32) || ((header.image_type != 10) && (header.image_type != 2))) { fclose(fp); return NULL; } /*memory allocation */ colormap = (BYTE*)malloc(header.width*header.height*4); cx = header.width; cy = header.height; fseek (fp, header.id_lenght, SEEK_CUR); fseek (fp, header.cm_length, SEEK_CUR); err = !ske_ReadTGAImageData((void*)fp, 0, colormap, header.width*header.height*4,header.image_type == 10); fclose(fp); } else { /* reading from resources IDR_TGA_DEFAULT_SKIN */ DWORD size = 0; BYTE * mem; HGLOBAL hRes; HRSRC hRSrc = FindResourceA(g_hInst,MAKEINTRESOURCEA(IDR_TGA_DEFAULT_SKIN),"TGA"); if (!hRSrc) return NULL; hRes = LoadResource(g_hInst,hRSrc); if (!hRes) return NULL; size = SizeofResource(g_hInst,hRSrc); mem = (BYTE*) LockResource(hRes); if (size>sizeof(header)) { tga_header_t * header = (tga_header_t *)mem; if (header->pixel_depth == 32 && (header->image_type == 2 || header->image_type == 10)) { colormap = (BYTE*)malloc(header->width*header->height*4); cx = header->width; cy = header->height; ske_ReadTGAImageData((void*)(mem+sizeof(tga_header_t)+header->id_lenght+header->cm_length), size-(sizeof(tga_header_t)+header->id_lenght+header->cm_length), colormap, cx*cy*4,header->image_type == 10); } } FreeResource(hRes); } if (colormap) { //create dib section BYTE * pt; HBITMAP hbmp = ske_CreateDIB32Point(cx,cy,(void**)&pt); if (hbmp) memcpy(pt,colormap,cx*cy*4); free(colormap); return hbmp; } return NULL; } //this function is required to load PNG to dib buffer myself static HBITMAP ske_LoadGlyphImage_Png2Dib(const TCHAR *tszFilename) { HANDLE hFile, hMap = NULL; BYTE* ppMap = NULL; long cbFileSize = 0; BITMAPINFOHEADER* pDib; BYTE* pDibBits; if (!ServiceExists( MS_PNG2DIB )) { MessageBox( NULL, TranslateT("You need an image services plugin to process PNG images."), TranslateT("Error"), MB_OK ); return (HBITMAP)NULL; } if ((hFile = CreateFile(tszFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) if ((hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL )) != NULL) if ((ppMap = ( BYTE* )MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0 )) != NULL) cbFileSize = GetFileSize(hFile, NULL); if (cbFileSize != 0) { PNG2DIB param; param.pSource = ppMap; param.cbSourceSize = cbFileSize; param.pResult = &pDib; if ( CallService(MS_PNG2DIB, 0, (LPARAM)¶m )) pDibBits = ( BYTE* )( pDib+1 ); else cbFileSize = 0; } if ( ppMap != NULL ) UnmapViewOfFile( ppMap ); if ( hMap != NULL ) CloseHandle( hMap ); if ( hFile != NULL ) CloseHandle( hFile ); if ( cbFileSize == 0 ) return (HBITMAP)NULL; HBITMAP hBitmap; BITMAPINFO* bi = ( BITMAPINFO* )pDib; BYTE *pt = (BYTE*)bi; pt += bi->bmiHeader.biSize; if (bi->bmiHeader.biBitCount != 32) { HDC sDC = GetDC( NULL ); hBitmap = CreateDIBitmap( sDC, pDib, CBM_INIT, pDibBits, bi, DIB_PAL_COLORS ); SelectObject( sDC, hBitmap ); DeleteDC( sDC ); } else { BYTE *ptPixels = pt; hBitmap = CreateDIBSection(NULL,bi, DIB_RGB_COLORS, (void **)&ptPixels, NULL, 0); memcpy(ptPixels,pt,bi->bmiHeader.biSizeImage); } GlobalFree( pDib ); return hBitmap; } static HBITMAP ske_LoadGlyphImageByDecoders(const TCHAR *tszFileName) { // Loading image from file by imgdecoder... HBITMAP hBitmap = NULL; TCHAR ext[5]; BYTE f = 0; LPVOID pImg = NULL; BITMAP bmpInfo; { int l = lstrlen(tszFileName); lstrcpyn(ext, tszFileName+(l-4),5); } if (!_tcschr(tszFileName,'%') && !PathFileExists(tszFileName)) return NULL; if (mir_bool_tstrcmpi(ext, _T(".tga"))) { hBitmap = ske_LoadGlyphImage_TGA(tszFileName); f = 1; } else if ( ServiceExists("Image/Png2Dib") && mir_bool_tstrcmpi(ext, _T(".png"))) { hBitmap = ske_LoadGlyphImage_Png2Dib(tszFileName); GetObject(hBitmap, sizeof(BITMAP), &bmpInfo); f = (bmpInfo.bmBits != NULL); } else if (!mir_bool_tstrcmpi(ext, _T(".png"))) { hBitmap = (HBITMAP)CallService(MS_UTILS_LOADBITMAPT, 0, (LPARAM)tszFileName); } if (hBitmap) { GetObject(hBitmap, sizeof(BITMAP), &bmpInfo); if (bmpInfo.bmBitsPixel == 32) ske_PreMultiplyChanells(hBitmap,f); else { HDC dc24,dc32; HBITMAP hBitmap32,obmp24,obmp32; dc32 = CreateCompatibleDC(NULL); dc24 = CreateCompatibleDC(NULL); hBitmap32 = ske_CreateDIB32(bmpInfo.bmWidth,bmpInfo.bmHeight); obmp24 = (HBITMAP)SelectObject(dc24,hBitmap); obmp32 = (HBITMAP)SelectObject(dc32,hBitmap32); BitBlt(dc32, 0, 0, bmpInfo.bmWidth,bmpInfo.bmHeight,dc24, 0, 0, SRCCOPY); SelectObject(dc24,obmp24); SelectObject(dc32,obmp32); DeleteDC(dc24); DeleteDC(dc32); DeleteObject(hBitmap); hBitmap = hBitmap32; ske_PreMultiplyChanells(hBitmap,0); } } return hBitmap; } static HBITMAP ske_skinLoadGlyphImage(const TCHAR *tszFileName) { if (!wildcmpit(tszFileName, _T("*.tga"))) return GDIPlus_LoadGlyphImage(tszFileName); return ske_LoadGlyphImageByDecoders(tszFileName); } HBITMAP ske_LoadGlyphImage(const TCHAR *tszFileName) { // try to find image in loaded DWORD i; HBITMAP hbmp; TCHAR szFile [MAX_PATH] = {0}; ske_GetFullFilename(szFile, tszFileName, g_SkinObjectList.szSkinPlace, TRUE); ske_LockSkin(); if (pLoadedImages) { for (i=0; i < dwLoadedImagesCount; i++) { if (mir_bool_tstrcmpi(pLoadedImages[i].szFileName, szFile)) { pLoadedImages[i].dwLoadedTimes++; ske_UnlockSkin(); return pLoadedImages[i].hGlyph; } } } // load new image hbmp = ske_skinLoadGlyphImage(szFile); if (hbmp == NULL) { ske_UnlockSkin(); return NULL; } // add to loaded list if (dwLoadedImagesCount+1>dwLoadedImagesAlocated) { pLoadedImages = (GLYPHIMAGE*)mir_realloc(pLoadedImages,sizeof(GLYPHIMAGE)*(dwLoadedImagesCount+1)); if (pLoadedImages) dwLoadedImagesAlocated++; else { ske_UnlockSkin(); return NULL; } } pLoadedImages[dwLoadedImagesCount].dwLoadedTimes = 1; pLoadedImages[dwLoadedImagesCount].hGlyph = hbmp; pLoadedImages[dwLoadedImagesCount].szFileName = mir_tstrdup(szFile); dwLoadedImagesCount++; ske_UnlockSkin(); return hbmp; } int ske_UnloadGlyphImage(HBITMAP hbmp) { DWORD i; for (i=0; i < dwLoadedImagesCount; i++) { if (hbmp == pLoadedImages[i].hGlyph) { pLoadedImages[i].dwLoadedTimes--; if (pLoadedImages[i].dwLoadedTimes == 0) { LPGLYPHIMAGE gl = &(pLoadedImages[i]); mir_free_and_nil(gl->szFileName); memmove(&(pLoadedImages[i]),&(pLoadedImages[i+1]),sizeof(GLYPHIMAGE)*(dwLoadedImagesCount-i-1)); dwLoadedImagesCount--; DeleteObject(hbmp); if (pLoadedImages && dwLoadedImagesCount == 0) { dwLoadedImagesAlocated = 0; mir_free_and_nil(pLoadedImages); } } return 0; } } DeleteObject(hbmp); return 0; } int ske_UnloadSkin(SKINOBJECTSLIST * Skin) { DWORD i; ske_LockSkin(); ClearMaskList(Skin->pMaskList); //clear font list if (gl_plSkinFonts && gl_plSkinFonts->realCount > 0) { for (int i=0; i < gl_plSkinFonts->realCount; i++) { SKINFONT * sf = (SKINFONT *)gl_plSkinFonts->items[i]; if (sf) { mir_free(sf->szFontID); DeleteObject(sf->hFont); mir_free(sf); } } List_Destroy(gl_plSkinFonts); mir_free_and_nil(gl_plSkinFonts); } mir_free_and_nil(Skin->szSkinPlace); if (Skin->pTextList) List_Destroy(Skin->pTextList); mir_free_and_nil(Skin->pTextList); ModernSkinButtonDeleteAll(); if (Skin->dwObjLPAlocated == 0) { ske_UnlockSkin(); return 0;} for (i=0; i < Skin->dwObjLPAlocated; i++) { switch(Skin->pObjects[i].bType) { case OT_GLYPHOBJECT: { GLYPHOBJECT * dt; dt = (GLYPHOBJECT*)Skin->pObjects[i].Data; if (dt->hGlyph && dt->hGlyph != (HBITMAP)-1) ske_UnloadGlyphImage(dt->hGlyph); dt->hGlyph = NULL; mir_free_and_nil(dt->szFileName); {// delete texts int i; if (dt->plTextList && dt->plTextList->realCount>0) { for (i=0; i < dt->plTextList->realCount; i++) { GLYPHTEXT * gt = (GLYPHTEXT *)dt->plTextList->items[i]; if (gt) { mir_free(gt->stText); mir_free(gt->stValueText); mir_free(gt->szFontID); mir_free(gt->szGlyphTextID); mir_free(gt); } } List_Destroy(dt->plTextList); mir_free(dt->plTextList); } } mir_free(dt); } break; } mir_free_and_nil(Skin->pObjects[i].szObjectID); } mir_free_and_nil(Skin->pObjects); Skin->pTextList = NULL; Skin->dwObjLPAlocated = 0; Skin->dwObjLPReserved = 0; ske_UnlockSkin(); return 0; } static void RegisterMaskByParce(const char * szSetting, char * szValue, SKINOBJECTSLIST * pSkin) { int i; DWORD ID=atoi(szSetting+1); for (i=0; i < mir_strlen(szValue); i++) if (szValue[i] == ':') break; if (i < mir_strlen(szValue)) { char * Obj, *Mask; int res; Mask = szValue+i+1; Obj = (char*)mir_alloc(i+1); strncpy(Obj,szValue,i); Obj[i] = '\0'; res = AddStrModernMaskToList(ID,Mask,Obj,pSkin->pMaskList,pSkin); mir_free(Obj); } } static int ske_ProcessLoadindString(const char * szSetting, char *szValue) { if (!pCurrentSkin) return 0; if (szSetting[0] == '$') RegisterObjectByParce((char *)szSetting, szValue); else if (szSetting[0] == '#') RegisterButtonByParce((char *)szSetting,szValue); else if (szSetting[0] == '@') RegisterMaskByParce((char *)szSetting, szValue, pCurrentSkin); /// else if (szSetting[0] == 't') ske_AddParseTextGlyphObject((char*)szSetting,szValue,pCurrentSkin); else if (szSetting[0] == 'f') ske_AddParseSkinFont((char*)szSetting,szValue,pCurrentSkin); else return 0; return 1; } static int ske_enumdb_SkinObjectsProc (const char *szSetting,LPARAM lParam) { char *value; value = db_get_sa(NULL,SKIN,szSetting); ske_ProcessLoadindString(szSetting,value); mir_free_and_nil(value); return 0; } static int ske_SortTextGlyphObjectFunc(void * first, void * second) { return strcmp(((GLYPHTEXT*)(((int*)first)[0]))->szGlyphTextID,((GLYPHTEXT*)(((int*)second)[0]))->szGlyphTextID); } static void ske_LinkSkinObjects(SKINOBJECTSLIST * pObjectList) { DWORD i; // LINK Mask with objects for (i=0; i < pObjectList->pMaskList->dwMaskCnt; i++) { MODERNMASK *mm = &(pObjectList->pMaskList->pl_Masks[i]); void * pObject = (void*) ske_FindObjectByName(mm->szObjectName, OT_ANY, (SKINOBJECTSLIST*) pObjectList); mir_free_and_nil(mm->szObjectName); mm->bObjectFound = TRUE; mm->pObject = pObject; } if (pObjectList->pTextList) { int i; // LINK Text with objects for (i=0; i < pObjectList->pTextList->realCount; i++) { GLYPHTEXT * glText; GLYPHOBJECT *globj = NULL; SKINOBJECTDESCRIPTOR * lpobj; glText = (GLYPHTEXT *)pObjectList->pTextList->items[i]; lpobj = ske_FindObjectByName(glText->szObjectName,OT_GLYPHOBJECT, pObjectList); mir_free_and_nil(glText->szObjectName); if (lpobj) globj = (GLYPHOBJECT*)lpobj->Data; if (globj) { if (!globj->plTextList) { globj->plTextList = List_Create(0, 1); globj->plTextList->sortFunc = ske_SortTextGlyphObjectFunc; } List_Insert(globj->plTextList,(void*)glText,globj->plTextList->realCount); qsort(globj->plTextList->items,globj->plTextList->realCount,sizeof(void*),(int(*)(const void*, const void*))globj->plTextList->sortFunc); pObjectList->pTextList->items[i] = NULL; } else { GLYPHTEXT *gt = glText; if (gt) { mir_free(gt->stText); mir_free(gt->stValueText); mir_free(gt->szFontID); mir_free(gt->szGlyphTextID); mir_free(gt); } } } List_Destroy(pObjectList->pTextList); mir_free_and_nil(pObjectList->pTextList); } } // Getting skin objects and masks from DB static int ske_GetSkinFromDB(char * szSection, SKINOBJECTSLIST * Skin) { if (Skin == NULL) return 0; ske_UnloadSkin(Skin); g_CluiData.fDisableSkinEngine = db_get_b(NULL,"ModernData","DisableEngine", SETTING_DISABLESKIN_DEFAULT); //window borders if (g_CluiData.fDisableSkinEngine) { g_CluiData.LeftClientMargin = 0; g_CluiData.RightClientMargin = 0; g_CluiData.TopClientMargin = 0; g_CluiData.BottomClientMargin = 0; } else { //window borders g_CluiData.LeftClientMargin = (int)db_get_b(NULL,"CLUI","LeftClientMargin",SETTING_LEFTCLIENTMARIGN_DEFAULT); g_CluiData.RightClientMargin = (int)db_get_b(NULL,"CLUI","RightClientMargin",SETTING_RIGHTCLIENTMARIGN_DEFAULT); g_CluiData.TopClientMargin = (int)db_get_b(NULL,"CLUI","TopClientMargin",SETTING_TOPCLIENTMARIGN_DEFAULT); g_CluiData.BottomClientMargin = (int)db_get_b(NULL,"CLUI","BottomClientMargin",SETTING_BOTTOMCLIENTMARIGN_DEFAULT); } if (g_CluiData.fDisableSkinEngine) return 0; Skin->pMaskList = (LISTMODERNMASK*)mir_alloc(sizeof(LISTMODERNMASK)); memset(Skin->pMaskList, 0, sizeof(LISTMODERNMASK)); Skin->szSkinPlace = db_get_tsa(NULL, SKIN, "SkinFolder"); if (!Skin->szSkinPlace || (_tcschr(Skin->szSkinPlace, '%') && !db_get_b(NULL,SKIN,"Modified",0))) { BOOL bOnlyObjects = FALSE; if (Skin->szSkinPlace && _tcschr(Skin->szSkinPlace, '%')) bOnlyObjects = TRUE; mir_free(Skin->szSkinPlace); Skin->szSkinPlace = mir_tstrdup( _T("%Default%")); ske_LoadSkinFromResource( bOnlyObjects ); } //Load objects { DBCONTACTENUMSETTINGS dbces; pCurrentSkin = Skin; dbces.pfnEnumProc = ske_enumdb_SkinObjectsProc; dbces.szModule = SKIN; dbces.ofsSettings = 0; CallService(MS_DB_CONTACT_ENUMSETTINGS, 0, (LPARAM)&dbces); SortMaskList(pCurrentSkin->pMaskList); ske_LinkSkinObjects(pCurrentSkin); } //Load Masks return 0; } //surrogate to be called from outside void ske_LoadSkinFromDB(void) { ske_GetSkinFromDB(SKIN,&g_SkinObjectList); g_CluiData.dwKeyColor = db_get_dw(NULL,"ModernSettings","KeyColor",(DWORD)SETTING_KEYCOLOR_DEFAULT); } // static int ske_LoadSkinFromResource(BOOL bOnlyObjects) { IniParser parser(g_hInst, MAKEINTRESOURCEA(IDR_MSF_DEFAULT_SKIN), "MSF", bOnlyObjects ? IniParser::FLAG_ONLY_OBJECTS : IniParser::FLAG_WITH_SETTINGS); if (parser.CheckOK()) { ske_DeleteAllSettingInSection("ModernSkin"); db_set_s(NULL, SKIN, "SkinFolder", "%Default%"); db_set_s(NULL, SKIN, "SkinFile", "%Default%"); parser.Parse(IniParser::WriteStrToDb, 0); } return 0; } //Load data from ini file int ske_LoadSkinFromIniFile(TCHAR *szFileName, BOOL bOnlyObjects) { if (_tcschr(szFileName,_T('%'))) return ske_LoadSkinFromResource( bOnlyObjects ); IniParser parser(szFileName, bOnlyObjects ? IniParser::FLAG_ONLY_OBJECTS : IniParser::FLAG_WITH_SETTINGS); if (!parser.CheckOK()) return 0; ske_DeleteAllSettingInSection("ModernSkin"); TCHAR skinFolder[MAX_PATH], skinFile[MAX_PATH]; IniParser::GetSkinFolder(szFileName, skinFolder); PathToRelativeT(szFileName, skinFile); db_set_ts(NULL,SKIN,"SkinFolder", skinFolder); db_set_ts(NULL,SKIN,"SkinFile", skinFile); parser.Parse(IniParser::WriteStrToDb, 1); return 0; } static int ske_enumdb_SkinSectionDeletionProc (const char *szSetting,LPARAM lParam) { if (szSetting == NULL) return 0; nArrayLen++; pszSettingName = (char **)realloc(pszSettingName, nArrayLen*sizeof(char *)); pszSettingName[nArrayLen-1] = _strdup(szSetting); return 0; } static int ske_DeleteAllSettingInSection(char * SectionName) { DBCONTACTENUMSETTINGS dbces; nArrayLen = 0; pszSettingName = NULL; dbces.pfnEnumProc = ske_enumdb_SkinSectionDeletionProc; dbces.szModule = SectionName; dbces.ofsSettings = 0; CallService(MS_DB_CONTACT_ENUMSETTINGS, 0, (LPARAM)&dbces); //delete all settings if (nArrayLen == 0) return 0; for (int i=0; i < nArrayLen; i++) { db_unset(0, SectionName,pszSettingName[i]); free(pszSettingName[i]); } free(pszSettingName); pszSettingName = NULL; nArrayLen = 0; return 0; } BOOL ske_TextOut(HDC hdc, int x, int y, LPCTSTR lpString, int nCount) { SIZE sz; GetTextExtentPoint32(hdc, lpString, nCount, &sz); int ta = GetTextAlign(hdc); RECT rc = { 0 }; SetRect(&rc, x, y, x + sz.cx, y + sz.cy); ske_DrawText(hdc, lpString, nCount, &rc, DT_NOCLIP | DT_SINGLELINE | DT_LEFT); return 1; } static INT_PTR ske_Service_AlphaTextOut(WPARAM wParam,LPARAM lParam) { if (!wParam) return 0; AlphaTextOutParams ap = *(AlphaTextOutParams*)wParam; return ske_AlphaTextOut(ap.hDC,ap.lpString,ap.nCount,ap.lpRect,ap.format,ap.ARGBcolor); } static __inline void ske_SetMatrix( sbyte * matrix, sbyte a, sbyte b, sbyte c, sbyte d, sbyte e, sbyte f, sbyte g, sbyte h, sbyte i) { matrix[0] = a; matrix[1] = b; matrix[2] = c; matrix[3] = d; matrix[4] = e; matrix[5] = f; matrix[6] = g; matrix[7] = h; matrix[8] = i; } static void ske_SetTextEffect(BYTE EffectID, DWORD FirstColor, DWORD SecondColor) { if (EffectID > MAXPREDEFINEDEFFECTS) return; if (EffectID == -1) meCurrentEffect.EffectID = -1; else { meCurrentEffect.EffectID = EffectID; meCurrentEffect.EffectMatrix = ModernEffectsEnum[EffectID]; meCurrentEffect.EffectColor1 = FirstColor; meCurrentEffect.EffectColor2 = SecondColor; } } bool ske_ResetTextEffect(HDC hdc) { int idx = arEffectStack.getIndex((EFFECTSSTACKITEM*)&hdc); if (idx == -1) return false; mir_free(arEffectStack[idx]); arEffectStack.remove(idx); return true; } bool ske_SelectTextEffect(HDC hdc, BYTE EffectID, DWORD FirstColor, DWORD SecondColor) { if (EffectID > MAXPREDEFINEDEFFECTS) return false; if (EffectID == -1) return ske_ResetTextEffect(hdc); EFFECTSSTACKITEM *effect = arEffectStack.find((EFFECTSSTACKITEM*)&hdc); if (effect == NULL) { effect = (EFFECTSSTACKITEM *)mir_alloc(sizeof(EFFECTSSTACKITEM)); effect->hdc = hdc; arEffectStack.insert(effect); } effect->EffectID = EffectID; effect->FirstColor = FirstColor; effect->SecondColor = SecondColor; return true; } static bool ske_GetTextEffect(HDC hdc, MODERNEFFECT *modernEffect) { if (!modernEffect) return false; EFFECTSSTACKITEM *effect = arEffectStack.find((EFFECTSSTACKITEM*)&hdc); if (effect == NULL) return false; modernEffect->EffectID = effect->EffectID; modernEffect->EffectColor1 = effect->FirstColor; modernEffect->EffectColor2 = effect->SecondColor; modernEffect->EffectMatrix = ModernEffectsEnum[effect->EffectID]; return true; } static bool ske_DrawTextEffect(BYTE* destPt, BYTE* maskPt, DWORD width, DWORD height, MODERNEFFECT *effect) { sbyte *buf; sbyte *outbuf; sbyte *bufline, *buflineTop, *buflineMid; int sign = 0; BYTE *maskline,*destline; BYTE al,rl,gl,bl,ad,rd,gd,bd; int k = 0; DWORD x,y; sbyte *matrix; BYTE mcTopStart; BYTE mcBottomEnd; BYTE mcLeftStart; BYTE mcRightEnd; BYTE effectCount; int minX = width; int maxX = 0; int minY = height; int maxY = 0; if (effect->EffectID == 0xFF) return false; if (!width || !height) return false; if (!destPt) return false; buf = (sbyte*)malloc(width*height*sizeof(BYTE)); { matrix = effect->EffectMatrix.matrix; mcTopStart = 2-effect->EffectMatrix.topEffect; mcBottomEnd = 3+effect->EffectMatrix.bottomEffect; mcLeftStart = 2-effect->EffectMatrix.leftEffect; mcRightEnd = 3+effect->EffectMatrix.rightEffect; effectCount = effect->EffectMatrix.cycleCount; } al = 255-((BYTE)(effect->EffectColor1>>24)); rl = GetRValue(effect->EffectColor1); gl = GetGValue(effect->EffectColor1); bl = GetBValue(effect->EffectColor1); ad = 255-((BYTE)(effect->EffectColor2>>24)); rd = GetRValue(effect->EffectColor2); gd = GetGValue(effect->EffectColor2); bd = GetBValue(effect->EffectColor2); //Fill buffer by mid values of image for (y = 0; y < height; y++) { bufline = buf+y*width; maskline = maskPt+((y*width) << 2); for (x = 0; x < width; x++) { BYTE a = (sbyte)(DWORD)((maskline[0]+maskline[2]+maskline[1]+maskline[1])>>4); *bufline = a; if (a != 0) { minX = min((int)x,minX); minY = min((int)y,minY); maxX = max((int)x,maxX); maxY = max((int)y,maxY); } bufline++; maskline += 4; } } //Here perform effect on buffer and place results to outbuf for (k = 0; k < (effectCount&0x7F); k++) { minX = max( 0, minX + mcLeftStart - 2 ); minY = max( 0, minY + mcTopStart - 2 ); maxX = min((int)width, maxX + mcRightEnd - 1 ); maxY = min((int)height, maxY + mcBottomEnd - 1 ); outbuf = (sbyte*)malloc(width*height*sizeof(sbyte)); memset(outbuf, 0, width*height*sizeof(sbyte)); for (y = (DWORD)minY; y < (DWORD)maxY; y++) { int val; bufline = outbuf+y*width+minX; buflineMid = buf+y*width+minX; for (x = (DWORD)minX; x < (DWORD)maxX; x++) { int matrixHor,matrixVer; val = 0; for (matrixVer = mcTopStart; matrixVer < mcBottomEnd; matrixVer++) { int buflineStep = width*(matrixVer-2); int as = y+matrixVer-2; sbyte * buflineTopS = NULL; if (as >= 0 && (DWORD)as < height) buflineTopS = buflineMid+buflineStep; for (matrixHor = mcLeftStart; matrixHor < mcRightEnd;matrixHor++) { buflineTop = buflineTopS; int a = x+matrixHor-2; if (buflineTop && a >= 0 && (DWORD)a < width) buflineTop += matrixHor-2; else buflineTop = NULL; if (buflineTop) val += ((*buflineTop)*matrix[matrixVer*5+matrixHor]); } } val = (val+1)>>5; *bufline = (sbyte)((val>127)?127:(val < -125)?-125:val); bufline++; buflineMid++; } } free(buf); buf = outbuf; } { BYTE r1,b1,g1,a1; b1 = bl; r1 = rl; g1 = gl; a1 = al; sign = 1; //perform out to dest for (y = 0; y < height; y++) { bufline = buf+y*width; destline = destPt+((y*width) << 2); for (x = 0; x < width; x++) { sbyte val = *bufline; BYTE absVal = ((val < 0)?-val:val); if (val != 0) { if (val>0 && sign < 0) { b1 = bl; r1 = rl; g1 = gl; a1 = al; sign = 1;} else if (val < 0 && sign>0) { b1 = bd; r1 = rd; g1 = gd; a1 = ad; sign = -1;} absVal = absVal*a1/255; destline[0] = ((destline[0]*(128-absVal))+absVal*b1)>>7; destline[1] = ((destline[1]*(128-absVal))+absVal*g1)>>7; destline[2] = ((destline[2]*(128-absVal))+absVal*r1)>>7; destline[3] += ((255-destline[3])*(a1*absVal))/32640; } bufline++; destline += 4; } } free(buf); } return false; } static int ske_AlphaTextOut (HDC hDC, LPCTSTR lpString, int nCount, RECT *lpRect, UINT format, DWORD ARGBcolor) { if (!(lpString && lpRect)) return 0; // Step first fill fast calc correction tables: static bool _tables_empty = true; static BYTE gammaTbl[256]; // Gamma correction table static WORD blueMulTbl[256]; // blue coefficient multiplication table static WORD greenMulTbl[256]; // green coefficient multiplication table static WORD redMulTbl[256]; // red coefficient multiplication table if ( _tables_empty ) { // fill tables double gammaCfPw = 1000 / (double)DBGetContactSettingRangedWord(NULL,"ModernData","AlphaTextOutGamma", 700, 1, 5000 ); BYTE blueCf = db_get_b(NULL,"ModernData","AlphaTextOutBlueCorrection", 28 ); BYTE redCf = db_get_b(NULL,"ModernData","AlphaTextOutRed Correction", 77 ); BYTE greenCf = db_get_b(NULL,"ModernData","AlphaTextOutGreen Correction", 151 ); for ( int i=0; i < 256; i++ ) { gammaTbl[i] = (BYTE)( 255 * pow((double)i / 255, gammaCfPw )); blueMulTbl[i] = i * blueCf; redMulTbl[i] = i * redCf; greenMulTbl[i] = i * greenCf; } } // Calc len of input string if (nCount == -1) nCount = lstrlen(lpString); // retrieve destination bitmap bits HBITMAP hDestBitmap = (HBITMAP)GetCurrentObject(hDC, OBJ_BITMAP); BITMAP bmpDest; GetObject(hDestBitmap, sizeof(BITMAP), &bmpDest); BOOL destHasNotDIB = FALSE; BYTE *pDestBits = NULL; if (bmpDest.bmBits == NULL) { destHasNotDIB = TRUE; pDestBits = (BYTE*) malloc ( bmpDest.bmHeight * bmpDest.bmWidthBytes ); GetBitmapBits( hDestBitmap, bmpDest.bmHeight*bmpDest.bmWidthBytes, pDestBits ); } else pDestBits = (BYTE*)bmpDest.bmBits; BOOL isDest16bit = (bmpDest.bmBitsPixel) != 32; // Creating offscreen buffer HDC hOffscreenDC = CreateCompatibleDC(hDC); // Font to be used to draw text HFONT hFont = (HFONT)GetCurrentObject(hDC, OBJ_FONT); HFONT hOldOffscreenFont = (HFONT)SelectObject(hOffscreenDC, hFont); // Calculating text geometric size RECT workRect = *lpRect; int workRectWidth = workRect.right - workRect.left; int workRectHeight = workRect.bottom - workRect.top; if (workRectWidth <= 0 || workRectHeight <= 0) return 0; SIZE textSize; GetTextExtentPoint32( hOffscreenDC, lpString, nCount, &textSize ); LPCTSTR lpWorkString = lpString; BOOL bNeedFreeWorkString = FALSE; // if we need to cut the text with ellipsis if ((format & DT_END_ELLIPSIS) && textSize.cx > workRectWidth) { // Calc geometric width of ellipsis SIZE szEllipsis; GetTextExtentPoint32A(hOffscreenDC,"...",3,&szEllipsis); szEllipsis.cx++; // CORRECTION: some width correction // Calc count of visible chars int visibleCharCount = nCount; if (workRectWidth > szEllipsis.cx) GetTextExtentExPoint(hOffscreenDC, lpString, nCount, workRectWidth - szEllipsis.cx, &visibleCharCount, NULL, &textSize); else GetTextExtentExPoint(hOffscreenDC, lpString, nCount, 0, &visibleCharCount, NULL, &textSize); // replace end of string by elipsis bNeedFreeWorkString = TRUE; lpWorkString = (TCHAR*) malloc(( visibleCharCount + 4) * sizeof(TCHAR)); memcpy((void*) lpWorkString, lpString, visibleCharCount * sizeof(TCHAR)); memcpy((void*) ( lpWorkString + visibleCharCount ), _T("..."), 4 * sizeof(TCHAR)); // 3 + 1 nCount = visibleCharCount + 3; } // Calc sizes and offsets textSize.cx += 2; // CORRECTION: for italic int drx = 0; // x-axis offset of draw point if (workRectWidth > textSize.cx) { if ( format & ( DT_RIGHT | DT_RTLREADING )) drx = workRectWidth - textSize.cx; else if ( format & DT_CENTER ) drx = ( workRectWidth - textSize.cx ) >> 1; } else textSize.cx = workRectWidth; int dry = 0; // y-axis offset of draw point if (workRectHeight > textSize.cy) { if (format & DT_BOTTOM) dry = workRectHeight - textSize.cy; else if (format & DT_VCENTER) dry = (workRectHeight - textSize.cy) >> 1; } else textSize.cy = workRectHeight; textSize.cx += 4; // CORRECTION: for effects ??? textSize.cy += 4; // CORRECTION: for effects ??? if (textSize.cx > 0 && textSize.cy > 0) { // Ok we need to paint // probably here are mess ofscreen and temp buff dc //Create bitmap image for offscreen BYTE *bits = NULL; HBITMAP hbmp = ske_CreateDIB32Point(textSize.cx, textSize.cy, (void**)&bits); if (bits != NULL) { HBITMAP holdbmp = (HBITMAP)SelectObject( hOffscreenDC, hbmp ); //Create buffer bitmap image for temp text BYTE *bufbits = NULL; HBITMAP bufbmp = ske_CreateDIB32Point(textSize.cx, textSize.cy, (void**)&bufbits); if ( bufbits != NULL ) { HDC bufDC = CreateCompatibleDC(hDC); HBITMAP bufoldbmp = (HBITMAP)SelectObject(bufDC, bufbmp); HFONT hOldBufFont = (HFONT)SelectObject(bufDC, hFont); SetBkColor(bufDC, RGB(0, 0, 0)); SetTextColor(bufDC, RGB(255, 255, 255)); // Copy from destination to temp buffer BitBlt(hOffscreenDC, 0, 0, textSize.cx, textSize.cy, hDC, workRect.left + drx - 2, workRect.top + dry - 2, SRCCOPY); //Draw text on offscreen bitmap TextOut(bufDC, 2, 2, lpWorkString, nCount); MODERNEFFECT effect; if (ske_GetTextEffect(hDC, &effect)) ske_DrawTextEffect(bits, bufbits, textSize.cx, textSize.cy, &effect); // RenderText RECT drawRect; drawRect.left = 0; drawRect.top = 0; drawRect.right = textSize.cx; drawRect.bottom = textSize.cy; DWORD width = textSize.cx; DWORD heigh = textSize.cy; BYTE *pDestScanLine; BYTE *pBufScanLine; BYTE *pix; BYTE *bufpix; BYTE al = 255 - ((BYTE)( ARGBcolor >> 24 )); BYTE r = GetRValue( ARGBcolor ); BYTE g = GetGValue( ARGBcolor ); BYTE b = GetBValue( ARGBcolor ); for (DWORD y = 2; y < heigh - 2; y++) { int lineBytes = y * (width << 2); pDestScanLine = bits + lineBytes; pBufScanLine = bufbits + lineBytes; for (DWORD x = 2; x < width - 2; x++) { pix = pDestScanLine + ( x << 2 ); bufpix = pBufScanLine + ( x << 2 ); // Monochromatic BYTE bx = gammaTbl[ bufpix[0] ]; BYTE gx = gammaTbl[ bufpix[1] ]; BYTE rx = gammaTbl[ bufpix[2] ]; if ( al != 255 ) { bx *= al/255; gx *= al/255; rx *= al/255; } BYTE ax = (BYTE)(( (DWORD)rx*77 + (DWORD)gx * 151 + (DWORD)bx *28 + 128 ) / 256 ); if (ax) { //Normalize components to gray BYTE axx = 255 - (( r + g + b ) >> 2 ) ; // Coefficient of grayance, more white font - more gray edges WORD atx = ax * (255 - axx); bx = ( atx + bx * axx )/255; gx = ( atx + gx * axx )/255; rx = ( atx + rx * axx )/255; short brx = (short)((b - pix[0])*bx / 255); short grx = (short)((g - pix[1])*gx / 255); short rrx = (short)((r - pix[2])*rx / 255); pix[0] += brx; pix[1] += grx; pix[2] += rrx; pix[3] = (BYTE)(ax+(BYTE)(255-ax)*pix[3]/255); } } } // Blit to destination BitBlt(hDC, workRect.left + drx - 2, workRect.top + dry - 2, textSize.cx, textSize.cy, hOffscreenDC, 0, 0, SRCCOPY); //free resources SelectObject(bufDC, bufoldbmp); DeleteObject(bufbmp); SelectObject(bufDC, hOldBufFont); DeleteDC(bufDC); } SelectObject(hOffscreenDC, holdbmp); DeleteObject(hbmp); } } // Final cleanup SelectObject(hOffscreenDC, hOldOffscreenFont); DeleteDC(hOffscreenDC); if (destHasNotDIB) free(pDestBits); if (bNeedFreeWorkString) free((void*)lpWorkString); return 0; } static int ske_DrawTextWithEffectWorker( HDC hdc, LPCTSTR lpString, int nCount, RECT *lpRect, UINT format, MODERNFONTEFFECT * effect ) { if (format & DT_CALCRECT) return DrawText(hdc, lpString, nCount, lpRect, format); if (format & DT_RTLREADING) SetTextAlign(hdc, TA_RTLREADING); DWORD color = GetTextColor(hdc); RECT r = *lpRect; OffsetRect(&r, 1, 1); DWORD form = format; if (effect && effect->effectIndex) ske_SelectTextEffect(hdc, effect->effectIndex - 1, effect->baseColour, effect->secondaryColour); int res = ske_AlphaTextOut(hdc, lpString, nCount, lpRect, form, color); if (effect && effect->effectIndex) ske_ResetTextEffect(hdc); return res; } INT_PTR ske_Service_DrawTextWithEffect(WPARAM wParam, LPARAM lParam) { DrawTextWithEffectParam *p = (DrawTextWithEffectParam *)wParam; if (p->cbSize != sizeof(DrawTextWithEffectParam)) return FALSE; return ske_DrawTextWithEffectWorker(p->hdc, p->lpchText, p->cchText, p->lprc, p->dwDTFormat, p->pEffect); } BOOL ske_DrawText(HDC hdc, LPCTSTR lpString, int nCount, RECT *lpRect, UINT format) { DWORD form = 0, color = 0; RECT r = *lpRect; OffsetRect(&r, 1, 1); if (format & DT_RTLREADING) SetTextAlign(hdc, TA_RTLREADING); if (format & DT_CALCRECT) return DrawText(hdc, lpString, nCount, lpRect, format); if (format & DT_FORCENATIVERENDER || g_CluiData.fDisableSkinEngine) return DrawText(hdc, lpString, nCount, lpRect, format&~DT_FORCENATIVERENDER); form = format; color = GetTextColor(hdc); return ske_AlphaTextOut(hdc, lpString, nCount, lpRect, form, color); } HICON ske_ImageList_GetIcon(HIMAGELIST himl, int i, UINT fStyle) { IMAGEINFO imi = {0}; BITMAP bm = {0}; if (i != -1) { ImageList_GetImageInfo(himl,i,&imi); GetObject(imi.hbmImage,sizeof(bm),&bm); if (bm.bmBitsPixel == 32) //stupid bug of Microsoft // Icons bitmaps are not premultiplied // So Imagelist_AddIcon - premultiply alpha // But incorrect - it is possible that alpha will // be less than color and // ImageList_GetIcon will return overflowed colors // TODO: Direct draw Icon from imagelist without // extracting of icon { BYTE *bits = (BYTE*)bm.bmBits; if (!bits) { bits = (BYTE*)malloc(bm.bmWidthBytes*bm.bmHeight); GetBitmapBits(imi.hbmImage,bm.bmWidthBytes*bm.bmHeight,bits); } int wb = ((imi.rcImage.right - imi.rcImage.left)*bm.bmBitsPixel >> 3); BYTE *bcbits = bits + (bm.bmHeight - imi.rcImage.bottom)*bm.bmWidthBytes + (imi.rcImage.left*bm.bmBitsPixel >> 3); for (int iy = 0; iy < imi.rcImage.bottom - imi.rcImage.top; iy++) { int x; // Dummy microsoft fix - alpha can be less than r,g or b // Looks like color channels in icons should be non-premultiplied with alpha // But AddIcon store it premultiplied (incorrectly cause can be Alpha == 7F, but R,G or B == 80 // So i check that alpha is 0x7F and set it to 0x80 DWORD *c = ((DWORD*)bcbits); for (x = 0; x < imi.rcImage.right - imi.rcImage.left; x++) { DWORD val = *c; BYTE a = (BYTE)((val) >> 24); if (a != 0) { BYTE r = (BYTE)((val & 0xFF0000) >> 16); BYTE g = (BYTE)((val & 0xFF00) >> 8); BYTE b = (BYTE)(val & 0xFF); if (a < r || a < g || a < b) { a = max(max(r, g), b); val = a << 24 | r << 16 | g << 8 | b; *c = val; } } c++; } bcbits += bm.bmWidthBytes; } if (!bm.bmBits) { SetBitmapBits(imi.hbmImage, bm.bmWidthBytes*bm.bmHeight, bits); free(bits); } } } return ImageList_GetIcon(himl,i,ILD_NORMAL); } //////////////////////////////////////////////////////////////////////////// // This creates new dib image from Imagelist icon ready to alphablend it HBITMAP ske_ExtractDIBFromImagelistIcon( HIMAGELIST himl,int index, int * outWidth, int * outHeight) { return NULL; } BOOL ske_ImageList_DrawEx( HIMAGELIST himl,int i,HDC hdcDst,int x,int y,int dx,int dy,COLORREF rgbBk,COLORREF rgbFg,UINT fStyle) { //the routine to directly draw icon from image list without creating icon from there - should be some faster if (i < 0) return FALSE; if (g_CluiData.fDisableSkinEngine) return ImageList_DrawEx(himl, i, hdcDst, x, y, dx, dy, rgbBk, rgbFg, fStyle); BYTE alpha; if (fStyle&ILD_BLEND25) alpha = 64; else if (fStyle&ILD_BLEND50) alpha = 128; else alpha = 255; HICON hIcon = ske_ImageList_GetIcon(himl, i, ILD_NORMAL); if (hIcon == NULL) return FALSE; ske_DrawIconEx(hdcDst, x, y, hIcon, dx ? dx : GetSystemMetrics(SM_CXSMICON), dy ? dy : GetSystemMetrics(SM_CYSMICON), 0, NULL, DI_NORMAL | (alpha << 24)); DestroyIcon(hIcon); return TRUE; } static INT_PTR ske_Service_DrawIconEx(WPARAM wParam,LPARAM lParam) { DrawIconFixParam *p = (DrawIconFixParam*)wParam; if (!p) return 0; return ske_DrawIconEx(p->hdc,p->xLeft,p->yTop,p->hIcon,p->cxWidth,p->cyWidth,p->istepIfAniCur,p->hbrFlickerFreeDraw,p->diFlags); } BOOL ske_DrawIconEx(HDC hdcDst,int xLeft,int yTop,HICON hIcon,int cxWidth,int cyWidth, UINT istepIfAniCur, HBRUSH hbrFlickerFreeDraw, UINT diFlags) { ICONINFO ici; BYTE alpha = (BYTE)((diFlags&0xFF000000)>>24); HDC imDC; HBITMAP oldBmp, imBmp,tBmp; BITMAP imbt,immaskbt; BYTE * imbits; BYTE * imimagbits; BYTE * immaskbits; DWORD cx,cy,icy; BYTE *t1, *t2, *t3; BOOL NoDIBImage = FALSE; //lockimagelist BYTE hasmask = FALSE; BYTE no32bit = FALSE; BYTE noMirrorMask = FALSE; BYTE hasalpha = FALSE; alpha = alpha?alpha:255; if ( g_CluiData.fDisableSkinEngine && !(diFlags&0x80)) return DrawIconEx(hdcDst,xLeft,yTop,hIcon,cxWidth,cyWidth,istepIfAniCur,hbrFlickerFreeDraw,diFlags&0xFFFF7F); if (!GetIconInfo(hIcon, &ici)) return 0; GetObject(ici.hbmColor,sizeof(BITMAP),&imbt); if (imbt.bmWidth*imbt.bmHeight == 0) { DeleteObject(ici.hbmColor); DeleteObject(ici.hbmMask); return 0; } GetObject(ici.hbmMask,sizeof(BITMAP),&immaskbt); cy = imbt.bmHeight; if (imbt.bmBitsPixel != 32) { HBITMAP otBmp; no32bit = TRUE; HDC tempDC1 = CreateCompatibleDC(hdcDst); tBmp = ske_CreateDIB32(imbt.bmWidth, imbt.bmHeight); if (tBmp) { GetObject(tBmp, sizeof(BITMAP), &imbt); otBmp = (HBITMAP)SelectObject(tempDC1, tBmp); DrawIconEx(tempDC1, 0, 0, hIcon, imbt.bmWidth, imbt.bmHeight, istepIfAniCur, hbrFlickerFreeDraw, DI_IMAGE); noMirrorMask = TRUE; } SelectObject(tempDC1, otBmp); DeleteDC(tempDC1); } if (imbt.bmBits == NULL) { NoDIBImage = TRUE; imimagbits = (BYTE*)malloc(cy*imbt.bmWidthBytes); GetBitmapBits(ici.hbmColor, cy*imbt.bmWidthBytes, (void*)imimagbits); } else imimagbits = (BYTE*)imbt.bmBits; if (immaskbt.bmBits == NULL) { immaskbits = (BYTE*)malloc(cy*immaskbt.bmWidthBytes); GetBitmapBits(ici.hbmMask, cy*immaskbt.bmWidthBytes, (void*)immaskbits); } else immaskbits = (BYTE*)immaskbt.bmBits; icy = imbt.bmHeight; cx = imbt.bmWidth; imDC = CreateCompatibleDC(hdcDst); imBmp = ske_CreateDIB32Point(cx, icy, (void**)&imbits); oldBmp = (HBITMAP)SelectObject(imDC, imBmp); if (imbits != NULL && imimagbits != NULL && immaskbits != NULL) { int x; int y; int bottom, right, top, h; int mwb, mwb2; mwb = immaskbt.bmWidthBytes; mwb2 = imbt.bmWidthBytes; bottom = icy; right = cx; top = 0; h = icy; for (y = top; (y < bottom) && !hasmask; y++) { t1 = immaskbits + y*mwb; for (x = 0; (x < mwb) && !hasmask; x++) hasmask |= (*(t1 + x) != 0); } for (y = top; (y < bottom) && !hasalpha; y++) { t1 = imimagbits + (cy - y - 1)*mwb2; for (x = 0; (x < right) && !hasalpha; x++) hasalpha |= (*(t1+(x << 2)+3) != 0); } for (y = 0; y < (int)icy; y++) { t1 = imimagbits+(h-y-1-top)*mwb2; t2 = imbits+(!no32bit?y:(icy-y-1))*mwb2; t3 = immaskbits+(noMirrorMask?y:(h-y-1-top))*mwb; for (x = 0; x < right; x++) { BYTE mask = 0; BYTE a = 0; DWORD *src = (DWORD*)(t1 + (x << 2)); DWORD *dest = (DWORD*)(t2 + (x << 2)); if (hasalpha && !hasmask) a = ((BYTE*)src)[3]; else { mask = ((1 << (7 - x % 8))&(*(t3 + (x >> 3)))) != 0; if (mask) { if (!hasalpha) { *dest = 0; continue; } if (((BYTE*)src)[3]>0 ) a = ((BYTE*)src)[3]; else a = 0; } else if (hasalpha || hasmask) a = (((BYTE*)src)[3]>0?((BYTE*)src)[3]:255); else if (!hasalpha && !hasmask) a = 255; else { *dest = 0; continue; } } if (a > 0) { ((BYTE*)dest)[3] = a; ((BYTE*)dest)[0] = ((BYTE*)src)[0] * a / 255; ((BYTE*)dest)[1] = ((BYTE*)src)[1] * a / 255; ((BYTE*)dest)[2] = ((BYTE*)src)[2] * a / 255; } else *dest = 0; } } } BLENDFUNCTION bf = { AC_SRC_OVER, diFlags & 128, alpha, AC_SRC_ALPHA }; ske_AlphaBlend(hdcDst, xLeft, yTop, cxWidth, cyWidth, imDC, 0, 0, cx, icy, bf); if (immaskbt.bmBits == NULL) free(immaskbits); if (imbt.bmBits == NULL) free(imimagbits); SelectObject(imDC, oldBmp); DeleteObject(imBmp); if (no32bit)DeleteObject(tBmp); DeleteObject(ici.hbmColor); DeleteObject(ici.hbmMask); SelectObject(imDC, GetStockObject(DEFAULT_GUI_FONT)); DeleteDC(imDC); return 1; } int ske_PrepareImageButDontUpdateIt(RECT *r) { if (!g_CluiData.fLayered) return ske_ReCreateBackImage(FALSE, r); mutex_bLockUpdate = 1; ske_DrawNonFramedObjects(TRUE, r); ske_ValidateFrameImageProc(r); mutex_bLockUpdate = 0; return 0; } int ske_RedrawCompleteWindow() { if (g_CluiData.fLayered) { ske_DrawNonFramedObjects(TRUE,0); CallService(MS_SKINENG_INVALIDATEFRAMEIMAGE, 0, 0); } else RedrawWindow(pcli->hwndContactList,NULL,NULL,RDW_ALLCHILDREN|RDW_ERASE|RDW_INVALIDATE|RDW_FRAME); return 0; } // Request to repaint frame or change/drop callback data // wParam = hWnd of called frame // lParam = pointer to sPaintRequest (or NULL to redraw all) // return 2 - already queued, data updated, 1-have been queued, 0 - failure static INT_PTR ske_Service_UpdateFrameImage(WPARAM wParam, LPARAM lParam) // Immideately recall paint routines for frame and refresh image { if ( MirandaLoading()) return 0; RECT wnd; FRAMEWND *frm; BOOL NoCancelPost = 0; BOOL IsAnyQueued = 0; if (!g_CluiData.mutexOnEdgeSizing) GetWindowRect(pcli->hwndContactList,&wnd); else wnd = g_rcEdgeSizingRect; if (!g_CluiData.fLayered) { RedrawWindow((HWND)wParam,NULL,NULL,RDW_UPDATENOW|RDW_ERASE|RDW_INVALIDATE|RDW_FRAME); return 0; } if (g_pCachedWindow == NULL) ske_ValidateFrameImageProc(&wnd); else if (g_pCachedWindow->Width != wnd.right-wnd.left || g_pCachedWindow->Height != wnd.bottom-wnd.top) ske_ValidateFrameImageProc(&wnd); else if (wParam == 0) ske_ValidateFrameImageProc(&wnd); else { // all Ok Update Single Frame // TO BE LOCKED OR PROXIED frm = FindFrameByItsHWND((HWND)wParam); if (!frm) ske_ValidateFrameImageProc(&wnd); // Validate frame, update window image and remove it from queue else { if (frm->UpdateRgn) { DeleteObject(frm->UpdateRgn); frm->UpdateRgn = 0; } ske_ValidateSingleFrameImage(frm, 0); ske_UpdateWindowImage(); NoCancelPost = 1; //-- Remove frame from queue if (flag_bUpdateQueued) { frm->bQueued = 0; for (int i = 0; i < g_nFramesCount; i++) if (IsAnyQueued |= g_pfwFrames[i].bQueued) break; } } } if ((!NoCancelPost || !IsAnyQueued) && flag_bUpdateQueued) { // no any queued updating cancel post or need to cancel post flag_bUpdateQueued = 0; g_flag_bPostWasCanceled = 1; } return 1; } static INT_PTR ske_Service_InvalidateFrameImage(WPARAM wParam, LPARAM lParam) // Post request for updating { if (MirandaLoading()) return 0; if (wParam) { FRAMEWND *frm = FindFrameByItsHWND((HWND)wParam); sPaintRequest *pr = (sPaintRequest*)lParam; if (!g_CluiData.fLayered || (frm && frm->floating)) return InvalidateRect((HWND)wParam, pr ? (RECT*)&(pr->rcUpdate) : NULL, FALSE); if (frm) { if (frm->PaintCallbackProc != NULL) { frm->PaintData = (sPaintRequest *)pr; frm->bQueued = 1; if (pr) { HRGN r2; if (!IsRectEmpty(&pr->rcUpdate)) { RECT rcClient; RECT rcUpdate; GetClientRect(frm->hWnd, &rcClient); IntersectRect(&rcUpdate, &rcClient, &pr->rcUpdate); if (IsRectEmpty(&rcUpdate)) return 0; r2 = CreateRectRgn(rcUpdate.left, rcUpdate.top, rcUpdate.right, rcUpdate.bottom); } else { RECT r; GetClientRect(frm->hWnd, &r); r2 = CreateRectRgn(r.left, r.top, r.right, r.bottom); } if (!frm->UpdateRgn) { frm->UpdateRgn = CreateRectRgn(0, 0, 1, 1); CombineRgn(frm->UpdateRgn, r2, 0, RGN_COPY); } else CombineRgn(frm->UpdateRgn, frm->UpdateRgn, r2, RGN_OR); DeleteObject(r2); } } } else Sync(QueueAllFramesUpdating, 1); } else Sync(QueueAllFramesUpdating, 1); if (!flag_bUpdateQueued || g_flag_bPostWasCanceled) if (PostMessage(pcli->hwndContactList, UM_UPDATE, 0, 0)) { flag_bUpdateQueued = 1; g_flag_bPostWasCanceled = 0; } return 1; } static int ske_ValidateSingleFrameImage(FRAMEWND * Frame, BOOL SkipBkgBlitting) // Calling frame paint proc { if (!g_pCachedWindow) { TRACE("ske_ValidateSingleFrameImage calling without cached\n"); return 0;} if (Frame->hWnd == (HWND)-1 && !Frame->PaintCallbackProc) { TRACE("ske_ValidateSingleFrameImage calling without FrameProc\n"); return 0;} // if ok update image HDC hdc; HBITMAP o,n; RECT rcPaint,wnd; RECT ru = {0}; int w,h,x,y; int w1,h1,x1,y1; CLUI_SizingGetWindowRect(pcli->hwndContactList,&wnd); rcPaint = Frame->wndSize; { int dx,dy,bx,by; if (g_CluiData.mutexOnEdgeSizing) { dx = rcPaint.left-wnd.left; dy = rcPaint.top-wnd.top; bx = rcPaint.right-wnd.right; by = rcPaint.bottom-wnd.bottom; wnd = g_rcEdgeSizingRect; rcPaint.left = wnd.left+dx; rcPaint.top = wnd.top+dy; rcPaint.right = wnd.right+bx; rcPaint.bottom = wnd.bottom+by; } } //OffsetRect(&rcPaint,-wnd.left,-wnd.top); w = rcPaint.right-rcPaint.left; h = rcPaint.bottom-rcPaint.top; if (w <= 0 || h <= 0) { TRACE("Frame size smaller than 0\n"); return 0; } x = rcPaint.left; y = rcPaint.top; hdc = CreateCompatibleDC(g_pCachedWindow->hImageDC); n = ske_CreateDIB32(w,h); o = (HBITMAP)SelectObject(hdc,n); { if (Frame->UpdateRgn && !SkipBkgBlitting) { GetRgnBox(Frame->UpdateRgn,&ru); { RECT rc; GetClientRect(Frame->hWnd,&rc); if (ru.top < 0) ru.top = 0; if (ru.left < 0) ru.left = 0; if (ru.right>rc.right) ru.right = rc.right; if (ru.bottom>rc.bottom) ru.bottom = rc.bottom; } if (!IsRectEmpty(&ru)) { x1 = ru.left; y1 = ru.top; w1 = ru.right-ru.left; h1 = ru.bottom-ru.top; } else {x1 = 0; y1 = 0; w1 = w; h1 = h;} // copy image at hdc if (SkipBkgBlitting) //image already at foreground { BitBlt(hdc,x1,y1,w1,h1,g_pCachedWindow->hImageDC,x+x1,y+y1,SRCCOPY); } else { BitBlt(hdc,x1,y1,w1,h1,g_pCachedWindow->hBackDC,x+x1,y+y1,SRCCOPY); } Frame->PaintCallbackProc(Frame->hWnd,hdc,&ru,Frame->UpdateRgn, Frame->dwFlags,Frame->PaintData); } else { HRGN rgnUpdate; RECT r; GetClientRect(Frame->hWnd,&r); rgnUpdate = CreateRectRgn(r.left,r.top,r.right,r.bottom); ru = r; if (!IsRectEmpty(&ru)) { x1 = ru.left; y1 = ru.top; w1 = ru.right-ru.left; h1 = ru.bottom-ru.top; } else {x1 = 0; y1 = 0; w1 = w; h1 = h;} // copy image at hdc if (SkipBkgBlitting) //image already at foreground { BitBlt(hdc,x1,y1,w1,h1,g_pCachedWindow->hImageDC,x+x1,y+y1,SRCCOPY); } else { BitBlt(hdc,x1,y1,w1,h1,g_pCachedWindow->hBackDC,x+x1,y+y1,SRCCOPY); } Frame->PaintCallbackProc(Frame->hWnd,hdc,&r,rgnUpdate, Frame->dwFlags,Frame->PaintData); ru = r; DeleteObject(rgnUpdate); } DeleteObject(Frame->UpdateRgn); Frame->UpdateRgn = 0; } if (!IsRectEmpty(&ru)) { x1 = ru.left; y1 = ru.top; w1 = ru.right-ru.left; h1 = ru.bottom-ru.top; } else { x1 = 0; y1 = 0; w1 = w; h1 = h; } BitBlt(g_pCachedWindow->hImageDC,x+x1,y+y1,w1,h1,hdc,x1,y1,SRCCOPY); if (GetWindowLongPtr(Frame->hWnd, GWL_STYLE) & WS_VSCROLL) { //Draw vertical scroll bar // SCROLLBARINFO si = {0}; si.cbSize = sizeof(SCROLLBARINFO); GetScrollBarInfo(Frame->hWnd, OBJID_VSCROLL, &si); RECT rLine = (si.rcScrollBar); RECT rUpBtn = rLine; RECT rDnBtn = rLine; RECT rThumb = rLine; rUpBtn.bottom = rUpBtn.top+si.dxyLineButton; rDnBtn.top = rDnBtn.bottom-si.dxyLineButton; rThumb.top = rLine.top+si.xyThumbTop; rThumb.bottom = rLine.top+si.xyThumbBottom; int dx = Frame->wndSize.right-rLine.right; int dy = -rLine.top + Frame->wndSize.top; OffsetRect(&rLine, dx, dy); OffsetRect(&rUpBtn, dx, dy); OffsetRect(&rDnBtn, dx, dy); OffsetRect(&rThumb, dx, dy); BitBlt(g_pCachedWindow->hImageDC, rLine.left, rLine.top, rLine.right - rLine.left, rLine.bottom - rLine.top, g_pCachedWindow->hBackDC, rLine.left, rLine.top, SRCCOPY); char req[255]; mir_snprintf(req, sizeof(req), "Main,ID=ScrollBar,Frame=%s,Part=Back", Frame->szName); SkinDrawGlyph(g_pCachedWindow->hImageDC,&rLine,&rLine,req); mir_snprintf(req, sizeof(req), "Main,ID=ScrollBar,Frame=%s,Part=Thumb", Frame->szName); SkinDrawGlyph(g_pCachedWindow->hImageDC,&rThumb,&rThumb,req); mir_snprintf(req, sizeof(req), "Main,ID=ScrollBar, Frame=%s,Part=UpLineButton", Frame->szName); SkinDrawGlyph(g_pCachedWindow->hImageDC,&rUpBtn,&rUpBtn,req); mir_snprintf(req, sizeof(req), "Main,ID=ScrollBar,Frame=%s,Part=DownLineButton", Frame->szName); SkinDrawGlyph(g_pCachedWindow->hImageDC,&rDnBtn,&rDnBtn,req); } SelectObject(hdc, o); DeleteObject(n); DeleteDC(hdc); return 1; } int ske_BltBackImage (HWND destHWND, HDC destDC, RECT *BltClientRect) { POINT ptMainWnd = {0}; POINT ptChildWnd = {0}; RECT from = {0}; RECT w = {0}; if (g_CluiData.fDisableSkinEngine) { FillRect(destDC,BltClientRect,GetSysColorBrush(COLOR_3DFACE)); return 0; } ske_ReCreateBackImage(FALSE,NULL); if (BltClientRect) w = *BltClientRect; else GetClientRect(destHWND,&w); ptChildWnd.x = w.left; ptChildWnd.y = w.top; ClientToScreen(destHWND,&ptChildWnd); ClientToScreen(pcli->hwndContactList,&ptMainWnd); //TODO if main not relative to client area return BitBlt(destDC,w.left,w.top,(w.right-w.left),(w.bottom-w.top),g_pCachedWindow->hBackDC,(ptChildWnd.x-ptMainWnd.x),(ptChildWnd.y-ptMainWnd.y),SRCCOPY); } int ske_ReCreateBackImage(BOOL Erase,RECT *w) { HBITMAP hb2; RECT wnd = {0}; BOOL IsNewCache = 0; if (g_CluiData.fDisableSkinEngine) return 0; GetClientRect(pcli->hwndContactList,&wnd); if (w) wnd = *w; //-- Check cached. if (g_pCachedWindow == NULL) { //-- Create New Cache g_pCachedWindow = (CURRWNDIMAGEDATA*)mir_calloc(sizeof(CURRWNDIMAGEDATA)); g_pCachedWindow->hScreenDC = GetDC(NULL); g_pCachedWindow->hBackDC = CreateCompatibleDC(g_pCachedWindow->hScreenDC); g_pCachedWindow->hImageDC = CreateCompatibleDC(g_pCachedWindow->hScreenDC); g_pCachedWindow->Width = wnd.right-wnd.left; g_pCachedWindow->Height = wnd.bottom-wnd.top; if (g_pCachedWindow->Width != 0 && g_pCachedWindow->Height != 0) { g_pCachedWindow->hImageDIB = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hImageDIBByte)); g_pCachedWindow->hBackDIB = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hBackDIBByte)); g_pCachedWindow->hImageOld = (HBITMAP)SelectObject(g_pCachedWindow->hImageDC,g_pCachedWindow->hImageDIB); g_pCachedWindow->hBackOld = (HBITMAP)SelectObject(g_pCachedWindow->hBackDC,g_pCachedWindow->hBackDIB); } IsNewCache = 1; } if (g_pCachedWindow->Width != wnd.right-wnd.left || g_pCachedWindow->Height != wnd.bottom-wnd.top) { HBITMAP hb1 = NULL,hb2 = NULL; g_pCachedWindow->Width = wnd.right-wnd.left; g_pCachedWindow->Height = wnd.bottom-wnd.top; if (g_pCachedWindow->Width != 0 && g_pCachedWindow->Height != 0) { hb1 = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hImageDIBByte)); hb2 = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hBackDIBByte)); SelectObject(g_pCachedWindow->hImageDC,hb1); SelectObject(g_pCachedWindow->hBackDC,hb2); } else { SelectObject(g_pCachedWindow->hImageDC,g_pCachedWindow->hImageOld); SelectObject(g_pCachedWindow->hBackDC,g_pCachedWindow->hBackOld); } if (g_pCachedWindow->hImageDIB) DeleteObject(g_pCachedWindow->hImageDIB); if (g_pCachedWindow->hBackDIB) DeleteObject(g_pCachedWindow->hBackDIB); g_pCachedWindow->hImageDIB = hb1; g_pCachedWindow->hBackDIB = hb2; IsNewCache = 1; } if ((Erase || IsNewCache ) && (g_pCachedWindow->Width != 0 && g_pCachedWindow->Height != 0)) { hb2 = ske_CreateDIB32(g_pCachedWindow->Width,g_pCachedWindow->Height); SelectObject(g_pCachedWindow->hBackDC,hb2); DeleteObject(g_pCachedWindow->hBackDIB); g_pCachedWindow->hBackDIB = hb2; FillRect(g_pCachedWindow->hBackDC,&wnd,GetSysColorBrush(COLOR_BTNFACE)); SkinDrawGlyph(g_pCachedWindow->hBackDC,&wnd,&wnd,"Main,ID=Background,Opt=Non-Layered"); ske_SetRectOpaque(g_pCachedWindow->hBackDC,&wnd); } return 1; } int ske_DrawNonFramedObjects(BOOL Erase,RECT *r) { RECT w, wnd; if (r) w = *r; else CLUI_SizingGetWindowRect(pcli->hwndContactList, &w); if (!g_CluiData.fLayered) return ske_ReCreateBackImage(FALSE, 0); if (g_pCachedWindow == NULL) return ske_ValidateFrameImageProc(&w); wnd = w; OffsetRect(&w, -w.left, -w.top); if (Erase) { HBITMAP hb2; hb2 = ske_CreateDIB32(g_pCachedWindow->Width, g_pCachedWindow->Height); SelectObject(g_pCachedWindow->hBackDC, hb2); DeleteObject(g_pCachedWindow->hBackDIB); g_pCachedWindow->hBackDIB = hb2; } SkinDrawGlyph(g_pCachedWindow->hBackDC, &w, &w, "Main,ID=Background"); //--Draw frames captions for (int i = 0; i < g_nFramesCount; i++) { if (g_pfwFrames[i].TitleBar.ShowTitleBar && g_pfwFrames[i].visible && !g_pfwFrames[i].floating) { RECT rc; SetRect(&rc, g_pfwFrames[i].wndSize.left, g_pfwFrames[i].wndSize.top - g_nTitleBarHeight - g_CluiData.nGapBetweenTitlebar, g_pfwFrames[i].wndSize.right, g_pfwFrames[i].wndSize.top - g_CluiData.nGapBetweenTitlebar); Sync(DrawTitleBar, g_pCachedWindow->hBackDC, &rc, g_pfwFrames[i].id); } } g_mutex_bLockUpdating = 1; flag_bJustDrawNonFramedObjects = 1; return 0; } int ske_ValidateFrameImageProc(RECT *r) // Calling queued frame paint procs and refresh image { RECT wnd = {0}; BOOL IsNewCache = 0; BOOL IsForceAllPainting = 0; if (r) wnd = *r; else GetWindowRect(pcli->hwndContactList,&wnd); if (wnd.right-wnd.left == 0 || wnd.bottom-wnd.top == 0) return 0; g_mutex_bLockUpdating = 1; //-- Check cached. if (g_pCachedWindow == NULL) { //-- Create New Cache g_pCachedWindow = (CURRWNDIMAGEDATA*)mir_calloc(sizeof(CURRWNDIMAGEDATA)); g_pCachedWindow->hScreenDC = GetDC(NULL); g_pCachedWindow->hBackDC = CreateCompatibleDC(g_pCachedWindow->hScreenDC); g_pCachedWindow->hImageDC = CreateCompatibleDC(g_pCachedWindow->hScreenDC); g_pCachedWindow->Width = wnd.right-wnd.left; g_pCachedWindow->Height = wnd.bottom-wnd.top; g_pCachedWindow->hImageDIB = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hImageDIBByte)); g_pCachedWindow->hBackDIB = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hBackDIBByte)); g_pCachedWindow->hImageOld = (HBITMAP)SelectObject(g_pCachedWindow->hImageDC,g_pCachedWindow->hImageDIB); g_pCachedWindow->hBackOld = (HBITMAP)SelectObject(g_pCachedWindow->hBackDC,g_pCachedWindow->hBackDIB); IsNewCache = 1; } if (g_pCachedWindow->Width != wnd.right-wnd.left || g_pCachedWindow->Height != wnd.bottom-wnd.top) { HBITMAP hb1,hb2; g_pCachedWindow->Width = wnd.right-wnd.left; g_pCachedWindow->Height = wnd.bottom-wnd.top; hb1 = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hImageDIBByte)); hb2 = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hBackDIBByte)); SelectObject(g_pCachedWindow->hImageDC,hb1); SelectObject(g_pCachedWindow->hBackDC,hb2); DeleteObject(g_pCachedWindow->hImageDIB); DeleteObject(g_pCachedWindow->hBackDIB); g_pCachedWindow->hImageDIB = hb1; g_pCachedWindow->hBackDIB = hb2; IsNewCache = 1; } if (IsNewCache) { ske_DrawNonFramedObjects(0, &wnd); IsForceAllPainting = 1; } if (flag_bJustDrawNonFramedObjects) { IsForceAllPainting = 1; flag_bJustDrawNonFramedObjects = 0; } if (IsForceAllPainting) { BitBlt(g_pCachedWindow->hImageDC, 0, 0, g_pCachedWindow->Width,g_pCachedWindow->Height,g_pCachedWindow->hBackDC, 0, 0, SRCCOPY); Sync( QueueAllFramesUpdating, (BYTE)1 ); } //-- Validating frames for (int i=0; i < g_nFramesCount; i++) if (g_pfwFrames[i].PaintCallbackProc && g_pfwFrames[i].visible && !g_pfwFrames[i].floating) if (g_pfwFrames[i].bQueued || IsForceAllPainting) ske_ValidateSingleFrameImage(&g_pfwFrames[i], IsForceAllPainting); g_mutex_bLockUpdating = 1; ModernSkinButtonRedrawAll(0); g_mutex_bLockUpdating = 0; if (!mutex_bLockUpdate) ske_UpdateWindowImageRect(&wnd); //-- Clear queue Sync(QueueAllFramesUpdating, 0); flag_bUpdateQueued = 0; g_flag_bPostWasCanceled = 0; return 1; } int ske_UpdateWindowImage() { if (MirandaExiting()) return 0; if (g_CluiData.fLayered) { RECT r; GetWindowRect(pcli->hwndContactList,&r); return ske_UpdateWindowImageRect(&r); } else ske_ReCreateBackImage(FALSE,0); ske_ApplyTranslucency(); return 0; } int ske_UpdateWindowImageRect(RECT *r) // Update window with current image and { //if not validity -> ValidateImageProc //else Update using current alpha RECT wnd = *r; if (!g_CluiData.fLayered) return ske_ReCreateBackImage(FALSE, 0); if (g_pCachedWindow == NULL) return ske_ValidateFrameImageProc(&wnd); if (g_pCachedWindow->Width != wnd.right-wnd.left || g_pCachedWindow->Height != wnd.bottom-wnd.top) return ske_ValidateFrameImageProc(&wnd); if (g_flag_bFullRepaint) { g_flag_bFullRepaint = 0; return ske_ValidateFrameImageProc(&wnd); } ske_JustUpdateWindowImageRect(&wnd); return 0; } void ske_ApplyTranslucency() { int IsTransparancy; HWND hwnd = pcli->hwndContactList; BOOL layered = (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED)?TRUE:FALSE; IsTransparancy = g_CluiData.fSmoothAnimation || g_bTransparentFlag; if (!g_bTransparentFlag && !g_CluiData.fSmoothAnimation && g_CluiData.bCurrentAlpha != 0) g_CluiData.bCurrentAlpha = 255; if (!g_CluiData.fLayered && IsTransparancy) { if (!layered) SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED); SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), (BYTE)g_CluiData.bCurrentAlpha, LWA_ALPHA); } AniAva_RedrawAllAvatars(FALSE); return; } int ske_JustUpdateWindowImage() { RECT r; if (!g_CluiData.fLayered) { ske_ApplyTranslucency(); return 0; } GetWindowRect(pcli->hwndContactList,&r); return ske_JustUpdateWindowImageRect(&r); } // Update window image int ske_JustUpdateWindowImageRect(RECT *rty) { if (!g_CluiData.fLayered) { ske_ApplyTranslucency(); return 0; } if (!pcli->hwndContactList) return 0; RECT wnd = *rty; RECT rect = wnd; POINT dest = { 0 }, src = { 0 }; dest.x = rect.left; dest.y = rect.top; SIZE sz = { rect.right - rect.left, rect.bottom - rect.top }; if (g_CluiData.fLayered) { if (!(GetWindowLongPtr(pcli->hwndContactList, GWL_EXSTYLE)&WS_EX_LAYERED)) SetWindowLongPtr(pcli->hwndContactList, GWL_EXSTYLE, GetWindowLongPtr(pcli->hwndContactList, GWL_EXSTYLE) | WS_EX_LAYERED); Sync(SetAlpha, g_CluiData.bCurrentAlpha); BLENDFUNCTION bf = { AC_SRC_OVER, 0, g_CluiData.bCurrentAlpha, AC_SRC_ALPHA }; UpdateLayeredWindow(pcli->hwndContactList, g_pCachedWindow->hScreenDC, &dest, &sz, g_pCachedWindow->hImageDC, &src, RGB(1, 1, 1), &bf, ULW_ALPHA); g_CluiData.fAeroGlass = false; CLUI_UpdateAeroGlass(); } else InvalidateRect(pcli->hwndContactList,NULL,TRUE); return 0; } int ske_DrawImageAt(HDC hdc, RECT *rc) { BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; BitBlt(g_pCachedWindow->hImageDC,rc->left,rc->top,rc->right-rc->left,rc->bottom-rc->top,g_pCachedWindow->hBackDC,rc->left,rc->top,SRCCOPY); ske_AlphaBlend(g_pCachedWindow->hImageDC,rc->left,rc->top,rc->right-rc->left,rc->bottom-rc->top,hdc, 0, 0, rc->right-rc->left,rc->bottom-rc->top,bf); if (!g_mutex_bLockUpdating) ske_UpdateWindowImage(); return 0; } HBITMAP ske_GetCurrentWindowImage() { return g_pCachedWindow->hImageDIB; } /* * Glyph text routine */ static DWORD ske_HexToARGB(char * Hex) { char buf[10] = {0}; char buf2[11] = {0}; mir_snprintf(buf, SIZEOF(buf), "%s\n", Hex); if (buf[1] == 'x' || buf[1] == 'X') mir_snprintf(buf2, SIZEOF(buf2), "0x%s\n", buf+2); else mir_snprintf(buf2, SIZEOF(buf2), "0x%s\n", buf); buf2[10] = '\0'; char *st; DWORD AARRGGBB = strtoul(buf2, &st, 16); BYTE alpha = (BYTE)((AARRGGBB & 0xFF000000) >> 24); alpha = 255-((alpha == 0)?255:alpha); AARRGGBB = (alpha << 24)+((AARRGGBB&0x00FF0000)>>16)+((AARRGGBB&0x000000FF) << 16)+(AARRGGBB&0x0000FF00); return AARRGGBB; } static TCHAR *ske_ReAppend(TCHAR *lfirst, TCHAR * lsecond, int len) { int l1 = lfirst?lstrlen(lfirst):0; int l2 = (len?len:(lstrlen(lsecond)+1)); TCHAR *buf = (TCHAR *)mir_alloc((l1+l2+1)*sizeof(TCHAR)); if (lfirst) memmove(buf,lfirst,l1*sizeof(TCHAR)); memmove(buf+l1,lsecond,l2*sizeof(TCHAR)); mir_free(lfirst); if (len) buf[l1+l2] = _T('\0'); return buf; } TCHAR* ske_ReplaceVar(TCHAR *var) { if (!var) return mir_tstrdup(_T("")); if (!lstrcmpi(var,_T("Profile"))) { char buf[MAX_PATH] = {0}; CallService(MS_DB_GETPROFILENAME,(WPARAM)MAX_PATH,(LPARAM)buf); int i = strlen(buf); while (buf[i] != '.' && i>0) i--; buf[i] = '\0'; mir_free(var); return mir_a2u(buf); } mir_free(var); return mir_tstrdup(_T("")); } TCHAR *ske_ParseText(TCHAR *stzText) { int len = lstrlen(stzText); TCHAR *result = NULL; int stpos = 0; int curpos = 0; while (curpos < len) { //1 find first % while (curpos < len && stzText[curpos] != (TCHAR)'%') curpos++; if (curpos < len) { //% found if (curpos-stpos>0) result = ske_ReAppend(result,stzText+stpos,curpos-stpos); stpos = curpos+1; curpos++; //3 find second % while(curpos < len && stzText[curpos] != (TCHAR)'%') curpos++; if (curpos >= len) break; if (curpos - stpos > 0) { TCHAR *var = (TCHAR *)mir_alloc((curpos - stpos + 1)*sizeof(TCHAR)); memmove(var, stzText + stpos, (curpos - stpos)*sizeof(TCHAR)); var[curpos - stpos] = (TCHAR)'\0'; var = ske_ReplaceVar(var); result = ske_ReAppend(result, var, 0); mir_free(var); } else result = ske_ReAppend(result, _T("%"), 0); curpos++; stpos = curpos; } else { if (curpos - stpos > 0) result = ske_ReAppend(result, stzText + stpos, curpos - stpos); break; } } return result; } /* * Parse text object string, find glyph object and add text to it. * szGlyphTextID and Define string is: * t[szGlyphTextID] = s[HostObjectID],[Left],[Top],[Right],[Bottom],[LTRBHV],[FontID],[Color1],[reservedforColor2],[Text] */ static void ske_AddParseTextGlyphObject(char * szGlyphTextID,char * szDefineString,SKINOBJECTSLIST *Skin) { char buf[255] = {0}; GetParamN(szDefineString,buf,sizeof(buf), 0, ',',TRUE); if (buf[0] == 0) return; GLYPHTEXT *glText = (GLYPHTEXT*)mir_calloc(sizeof(GLYPHTEXT)); glText->szGlyphTextID = mir_strdup(szGlyphTextID); glText->szObjectName = mir_strdup(buf); glText->iLeft = atoi(GetParamN(szDefineString,buf,sizeof(buf),1,',',TRUE)); glText->iTop = atoi(GetParamN(szDefineString,buf,sizeof(buf),2,',',TRUE)); glText->iRight = atoi(GetParamN(szDefineString,buf,sizeof(buf),3,',',TRUE)); glText->iBottom = atoi(GetParamN(szDefineString,buf,sizeof(buf),4,',',TRUE)); { memset(buf, 0, 6); GetParamN(szDefineString,buf,sizeof(buf),5,',',TRUE); buf[0] &= 95; buf[1] &= 95; buf[2] &= 95; buf[3] &= 95; buf[4] &= 95; buf[5] &= 95; //to uppercase: &01011111 (0-95) glText->RelativeFlags = (buf[0] == 'C'?1:((buf[0] == 'R')?2:0)) //[BC][RC][BC][RC] --- Left relative |(buf[1] == 'C'?4:((buf[1] == 'B')?8:0)) // | | |--------- Top relative |(buf[2] == 'C'?16:((buf[2] == 'R')?32:0)) // | |--------------Right relative |(buf[3] == 'C'?64:((buf[3] == 'B')?128:0)); // |------------------Bottom relative glText->dwFlags = (buf[4] == 'C'?DT_CENTER:((buf[4] == 'R')?DT_RIGHT:DT_LEFT)) |(buf[5] == 'C'?DT_VCENTER:((buf[5] == 'B')?DT_BOTTOM:DT_TOP)); } glText->szFontID = mir_strdup(GetParamN(szDefineString,buf,sizeof(buf),6,',',TRUE)); glText->dwColor = ske_HexToARGB(GetParamN(szDefineString,buf,sizeof(buf),7,',',TRUE)); glText->dwShadow = ske_HexToARGB(GetParamN(szDefineString,buf,sizeof(buf),8,',',TRUE)); glText->stValueText = mir_a2u(GetParamN(szDefineString,buf,sizeof(buf),9,',',TRUE)); glText->stText = ske_ParseText(glText->stValueText); if (!Skin->pTextList) Skin->pTextList = List_Create(0, 1); List_InsertPtr(Skin->pTextList,glText); } /* * Parse font definition string. * szGlyphTextID and Define string is: * f[szFontID] = s[FontTypefaceName],[size],[BIU] */ static void ske_AddParseSkinFont(char * szFontID,char * szDefineString,SKINOBJECTSLIST *Skin) { SKINFONT *sf = (SKINFONT*)mir_calloc(sizeof(SKINFONT)); if (!sf) return; char buf[255]; int fntSize = 0; BOOL fntBold = FALSE, fntItalic = FALSE, fntUnderline = FALSE; LOGFONTA logfont = {0}; logfont.lfCharSet = DEFAULT_CHARSET; logfont.lfOutPrecision = OUT_DEFAULT_PRECIS; logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; logfont.lfQuality = DEFAULT_QUALITY; logfont.lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE; strncpy(logfont.lfFaceName,GetParamN(szDefineString,buf,sizeof(buf), 0, ',',TRUE),32); logfont.lfHeight = atoi(GetParamN(szDefineString,buf,sizeof(buf),1,',',TRUE)); if (logfont.lfHeight < 0) { HDC hdc = CreateCompatibleDC(NULL); logfont.lfHeight = (long)-MulDiv(logfont.lfHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72); DeleteDC(hdc); } logfont.lfHeight = -logfont.lfHeight; GetParamN(szDefineString,buf,sizeof(buf),2,',',TRUE); buf[0] &= 95; buf[1] &= 95; buf[2] &= 95; logfont.lfWeight = (buf[0] == 'B')?FW_BOLD:FW_NORMAL; logfont.lfItalic = (buf[1] == 'I')?1:0; logfont.lfUnderline = (buf[2] == 'U')?1:0; sf->hFont = CreateFontIndirectA(&logfont); if (sf->hFont) { sf->szFontID = mir_strdup(szFontID); if (!gl_plSkinFonts) gl_plSkinFonts = List_Create(0, 1); if (gl_plSkinFonts) List_Insert(gl_plSkinFonts,(void*)sf,gl_plSkinFonts->realCount); } } /* * ske_CheckHasAlfaChannel - checks if image has at least one BYTE in alpha chennel * that is not a 0. (is image real 32 bit or just 24 bit) */ static BOOL ske_CheckHasAlfaChannel(BYTE * from, int widthByte, int height) { DWORD *pt = (DWORD*)from; for (int j = 0; j < height; j++) { BYTE *add = (BYTE*)pt+widthByte; while (pt < (DWORD*)add) { if ((*pt & 0xFF000000) != 0) return TRUE; pt++; } pt = (DWORD*)(from+widthByte*j); } return FALSE; } /* * ske_CheckIconHasMask - checks if mask image has at least one that is not a 0. * Not sure is ir required or not */ static BOOL ske_CheckIconHasMask(BYTE * from) { for (int i=0; i < 16*16/8; i++) if (from[i] != 0) return TRUE; return FALSE; } /* * ske_GetMaskBit - return value of apropriate mask bit in line at x position */ static BOOL ske_GetMaskBit(BYTE *line, int x) { return ((*(line+(x>>3)))&(0x01 << (7-(x&0x07)))) != 0; } /* * ske_Blend - alpha ske_Blend ARGB values of 2 pixels. X1 - underlaying, * X2 - overlaying points. */ static DWORD ske_Blend(DWORD X1,DWORD X2, BYTE alpha) { BYTE a1 = (BYTE)(X1>>24); BYTE a2 = (BYTE)(((X2>>24)*alpha)>>8); BYTE r1 = (BYTE)(X1>>16); BYTE r2 = (BYTE)(X2>>16); BYTE g1 = (BYTE)(X1>>8); BYTE g2 = (BYTE)(X2>>8); BYTE b1 = (BYTE)(X1); BYTE b2 = (BYTE)(X2); BYTE a_1 = ~a1; BYTE a_2 = ~a2; WORD am = (WORD)a1*a_2; /* it is possible to use >>8 instead of /255 but it is require additional * checking of alphavalues */ WORD ar = a1+(((WORD)a_1*a2)/255); // if a2 more than 0 than result should be more // or equal (if a1 == 0) to a2, else in combination // with mask we can get here black points ar = (a2>ar)?a2:ar; if (ar == 0) return 0; WORD arm = ar*255; WORD rr = (((WORD)r1*am+(WORD)r2*a2*255))/arm; WORD gr = (((WORD)g1*am+(WORD)g2*a2*255))/arm; WORD br = (((WORD)b1*am+(WORD)b2*a2*255))/arm; return (ar << 24)|(rr << 16)|(gr << 8)|br; } /* * CreateJoinedIcon - creates new icon by drawing hTop over hBottom. */ HICON ske_CreateJoinedIcon(HICON hBottom, HICON hTop, BYTE alpha) { HBITMAP nMask; BITMAP bmp = { 0 }; BYTE *ptPixels; ICONINFO iNew = { 0 }; ICONINFO iciBottom = { 0 }; ICONINFO iciTop = { 0 }; BITMAP bmp_top = { 0 }; BITMAP bmp_top_mask = { 0 }; BITMAP bmp_bottom = { 0 }; BITMAP bmp_bottom_mask = { 0 }; HDC tempDC = CreateCompatibleDC(NULL); HBITMAP nImage = ske_CreateDIB32Point(16, 16, (void**)&ptPixels); HBITMAP oImage = (HBITMAP)SelectObject(tempDC, nImage); GetIconInfo(hBottom, &iciBottom); GetObject(iciBottom.hbmColor, sizeof(BITMAP), &bmp_bottom); GetObject(iciBottom.hbmMask, sizeof(BITMAP), &bmp_bottom_mask); GetIconInfo(hTop, &iciTop); GetObject(iciTop.hbmColor, sizeof(BITMAP), &bmp_top); GetObject(iciTop.hbmMask, sizeof(BITMAP), &bmp_top_mask); if (bmp_bottom.bmBitsPixel == 32 && bmp_top.bmBitsPixel == 32) { BYTE *BottomBuffer, *TopBuffer, *BottomMaskBuffer, *TopMaskBuffer; BYTE *bb, *tb, *bmb, *tmb; BYTE *db = ptPixels; int vstep_d = 16 * 4; int vstep_b = bmp_bottom.bmWidthBytes; int vstep_t = bmp_top.bmWidthBytes; int vstep_bm = bmp_bottom_mask.bmWidthBytes; int vstep_tm = bmp_top_mask.bmWidthBytes; alpha = alpha ? alpha : 255; if (bmp_bottom.bmBits) bb = BottomBuffer = (BYTE*)bmp_bottom.bmBits; else { BottomBuffer = (BYTE*)malloc(bmp_bottom.bmHeight*bmp_bottom.bmWidthBytes); GetBitmapBits(iciBottom.hbmColor, bmp_bottom.bmHeight*bmp_bottom.bmWidthBytes, BottomBuffer); bb = BottomBuffer + vstep_b*(bmp_bottom.bmHeight - 1); vstep_b = -vstep_b; } if (bmp_top.bmBits) tb = TopBuffer = (BYTE*)bmp_top.bmBits; else { TopBuffer = (BYTE*)malloc(bmp_top.bmHeight*bmp_top.bmWidthBytes); GetBitmapBits(iciTop.hbmColor,bmp_top.bmHeight*bmp_top.bmWidthBytes,TopBuffer); tb = TopBuffer+vstep_t*(bmp_top.bmHeight-1); vstep_t = -vstep_t; } if (bmp_bottom_mask.bmBits) { BottomMaskBuffer = (BYTE*)bmp_bottom_mask.bmBits; bmb = BottomMaskBuffer; } else { BottomMaskBuffer = (BYTE*)malloc(bmp_bottom_mask.bmHeight*bmp_bottom_mask.bmWidthBytes); GetBitmapBits(iciBottom.hbmMask,bmp_bottom_mask.bmHeight*bmp_bottom_mask.bmWidthBytes,BottomMaskBuffer); bmb = BottomMaskBuffer+vstep_bm*(bmp_bottom_mask.bmHeight-1); vstep_bm = -vstep_bm; } if (bmp_top_mask.bmBits) { TopMaskBuffer = (BYTE*)bmp_top_mask.bmBits; tmb = TopMaskBuffer; } else { TopMaskBuffer = (BYTE*)malloc(bmp_top_mask.bmHeight*bmp_top_mask.bmWidthBytes); GetBitmapBits(iciTop.hbmMask,bmp_top_mask.bmHeight*bmp_top_mask.bmWidthBytes,TopMaskBuffer); tmb = TopMaskBuffer+vstep_tm*(bmp_top_mask.bmHeight-1); vstep_tm = -vstep_tm; } BOOL topHasAlpha = ske_CheckHasAlfaChannel(TopBuffer, bmp_top.bmWidthBytes, bmp_top.bmHeight); BOOL bottomHasAlpha = ske_CheckHasAlfaChannel(BottomBuffer, bmp_bottom.bmWidthBytes, bmp_bottom.bmHeight); BOOL topHasMask = ske_CheckIconHasMask(TopMaskBuffer); BOOL bottomHasMask = ske_CheckIconHasMask(BottomMaskBuffer); for (int y = 0; y < 16; y++) { for (int x = 0; x < 16; x++) { BOOL mask_b = ske_GetMaskBit(bmb, x); BOOL mask_t = ske_GetMaskBit(tmb, x); DWORD bottom_d = ((DWORD*)bb)[x]; DWORD top_d = ((DWORD*)tb)[x]; if (topHasMask) { if (mask_t == 1 && !topHasAlpha) top_d &= 0xFFFFFF; else if (!topHasAlpha) top_d |= 0xFF000000; } if (bottomHasMask) { if (mask_b == 1 && !bottomHasAlpha) bottom_d &= 0xFFFFFF; else if (!bottomHasAlpha) bottom_d |= 0xFF000000; } ((DWORD*)db)[x] = ske_Blend(bottom_d, top_d, alpha); } bb += vstep_b; tb += vstep_t; bmb += vstep_bm; tmb += vstep_tm; db += vstep_d; } if (!bmp_bottom.bmBits) free(BottomBuffer); if (!bmp_top.bmBits) free(TopBuffer); if (!bmp_bottom_mask.bmBits) free(BottomMaskBuffer); if (!bmp_top_mask.bmBits) free(TopMaskBuffer); } else { ske_DrawIconEx(tempDC, 0, 0, hBottom,16,16, 0, NULL,DI_NORMAL); ske_DrawIconEx(tempDC, 0, 0, hTop,16,16, 0, NULL,DI_NORMAL|(alpha << 24)); } DeleteObject(iciBottom.hbmColor); DeleteObject(iciTop.hbmColor); DeleteObject(iciBottom.hbmMask); DeleteObject(iciTop.hbmMask); SelectObject(tempDC,oImage); DeleteDC(tempDC); BYTE p[32] = {0}; nMask = CreateBitmap(16,16,1,1,(void*)&p); { HDC tempDC2 = CreateCompatibleDC(NULL); HDC tempDC3 = CreateCompatibleDC(NULL); HBITMAP hbm = CreateCompatibleBitmap(tempDC3,16,16); HBITMAP obmp = (HBITMAP)SelectObject(tempDC2,nMask); HBITMAP obmp2 = (HBITMAP)SelectObject(tempDC3,hbm); DrawIconEx(tempDC2, 0, 0, hBottom,16,16, 0, NULL,DI_MASK); DrawIconEx(tempDC3, 0, 0, hTop,16,16, 0, NULL,DI_MASK); BitBlt(tempDC2, 0, 0, 16,16,tempDC3, 0, 0, SRCAND); SelectObject(tempDC2,obmp); SelectObject(tempDC3,obmp2); DeleteObject(hbm); DeleteDC(tempDC2); DeleteDC(tempDC3); } iNew.fIcon = TRUE; iNew.hbmColor = nImage; iNew.hbmMask = nMask; HICON res = CreateIconIndirect(&iNew); DeleteObject(nImage); DeleteObject(nMask); return res; } #define NEWJOINEDSTR( destination, first, separator, last) \ destination = (char*)alloca(strlen(first)+strlen(separator)+strlen(last)+1); \ if (destination) { \ *destination = '\0'; \ strcat(destination,first); \ strcat(destination,separator); \ strcat(destination,last); \ } #define SKINSETSECTION "SkinnedSettings" BOOL SkinDBGetContactSetting(MCONTACT hContact, const char* szSection, const char*szKey, DBVARIANT * retdbv, BOOL * bSkinned ) { if (!hContact) { //only for not contact settings char *szSkinKey; NEWJOINEDSTR(szSkinKey, szSection, "@", szKey); if (!db_get(hContact, SKINSETSECTION, szSkinKey, retdbv)) { if (bSkinned) *bSkinned = TRUE; return FALSE; } } // not skinned if (bSkinned) bSkinned = FALSE; return db_get(hContact, szSection, szKey, retdbv); } BYTE SkinDBGetContactSettingByte(MCONTACT hContact, const char* szSection, const char*szKey, BYTE bDefault) { DBVARIANT dbv = { 0 }; BOOL bSkinned = FALSE; if (!SkinDBGetContactSetting(hContact, szSection, szKey, &dbv, &bSkinned)) { if (dbv.type == DBVT_BYTE) { BYTE retVal = dbv.bVal; db_free(&dbv); return retVal; } else { db_free(&dbv); if (!bSkinned) return db_get_b(hContact, szSection, szKey, bDefault); } } return bDefault; } WORD SkinDBGetContactSettingWord(MCONTACT hContact, const char* szSection, const char*szKey, WORD wDefault) { BOOL bSkinned = FALSE; DBVARIANT dbv = { 0 }; if (!SkinDBGetContactSetting(hContact, szSection, szKey, &dbv, &bSkinned)) { if (dbv.type == DBVT_WORD) { WORD retVal = dbv.wVal; db_free(&dbv); return retVal; } db_free(&dbv); if (!bSkinned) return db_get_w(hContact, szSection, szKey, wDefault); } return wDefault; } DWORD SkinDBGetContactSettingDword(MCONTACT hContact, const char* szSection, const char*szKey, DWORD dwDefault) { DBVARIANT dbv = { 0 }; BOOL bSkinned = FALSE; if (!SkinDBGetContactSetting(hContact, szSection, szKey, &dbv, &bSkinned)) { if (dbv.type == DBVT_DWORD) { DWORD retVal = dbv.dVal; db_free(&dbv); return retVal; } db_free(&dbv); if (!bSkinned) return db_get_dw(hContact, szSection, szKey, dwDefault); } return dwDefault; }