[PATCH 08/25] Convert VncConnection over to use VncFramebuffer object



Remove the vnc_framebuffer struct, and make VncConnection use the
new VncFramebuffer object.

VncDisplay is changed to use the VncImageFramebuffer object
type as its implementation of VncFramebuffer
---
 src/blt.h                |  334 ------------------------------------
 src/blt1.h               |   31 ----
 src/vncbaseframebuffer.c |   10 +
 src/vncconnection.c      |  423 ++++++++++++++++++----------------------------
 src/vncconnection.h      |   29 +---
 src/vncconnectionblt.h   |  163 ++++++++++++++++++
 src/vncdisplay.c         |  195 +++++++++++-----------
 7 files changed, 440 insertions(+), 745 deletions(-)
 delete mode 100644 src/blt.h
 delete mode 100644 src/blt1.h
 create mode 100644 src/vncconnectionblt.h

diff --git a/src/blt.h b/src/blt.h
deleted file mode 100644
index 66ce688..0000000
--- a/src/blt.h
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * GTK VNC Widget
- *
- * Copyright (C) 2006  Anthony Liguori <anthony codemonkey ws>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.0 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-/* Ordering of the SPLICE calls here is important to avoid
- * a Solaris compiler/cpp  whitespace bug
- */
-#define src_pixel_t SPLICE(SPLICE(uint, SRC), _t)
-#define ssrc_pixel_t SPLICE(SPLICE(int, SRC), _t)
-#define dst_pixel_t SPLICE(SPLICE(uint, DST), _t)
-#define SUFFIX() SPLICE(SRC,SPLICE(x,DST))
-#define SET_PIXEL SPLICE(vnc_connection_set_pixel_, SUFFIX())
-#define SET_PIXEL_AT SPLICE(vnc_connection_set_pixel_at_, SUFFIX())
-#define BLIT SPLICE(vnc_connection_blt_, SUFFIX())
-#define FILL SPLICE(vnc_connection_fill_, SUFFIX())
-#define FAST_FILL SPLICE(vnc_connection_fill_fast_, SUFFIX())
-#define HEXTILE SPLICE(vnc_connection_hextile_, SUFFIX())
-#define RRE SPLICE(vnc_connection_rre_, SUFFIX())
-#define RICH_CURSOR_BLIT SPLICE(vnc_connection_rich_cursor_blt_, SUFFIX())
-#define RGB24_BLIT SPLICE(vnc_connection_rgb24_blt_, SUFFIX())
-#define TIGHT_COMPUTE_PREDICTED SPLICE(vnc_connection_tight_compute_predicted_, SUFFIX())
-#define TIGHT_SUM_PIXEL SPLICE(vnc_connection_tight_sum_pixel_, SUFFIX())
-#define SWAP_RFB(conn, pixel) SPLICE(vnc_connection_swap_rfb_, SRC)(conn, pixel)
-#define SWAP_IMG(conn, pixel) SPLICE(vnc_connection_swap_img_, DST)(conn, pixel)
-#define COMPONENT(color, pixel) ((SWAP_RFB(conn, pixel) >> conn->fmt.SPLICE(color, _shift) & conn->fmt.SPLICE(color, _max)))
-
-static void FAST_FILL(VncConnection *conn, src_pixel_t *sp,
-		      int x, int y, int width, int height)
-{
-	guint8 *dst = vnc_connection_get_local(conn, x, y);
-	int i;
-
-	for (i = 0; i < 1; i++) {
-		int j;
-		dst_pixel_t *dp = (dst_pixel_t *)dst;
-
-		for (j = 0; j < width; j++) {
-			*dp = *sp;
-			dp++;
-		}
-		dst += conn->local.linesize;
-	}
-	for (i = 1; i < height; i++) {
-		memcpy(dst, dst - conn->local.linesize, width * sizeof(*sp));
-		dst += conn->local.linesize;
-	}
-}
-
-static void SET_PIXEL(VncConnection *conn, dst_pixel_t *dp, src_pixel_t sp)
-{
-	*dp = SWAP_IMG(conn, ((sp >> conn->rrs) & conn->rm) << conn->rls
-		       | ((sp >> conn->grs) & conn->gm) << conn->gls
-		       | ((sp >> conn->brs) & conn->bm) << conn->bls);
-}
-
-static void SET_PIXEL_AT(VncConnection *conn, int x, int y, src_pixel_t *sp)
-{
-	dst_pixel_t *dp = (dst_pixel_t *)vnc_connection_get_local(conn, x, y);
-
-	SET_PIXEL(conn, dp, SWAP_RFB(conn, *sp));
-}
-
-static void FILL(VncConnection *conn, src_pixel_t *sp,
-		 int x, int y, int width, int height)
-{
-	guint8 *dst = vnc_connection_get_local(conn, x, y);
-	int i;
-
-	for (i = 0; i < 1; i++) {
-		dst_pixel_t *dp = (dst_pixel_t *)dst;
-		int j;
-
-		for (j = 0; j < width; j++) {
-			SET_PIXEL(conn, dp, SWAP_RFB(conn, *sp));
-			dp++;
-		}
-		dst += conn->local.linesize;
-	}
-	for (i = 1; i < height; i++) {
-		memcpy(dst, dst - conn->local.linesize, width * sizeof(dst_pixel_t));
-		dst += conn->local.linesize;
-	}
-}
-
-static void BLIT(VncConnection *conn, guint8 *src, int pitch, int x, int y, int w, int h)
-{
-	guint8 *dst = vnc_connection_get_local(conn, x, y);
-	int i;
-
-	for (i = 0; i < h; i++) {
-		dst_pixel_t *dp = (dst_pixel_t *)dst;
-		src_pixel_t *sp = (src_pixel_t *)src;
-		int j;
-
-		for (j = 0; j < w; j++) {
-			SET_PIXEL(conn, dp, SWAP_RFB(conn, *sp));
-			dp++;
-			sp++;
-		}
-		dst += conn->local.linesize;
-		src += pitch;
-	}
-}
-
-static void HEXTILE(VncConnection *conn, guint8 flags, guint16 x, guint16 y,
-		    guint16 width, guint16 height, src_pixel_t *fg, src_pixel_t *bg)
-{
-	int stride = width * sizeof(src_pixel_t);
-	int i;
-
-	if (flags & 0x01) {
-		/* Raw tile */
-		if (conn->perfect_match) {
-			guint8 *dst = vnc_connection_get_local(conn, x, y);
-
-			for (i = 0; i < height; i++) {
-				vnc_connection_read(conn, dst, stride);
-				dst += conn->local.linesize;
-			}
-		} else {
-			guint8 data[16 * 16 * sizeof(src_pixel_t)];
-
-			vnc_connection_read(conn, data, stride * height);
-			BLIT(conn, data, stride, x, y, width, height);
-		}
-	} else {
-		/* Background Specified */
-		if (flags & 0x02)
-			vnc_connection_read(conn, bg, sizeof(*bg));
-
-		/* Foreground Specified */
-		if (flags & 0x04)
-			vnc_connection_read(conn, fg, sizeof(*fg));
-
-		if (conn->perfect_match)
-			FAST_FILL(conn, bg, x, y, width, height);
-		else
-			FILL(conn, bg, x, y, width, height);
-
-
-		/* AnySubrects */
-		if (flags & 0x08) {
-			guint8 n_rects = vnc_connection_read_u8(conn);
-
-			for (i = 0; i < n_rects; i++) {
-				guint8 xy, wh;
-
-				/* SubrectsColored */
-				if (flags & 0x10)
-					vnc_connection_read(conn, fg, sizeof(*fg));
-
-				xy = vnc_connection_read_u8(conn);
-				wh = vnc_connection_read_u8(conn);
-
-
-				if (conn->perfect_match)
-					FAST_FILL(conn, fg,
-						  x + nibhi(xy), y + niblo(xy),
-						  nibhi(wh) + 1, niblo(wh) + 1);
-				else
-					FILL(conn, fg,
-					     x + nibhi(xy), y + niblo(xy),
-					     nibhi(wh) + 1, niblo(wh) + 1);
-			}
-		}
-	}
-}
-
-/* We need to convert to a GdkPixbuf which is always 32-bit */
-#if DST == 32
-static void RICH_CURSOR_BLIT(VncConnection *conn, guint8 *pixbuf,
-			     guint8 *image, guint8 *mask, int pitch,
-			     guint16 width, guint16 height)
-{
-	int x1, y1;
-	guint32 *dst = (guint32 *)pixbuf;
-	guint8 *src = image;
-	guint8 *alpha = mask;
-	int as, rs, gs, bs, n;
-
-	/*
-	 * GdkPixbuf is always 32-bit RGB, so we can't use the precomputed
-	 * left / right shift data from conn->{r,g,b}{r,l}s. The latter
-	 * is set for the local display depth, which may be different
-	 * to GdkPixbuf's fixed 32-bit RGBA
-	 *
-	 * This function isn't called often, so just re-compute them now
-	 */
-
-#if G_BYTE_ORDER == G_BIG_ENDIAN
-	as = 0;
-	rs = 8;
-	gs = 16;
-	bs = 24;
-#else
-	as = 24;
-	rs = 16;
-	gs = 8;
-	bs = 0;
-#endif
-
-	/* Then this adjusts for remote having less bpp than 32 */
-	for (n = 255 ; n > conn->fmt.red_max ; n>>= 1)
-		rs++;
-	for (n = 255 ; n > conn->fmt.green_max ; n>>= 1)
-		gs++;
-	for (n = 255 ; n > conn->fmt.blue_max ; n>>= 1)
-		bs++;
-
-	for (y1 = 0; y1 < height; y1++) {
-		src_pixel_t *sp = (src_pixel_t *)src;
-		guint8 *mp = alpha;
-		for (x1 = 0; x1 < width; x1++) {
-			*dst = (COMPONENT(red, *sp) << rs)
-				| (COMPONENT(green, *sp) << gs)
-				| (COMPONENT(blue, *sp) << bs);
-
-			if ((mp[x1 / 8] >> (7 - (x1 % 8))) & 1)
-				*dst |= (0xFF << as);
-
-			dst++;
-			sp++;
-		}
-		src += pitch;
-		alpha += ((width + 7) / 8);
-	}
-}
-#endif
-
-#if SRC == 32
-static void RGB24_BLIT(VncConnection *conn, int x, int y, int width, int height,
-		       guint8 *data, int pitch)
-{
-	guint8 *dst = vnc_connection_get_local(conn, x, y);
-	int i, j;
-
-	for (j = 0; j < height; j++) {
-		dst_pixel_t *dp = (dst_pixel_t *)dst;
-		guint8 *sp = data;
-
-		for (i = 0; i < width; i++) {
-			/*
-			 * We use conn->fmt.XXX_shift instead of usual conn->Xls
-			 * because the source pixel component is a full 8 bits in
-			 * size, and so doesn't need the adjusted shift
-			 */
-			*dp = (((sp[0] * conn->fmt.red_max) / 255) << conn->fmt.red_shift) |
-				(((sp[1] * conn->fmt.green_max) / 255) << conn->fmt.green_shift) |
-				(((sp[2] * conn->fmt.blue_max) / 255) << conn->fmt.blue_shift);
-			dp++;
-			sp += 3;
-		}
-
-		dst += conn->local.linesize;
-		data += pitch;
-	}
-}
-#endif
-
-#if SRC == DST
-
-static void TIGHT_COMPUTE_PREDICTED(VncConnection *conn, src_pixel_t *ppixel,
-				    src_pixel_t *lp, src_pixel_t *cp,
-				    src_pixel_t *llp)
-{
-	ssrc_pixel_t red, green, blue;
-
-	red = COMPONENT(red, *lp) + COMPONENT(red, *cp) - COMPONENT(red, *llp);
-	red = MAX(red, 0);
-	red = MIN(red, conn->fmt.red_max);
-
-	green = COMPONENT(green, *lp) + COMPONENT(green, *cp) - COMPONENT(green, *llp);
-	green = MAX(green, 0);
-	green = MIN(green, conn->fmt.green_max);
-
-	blue = COMPONENT(blue, *lp) + COMPONENT(blue, *cp) - COMPONENT(blue, *llp);
-	blue = MAX(blue, 0);
-	blue = MIN(blue, conn->fmt.blue_max);
-
-	*ppixel = SWAP_RFB(conn,
-		       (red << conn->fmt.red_shift) |
-		       (green << conn->fmt.green_shift) |
-		       (blue << conn->fmt.blue_shift));
-}
-
-static void TIGHT_SUM_PIXEL(VncConnection *conn,
-			    src_pixel_t *lhs, src_pixel_t *rhs)
-{
-	src_pixel_t red, green, blue;
-
-	red = COMPONENT(red, *lhs) + COMPONENT(red, *rhs);
-	green = COMPONENT(green, *lhs) + COMPONENT(green, *rhs);
-	blue = COMPONENT(blue, *lhs) + COMPONENT(blue, *rhs);
-
-	*lhs = SWAP_RFB(conn,
-		    ((red & conn->fmt.red_max) << conn->fmt.red_shift) |
-		    ((green & conn->fmt.green_max) << conn->fmt.green_shift) |
-		    ((blue & conn->fmt.blue_max) << conn->fmt.blue_shift));
-}
-
-#endif
-
-#undef COMPONENT
-#undef HEXTILE
-#undef FILL
-#undef FAST_FILL
-#undef BLIT
-#undef dst_pixel_t
-#undef src_pixel_t
-
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- *  tab-width: 8
- * End:
- */
diff --git a/src/blt1.h b/src/blt1.h
deleted file mode 100644
index 9bdda04..0000000
--- a/src/blt1.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * GTK VNC Widget
- *
- * Copyright (C) 2006  Anthony Liguori <anthony codemonkey ws>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.0 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#define DST 8
-#include "blt.h"
-#undef DST
-
-#define DST 16
-#include "blt.h"
-#undef DST
-
-#define DST 32
-#include "blt.h"
-#undef DST
diff --git a/src/vncbaseframebuffer.c b/src/vncbaseframebuffer.c
index f7dab3b..1651870 100644
--- a/src/vncbaseframebuffer.c
+++ b/src/vncbaseframebuffer.c
@@ -351,6 +351,15 @@ static const VncPixelFormat *vnc_base_framebuffer_get_remote_format(VncFramebuff
 }
 
 
