Add alpha blending support to surfaces
diff --git a/vncviewer/Surface_OSX.cxx b/vncviewer/Surface_OSX.cxx
index dbf0c41..73c10f4 100644
--- a/vncviewer/Surface_OSX.cxx
+++ b/vncviewer/Surface_OSX.cxx
@@ -28,7 +28,7 @@
 
 #include "Surface.h"
 
-static void render(CGContextRef gc, CGImageRef image,
+static void render(CGContextRef gc, CGImageRef image, CGBlendMode mode,
                    int src_x, int src_y, int src_w, int src_h,
                    int x, int y, int w, int h)
 {
@@ -36,6 +36,8 @@
 
   CGContextSaveGState(gc);
 
+  CGContextSetBlendMode(gc, mode);
+
   // We have to use clipping to partially display an image
   rect.origin.x = x;
   rect.origin.y = y;
@@ -54,6 +56,27 @@
   CGContextRestoreGState(gc);
 }
 
+static CGContextRef make_bitmap(int width, int height, unsigned char* data)
+{
+  CGColorSpaceRef lut;
+  CGContextRef bitmap;
+
+  lut = CGDisplayCopyColorSpace(kCGDirectMainDisplay);
+  if (!lut) {
+    lut = CGColorSpaceCreateDeviceRGB();
+    if (!lut)
+      throw rdr::Exception("CGColorSpaceCreateDeviceRGB");
+  }
+
+  bitmap = CGBitmapContextCreate(data, width, height, 8, width*4, lut,
+                                 kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);
+  CGColorSpaceRelease(lut);
+  if (!bitmap)
+    throw rdr::Exception("CGBitmapContextCreate");
+
+  return bitmap;
+}
+
 void Surface::clear(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
 {
   unsigned char* out;
@@ -86,35 +109,58 @@
   src_y = height() - (src_y + h);
   y = Fl_Window::current()->h() - (y + h);
 
-  render(fl_gc, image, src_x, src_y, width(), height(), x, y, w, h);
+  render(fl_gc, image, kCGBlendModeCopy,
+         src_x, src_y, width(), height(), x, y, w, h);
 
   CGContextRestoreGState(fl_gc);
 }
 
 void Surface::draw(Surface* dst, int src_x, int src_y, int x, int y, int w, int h)
 {
-  CGColorSpaceRef lut;
   CGContextRef bitmap;
 
-  lut = CGDisplayCopyColorSpace(kCGDirectMainDisplay);
-  if (!lut) {
-    lut = CGColorSpaceCreateDeviceRGB();
-    if (!lut)
-      throw rdr::Exception("CGColorSpaceCreateDeviceRGB");
-  }
-
-  bitmap = CGBitmapContextCreate(dst->data, dst->width(),
-                                 dst->height(), 8, dst->width()*4, lut,
-                                 kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little);
-  CGColorSpaceRelease(lut);
-  if (!bitmap)
-    throw rdr::Exception("CGBitmapContextCreate");
+  bitmap = make_bitmap(dst->width(), dst->height(), dst->data);
 
   // macOS Coordinates are from bottom left, not top left
   src_y = height() - (src_y + h);
   y = dst->height() - (y + h);
 
-  render(bitmap, image, src_x, src_y, width(), height(), x, y, w, h);
+  render(bitmap, image, kCGBlendModeCopy,
+         src_x, src_y, width(), height(), x, y, w, h);
+
+  CGContextRelease(bitmap);
+}
+
+void Surface::blend(int src_x, int src_y, int x, int y, int w, int h)
+{
+  CGContextSaveGState(fl_gc);
+
+  // Reset the transformation matrix back to the default identity
+  // matrix as otherwise we get a massive performance hit
+  CGContextConcatCTM(fl_gc, CGAffineTransformInvert(CGContextGetCTM(fl_gc)));
+
+  // macOS Coordinates are from bottom left, not top left
+  src_y = height() - (src_y + h);
+  y = Fl_Window::current()->h() - (y + h);
+
+  render(fl_gc, image, kCGBlendModeNormal,
+         src_x, src_y, width(), height(), x, y, w, h);
+
+  CGContextRestoreGState(fl_gc);
+}
+
+void Surface::blend(Surface* dst, int src_x, int src_y, int x, int y, int w, int h)
+{
+  CGContextRef bitmap;
+
+  bitmap = make_bitmap(dst->width(), dst->height(), dst->data);
+
+  // macOS Coordinates are from bottom left, not top left
+  src_y = height() - (src_y + h);
+  y = dst->height() - (y + h);
+
+  render(bitmap, image, kCGBlendModeNormal,
+         src_x, src_y, width(), height(), x, y, w, h);
 
   CGContextRelease(bitmap);
 }
@@ -139,7 +185,7 @@
     throw rdr::Exception("CGDataProviderCreateWithData");
 
   image = CGImageCreate(width(), height(), 8, 32, width() * 4, lut,
-                        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little,
+                        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little,
                         provider, NULL, false, kCGRenderingIntentDefault);
   CGColorSpaceRelease(lut);
   CGDataProviderRelease(provider);