blob: 2d53335e6ba77bd699d8c44f0c6295991e7d9aa6 [file] [log] [blame] [edit]
/* Copyright Krzysztof Kowalczyk 2006-2007
License: GPLv2 */
/* This is a preview support for perf-test for Windows */
#include <windows.h>
#include <assert.h>
#include "SplashBitmap.h"
#define WIN_CLASS_NAME "PDFTEST_PDF_WIN"
#define COL_WINDOW_BG RGB(0xff, 0xff, 0xff)
static HWND gHwndSplash;
static HBRUSH gBrushBg;
static SplashBitmap *gBmpSplash;
int rect_dx(RECT *r)
{
int dx = r->right - r->left;
assert(dx >= 0);
return dx;
}
int rect_dy(RECT *r)
{
int dy = r->bottom - r->top;
assert(dy >= 0);
return dy;
}
static HBITMAP createDIBitmapCommon(SplashBitmap *bmp, HDC hdc)
{
int bmpDx = bmp->getWidth();
int bmpDy = bmp->getHeight();
int bmpRowSize = bmp->getRowSize();
BITMAPINFOHEADER bmih;
bmih.biSize = sizeof(bmih);
bmih.biHeight = -bmpDy;
bmih.biWidth = bmpDx;
bmih.biPlanes = 1;
bmih.biBitCount = 24;
bmih.biCompression = BI_RGB;
bmih.biSizeImage = bmpDy * bmpRowSize;;
bmih.biXPelsPerMeter = bmih.biYPelsPerMeter = 0;
bmih.biClrUsed = bmih.biClrImportant = 0;
unsigned char* bmpData = bmp->getDataPtr();
HBITMAP hbmp = ::CreateDIBitmap(hdc, &bmih, CBM_INIT, bmpData, (BITMAPINFO *)&bmih , DIB_RGB_COLORS);
return hbmp;
}
static void stretchDIBitsCommon(SplashBitmap *bmp, HDC hdc, int leftMargin, int topMargin, int pageDx, int pageDy)
{
int bmpDx = bmp->getWidth();
int bmpDy = bmp->getHeight();
int bmpRowSize = bmp->getRowSize();
BITMAPINFOHEADER bmih;
bmih.biSize = sizeof(bmih);
bmih.biHeight = -bmpDy;
bmih.biWidth = bmpDx;
bmih.biPlanes = 1;
// we could create this dibsection in monochrome
// if the printer is monochrome, to reduce memory consumption
// but splash is currently setup to return a full colour bitmap
bmih.biBitCount = 24;
bmih.biCompression = BI_RGB;
bmih.biSizeImage = bmpDy * bmpRowSize;;
bmih.biXPelsPerMeter = bmih.biYPelsPerMeter = 0;
bmih.biClrUsed = bmih.biClrImportant = 0;
SplashColorPtr bmpData = bmp->getDataPtr();
::StretchDIBits(hdc,
// destination rectangle
-leftMargin, -topMargin, pageDx, pageDy,
// source rectangle
0, 0, bmpDx, bmpDy,
bmpData,
(BITMAPINFO *)&bmih ,
DIB_RGB_COLORS,
SRCCOPY);
}
/* Set the client area size of the window 'hwnd' to 'dx'/'dy'. */
static void resizeClientArea(HWND hwnd, int x, int dx, int dy, int *dx_out)
{
RECT rc;
GetClientRect(hwnd, &rc);
if ((rect_dx(&rc) == dx) && (rect_dy(&rc) == dy))
return;
RECT rw;
GetWindowRect(hwnd, &rw);
int win_dx = rect_dx(&rw) + (dx - rect_dx(&rc));
int win_dy = rect_dy(&rw) + (dy - rect_dy(&rc));
SetWindowPos(hwnd, NULL, x, 0, win_dx, win_dy, SWP_NOACTIVATE | SWP_NOREPOSITION | SWP_NOZORDER);
if (dx_out)
*dx_out = win_dx;
}
static void resizeClientAreaToRenderedBitmap(HWND hwnd, SplashBitmap *bmp, int x, int *dxOut)
{
int dx = bmp->getWidth();
int dy = bmp->getHeight();
resizeClientArea(hwnd, x, dx, dy, dxOut);
}
static void drawBitmap(HWND hwnd, SplashBitmap *bmp)
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
SetBkMode(hdc, TRANSPARENT);
FillRect(hdc, &ps.rcPaint, gBrushBg);
HBITMAP hbmp = createDIBitmapCommon(bmp, hdc);
if (hbmp) {
HDC bmpDC = CreateCompatibleDC(hdc);
if (bmpDC) {
SelectObject(bmpDC, hbmp);
int xSrc = 0, ySrc = 0;
int xDest = 0, yDest = 0;
int bmpDx = bmp->getWidth();
int bmpDy = bmp->getHeight();
BitBlt(hdc, xDest, yDest, bmpDx, bmpDy, bmpDC, xSrc, ySrc, SRCCOPY);
DeleteDC(bmpDC);
bmpDC = NULL;
}
DeleteObject(hbmp);
hbmp = NULL;
}
EndPaint(hwnd, &ps);
}
static void onPaint(HWND hwnd)
{
if (hwnd == gHwndSplash) {
if (gBmpSplash) {
drawBitmap(hwnd, gBmpSplash);
}
}
}
static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
// do nothing
break;
case WM_ERASEBKGND:
return TRUE;
case WM_PAINT:
/* it might happen that we get WM_PAINT after destroying a window */
onPaint(hwnd);
break;
case WM_DESTROY:
/* WM_DESTROY might be sent as a result of File\Close, in which case CloseWindow() has already been called */
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
static BOOL registerWinClass(void)
{
WNDCLASSEX wcex;
ATOM atom;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = NULL;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = NULL;
wcex.lpszMenuName = NULL;
wcex.lpszClassName = WIN_CLASS_NAME;
wcex.hIconSm = NULL;
atom = RegisterClassEx(&wcex);
if (atom)
return TRUE;
return FALSE;
}
static bool initWinIfNecessary(void)
{
if (gHwndSplash)
return true;
if (!registerWinClass())
return false;
gBrushBg = CreateSolidBrush(COL_WINDOW_BG);
gHwndSplash = CreateWindow(
WIN_CLASS_NAME, "Splash",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0,
CW_USEDEFAULT, 0,
NULL, NULL,
NULL, NULL);
if (!gHwndSplash)
return false;
ShowWindow(gHwndSplash, SW_HIDE);
return true;
}
static void pumpMessages(void)
{
BOOL isMessage;
MSG msg;
for (;;) {
isMessage = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
if (!isMessage)
return;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
void PreviewBitmapInit(void)
{
/* no need to do anything */
}
void PreviewBitmapDestroy(void)
{
PostQuitMessage(0);
pumpMessages();
DeleteObject(gBrushBg);
}
static void UpdateWindows(void)
{
if (gBmpSplash) {
resizeClientAreaToRenderedBitmap(gHwndSplash, gBmpSplash, 0, NULL);
ShowWindow(gHwndSplash, SW_SHOW);
InvalidateRect(gHwndSplash, NULL, FALSE);
UpdateWindow(gHwndSplash);
} else {
ShowWindow(gHwndSplash, SW_HIDE);
}
pumpMessages();
}
void PreviewBitmapSplash(SplashBitmap *bmpSplash)
{
if (!initWinIfNecessary())
return;
gBmpSplash = bmpSplash;
UpdateWindows();
}