blob: b5e6b15f3161e4ceeb1ff1811da3a5f6faf5926e [file] [log] [blame]
// 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)
}