Index: uspace/lib/gfx/include/gfx/coord.h
===================================================================
--- uspace/lib/gfx/include/gfx/coord.h	(revision e1f2079eea6e0ce553d66ced5b7ca0b64e0b4929)
+++ uspace/lib/gfx/include/gfx/coord.h	(revision 2a515dcdbf45d99dae90d9f82bc03f8416d806b7)
@@ -43,4 +43,6 @@
 extern void gfx_coord2_subtract(gfx_coord2_t *, gfx_coord2_t *, gfx_coord2_t *);
 extern void gfx_coord2_clip(gfx_coord2_t *, gfx_rect_t *, gfx_coord2_t *);
+extern void gfx_coord2_project(gfx_coord2_t *, gfx_rect_t *, gfx_rect_t *,
+    gfx_coord2_t *);
 extern void gfx_span_points_sort(gfx_coord_t, gfx_coord_t, gfx_coord_t *,
     gfx_coord_t *);
Index: uspace/lib/gfx/src/coord.c
===================================================================
--- uspace/lib/gfx/src/coord.c	(revision e1f2079eea6e0ce553d66ced5b7ca0b64e0b4929)
+++ uspace/lib/gfx/src/coord.c	(revision 2a515dcdbf45d99dae90d9f82bc03f8416d806b7)
@@ -62,4 +62,10 @@
 }
 
+/** Clip point coordinates to be within a rectangle.
+ *
+ * @param a Pixel coordinates
+ * @param clip Clipping rectangle
+ * @param d Place to store clipped coordinates
+ */
 void gfx_coord2_clip(gfx_coord2_t *a, gfx_rect_t *clip, gfx_coord2_t *d)
 {
@@ -74,4 +80,30 @@
 	d->x = max(clip->p0.x, t.x);
 	d->y = max(clip->p0.y, t.y);
+}
+
+/** Transform coordinates via rectangle to rectangle projection.
+ *
+ * Transform pixel coordinate via a projection that maps one rectangle
+ * onto another rectangle. The source rectangle must have both dimensions
+ * greater than one.
+ *
+ * @param a Pixel coordinates
+ * @param srect Source rectangle
+ * @param drect Destination rectangle
+ * @param d Place to store resulting coordinates.
+ */
+void gfx_coord2_project(gfx_coord2_t *a, gfx_rect_t *srect, gfx_rect_t *drect,
+    gfx_coord2_t *d)
+{
+	gfx_rect_t sr;
+	gfx_rect_t dr;
+
+	gfx_rect_points_sort(srect, &sr);
+	gfx_rect_points_sort(drect, &dr);
+
+	d->x = dr.p0.x + (a->x - sr.p0.x) * (dr.p1.x - dr.p0.x - 1) /
+	    (sr.p1.x - sr.p0.x - 1);
+	d->y = dr.p0.y + (a->y - sr.p0.y) * (dr.p1.y - dr.p0.y - 1) /
+	    (sr.p1.y - sr.p0.y - 1);
 }
 
Index: uspace/lib/gfx/test/coord.c
===================================================================
--- uspace/lib/gfx/test/coord.c	(revision e1f2079eea6e0ce553d66ced5b7ca0b64e0b4929)
+++ uspace/lib/gfx/test/coord.c	(revision 2a515dcdbf45d99dae90d9f82bc03f8416d806b7)
@@ -131,4 +131,45 @@
 }
 
+/** gfx_coord2_project projects pixel from one rectangle to another  */
+PCUT_TEST(coord2_project)
+{
+	gfx_coord2_t a, d;
+	gfx_rect_t srect, drect;
+
+	srect.p0.x = 10;
+	srect.p0.y = 10;
+	srect.p1.x = 20 + 1;
+	srect.p1.y = 20 + 1;
+
+	drect.p0.x = 100;
+	drect.p0.y = 100;
+	drect.p1.x = 200 + 1;
+	drect.p1.y = 200 + 1;
+
+	a.x = 10;
+	a.y = 10;
+	gfx_coord2_project(&a, &srect, &drect, &d);
+	PCUT_ASSERT_INT_EQUALS(100, d.x);
+	PCUT_ASSERT_INT_EQUALS(100, d.y);
+
+	a.x = 15;
+	a.y = 15;
+	gfx_coord2_project(&a, &srect, &drect, &d);
+	PCUT_ASSERT_INT_EQUALS(150, d.x);
+	PCUT_ASSERT_INT_EQUALS(150, d.y);
+
+	a.x = 12;
+	a.y = 16;
+	gfx_coord2_project(&a, &srect, &drect, &d);
+	PCUT_ASSERT_INT_EQUALS(120, d.x);
+	PCUT_ASSERT_INT_EQUALS(160, d.y);
+
+	a.x = 20;
+	a.y = 20;
+	gfx_coord2_project(&a, &srect, &drect, &d);
+	PCUT_ASSERT_INT_EQUALS(200, d.x);
+	PCUT_ASSERT_INT_EQUALS(200, d.y);
+}
+
 /** gfx_rect_translate should translate rectangle */
 PCUT_TEST(rect_translate)
