Index: uspace/lib/c/generic/io/asprintf.c
===================================================================
--- uspace/lib/c/generic/io/asprintf.c	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/c/generic/io/asprintf.c	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -76,4 +76,32 @@
  *             the newly allocated string.
  * @fmt        Format string.
+ * @args       Variable argument list
+ *
+ * @return Number of characters printed or a negative error code.
+ *
+ */
+int vasprintf(char **strp, const char *fmt, va_list args)
+{
+	va_list args2;
+	va_copy(args2, args);
+	int ret = vprintf_size(fmt, args2);
+	va_end(args2);
+	
+	if (ret > 0) {
+		*strp = malloc(STR_BOUNDS(ret) + 1);
+		if (*strp == NULL)
+			return -1;
+		
+		vsnprintf(*strp, STR_BOUNDS(ret) + 1, fmt, args);
+	}
+	
+	return ret;
+}
+
+/** Allocate and print to string.
+ *
+ * @param strp Address of the pointer where to store the address of
+ *             the newly allocated string.
+ * @fmt        Format string.
  *
  * @return Number of characters printed or a negative error code.
@@ -84,16 +112,6 @@
 	va_list args;
 	va_start(args, fmt);
-	int ret = vprintf_size(fmt, args);
+	int ret = vasprintf(strp, fmt, args);
 	va_end(args);
-	
-	if (ret > 0) {
-		*strp = malloc(STR_BOUNDS(ret) + 1);
-		if (*strp == NULL)
-			return -1;
-		
-		va_start(args, fmt);
-		vsnprintf(*strp, STR_BOUNDS(ret) + 1, fmt, args);
-		va_end(args);
-	}
 	
 	return ret;
Index: uspace/lib/c/include/io/pixelmap.h
===================================================================
--- uspace/lib/c/include/io/pixelmap.h	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/c/include/io/pixelmap.h	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2011 Petr Koupy
+ * Copyright (c) 2014 Martin Sucha
  * All rights reserved.
  *
@@ -40,4 +41,21 @@
 #include <unistd.h>
 #include <io/pixel.h>
+
+/* Defines how a pixel outside of pixmap rectangle shall be treated */
+typedef enum {
+	/* Pixels outside of a pixmap are PIXEL(0, 0, 0, 0) */
+	PIXELMAP_EXTEND_TRANSPARENT_BLACK = 0,
+	
+	/* The pixmap is repeated infinetely */
+	PIXELMAP_EXTEND_TILE,
+	
+	/* If outside of a pixmap, return closest pixel from the edge */
+	PIXELMAP_EXTEND_SIDES,
+	
+	/* If outside of a pixmap, return closest pixel from the edge,
+	 * with alpha = 0
+	 */
+	PIXELMAP_EXTEND_TRANSPARENT_SIDES
+} pixelmap_extend_t;
 
 typedef struct {
@@ -86,4 +104,48 @@
 }
 
+static inline pixel_t pixelmap_get_extended_pixel(pixelmap_t *pixmap,
+    native_t x, native_t y, pixelmap_extend_t extend)
+{
+	bool transparent = false;
+	if (extend == PIXELMAP_EXTEND_TILE) {
+		x %= pixmap->width;
+		y %= pixmap->height;
+	}
+	else if (extend == PIXELMAP_EXTEND_SIDES ||
+	    extend == PIXELMAP_EXTEND_TRANSPARENT_SIDES) {
+		bool transparent_outside =
+		    (extend == PIXELMAP_EXTEND_TRANSPARENT_SIDES);
+		if (x < 0) {
+			x = 0;
+			transparent = transparent_outside;
+		}
+		else if (((sysarg_t) x) >= pixmap->width) {
+			x = pixmap->width - 1;
+			transparent = transparent_outside;
+		}
+		
+		if (y < 0) {
+			y = 0;
+			transparent = transparent_outside;
+		}
+		else if (((sysarg_t) y) >= pixmap->height) {
+			y = pixmap->height - 1;
+			transparent = transparent_outside;
+		}
+	}
+	
+	if (x < 0 || ((sysarg_t) x) >= pixmap->width ||
+	    y < 0 || ((sysarg_t) y) >= pixmap->height)
+		return PIXEL(0, 0, 0, 0);
+
+	pixel_t pixel = pixelmap_get_pixel(pixmap, x, y);
+	
+	if (transparent)
+		pixel = PIXEL(0, RED(pixel), GREEN(pixel), BLUE(pixel));
+	
+	return pixel;
+}
+
+
 #endif
 
Index: uspace/lib/c/include/stdio.h
===================================================================
--- uspace/lib/c/include/stdio.h	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/c/include/stdio.h	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -120,4 +120,5 @@
 extern int snprintf(char *, size_t , const char *, ...)
     PRINTF_ATTRIBUTE(3, 4);
+extern int vasprintf(char **, const char *, va_list);
 extern int asprintf(char **, const char *, ...)
     PRINTF_ATTRIBUTE(2, 3);
Index: uspace/lib/draw/Makefile
===================================================================
--- uspace/lib/draw/Makefile	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/draw/Makefile	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -37,4 +37,6 @@
 	cursor/embedded.c \
 	font/embedded.c \
+	font/bitmap_backend.c \
+	font/pcf.c \
 	gfx/font-8x16.c \
 	gfx/cursor-11x18.c \
Index: uspace/lib/draw/font.c
===================================================================
--- uspace/lib/draw/font.c	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/draw/font.c	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2012 Petr Koupy
+ * Copyright (c) 2014 Martin Sucha
  * All rights reserved.
  *
@@ -34,6 +35,7 @@
  */
 
-#include <assert.h>
 #include <malloc.h>
+#include <errno.h>
+#include <str.h>
 
 #include "font.h"
@@ -41,127 +43,129 @@
 #include "drawctx.h"
 
