| // Copyright 2015 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| //go:build windows |
| // +build windows |
| |
| package windriver |
| |
| import ( |
| "fmt" |
| "image" |
| "image/color" |
| "image/draw" |
| "syscall" |
| "unsafe" |
| ) |
| |
| func mkbitmap(size image.Point) (syscall.Handle, *byte, error) { |
| bi := _BITMAPINFO{ |
| Header: _BITMAPINFOHEADER{ |
| Size: uint32(unsafe.Sizeof(_BITMAPINFOHEADER{})), |
| Width: int32(size.X), |
| Height: -int32(size.Y), // negative height to force top-down drawing |
| Planes: 1, |
| BitCount: 32, |
| Compression: _BI_RGB, |
| SizeImage: uint32(size.X * size.Y * 4), |
| }, |
| } |
| |
| var ppvBits *byte |
| bitmap, err := _CreateDIBSection(0, &bi, _DIB_RGB_COLORS, &ppvBits, 0, 0) |
| if err != nil { |
| return 0, nil, err |
| } |
| return bitmap, ppvBits, nil |
| } |
| |
| var blendOverFunc = _BLENDFUNCTION{ |
| BlendOp: _AC_SRC_OVER, |
| BlendFlags: 0, |
| SourceConstantAlpha: 255, // only use per-pixel alphas |
| AlphaFormat: _AC_SRC_ALPHA, // premultiplied |
| } |
| |
| func copyBitmapToDC(dc syscall.Handle, dr image.Rectangle, src syscall.Handle, sr image.Rectangle, op draw.Op) (retErr error) { |
| memdc, err := _CreateCompatibleDC(dc) |
| if err != nil { |
| return err |
| } |
| defer _DeleteDC(memdc) |
| |
| prev, err := _SelectObject(memdc, src) |
| if err != nil { |
| return err |
| } |
| defer func() { |
| _, err2 := _SelectObject(memdc, prev) |
| if retErr == nil { |
| retErr = err2 |
| } |
| }() |
| |
| if _GetDeviceCaps(dc, _SHADEBLENDCAPS) == _SB_NONE { |
| // This output device does not support blending capabilities, |
| // so the subsequent output is incorrect, but is the best we |
| // can do on systems that do not support AlphaBlend. |
| op = draw.Src |
| } |
| |
| switch op { |
| case draw.Src: |
| return _StretchBlt(dc, int32(dr.Min.X), int32(dr.Min.Y), int32(dr.Dx()), int32(dr.Dy()), |
| memdc, int32(sr.Min.X), int32(sr.Min.Y), int32(sr.Dx()), int32(sr.Dy()), _SRCCOPY) |
| case draw.Over: |
| return _AlphaBlend(dc, int32(dr.Min.X), int32(dr.Min.Y), int32(dr.Dx()), int32(dr.Dy()), |
| memdc, int32(sr.Min.X), int32(sr.Min.Y), int32(sr.Dx()), int32(sr.Dy()), blendOverFunc.ToUintptr()) |
| default: |
| return fmt.Errorf("windriver: invalid draw operation %v", op) |
| } |
| } |
| |
| func fill(dc syscall.Handle, dr image.Rectangle, c color.Color, op draw.Op) error { |
| r, g, b, a := c.RGBA() |
| r >>= 8 |
| g >>= 8 |
| b >>= 8 |
| a >>= 8 |
| |
| if op == draw.Src { |
| color := _RGB(byte(r), byte(g), byte(b)) |
| brush, err := _CreateSolidBrush(color) |
| if err != nil { |
| return err |
| } |
| defer _DeleteObject(brush) |
| |
| rect := _RECT{ |
| Left: int32(dr.Min.X), |
| Top: int32(dr.Min.Y), |
| Right: int32(dr.Max.X), |
| Bottom: int32(dr.Max.Y), |
| } |
| return _FillRect(dc, &rect, brush) |
| } |
| |
| // AlphaBlend will stretch the input image (using StretchBlt's |
| // COLORONCOLOR mode) to fill the output rectangle. Testing |
| // this shows that the result appears to be the same as if we had |
| // used a MxN bitmap instead. |
| sr := image.Rect(0, 0, 1, 1) |
| bitmap, bitvalues, err := mkbitmap(sr.Size()) |
| if err != nil { |
| return err |
| } |
| defer _DeleteObject(bitmap) // TODO handle error? |
| |
| color := _COLORREF((a << 24) | (r << 16) | (g << 8) | b) |
| *(*_COLORREF)(unsafe.Pointer(bitvalues)) = color |
| |
| return copyBitmapToDC(dc, dr, bitmap, sr, draw.Over) |
| } |