github.com/as/shiny@v0.8.2/driver/windriver/windraw.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build windows
     6  
     7  package windriver
     8  
     9  import (
    10  	"fmt"
    11  	"image"
    12  	"image/color"
    13  	"image/draw"
    14  	"syscall"
    15  	"unsafe"
    16  
    17  	"github.com/as/shiny/driver/win32"
    18  )
    19  
    20  func mkbitmap(size image.Point) (syscall.Handle, *byte, error) {
    21  	bi := win32.BitmapInfo{
    22  		Header: win32.BitmapInfoV4{
    23  			Size:        uint32(unsafe.Sizeof(win32.BitmapInfoV4{})),
    24  			Width:       int32(size.X),
    25  			Height:      -int32(size.Y), // negative height to force top-down drawing
    26  			Planes:      1,
    27  			BitCount:    32,
    28  			Compression: win32.BiRGB,
    29  			SizeImage:   uint32(size.X * size.Y * 4),
    30  		},
    31  	}
    32  
    33  	var ppvBits *byte
    34  	bitmap, err := win32.CreateDIBSection(0, &bi, win32.DibRGBColors, &ppvBits, 0, 0)
    35  	if err != nil {
    36  		return 0, nil, err
    37  	}
    38  	return bitmap, ppvBits, nil
    39  }
    40  
    41  var blendOverFunc = win32.BlendFunc{
    42  	Op:            win32.AcSrcOver,
    43  	Flags:         0,
    44  	SrcConstAlpha: 255,              // only use per-pixel alphas
    45  	AlphaFormat:   win32.AcSrcAlpha, // premultiplied
    46  }
    47  
    48  func copyBitmapToDC(dc syscall.Handle, dr image.Rectangle, src syscall.Handle, sr image.Rectangle, op draw.Op) (retErr error) {
    49  	memdc, err := win32.CreateCompatibleDC(dc)
    50  	if err != nil {
    51  		return err
    52  	}
    53  	defer win32.DeleteDC(memdc)
    54  
    55  	_, err = win32.SelectObject(memdc, src)
    56  	if err != nil {
    57  		return err
    58  	}
    59  
    60  	switch op {
    61  	case draw.Src:
    62  		return win32.StretchBlt(dc, int32(dr.Min.X), int32(dr.Min.Y), int32(dr.Dx()), int32(dr.Dy()),
    63  			memdc, int32(sr.Min.X), int32(sr.Min.Y), int32(sr.Dx()), int32(sr.Dy()), win32.SrcCopy)
    64  	case draw.Over:
    65  		return win32.AlphaBlend(dc, int32(dr.Min.X), int32(dr.Min.Y), int32(dr.Dx()), int32(dr.Dy()),
    66  			memdc, int32(sr.Min.X), int32(sr.Min.Y), int32(sr.Dx()), int32(sr.Dy()), blendOverFunc.Uintptr())
    67  	default:
    68  		return fmt.Errorf("windriver: invalid draw operation %v", op)
    69  	}
    70  }
    71  
    72  func fill(dc syscall.Handle, dr image.Rectangle, c color.Color, op draw.Op) error {
    73  	const bgrmask = ((1 << 24) - 1)
    74  	cr := win32.NewColorRef(c)
    75  
    76  	if op == draw.Src {
    77  		brush, err := win32.CreateSolidBrush(cr & bgrmask)
    78  		if err != nil {
    79  			return err
    80  		}
    81  		defer win32.DeleteObject(brush)
    82  
    83  		return win32.FillRect(dc, &win32.Rectangle{
    84  			win32.Point{int32(dr.Min.X), int32(dr.Min.Y)},
    85  			win32.Point{int32(dr.Max.X), int32(dr.Max.Y)},
    86  		}, brush)
    87  	}
    88  
    89  	// AlphaBlend will stretch the input image (using StretchBlt's
    90  	// COLORONCOLOR mode) to fill the output rectangle. Testing
    91  	// this shows that the result appears to be the same as if we had
    92  	// used a MxN bitmap instead.
    93  	sr := image.Rectangle{image.ZP, image.Point{1, 1}}
    94  	bitmap, bitvalues, err := mkbitmap(sr.Max)
    95  	if err != nil {
    96  		return err
    97  	}
    98  	defer win32.DeleteObject(bitmap)
    99  
   100  	*(*win32.ColorRef)(unsafe.Pointer(bitvalues)) = cr
   101  
   102  	return copyBitmapToDC(dc, dr, bitmap, sr, draw.Over)
   103  }