-void font_init(font_t *font, font_decoder_type_t decoder, char *path, uint16_t points)
+font_t *font_create(font_backend_t *backend, void *backend_data)
 {
-	font->points = points;
-
-	switch (decoder) {
-	case FONT_DECODER_EMBEDDED:
-		font->decoder = &fd_embedded;
-		break;
-	default:
-		font->decoder = NULL;
-		break;
-	}
-
-	if (font->decoder) {
-		font->decoder->init(path, &font->glyph_count, &font->decoder_data);
-
-		if (font->glyph_count > 0) {
-			font->glyphs = (surface_t **) malloc(sizeof(surface_t *) * font->glyph_count);
-		} else {
-			font->glyphs = NULL;
-		}
-
-		if (font->glyphs) {
-			for (size_t i = 0; i < font->glyph_count; ++i) {
-				font->glyphs[i] = NULL;
-			}
-		} else {
-			font->glyph_count = 0;
-		}
-	} else {
-		font->glyph_count = 0;
-		font->glyphs = NULL;
-		font->decoder_data = NULL;
-	}
+	font_t *font = malloc(sizeof(font_t));
+	if (font == NULL)
+		return NULL;
+	
+	font->backend = backend;
+	font->backend_data = backend_data;
+	
+	return font;
 }
 
 void font_release(font_t *font)
 {
-	if (font->glyphs) {
-		for (size_t i = 0; i < font->glyph_count; ++i) {
-			if (font->glyphs[i]) {
-				surface_destroy(font->glyphs[i]);
+	font->backend->release(font->backend_data);
+}
+
+int font_get_metrics(font_t *font, font_metrics_t *metrics) {
+	return font->backend->get_font_metrics(font->backend_data, metrics);
+}
+
+int font_resolve_glyph(font_t *font, wchar_t c, glyph_id_t *glyph_id) {
+	return font->backend->resolve_glyph(font->backend_data, c, glyph_id);
+}
+
+int font_get_glyph_metrics(font_t *font, glyph_id_t glyph_id,
+    glyph_metrics_t *glyph_metrics)
+{
+	return font->backend->get_glyph_metrics(font->backend_data,
+	    glyph_id, glyph_metrics);
+}
+
+int font_render_glyph(font_t *font, drawctx_t *context, source_t *source,
+    sysarg_t x, sysarg_t y, glyph_id_t glyph_id)
+{
+	return font->backend->render_glyph(font->backend_data, context, source,
+	    x, y, glyph_id);
+}
+
+/* TODO this is bad interface */
+int font_get_box(font_t *font, char *text, sysarg_t *width, sysarg_t *height)
+{
+	font_metrics_t fm;
+	int rc = font_get_metrics(font, &fm);
+	if (rc != EOK)
+		return rc;
+
+	native_t x = 0;
+
+	size_t off = 0;
+	while (true) {
+		wchar_t c = str_decode(text, &off, STR_NO_LIMIT);
+		if (c == 0)
+			break;
+		
+		glyph_id_t glyph_id;
+		rc = font_resolve_glyph(font, c, &glyph_id);
+		if (rc != EOK) {
+			int rc2 = font_resolve_glyph(font, U_SPECIAL, &glyph_id);
+			if (rc2 != EOK) {
+				return rc;
 			}
 		}
-		free(font->glyphs);
+		
+		glyph_metrics_t glyph_metrics;
+		rc = font_get_glyph_metrics(font, glyph_id, &glyph_metrics);
+		if (rc != EOK)
+			return rc;
+		
+		x += glyph_metrics_get_advancement(&glyph_metrics);
 	}
-	
-	if (font->decoder) {
-		font->decoder->release(font->decoder_data);
-	}
+
+	*width = x;
+	*height = fm.ascender + fm.descender;
+	return EOK;
 }
 
-void font_get_box(font_t *font, char *text, sysarg_t *width, sysarg_t *height)
+/* TODO this is bad interface */
+int font_draw_text(font_t *font, drawctx_t *context, source_t *source,
+    const char *text, sysarg_t sx, sysarg_t sy)
 {
-	assert(width);
-	assert(height);
-
-	(*width) = 0;
-	(*height) = 0;
-
-	if (!text) {
-		return;
-	}
-
-	while (*text) {
-		uint16_t glyph_idx = font->decoder->resolve(*text, font->decoder_data);
-		if (glyph_idx < font->glyph_count) {
-			if (!font->glyphs[glyph_idx]) {
-				font->glyphs[glyph_idx] =
-				    font->decoder->render(glyph_idx, font->points);
-			}
-
-			surface_t *glyph = font->glyphs[glyph_idx];
-			if (glyph) {
-				sysarg_t w;
-				sysarg_t h;
-				surface_get_resolution(glyph, &w, &h);
-				(*width) += w;
-				(*height) = (*height) < h ? h : (*height);
-			}
-		}
-		++text;
-	}
-}
-
-void font_draw_text(font_t *font, drawctx_t *context, source_t *source,
-    const char *text, sysarg_t x, sysarg_t y)
-{
-	assert(context);
-	assert(source);
-
 	drawctx_save(context);
 	drawctx_set_compose(context, compose_over);
 
-	while (*text) {
-		uint16_t glyph_idx = font->decoder->resolve(*text, font->decoder_data);
-		if (glyph_idx < font->glyph_count) {
-			if (!font->glyphs[glyph_idx]) {
-				font->glyphs[glyph_idx] =
-				    font->decoder->render(glyph_idx, font->points);
-			}
+	font_metrics_t fm;
+	int rc = font_get_metrics(font, &fm);
+	if (rc != EOK)
+		return rc;
 
-			surface_t *glyph = font->glyphs[glyph_idx];
-			if (glyph) {
-				sysarg_t w;
-				sysarg_t h;
-				surface_get_resolution(glyph, &w, &h);
+	native_t baseline = sy + fm.ascender;
+	native_t x = sx;
 
-				transform_t transform;
-				transform_identity(&transform);
-				transform_translate(&transform, x, y);
-				source_set_transform(source, transform);
-				source_set_mask(source, glyph, false);
-				drawctx_transfer(context, x, y, w, h);
-
-				x += w;
+	size_t off = 0;
+	while (true) {
+		wchar_t c = str_decode(text, &off, STR_NO_LIMIT);
+		if (c == 0)
+			break;
+		
+		glyph_id_t glyph_id;
+		rc = font_resolve_glyph(font, c, &glyph_id);
+		if (rc != EOK) {
+			int rc2 = font_resolve_glyph(font, U_SPECIAL, &glyph_id);
+			if (rc2 != EOK) {
+				return rc;
 			}
 		}
-		++text;
+		
+		glyph_metrics_t glyph_metrics;
+		rc = font_get_glyph_metrics(font, glyph_id, &glyph_metrics);
+		if (rc != EOK)
+			return rc;
+
+		rc = font_render_glyph(font, context, source, x, baseline,
+		    glyph_id);
+		if (rc != EOK)
+			return rc;
+
+		x += glyph_metrics_get_advancement(&glyph_metrics);
+
 	}
 
 	drawctx_restore(context);
 	source_set_mask(source, NULL, false);
+
+	return EOK;
 }
 
Index: uspace/lib/draw/font.h
===================================================================
--- uspace/lib/draw/font.h	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/draw/font.h	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2012 Petr Koupy
+ * Copyright (c) 2014 Martin Sucha
  * All rights reserved.
  *
@@ -45,28 +46,72 @@
 typedef struct drawctx drawctx_t;
 
-typedef enum {
-	FONT_DECODER_EMBEDDED
-} font_decoder_type_t;
+typedef int metric_t;
 
 typedef struct {
-	void (*init)(char *, uint16_t *, void **);
-	uint16_t (*resolve)(const wchar_t, void *);
-	surface_t *(*render)(uint16_t, uint16_t);
+	/* Horizontal distance between origin and left side of the glyph */ 
+	metric_t left_side_bearing;
+	
+	/* Width of the actual glyph drawn */
+	metric_t width;
+	
+	/* Horizontal distance between right side of the glyph and origin
+	   of the next glyph */
+	metric_t right_side_bearing;
+	
+	/* Vertical distance between baseline and top of the glyph
+	   (positive to top) */
+	metric_t ascender;
+	
+	/* Height of the actual glyph drawn */
+	metric_t height;
+} glyph_metrics_t;
+
+static inline metric_t glyph_metrics_get_descender(glyph_metrics_t *gm)
+{
+	return gm->height - gm->ascender;
+}
+
+static inline metric_t glyph_metrics_get_advancement(glyph_metrics_t *gm)
+{
+	return gm->left_side_bearing + gm->width + gm->right_side_bearing;
+}
+
+typedef struct {
+	/* Distance between top of the line and baseline */
+	metric_t ascender;
+	
+	/* Distance between baseline and bottom of the line */
+	metric_t descender;
+	
+	/* Distance between bottom of the line and top of the next line */
+	metric_t leading;
+} font_metrics_t;
+
+typedef uint32_t glyph_id_t;
+
+typedef struct {
+	int (*get_font_metrics)(void *, font_metrics_t *);
+	int (*resolve_glyph)(void *, wchar_t, glyph_id_t *);
+	int (*get_glyph_metrics)(void *, glyph_id_t, glyph_metrics_t *);
+	int (*render_glyph)(void *, drawctx_t *, source_t *, sysarg_t,
+	    sysarg_t, glyph_id_t);
 	void (*release)(void *);
-} font_decoder_t;
+} font_backend_t;
 
-typedef struct font {
-	uint16_t points;
-	uint16_t glyph_count;
-	surface_t **glyphs;
-	font_decoder_t *decoder;
-	void *decoder_data;
+typedef struct {
+	font_backend_t *backend;
+	void *backend_data;
 } font_t;
 
-extern void font_init(font_t *, font_decoder_type_t, char *, uint16_t);
+extern font_t *font_create(font_backend_t *, void *);
+extern int font_get_metrics(font_t *, font_metrics_t *);
+extern int font_resolve_glyph(font_t *, wchar_t, glyph_id_t *);
+extern int font_get_glyph_metrics(font_t *, glyph_id_t, glyph_metrics_t *);
+extern int font_render_glyph(font_t *, drawctx_t *, source_t *,
+    sysarg_t, sysarg_t, glyph_id_t);
 extern void font_release(font_t *);
 
-extern void font_get_box(font_t *, char *, sysarg_t *, sysarg_t *);
-extern void font_draw_text(font_t *, drawctx_t *, source_t *, const char *,
+extern int font_get_box(font_t *, char *, sysarg_t *, sysarg_t *);
+extern int font_draw_text(font_t *, drawctx_t *, source_t *, const char *,
     sysarg_t, sysarg_t);
 
Index: uspace/lib/draw/font/bitmap_backend.c
===================================================================
--- uspace/lib/draw/font/bitmap_backend.c	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
+++ uspace/lib/draw/font/bitmap_backend.c	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2012 Petr Koupy
+ * Copyright (c) 2014 Martin Sucha
+ * 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 draw
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <malloc.h>
+#include <errno.h>
+
+#include "../font.h"
+#include "../drawctx.h"
+#include "bitmap_backend.h"
+
+typedef struct {
+	surface_t *surface;
+	glyph_metrics_t metrics;
+	bool metrics_loaded;
+} glyph_cache_item_t;
+
+typedef struct {
+	uint16_t points;
+	uint32_t glyph_count;
+	font_metrics_t font_metrics;
+	glyph_cache_item_t *glyph_cache;
+	bitmap_font_decoder_t *decoder;
+	void *decoder_data;
+	bool scale;
+	double scale_ratio;
+} bitmap_backend_data_t;
+
+static int bb_get_font_metrics(void *backend_data, font_metrics_t *font_metrics)
+{
+	bitmap_backend_data_t *data = (bitmap_backend_data_t *) backend_data;
+	
+	*font_metrics = data->font_metrics;
+	
+	return EOK;
+}
+
+static int bb_resolve_glyph(void *backend_data, wchar_t c, glyph_id_t *glyph_id)
+{
+	bitmap_backend_data_t *data = (bitmap_backend_data_t *) backend_data;
+	return data->decoder->resolve_glyph(data->decoder_data, c, glyph_id);
+}
+
+static int bb_get_glyph_metrics(void *backend_data, glyph_id_t glyph_id,
+    glyph_metrics_t *glyph_metrics)
+{
+	bitmap_backend_data_t *data = (bitmap_backend_data_t *) backend_data;
+	
+	if (glyph_id >= data->glyph_count)
+		return ENOENT;
+	
+	if (data->glyph_cache[glyph_id].metrics_loaded) {
+		*glyph_metrics = data->glyph_cache[glyph_id].metrics;
+		return EOK;
+	}
+	
+	glyph_metrics_t gm;
+	
+	int rc = data->decoder->load_glyph_metrics(data->decoder_data, glyph_id,
+	    &gm);
+	if (rc != EOK)
+		return rc;
+	
+	if (data->scale) {
+		gm.left_side_bearing = (metric_t)
+		    (data->scale_ratio * gm.left_side_bearing + 0.5);
+		gm.width = (metric_t)
+		    (data->scale_ratio * gm.width + 0.5);
+		gm.right_side_bearing = (metric_t)
+		    (data->scale_ratio * gm.right_side_bearing + 0.5);
+		gm.ascender = (metric_t)
+		    (data->scale_ratio * gm.ascender + 0.5);
+		gm.height = (metric_t)
+		    (data->scale_ratio * gm.height + 0.5);
+	}
+	
+	
+	
+	data->glyph_cache[glyph_id].metrics = gm;
+	data->glyph_cache[glyph_id].metrics_loaded = true;
+	*glyph_metrics = gm;
+	return EOK;
+}
+
+static int get_glyph_surface(bitmap_backend_data_t *data, glyph_id_t glyph_id,
+    surface_t **result)
+{
+	if (glyph_id >= data->glyph_count)
+		return ENOENT;
+	
+	if (data->glyph_cache[glyph_id].surface != NULL) {
+		*result = data->glyph_cache[glyph_id].surface;
+		return EOK;
+	}
+	
+	surface_t *raw_surface;
+	int rc = data->decoder->load_glyph_surface(data->decoder_data, glyph_id,
+	    &raw_surface);
+	if (rc != EOK)
+		return rc;
+	
+	sysarg_t w;
+	sysarg_t h;
+	surface_get_resolution(raw_surface, &w, &h);
+	
+	if (!data->scale) {
+		*result = raw_surface;
+		return EOK;
+	}
+	
+	source_t source;
+	source_init(&source);
+	source_set_texture(&source, raw_surface, PIXELMAP_EXTEND_TRANSPARENT_BLACK);
+
+	transform_t transform;
+	transform_identity(&transform);
+	transform_translate(&transform, 0.5, 0.5);
+	transform_scale(&transform, data->scale_ratio, data->scale_ratio);
+	source_set_transform(&source, transform);
+
+	surface_coord_t scaled_width = (data->scale_ratio * ((double) w) + 0.5);
+	surface_coord_t scaled_height = (data->scale_ratio * ((double) h) + 0.5);
+
+	surface_t *scaled_surface = surface_create(scaled_width, scaled_height,
+	    NULL, 0);
+	if (!scaled_surface) {
+		surface_destroy(raw_surface);
+		return ENOMEM;
+	}
+
+	drawctx_t context;
+	drawctx_init(&context, scaled_surface);
+	drawctx_set_source(&context, &source);
+	drawctx_transfer(&context, 0, 0, scaled_width, scaled_height);
+
+	surface_destroy(raw_surface);
+	
+	data->glyph_cache[glyph_id].surface = scaled_surface;
+	*result = scaled_surface;
+	return EOK;
+}
+
+static int bb_render_glyph(void *backend_data, drawctx_t *context,
+    source_t *source, sysarg_t ox, sysarg_t oy, glyph_id_t glyph_id)
+{
+	bitmap_backend_data_t *data = (bitmap_backend_data_t *) backend_data;
+	
+	glyph_metrics_t glyph_metrics;
+	int rc = bb_get_glyph_metrics(backend_data, glyph_id, &glyph_metrics);
+	if (rc != EOK)
+		return rc;
+	
+	surface_t *glyph_surface;
+	rc = get_glyph_surface(data, glyph_id, &glyph_surface);
+	if (rc != EOK)
+		return rc;
+	
+	native_t x = ox + glyph_metrics.left_side_bearing;
+	native_t y = oy - glyph_metrics.ascender;
+	
+	transform_t transform;
+	transform_identity(&transform);
+	transform_translate(&transform, x, y);
+	source_set_transform(source, transform);
+	source_set_mask(source, glyph_surface, false);
+	drawctx_transfer(context, x, y, glyph_metrics.width,
+	    glyph_metrics.height);
+
+	return EOK;
+}
+
+static void bb_release(void *backend_data)
+{
+	bitmap_backend_data_t *data = (bitmap_backend_data_t *) backend_data;
+
+	for (size_t i = 0; i < data->glyph_count; ++i) {
+		if (data->glyph_cache[i].surface) {
+			surface_destroy(data->glyph_cache[i].surface);
+		}
+	}
+	free(data->glyph_cache);
+
+	data->decoder->release(data->decoder_data);
+}
+
+font_backend_t bitmap_backend = {
+	.get_font_metrics = bb_get_font_metrics,
+	.resolve_glyph = bb_resolve_glyph,
+	.get_glyph_metrics = bb_get_glyph_metrics,
+	.render_glyph = bb_render_glyph,
+	.release = bb_release
+};
+
+int bitmap_font_create(bitmap_font_decoder_t *decoder, void *decoder_data,
+    uint32_t glyph_count, font_metrics_t font_metrics, uint16_t points,
+    font_t **out_font)
+{
+	if (glyph_count == 0)
+		return EINVAL;
+	
+	bitmap_backend_data_t *data = malloc(sizeof(bitmap_backend_data_t));
+	if (data == NULL)
+		return ENOMEM;
+
+	data->glyph_count = glyph_count;
+	data->points = points;
+	data->decoder = decoder;
+	data->decoder_data = decoder_data;
+	data->font_metrics = font_metrics;
+	metric_t line_height = (font_metrics.ascender + font_metrics.descender);
+	if (points == line_height) {
+		data->scale = false;
+		data->scale_ratio = 1.0;
+	}
+	else {
+		data->scale = true;
+		data->scale_ratio = ((double) points) / ((double) line_height);
+		line_height = (data->scale_ratio * ((double) line_height));
+		data->font_metrics.ascender = (metric_t)
+		    (data->scale_ratio * data->font_metrics.ascender + 0.5);
+		data->font_metrics.descender =
+		    line_height - data->font_metrics.ascender;
+		data->font_metrics.leading = (metric_t)
+		    (data->scale_ratio * data->font_metrics.leading + 0.5);
+	}
+
+	data->glyph_cache = calloc(data->glyph_count,
+	    sizeof(glyph_cache_item_t));
+	if (data->glyph_cache == NULL) {
+		free(data);
+		return ENOMEM;
+	}
+
+	for (size_t i = 0; i < data->glyph_count; ++i) {
+		data->glyph_cache[i].surface = NULL;
+		data->glyph_cache[i].metrics_loaded = false;
+	}
+
+	font_t *font = font_create(&bitmap_backend, data);
+	if (font == NULL) {
+		free(data->glyph_cache);
+		free(data);
+		return ENOMEM;
+	}
+	
+	*out_font = font;
+	return EOK;
+}
+
+/** @}
+ */
Index: uspace/lib/draw/font/bitmap_backend.h
===================================================================
--- uspace/lib/draw/font/bitmap_backend.h	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
+++ uspace/lib/draw/font/bitmap_backend.h	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2012 Petr Koupy
+ * Copyright (c) 2014 Martin Sucha
+ * 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 draw
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef DRAW_FONT_BITMAP_BACKEND_H_
+#define DRAW_FONT_BITMAP_BACKEND_H_
+
+#include <sys/types.h>
+
+#include "../font.h"
+#include "../surface.h"
+#include "../source.h"
+
+typedef struct {
+	int (*resolve_glyph)(void *, const wchar_t, glyph_id_t *);
+	int (*load_glyph_surface)(void *, glyph_id_t, surface_t **);
+	int (*load_glyph_metrics)(void *, glyph_id_t, glyph_metrics_t *);
+	void (*release)(void *);
+} bitmap_font_decoder_t;
+
+extern int bitmap_font_create(bitmap_font_decoder_t *, void *, uint32_t,
+    font_metrics_t, uint16_t, font_t **);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/draw/font/embedded.c
===================================================================
--- uspace/lib/draw/font/embedded.c	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/draw/font/embedded.c	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2012 Petr Koupy
+ * Copyright (c) 2014 Martin Sucha
  * All rights reserved.
  *
@@ -34,71 +35,55 @@
  */
 
-#include <assert.h>
 #include <sys/types.h>
 #include <malloc.h>
+#include <errno.h>
 
 #include "../gfx/font-8x16.h"
 #include "embedded.h"
 #include "../drawctx.h"
+#include "bitmap_backend.h"
 
-static void fde_init(char *path, uint16_t *glyph_count, void **data)
+static int fde_resolve_glyph(void *unused, const wchar_t chr,
+    glyph_id_t *glyph_id)
 {
-	assert(glyph_count);
-	assert(data);
-
-	(*glyph_count) = FONT_GLYPHS;
-	(*data) = NULL;
+	bool found = false;
+	uint16_t glyph = fb_font_glyph(chr, &found);
+	if (!found)
+		return ENOENT;
+	
+	*glyph_id = glyph;
+	return EOK;
 }
 
-static uint16_t fde_resolve(const wchar_t chr, void *data)
+static int fde_load_glyph_surface(void *unused, glyph_id_t glyph_id,
+    surface_t **out_surface)
 {
-	return fb_font_glyph(chr);
+	surface_t *surface = surface_create(FONT_WIDTH, FONT_SCANLINES, NULL, 0);
+	if (!surface)
+		return ENOMEM;
+	
+	for (unsigned int y = 0; y < FONT_SCANLINES; ++y) {
+		for (unsigned int x = 0; x < FONT_WIDTH; ++x) {
+			pixel_t p = (fb_font[glyph_id][y] & (1 << (7 - x))) ? 
+			    PIXEL(255, 0, 0, 0) : PIXEL(0, 0, 0, 0);
+			surface_put_pixel(surface, x, y, p);
+		}
+	}
+	
+	*out_surface = surface;
+	return EOK;
 }
 
-static surface_t *fde_render(uint16_t glyph, uint16_t points)
+static int fde_load_glyph_metrics(void *unused, glyph_id_t glyph_id,
+    glyph_metrics_t *gm)
 {
-	surface_t *template = surface_create(FONT_WIDTH, FONT_SCANLINES, NULL, 0);
-	if (!template) {
-		return NULL;
-	}
-	for (unsigned int y = 0; y < FONT_SCANLINES; ++y) {
-		for (unsigned int x = 0; x < FONT_WIDTH; ++x) {
-			pixel_t p = (fb_font[glyph][y] & (1 << (7 - x))) ? 
-			    PIXEL(255, 0, 0, 0) : PIXEL(0, 0, 0, 0);
-			surface_put_pixel(template, x, y, p);
-		}
-	}
-
-	source_t source;
-	source_init(&source);
-	source_set_texture(&source, template, false);
-
-	transform_t transform;
-	transform_identity(&transform);
-	if (points != FONT_SCANLINES) {
-		double ratio = ((double) points) / ((double) FONT_SCANLINES);
-		transform_scale(&transform, ratio, ratio);
-		source_set_transform(&source, transform);
-	}
-
-	double width = FONT_WIDTH;
-	double height = FONT_SCANLINES;
-	transform_apply_linear(&transform, &width, &height);
-	surface_t *result =
-	    surface_create((sysarg_t) (width + 0.5), (sysarg_t) (height + 0.5), NULL, 0);
-	if (!result) {
-		surface_destroy(template);
-		return NULL;
-	}
-
-	drawctx_t context;
-	drawctx_init(&context, result);
-	drawctx_set_source(&context, &source);
-	drawctx_transfer(&context, 0, 0,
-	    (sysarg_t) (width + 0.5), (sysarg_t) (height + 0.5));
-
-	surface_destroy(template);
-
-	return result;
+	/* This is simple monospaced font, so fill this data statically */
+	gm->left_side_bearing = 0;
+	gm->width = FONT_WIDTH;
+	gm->right_side_bearing = 0;
+	gm->ascender = FONT_ASCENDER;
+	gm->height = FONT_SCANLINES;
+	
+	return EOK;
 }
 
@@ -108,11 +93,23 @@
 }
 
-font_decoder_t fd_embedded = {
-	.init = fde_init,
-	.resolve = fde_resolve,
-	.render = fde_render,
+bitmap_font_decoder_t fd_embedded = {
+	.resolve_glyph = fde_resolve_glyph,
+	.load_glyph_surface = fde_load_glyph_surface,
+	.load_glyph_metrics = fde_load_glyph_metrics,
 	.release = fde_release
 };
 
+font_metrics_t font_metrics = {
+	.ascender = FONT_ASCENDER,
+	.descender = (FONT_SCANLINES - FONT_ASCENDER),
+	.leading = 0
+};
+
+int embedded_font_create(font_t **font, uint16_t points)
+{
+	return bitmap_font_create(&fd_embedded, NULL, FONT_GLYPHS, font_metrics,
+	    points, font);
+}
+
 /** @}
  */
Index: uspace/lib/draw/font/embedded.h
===================================================================
--- uspace/lib/draw/font/embedded.h	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/draw/font/embedded.h	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -39,5 +39,5 @@
 #include "../font.h"
 
-extern font_decoder_t fd_embedded;
+extern int embedded_font_create(font_t **, uint16_t points);
 
 #endif
Index: uspace/lib/draw/font/pcf.c
===================================================================
--- uspace/lib/draw/font/pcf.c	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
+++ uspace/lib/draw/font/pcf.c	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -0,0 +1,628 @@
+/*
+ * Copyright (c) 2014 Martin Sucha
+ * 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 draw
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <sys/types.h>
+#include <malloc.h>
+#include <errno.h>
+#include <byteorder.h>
+#include <stdio.h>
+#include <align.h>
+
+#include "pcf.h"
+#include "../drawctx.h"
+#include "bitmap_backend.h"
+
+#define PCF_TABLE_ACCELERATORS 0x02
+#define PCF_TABLE_METRICS      0x04
+#define PCF_TABLE_BITMAPS      0x08
+#define PCF_TABLE_INK_METRICS  0x10
+#define PCF_TABLE_ENCODINGS    0x20
+
+#define PCF_FORMAT_DEFAULT            0x00000000
+#define PCF_FORMAT_MASK               0xffffff00
+#define PCF_FORMAT_MSBYTE_FIRST       0x00000004
+#define PCF_FORMAT_MSBIT_FIRST        0x00000008
+#define PCF_FORMAT_COMPRESSED_METRICS 0x00000100
+
+typedef struct {
+	uint32_t type;
+	uint32_t format;
+	uint32_t size; /* in bytes */
+	uint32_t offset; /* in bytes from beginning of file */
+} __attribute__((__packed__)) pcf_toc_entry_t;
+
+typedef struct {
+	uint16_t min_byte2;
+	uint16_t max_byte2;
+	uint16_t min_byte1;
+	uint16_t max_byte1;
+	uint16_t default_char;
+} __attribute__((__packed__)) pcf_encoding_t;
+
+typedef struct {
+	uint8_t left_side_bearing;
+	uint8_t right_side_bearing;
+	uint8_t character_width;
+	uint8_t character_ascent;
+	uint8_t character_descent;
+} __attribute__((__packed__)) pcf_compressed_metrics_t;
+
+typedef struct {
+	int16_t left_side_bearing;
+	int16_t right_side_bearing;
+	int16_t character_width;
+	int16_t character_ascent;
+	int16_t character_descent;
+	uint16_t character_attributes;
+} __attribute__((__packed__)) pcf_default_metrics_t;
+
+typedef struct {
+	uint8_t unused_font_information[8];
+	int32_t font_ascent;
+	int32_t font_descent;
+} __attribute__((__packed__)) pcf_accelerators_t;
+
+typedef struct {
+	FILE *file;
+	uint32_t glyph_count;
+	pcf_toc_entry_t bitmap_table;
+	pcf_toc_entry_t metrics_table;
+	pcf_toc_entry_t encodings_table;
+	pcf_toc_entry_t accelerators_table;
+	pcf_encoding_t encoding;
+	font_metrics_t font_metrics;
+} pcf_data_t;
+
+static inline uint32_t uint32_t_pcf2host(uint32_t val, uint32_t format)
+{
+	if (format & PCF_FORMAT_MSBYTE_FIRST) {
+		return uint32_t_be2host(val);
+	}
+	else {
+		return uint32_t_le2host(val);
+	}
+}
+
+static inline uint16_t uint16_t_pcf2host(uint16_t val, uint32_t format)
+{
+	if (format & PCF_FORMAT_MSBYTE_FIRST) {
+		return uint16_t_be2host(val);
+	}
+	else {
+		return uint16_t_le2host(val);
+	}
+}
+
+static inline int16_t int16_t_pcf2host(int16_t val, uint32_t format)
+{
+	return (int16_t) uint16_t_pcf2host((uint16_t) val, format);
+}
+
+static inline int32_t int32_t_pcf2host(int32_t val, uint32_t format)
+{
+	return (int32_t) uint32_t_pcf2host((uint32_t) val, format);
+}
+
+
+static int16_t compressed2int(uint8_t compressed)
+{
+	int16_t ret = compressed;
+	ret -= 0x80;
+	return ret;
+}
+
+static int pcf_resolve_glyph(void *opaque_data, const wchar_t chr,
+    glyph_id_t *glyph_id)
+{
+	pcf_data_t *data = (pcf_data_t *) opaque_data;
+	
+	/* TODO is this correct? */
+	uint8_t byte1 = (chr >> 8) & 0xff;
+	uint8_t byte2 = chr & 0xff;
+	pcf_encoding_t *e = &data->encoding;
+
+	aoff64_t entry_index =
+	    (byte1 - e->min_byte1) * (e->max_byte2 - e->min_byte2 + 1) +
+	    (byte2 - e->min_byte2);
+	
+	aoff64_t entry_offset = data->encodings_table.offset +
+	    (sizeof(uint32_t) + 5 * sizeof(uint16_t)) +
+	    entry_index * sizeof(uint16_t);
+	
+	int rc = fseek(data->file, entry_offset, SEEK_SET);
+	if (rc != 0)
+		return errno;
+	
+	uint16_t glyph = 0;
+	size_t records_read = fread(&glyph, sizeof(uint16_t), 1, data->file);
+	if (records_read != 1)
+		return EINVAL;
+	
+	glyph = uint16_t_pcf2host(glyph, data->encodings_table.format);
+	
+	if (glyph == 0xffff)
+		return ENOENT;
+	
+	*glyph_id = glyph;
+	
+	return EOK;
+}
+
+static int load_glyph_metrics(pcf_data_t *data, uint32_t glyph_id,
+    pcf_toc_entry_t *table, pcf_default_metrics_t *metrics)
+{
+	aoff64_t offset;
+	int rc;
+	size_t records_read;
+	
+	if (table->format & PCF_FORMAT_COMPRESSED_METRICS) {
+		offset = table->offset + sizeof(uint32_t) + sizeof(uint16_t) +
+		    glyph_id * sizeof(pcf_compressed_metrics_t);
+		
+		rc = fseek(data->file, offset, SEEK_SET);
+		if (rc != 0)
+			return errno;
+		
+		pcf_compressed_metrics_t compressed_metrics;
+		records_read = fread(&compressed_metrics,
+		    sizeof(pcf_compressed_metrics_t), 1,data->file);
+		if (records_read != 1)
+			return EINVAL;
+		
+		metrics->left_side_bearing =
+		    compressed2int(compressed_metrics.left_side_bearing);
+		metrics->right_side_bearing =
+		    compressed2int(compressed_metrics.right_side_bearing);
+		metrics->character_width =
+		    compressed2int(compressed_metrics.character_width);
+		metrics->character_ascent =
+		    compressed2int(compressed_metrics.character_ascent);
+		metrics->character_descent =
+		    compressed2int(compressed_metrics.character_descent);
+		metrics->character_attributes = 0;
+	}
+	else {
+		offset = table->offset + 2 * sizeof(uint32_t) +
+		    glyph_id * sizeof(pcf_default_metrics_t);
+		
+		rc = fseek(data->file, offset, SEEK_SET);
+		if (rc != 0)
+			return errno;
+	
+		pcf_default_metrics_t uncompressed_metrics;
+		records_read = fread(&uncompressed_metrics,
+		    sizeof(pcf_default_metrics_t), 1,data->file);
+		if (records_read != 1)
+			return EINVAL;
+		
+		metrics->left_side_bearing =
+		    int16_t_pcf2host(uncompressed_metrics.left_side_bearing,
+		    table->format);
+		metrics->right_side_bearing =
+		    int16_t_pcf2host(uncompressed_metrics.right_side_bearing,
+		    table->format);
+		metrics->character_width =
+		    int16_t_pcf2host(uncompressed_metrics.character_width,
+		    table->format);
+		metrics->character_ascent =
+		    int16_t_pcf2host(uncompressed_metrics.character_ascent,
+		    table->format);
+		metrics->character_descent =
+		    int16_t_pcf2host(uncompressed_metrics.character_descent,
+		    table->format);
+		metrics->character_attributes =
+		    uint16_t_pcf2host(uncompressed_metrics.character_attributes,
+		    table->format);
+	}
+	
+	return EOK;
+}
+
+static int pcf_load_glyph_surface(void *opaque_data, glyph_id_t glyph_id,
+    surface_t **out_surface)
+{
+	pcf_data_t *data = (pcf_data_t *) opaque_data;
+	
+	pcf_default_metrics_t pcf_metrics;
+	memset(&pcf_metrics, 0, sizeof(pcf_default_metrics_t));
+	int rc = load_glyph_metrics(data, glyph_id, &data->metrics_table,
+	    &pcf_metrics);
+	if (rc != EOK)
+		return rc;
+	
+	aoff64_t offset = data->bitmap_table.offset + (2 * sizeof(uint32_t)) +
+	    (glyph_id * sizeof(uint32_t));
+	
+	rc = fseek(data->file, offset, SEEK_SET);
+	if (rc != 0)
+		return errno;
+	
+	uint32_t bitmap_offset = 0;
+	size_t records_read = fread(&bitmap_offset, sizeof(uint32_t), 1,
+	    data->file);
+	if (records_read != 1)
+		return EINVAL;
+	bitmap_offset = uint32_t_pcf2host(bitmap_offset,
+	    data->bitmap_table.format);
+	
+	offset = data->bitmap_table.offset + (2 * sizeof(uint32_t)) +
+	    (data->glyph_count * sizeof(uint32_t)) + (4 * sizeof(uint32_t))
+	    + bitmap_offset;
+	
+	rc = fseek(data->file, offset, SEEK_SET);
+	if (rc != 0)
+		return errno;
+	
+	surface_coord_t width = pcf_metrics.character_width;
+	surface_coord_t height = pcf_metrics.character_ascent +
+	    pcf_metrics.character_descent;
+	size_t row_padding_bytes = (1 << (data->bitmap_table.format & 3));
+	size_t word_size_bytes = (1 << ((data->bitmap_table.format >> 4) & 3));
+	size_t row_bytes = ALIGN_UP(ALIGN_UP(width, 8) / 8, row_padding_bytes);
+	size_t bitmap_bytes = height * row_bytes;
+	
+	uint8_t *bitmap = malloc(bitmap_bytes);
+	if (bitmap == NULL)
+		return ENOMEM;
+	
+	records_read = fread(bitmap, sizeof(uint8_t), bitmap_bytes,
+	    data->file);
+	
+	surface_t *surface = surface_create(width, height, NULL, 0);
+	if (!surface) {
+		free(bitmap);
+		return ENOMEM;
+	}
+	
+	for (unsigned int y = 0; y < height; ++y) {
+		size_t row_offset = row_bytes * y;
+		for (unsigned int x = 0; x < width; ++x) {
+			size_t word_index = x / (word_size_bytes * 8);
+			size_t column_offset1 = word_index * word_size_bytes;
+			size_t byte_index_within_word =
+				(x % (word_size_bytes * 8)) / 8;
+			size_t column_offset2;
+			if (data->bitmap_table.format & PCF_FORMAT_MSBYTE_FIRST) {
+				column_offset2 = (word_size_bytes - 1) - byte_index_within_word;
+			}
+			else {
+				column_offset2 = byte_index_within_word;
+			}
+			uint8_t b = bitmap[row_offset + column_offset1 + column_offset2];
+			bool set;
+			if (data->bitmap_table.format & PCF_FORMAT_MSBIT_FIRST) {
+				set = (b >> (7 - (x % 8))) & 1;
+			}
+			else {
+				set = (b >> (x % 8)) & 1;
+			}
+			pixel_t p = set ? PIXEL(255, 0, 0, 0) : PIXEL(0, 0, 0, 0);
+			surface_put_pixel(surface, x, y, p);
+		}
+	}
+	
+	*out_surface = surface;
+	free(bitmap);
+	return EOK;
+}
+
+static int pcf_load_glyph_metrics(void *opaque_data, glyph_id_t glyph_id,
+    glyph_metrics_t *gm)
+{
+	pcf_data_t *data = (pcf_data_t *) opaque_data;
+	
+	pcf_default_metrics_t pcf_metrics;
+	memset(&pcf_metrics, 0, sizeof(pcf_default_metrics_t));
+	int rc = load_glyph_metrics(data, glyph_id, &data->metrics_table,
+	    &pcf_metrics);
+	if (rc != EOK)
+		return rc;
+	
+	gm->left_side_bearing = pcf_metrics.left_side_bearing;
+	gm->width = pcf_metrics.character_width;
+	gm->right_side_bearing = pcf_metrics.right_side_bearing -
+	    pcf_metrics.character_width;
+	gm->height = pcf_metrics.character_descent +
+	    pcf_metrics.character_ascent;
+	gm->ascender = pcf_metrics.character_ascent;
+	
+	return EOK;
+}
+
+static void pcf_release(void *opaque_data)
+{
+	pcf_data_t *data = (pcf_data_t *) opaque_data;
+	
+	fclose(data->file);
+	free(data);
+}
+
+bitmap_font_decoder_t fd_pcf = {
+	.resolve_glyph = pcf_resolve_glyph,
+	.load_glyph_surface = pcf_load_glyph_surface,
+	.load_glyph_metrics = pcf_load_glyph_metrics,
+	.release = pcf_release
+};
+
+static int pcf_read_toc(pcf_data_t *data)
+{
+	int rc = fseek(data->file, 0, SEEK_END);
+	if (rc != 0)
+		return errno;
+	
+	aoff64_t file_size = ftell(data->file);
+	
+	rc = fseek(data->file, 0, SEEK_SET);
+	if (rc != 0)
+		return errno;
+	
+	char header[4];
+	size_t records_read = fread(header, sizeof(char), 4, data->file);
+	if (records_read != 4)
+		return EINVAL;
+	
+	if (header[0] != 1 || header[1] != 'f' || header[2] != 'c' ||
+	    header[3] != 'p')
+		return EINVAL;
+	
+	uint32_t table_count;
+	records_read = fread(&table_count, sizeof(uint32_t), 1,
+	    data->file);
+	if (records_read != 1)
+		return EINVAL;
+	
+	table_count = uint32_t_le2host(table_count);
+	
+	bool found_bitmap_table = false;
+	bool found_metrics_table = false;
+	bool found_encodings_table = false;
+	bool found_accelerators_table = false;
+	
+	for (uint32_t index = 0; index < table_count; index++) {
+		pcf_toc_entry_t toc_entry;
+		records_read = fread(&toc_entry, sizeof(pcf_toc_entry_t), 1,
+		    data->file);
+		toc_entry.type = uint32_t_le2host(toc_entry.type);
+		toc_entry.format = uint32_t_le2host(toc_entry.format);
+		toc_entry.size = uint32_t_le2host(toc_entry.size);
+		toc_entry.offset = uint32_t_le2host(toc_entry.offset);
+		
+		if (toc_entry.offset >= file_size)
+			continue;
+		
+		aoff64_t end = ((aoff64_t) toc_entry.offset) + ((aoff64_t) toc_entry.size);
+		if (end > file_size)
+			continue;
+		
+		if (toc_entry.type == PCF_TABLE_BITMAPS) {
+			if (found_bitmap_table)
+				return EINVAL;
+			found_bitmap_table = true;
+			data->bitmap_table = toc_entry;
+		}
+		else if (toc_entry.type == PCF_TABLE_METRICS) {
+			if (found_metrics_table)
+				return EINVAL;
+			found_metrics_table = true;
+			data->metrics_table = toc_entry;
+		}
+		else if (toc_entry.type == PCF_TABLE_ENCODINGS) {
+			if (found_encodings_table)
+				return EINVAL;
+			found_encodings_table = true;
+			data->encodings_table = toc_entry;
+		}
+		else if (toc_entry.type == PCF_TABLE_ACCELERATORS) {
+			if (found_accelerators_table)
+				return EINVAL;
+			found_accelerators_table = true;
+			data->accelerators_table = toc_entry;
+		}
+	}
+	
+	if (!found_bitmap_table || !found_metrics_table ||
+	    !found_encodings_table || !found_accelerators_table)
+		return EINVAL;
+	
+	return EOK;
+}
+
+static int pcf_seek_table_header(pcf_data_t *data, pcf_toc_entry_t *table)
+{
+	uint32_t format;
+	int rc = fseek(data->file, table->offset, SEEK_SET);
+	if (rc != 0)
+		return errno;
+	
+	size_t records_read = fread(&format, sizeof(uint32_t), 1, data->file);
+	if (records_read != 1)
+		return EINVAL;
+	
+	format = uint32_t_le2host(format);
+	if (format != table->format)
+		return EINVAL;
+	
+	return EOK;
+}
+
+static int pcf_read_bitmap_table_header(pcf_data_t *data)
+{
+	int rc = pcf_seek_table_header(data, &data->bitmap_table);
+	if (rc != EOK)
+		return rc;
+	
+	if ((data->bitmap_table.format & PCF_FORMAT_MASK) != PCF_FORMAT_DEFAULT)
+		return EINVAL;
+	
+	uint32_t glyph_count = 0;
+	size_t records_read = fread(&glyph_count, sizeof(uint32_t), 1,
+	    data->file);
+	if (records_read != 1)
+		return EINVAL;
+	glyph_count =  uint32_t_pcf2host(glyph_count, data->bitmap_table.format);
+
+	data->glyph_count = glyph_count;
+	return EOK;
+}
+
+static int pcf_read_metrics_table_header(pcf_data_t *data)
+{
+	int rc = pcf_seek_table_header(data, &data->metrics_table);
+	if (rc != EOK)
+		return rc;
+	
+	size_t records_read;
+	uint32_t metrics_count;
+	if (data->metrics_table.format & PCF_FORMAT_COMPRESSED_METRICS) {
+		uint16_t metrics_count_16;
+		records_read = fread(&metrics_count_16, sizeof(uint16_t), 1,
+		    data->file);
+		if (records_read != 1)
+			return EINVAL;
+		metrics_count_16 = uint16_t_pcf2host(metrics_count_16,
+		    data->metrics_table.format);
+		metrics_count = metrics_count_16;
+	}
+	else {
+		records_read = fread(&metrics_count, sizeof(uint32_t), 1,
+		    data->file);
+		if (records_read != 1)
+			return EINVAL;
+		metrics_count = uint32_t_pcf2host(metrics_count,
+		    data->metrics_table.format);
+	}
+	
+	if (metrics_count != data->glyph_count)
+		return EINVAL;
+	
+	return EOK;
+}
+
+static int pcf_read_encodings_table_header(pcf_data_t *data)
+{
+	int rc = pcf_seek_table_header(data, &data->encodings_table);
+	if (rc != EOK)
+		return rc;
+	
+	pcf_encoding_t encoding;
+	size_t records_read = fread(&encoding, sizeof(pcf_encoding_t), 1,
+	    data->file);
+	if (records_read != 1)
+		return EINVAL;
+	
+	encoding.min_byte1 = uint16_t_pcf2host(encoding.min_byte1,
+	    data->encodings_table.format);
+	encoding.max_byte1 = uint16_t_pcf2host(encoding.max_byte1,
+	    data->encodings_table.format);
+	encoding.min_byte2 = uint16_t_pcf2host(encoding.min_byte2,
+	    data->encodings_table.format);
+	encoding.max_byte2 = uint16_t_pcf2host(encoding.max_byte2,
+	    data->encodings_table.format);
+	encoding.default_char = uint16_t_pcf2host(encoding.default_char,
+	    data->encodings_table.format);
+	
+	data->encoding = encoding;
+	return EOK;
+}
+
+static int pcf_read_accelerators_table(pcf_data_t *data)
+{
+	int rc = pcf_seek_table_header(data, &data->accelerators_table);
+	if (rc != EOK)
+		return rc;
+	
+	pcf_accelerators_t accelerators;
+	size_t records_read = fread(&accelerators, sizeof(pcf_accelerators_t),
+	    1, data->file);
+	if (records_read != 1)
+		return EINVAL;
+	
+	data->font_metrics.ascender = int32_t_pcf2host(accelerators.font_ascent,
+	    data->accelerators_table.format);
+	data->font_metrics.descender = int32_t_pcf2host(accelerators.font_descent,
+	    data->accelerators_table.format);
+	data->font_metrics.leading = 0;
+	
+	return EOK;
+}
+
+int pcf_font_create(font_t **font, char *filename, uint16_t points)
+{
+	int rc;
+	pcf_data_t *data = malloc(sizeof(pcf_data_t));
+	if (data == NULL)
+		return ENOMEM;
+	
+	data->file = fopen(filename, "rb");
+	if (data->file == NULL)
+		goto read_error;
+	
+	rc = pcf_read_toc(data);
+	if (rc != EOK)
+		goto error;
+	
+	rc = pcf_read_bitmap_table_header(data);
+	if (rc != EOK)
+		goto error;
+	
+	rc = pcf_read_metrics_table_header(data);
+	if (rc != EOK)
+		goto error;
+	
+	rc = pcf_read_encodings_table_header(data);
+	if (rc != EOK)
+		goto error;
+	
+	rc = pcf_read_accelerators_table(data);
+	if (rc != EOK)
+		goto error;
+	
+	rc = bitmap_font_create(&fd_pcf, data, data->glyph_count,
+	    data->font_metrics, points, font);
+	if (rc != EOK)
+		goto error;
+	
+	return EOK;
+read_error:
+	rc = EINVAL;
+error:
+	if (data->file)
+		fclose(data->file);
+	free(data);
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/draw/font/pcf.h
===================================================================
--- uspace/lib/draw/font/pcf.h	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
+++ uspace/lib/draw/font/pcf.h	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2014 Martin Sucha
+ * 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 draw
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef DRAW_FONT_PBF_H_
+#define DRAW_FONT_PBF_H_
+
+#include "../font.h"
+
+extern int pcf_font_create(font_t **, char *path, uint16_t points);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/draw/gfx/font-8x16.c
===================================================================
--- uspace/lib/draw/gfx/font-8x16.c	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/draw/gfx/font-8x16.c	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -44,7 +44,12 @@
  * mark glyph if no specific glyph exists.
  *
+ * If found is not null, indicate whether the glyph was found or not.
+ *
  */
-uint16_t fb_font_glyph(const wchar_t ch)
+uint16_t fb_font_glyph(const wchar_t ch, bool *found)
 {
+	if (found)
+		*found = true;
+	
 	if (ch == 0x0000)
 		return 0;
@@ -361,4 +366,7 @@
 	if (ch == 0xfeff)
 		return 2896;
+	
+	if (found)
+		*found = false;
 	
 	return 2898;
Index: uspace/lib/draw/gfx/font-8x16.h
===================================================================
--- uspace/lib/draw/gfx/font-8x16.h	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/draw/gfx/font-8x16.h	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -37,10 +37,12 @@
 
 #include <sys/types.h>
+#include <stdbool.h>
 
 #define FONT_GLYPHS     2899
 #define FONT_WIDTH      8
 #define FONT_SCANLINES  16
+#define FONT_ASCENDER   12
 
-extern uint16_t fb_font_glyph(const wchar_t);
+extern uint16_t fb_font_glyph(const wchar_t, bool *);
 extern uint8_t fb_font[FONT_GLYPHS][FONT_SCANLINES];
 
Index: uspace/lib/draw/source.c
===================================================================
--- uspace/lib/draw/source.c	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/draw/source.c	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -45,9 +45,9 @@
 	source->color = PIXEL(0, 0, 0, 0);
 	source->texture = NULL;
-	source->texture_tile = false;
+	source->texture_extend = PIXELMAP_EXTEND_TRANSPARENT_BLACK;
 
 	source->alpha = PIXEL(255, 0, 0, 0);
 	source->mask = NULL;
-	source->mask_tile = false;
+	source->mask_extend = PIXELMAP_EXTEND_TRANSPARENT_BLACK;
 }
 
@@ -73,8 +73,9 @@
 }
 
-void source_set_texture(source_t *source, surface_t *texture, bool tile)
+void source_set_texture(source_t *source, surface_t *texture,
+    pixelmap_extend_t extend)
 {
 	source->texture = texture;
-	source->texture_tile = tile;
+	source->texture_extend = extend;
 }
 
@@ -84,8 +85,9 @@
 }
 
-void source_set_mask(source_t *source, surface_t *mask, bool tile)
+void source_set_mask(source_t *source, surface_t *mask,
+    pixelmap_extend_t extend)
 {
 	source->mask = mask;
-	source->mask_tile = tile;
+	source->mask_extend = extend;
 }
 
@@ -95,5 +97,5 @@
 	    (source->alpha == (pixel_t) PIXEL(255, 0, 0, 0)) &&
 	    (source->texture != NULL) &&
-	    (source->texture_tile == false) &&
+	    (source->texture_extend == PIXELMAP_EXTEND_TRANSPARENT_BLACK) &&
 	    (transform_is_fast(&source->transform)));
 }
@@ -120,5 +122,5 @@
 		mask_pix = source->filter(
 		    surface_pixmap_access(source->mask),
-		    x, y, source->mask_tile);
+		    x, y, source->mask_extend);
 	} else {
 		mask_pix = source->alpha;
@@ -133,5 +135,5 @@
 		texture_pix = source->filter(
 		    surface_pixmap_access(source->texture),
-		    x, y, source->texture_tile);
+		    x, y, source->texture_extend);
 	} else {
 		texture_pix = source->color;
Index: uspace/lib/draw/source.h
===================================================================
--- uspace/lib/draw/source.h	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/draw/source.h	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -42,4 +42,5 @@
 #include <transform.h>
 #include <filter.h>
+#include <io/pixelmap.h>
 
 #include "surface.h"
@@ -51,9 +52,9 @@
 	pixel_t color;
 	surface_t *texture;
-	bool texture_tile;
+	pixelmap_extend_t texture_extend;
 
 	pixel_t alpha;
 	surface_t *mask;
-	bool mask_tile;
+	pixelmap_extend_t mask_extend;
 } source_t;
 