+static gboolean vnc_base_framebuffer_perfect_format_match(VncFramebuffer *iface)
+{
+	VncBaseFramebuffer *fb = VNC_BASE_FRAMEBUFFER(iface);
+	VncBaseFramebufferPrivate *priv = fb->priv;
+
+	return priv->perfect_match;
+}
+
+
 static guint8 vnc_base_framebuffer_swap_img_8(VncBaseFramebufferPrivate *priv G_GNUC_UNUSED, guint8 pixel)
 {
 	return pixel;
@@ -710,6 +719,7 @@ static void vnc_base_framebuffer_interface_init(gpointer g_iface,
     iface->get_buffer = vnc_base_framebuffer_get_buffer;
     iface->get_local_format = vnc_base_framebuffer_get_local_format;
     iface->get_remote_format = vnc_base_framebuffer_get_remote_format;
+    iface->perfect_format_match = vnc_base_framebuffer_perfect_format_match;
 
     iface->set_pixel_at = vnc_base_framebuffer_set_pixel_at;
     iface->fill = vnc_base_framebuffer_fill;
diff --git a/src/vncconnection.c b/src/vncconnection.c
index 6b0f465..35e54da 100644
--- a/src/vncconnection.c
+++ b/src/vncconnection.c
@@ -71,23 +71,9 @@ struct wait_queue
 };
 
 
-typedef void vnc_connection_blt_func(VncConnection *conn, guint8 *, int, int, int, int, int);
-
-typedef void vnc_connection_fill_func(VncConnection *conn, guint8 *, int, int, int, int);
-
-typedef void vnc_connection_set_pixel_at_func(VncConnection *conn, int, int, guint8 *);
-
-typedef void vnc_connection_hextile_func(VncConnection *conn, guint8 flags,
-					  guint16 x, guint16 y,
-					  guint16 width, guint16 height,
-					  guint8 *fg, guint8 *bg);
-
 typedef void vnc_connection_rich_cursor_blt_func(VncConnection *conn, guint8 *, guint8 *,
 						  guint8 *, int, guint16, guint16);
 
-typedef void vnc_connection_rgb24_blt_func(VncConnection *conn, int, int, int, int,
-					    guint8 *, int);
-
 typedef void vnc_connection_tight_compute_predicted_func(VncConnection *conn, guint8 *,
 							  guint8 *, guint8 *,
 							  guint8 *);
@@ -156,19 +142,10 @@ struct _VncConnection
 	char write_buffer[4096];
 	size_t write_offset;
 
-	gboolean perfect_match;
-	struct vnc_framebuffer local;
-
-	int rm, gm, bm;
-	int rrs, grs, brs;
-	int rls, gls, bls;
+	VncFramebuffer *fb;
+	gboolean fbSwapRemote;
 
-	vnc_connection_blt_func *blt;
-	vnc_connection_fill_func *fill;
-	vnc_connection_set_pixel_at_func *set_pixel_at;
-	vnc_connection_hextile_func *hextile;
 	vnc_connection_rich_cursor_blt_func *rich_cursor_blt;
-	vnc_connection_rgb24_blt_func *rgb24_blt;
 	vnc_connection_tight_compute_predicted_func *tight_compute_predicted;
 	vnc_connection_tight_sum_pixel_func *tight_sum_pixel;
 
@@ -1025,6 +1002,11 @@ gboolean vnc_connection_set_pixel_format(VncConnection *conn,
 }
 
 
+const VncPixelFormat *vnc_connection_get_pixel_format(VncConnection *conn)
+{
+	return &conn->fmt;
+}
+
 gboolean vnc_connection_set_encodings(VncConnection *conn, int n_encoding, gint32 *encoding)
 {
 	guint8 pad[1] = {0};
@@ -1170,59 +1152,37 @@ gboolean vnc_connection_client_cut_text(VncConnection *conn,
 	return !vnc_connection_has_error(conn);
 }
 
+
 static inline guint8 *vnc_connection_get_local(VncConnection *conn, int x, int y)
 {
-	return conn->local.data +
-		(y * conn->local.linesize) +
-		(x * conn->local.bpp);
-}
+	const VncPixelFormat *local = vnc_framebuffer_get_local_format(conn->fb);
+	int rowstride = vnc_framebuffer_get_rowstride(conn->fb);
 
-static guint8 vnc_connection_swap_img_8(VncConnection *conn G_GNUC_UNUSED, guint8 pixel)
-{
-	return pixel;
+	return vnc_framebuffer_get_buffer(conn->fb) +
+		(y * rowstride) +
+		(x * (local->bits_per_pixel / 8));
 }
 
+
 static guint8 vnc_connection_swap_rfb_8(VncConnection *conn G_GNUC_UNUSED, guint8 pixel)
 {
 	return pixel;
 }
 
-/* local host native format -> X server image format */
-static guint16 vnc_connection_swap_img_16(VncConnection *conn, guint16 pixel)
-{
-	if (G_BYTE_ORDER != conn->local.byte_order)
-		return  (((pixel >> 8) & 0xFF) << 0) |
-			(((pixel >> 0) & 0xFF) << 8);
-	else
-		return pixel;
-}
-
 /* VNC server RFB  format ->  local host native format */
 static guint16 vnc_connection_swap_rfb_16(VncConnection *conn, guint16 pixel)
 {
-	if (conn->fmt.byte_order != G_BYTE_ORDER)
+	if (conn->fbSwapRemote)
 		return  (((pixel >> 8) & 0xFF) << 0) |
 			(((pixel >> 0) & 0xFF) << 8);
 	else
 		return pixel;
 }
 
-/* local host native format -> X server image format */
-static guint32 vnc_connection_swap_img_32(VncConnection *conn, guint32 pixel)
-{
-	if (G_BYTE_ORDER != conn->local.byte_order)
-		return  (((pixel >> 24) & 0xFF) <<  0) |
-			(((pixel >> 16) & 0xFF) <<  8) |
-			(((pixel >>  8) & 0xFF) << 16) |
-			(((pixel >>  0) & 0xFF) << 24);
-	else
-		return pixel;
-}
-
 /* VNC server RFB  format ->  local host native format */
 static guint32 vnc_connection_swap_rfb_32(VncConnection *conn, guint32 pixel)
 {
-	if (conn->fmt.byte_order != G_BYTE_ORDER)
+	if (conn->fbSwapRemote)
 		return  (((pixel >> 24) & 0xFF) <<  0) |
 			(((pixel >> 16) & 0xFF) <<  8) |
 			(((pixel >>  8) & 0xFF) << 16) |
@@ -1231,62 +1191,61 @@ static guint32 vnc_connection_swap_rfb_32(VncConnection *conn, guint32 pixel)
 		return pixel;
 }
 
-#define SPLICE_I(a, b) a ## b
-#define SPLICE(a, b) SPLICE_I(a, b)
+#define SRC 8
+#define DST 8
+#include "vncconnectionblt.h"
+#undef SRC
+#undef DST
+
+#define SRC 8
+#define DST 16
+#include "vncconnectionblt.h"
+#undef SRC
+#undef DST
 
 #define SRC 8
-#include "blt1.h"
+#define DST 32
+#include "vncconnectionblt.h"
 #undef SRC
+#undef DST
+
 
 #define SRC 16
-#include "blt1.h"
+#define DST 8
+#include "vncconnectionblt.h"
 #undef SRC
+#undef DST
 
-#define SRC 32
-#include "blt1.h"
+#define SRC 16
+#define DST 16
+#include "vncconnectionblt.h"
 #undef SRC
+#undef DST
 
-static vnc_connection_blt_func *vnc_connection_blt_table[3][3] = {
-	{  vnc_connection_blt_8x8,  vnc_connection_blt_8x16,  vnc_connection_blt_8x32 },
-	{ vnc_connection_blt_16x8, vnc_connection_blt_16x16, vnc_connection_blt_16x32 },
-	{ vnc_connection_blt_32x8, vnc_connection_blt_32x16, vnc_connection_blt_32x32 },
-};
+#define SRC 16
+#define DST 32
+#include "vncconnectionblt.h"
+#undef SRC
+#undef DST
 
-static vnc_connection_hextile_func *vnc_connection_hextile_table[3][3] = {
-	{ (vnc_connection_hextile_func *)vnc_connection_hextile_8x8,
-	  (vnc_connection_hextile_func *)vnc_connection_hextile_8x16,
-	  (vnc_connection_hextile_func *)vnc_connection_hextile_8x32 },
-	{ (vnc_connection_hextile_func *)vnc_connection_hextile_16x8,
-	  (vnc_connection_hextile_func *)vnc_connection_hextile_16x16,
-	  (vnc_connection_hextile_func *)vnc_connection_hextile_16x32 },
-	{ (vnc_connection_hextile_func *)vnc_connection_hextile_32x8,
-	  (vnc_connection_hextile_func *)vnc_connection_hextile_32x16,
-	  (vnc_connection_hextile_func *)vnc_connection_hextile_32x32 },
-};
 
-static vnc_connection_set_pixel_at_func *vnc_connection_set_pixel_at_table[3][3] = {
-	{ (vnc_connection_set_pixel_at_func *)vnc_connection_set_pixel_at_8x8,
-	  (vnc_connection_set_pixel_at_func *)vnc_connection_set_pixel_at_8x16,
-	  (vnc_connection_set_pixel_at_func *)vnc_connection_set_pixel_at_8x32 },
-	{ (vnc_connection_set_pixel_at_func *)vnc_connection_set_pixel_at_16x8,
-	  (vnc_connection_set_pixel_at_func *)vnc_connection_set_pixel_at_16x16,
-	  (vnc_connection_set_pixel_at_func *)vnc_connection_set_pixel_at_16x32 },
-	{ (vnc_connection_set_pixel_at_func *)vnc_connection_set_pixel_at_32x8,
-	  (vnc_connection_set_pixel_at_func *)vnc_connection_set_pixel_at_32x16,
-	  (vnc_connection_set_pixel_at_func *)vnc_connection_set_pixel_at_32x32 },
-};
+#define SRC 32
+#define DST 8
+#include "vncconnectionblt.h"
+#undef SRC
+#undef DST
 
-static vnc_connection_fill_func *vnc_connection_fill_table[3][3] = {
-	{ (vnc_connection_fill_func *)vnc_connection_fill_8x8,
-	  (vnc_connection_fill_func *)vnc_connection_fill_8x16,
-	  (vnc_connection_fill_func *)vnc_connection_fill_8x32 },
-	{ (vnc_connection_fill_func *)vnc_connection_fill_16x8,
-	  (vnc_connection_fill_func *)vnc_connection_fill_16x16,
-	  (vnc_connection_fill_func *)vnc_connection_fill_16x32 },
-	{ (vnc_connection_fill_func *)vnc_connection_fill_32x8,
-	  (vnc_connection_fill_func *)vnc_connection_fill_32x16,
-	  (vnc_connection_fill_func *)vnc_connection_fill_32x32 },
-};
+#define SRC 32
+#define DST 16
+#include "vncconnectionblt.h"
+#undef SRC
+#undef DST
+
+#define SRC 32
+#define DST 32
+#include "vncconnectionblt.h"
+#undef SRC
+#undef DST
 
 static vnc_connection_rich_cursor_blt_func *vnc_connection_rich_cursor_blt_table[3] = {
 	vnc_connection_rich_cursor_blt_8x32,
@@ -1294,12 +1253,6 @@ static vnc_connection_rich_cursor_blt_func *vnc_connection_rich_cursor_blt_table
 	vnc_connection_rich_cursor_blt_32x32,
 };
 
-static vnc_connection_rgb24_blt_func *vnc_connection_rgb24_blt_table[3] = {
-	(vnc_connection_rgb24_blt_func *)vnc_connection_rgb24_blt_32x8,
-	(vnc_connection_rgb24_blt_func *)vnc_connection_rgb24_blt_32x16,
-	(vnc_connection_rgb24_blt_func *)vnc_connection_rgb24_blt_32x32,
-};
-
 static vnc_connection_tight_compute_predicted_func *vnc_connection_tight_compute_predicted_table[3] = {
 	(vnc_connection_tight_compute_predicted_func *)vnc_connection_tight_compute_predicted_8x8,
 	(vnc_connection_tight_compute_predicted_func *)vnc_connection_tight_compute_predicted_16x16,
@@ -1312,52 +1265,39 @@ static vnc_connection_tight_sum_pixel_func *vnc_connection_tight_sum_pixel_table
 	(vnc_connection_tight_sum_pixel_func *)vnc_connection_tight_sum_pixel_32x32,
 };
 
-/* a fast blit for the perfect match scenario */
-static void vnc_connection_blt_fast(VncConnection *conn, guint8 *src, int pitch,
-				    int x, int y, int width, int height)
-{
-	guint8 *dst = vnc_connection_get_local(conn, x, y);
-	int i;
-	for (i = 0; i < height; i++) {
-		memcpy(dst, src, width * conn->local.bpp);
-		dst += conn->local.linesize;
-		src += pitch;
-	}
-}
-
-static void vnc_connection_blt(VncConnection *conn, guint8 *src, int pitch,
-			       int x, int y, int width, int height)
-{
-	conn->blt(conn, src, pitch, x, y, width, height);
-}
 
 static void vnc_connection_raw_update(VncConnection *conn,
 				      guint16 x, guint16 y,
 				      guint16 width, guint16 height)
 {
-	guint8 *dst;
-	int i;
-
 	/* optimize for perfect match between server/client
 	   FWIW, in the local case, we ought to be doing a write
 	   directly from the source framebuffer and a read directly
 	   into the client framebuffer
 	*/
-	if (conn->perfect_match) {
-		dst = vnc_connection_get_local(conn, x, y);
+	if (vnc_framebuffer_perfect_format_match(conn->fb)) {
+		int i;
+		int rowstride = vnc_framebuffer_get_rowstride(conn->fb);
+		guint8 *dst = vnc_framebuffer_get_buffer(conn->fb);
+
+		dst += (y * rowstride) + (x * (conn->fmt.bits_per_pixel/8));
+
 		for (i = 0; i < height; i++) {
-			vnc_connection_read(conn, dst, width * conn->local.bpp);
-			dst += conn->local.linesize;
+			vnc_connection_read(conn, dst,
+					    width * (conn->fmt.bits_per_pixel/8));
+			dst += rowstride;
 		}
-		return;
-	}
+	} else {
+		guint8 *dst;
+		int i;
 
-	dst = g_malloc(width * (conn->fmt.bits_per_pixel / 8));
-	for (i = 0; i < height; i++) {
-		vnc_connection_read(conn, dst, width * (conn->fmt.bits_per_pixel / 8));
-		vnc_connection_blt(conn, dst, 0, x, y + i, width, 1);
+		dst = g_malloc(width * (conn->fmt.bits_per_pixel / 8));
+		for (i = 0; i < height; i++) {
+			vnc_connection_read(conn, dst, width * (conn->fmt.bits_per_pixel / 8));
+			vnc_framebuffer_blt(conn->fb, dst, 0, x, y + i, width, 1);
+		}
+		g_free(dst);
 	}
-	g_free(dst);
 }
 
 static void vnc_connection_copyrect_update(VncConnection *conn,
@@ -1365,28 +1305,60 @@ static void vnc_connection_copyrect_update(VncConnection *conn,
 					   guint16 width, guint16 height)
 {
 	int src_x, src_y;
-	guint8 *dst, *src;
-	int pitch = conn->local.linesize;
-	int i;
 
 	src_x = vnc_connection_read_u16(conn);
 	src_y = vnc_connection_read_u16(conn);
 
-	if (src_y < dst_y) {
-		pitch = -pitch;
-		src_y += (height - 1);
-		dst_y += (height - 1);
-	}
+	vnc_framebuffer_copyrect(conn->fb,
+				 src_x, src_y,
+				 dst_x, dst_y,
+				 width, height);
+}
+
+static void vnc_connection_hextile_rect(VncConnection *conn,
+					guint8 flags,
+					guint16 x, guint16 y,
+					guint16 width, guint16 height,
+					guint8 *fg, guint8 *bg)
+{
+	int i;
+
+	if (flags & 0x01) {
+		vnc_connection_raw_update(conn, x, y, width, height);
+	} else {
+		/* Background Specified */
+		if (flags & 0x02)
+			vnc_connection_read_pixel(conn, bg);
+
+		/* Foreground Specified */
+		if (flags & 0x04)
+			vnc_connection_read_pixel(conn, fg);
+
+		vnc_framebuffer_fill(conn->fb, bg, x, y, width, height);
+
+		/* AnySubrects */
+		if (flags & 0x08) {
+			guint8 n_rects = vnc_connection_read_u8(conn);
+
+			for (i = 0; i < n_rects; i++) {
+				guint8 xy, wh;
+
+				/* SubrectsColored */
+				if (flags & 0x10)
+					vnc_connection_read_pixel(conn, fg);
+
+				xy = vnc_connection_read_u8(conn);
+				wh = vnc_connection_read_u8(conn);
 
-	dst = vnc_connection_get_local(conn, dst_x, dst_y);
-	src = vnc_connection_get_local(conn, src_x, src_y);
-	for (i = 0; i < height; i++) {
-		memmove(dst, src, width * conn->local.bpp);
-		dst += pitch;
-		src += pitch;
+				vnc_framebuffer_fill(conn->fb, fg,
+						     x + nibhi(xy), y + niblo(xy),
+						     nibhi(wh) + 1, niblo(wh) + 1);
+			}
+		}
 	}
 }
 
+
 static void vnc_connection_hextile_update(VncConnection *conn,
 					  guint16 x, guint16 y,
 					  guint16 width, guint16 height)
@@ -1403,22 +1375,14 @@ static void vnc_connection_hextile_update(VncConnection *conn,
 			int h = MIN(16, height - j);
 
 			flags = vnc_connection_read_u8(conn);
-			conn->hextile(conn, flags, x + i, y + j, w, h, fg, bg);
+			vnc_connection_hextile_rect(conn, flags,
+						    x + i, y + j,
+						    w, h,
+						    fg, bg);
 		}
 	}
 }
 
-static void vnc_connection_fill(VncConnection *conn, guint8 *color,
-				guint16 x, guint16 y, guint16 width, guint16 height)
-{
-	conn->fill(conn, color, x, y, width, height);
-}
-
-static void vnc_connection_set_pixel_at(VncConnection *conn, int x, int y, guint8 *pixel)
-{
-	conn->set_pixel_at(conn, x, y, pixel);
-}
-
 static void vnc_connection_rre_update(VncConnection *conn,
 				      guint16 x, guint16 y,
 				      guint16 width, guint16 height)
@@ -1429,7 +1393,7 @@ static void vnc_connection_rre_update(VncConnection *conn,
 
 	num = vnc_connection_read_u32(conn);
 	vnc_connection_read_pixel(conn, bg);
-	vnc_connection_fill(conn, bg, x, y, width, height);
+	vnc_framebuffer_fill(conn->fb, bg, x, y, width, height);
 
 	for (i = 0; i < num; i++) {
 		guint8 fg[4];
@@ -1441,8 +1405,8 @@ static void vnc_connection_rre_update(VncConnection *conn,
 		sub_w = vnc_connection_read_u16(conn);
 		sub_h = vnc_connection_read_u16(conn);
 
-		vnc_connection_fill(conn, fg,
-				    x + sub_x, y + sub_y, sub_w, sub_h);
+		vnc_framebuffer_fill(conn->fb, fg,
+				     x + sub_x, y + sub_y, sub_w, sub_h);
 	}
 }
 
@@ -1491,7 +1455,7 @@ static void vnc_connection_zrle_update_tile_blit(VncConnection *conn,
 	for (i = 0; i < width * height; i++)
 		vnc_connection_read_cpixel(conn, blit_data + (i * bpp));
 
-	vnc_connection_blt(conn, blit_data, width * bpp, x, y, width, height);
+	vnc_framebuffer_blt(conn->fb, blit_data, width * bpp, x, y, width, height);
 }
 
 static guint8 vnc_connection_read_zrle_pi(VncConnection *conn, int palette_size)
@@ -1534,8 +1498,8 @@ static void vnc_connection_zrle_update_tile_palette(VncConnection *conn,
 		for (i = 0; i < width; i++) {
 			int ind = vnc_connection_read_zrle_pi(conn, palette_size);
 
-			vnc_connection_set_pixel_at(conn, x + i, y + j,
-						    palette[ind & 0x7F]);
+			vnc_framebuffer_set_pixel_at(conn->fb, palette[ind & 0x7F],
+						     x + i, y + j);
 		}
 	}
 }
@@ -1566,7 +1530,7 @@ static void vnc_connection_zrle_update_tile_rle(VncConnection *conn,
 				vnc_connection_read_cpixel(conn, pixel);
 				rl = vnc_connection_read_zrle_rl(conn);
 			}
-			vnc_connection_set_pixel_at(conn, x + i, y + j, pixel);
+			vnc_framebuffer_set_pixel_at(conn->fb, pixel, x + i, y + j);
 			rl -= 1;
 		}
 	}
@@ -1595,7 +1559,7 @@ static void vnc_connection_zrle_update_tile_prle(VncConnection *conn,
 					rl = 1;
 			}
 
-			vnc_connection_set_pixel_at(conn, x + i, y + j, palette[pi]);
+			vnc_framebuffer_set_pixel_at(conn->fb, palette[pi], x + i, y + j);
 			rl -= 1;
 		}
 	}
