windows-nt/Source/XPSP1/NT/shell/themes/uxtheme/ninegrid2.cpp

689 lines
24 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
// --------------------------------------------------------------------------
// Module Name: NineGrid2.cpp
//
// Copyright (c) 2000, 2001 Microsoft Corporation
//
// Implementation of the DrawNineGrid2 function
//
// History: 2000-12-20 justmann created
// --------------------------------------------------------------------------
#include "stdafx.h"
#include "resource.h"
#include "tmschema.h"
#include "ninegrid2.h"
#define DNG_BUF_WIDTH 256
#define DNG_BUF_HEIGHT 60
typedef struct STRETCH
{
ULONG xStart;
ULONG xAccum;
ULONG xFrac;
ULONG xInt;
ULONG ulDestWidth;
ULONG ulSrcWidth;
int left;
int right;
} STRETCH;
typedef struct DNGINTERNALDATAtag
{
int cxClipMin;
int cxClipMax;
ULONG* pvDestBits;
int iDestWidth;
int iClipWidth;
ULONG* pvSrcBits;
int iSrcWidth;
int iSrcBufWidth;
int cxLeftWidth;
int xMinLeft;
int xMaxLeft;
int cxRightWidth;
int xMinRight;
int xMaxRight;
int cxMiddleWidth;
int cxNewMiddleWidth;
int xMinMiddle;
int xMaxMiddle;
// Variable for shrunken corners and sides
BOOL fShowMiddle;
STRETCH stretchLeft;
STRETCH stretchRight;
int cxNewLeftWidth;
int cxNewRightWidth;
BOOL fTileMode;
// Specific to non-tile mode (i.e. stretch mode)
STRETCH stretchMiddle;
} DNGINTERNALDATA;
static HDC s_hdcBuf = NULL;
static HBITMAP s_hbmBuf = NULL;
static HBITMAP s_hbmOldBuf = NULL;
static CRITICAL_SECTION s_dngLock;
void DNG_FreeDIB(HDC* phdcDest, HBITMAP* phbmDest, HBITMAP* phbmDestOld);
BOOL NineGrid2StartUp()
{
InitializeCriticalSection(&s_dngLock);
return TRUE;
}
void NineGrid2ShutDown()
{
DNG_FreeDIB(&s_hdcBuf, &s_hbmBuf, &s_hbmOldBuf);
DeleteCriticalSection(&s_dngLock);
}
inline void DNG_CreateDIB(HDC hdc, int iWidth, int iHeight, ULONG** ppvDestBits, HDC* phdcDest, HBITMAP* phbmDest, HBITMAP* phbmDestOld)
{
*phdcDest = CreateCompatibleDC(hdc);
if (*phdcDest)
{
BITMAPINFO bi = {0};
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biWidth = iWidth;
bi.bmiHeader.biHeight = iHeight;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biCompression = BI_RGB;
*phbmDest = CreateDIBSection(*phdcDest, &bi, DIB_RGB_COLORS, (VOID**)ppvDestBits, NULL, 0);
if (*phbmDest)
{
*phbmDestOld = (HBITMAP) SelectObject(*phdcDest, *phbmDest);
}
else
{
DeleteDC(*phdcDest);
*phdcDest = NULL;
}
}
}
void DNG_FreeDIB(HDC* phdcDest, HBITMAP* phbmDest, HBITMAP* phbmDestOld)
{
if (*phdcDest)
{
SelectObject(*phdcDest, *phbmDestOld);
DeleteObject(*phbmDest);
DeleteDC(*phdcDest);
}
*phdcDest = NULL;
}
HRESULT BitmapToNGImage(HDC hdc, HBITMAP hbm, int left, int top, int right, int bottom, MARGINS margin, SIZINGTYPE eSize, DWORD dwFlags, COLORREF crTrans, PNGIMAGE pngi)
{
HRESULT hr = E_INVALIDARG;
if (pngi)
{
pngi->margin = margin;
pngi->eSize = eSize;
pngi->dwFlags = dwFlags;
pngi->crTrans = crTrans;
pngi->iWidth = right - left;
pngi->iHeight = bottom - top;
HDC hdcBuf = NULL;
HBITMAP hbmOld;
DNG_CreateDIB(hdc, pngi->iWidth, pngi->iHeight, &(pngi->pvBits), &hdcBuf, &pngi->hbm, &hbmOld);
if (hdcBuf)
{
HDC hdcTempMem = CreateCompatibleDC(hdc);
if (hdcTempMem)
{
HBITMAP hbmTempOld = (HBITMAP) SelectObject(hdcTempMem, hbm);
BitBlt(hdcBuf, 0, 0, pngi->iWidth, pngi->iHeight, hdcTempMem, left, top, SRCCOPY);
hr = S_OK;
SelectObject(hdcTempMem, hbmTempOld);
DeleteDC(hdcTempMem);
}
SelectObject(hdcBuf, hbmOld);
DeleteDC(hdcBuf);
}
}
return hr;
}
HRESULT FreeNGImage(PNGIMAGE pngi)
{
HRESULT hr = E_INVALIDARG;
if (pngi)
{
if (pngi->hbm)
{
DeleteObject(pngi->hbm);
}
pngi->hbm = NULL;
hr = S_OK;
}
return hr;
}
inline void DNG_StretchRow(ULONG* pvDestBits, ULONG* pvSrcBits, STRETCH * ps)
{
ULONG* pvTemp = pvDestBits + ps->left;
ULONG* pvSentinel = pvDestBits + ps->right;
ULONG xInt = ps->xInt;
ULONG xFrac = ps->xFrac;
ULONG xTmp;
ULONG xAccum = ps->xAccum;
ULONG * pulSrc = pvSrcBits + ps->xStart;
ULONG ulSrc;
while (pvTemp != pvSentinel)
{
ulSrc = *pulSrc;
xTmp = xAccum + xFrac;
pulSrc = pulSrc + xInt + (xTmp < xAccum);
*pvTemp = ulSrc;
pvTemp++;
xAccum = xTmp;
}
}
inline void DNG_InitStretch(STRETCH* pStretch, ULONG ulDestWidth, ULONG ulSrcWidth, int left, int right)
{
pStretch->right = right;
pStretch->left = left;
ULONGLONG dx = ((((ULONGLONG) ulSrcWidth << 32) - 1) / (ULONGLONG) ulDestWidth) + 1;
ULONGLONG x = (((ULONGLONG) ulSrcWidth << 32) / (ULONGLONG) ulDestWidth) >> 1;
ULONG xInt = pStretch->xInt = (ULONG) (dx >> 32);
ULONG xFrac = pStretch->xFrac = (ULONG) (dx & 0xFFFFFFFF);
ULONG xAccum = (ULONG) (x & 0xFFFFFFFF);
ULONG xTmp;
ULONG xStart = (ULONG) (x >> 32);
for (int i = 0; i < left; i++)
{
xTmp = xAccum + xFrac;
xStart = xStart + xInt + (xTmp < xAccum);
xAccum = xTmp;
}
pStretch->xStart = xStart;
pStretch->xAccum = xAccum;
}
inline void DNG_DrawRow(DNGINTERNALDATA* pdng)
{
ULONG* pvDestLoc = pdng->pvDestBits;
ULONG* pvSrcLoc = pdng->pvSrcBits;
// Left
if (pdng->cxClipMin < pdng->cxNewLeftWidth)
{
if (pdng->cxLeftWidth == pdng->cxNewLeftWidth)
{
CopyMemory(pvDestLoc + pdng->xMinLeft, pvSrcLoc + pdng->xMinLeft, (pdng->xMaxLeft - pdng->xMinLeft) * sizeof(ULONG));
}
else
{
DNG_StretchRow(pvDestLoc, pvSrcLoc, &pdng->stretchLeft);
}
}
pvDestLoc += pdng->cxNewLeftWidth;
pvSrcLoc += pdng->cxLeftWidth;
// Middle
if (pdng->fShowMiddle)
{
if (pdng->xMinMiddle < pdng->xMaxMiddle)
{
if (pdng->fTileMode)
{
ULONG* pvTempSrc = pvSrcLoc;
ULONG* pvTempDest = pvDestLoc;
// Fill in Top Tile
int xMin = pdng->xMinMiddle;
int xDiff = xMin - pdng->cxLeftWidth;
pvDestLoc += xDiff;
int iTileSize = pdng->cxMiddleWidth - (xDiff % pdng->cxMiddleWidth);
pvSrcLoc += xDiff % pdng->cxMiddleWidth;
int xMax = pdng->xMaxMiddle;
for (int x = xMin; x < xMax; x++, pvDestLoc++ , pvSrcLoc++)
{
*pvDestLoc = *pvSrcLoc;
iTileSize--;
if (iTileSize == 0)
{
iTileSize = pdng->cxMiddleWidth;
pvSrcLoc -= iTileSize;
}
}
pvDestLoc = pvTempDest;
pvSrcLoc = pvTempSrc;
}
else
{
DNG_StretchRow(pvDestLoc, pvSrcLoc, &pdng->stretchMiddle);
}
}
pvDestLoc += pdng->cxNewMiddleWidth;
}
pvSrcLoc += pdng->cxMiddleWidth;
// Right
if (pdng->cxClipMax > (pdng->iDestWidth - pdng->cxNewRightWidth))
{
if (pdng->cxRightWidth == pdng->cxNewRightWidth)
{
CopyMemory(pvDestLoc + pdng->xMinRight, pvSrcLoc + pdng->xMinRight, (pdng->xMaxRight - pdng->xMinRight) * sizeof(ULONG));
}
else
{
DNG_StretchRow(pvDestLoc, pvSrcLoc, &pdng->stretchRight);
}
}
}
inline void DNG_StretchCol(DNGINTERNALDATA* pdng, STRETCH * ps)
{
ULONG* pvOldDestBits = pdng->pvDestBits;
ULONG* pvOldSrcBits = pdng->pvSrcBits;
ULONG* pvTemp = pdng->pvDestBits + (DNG_BUF_WIDTH * ps->left);
ULONG* pvSentinel = pdng->pvDestBits + (DNG_BUF_WIDTH * ps->right);
ULONG xInt = ps->xInt;
ULONG xFrac = ps->xFrac;
ULONG xTmp;
ULONG xAccum = ps->xAccum;
ULONG * pulSrc = pdng->pvSrcBits + (pdng->iSrcBufWidth * ps->xStart);
ULONG xDelta = 1; // force stretch on first scan
while (pvTemp != pvSentinel)
{
if (xDelta != 0)
{
pdng->pvDestBits = pvTemp;
pdng->pvSrcBits = pulSrc;
DNG_DrawRow(pdng);
}
else
{
memcpy(pvTemp + pdng->cxClipMin, pvTemp + pdng->cxClipMin - DNG_BUF_WIDTH, pdng->iClipWidth * sizeof(ULONG));
}
xTmp = xAccum + xFrac;
xDelta = (xInt + (xTmp < xAccum));
pulSrc = pulSrc + (pdng->iSrcBufWidth * xDelta);
pvTemp += DNG_BUF_WIDTH;
xAccum = xTmp;
}
pdng->pvDestBits = pvOldDestBits;
pdng->pvSrcBits = pvOldSrcBits;
}
HRESULT DrawNineGrid2(HDC hdc, PNGIMAGE pngiSrc, RECT* pRect, const RECT *prcClip, DWORD dwFlags)
{
// Store the static buffer
static ULONG* s_pvBitsBuf = NULL;
// Make sure that coordinates are valid;
RECT rcDest = *pRect;
if (rcDest.left > rcDest.right)
{
int xTemp = rcDest.left;
rcDest.left = rcDest.right;
rcDest.right = xTemp;
}
if (rcDest.top > rcDest.bottom)
{
int yTemp = rcDest.bottom;
rcDest.bottom = rcDest.top;
rcDest.top = yTemp;
}
RECT rcClip;
if (prcClip)
{
IntersectRect(&rcClip, &rcDest, prcClip);
}
else
{
CopyRect(&rcClip, &rcDest);
}
HRESULT hr = S_OK;
if ((pngiSrc->eSize == ST_TILE) || (pngiSrc->eSize == ST_STRETCH) || (pngiSrc->eSize == ST_TRUESIZE))
{
ULONG* pvDestBits = NULL;
int iDestWidth = rcDest.right - rcDest.left;
int iDestHeight = rcDest.bottom - rcDest.top;
int iClipWidth = rcClip.right - rcClip.left;
int iClipHeight = rcClip.bottom - rcClip.top;
if ((iClipWidth > DNG_BUF_WIDTH) || (iClipHeight > DNG_BUF_HEIGHT))
{
// Divide the image into chunks smaller or equal to the buffer
for (int y = rcClip.top; y < rcClip.bottom; y += DNG_BUF_HEIGHT)
{
for (int x = rcClip.left; x < rcClip.right; x += DNG_BUF_WIDTH)
{
RECT rcTemp = { x, y, x + DNG_BUF_WIDTH, y + DNG_BUF_HEIGHT };
RECT rcNewClip;
IntersectRect(&rcNewClip, &rcTemp, &rcClip);
DrawNineGrid2(hdc, pngiSrc, &rcDest, &rcNewClip, dwFlags);
}
}
}
else
{
EnterCriticalSection(&s_dngLock);
// Use temporary buffer
if (!s_hdcBuf)
{
DNG_CreateDIB(hdc, DNG_BUF_WIDTH, DNG_BUF_HEIGHT, &s_pvBitsBuf, &s_hdcBuf, &s_hbmBuf, &s_hbmOldBuf);
SetLayout(s_hdcBuf, LAYOUT_BITMAPORIENTATIONPRESERVED);
}
pvDestBits = s_pvBitsBuf;
if (s_hdcBuf)
{
DNGINTERNALDATA dng;
dng.cxClipMin = rcClip.left - rcDest.left;
dng.cxClipMax = rcClip.right - rcDest.left;
int cyClipMin = rcClip.top - rcDest.top;
int cyClipMax = rcClip.bottom - rcDest.top;
pvDestBits += ((cyClipMin - (iDestHeight - DNG_BUF_HEIGHT)) * DNG_BUF_WIDTH) - dng.cxClipMin;
int cxImage = rcClip.right - rcClip.left;
int cyImage = rcClip.bottom - rcClip.top;
if (pngiSrc->eSize == ST_TRUESIZE)
{
ULONG* pvDestLoc = pvDestBits + (iDestHeight - 1) * DNG_BUF_WIDTH;
ULONG* pvSrcLoc = pngiSrc->pvBits + pngiSrc->iBufWidth * (pngiSrc->iHeight - 1);
int yMin = cyClipMin;
pvDestLoc -= yMin * DNG_BUF_WIDTH;
pvSrcLoc -= yMin * pngiSrc->iBufWidth;
int yMax = min(pngiSrc->iHeight, cyClipMax);
int xMin = dng.cxClipMin;
int xMax = min(pngiSrc->iWidth, dng.cxClipMax);
if (xMax > xMin)
{
for (int y = yMin; y < yMax; y++, pvDestLoc -= DNG_BUF_WIDTH, pvSrcLoc -= pngiSrc->iBufWidth)
{
CopyMemory(pvDestLoc + xMin, pvSrcLoc + xMin, (xMax - xMin) * 4);
}
}
cxImage = xMax - xMin;
cyImage = yMax - yMin;
}
else
{
// Setup data
dng.iDestWidth = iDestWidth;
dng.iClipWidth = iClipWidth;
dng.iSrcWidth = pngiSrc->iWidth;
dng.iSrcBufWidth = pngiSrc->iBufWidth;
dng.cxLeftWidth = pngiSrc->margin.cxLeftWidth;
dng.cxRightWidth = pngiSrc->margin.cxRightWidth;
dng.fTileMode = (pngiSrc->eSize == ST_TILE);
// Calculate clip stuff
// Pre-calc corner stretching variables
dng.fShowMiddle = (iDestWidth - pngiSrc->margin.cxLeftWidth - pngiSrc->margin.cxRightWidth > 0);
if (!dng.fShowMiddle)
{
dng.cxNewLeftWidth = (dng.cxLeftWidth + dng.cxRightWidth == 0) ? 0 : (dng.cxLeftWidth * dng.iDestWidth) / (dng.cxLeftWidth + dng.cxRightWidth);
dng.cxNewRightWidth = dng.iDestWidth - dng.cxNewLeftWidth;
}
else
{
dng.cxNewLeftWidth = pngiSrc->margin.cxLeftWidth;
dng.cxNewRightWidth = pngiSrc->margin.cxRightWidth;
}
// Pre-calc Left side variables
dng.xMinLeft = dng.cxClipMin;
dng.xMaxLeft = min(dng.cxNewLeftWidth, dng.cxClipMax);
if (!dng.fShowMiddle && dng.cxNewLeftWidth)
{
DNG_InitStretch(&dng.stretchLeft, dng.cxNewLeftWidth, dng.cxLeftWidth, dng.xMinLeft, dng.xMaxLeft);
}
// Pre-calc Horizontal Middle Variables
dng.cxMiddleWidth = dng.iSrcWidth - dng.cxLeftWidth - dng.cxRightWidth;
dng.cxNewMiddleWidth = dng.iDestWidth - dng.cxNewLeftWidth - dng.cxNewRightWidth;
dng.xMinMiddle = max(dng.cxNewLeftWidth, dng.cxClipMin);
dng.xMaxMiddle = min(dng.cxNewLeftWidth + dng.cxNewMiddleWidth, dng.cxClipMax);
if (dng.fShowMiddle)
{
DNG_InitStretch(&dng.stretchMiddle, dng.cxNewMiddleWidth, dng.cxMiddleWidth, dng.xMinMiddle - dng.cxNewLeftWidth, dng.xMaxMiddle - dng.cxNewLeftWidth);
}
// Pre-calc Right side variables
dng.xMinRight = max(dng.iDestWidth - dng.cxNewRightWidth, dng.cxClipMin) - dng.cxNewLeftWidth - dng.cxNewMiddleWidth;
dng.xMaxRight = min(dng.iDestWidth, dng.cxClipMax) - dng.cxNewLeftWidth - dng.cxNewMiddleWidth;
if (!dng.fShowMiddle && dng.cxNewRightWidth)
{
DNG_InitStretch(&dng.stretchRight, dng.cxNewRightWidth, dng.cxRightWidth, dng.xMinRight, dng.xMaxRight);
}
BOOL fShowVertMiddle = (iDestHeight - pngiSrc->margin.cyTopHeight - pngiSrc->margin.cyBottomHeight > 0);
int cyTopHeight = pngiSrc->margin.cyTopHeight;
int cyBottomHeight = pngiSrc->margin.cyBottomHeight;
int cyNewTopHeight;
int cyNewBottomHeight;
if (!fShowVertMiddle)
{
cyNewTopHeight = (cyTopHeight + cyBottomHeight == 0) ? 0 : (cyTopHeight * iDestHeight) / (cyTopHeight + cyBottomHeight);
cyNewBottomHeight = iDestHeight - cyNewTopHeight;
}
else
{
cyNewTopHeight = cyTopHeight;
cyNewBottomHeight = cyBottomHeight;
}
// Draw Bottom
// Draw the scan line from (iDestHeight - cyNewBottomHeight) to less than iDestHeight, in screen coordinates
int yMin = max(iDestHeight - cyNewBottomHeight, cyClipMin);
int yMax = min(iDestHeight, cyClipMax);
if (cyClipMax > iDestHeight - cyNewBottomHeight)
{
dng.pvDestBits = pvDestBits;
dng.pvSrcBits = pngiSrc->pvBits;
if (cyBottomHeight == cyNewBottomHeight)
{
int yDiff = yMin - (iDestHeight - cyNewBottomHeight);
dng.pvDestBits += (cyBottomHeight - 1 - yDiff) * DNG_BUF_WIDTH;
dng.pvSrcBits += (cyBottomHeight - 1 - yDiff) * dng.iSrcBufWidth;
for (int y = yMin; y < yMax; y++, dng.pvDestBits -= DNG_BUF_WIDTH, dng.pvSrcBits -= dng.iSrcBufWidth)
{
DNG_DrawRow(&dng);
}
}
else if (cyNewBottomHeight > 0)
{
STRETCH stretch;
DNG_InitStretch(&stretch, cyNewBottomHeight, cyBottomHeight, cyNewBottomHeight - (yMax - iDestHeight + cyNewBottomHeight), cyNewBottomHeight - (yMin - iDestHeight + cyNewBottomHeight));
DNG_StretchCol(&dng, &stretch);
}
}
// Draw Middle
// Draw the scan line from cyNewTopHeight to less than (iDestHeight - cyNewBottomHeight), in screen coordinates
if (fShowVertMiddle && (cyClipMin < iDestHeight - cyNewBottomHeight) && (cyClipMax > cyNewTopHeight))
{
int cySrcTileSize = pngiSrc->iHeight - pngiSrc->margin.cyTopHeight - pngiSrc->margin.cyBottomHeight;
int cyDestTileSize = iDestHeight - pngiSrc->margin.cyTopHeight - pngiSrc->margin.cyBottomHeight;
dng.pvDestBits = pvDestBits + pngiSrc->margin.cyBottomHeight * DNG_BUF_WIDTH;
dng.pvSrcBits = pngiSrc->pvBits + pngiSrc->margin.cyBottomHeight * pngiSrc->iBufWidth;
int yMin = max(cyTopHeight, cyClipMin);
if (dng.fTileMode)
{
// Start off tile
dng.pvDestBits += (cyDestTileSize - 1) * DNG_BUF_WIDTH;
dng.pvSrcBits += (cySrcTileSize - 1) * dng.iSrcBufWidth;
int yDiff = yMin - cyTopHeight;
dng.pvDestBits -= yDiff * DNG_BUF_WIDTH;
int yOffset = (yDiff % cySrcTileSize);
dng.pvSrcBits -= yOffset * dng.iSrcBufWidth;
int iTileOffset = cySrcTileSize - yOffset;
int yMax = min(yMin + min(cySrcTileSize, cyDestTileSize), min(iDestHeight - cyBottomHeight, cyClipMax));
for (int y = yMin; y < yMax; y++, dng.pvDestBits -= DNG_BUF_WIDTH, dng.pvSrcBits -= dng.iSrcBufWidth)
{
DNG_DrawRow(&dng);
iTileOffset--;
if (iTileOffset == 0)
{
iTileOffset = cySrcTileSize;
dng.pvSrcBits += dng.iSrcBufWidth * cySrcTileSize;
}
}
// Repeat tile pattern
dng.pvSrcBits = dng.pvDestBits + (DNG_BUF_WIDTH * cySrcTileSize);
yMin = yMax;
yMax = min(iDestHeight - cyBottomHeight, cyClipMax);
for (int y = yMin; y < yMax; y++, dng.pvDestBits -= DNG_BUF_WIDTH, dng.pvSrcBits -= DNG_BUF_WIDTH)
{
CopyMemory(dng.pvDestBits + dng.cxClipMin, dng.pvSrcBits + dng.cxClipMin, dng.iClipWidth * sizeof(ULONG));
}
}
else
{
int yMax = min(iDestHeight - cyBottomHeight, cyClipMax);
STRETCH stretch;
DNG_InitStretch(&stretch, cyDestTileSize, cySrcTileSize, cyDestTileSize - (yMax - cyTopHeight), cyDestTileSize - (yMin - cyTopHeight));
// Convert from screen coords to DIB coords
DNG_StretchCol(&dng, &stretch);
}
}
// Draw Top
// Draw the scan line from 0 to less than cyNewTopHeight, in screen coordinates
yMin = cyClipMin;
yMax = min(cyNewTopHeight, cyClipMax);
if (cyClipMin < cyNewTopHeight)
{
dng.pvDestBits = pvDestBits + (iDestHeight - cyNewTopHeight) * DNG_BUF_WIDTH;
dng.pvSrcBits = pngiSrc->pvBits + (pngiSrc->iHeight - pngiSrc->margin.cyTopHeight) * pngiSrc->iBufWidth;
if (cyTopHeight == cyNewTopHeight)
{
dng.pvDestBits += (cyTopHeight - 1 - yMin) * DNG_BUF_WIDTH;
dng.pvSrcBits += (cyTopHeight - 1 - yMin) * dng.iSrcBufWidth;
for (int y = yMin; y < yMax; y++, dng.pvDestBits -= DNG_BUF_WIDTH, dng.pvSrcBits -= dng.iSrcBufWidth)
{
DNG_DrawRow(&dng);
}
}
else if (cyNewTopHeight > 0)
{
STRETCH stretch;
DNG_InitStretch(&stretch, cyNewTopHeight, cyTopHeight, cyNewTopHeight - yMax, cyNewTopHeight - yMin);
DNG_StretchCol(&dng, &stretch);
}
}
}
if ((dwFlags & DNG_MUSTFLIP) && ((pngiSrc->dwFlags & NGI_TRANS) || (pngiSrc->dwFlags & NGI_ALPHA)))
{
// Flip the buffer
for (int y = 0; y < DNG_BUF_HEIGHT; y++)
{
ULONG* pvLeftBits = s_pvBitsBuf + (y * DNG_BUF_WIDTH);
ULONG* pvRightBits = s_pvBitsBuf + (y * DNG_BUF_WIDTH) + iClipWidth - 1;
for (int x = 0; x < (iClipWidth / 2); x++)
{
ULONG ulTemp = *pvLeftBits;
*pvLeftBits = *pvRightBits;
*pvRightBits = ulTemp;
pvLeftBits++;
pvRightBits--;
}
}
}
if (pngiSrc->dwFlags & NGI_ALPHA)
{
BLENDFUNCTION bf;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 255;
bf.AlphaFormat = AC_SRC_ALPHA;
GdiAlphaBlend(hdc, rcClip.left, rcClip.top, cxImage, cyImage, s_hdcBuf, 0, 0, cxImage, cyImage, bf);
}
else if (pngiSrc->dwFlags & NGI_TRANS)
{
GdiTransparentBlt(hdc, rcClip.left, rcClip.top, cxImage, cyImage, s_hdcBuf, 0, 0, cxImage, cyImage, pngiSrc->crTrans);
}
else
{
BitBlt(hdc, rcClip.left, rcClip.top, cxImage, cyImage, s_hdcBuf, 0, 0, SRCCOPY);
}
}
else
{
hr = E_OUTOFMEMORY;
}
LeaveCriticalSection(&s_dngLock);
}
}
return hr;
}