@@ -66,8 +67,8 @@
 
 extern void source_set_color(source_t *, pixel_t);
-extern void source_set_texture(source_t *, surface_t *, bool);
+extern void source_set_texture(source_t *, surface_t *, pixelmap_extend_t);
 
 extern void source_set_alpha(source_t *, pixel_t);
-extern void source_set_mask(source_t *, surface_t *, bool);
+extern void source_set_mask(source_t *, surface_t *, pixelmap_extend_t);
 
 extern bool source_is_fast(source_t *);
Index: uspace/lib/gui/button.c
===================================================================
--- uspace/lib/gui/button.c	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/gui/button.c	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -38,4 +38,6 @@
 #include <drawctx.h>
 #include <surface.h>
+#include <font/embedded.h>
+#include <errno.h>
 #include "common.h"
 #include "window.h"
@@ -76,5 +78,5 @@
 	sysarg_t cpt_width;
 	sysarg_t cpt_height;
-	font_get_box(&btn->font, btn->caption, &cpt_width, &cpt_height);
+	font_get_box(btn->font, btn->caption, &cpt_width, &cpt_height);
 	
 	if ((widget->width >= cpt_width) && (widget->height >= cpt_height)) {
@@ -83,5 +85,5 @@
 		
 		drawctx_set_source(&drawctx, &btn->text);
-		drawctx_set_font(&drawctx, &btn->font);
+		drawctx_set_font(&drawctx, btn->font);
 		
 		if (btn->caption)
@@ -96,5 +98,5 @@
 	widget_deinit(&btn->widget);
 	free(btn->caption);
-	font_release(&btn->font);
+	font_release(btn->font);
 }
 
