First draw call alpha can't be 0 or 1 on Win32 surface
I'm working on a Win32 app with layered windows. The window contents are drawn using Cairo. The transparency is very unpredictable however. It seems like the first draw call can't have an alpha value of exactly 1 or 0. It might be related to #476.
This is the most minimal example I could reduce the problem to. It should draw a square in the upper left corner of the screen, with both the left and right half opaque black.
import core.sys.windows.windows;
import std.utf;
import std.stdio;
import cairo;
import cairo_win32;
const UINT WIDTH = 500;
const UINT HEIGHT = 500;
extern(Windows)
LRESULT WndProc(HWND hwnd, uint msg, WPARAM wParam, LPARAM lParam) nothrow {
return DefWindowProc(hwnd, msg, wParam, lParam);
}
void main(string[] args) {
WNDCLASS wndclass;
wndclass.lpszClassName = "Test".toUTF16z;
wndclass.lpfnWndProc = &WndProc;
RegisterClass(&wndclass);
HINSTANCE hInstance = GetModuleHandle(NULL);
HWND hwnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TOOLWINDOW, wndclass.lpszClassName, "Test".toUTF16z, WS_POPUP, 50, 50, WIDTH, HEIGHT, NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, SW_SHOWNA);
HDC hdcScreen = GetDC(NULL);
// Offscreen hdc for painting
HDC hdcMem = CreateCompatibleDC(hdcScreen);
HBITMAP hbmMem = CreateCompatibleBitmap(hdcScreen, WIDTH, HEIGHT);
auto hOld = SelectObject(hdcMem, hbmMem);
// Draw using offscreen hdc
auto surface = cairo_win32_surface_create(hdcMem);
auto cr = cairo_create(surface);
// Almost opaque black
cairo_rectangle(cr, 0, 0, 250, HEIGHT);
cairo_set_source_rgba(cr, 1.0, 0, 0, 0.99);
cairo_fill(cr);
// Opaque black
cairo_rectangle(cr, 250, 0, 250, HEIGHT);
cairo_set_source_rgba(cr, 0, 0, 0, 1.0);
cairo_fill(cr);
cairo_destroy(cr);
cairo_surface_destroy(surface);
// Show on screen
BLENDFUNCTION blend = { 0 };
blend.BlendOp = AC_SRC_OVER;
blend.SourceConstantAlpha = 255;
blend.AlphaFormat = AC_SRC_ALPHA;
RECT win_rect;
GetWindowRect(hwnd, &win_rect);
POINT ptZero = POINT(0, 0);
POINT win_pos = POINT(win_rect.left, win_rect.top);
SIZE win_dims = SIZE(WIDTH, HEIGHT);
UpdateLayeredWindow(hwnd, hdcScreen, &win_pos, &win_dims, hdcMem, &ptZero, RGB(0, 0, 0), &blend, ULW_ALPHA);
// Reset offscreen hdc to default bitmap
SelectObject(hdcMem, hOld);
// Cleanup
DeleteObject(hbmMem);
DeleteDC (hdcMem);
ReleaseDC(NULL, hdcScreen);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
This works, as you can see here.
However, when I now change the first calls alpha to 1.0 like this:
// Actually opaque black
cairo_rectangle(cr, 0, 0, 250, HEIGHT);
cairo_set_source_rgba(cr, 0, 0, 0, 1.0);
cairo_fill(cr);
// Opaque black
cairo_rectangle(cr, 250, 0, 250, HEIGHT);
cairo_set_source_rgba(cr, 0, 0, 0, 1.0);
cairo_fill(cr);
Then everything vanishes.
Same thing happens with an alpha of 0.0.
I tried to create an image surface with CAIRO_FORMAT_ARGB32
, used the exact same drawing operations and wrote it to a PNG file. In that case both images look correct and identical.