/* Copyright Krzysztof Kowalczyk 2006-2007 License: GPLv2 */ /* This is a preview support for perf-test for Windows */ #include #include #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(); }