@@ -171,9 +173,14 @@
 		btn->caption = str_dup(caption);
 	
-	font_init(&btn->font, FONT_DECODER_EMBEDDED, NULL, points);
+	int rc = embedded_font_create(&btn->font, points);
+	if (rc != EOK) {
+		free(btn->caption);
+		btn->caption = NULL;
+		return false;
+	}
 	
 	sysarg_t cpt_width;
 	sysarg_t cpt_height;
-	font_get_box(&btn->font, btn->caption, &cpt_width, &cpt_height);
+	font_get_box(btn->font, btn->caption, &cpt_width, &cpt_height);
 	btn->widget.width_min = cpt_width + 10;
 	btn->widget.height_min = cpt_height + 10;
Index: uspace/lib/gui/button.h
===================================================================
--- uspace/lib/gui/button.h	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/gui/button.h	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -52,5 +52,5 @@
 	source_t text;
 	char *caption;
-	font_t font;
+	font_t *font;
 	signal_t clicked;
 } button_t;
Index: uspace/lib/gui/canvas.c
===================================================================
--- uspace/lib/gui/canvas.c	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/gui/canvas.c	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -58,5 +58,6 @@
 	source_init(&source);
 	source_set_transform(&source, transform);
-	source_set_texture(&source, canvas->surface, false);
+	source_set_texture(&source, canvas->surface,
+	    PIXELMAP_EXTEND_TRANSPARENT_BLACK);
 	
 	drawctx_t drawctx;
