/* 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(); | |
} | |