@@ -1613,7 +1577,7 @@ static void vnc_connection_zrle_update_tile(VncConnection *conn, guint16 x, guin
 	} else if (subencoding == 1) {
 		/* Solid tile of a single color */
 		vnc_connection_read_cpixel(conn, pixel);
-		vnc_connection_fill(conn, pixel, x, y, width, height);
+		vnc_framebuffer_fill(conn->fb, pixel, x, y, width, height);
 	} else if ((subencoding >= 2) && (subencoding <= 16)) {
 		/* Packed palette types */
 		vnc_connection_zrle_update_tile_palette(conn, subencoding,
@@ -1670,12 +1634,6 @@ static void vnc_connection_zrle_update(VncConnection *conn,
 	g_free(zlib_data);
 }
 
-static void vnc_connection_rgb24_blt(VncConnection *conn, int x, int y,
-				     int width, int height, guint8 *data, int pitch)
-{
-	conn->rgb24_blt(conn, x, y, width, height, data, pitch);
-}
-
 static guint32 vnc_connection_read_cint(VncConnection *conn)
 {
 	guint32 value = 0;
@@ -1734,7 +1692,7 @@ static void vnc_connection_tight_update_copy(VncConnection *conn,
 	for (j = 0; j < height; j++) {
 		for (i = 0; i < width; i++) {
 			vnc_connection_read_tpixel(conn, pixel);
-			vnc_connection_set_pixel_at(conn, x + i, y + j, pixel);
+			vnc_framebuffer_set_pixel_at(conn->fb, pixel, x + i, y + j);
 		}
 	}
 }
@@ -1765,8 +1723,7 @@ static void vnc_connection_tight_update_palette(VncConnection *conn,
 			guint8 ind;
 
 			ind = vnc_connection_tight_get_pi(conn, &ra, i, palette_size);
-			vnc_connection_set_pixel_at(conn, x + i, y + j,
-						    &palette[ind * 4]);
+			vnc_framebuffer_set_pixel_at(conn->fb, &palette[ind * 4], x + i, y + j);
 		}
 	}
 }
@@ -1829,7 +1786,7 @@ static void vnc_connection_tight_update_gradient(VncConnection *conn,
 		}
 
 		/* write out row of pixel data */
-		vnc_connection_blt(conn, row, width * bpp, x, y + j, width, 1);
+		vnc_framebuffer_blt(conn->fb, row, width * bpp, x, y + j, width, 1);
 
 		/* swap last row and current row */
 		tmp_row = last_row;
@@ -1846,7 +1803,7 @@ static void jpeg_draw(void *opaque, int x, int y, int w, int h,
 {
 	VncConnection *conn = opaque;
 
-	vnc_connection_rgb24_blt(conn, x, y, w, h, data, stride);
+	vnc_framebuffer_rgb24_blt(conn->fb, data, stride, x, y, w, h);
 }
 
 static void vnc_connection_tight_update_jpeg(VncConnection *conn, guint16 x, guint16 y,
@@ -1950,7 +1907,7 @@ static void vnc_connection_tight_update(VncConnection *conn,
 		/* fill */
 		/* FIXME check each width; endianness */
 		vnc_connection_read_tpixel(conn, pixel);
-		vnc_connection_fill(conn, pixel, x, y, width, height);
+		vnc_framebuffer_fill(conn->fb, pixel, x, y, width, height);
 	} else if (ccontrol == 9) {
 		/* jpeg */
 		guint32 length;
@@ -1973,6 +1930,7 @@ static void vnc_connection_update(VncConnection *conn, int x, int y, int width,
 {
 	if (conn->has_error || !conn->ops.update)
 		return;
+	GVNC_DEBUG("Notify update area (%dx%d) at location %d,%d", width, height, x, y);
 	if (!conn->ops.update(conn->ops_data, x, y, width, height)) {
 		GVNC_DEBUG("Closing the connection: vnc_connection_update");
 		conn->has_error = TRUE;
@@ -2153,8 +2111,8 @@ static void vnc_connection_framebuffer_update(VncConnection *conn, gint32 etype,
 					      guint16 x, guint16 y,
 					      guint16 width, guint16 height)
 {
-	GVNC_DEBUG("FramebufferUpdate(%d, %d, %d, %d, %d)",
-		   etype, x, y, width, height);
+	GVNC_DEBUG("FramebufferUpdate type=%d area (%dx%d) at location %d,%d",
+		   etype, width, height, x, y);
 
 	switch (etype) {
 	case GVNC_ENCODING_RAW:
@@ -3403,6 +3361,9 @@ void vnc_connection_free(VncConnection *conn)
 	if (vnc_connection_is_open(conn))
 		vnc_connection_close(conn);
 
+	if (conn->fb)
+		g_object_unref(G_OBJECT(conn->fb));
+
 	g_free(conn);
 	conn = NULL;
 }
@@ -3853,86 +3814,28 @@ gboolean vnc_connection_set_credential_x509_cert(VncConnection *conn, const char
 }
 
 
-gboolean vnc_connection_set_local(VncConnection *conn, struct vnc_framebuffer *fb)
+gboolean vnc_connection_set_framebuffer(VncConnection *conn, VncFramebuffer *fb)
 {
-	int i, j, n;
-	int depth;
+	const VncPixelFormat *remote;
+	int i;
 
-	memcpy(&conn->local, fb, sizeof(*fb));
+	if (conn->fb)
+		g_object_unref(G_OBJECT(conn->fb));
+	conn->fb = fb;
+	g_object_ref(G_OBJECT(conn->fb));
+
+	remote = vnc_framebuffer_get_remote_format(conn->fb);
+
+	conn->fbSwapRemote = remote->byte_order != G_BYTE_ORDER;
+
+        i = conn->fmt.bits_per_pixel / 8;
+
+        if (i == 4) i = 3;
 
-	if (fb->bpp == (conn->fmt.bits_per_pixel / 8) &&
-	    fb->red_mask == conn->fmt.red_max &&
-	    fb->green_mask == conn->fmt.green_max &&
-	    fb->blue_mask == conn->fmt.blue_max &&
-	    fb->red_shift == conn->fmt.red_shift &&
-	    fb->green_shift == conn->fmt.green_shift &&
-	    fb->blue_shift == conn->fmt.blue_shift &&
-	    fb->byte_order == G_BYTE_ORDER &&
-	    conn->fmt.byte_order == G_BYTE_ORDER)
-		conn->perfect_match = TRUE;
-	else
-		conn->perfect_match = FALSE;
-
-	depth = conn->fmt.depth;
-	if (depth == 32)
-		depth = 24;
-
-	conn->rm = conn->local.red_mask & conn->fmt.red_max;
-	conn->gm = conn->local.green_mask & conn->fmt.green_max;
-	conn->bm = conn->local.blue_mask & conn->fmt.blue_max;
-	GVNC_DEBUG("Mask local: %3d %3d %3d\n"
-		   "    remote: %3d %3d %3d\n"
-		   "    merged: %3d %3d %3d",
-		   conn->local.red_mask, conn->local.green_mask, conn->local.blue_mask,
-		   conn->fmt.red_max, conn->fmt.green_max, conn->fmt.blue_max,
-		   conn->rm, conn->gm, conn->bm);
-
-	/* Setup shifts assuming matched bpp (but not necessarily match rgb order)*/
-	conn->rrs = conn->fmt.red_shift;
-	conn->grs = conn->fmt.green_shift;
-	conn->brs = conn->fmt.blue_shift;
-
-	conn->rls = conn->local.red_shift;
-	conn->gls = conn->local.green_shift;
-	conn->bls = conn->local.blue_shift;
-
-	/* This adjusts for remote having more bpp than local */
-	for (n = conn->fmt.red_max; n > conn->local.red_mask ; n>>= 1)
-		conn->rrs++;
-	for (n = conn->fmt.green_max; n > conn->local.green_mask ; n>>= 1)
-		conn->grs++;
-	for (n = conn->fmt.blue_max; n > conn->local.blue_mask ; n>>= 1)
-		conn->brs++;
-
-	/* This adjusts for remote having less bpp than remote */
-	for (n = conn->local.red_mask ; n > conn->fmt.red_max ; n>>= 1)
-		conn->rls++;
-	for (n = conn->local.green_mask ; n > conn->fmt.green_max ; n>>= 1)
-		conn->gls++;
-	for (n = conn->local.blue_mask ; n > conn->fmt.blue_max ; n>>= 1)
-		conn->bls++;
-	GVNC_DEBUG("Pixel shifts\n   right: %3d %3d %3d\n    left: %3d %3d %3d",
-		   conn->rrs, conn->grs, conn->brs,
-		   conn->rls, conn->gls, conn->bls);
-
-	i = conn->fmt.bits_per_pixel / 8;
-	j = conn->local.bpp;
-
-	if (i == 4) i = 3;
-	if (j == 4) j = 3;
-
-	conn->blt = vnc_connection_blt_table[i - 1][j - 1];
-	conn->fill = vnc_connection_fill_table[i - 1][j - 1];
-	conn->set_pixel_at = vnc_connection_set_pixel_at_table[i - 1][j - 1];
-	conn->hextile = vnc_connection_hextile_table[i - 1][j - 1];
 	conn->rich_cursor_blt = vnc_connection_rich_cursor_blt_table[i - 1];
-	conn->rgb24_blt = vnc_connection_rgb24_blt_table[i - 1];
 	conn->tight_compute_predicted = vnc_connection_tight_compute_predicted_table[i - 1];
 	conn->tight_sum_pixel = vnc_connection_tight_sum_pixel_table[i - 1];
 
-	if (conn->perfect_match)
-		conn->blt = vnc_connection_blt_fast;
-
 	return !vnc_connection_has_error(conn);
 }
 
diff --git a/src/vncconnection.h b/src/vncconnection.h
index 1c8ef27..9c3de73 100644
--- a/src/vncconnection.h
+++ b/src/vncconnection.h
@@ -23,7 +23,7 @@
 
 #include <glib.h>
 
-#include "vncpixelformat.h"
+#include "vncframebuffer.h"
 
 typedef struct _VncConnection VncConnection;
 
@@ -50,28 +50,6 @@ struct vnc_connection_ops
 };
 
 
-struct vnc_framebuffer
-{
-	guint8 *data;
-
-	int width;
-	int height;
-
-	int linesize;
-
-	guint16 byte_order;
-	int depth;
-	int bpp;
-
-	int red_mask;
-	int green_mask;
-	int blue_mask;
-
-	int red_shift;
-	int blue_shift;
-	int green_shift;
-};
-
 typedef enum {
 	GVNC_ENCODING_RAW = 0,
 	GVNC_ENCODING_COPY_RECT = 1,
@@ -180,9 +158,12 @@ gboolean vnc_connection_set_encodings(VncConnection *conn, int n_encoding, gint3
 gboolean vnc_connection_set_pixel_format(VncConnection *conn,
 					 const VncPixelFormat *fmt);
 
+const VncPixelFormat *vnc_connection_get_pixel_format(VncConnection *conn);
+
 gboolean vnc_connection_has_error(VncConnection *conn);
 
-gboolean vnc_connection_set_local(VncConnection *conn, struct vnc_framebuffer *fb);
+gboolean vnc_connection_set_framebuffer(VncConnection *conn,
+					VncFramebuffer *fb);
 
 const char *vnc_connection_get_name(VncConnection *conn);
 int vnc_connection_get_width(VncConnection *conn);
diff --git a/src/vncconnectionblt.h b/src/vncconnectionblt.h
new file mode 100644
index 0000000..031fcf2
--- /dev/null
+++ b/src/vncconnectionblt.h
@@ -0,0 +1,163 @@
+/*
+ * GTK VNC Widget
+ *
+ * Copyright (C) 2006  Anthony Liguori <anthony codemonkey ws>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.0 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/* Ordering of the SPLICE calls here is important to avoid
+ * a Solaris compiler/cpp  whitespace bug
+ */
+#define SPLICE_I(a, b) a ## b
+#define SPLICE(a, b) SPLICE_I(a, b)
+#define src_pixel_t SPLICE(SPLICE(uint, SRC), _t)
+#define ssrc_pixel_t SPLICE(SPLICE(int, SRC), _t)
+#define dst_pixel_t SPLICE(SPLICE(uint, DST), _t)
+#define SUFFIX() SPLICE(SRC,SPLICE(x,DST))
+#define RICH_CURSOR_BLIT SPLICE(vnc_connection_rich_cursor_blt_, SUFFIX())
+#define TIGHT_COMPUTE_PREDICTED SPLICE(vnc_connection_tight_compute_predicted_, SUFFIX())
+#define TIGHT_SUM_PIXEL SPLICE(vnc_connection_tight_sum_pixel_, SUFFIX())
+#define SWAP_RFB(conn, pixel) SPLICE(vnc_connection_swap_rfb_, SRC)(conn, pixel)
+#define SWAP_IMG(conn, pixel) SPLICE(vnc_connection_swap_img_, DST)(conn, pixel)
+#define COMPONENT(color, pixel) ((SWAP_RFB(conn, pixel) >> conn->fmt.SPLICE(color, _shift) & conn->fmt.SPLICE(color, _max)))
+
+
+/* We need to convert to a GdkPixbuf which is always 32-bit */
+#if DST == 32
+static void RICH_CURSOR_BLIT(VncConnection *conn, guint8 *pixbuf,
+			     guint8 *image, guint8 *mask, int pitch,
+			     guint16 width, guint16 height)
+{
+	int x1, y1;
+	guint32 *dst = (guint32 *)pixbuf;
+	guint8 *src = image;
+	guint8 *alpha = mask;
+	int as, rs, gs, bs, n;
+
+	/*
+	 * GdkPixbuf is always 32-bit RGB, so we can't use the precomputed
+	 * left / right shift data from conn->{r,g,b}{r,l}s. The latter
+	 * is set for the local display depth, which may be different
+	 * to GdkPixbuf's fixed 32-bit RGBA
+	 *
+	 * This function isn't called often, so just re-compute them now
+	 */
+
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+	as = 0;
+	rs = 8;
+	gs = 16;
+	bs = 24;
+#else
+	as = 24;
+	rs = 16;
+	gs = 8;
+	bs = 0;
+#endif
+
+	/* Then this adjusts for remote having less bpp than 32 */
+	for (n = 255 ; n > conn->fmt.red_max ; n>>= 1)
+		rs++;
+	for (n = 255 ; n > conn->fmt.green_max ; n>>= 1)
+		gs++;
+	for (n = 255 ; n > conn->fmt.blue_max ; n>>= 1)
+		bs++;
+
+	for (y1 = 0; y1 < height; y1++) {
+		src_pixel_t *sp = (src_pixel_t *)src;
+		guint8 *mp = alpha;
+		for (x1 = 0; x1 < width; x1++) {
+			*dst = (COMPONENT(red, *sp) << rs)
+				| (COMPONENT(green, *sp) << gs)
+				| (COMPONENT(blue, *sp) << bs);
+
+			if ((mp[x1 / 8] >> (7 - (x1 % 8))) & 1)
+				*dst |= (0xFF << as);
+
+			dst++;
+			sp++;
+		}
+		src += pitch;
+		alpha += ((width + 7) / 8);
+	}
+}
+#endif
+
+
+#if SRC == DST
+
+static void TIGHT_COMPUTE_PREDICTED(VncConnection *conn, src_pixel_t *ppixel,
+				    src_pixel_t *lp, src_pixel_t *cp,
+				    src_pixel_t *llp)
+{
+	ssrc_pixel_t red, green, blue;
+
+	red = COMPONENT(red, *lp) + COMPONENT(red, *cp) - COMPONENT(red, *llp);
+	red = MAX(red, 0);
+	red = MIN(red, conn->fmt.red_max);
+
+	green = COMPONENT(green, *lp) + COMPONENT(green, *cp) - COMPONENT(green, *llp);
+	green = MAX(green, 0);
+	green = MIN(green, conn->fmt.green_max);
+
+	blue = COMPONENT(blue, *lp) + COMPONENT(blue, *cp) - COMPONENT(blue, *llp);
+	blue = MAX(blue, 0);
+	blue = MIN(blue, conn->fmt.blue_max);
+
+	*ppixel = SWAP_RFB(conn,
+		       (red << conn->fmt.red_shift) |
+		       (green << conn->fmt.green_shift) |
+		       (blue << conn->fmt.blue_shift));
+}
+
+static void TIGHT_SUM_PIXEL(VncConnection *conn,
+			    src_pixel_t *lhs, src_pixel_t *rhs)
+{
+	src_pixel_t red, green, blue;
+
+	red = COMPONENT(red, *lhs) + COMPONENT(red, *rhs);
+	green = COMPONENT(green, *lhs) + COMPONENT(green, *rhs);
+	blue = COMPONENT(blue, *lhs) + COMPONENT(blue, *rhs);
+
+	*lhs = SWAP_RFB(conn,
+		    ((red & conn->fmt.red_max) << conn->fmt.red_shift) |
+		    ((green & conn->fmt.green_max) << conn->fmt.green_shift) |
+		    ((blue & conn->fmt.blue_max) << conn->fmt.blue_shift));
+}
+
+#endif
+
+#undef SPLICE
+#undef SPLICE_T
+#undef SUFFIX
+#undef RICH_CURSOR_BLIT
+#undef TIGHT_SUM_PIXEL
+#undef TIGHT_COMPUTE_PREDICTED
+#undef SWAP_RFB
+#undef SWAP_IMG
+#undef COMPONENT
+#undef dst_pixel_t
+#undef src_pixel_t
+#undef ssrc_pixel_t
+
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/src/vncdisplay.c b/src/vncdisplay.c
index c923efe..157b7ee 100644
--- a/src/vncdisplay.c
+++ b/src/vncdisplay.c
@@ -24,6 +24,7 @@
 #include "vncdisplay.h"
 #include "coroutine.h"
 #include "vncconnection.h"
+#include "vncimageframebuffer.h"
 #include "utils.h"
 #include "vncmarshal.h"
 #include "config.h"
@@ -59,14 +60,13 @@ struct _VncDisplayPrivate
 	char *host;
 	char *port;
 	GdkGC *gc;
-	GdkImage *image;
 	GdkPixmap *pixmap;
 	GdkCursor *null_cursor;
 	GdkCursor *remote_cursor;
 
-	struct vnc_framebuffer fb;
 	struct coroutine coroutine;
 	VncConnection *conn;
+	VncImageFramebuffer *fb;
 
 	guint open_id;
 	VncDisplayDepthColor depth;
@@ -304,19 +304,23 @@ static gboolean expose_event(GtkWidget *widget, GdkEventExpose *expose)
 	GdkRectangle drawn;
 	GdkRegion *clear, *copy;
 #endif
+	int fbw, fbh;
 
-	GVNC_DEBUG("Expose %dx%d @ %d,%d",
-		   expose->area.x,
-		   expose->area.y,
+	fbw = vnc_framebuffer_get_width(VNC_FRAMEBUFFER(priv->fb));
+	fbh = vnc_framebuffer_get_height(VNC_FRAMEBUFFER(priv->fb));
+
+	GVNC_DEBUG("Expose area %dx%d at location %d,%d",
 		   expose->area.width,
-		   expose->area.height);
+		   expose->area.height,
+		   expose->area.x,
+		   expose->area.y);
 
 	gdk_drawable_get_size(widget->window, &ww, &wh);
 
-	if (ww > priv->fb.width)
-		mx = (ww - priv->fb.width) / 2;
-	if (wh > priv->fb.height)
-		my = (wh - priv->fb.height) / 2;
+	if (ww > fbw)
+		mx = (ww - fbw) / 2;
+	if (wh > fbh)
+		my = (wh - fbh) / 2;
 
 #if WITH_GTK_CAIRO
 	cr = gdk_cairo_create(GTK_WIDGET(obj)->window);
@@ -338,8 +342,8 @@ static gboolean expose_event(GtkWidget *widget, GdkEventExpose *expose)
 		   behaviour of drawing the rectangle from right to left
 		   to cut out the whole */
 		if (priv->pixmap)
-			cairo_rectangle(cr, mx + priv->fb.width, my,
-					-1 * priv->fb.width, priv->fb.height);
+			cairo_rectangle(cr, mx + fbw, my,
+					-1 * fbw, fbh);
 		cairo_fill(cr);
 	}
 
@@ -348,8 +352,8 @@ static gboolean expose_event(GtkWidget *widget, GdkEventExpose *expose)
 		if (priv->allow_scaling) {
 			double sx, sy;
 			/* Scale to fill window */
-			sx = (double)ww / (double)priv->fb.width;
-			sy = (double)wh / (double)priv->fb.height;
+			sx = (double)ww / (double)fbw;
+			sy = (double)wh / (double)fbh;
 			cairo_scale(cr, sx, sy);
 			gdk_cairo_set_source_pixmap(cr,
 						    priv->pixmap,
@@ -364,10 +368,10 @@ static gboolean expose_event(GtkWidget *widget, GdkEventExpose *expose)
 
 	cairo_destroy(cr);
 #else
-	x = MIN(expose->area.x - mx, priv->fb.width);
-	y = MIN(expose->area.y - my, priv->fb.height);
-	w = MIN(expose->area.x + expose->area.width - mx, priv->fb.width);
-	h = MIN(expose->area.y + expose->area.height - my, priv->fb.height);
+	x = MIN(expose->area.x - mx, fbw);
+	y = MIN(expose->area.y - my, fbh);
+	w = MIN(expose->area.x + expose->area.width - mx, fbw);
+	h = MIN(expose->area.y + expose->area.height - my, fbh);
 	x = MAX(0, x);
 	y = MAX(0, y);
 	w = MAX(0, w);
@@ -590,6 +594,10 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
 {
 	VncDisplayPrivate *priv = VNC_DISPLAY(widget)->priv;
 	int ww, wh;
+	int fbw, fbh;
+
+	fbw = vnc_framebuffer_get_width(VNC_FRAMEBUFFER(priv->fb));
+	fbh = vnc_framebuffer_get_height(VNC_FRAMEBUFFER(priv->fb));
 
 	if (priv->conn == NULL || !vnc_connection_is_initialized(priv->conn))
 		return FALSE;
@@ -607,8 +615,8 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
 	/* First apply adjustments to the coords in the motion event */
 	if (priv->allow_scaling) {
 		double sx, sy;
-		sx = (double)priv->fb.width / (double)ww;
-		sy = (double)priv->fb.height / (double)wh;
+		sx = (double)fbw / (double)ww;
+		sy = (double)fbh / (double)wh;
 
 		/* Scaling the desktop, so scale the mouse coords
 		 * by same ratio */
@@ -617,10 +625,10 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
 	} else {
 		int mw = 0, mh = 0;
 
-		if (ww > priv->fb.width)
-			mw = (ww - priv->fb.width) / 2;
-		if (wh > priv->fb.height)
-			mh = (wh - priv->fb.height) / 2;
+		if (ww > fbw)
+			mw = (ww - fbw) / 2;
+		if (wh > fbh)
+			mh = (wh - fbh) / 2;
 
 		/* Not scaling, drawing the desktop centered
 		 * in the larger window, so offset the mouse
@@ -666,8 +674,8 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
 
 			/* Drop out of bounds motion to avoid upsetting
 			 * the server */
-			if (dx < 0 || dx >= priv->fb.width ||
-			    dy < 0 || dy >= priv->fb.height)
+			if (dx < 0 || dx >= fbw ||
+			    dy < 0 || dy >= fbh)
 				return FALSE;
 		} else {
 			/* Just send the delta since last motion event */
@@ -830,10 +838,15 @@ static gboolean on_update(void *opaque, int x, int y, int w, int h)
 	VncDisplayPrivate *priv = obj->priv;
 	int ww, wh;
 	GdkRectangle r = { x, y, w, h };
+	int fbw, fbh;
+
+	fbw = vnc_framebuffer_get_width(VNC_FRAMEBUFFER(priv->fb));
+	fbh = vnc_framebuffer_get_height(VNC_FRAMEBUFFER(priv->fb));
 
 	/* Copy pixbuf to pixmap */
 	gdk_gc_set_clip_rectangle(priv->gc, &r);
-	gdk_draw_image(priv->pixmap, priv->gc, priv->image,
+	gdk_draw_image(priv->pixmap, priv->gc,
+		       vnc_image_framebuffer_get_image(priv->fb),
 		       x, y, x, y, w, h);
 
 	gdk_drawable_get_size(widget->window, &ww, &wh);
@@ -843,8 +856,8 @@ static gboolean on_update(void *opaque, int x, int y, int w, int h)
 
 		/* Scale the VNC region to produce expose region */
 
-		sx = (double)ww / (double)priv->fb.width;
-		sy = (double)wh / (double)priv->fb.height;
+		sx = (double)ww / (double)fbw;
+		sy = (double)wh / (double)fbh;
 		x *= sx;
 		y *= sy;
 		w *= sx;
@@ -854,10 +867,10 @@ static gboolean on_update(void *opaque, int x, int y, int w, int h)
 
 		/* Offset the VNC region to produce expose region */
 
-		if (ww > priv->fb.width)
-			mw = (ww - priv->fb.width) / 2;
-		if (wh > priv->fb.height)
-			mh = (wh - priv->fb.height) / 2;
+		if (ww > fbw)
+			mw = (ww - fbw) / 2;
+		if (wh > fbh)
+			mh = (wh - fbh) / 2;
 
 		x += mw;
 		y += mh;
@@ -868,42 +881,6 @@ static gboolean on_update(void *opaque, int x, int y, int w, int h)
 	return TRUE;
 }
 
-static void setup_gdk_image(VncDisplay *obj, gint width, gint height)
-{
-	VncDisplayPrivate *priv = obj->priv;
-	GdkVisual *visual;
-
-	visual = gdk_drawable_get_visual(GTK_WIDGET(obj)->window);
-
-	priv->image = gdk_image_new(GDK_IMAGE_FASTEST, visual, width, height);
-	priv->pixmap = gdk_pixmap_new(GTK_WIDGET(obj)->window, width, height, -1);
-
-	GVNC_DEBUG("Visual mask: %3d %3d %3d\n      shift: %3d %3d %3d",
-		   visual->red_mask,
-		   visual->green_mask,
-		   visual->blue_mask,
-		   visual->red_shift,
-		   visual->green_shift,
-		   visual->blue_shift);
-
-	priv->fb.red_mask = visual->red_mask >> visual->red_shift;
-	priv->fb.green_mask = visual->green_mask >> visual->green_shift;
-	priv->fb.blue_mask = visual->blue_mask >> visual->blue_shift;
-	priv->fb.red_shift = visual->red_shift;
-	priv->fb.green_shift = visual->green_shift;
-	priv->fb.blue_shift = visual->blue_shift;
-	priv->fb.depth = priv->image->depth;
-	priv->fb.bpp = priv->image->bpp;
-	priv->fb.width = priv->image->width;
-	priv->fb.height = priv->image->height;
-	priv->fb.linesize = priv->image->bpl;
-	priv->fb.data = (guint8 *)priv->image->mem;
-	priv->fb.byte_order = priv->image->byte_order == GDK_LSB_FIRST ? G_LITTLE_ENDIAN : G_BIG_ENDIAN;
-
-	if (priv->force_size)
-		gtk_widget_set_size_request(GTK_WIDGET(obj), width, height);
-}
-
 
 static gboolean emit_signal_auth_cred(gpointer opaque)
 {
@@ -966,18 +943,21 @@ static void emit_signal_delayed(VncDisplay *obj, int signum,
 	coroutine_yield(NULL);
 }
 
-static gboolean do_resize(void *opaque, int width, int height, gboolean quiet)
+static gboolean do_framebuffer_init(VncDisplay *obj,
+				    const VncPixelFormat *remoteFormat,
+				    int width, int height, gboolean quiet)
 {
-	VncDisplay *obj = VNC_DISPLAY(opaque);
 	VncDisplayPrivate *priv = obj->priv;
 	struct signal_data s;
+	GdkVisual *visual;
+	GdkImage *image;
 
 	if (priv->conn == NULL || !vnc_connection_is_initialized(priv->conn))
 		return TRUE;
 
-	if (priv->image) {
-		g_object_unref(priv->image);
-		priv->image = NULL;
+	if (priv->fb) {
+		g_object_unref(priv->fb);
+		priv->fb = NULL;
 	}
 	if (priv->pixmap) {
 		g_object_unref(priv->pixmap);
@@ -994,9 +974,18 @@ static gboolean do_resize(void *opaque, int width, int height, gboolean quiet)
 		priv->gc = gdk_gc_new(GTK_WIDGET(obj)->window);
 	}
 
-	setup_gdk_image(obj, width, height);
+	visual = gdk_drawable_get_visual(GTK_WIDGET(obj)->window);
+	image = gdk_image_new(GDK_IMAGE_FASTEST, visual, width, height);
 
-	vnc_connection_set_local(priv->conn, &priv->fb);
+	priv->fb = vnc_image_framebuffer_new(image, remoteFormat);
+	priv->pixmap = gdk_pixmap_new(GTK_WIDGET(obj)->window, width, height, -1);
+
+	g_object_unref(G_OBJECT(image));
+
+	vnc_connection_set_framebuffer(priv->conn, VNC_FRAMEBUFFER(priv->fb));
+
+	if (priv->force_size)
+		gtk_widget_set_size_request(GTK_WIDGET(obj), width, height);
 
 	if (!quiet) {
 		s.width = width;
@@ -1009,16 +998,24 @@ static gboolean do_resize(void *opaque, int width, int height, gboolean quiet)
 
 static gboolean on_resize(void *opaque, int width, int height)
 {
-	return do_resize(opaque, width, height, FALSE);
+        VncDisplay *obj = VNC_DISPLAY(opaque);
+	VncDisplayPrivate *priv = obj->priv;
+	const VncPixelFormat *remoteFormat;
+
+	remoteFormat = vnc_connection_get_pixel_format(priv->conn);
+
+	return do_framebuffer_init(opaque, remoteFormat, width, height, FALSE);
 }
 
 static gboolean on_pixel_format(void *opaque,
-				VncPixelFormat *fmt G_GNUC_UNUSED)
+				VncPixelFormat *remoteFormat)
 {
         VncDisplay *obj = VNC_DISPLAY(opaque);
         VncDisplayPrivate *priv = obj->priv;
+	gint16 width = vnc_connection_get_width(priv->conn);
+	gint16 height = vnc_connection_get_height(priv->conn);
 
-        return do_resize(opaque, priv->fb.width, priv->fb.height, TRUE);
+        return do_framebuffer_init(opaque, remoteFormat, width, height, TRUE);
 }
 
 static gboolean on_get_preferred_pixel_format(void *opaque,
@@ -1348,9 +1345,9 @@ static gboolean delayed_unref_object(gpointer data)
 
 	g_assert(obj->priv->coroutine.exited == TRUE);
 
-	if (obj->priv->image) {
-		g_object_unref(obj->priv->image);
-		obj->priv->image = NULL;
+	if (obj->priv->fb) {
+		g_object_unref(obj->priv->fb);
+		obj->priv->fb = NULL;
 	}
 	if (obj->priv->pixmap) {
 		g_object_unref(obj->priv->pixmap);
@@ -1428,13 +1425,16 @@ static void *vnc_coroutine(void *opaque)
 	if (!vnc_connection_set_encodings(priv->conn, n_encodings, encodingsp))
 			goto cleanup;
 
-	if (!vnc_connection_framebuffer_update_request(priv->conn, 0, 0, 0, priv->fb.width, priv->fb.height))
+	if (!vnc_connection_framebuffer_update_request(priv->conn, 0, 0, 0,
+						       vnc_connection_get_width(priv->conn),
+						       vnc_connection_get_height(priv->conn)))
 		goto cleanup;
 
 	GVNC_DEBUG("Running main loop");
 	while ((ret = vnc_connection_server_message(priv->conn))) {
 		if (!vnc_connection_framebuffer_update_request(priv->conn, 1, 0, 0,
-						     priv->fb.width, priv->fb.height))
+							       vnc_connection_get_width(priv->conn),
+							       vnc_connection_get_height(priv->conn)))
 			goto cleanup;
 	}
 
@@ -1622,9 +1622,9 @@ static void vnc_display_finalize (GObject *obj)
 	vnc_connection_free(priv->conn);
 	display->priv->conn = NULL;
 
-	if (priv->image) {
-		g_object_unref(priv->image);
-		priv->image = NULL;
+	if (priv->fb) {
+		g_object_unref(priv->fb);
+		priv->fb = NULL;
 	}
 
 	if (priv->null_cursor) {
@@ -2136,20 +2136,23 @@ GdkPixbuf *vnc_display_get_pixbuf(VncDisplay *obj)
 {
 	VncDisplayPrivate *priv = obj->priv;
 	GdkPixbuf *pixbuf;
+	GdkImage *image;
 
 	if (!priv->conn ||
 	    !vnc_connection_is_initialized(priv->conn))
 		return NULL;
 
+	image = vnc_image_framebuffer_get_image(priv->fb);
+
 	pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
-				priv->image->width, priv->image->height);
+				image->width, image->height);
 
 	if (!gdk_pixbuf_get_from_image(pixbuf,
-				       priv->image,
+				       image,
 				       gdk_colormap_get_system(),
 				       0, 0, 0, 0,
-				       priv->image->width,
-				       priv->image->height))
+				       image->width,
+				       image->height))
 		return NULL;
 
 	return pixbuf;
@@ -2338,11 +2341,11 @@ vnc_display_request_update(VncDisplay *obj)
 
 	GVNC_DEBUG ("Requesting a full update");
 	return vnc_connection_framebuffer_update_request(obj->priv->conn,
-					       0,
-					       0,
-					       0,
-					       obj->priv->fb.width,
-					       obj->priv->fb.height);
+							 0,
+							 0,
+							 0,
+							 vnc_connection_get_width(obj->priv->conn),
+							 vnc_connection_get_width(obj->priv->conn));
 }
 
 #ifdef WIN32
-- 
1.6.5.2



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]