Index: uspace/lib/gui/label.c
===================================================================
--- uspace/lib/gui/label.c	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/gui/label.c	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -38,4 +38,6 @@
 #include <drawctx.h>
 #include <surface.h>
+#include <font/embedded.h>
+#include <errno.h>
 #include "window.h"
 #include "label.h"
@@ -58,5 +60,5 @@
 	sysarg_t cpt_width;
 	sysarg_t cpt_height;
-	font_get_box(&lbl->font, lbl->caption, &cpt_width, &cpt_height);
+	font_get_box(lbl->font, lbl->caption, &cpt_width, &cpt_height);
 	
 	if ((widget->width >= cpt_width) && (widget->height >= cpt_height)) {
@@ -65,5 +67,5 @@
 		
 		drawctx_set_source(&drawctx, &lbl->text);
-		drawctx_set_font(&drawctx, &lbl->font);
+		drawctx_set_font(&drawctx, lbl->font);
 		
 		if (lbl->caption)
@@ -84,5 +86,5 @@
 		sysarg_t cpt_width;
 		sysarg_t cpt_height;
-		font_get_box(&lbl->font, lbl->caption, &cpt_width, &cpt_height);
+		font_get_box(lbl->font, lbl->caption, &cpt_width, &cpt_height);
 		
 		lbl->widget.width_min = cpt_width + 4;
@@ -99,5 +101,5 @@
 	widget_deinit(&lbl->widget);
 	free(lbl->caption);
-	font_release(&lbl->font);
+	font_release(lbl->font);
 }
 
