Index: uspace/lib/draw/Makefile
===================================================================
--- uspace/lib/draw/Makefile	(revision 613d6445032773dfb7bc4ee44f3e7a827a802fbe)
+++ uspace/lib/draw/Makefile	(revision 2cc1ec062d6e172ce570169e6b0485b9da3db610)
@@ -37,4 +37,5 @@
 	cursor/embedded.c \
 	font/embedded.c \
+	font/bitmap_backend.c \
 	gfx/font-8x16.c \
 	gfx/cursor-11x18.c \
Index: uspace/lib/draw/font.c
===================================================================
--- uspace/lib/draw/font.c	(revision 613d6445032773dfb7bc4ee44f3e7a827a802fbe)
+++ uspace/lib/draw/font.c	(revision 2cc1ec062d6e172ce570169e6b0485b9da3db610)
@@ -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 613d6445032773dfb7bc4ee44f3e7a827a802fbe)
+++ uspace/lib/draw/font.h	(revision 2cc1ec062d6e172ce570169e6b0485b9da3db610)
@@ -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 2cc1ec062d6e172ce570169e6b0485b9da3db610)
+++ uspace/lib/draw/font/bitmap_backend.c	(revision 2cc1ec062d6e172ce570169e6b0485b9da3db610)
@@ -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 (h == data->points) {
+		*result = raw_surface;
+		return EOK;
+	}
+	
+	source_t source;
+	source_init(&source);
+	source_set_texture(&source, raw_surface, false);
+
+	transform_t transform;
+	transform_identity(&transform);
+	double ratio = ((double) data->points) / ((double) h);
+	transform_scale(&transform, ratio, ratio);
+	source_set_transform(&source, transform);
+
+	double width = w;
+	double height = h;
+	transform_apply_linear(&transform, &width, &height);
+	surface_t *scaled_surface =
+	    surface_create((sysarg_t) (width + 0.5), (sysarg_t) (height + 0.5), 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,
+	    (sysarg_t) (width + 0.5), (sysarg_t) (height + 0.5));
+
+	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);
+		data->font_metrics.ascender = (metric_t)
+		    (data->scale_ratio * data->font_metrics.ascender + 0.5);
+		data->font_metrics.descender = (metric_t)
+		    (data->scale_ratio * data->font_metrics.descender - 0.5);
+		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 2cc1ec062d6e172ce570169e6b0485b9da3db610)
+++ uspace/lib/draw/font/bitmap_backend.h	(revision 2cc1ec062d6e172ce570169e6b0485b9da3db610)
@@ -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 613d6445032773dfb7bc4ee44f3e7a827a802fbe)
+++ uspace/lib/draw/font/embedded.c	(revision 2cc1ec062d6e172ce570169e6b0485b9da3db610)
@@ -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 613d6445032773dfb7bc4ee44f3e7a827a802fbe)
+++ uspace/lib/draw/font/embedded.h	(revision 2cc1ec062d6e172ce570169e6b0485b9da3db610)
@@ -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/gfx/font-8x16.c
===================================================================
--- uspace/lib/draw/gfx/font-8x16.c	(revision 613d6445032773dfb7bc4ee44f3e7a827a802fbe)
+++ uspace/lib/draw/gfx/font-8x16.c	(revision 2cc1ec062d6e172ce570169e6b0485b9da3db610)
@@ -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 613d6445032773dfb7bc4ee44f3e7a827a802fbe)
+++ uspace/lib/draw/gfx/font-8x16.h	(revision 2cc1ec062d6e172ce570169e6b0485b9da3db610)
@@ -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/gui/button.c
===================================================================
--- uspace/lib/gui/button.c	(revision 613d6445032773dfb7bc4ee44f3e7a827a802fbe)
+++ uspace/lib/gui/button.c	(revision 2cc1ec062d6e172ce570169e6b0485b9da3db610)
@@ -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 613d6445032773dfb7bc4ee44f3e7a827a802fbe)
+++ uspace/lib/gui/button.h	(revision 2cc1ec062d6e172ce570169e6b0485b9da3db610)
@@ -52,5 +52,5 @@
 	source_t text;
 	char *caption;
-	font_t font;
+	font_t *font;
 	signal_t clicked;
 } button_t;
Index: uspace/lib/gui/label.c
===================================================================
--- uspace/lib/gui/label.c	(revision 613d6445032773dfb7bc4ee44f3e7a827a802fbe)
+++ uspace/lib/gui/label.c	(revision 2cc1ec062d6e172ce570169e6b0485b9da3db610)
@@ -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 613d6445032773dfb7bc4ee44f3e7a827a802fbe)
+++ uspace/lib/gui/label.h	(revision 2cc1ec062d6e172ce570169e6b0485b9da3db610)
@@ -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 613d6445032773dfb7bc4ee44f3e7a827a802fbe)
+++ uspace/lib/gui/terminal.c	(revision 2cc1ec062d6e172ce570169e6b0485b9da3db610)
@@ -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 613d6445032773dfb7bc4ee44f3e7a827a802fbe)
+++ uspace/lib/gui/window.c	(revision 2cc1ec062d6e172ce570169e6b0485b9da3db610)
@@ -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);
 }
