Index: uspace/lib/congfx/src/console.c
===================================================================
--- uspace/lib/congfx/src/console.c	(revision 1822545095edd9f4723bf932de051361380e1215)
+++ uspace/lib/congfx/src/console.c	(revision 7b882c1fb956e7997643c445ef2c7aed9e2891ff)
@@ -40,4 +40,5 @@
 #include <congfx/console.h>
 #include <gfx/context.h>
+#include <gfx/coord.h>
 #include <gfx/render.h>
 #include <io/pixel.h>
@@ -191,5 +192,5 @@
 	console_gc_t *cgc = (console_gc_t *) arg;
 	console_gc_bitmap_t *cbm = NULL;
-	gfx_coord_t w, h;
+	gfx_coord2_t dim;
 	errno_t rc;
 
@@ -198,12 +199,11 @@
 		return ENOMEM;
 
-	w = params->rect.p1.x - params->rect.p0.x;
-	h = params->rect.p1.y - params->rect.p0.y;
+	gfx_coord2_subtract(&params->rect.p1, &params->rect.p0, &dim);
 	cbm->rect = params->rect;
 
 	if (alloc == NULL) {
-		cbm->alloc.pitch = w * sizeof(uint32_t);
+		cbm->alloc.pitch = dim.x * sizeof(uint32_t);
 		cbm->alloc.off0 = 0;
-		cbm->alloc.pixels = calloc(w * h, sizeof(uint32_t));
+		cbm->alloc.pixels = calloc(dim.x * dim.y, sizeof(uint32_t));
 		if (cbm->alloc.pixels == NULL) {
 			rc = ENOMEM;
@@ -271,8 +271,5 @@
 
 	// XXX Add function to translate rectangle
-	drect.p0.x = srect.p0.x + offs.x;
-	drect.p0.y = srect.p0.y + offs.y;
-	drect.p1.x = srect.p1.x + offs.x;
-	drect.p1.y = srect.p1.y + offs.y;
+	gfx_rect_translate(&offs, &srect, &drect);
 
 	pixelmap.width = cbm->rect.p1.x - cbm->rect.p0.x;
@@ -313,5 +310,4 @@
 }
 
-
 /** @}
  */
Index: uspace/lib/gfx/include/gfx/coord.h
===================================================================
--- uspace/lib/gfx/include/gfx/coord.h	(revision 1822545095edd9f4723bf932de051361380e1215)
+++ uspace/lib/gfx/include/gfx/coord.h	(revision 7b882c1fb956e7997643c445ef2c7aed9e2891ff)
@@ -39,4 +39,8 @@
 #include <types/gfx/coord.h>
 
+extern void gfx_coord2_add(gfx_coord2_t *, gfx_coord2_t *, gfx_coord2_t *);
+extern void gfx_coord2_subtract(gfx_coord2_t *, gfx_coord2_t *, gfx_coord2_t *);
+extern void gfx_rect_translate(gfx_coord2_t *, gfx_rect_t *, gfx_rect_t *);
+
 #endif
 
Index: uspace/lib/gfx/include/types/gfx/coord.h
===================================================================
--- uspace/lib/gfx/include/types/gfx/coord.h	(revision 1822545095edd9f4723bf932de051361380e1215)
+++ uspace/lib/gfx/include/types/gfx/coord.h	(revision 7b882c1fb956e7997643c445ef2c7aed9e2891ff)
@@ -34,6 +34,6 @@
  */
 
-#ifndef _GFX_COORD_H
-#define _GFX_COORD_H
+#ifndef _GFX_TYPES_COORD_H
+#define _GFX_TYPES_COORD_H
 
 #include <errno.h>
Index: uspace/lib/gfx/meson.build
===================================================================
--- uspace/lib/gfx/meson.build	(revision 1822545095edd9f4723bf932de051361380e1215)
+++ uspace/lib/gfx/meson.build	(revision 7b882c1fb956e7997643c445ef2c7aed9e2891ff)
@@ -30,4 +30,5 @@
 	'src/bitmap.c',
 	'src/color.c',
+	'src/coord.c',
 	'src/context.c',
 	'src/render.c'
@@ -37,4 +38,5 @@
 	'test/bitmap.c',
 	'test/color.c',
+	'test/coord.c',
 	'test/main.c',
 	'test/render.c',
Index: uspace/lib/gfx/src/coord.c
===================================================================
--- uspace/lib/gfx/src/coord.c	(revision 7b882c1fb956e7997643c445ef2c7aed9e2891ff)
+++ uspace/lib/gfx/src/coord.c	(revision 7b882c1fb956e7997643c445ef2c7aed9e2891ff)
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2019 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libgfx
+ * @{
+ */
+/**
+ * @file Coordinates
+ */
+
+#include <gfx/coord.h>
+
+/** Add two vectors.
+ *
+ * @param a First vector
+ * @param b Second vector
+ * @param d Destination
+ */
+void gfx_coord2_add(gfx_coord2_t *a, gfx_coord2_t *b, gfx_coord2_t *d)
+{
+	d->x = a->x + b->x;
+	d->y = a->y + b->y;
+}
+
+/** Subtract two vectors.
+ *
+ * @param a First vector
+ * @param b Second vector
+ * @param d Destination
+ */
+void gfx_coord2_subtract(gfx_coord2_t *a, gfx_coord2_t *b, gfx_coord2_t *d)
+{
+	d->x = a->x - b->x;
+	d->y = a->y - b->y;
+}
+
+/** Move (translate) rectangle.
+ *
+ * @param trans Translation
+ * @param src Source rectangle
+ * @param dest Destination rectangle
+ */
+void gfx_rect_translate(gfx_coord2_t *trans, gfx_rect_t *src, gfx_rect_t *dest)
+{
+	gfx_coord2_add(trans, &src->p0, &dest->p0);
+	gfx_coord2_add(trans, &src->p1, &dest->p1);
+}
+
+/** @}
+ */
Index: uspace/lib/gfx/test/coord.c
===================================================================
--- uspace/lib/gfx/test/coord.c	(revision 7b882c1fb956e7997643c445ef2c7aed9e2891ff)
+++ uspace/lib/gfx/test/coord.c	(revision 7b882c1fb956e7997643c445ef2c7aed9e2891ff)
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2019 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <gfx/coord.h>
+#include <pcut/pcut.h>
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(coord);
+
+extern void gfx_coord2_add(gfx_coord2_t *, gfx_coord2_t *, gfx_coord2_t *);
+extern void gfx_coord2_subtract(gfx_coord2_t *, gfx_coord2_t *, gfx_coord2_t *);
+extern void gfx_rect_translate(gfx_coord2_t *, gfx_rect_t *, gfx_rect_t *);
+
+/** gfx_coord2_add should add two coordinate vectors */
+PCUT_TEST(coord2_add)
+{
+	gfx_coord2_t a, b;
+	gfx_coord2_t d;
+
+	a.x = 10;
+	a.y = 11;
+	b.x = 20;
+	b.y = 22;
+
+	gfx_coord2_add(&a, &b, &d);
+
+	PCUT_ASSERT_EQUALS(a.x + b.x, d.x);
+	PCUT_ASSERT_EQUALS(a.y + b.y, d.y);
+}
+
+/** gfx_coord2_subtract should subtract two coordinate vectors */
+PCUT_TEST(coord2_subtract)
+{
+	gfx_coord2_t a, b;
+	gfx_coord2_t d;
+
+	a.x = 10;
+	a.y = 11;
+	b.x = 20;
+	b.y = 22;
+
+	gfx_coord2_subtract(&a, &b, &d);
+
+	PCUT_ASSERT_EQUALS(a.x - b.x, d.x);
+	PCUT_ASSERT_EQUALS(a.y - b.y, d.y);
+}
+
+/** gfx_rect_translate should translate rectangle */
+PCUT_TEST(rect_translate)
+{
+	gfx_coord2_t offs;
+	gfx_rect_t srect;
+	gfx_rect_t drect;
+
+	offs.x = 5;
+	offs.y = 6;
+
+	srect.p0.x = 10;
+	srect.p0.y = 11;
+	srect.p1.x = 20;
+	srect.p1.y = 22;
+
+	gfx_rect_translate(&offs, &srect, &drect);
+
+	PCUT_ASSERT_EQUALS(offs.x + srect.p0.x, drect.p0.x);
+	PCUT_ASSERT_EQUALS(offs.y + srect.p0.y, drect.p0.y);
+	PCUT_ASSERT_EQUALS(offs.x + srect.p1.x, drect.p1.x);
+	PCUT_ASSERT_EQUALS(offs.y + srect.p1.y, drect.p1.y);
+}
+
+PCUT_EXPORT(coord);
Index: uspace/lib/gfx/test/main.c
===================================================================
--- uspace/lib/gfx/test/main.c	(revision 1822545095edd9f4723bf932de051361380e1215)
+++ uspace/lib/gfx/test/main.c	(revision 7b882c1fb956e7997643c445ef2c7aed9e2891ff)
@@ -33,4 +33,5 @@
 PCUT_IMPORT(bitmap);
 PCUT_IMPORT(color);
+PCUT_IMPORT(coord);
 PCUT_IMPORT(render);
 
Index: uspace/lib/guigfx/src/canvas.c
===================================================================
--- uspace/lib/guigfx/src/canvas.c	(revision 1822545095edd9f4723bf932de051361380e1215)
+++ uspace/lib/guigfx/src/canvas.c	(revision 7b882c1fb956e7997643c445ef2c7aed9e2891ff)
@@ -188,5 +188,5 @@
 	canvas_gc_t *cgc = (canvas_gc_t *) arg;
 	canvas_gc_bitmap_t *cbm = NULL;
-	gfx_coord_t w, h;
+	gfx_coord2_t dim;
 	errno_t rc;
 
@@ -195,10 +195,9 @@
 		return ENOMEM;
 
-	w = params->rect.p1.x - params->rect.p0.x;
-	h = params->rect.p1.y - params->rect.p0.y;
+	gfx_coord2_subtract(&params->rect.p1, &params->rect.p0, &dim);
 	cbm->rect = params->rect;
 
 	if (alloc == NULL) {
-		cbm->surface = surface_create(w, h, NULL, 0);
+		cbm->surface = surface_create(dim.x, dim.y, NULL, 0);
 		if (cbm->surface == NULL) {
 			rc = ENOMEM;
@@ -206,10 +205,10 @@
 		}
 
-		cbm->alloc.pitch = w * sizeof(uint32_t);
+		cbm->alloc.pitch = dim.x * sizeof(uint32_t);
 		cbm->alloc.off0 = 0;
 		cbm->alloc.pixels = surface_direct_access(cbm->surface);
 		cbm->myalloc = true;
 	} else {
-		cbm->surface = surface_create(w, h, alloc->pixels, 0);
+		cbm->surface = surface_create(dim.x, dim.y, alloc->pixels, 0);
 		if (cbm->surface == NULL) {
 			rc = ENOMEM;
@@ -259,4 +258,5 @@
 	gfx_rect_t drect;
 	gfx_coord2_t offs;
+	gfx_coord2_t dim;
 
 	if (srect0 != NULL)
@@ -272,9 +272,8 @@
 	}
 
-	// XXX Add function to translate rectangle
-	drect.p0.x = srect.p0.x + offs.x;
-	drect.p0.y = srect.p0.y + offs.y;
-	drect.p1.x = srect.p1.x + offs.x;
-	drect.p1.y = srect.p1.y + offs.y;
+	/* Destination rectangle */
+	gfx_rect_translate(&offs, &srect, &drect);
+
+	gfx_coord2_subtract(&drect.p1, &drect.p0, &dim);
 
 	transform_t transform;
@@ -293,6 +292,5 @@
 
 	drawctx_set_source(&drawctx, &source);
-	drawctx_transfer(&drawctx, drect.p0.x, drect.p0.y,
-	    drect.p1.x - drect.p0.x, drect.p1.y - drect.p0.y);
+	drawctx_transfer(&drawctx, drect.p0.x, drect.p0.y, dim.x, dim.y);
 
 	update_canvas(cbm->cgc->canvas, cbm->cgc->surface);