@@ -161,9 +163,14 @@
 		lbl->caption = str_dup(caption);
 	
-	font_init(&lbl->font, FONT_DECODER_EMBEDDED, NULL, points);
+	int rc = embedded_font_create(&lbl->font, points);
+	if (rc != EOK) {
+		free(lbl->caption);
+		lbl->caption = NULL;
+		return false;
+	}
 	
 	sysarg_t cpt_width;
 	sysarg_t cpt_height;
-	font_get_box(&lbl->font, lbl->caption, &cpt_width, &cpt_height);
+	font_get_box(lbl->font, lbl->caption, &cpt_width, &cpt_height);
 	
 	lbl->widget.width_min = cpt_width + 4;
Index: uspace/lib/gui/label.h
===================================================================
--- uspace/lib/gui/label.h	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/gui/label.h	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -51,5 +51,5 @@
 	source_t text;
 	char *caption;
-	font_t font;
+	font_t *font;
 	slot_t rewrite;
 } label_t;
Index: uspace/lib/gui/terminal.c
===================================================================
--- uspace/lib/gui/terminal.c	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/gui/terminal.c	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -186,5 +186,5 @@
 	//        for full UTF-32 coverage.
 	
-	uint16_t glyph = fb_font_glyph(field->ch);
+	uint16_t glyph = fb_font_glyph(field->ch, NULL);
 	
 	for (unsigned int y = 0; y < FONT_SCANLINES; y++) {
Index: uspace/lib/gui/window.c
===================================================================
--- uspace/lib/gui/window.c	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/gui/window.c	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -55,4 +55,5 @@
 #include <drawctx.h>
 #include <surface.h>
+#include <font/embedded.h>
 
 #include "common.h"
@@ -160,8 +161,12 @@
 	/* Window caption */
 	
-	font_t font;
-	font_init(&font, FONT_DECODER_EMBEDDED, NULL, 16);
-	
-	drawctx_set_font(&drawctx, &font);
+	font_t *font;
+	int rc = embedded_font_create(&font, 16);
+	if (rc != EOK) {
+		window_yield(widget->window);
+		return;
+	}
+	
+	drawctx_set_font(&drawctx, font);
 	source_set_color(&source, widget->window->is_focused ?
 	    color_caption_focus : color_caption_unfocus);
@@ -169,5 +174,5 @@
 	sysarg_t cpt_width;
 	sysarg_t cpt_height;
-	font_get_box(&font, widget->window->caption, &cpt_width, &cpt_height);
+	font_get_box(font, widget->window->caption, &cpt_width, &cpt_height);
 	
 	bool draw_title =
@@ -183,5 +188,5 @@
 	}
 	
