Index: uspace/lib/draw/font.c
===================================================================
--- uspace/lib/draw/font.c	(revision 6d5e378b28e2c858f3813b5d4d57fa46f709d753)
+++ 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;
 }
 
