1462 lines
39 KiB
C++
1462 lines
39 KiB
C++
//---------------------------------------------------------------------------
|
|
// Render.cpp - implements the themed drawing services
|
|
//---------------------------------------------------------------------------
|
|
#include "stdafx.h"
|
|
#include "Render.h"
|
|
#include "Utils.h"
|
|
#include "Parser.h"
|
|
#include "Loader.h"
|
|
#include "tmutils.h"
|
|
#include "gradient.h"
|
|
#include "rgn.h"
|
|
#include "info.h"
|
|
#include "cache.h"
|
|
#include "cachelist.h"
|
|
#include "borderfill.h"
|
|
#include "imagefile.h"
|
|
|
|
#ifdef DEBUG
|
|
static DWORD s_dwSize = 0;
|
|
#endif
|
|
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CreateRenderObj(CUxThemeFile *pThemeFile, int iCacheSlot, int iThemeOffset,
|
|
int iClassNameOffset, __int64 iUniqueId, BOOL fEnableCache, CDrawBase *pBaseObj,
|
|
CTextDraw *pTextObj, DWORD dwOtdFlags, CRenderObj **ppObj)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CRenderObj *pRender = new CRenderObj(pThemeFile, iCacheSlot, iThemeOffset,
|
|
iClassNameOffset, iUniqueId, fEnableCache, dwOtdFlags);
|
|
|
|
if (! pRender)
|
|
{
|
|
hr = MakeError32(E_OUTOFMEMORY);
|
|
}
|
|
else
|
|
{
|
|
hr = pRender->Init(pBaseObj, pTextObj);
|
|
|
|
if (FAILED(hr))
|
|
delete pRender;
|
|
else
|
|
*ppObj = pRender;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
CRenderObj::CRenderObj(CUxThemeFile *pThemeFile, int iCacheSlot, int iThemeOffset,
|
|
int iClassNameOffset, __int64 iUniqueId, BOOL fEnableCache, DWORD dwOtdFlags)
|
|
{
|
|
strcpy(_szHead, "rendobj");
|
|
strcpy(_szTail, "end");
|
|
|
|
_fCacheEnabled = fEnableCache;
|
|
_fCloseThemeFile = FALSE;
|
|
_dwOtdFlags = dwOtdFlags;
|
|
|
|
if (pThemeFile)
|
|
{
|
|
if (SUCCEEDED(BumpThemeFileRefCount(pThemeFile)))
|
|
_fCloseThemeFile = TRUE;
|
|
}
|
|
|
|
_pThemeFile = pThemeFile;
|
|
_iCacheSlot = iCacheSlot;
|
|
_iUniqueId = iUniqueId;
|
|
|
|
if (pThemeFile)
|
|
{
|
|
_pbThemeData = pThemeFile->_pbThemeData;
|
|
_pbSectionData = _pbThemeData + iThemeOffset;
|
|
_ptm = GetThemeMetricsPtr(pThemeFile);
|
|
}
|
|
else
|
|
{
|
|
_pbThemeData = NULL;
|
|
_pbSectionData = NULL;
|
|
_ptm = NULL;
|
|
}
|
|
|
|
_pszClassName = ThemeString(pThemeFile, iClassNameOffset);
|
|
|
|
_iMaxPart = 0;
|
|
_pParts = NULL;
|
|
|
|
_iDpiOverride = 0;
|
|
|
|
//---- caller must call "Init()" after ctr! ----
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::PrepareAlphaBitmap(HBITMAP hBitmap)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//---- convert to DIBDATA ----
|
|
CBitmapPixels pixels;
|
|
DWORD *pPixelQuads;
|
|
int iWidth, iHeight, iBytesPerPixel, iBytesPerRow;
|
|
|
|
hr = pixels.OpenBitmap(NULL, hBitmap, TRUE, &pPixelQuads, &iWidth, &iHeight,
|
|
&iBytesPerPixel, &iBytesPerRow);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
PreMultiplyAlpha(pPixelQuads, iWidth, iHeight);
|
|
|
|
pixels.CloseBitmap(NULL, hBitmap);
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::Init(CDrawBase *pBaseObj, CTextDraw *pTextObj)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (_fCacheEnabled)
|
|
{
|
|
hr = BuildPackedPtrs(pBaseObj, pTextObj);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
}
|
|
|
|
//---- prepare direct objects ----
|
|
if ((pBaseObj) && (pBaseObj->_eBgType == BT_IMAGEFILE))
|
|
{
|
|
CMaxImageFile *pMaxIf = (CMaxImageFile *)pBaseObj;
|
|
|
|
//---- process primary image ----
|
|
DIBINFO *pdi = &pMaxIf->_ImageInfo;
|
|
|
|
if (pdi->fAlphaChannel)
|
|
{
|
|
hr = PrepareAlphaBitmap(pdi->hProcessBitmap);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
}
|
|
|
|
//---- process glyph image ----
|
|
pdi = &pMaxIf->_GlyphInfo;
|
|
|
|
if (pdi->fAlphaChannel)
|
|
{
|
|
hr = PrepareAlphaBitmap(pdi->hProcessBitmap);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
}
|
|
|
|
//---- process multiple images ----
|
|
for (int i=0; i < pMaxIf->_iMultiImageCount; i++)
|
|
{
|
|
pdi = pMaxIf->MultiDibPtr(i);
|
|
|
|
if (pdi->fAlphaChannel)
|
|
{
|
|
hr = PrepareAlphaBitmap(pdi->hProcessBitmap);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
CRenderObj::~CRenderObj()
|
|
{
|
|
//---- delete memory allocated for pack objects looked ----
|
|
if (_pParts)
|
|
{
|
|
for(int i=0; i<_iMaxPart+1; i++)
|
|
{
|
|
if (_pParts[i].pStateDrawObjs)
|
|
delete[] _pParts[i].pStateDrawObjs;
|
|
|
|
if (_pParts[i].pStateTextObjs)
|
|
delete[] _pParts[i].pStateTextObjs;
|
|
}
|
|
delete[] _pParts;
|
|
}
|
|
|
|
//---- if we opened a refcount on a themefile, close it now ----
|
|
if (_fCloseThemeFile)
|
|
CloseThemeFile(_pThemeFile);
|
|
|
|
//---- mark this object as "deleted" (for debugging) ----
|
|
strcpy(_szHead, "deleted");
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::SetDpiOverride(int iDpiOverride)
|
|
{
|
|
_iDpiOverride = iDpiOverride;
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
int CRenderObj::GetDpiOverride()
|
|
{
|
|
return _iDpiOverride;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::BuildPackedPtrs(CDrawBase *pBaseObj, CTextDraw *pTextObj)
|
|
{
|
|
MIXEDPTRS u;
|
|
HRESULT hr = S_OK;
|
|
int iPackedOffset = 0;
|
|
int *iPartOffsets = NULL;
|
|
BOOL fSingleObj = FALSE;
|
|
|
|
//---- extract _iMaxPart ----
|
|
if ((pBaseObj) || (pTextObj)) // single object to be used for all parts/states
|
|
{
|
|
_iMaxPart = 1; // dummy value
|
|
fSingleObj = TRUE;
|
|
}
|
|
else
|
|
{
|
|
u.pb = _pbSectionData;
|
|
if (*u.ps != TMT_PARTJUMPTABLE)
|
|
{
|
|
hr = MakeError32(E_FAIL); // something went amiss
|
|
goto exit;
|
|
}
|
|
|
|
u.pb += ENTRYHDR_SIZE;
|
|
iPackedOffset = *u.pi++;
|
|
|
|
_iMaxPart = *u.pb - 1;
|
|
|
|
u.pb++;
|
|
iPartOffsets = u.pi;
|
|
}
|
|
|
|
//---- allocate _pParts ----
|
|
_pParts = new PARTINFO[_iMaxPart+1];
|
|
if (! _pParts)
|
|
{
|
|
hr = MakeError32(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
memset(_pParts, 0, sizeof(PARTINFO)*(_iMaxPart+1));
|
|
|
|
if (fSingleObj)
|
|
{
|
|
for (int i=0; i <= _iMaxPart; i++)
|
|
_pParts[i].iMaxState = 1; // dummy value
|
|
|
|
if (pBaseObj) // single draw object to be used for all parts/states
|
|
{
|
|
for (int i=0; i <= _iMaxPart; i++)
|
|
{
|
|
_pParts[i].pDrawObj = pBaseObj;
|
|
}
|
|
}
|
|
|
|
if (pTextObj) // single text object t to be used for all parts/states
|
|
{
|
|
for (int i=0; i <= _iMaxPart; i++)
|
|
{
|
|
_pParts[i].pTextObj = pTextObj;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
u.pb = _pbThemeData + iPackedOffset;
|
|
|
|
hr = WalkDrawObjects(u, iPartOffsets);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
hr = WalkTextObjects(u, iPartOffsets);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::WalkDrawObjects(MIXEDPTRS &u, int *iPartOffsets)
|
|
{
|
|
int iPartId;
|
|
int iStateId;
|
|
HRESULT hr = S_OK;
|
|
THEMEHDR *pHdr = (THEMEHDR *)_pbThemeData;
|
|
UNPACKED_ENTRYHDR hdr;
|
|
|
|
//---- get ptr to global text obj ----
|
|
BYTE *pb = _pbThemeData + pHdr->iGlobalsDrawObjOffset;
|
|
pb += ENTRYHDR_SIZE + sizeof(DRAWOBJHDR);
|
|
CDrawBase *pGlobalObj = (CDrawBase *)pb;
|
|
|
|
//---- start with all parts inheriting from [globals] ----
|
|
for (int i=0; i <= _iMaxPart; i++)
|
|
_pParts[i].pDrawObj = pGlobalObj;
|
|
|
|
//---- now, process all specified objects ----
|
|
while (1)
|
|
{
|
|
if ((*u.ps == TMT_RGNLIST) || (*u.ps == TMT_STOCKBRUSHES))
|
|
{
|
|
//---- skip over this entry ----
|
|
FillAndSkipHdr(u, &hdr);
|
|
u.pb += hdr.dwDataLen;
|
|
continue;
|
|
}
|
|
|
|
if (*u.ps != TMT_DRAWOBJ)
|
|
break;
|
|
|
|
FillAndSkipHdr(u, &hdr);
|
|
|
|
DRAWOBJHDR *ph = (DRAWOBJHDR *)u.pb;
|
|
CDrawBase *pCurrentObj = (CDrawBase *)(u.pb + sizeof(DRAWOBJHDR));
|
|
u.pb += hdr.dwDataLen;
|
|
|
|
iPartId = ph->iPartNum;
|
|
iStateId = ph->iStateNum;
|
|
|
|
if ((! iPartId) && (! iStateId))
|
|
{
|
|
//---- all parts inherit from this obj ----
|
|
for (int i=0; i <= _iMaxPart; i++)
|
|
_pParts[i].pDrawObj = pCurrentObj;
|
|
continue;
|
|
}
|
|
|
|
PARTINFO *ppi = &_pParts[iPartId];
|
|
if (! iStateId)
|
|
{
|
|
ppi->pDrawObj = pCurrentObj;
|
|
}
|
|
else
|
|
{
|
|
if (! ppi->iMaxState) // extract MaxState
|
|
{
|
|
MIXEDPTRS u2;
|
|
u2.pb = _pbThemeData + iPartOffsets[iPartId];
|
|
if (*u2.ps != TMT_STATEJUMPTABLE)
|
|
{
|
|
hr = MakeError32(E_FAIL); // something went amiss
|
|
goto exit;
|
|
}
|
|
u2.pb += ENTRYHDR_SIZE;
|
|
ppi->iMaxState = *u2.pb - 1;
|
|
}
|
|
|
|
if (! ppi->pStateDrawObjs) // allocate now
|
|
{
|
|
ppi->pStateDrawObjs = new CDrawBase *[ppi->iMaxState];
|
|
if (! ppi->pStateDrawObjs)
|
|
{
|
|
hr = MakeError32(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
//---- fill in default objs as state 0 ----
|
|
for (int i=0; i < ppi->iMaxState; i++)
|
|
ppi->pStateDrawObjs[i] = ppi->pDrawObj;
|
|
}
|
|
|
|
ppi->pStateDrawObjs[iStateId-1] = pCurrentObj;
|
|
}
|
|
|
|
}
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::WalkTextObjects(MIXEDPTRS &u, int *iPartOffsets)
|
|
{
|
|
int iPartId;
|
|
int iStateId;
|
|
HRESULT hr = S_OK;
|
|
THEMEHDR *pHdr = (THEMEHDR *)_pbThemeData;
|
|
UNPACKED_ENTRYHDR hdr;
|
|
|
|
//---- get ptr to global text obj ----
|
|
BYTE *pb = _pbThemeData + pHdr->iGlobalsTextObjOffset;
|
|
pb += ENTRYHDR_SIZE + sizeof(DRAWOBJHDR);
|
|
CTextDraw *pGlobalObj = (CTextDraw *)pb;
|
|
|
|
//---- start with all parts inheriting from [globals] ----
|
|
for (int i=0; i <= _iMaxPart; i++)
|
|
_pParts[i].pTextObj = pGlobalObj;
|
|
|
|
while (*u.ps == TMT_TEXTOBJ)
|
|
{
|
|
FillAndSkipHdr(u, &hdr);
|
|
|
|
DRAWOBJHDR *ph = (DRAWOBJHDR *)u.pb;
|
|
CTextDraw *pCurrentObj = (CTextDraw *)(u.pb + sizeof(DRAWOBJHDR));
|
|
u.pb += hdr.dwDataLen;
|
|
|
|
iPartId = ph->iPartNum;
|
|
iStateId = ph->iStateNum;
|
|
|
|
if ((! iPartId) && (! iStateId))
|
|
{
|
|
//---- all parts inherit from this obj ----
|
|
for (int i=0; i <= _iMaxPart; i++)
|
|
_pParts[i].pTextObj = pCurrentObj;
|
|
continue;
|
|
}
|
|
|
|
PARTINFO *ppi = &_pParts[iPartId];
|
|
if (! iStateId)
|
|
{
|
|
ppi->pTextObj = pCurrentObj;
|
|
}
|
|
else
|
|
{
|
|
if (! ppi->iMaxState) // extract MaxState
|
|
{
|
|
MIXEDPTRS u2;
|
|
u2.pb = _pbThemeData + iPartOffsets[iPartId];
|
|
if (*u2.ps != TMT_STATEJUMPTABLE)
|
|
{
|
|
hr = MakeError32(E_FAIL); // something went amiss
|
|
goto exit;
|
|
}
|
|
u2.pb += ENTRYHDR_SIZE;
|
|
ppi->iMaxState = *u2.pb - 1;
|
|
}
|
|
|
|
if (! ppi->pStateTextObjs) // allocate now
|
|
{
|
|
ppi->pStateTextObjs = new CTextDraw *[ppi->iMaxState];
|
|
if (! ppi->pStateTextObjs)
|
|
{
|
|
hr = MakeError32(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
//---- fill in default objs as state 0 ----
|
|
for (int i=0; i < ppi->iMaxState; i++)
|
|
ppi->pStateTextObjs[i] = ppi->pTextObj;
|
|
}
|
|
|
|
ppi->pStateTextObjs[iStateId-1] = pCurrentObj;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::GetBitmap(HDC hdc, int iDibOffset, OUT HBITMAP *phBitmap)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HBITMAP hBitmap;
|
|
|
|
if ((! iDibOffset) || (! _pbThemeData))
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
TMBITMAPHEADER *pThemeBitmapHeader;
|
|
|
|
pThemeBitmapHeader = reinterpret_cast<TMBITMAPHEADER*>(_pbThemeData + iDibOffset);
|
|
ASSERT(pThemeBitmapHeader->dwSize == TMBITMAPSIZE);
|
|
|
|
*phBitmap = pThemeBitmapHeader->hBitmap;
|
|
if (*phBitmap != NULL)
|
|
{
|
|
//Log(LOG_TMBITMAP, L"Used stock bitmap:%8X", *phBitmap);
|
|
return hr;
|
|
}
|
|
|
|
hr = CreateBitmapFromData(hdc, iDibOffset + TMBITMAPSIZE, &hBitmap);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
Log(LOG_TM, L"GetBitmap - CACHE MISS: class=%s, diboffset=%d, bitmap=0x%x",
|
|
SHARECLASS(this), iDibOffset, hBitmap);
|
|
|
|
#if 0
|
|
if (lstrcmpi(SHARECLASS(this), L"progress")==0)
|
|
{
|
|
//---- validate the bitmap ----
|
|
int iBytes = GetObject(hBitmap, 0, NULL);
|
|
|
|
Log(LOG_RFBUG, L"progress: CREATE bitmap, diboff=%d, hbitmap=0x%x, iBytes=%d",
|
|
iDibOffset, hBitmap, iBytes);
|
|
}
|
|
#endif
|
|
|
|
*phBitmap = hBitmap;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void CRenderObj::ReturnBitmap(HBITMAP hBitmap)
|
|
{
|
|
DeleteObject(hBitmap);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::CreateBitmapFromData(HDC hdc, int iDibOffset, OUT HBITMAP *phBitmap)
|
|
{
|
|
BYTE *pDibData;
|
|
RESOURCE HDC hdcTemp = NULL;
|
|
RESOURCE HBITMAP hBitmap = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
if ((! iDibOffset) || (! _pbThemeData))
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
pDibData = (BYTE *)(_pbThemeData + iDibOffset);
|
|
BITMAPINFOHEADER *pBitmapHdr;
|
|
pBitmapHdr = (BITMAPINFOHEADER *)pDibData;
|
|
|
|
BOOL fAlphaChannel;
|
|
fAlphaChannel = (pBitmapHdr->biBitCount == 32);
|
|
|
|
if (! hdc)
|
|
{
|
|
hdcTemp = GetWindowDC(NULL);
|
|
if (! hdcTemp)
|
|
{
|
|
Log(LOG_ALWAYS, L"GetWindowDC() failed in CreateBitmapFromData");
|
|
hr = MakeErrorLast();
|
|
goto exit;
|
|
}
|
|
|
|
hdc = hdcTemp;
|
|
}
|
|
|
|
//---- create the actual bitmap ----
|
|
//---- if using alpha channel, we must use a DIB ----
|
|
if (fAlphaChannel)
|
|
{
|
|
void *pv;
|
|
hBitmap = CreateDIBSection(hdc, (BITMAPINFO *)pBitmapHdr, DIB_RGB_COLORS,
|
|
&pv, NULL, 0);
|
|
}
|
|
else
|
|
{
|
|
hBitmap = CreateCompatibleBitmap(hdc, pBitmapHdr->biWidth, pBitmapHdr->biHeight);
|
|
}
|
|
|
|
if (! hBitmap)
|
|
{
|
|
hr = MakeErrorLast();
|
|
goto exit;
|
|
}
|
|
|
|
int iSetVal;
|
|
|
|
//---- SetDIBits() can take unaligned data, right? ----
|
|
iSetVal = SetDIBits(hdc, hBitmap, 0, pBitmapHdr->biHeight, DIBDATA(pBitmapHdr), (BITMAPINFO *)pBitmapHdr,
|
|
DIB_RGB_COLORS);
|
|
|
|
if (! iSetVal)
|
|
{
|
|
hr = MakeErrorLast();
|
|
goto exit;
|
|
}
|
|
|
|
*phBitmap = hBitmap;
|
|
|
|
#ifdef DEBUG
|
|
if (hBitmap)
|
|
{
|
|
BITMAP bm;
|
|
|
|
GetObject(hBitmap, sizeof bm, &bm);
|
|
s_dwSize += bm.bmWidthBytes * bm.bmHeight;
|
|
//Log(LOG_TMBITMAP, L"Created a bitmap of %d bytes. total is %d", bm.bmWidthBytes * bm.bmHeight, s_dwSize);
|
|
}
|
|
#endif
|
|
|
|
exit:
|
|
if (hdcTemp)
|
|
ReleaseDC(NULL, hdcTemp);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
if (hBitmap)
|
|
DeleteObject(hBitmap);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::GetScaledFontHandle(HDC hdc, LOGFONT *plf, HFONT *phFont)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (_fCacheEnabled)
|
|
{
|
|
CRenderCache *pCacheObj = GetTlsCacheObj();
|
|
if (pCacheObj)
|
|
hr = pCacheObj->GetScaledFontHandle(hdc, plf, phFont);
|
|
}
|
|
else
|
|
{
|
|
LOGFONT lf = *plf;
|
|
|
|
//---- convert to current screen dpi ----
|
|
ScaleFontForHdcDpi(hdc, &lf);
|
|
|
|
*phFont = CreateFontIndirect(&lf);
|
|
if (! *phFont)
|
|
hr = MakeError32(E_OUTOFMEMORY);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void CRenderObj::ReturnFontHandle(HFONT hFont)
|
|
{
|
|
if (_fCacheEnabled)
|
|
{
|
|
//--- cache currently doesn't refcnt so save time by not calling ---
|
|
//CRenderCache *pCacheObj = GetTlsCacheObj();
|
|
//if (pCacheObj)
|
|
//{
|
|
//pCacheObj->ReturnFontHandle(hFont);
|
|
//goto exit;
|
|
//}
|
|
}
|
|
else
|
|
{
|
|
DeleteObject(hFont);
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::PrepareRegionDataForScaling(
|
|
RGNDATA *pRgnData, LPCRECT prcImage, MARGINS *pMargins)
|
|
{
|
|
//---- compute margin values ----
|
|
int sw = prcImage->left;
|
|
int lw = prcImage->left + pMargins->cxLeftWidth;
|
|
int rw = prcImage->right - pMargins->cxRightWidth;
|
|
|
|
int sh = prcImage->top;
|
|
int th = prcImage->top + pMargins->cyTopHeight;
|
|
int bh = prcImage->bottom - pMargins->cyBottomHeight;
|
|
|
|
//---- step thru region data & customize it ----
|
|
//---- classify each POINT according to a gridnum and ----
|
|
//---- make it 0-relative to its grid location ----
|
|
|
|
POINT *pt = (POINT *)pRgnData->Buffer;
|
|
BYTE *pByte = (BYTE *)pRgnData->Buffer + pRgnData->rdh.nRgnSize;
|
|
int iCount = 2 * pRgnData->rdh.nCount;
|
|
|
|
for (int i=0; i < iCount; i++, pt++, pByte++)
|
|
{
|
|
if (pt->x < lw)
|
|
{
|
|
pt->x -= sw;
|
|
|
|
if (pt->y < th) // left top
|
|
{
|
|
*pByte = GN_LEFTTOP;
|
|
pt->y -= sh;
|
|
}
|
|
else if (pt->y < bh) // left middle
|
|
{
|
|
*pByte = GN_LEFTMIDDLE;
|
|
pt->y -= th;
|
|
}
|
|
else // left bottom
|
|
{
|
|
*pByte = GN_LEFTBOTTOM;
|
|
pt->y -= bh;
|
|
}
|
|
}
|
|
else if (pt->x < rw)
|
|
{
|
|
pt->x -= lw;
|
|
|
|
if (pt->y < th) // middle top
|
|
{
|
|
*pByte = GN_MIDDLETOP;
|
|
pt->y -= sh;
|
|
}
|
|
else if (pt->y < bh) // middle middle
|
|
{
|
|
*pByte = GN_MIDDLEMIDDLE;
|
|
pt->y -= th;
|
|
}
|
|
else // middle bottom
|
|
{
|
|
*pByte = GN_MIDDLEBOTTOM;
|
|
pt->y -= bh;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pt->x -= rw;
|
|
|
|
if (pt->y < th) // right top
|
|
{
|
|
*pByte = GN_RIGHTTOP;
|
|
pt->y -= sh;
|
|
}
|
|
else if (pt->y < bh) // right middle
|
|
{
|
|
*pByte = GN_RIGHTMIDDLE;
|
|
pt->y -= th;
|
|
}
|
|
else // right bottom
|
|
{
|
|
*pByte = GN_RIGHTBOTTOM;
|
|
pt->y -= bh;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::CreateImageBrush(HDC hdc, int iPartId, int iStateId,
|
|
int iImageIndex, HBRUSH *phbr)
|
|
{
|
|
#if 0
|
|
HRESULT hr;
|
|
RESOURCE HDC dc2 = NULL;
|
|
RESOURCE HBITMAP hOldBitmap2 = NULL;
|
|
HBRUSH hBrush = NULL;
|
|
|
|
//---- get our bitmap from the cache ----
|
|
RESOURCE HBITMAP hBitmap;
|
|
hr = GetBitmap(hdc, iPartId, iStateId, &hBitmap);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
int iImageCount;
|
|
if (FAILED(GetInt(iPartId, iStateId, TMT_IMAGECOUNT, &iImageCount)))
|
|
iImageCount = 1; /// default value
|
|
|
|
if (iImageCount == 1) // do easy case first
|
|
{
|
|
hBrush = CreatePatternBrush(hBitmap);
|
|
goto gotit;
|
|
}
|
|
|
|
//---- create "dc2" to make our bitmap usable ----
|
|
dc2 = CreateCompatibleDC(hdc);
|
|
if (! dc2)
|
|
{
|
|
hr = MakeErrorLast();
|
|
goto exit;
|
|
}
|
|
|
|
hOldBitmap2 = (HBITMAP) SelectObject(dc2, hBitmap);
|
|
|
|
//---- create a sub-bitmap of just our target image in "memoryDC" ----
|
|
int width, height, xoffset, yoffset;
|
|
GetImageInfo(hBitmap, iPartId, iStateId, iImageIndex, &width, &height, &xoffset, &yoffset);
|
|
|
|
//---- local block ----
|
|
{
|
|
CMemoryDC memoryDC;
|
|
hr = memoryDC.OpenDC(dc2, width, height);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
BitBlt(memoryDC, 0, 0, width, height, dc2, xoffset, yoffset, SRCCOPY);
|
|
|
|
//---- finally, create our brush ----
|
|
hBrush = CreatePatternBrush(memoryDC._hBitmap);
|
|
}
|
|
|
|
gotit:
|
|
if (hBrush)
|
|
{
|
|
*phbr = hBrush;
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
hr = MakeErrorLast();
|
|
|
|
exit:
|
|
//---- now clean up all resources ----
|
|
if (dc2)
|
|
{
|
|
SelectObject(dc2, hOldBitmap2);
|
|
DeleteDC(dc2);
|
|
}
|
|
|
|
ReturnBitmap(hBitmap);
|
|
|
|
return hr;
|
|
#endif
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::GetColor(int iPartId, int iStateId, int iPropId, COLORREF *pColor)
|
|
{
|
|
if (! pColor)
|
|
return MakeError32(E_INVALIDARG);
|
|
|
|
int index = GetValueIndex(iPartId, iStateId, iPropId);
|
|
if (index < 0) // not found
|
|
return MakeError32(ERROR_NOT_FOUND);
|
|
|
|
MIXEDPTRS u;
|
|
u.pb = _pbThemeData + index; // point at data
|
|
|
|
*pColor = *u.pi;
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::GetString(int iPartId, int iStateId, int iPropId,
|
|
LPWSTR pszBuff, DWORD dwMaxBuffChars)
|
|
{
|
|
if (! pszBuff)
|
|
return MakeError32(E_INVALIDARG);
|
|
|
|
int index = GetValueIndex(iPartId, iStateId, iPropId);
|
|
if (index < 0)
|
|
return MakeError32(ERROR_NOT_FOUND);
|
|
|
|
MIXEDPTRS u;
|
|
u.pb = _pbThemeData + index - sizeof(int); // point at length
|
|
DWORD len = *u.pdw++;
|
|
len /= sizeof(WCHAR); // adjust to characters
|
|
|
|
HRESULT hr = hr_lstrcpy(pszBuff, u.pw, dwMaxBuffChars);
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::GetBool(int iPartId, int iStateId, int iPropId, BOOL *pfVal)
|
|
{
|
|
if (! pfVal)
|
|
return MakeError32(E_INVALIDARG);
|
|
|
|
int index = GetValueIndex(iPartId, iStateId, iPropId);
|
|
if (index < 0)
|
|
return MakeError32(ERROR_NOT_FOUND);
|
|
|
|
MIXEDPTRS u;
|
|
u.pb = _pbThemeData + index; // point at data
|
|
|
|
*pfVal = *u.pb;
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::GetInt(int iPartId, int iStateId, int iPropId, int *piVal)
|
|
{
|
|
if (! piVal)
|
|
return MakeError32(E_INVALIDARG);
|
|
|
|
int index = GetValueIndex(iPartId, iStateId, iPropId);
|
|
if (index < 0)
|
|
return MakeError32(ERROR_NOT_FOUND);
|
|
|
|
MIXEDPTRS u;
|
|
u.pb = _pbThemeData + index; // point at data
|
|
|
|
*piVal = *u.pi;
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
static int iMetricDefaults[] =
|
|
{
|
|
1, // TMT_BORDERWIDTH
|
|
18, // TMT_VERTSCROLLWIDTH
|
|
18, // TMT_HORZSCROLLHEIGHT
|
|
27, // TMT_CAPTIONBUTTONWIDTH
|
|
27, // TMT_CAPTIONBUTTONHEIGHT
|
|
22, // TMT_SMCAPTIONBUTTONWIDTH
|
|
22, // TMT_SMCAPTIONBUTTONHEIGHT
|
|
22, // TMT_MENUBUTTONWIDTH
|
|
22, // TMT_MENUBUTTONHEIGHT
|
|
};
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::GetMetric(OPTIONAL HDC hdc, int iPartId, int iStateId, int iPropId, int *piVal)
|
|
{
|
|
if (! piVal)
|
|
return MakeError32(E_INVALIDARG);
|
|
|
|
int index = GetValueIndex(iPartId, iStateId, iPropId);
|
|
int value;
|
|
|
|
if (index >= 0) // found
|
|
{
|
|
MIXEDPTRS u;
|
|
u.pb = _pbThemeData + index; // point at data
|
|
|
|
value = *u.pi;
|
|
}
|
|
else
|
|
return MakeError32(ERROR_NOT_FOUND);
|
|
|
|
*piVal = ScaleSizeForHdcDpi(hdc, value);
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::GetEnumValue(int iPartId, int iStateId, int iPropId, int *piVal)
|
|
{
|
|
if (! piVal)
|
|
return MakeError32(E_INVALIDARG);
|
|
|
|
int index = GetValueIndex(iPartId, iStateId, iPropId);
|
|
if (index < 0)
|
|
return MakeError32(ERROR_NOT_FOUND);
|
|
|
|
MIXEDPTRS u;
|
|
u.pb = _pbThemeData + index; // point at data
|
|
|
|
*piVal = *u.pi;
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::GetPosition(int iPartId, int iStateId, int iPropId, POINT *pPoint)
|
|
{
|
|
if (! pPoint)
|
|
return MakeError32(E_INVALIDARG);
|
|
|
|
int index = GetValueIndex(iPartId, iStateId, iPropId);
|
|
if (index < 0)
|
|
return MakeError32(ERROR_NOT_FOUND);
|
|
|
|
MIXEDPTRS u;
|
|
u.pb = _pbThemeData + index; // point at data
|
|
|
|
pPoint->x = *u.pi++;
|
|
pPoint->y = *u.pi++;
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::GetFont(OPTIONAL HDC hdc, int iPartId, int iStateId, int iPropId,
|
|
BOOL fWantHdcScaling, LOGFONT *pFont)
|
|
{
|
|
if (! pFont)
|
|
return MakeError32(E_INVALIDARG);
|
|
|
|
int index = GetValueIndex(iPartId, iStateId, iPropId);
|
|
if (index < 0)
|
|
return MakeError32(ERROR_NOT_FOUND);
|
|
|
|
MIXEDPTRS u;
|
|
u.pb = _pbThemeData + index; // point at data
|
|
|
|
*pFont = *(LOGFONT *)u.pb;
|
|
|
|
if (fWantHdcScaling)
|
|
{
|
|
ScaleFontForHdcDpi(hdc, pFont);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::GetMargins(OPTIONAL HDC hdc, int iPartId, int iStateId,
|
|
int iPropId, OPTIONAL RECT *prc, MARGINS *pMargins)
|
|
{
|
|
//---- return unscaled margins ----
|
|
|
|
if (! pMargins)
|
|
return MakeError32(E_INVALIDARG);
|
|
|
|
int index = GetValueIndex(iPartId, iStateId, iPropId);
|
|
if (index < 0)
|
|
return MakeError32(ERROR_NOT_FOUND);
|
|
|
|
MIXEDPTRS u;
|
|
u.pb = _pbThemeData + index; // point at data
|
|
|
|
pMargins->cxLeftWidth = *u.pi++;
|
|
pMargins->cxRightWidth = *u.pi++;
|
|
pMargins->cyTopHeight = *u.pi++;
|
|
pMargins->cyBottomHeight = *u.pi++;
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::GetIntList(int iPartId, int iStateId, int iPropId, INTLIST *pIntList)
|
|
{
|
|
if (! pIntList)
|
|
return MakeError32(E_INVALIDARG);
|
|
|
|
int index = GetValueIndex(iPartId, iStateId, iPropId);
|
|
if (index < 0)
|
|
return MakeError32(ERROR_NOT_FOUND);
|
|
|
|
MIXEDPTRS u;
|
|
u.pb = _pbThemeData + index; // point at data
|
|
|
|
int iCount = *u.pi++;
|
|
if (iCount > MAX_INTLIST_COUNT)
|
|
{
|
|
Log(LOG_ALWAYS, L"GetIntList() found bad theme data - Count=%d", iCount);
|
|
|
|
return MakeError32(ERROR_NOT_FOUND);
|
|
}
|
|
|
|
pIntList->iValueCount = iCount;
|
|
|
|
for (int i=0; i < iCount; i++)
|
|
pIntList->iValues[i] = *u.pi++;
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::GetRect(int iPartId, int iStateId, int iPropId, RECT *pRect)
|
|
{
|
|
if (! pRect)
|
|
return MakeError32(E_INVALIDARG);
|
|
|
|
int index = GetValueIndex(iPartId, iStateId, iPropId);
|
|
if (index < 0)
|
|
return MakeError32(ERROR_NOT_FOUND);
|
|
|
|
MIXEDPTRS u;
|
|
u.pb = _pbThemeData + index; // point at data
|
|
|
|
pRect->left = *u.pi++;
|
|
pRect->top = *u.pi++;
|
|
pRect->right = *u.pi++;
|
|
pRect->bottom = *u.pi++;
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::GetFilenameOffset(int iPartId, int iStateId, int iPropId,
|
|
int *piFileNameOffset)
|
|
{
|
|
if (! piFileNameOffset)
|
|
return MakeError32(E_INVALIDARG);
|
|
|
|
int index = GetValueIndex(iPartId, iStateId, iPropId);
|
|
if (index < 0)
|
|
return MakeError32(ERROR_NOT_FOUND);
|
|
|
|
*piFileNameOffset = index; // offset to filename
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::GetFilename(int iPartId, int iStateId, int iPropId, LPWSTR pszBuff,
|
|
DWORD dwMaxBuffChars)
|
|
{
|
|
if (! pszBuff)
|
|
return MakeError32(E_INVALIDARG);
|
|
|
|
int index = GetValueIndex(iPartId, iStateId, iPropId);
|
|
if (index < 0)
|
|
return MakeError32(ERROR_NOT_FOUND);
|
|
|
|
MIXEDPTRS u;
|
|
u.pb = _pbThemeData + index - sizeof(int); // point at length
|
|
DWORD len = *u.pdw++;
|
|
len /= sizeof(WCHAR); // adjust to chars size
|
|
|
|
HRESULT hr = hr_lstrcpy(pszBuff, u.pw, dwMaxBuffChars);
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::GetData(int iPartId, int iStateId, int iPropId, BYTE **ppData,
|
|
OPTIONAL int *piSize)
|
|
{
|
|
if (! ppData)
|
|
return MakeError32(E_INVALIDARG);
|
|
|
|
int index = GetValueIndex(iPartId, iStateId, iPropId);
|
|
if (index < 0)
|
|
return MakeError32(ERROR_NOT_FOUND);
|
|
|
|
MIXEDPTRS u;
|
|
u.pb = _pbThemeData + index - sizeof(int); // point at length
|
|
DWORD len = *u.pdw++;
|
|
|
|
*ppData = u.pb;
|
|
|
|
if (piSize)
|
|
*piSize = len;
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
int CRenderObj::GetValueIndex(int iPartId, int iStateId, int iTarget)
|
|
{
|
|
if (! iTarget)
|
|
{
|
|
Log(LOG_PARAMS, L"Invalid iProperyId passed to GetValueIndex: %d", iTarget);
|
|
return -1;
|
|
}
|
|
|
|
if (! _pbSectionData)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
MIXEDPTRS u;
|
|
int index;
|
|
|
|
u.pb = _pbSectionData;
|
|
|
|
//---- find end of data ----
|
|
THEMEHDR *hdr = (THEMEHDR *)_pbThemeData;
|
|
BYTE *pbLastValidChar = _pbThemeData + (hdr->dwTotalLength - 1) - kcbEndSignature;
|
|
|
|
while (u.pb <= pbLastValidChar)
|
|
{
|
|
UNPACKED_ENTRYHDR hdr;
|
|
|
|
FillAndSkipHdr(u, &hdr);
|
|
|
|
if (hdr.usTypeNum == TMT_PARTJUMPTABLE)
|
|
{
|
|
u.pi++; // skip over offset to first drawobj
|
|
|
|
BYTE cnt = *u.pb++;
|
|
|
|
if ((iPartId < 0) || (iPartId >= cnt))
|
|
{
|
|
index = u.pi[0];
|
|
}
|
|
else
|
|
{
|
|
index = u.pi[iPartId];
|
|
if (index == -1)
|
|
index = u.pi[0];
|
|
}
|
|
|
|
u.pb = _pbThemeData + index;
|
|
continue;
|
|
}
|
|
|
|
if (hdr.usTypeNum == (BYTE)TMT_STATEJUMPTABLE)
|
|
{
|
|
BYTE cnt = *u.pb++;
|
|
|
|
if ((iStateId < 0) || (iStateId >= cnt))
|
|
index = u.pi[0];
|
|
else
|
|
{
|
|
index = u.pi[iStateId];
|
|
if (index == -1)
|
|
index = u.pi[0];
|
|
}
|
|
|
|
u.pb = _pbThemeData + index;
|
|
continue;
|
|
}
|
|
|
|
if (hdr.usTypeNum == iTarget) // got our target
|
|
{
|
|
// Log("GetValueIndex: match at index=%d", u.pb - _pbThemeData);
|
|
return (int)(u.pb - _pbThemeData); // point at actual data (not hdr)
|
|
}
|
|
|
|
if (hdr.ePrimVal == TMT_JUMPTOPARENT)
|
|
{
|
|
index = *u.pi;
|
|
if (index == -1)
|
|
{
|
|
// Log("no match found");
|
|
return -1;
|
|
}
|
|
|
|
// Log("GetValueIndex: jumping to parent at index=%d", index);
|
|
u.pb = _pbThemeData + index;
|
|
continue;
|
|
}
|
|
|
|
// Log("GetValueIndex: no match to hdr.usTypeNum=%d", hdr.usTypeNum);
|
|
|
|
// advance to next value
|
|
u.pb += hdr.dwDataLen;
|
|
}
|
|
|
|
//---- something went wrong ----
|
|
Log(LOG_ERROR, L"GetValueIndex: ran off the valid data without a '-1' jump");
|
|
return -1;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::GetPropertyOrigin(int iPartId, int iStateId, int iTarget,
|
|
PROPERTYORIGIN *pOrigin)
|
|
{
|
|
if (! iTarget)
|
|
{
|
|
Log(LOG_PARAMS, L"Invalid iProperyId passed to GetPropertyOrigin: %d", iTarget);
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (! _pbSectionData)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
MIXEDPTRS u;
|
|
if (! pOrigin)
|
|
return MakeError32(E_INVALIDARG);
|
|
|
|
//---- start at our section ----
|
|
u.pb = _pbSectionData;
|
|
PROPERTYORIGIN origin = PO_CLASS;
|
|
|
|
//---- find end of data ----
|
|
THEMEHDR *hdr = (THEMEHDR *)_pbThemeData;
|
|
BYTE *pbLastValidChar = _pbThemeData + (hdr->dwTotalLength - 1) - kcbEndSignature;
|
|
|
|
while (u.pb <= pbLastValidChar)
|
|
{
|
|
UNPACKED_ENTRYHDR hdr;
|
|
|
|
FillAndSkipHdr(u, &hdr);
|
|
|
|
if (hdr.usTypeNum == TMT_PARTJUMPTABLE)
|
|
{
|
|
u.pi++; // skip over offset to first drawobj
|
|
|
|
BYTE cnt = *u.pb++;
|
|
int index;
|
|
|
|
if ((iPartId <= 0) || (iPartId >= cnt))
|
|
{
|
|
index = u.pi[0];
|
|
}
|
|
else
|
|
{
|
|
index = u.pi[iPartId];
|
|
if (index == -1)
|
|
index = u.pi[0];
|
|
}
|
|
|
|
if (index == u.pi[0])
|
|
origin = PO_CLASS;
|
|
else
|
|
origin = PO_PART;
|
|
|
|
u.pb = _pbThemeData + index;
|
|
continue;
|
|
}
|
|
|
|
if (hdr.usTypeNum == TMT_STATEJUMPTABLE)
|
|
{
|
|
BYTE cnt = *u.pb++;
|
|
int index;
|
|
|
|
if ((iStateId <= 0) || (iStateId >= cnt))
|
|
{
|
|
index = u.pi[0];
|
|
}
|
|
else
|
|
{
|
|
index = u.pi[iStateId];
|
|
if (index == -1)
|
|
index = u.pi[0];
|
|
}
|
|
|
|
if (index != u.pi[0])
|
|
origin = PO_STATE;
|
|
|
|
u.pb = _pbThemeData + index;
|
|
continue;
|
|
}
|
|
|
|
//Log("GetPropertyOrgin: iPartId=%d, iTarget=%d, DataIndex=%d",
|
|
// iPartId, iTarget, u.pb - _pbThemeData);
|
|
|
|
if ((iTarget == -1) || (hdr.usTypeNum == iTarget)) // got our target
|
|
{
|
|
// Log("GetPropertyOrgin: match at index=%d", u.pb - _pbThemeData);
|
|
*pOrigin = origin;
|
|
return S_OK;
|
|
}
|
|
|
|
if (hdr.ePrimVal == TMT_JUMPTOPARENT)
|
|
{
|
|
int index = *u.pi;
|
|
if (index == -1)
|
|
{
|
|
// Log("GetPropertyOrgin: no match found");
|
|
*pOrigin = PO_NOTFOUND;
|
|
return S_OK;
|
|
}
|
|
|
|
// Log("GetPropertyOrgin: jumping to parent at index=%d", index);
|
|
u.pb = _pbThemeData + index;
|
|
origin = (PROPERTYORIGIN) (origin + 1); // move down to next level of heirarchy
|
|
continue;
|
|
}
|
|
|
|
// advance to next value
|
|
u.pb += hdr.dwDataLen;
|
|
}
|
|
|
|
//---- something went wrong ----
|
|
Log(LOG_ERROR, L"GetPropertyOrigin: ran off the valid data without a '-1' jump");
|
|
return E_FAIL;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
BOOL WINAPI CRenderObj::IsPartDefined(int iPartId, int iStateId)
|
|
{
|
|
PROPERTYORIGIN origin;
|
|
HRESULT hr = GetPropertyOrigin(iPartId, iStateId, -1, &origin);
|
|
SET_LAST_ERROR(hr);
|
|
if (FAILED(hr))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (iStateId)
|
|
return (origin == PO_STATE);
|
|
|
|
return (origin == PO_PART);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
BOOL CRenderObj::ValidateObj()
|
|
{
|
|
BOOL fValid = TRUE;
|
|
|
|
//---- check object quickly ----
|
|
if ( (! this)
|
|
|| (ULONGAT(_szHead) != 'dner') // "rend"
|
|
|| (ULONGAT(&_szHead[4]) != 'jbo') // "obj"
|
|
|| (ULONGAT(_szTail) != 'dne')) // "end"
|
|
{
|
|
Log(LOG_ALWAYS, L"CRenderObj is corrupt, addr=0x%08x", this);
|
|
fValid = FALSE;
|
|
}
|
|
|
|
return fValid;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
CRenderCache *CRenderObj::GetTlsCacheObj()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CRenderCache *pCacheObj = NULL;
|
|
|
|
CCacheList *pcl = GetTlsCacheList(TRUE);
|
|
if (pcl)
|
|
hr = pcl->GetCacheObject(this, _iCacheSlot, &pCacheObj);
|
|
|
|
return pCacheObj;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
#if 0
|
|
HRESULT CRenderObj::DispatchDrawBg()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (FAILED(GetEnumValue(iPartId, iStateId, TMT_BGTYPE, (int *)&eBgType)))
|
|
eBgType = BT_BORDERFILL; // default value
|
|
|
|
if (eBgType == BT_NTLFILE)
|
|
{
|
|
BYTE *pNtlData;
|
|
int iNtlLen;
|
|
|
|
hr = GetData(iPartId, iStateId, TMT_NTLDATA, &pNtlData, &iNtlLen);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
RECT rc = *pRect;
|
|
|
|
//---- need to get these from callers... ---
|
|
HBRUSH hbrDefault = NULL;
|
|
DWORD dwOptions = 0;
|
|
|
|
hr = RunNtl(hdc, rc, hbrDefault, dwOptions, iPartId, iStateId, pNtlData, iNtlLen, this);
|
|
goto exit;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
#endif
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::FindGlobalDrawObj(BYTE *pb, int iPartId, int iStateId, CDrawBase **ppObj)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
MIXEDPTRS u;
|
|
u.pb = pb;
|
|
BOOL fFound = FALSE;
|
|
UNPACKED_ENTRYHDR hdr;
|
|
|
|
while (1)
|
|
{
|
|
if ((*u.ps == TMT_RGNLIST) || (*u.ps == TMT_STOCKBRUSHES))
|
|
{
|
|
//---- skip over this entry ----
|
|
FillAndSkipHdr(u, &hdr);
|
|
u.pb += hdr.dwDataLen;
|
|
continue;
|
|
}
|
|
|
|
if (*u.ps != TMT_DRAWOBJ)
|
|
break;
|
|
|
|
FillAndSkipHdr(u, &hdr);
|
|
|
|
DRAWOBJHDR *ph = (DRAWOBJHDR *)u.pb;
|
|
|
|
if ((ph->iPartNum == iPartId) && (ph->iStateNum == iStateId))
|
|
{
|
|
*ppObj = (CDrawBase *)(u.pb + sizeof(DRAWOBJHDR));
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
|
|
//---- skip over hdr+object ----
|
|
u.pb += hdr.dwDataLen;
|
|
}
|
|
|
|
if (! fFound)
|
|
hr = E_FAIL;
|
|
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CRenderObj::GetGlobalDrawObj(int iPartId, int iStateId, CDrawBase **ppObj)
|
|
{
|
|
//---- perf note: we don't currently cache the ptrs for LINE and BORDER ----
|
|
//---- global objects since they are not used much/at all ----
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (! _pbThemeData)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
THEMEHDR *pHdr;
|
|
pHdr = (THEMEHDR *)_pbThemeData;
|
|
|
|
//---- get ptr to global text obj ----
|
|
MIXEDPTRS u;
|
|
u.pb = _pbThemeData + pHdr->iGlobalsDrawObjOffset;
|
|
|
|
//---- first try exact match ---
|
|
hr = FindGlobalDrawObj(u.pb, iPartId, iStateId, ppObj);
|
|
if (FAILED(hr))
|
|
{
|
|
//---- look for state=0 ----
|
|
hr = FindGlobalDrawObj(u.pb, iPartId, 0, ppObj);
|
|
if (FAILED(hr))
|
|
{
|
|
//---- just use the global draw obj ----
|
|
if (*u.ps == TMT_DRAWOBJ)
|
|
{
|
|
u.pb += ENTRYHDR_SIZE + sizeof(DRAWOBJHDR);
|
|
*ppObj = (CDrawBase *)u.pb;
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|