-	font_release(&font);
+	font_release(font);
 	window_yield(widget->window);
 }
Index: uspace/lib/posix/include/posix/stdio.h
===================================================================
--- uspace/lib/posix/include/posix/stdio.h	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/posix/include/posix/stdio.h	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -107,4 +107,5 @@
 extern int snprintf(char *, size_t , const char *, ...) PRINTF_ATTRIBUTE(3, 4);
 #ifdef _GNU_SOURCE
+extern int vasprintf(char **, const char *, va_list);
 extern int asprintf(char **, const char *, ...) PRINTF_ATTRIBUTE(2, 3);
 #endif
Index: uspace/lib/softrend/filter.c
===================================================================
--- uspace/lib/softrend/filter.c	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/softrend/filter.c	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2012 Petr Koupy
+ * Copyright (c) 2014 Martin Sucha
  * All rights reserved.
  *
@@ -35,25 +36,83 @@
 
 #include "filter.h"
+#include <io/pixel.h>
 
-pixel_t filter_nearest(pixelmap_t *pixmap, double x, double y, bool tile)
+
+static long round(double val)
 {
-	long _x = x > 0 ? (long) (x + 0.5) : (long) (x - 0.5);
-	long _y = y > 0 ? (long) (y + 0.5) : (long) (y - 0.5);
-
-	if (tile) {
-		_x %= pixmap->width;
-		_y %= pixmap->height;
-	}
-
-	return pixelmap_get_pixel(pixmap, (sysarg_t) _x, (sysarg_t) _y);
+	return val > 0 ? (long) (val + 0.5) : (long) (val - 0.5);
 }
 
