689 lines
24 KiB
C++
689 lines
24 KiB
C++
// --------------------------------------------------------------------------
|
|
// 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;
|
|
}
|
|
|