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