-pixel_t filter_bilinear(pixelmap_t *pixmap, double x, double y, bool tile)
+static long floor(double val)
 {
-	// TODO
-	return 0;
+	long lval = (long) val;
+	if (val < 0 && lval != val)
+		return lval - 1;
+	return lval;
 }
 
-pixel_t filter_bicubic(pixelmap_t *pixmap, double x, double y, bool tile)
+static long ceil(double val)
+{
+	long lval = (long) val;
+	if (val > 0 && lval != val)
+		return lval + 1;
+	return lval;
+}
+
+
+static inline pixel_t blend_pixels(size_t count, float *weights,
+    pixel_t *pixels)
+{
+	float alpha = 0, red = 0, green = 0, blue = 0;
+	for (size_t index = 0; index < count; index++) {
+		alpha += weights[index] * ALPHA(pixels[index]);
+		red   += weights[index] *   RED(pixels[index]);
+		green += weights[index] * GREEN(pixels[index]);
+		blue  += weights[index] *  BLUE(pixels[index]);
+	}
+	
+	return PIXEL((uint8_t) alpha, (uint8_t) red, (uint8_t) green,
+	    (uint8_t) blue);
+}
+
+pixel_t filter_nearest(pixelmap_t *pixmap, double x, double y,
+    pixelmap_extend_t extend)
+{
+	return pixelmap_get_extended_pixel(pixmap, round(x), round(y), extend);
+}
+
+pixel_t filter_bilinear(pixelmap_t *pixmap, double x, double y,
+    pixelmap_extend_t extend)
+{
+	long x1 = floor(x);
+	long x2 = ceil(x);
+	long y1 = floor(y);
+	long y2 = ceil(y);
+	
+	if (y1 == y2 && x1 == x2) {
+		return pixelmap_get_extended_pixel(pixmap,
+		    (sysarg_t) x1, (sysarg_t) y1, extend);
+	}
+	
+	double x_delta = x - x1;
+	double y_delta = y - y1;
+	
+	pixel_t pixels[4];
+	pixels[0] = pixelmap_get_extended_pixel(pixmap, x1, y1, extend);
+	pixels[1] = pixelmap_get_extended_pixel(pixmap, x2, y1, extend);
+	pixels[2] = pixelmap_get_extended_pixel(pixmap, x1, y2, extend);
+	pixels[3] = pixelmap_get_extended_pixel(pixmap, x2, y2, extend);
+	
+	float weights[4];
+	weights[0] = (1 - x_delta) * (1 - y_delta);
+	weights[1] = (    x_delta) * (1 - y_delta);
+	weights[2] = (1 - x_delta) * (    y_delta);
+	weights[3] = (    x_delta) * (    y_delta);
+	
+	return blend_pixels(4, weights, pixels);
+}
+
+pixel_t filter_bicubic(pixelmap_t *pixmap, double x, double y,
+    pixelmap_extend_t extend)
 {
 	// TODO
Index: uspace/lib/softrend/filter.h
===================================================================
--- uspace/lib/softrend/filter.h	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
+++ uspace/lib/softrend/filter.h	(revision 5713e5faae70dc250ec698512ff0096c4b9891ce)
@@ -40,9 +40,9 @@
 #include <io/pixelmap.h>
 
-typedef pixel_t (*filter_t)(pixelmap_t *, double, double, bool);
+typedef pixel_t (*filter_t)(pixelmap_t *, double, double, pixelmap_extend_t);
 
-extern pixel_t filter_nearest(pixelmap_t *, double, double, bool);
-extern pixel_t filter_bilinear(pixelmap_t *, double, double, bool);
-extern pixel_t filter_bicubic(pixelmap_t *, double, double, bool);
+extern pixel_t filter_nearest(pixelmap_t *, double, double, pixelmap_extend_t);
+extern pixel_t filter_bilinear(pixelmap_t *, double, double, pixelmap_extend_t);
+extern pixel_t filter_bicubic(pixelmap_t *, double, double, pixelmap_extend_t);
 
 #endif
