Index: test/dump.h
===================================================================
--- test/dump.h	(revision 13101)
+++ test/dump.h	(working copy)
@@ -8,6 +8,7 @@
 #include "stylesheet.h"
 #include "bytecode/bytecode.h"
 #include "bytecode/opcodes.h"
+#include "select/font_face.h"
 
 #include "testutils.h"
 
@@ -18,11 +19,13 @@
 static void dump_rule_import(css_rule_import *s, char **buf, size_t *buflen);
 static void dump_rule_media(css_rule_media *s, char **buf, size_t *buflen);
 static void dump_rule_page(css_rule_page *s, char **buf, size_t *buflen);
+static void dump_rule_font_face(css_rule_font_face *s, char **buf, size_t *buflen);
 static void dump_selector_list(css_selector *list, char **ptr);
 static void dump_selector(css_selector *selector, char **ptr);
 static void dump_selector_detail(css_selector_detail *detail, char **ptr);
 static void dump_bytecode(css_style *style, char **ptr, uint32_t depth);
 static void dump_string(lwc_string *string, char **ptr);
+static void dump_font_face(css_font_face *font_face, char**ptr);
 
 void dump_sheet(css_stylesheet *sheet, char *buf, size_t *buflen)
 {
@@ -50,6 +53,10 @@
 			dump_rule_page((css_rule_page *) rule,
 				&buf, buflen);
 			break;
+		case CSS_RULE_FONT_FACE:
+			dump_rule_font_face((css_rule_font_face *) rule,
+				&buf, buflen);
+			break;
 		default:
 		{
 			int written = sprintf(buf, "Unhandled rule type %d\n",
@@ -157,6 +164,22 @@
 	*buf = ptr;
 }
 
+void dump_rule_font_face(css_rule_font_face *s, char **buf, size_t *buflen)
+{
+	char *ptr = *buf;
+
+	ptr += sprintf(ptr, "| @font-face ");
+
+	if (s->font_face) {
+		dump_font_face(s->font_face, &ptr);
+	}
+	
+	*ptr++ = '\n';
+
+	*buflen -= ptr - *buf;
+	*buf = ptr;
+}
+
 void dump_selector_list(css_selector *list, char **ptr)
 {
 	if (list->combinator != NULL) {
@@ -833,7 +856,8 @@
 					break;
 				case BACKGROUND_IMAGE_URI:
 				{
-					uint32_t snum = *((uint32_t *) bytecode);					lwc_string *he;
+					uint32_t snum = *((uint32_t *) bytecode);
+					lwc_string *he;
 					css__stylesheet_string_get(style->sheet, 
 								  snum, 
 								  &he);
@@ -2017,9 +2041,7 @@
                                                                 (int) lwc_string_length(he), 
                                                                 lwc_string_data(he));
 
-						he = 
-						*((lwc_string **) 
-						bytecode);
+						css__stylesheet_string_get(style->sheet, snum, &he);
 						ADVANCE(sizeof(he));
 						*ptr += sprintf(*ptr, " '%.*s' ", 
                                                                 (int) lwc_string_length(he), 
@@ -2365,4 +2387,134 @@
                         lwc_string_data(string));
 }
 
+void dump_font_face(css_font_face *font_face, char**ptr)
+{
+	uint8_t style, weight;
+
+	if (font_face->font_family != NULL) {
+		*(*ptr)++ = '\n';
+		*ptr += sprintf(*ptr, "|  font-family: %.*s",
+				(int) lwc_string_length(font_face->font_family), 
+				lwc_string_data(font_face->font_family));
+	}
+	
+	*ptr += sprintf(*ptr, "\n|  font-style: ");
+	style = css_font_face_font_style(font_face);
+	switch (style) {
+	case CSS_FONT_STYLE_INHERIT:
+		*ptr += sprintf(*ptr, "unspecified");
+		break;
+	case CSS_FONT_STYLE_NORMAL:
+		*ptr += sprintf(*ptr, "normal");
+		break;
+	case CSS_FONT_STYLE_ITALIC:
+		*ptr += sprintf(*ptr, "italic");
+		break;
+	case CSS_FONT_STYLE_OBLIQUE:
+		*ptr += sprintf(*ptr, "oblique");
+		break;
+	}
+
+	*ptr += sprintf(*ptr, "\n|  font-weight: ");
+	weight = css_font_face_font_weight(font_face);
+	switch (weight) {
+	case CSS_FONT_WEIGHT_INHERIT:
+		*ptr += sprintf(*ptr, "unspecified");
+		break;
+	case CSS_FONT_WEIGHT_NORMAL:
+		*ptr += sprintf(*ptr, "normal");
+		break;
+	case CSS_FONT_WEIGHT_BOLD:
+		*ptr += sprintf(*ptr, "bold");
+		break;
+	case CSS_FONT_WEIGHT_100:
+		*ptr += sprintf(*ptr, "100");
+		break;
+	case CSS_FONT_WEIGHT_200:
+		*ptr += sprintf(*ptr, "200");
+		break;
+	case CSS_FONT_WEIGHT_300:
+		*ptr += sprintf(*ptr, "300");
+		break;
+	case CSS_FONT_WEIGHT_400:
+		*ptr += sprintf(*ptr, "400");
+		break;
+	case CSS_FONT_WEIGHT_500:
+		*ptr += sprintf(*ptr, "500");
+		break;
+	case CSS_FONT_WEIGHT_600:
+		*ptr += sprintf(*ptr, "600");
+		break;
+	case CSS_FONT_WEIGHT_700:
+		*ptr += sprintf(*ptr, "700");
+		break;
+	case CSS_FONT_WEIGHT_800:
+		*ptr += sprintf(*ptr, "800");
+		break;
+	case CSS_FONT_WEIGHT_900:
+		*ptr += sprintf(*ptr, "900");
+		break;
+	default:
+		*ptr += sprintf(*ptr, "Unhandled weight %d\n", (int)weight);
+		break;
+	}
+
+	
+	if (font_face->srcs != NULL) {
+		uint32_t i;
+		css_font_face_src *srcs = font_face->srcs;
+		for (i = 0; i < font_face->n_srcs; ++i) {
+			*ptr += sprintf(*ptr, "\n|  src: ");
+			
+			css_font_face_format format = css_font_face_src_format(&srcs[i]);
+			
+			*ptr += sprintf(*ptr, "\n|   format: ");
+			
+			switch(format) {
+			case CSS_FONT_FACE_FORMAT_UNSPECIFIED:
+				*ptr += sprintf(*ptr, "unspecified");
+				break;
+			case CSS_FONT_FACE_FORMAT_WOFF:
+				*ptr += sprintf(*ptr, "WOFF");
+				break;
+			case CSS_FONT_FACE_FORMAT_OPENTYPE:
+				*ptr += sprintf(*ptr, "OTF");
+				break;
+			case CSS_FONT_FACE_FORMAT_EMBEDDED_OPENTYPE:
+				*ptr += sprintf(*ptr, "EOTF");
+				break;
+			case CSS_FONT_FACE_FORMAT_SVG:
+				*ptr += sprintf(*ptr, "SVG");
+				break;
+			case CSS_FONT_FACE_FORMAT_UNKNOWN:
+				*ptr += sprintf(*ptr, "unknown");
+				break;
+			default:
+				*ptr += sprintf(*ptr, "UNEXPECTED");
+				break;
+			}
+
+			if (srcs[i].location != NULL) {
+				*ptr += sprintf(*ptr, "\n|   location: ");
+
+				switch(css_font_face_src_location_type(&srcs[i])) {
+				case CSS_FONT_FACE_LOCATION_TYPE_LOCAL:
+					*ptr += sprintf(*ptr, "local");
+					break;
+				case CSS_FONT_FACE_LOCATION_TYPE_URI:
+					*ptr += sprintf(*ptr, "url");
+					break;
+				default:
+					*ptr += sprintf(*ptr, "UNKNOWN");
+					break;
+				}
+				
+				*ptr += sprintf(*ptr, "(%.*s)",
+					(int) lwc_string_length(srcs[i].location), 
+					lwc_string_data(srcs[i].location));
+			}
+		}
+	}
+}
+
 #endif
Index: test/data/css/INDEX
===================================================================
--- test/data/css/INDEX	(revision 13101)
+++ test/data/css/INDEX	(working copy)
@@ -7,3 +7,4 @@
 blocks.css		Basic blocks and at-rule syntax
 malformed.css		Malformed declarations from the CSS 2.1 spec
 badcomment.css		Comment inside { ... } lacks starting /*
+fontface.css		Various @font-face rules
\ No newline at end of file
Index: include/libcss/libcss.h
===================================================================
--- include/libcss/libcss.h	(revision 13101)
+++ include/libcss/libcss.h	(working copy)
@@ -22,6 +22,7 @@
 #include <libcss/properties.h>
 #include <libcss/select.h>
 #include <libcss/stylesheet.h>
+#include <libcss/font_face.h>
 
 #ifdef __cplusplus
 }
Index: include/libcss/select.h
===================================================================
--- include/libcss/select.h	(revision 13101)
+++ include/libcss/select.h	(working copy)
@@ -129,6 +129,17 @@
 	css_error (*compute_font_size)(void *pw, const css_hint *parent,
 			css_hint *size);
 } css_select_handler;
+	
+typedef struct css_select_font_faces_results {
+	css_allocator_fn alloc;
+	void *pw;
+	
+	/**
+	 * Array of pointers to computed font faces. 
+	 */
+	css_font_face **font_faces;
+	uint32_t n_font_faces;
+} css_select_font_faces_results;
 
 css_error css_select_ctx_create(css_allocator_fn alloc, void *pw,
 		css_select_ctx **result);
@@ -151,8 +162,12 @@
 		uint64_t media, const css_stylesheet *inline_style,
 		css_select_handler *handler, void *pw,
 		css_select_results **result);
+css_error css_select_results_destroy(css_select_results *results);    
 
-css_error css_select_results_destroy(css_select_results *results);
+css_error css_select_font_faces(css_select_ctx *ctx,
+		uint64_t media, lwc_string *font_family,
+		css_select_font_faces_results **result);
+css_error css_select_font_faces_results_destroy(css_select_font_faces_results *results);	
 
 #ifdef __cplusplus
 }
Index: include/libcss/types.h
===================================================================
--- include/libcss/types.h	(revision 13101)
+++ include/libcss/types.h	(working copy)
@@ -127,6 +127,10 @@
 
 typedef struct css_computed_style css_computed_style;
 
+typedef struct css_font_face css_font_face;
+
+typedef struct css_font_face_src css_font_face_src;
+
 #ifdef __cplusplus
 }
 #endif
Index: src/select/select.c
===================================================================
--- src/select/select.c	(revision 13101)
+++ src/select/select.c	(working copy)
@@ -8,6 +8,8 @@
 #include <assert.h>
 #include <string.h>
 
+#include <libwapcaplet/libwapcaplet.h>
+
 #include <libcss/select.h>
 
 #include "bytecode/bytecode.h"
@@ -17,6 +19,7 @@
 #include "select/dispatch.h"
 #include "select/hash.h"
 #include "select/propset.h"
+#include "select/font_face.h"
 #include "select/select.h"
 #include "utils/parserutilserror.h"
 #include "utils/utils.h"
@@ -74,6 +77,21 @@
 	lwc_string *after;
 };
 
+typedef struct css_select_font_faces_list {
+	const css_font_face **font_faces;
+	size_t count;
+} css_select_font_faces_list;
+
+typedef struct css_select_font_faces_state {
+	lwc_string *font_family;
+	uint64_t media;
+
+	css_select_font_faces_list ua_font_faces;
+	css_select_font_faces_list user_font_faces;
+	css_select_font_faces_list author_font_faces;
+} css_select_font_faces_state;
+
+
 static css_error set_hint(css_select_state *state, uint32_t prop);
 static css_error set_initial(css_select_state *state, 
 		uint32_t prop, css_pseudo_element pseudo,
@@ -103,6 +121,11 @@
 		bool *match, css_pseudo_element *pseudo_element);
 static css_error cascade_style(const css_style *style, css_select_state *state);
 
+static css_error select_font_faces_from_sheet(css_select_ctx *ctx, 
+		const css_stylesheet *sheet, 
+		css_origin origin, 
+		css_select_font_faces_state *state);
+
 #ifdef DEBUG_CHAIN_MATCHING
 static void dump_chain(const css_selector *selector);
 #endif
@@ -555,6 +578,138 @@
 	return CSS_OK;
 }
 
+css_error css_select_font_faces(css_select_ctx *ctx,
+		uint64_t media, lwc_string *font_family,
+		css_select_font_faces_results **result)
+{
+	uint32_t i;
+	css_error error;
+	css_select_font_faces_state state;
+	uint32_t n_font_faces;
+	
+	if (ctx == NULL || font_family == NULL || result == NULL)
+		return CSS_BADPARM;
+
+	memset(&state, 0, sizeof(css_select_font_faces_state));
+	state.font_family = font_family;
+	state.media = media;
+	
+	/* Iterate through the top-level stylesheets, selecting font-faces
+	 * from those which apply to our current media requirements and
+	 * are not disabled */
+	for (i = 0; i < ctx->n_sheets; i++) {
+		const css_select_sheet s = ctx->sheets[i];
+		
+		if ((s.media & media) != 0 &&
+		    s.sheet->disabled == false) {
+			error = select_font_faces_from_sheet(ctx, s.sheet,
+					s.origin, &state);
+			if (error != CSS_OK)
+				goto cleanup;
+		}
+	}
+	
+	n_font_faces = state.ua_font_faces.count + 
+		state.user_font_faces.count +
+		state.author_font_faces.count;
+				
+	
+	if (n_font_faces > 0) {
+		/* We found some matching faces.  Make a results structure with
+		 * the font faces in priority order. */
+
+		css_select_font_faces_results *results;
+		
+		results = ctx->alloc(NULL, 
+					sizeof(css_select_font_faces_results),
+					ctx->pw);
+		
+		if (results == NULL) {
+			error = CSS_NOMEM;
+			goto cleanup;
+		}
+		
+		results->alloc = ctx->alloc;
+		results->pw = ctx->pw;
+		
+		results->font_faces = ctx->alloc(NULL, 
+						n_font_faces * 
+							sizeof(css_font_face *),
+						ctx->pw);
+		
+		if (results->font_faces == NULL) {
+			ctx->alloc(results, 0, ctx->pw);
+			error = CSS_NOMEM;
+			goto cleanup;
+		}
+		results->n_font_faces = n_font_faces;
+		
+		i = 0;
+		if (state.ua_font_faces.count != 0) {
+			memcpy(results->font_faces, 
+				state.ua_font_faces.font_faces,
+				sizeof(css_font_face *) * 
+					state.ua_font_faces.count);
+			
+			i += state.ua_font_faces.count;
+		}
+				
+		if (state.user_font_faces.count != 0) {
+			memcpy(results->font_faces + i, 
+			       state.user_font_faces.font_faces,
+			       sizeof(css_font_face *) * 
+			       state.user_font_faces.count);
+			i += state.user_font_faces.count;
+		}
+		
+		if (state.author_font_faces.count != 0) {
+			memcpy(results->font_faces + i, 
+				state.author_font_faces.font_faces,
+				sizeof(css_font_face *) * 
+					state.author_font_faces.count);
+		}
+
+		*result = results;
+	}
+	
+	error = CSS_OK;
+	
+cleanup:
+	if (state.ua_font_faces.count != 0) 
+		ctx->alloc(state.ua_font_faces.font_faces, 0, ctx->pw);
+
+	if (state.user_font_faces.count != 0) 
+		ctx->alloc(state.user_font_faces.font_faces, 0, ctx->pw);
+	
+	if (state.author_font_faces.count != 0) 
+		ctx->alloc(state.author_font_faces.font_faces, 0, ctx->pw);
+	
+	return error;
+}
+
+/**
+ * Destroy a font-face result set
+ *
+ * \param results  Result set to destroy
+ * \return CSS_OK on success, appropriate error otherwise
+ */
+css_error css_select_font_faces_results_destroy(
+	css_select_font_faces_results *results)
+{
+	if (results == NULL)
+		return CSS_BADPARM;
+	
+	if (results->font_faces != NULL) {
+		/* Don't destroy the individual css_font_faces, they're owned
+		   by their respective sheets */
+		results->alloc(results->font_faces, 0, results->pw);
+	}
+	
+	results->alloc(results, 0, results->pw);
+	
+	return CSS_OK;
+}
+
 /******************************************************************************
  * Selection engine internals below here                                      *
  ******************************************************************************/
@@ -867,13 +1022,14 @@
 	return CSS_OK;
 }
 
+#define IMPORT_STACK_SIZE 256
+
 css_error select_from_sheet(css_select_ctx *ctx, const css_stylesheet *sheet, 
 		css_origin origin, css_select_state *state)
 {
 	const css_stylesheet *s = sheet;
 	const css_rule *rule = s->rule_list;
 	uint32_t sp = 0;
-#define IMPORT_STACK_SIZE 256
 	const css_rule *import_stack[IMPORT_STACK_SIZE];
 
 	do {
@@ -891,7 +1047,8 @@
 			if (import->sheet != NULL &&
 					(import->media & state->media) != 0) {
 				/* It's applicable, so process it */
-				assert(sp < IMPORT_STACK_SIZE - 1);
+				if(sp >= IMPORT_STACK_SIZE)
+					return CSS_NOMEM;
 
 				import_stack[sp++] = rule;
 
@@ -927,6 +1084,140 @@
 	return CSS_OK;
 }
 
+static inline bool _rule_applies_to_media(const css_rule *rule, uint64_t media)
+{
+	bool applies = true;
+	const css_rule *ancestor = rule;
+
+	while(ancestor) {
+		if (ancestor->type == CSS_RULE_MEDIA && 
+		    (((css_rule_media *) ancestor)->media & media) == 0) {
+			applies = false;
+			break;
+		}
+		
+		if (ancestor->ptype != CSS_RULE_PARENT_STYLESHEET)
+			ancestor = ancestor->parent;
+		else
+			ancestor = NULL;
+	}
+	
+	return applies;
+}
+
+static css_error _select_font_face_from_rule(css_select_ctx *ctx, 
+		const css_rule_font_face *rule, css_origin origin,
+		css_select_font_faces_state *state)
+{
+	if(_rule_applies_to_media((const css_rule *) rule, state->media)) {
+		
+		bool correct_family;
+		if(lwc_string_isequal(
+			rule->font_face->font_family,
+			state->font_family, 
+			&correct_family) == lwc_error_ok &&
+		   correct_family) {
+			
+			css_select_font_faces_list *list;
+			switch (origin) {
+				case CSS_ORIGIN_UA:
+					list = &state->ua_font_faces;
+					break;
+				case CSS_ORIGIN_USER:
+					list = &state->user_font_faces;
+					break;
+				case CSS_ORIGIN_AUTHOR:
+					list = &state->author_font_faces;
+					break;
+			}
+			
+			uint32_t index = list->count++;			
+			uint32_t new_size = list->count * 
+						sizeof(css_font_face *);
+			
+			list->font_faces = ctx->alloc(list->font_faces, 
+							new_size,
+							ctx->pw);
+			
+			if(!list->font_faces) {
+				list->count = 0;
+				return CSS_NOMEM;
+			}
+			
+			list->font_faces[index] = rule->font_face;
+		}
+	}
+	return CSS_OK;
+}
+
+static css_error select_font_faces_from_sheet(css_select_ctx *ctx, 
+		const css_stylesheet *sheet, 
+		css_origin origin, 
+		css_select_font_faces_state *state)
+{
+	const css_stylesheet *s = sheet;
+	const css_rule *rule = s->rule_list;
+	uint32_t sp = 0;
+	const css_rule *import_stack[IMPORT_STACK_SIZE];
+	
+	do {
+		/* Find first non-charset rule, if we're at the list head */
+		if (rule == s->rule_list) {
+			while (rule != NULL && rule->type == CSS_RULE_CHARSET)
+				rule = rule->next;
+		}
+		
+		if (rule != NULL && rule->type == CSS_RULE_IMPORT) {
+			/* Current rule is an import */
+			const css_rule_import *import = 
+					(const css_rule_import *) rule;
+			
+			if (import->sheet != NULL &&
+			    (import->media & state->media) != 0) {
+				/* It's applicable, so process it */
+				if(sp >= IMPORT_STACK_SIZE)
+					return CSS_NOMEM;
+				
+				import_stack[sp++] = rule;
+				
+				s = import->sheet;
+				rule = s->rule_list;
+			} else {
+				/* Not applicable; skip over it */
+				rule = rule->next;
+			}
+		} else if (rule != NULL && rule->type == CSS_RULE_FONT_FACE) {
+			css_error error;
+			
+			error = _select_font_face_from_rule(
+					ctx, 
+					(const css_rule_font_face *) rule,
+					origin,
+					state);
+			
+			if(error != CSS_OK)
+				return error;
+			
+			rule = rule->next;
+		} else if (rule == NULL) {
+			/* Find next sheet to process */
+			if (sp > 0) {
+				sp--;
+				rule = import_stack[sp]->next;
+				s = import_stack[sp]->parent;
+			} else {
+				s = NULL;
+			}
+		} else {
+			rule = rule->next;
+		}
+	} while (s != NULL);
+	
+	return CSS_OK;
+}
+
+#undef IMPORT_STACK_SIZE
+
 static inline bool _selectors_pending(const css_selector **node,
 		const css_selector **id, const css_selector ***classes,
 		uint32_t n_classes, const css_selector **univ)
@@ -1060,8 +1351,6 @@
 	while (_selectors_pending(node_selectors, id_selectors, 
 			class_selectors, n_classes, univ_selectors)) {
 		const css_selector *selector;
-		css_rule *rule, *parent;
-		bool process = true;
 
 		/* Selectors must be matched in ascending order of specificity
 		 * and rule index. (c.f. css__outranks_existing())
@@ -1074,21 +1363,7 @@
 		/* Ignore any selectors contained in rules which are a child 
 		 * of an @media block that doesn't match the current media 
 		 * requirements. */
-		for (rule = selector->rule; rule != NULL; rule = parent) {
-			if (rule->type == CSS_RULE_MEDIA && 
-					(((css_rule_media *) rule)->media & 
-					state->media) == 0) {
-				process = false;
-				break;
-			}
-
-			if (rule->ptype != CSS_RULE_PARENT_STYLESHEET)
-				parent = rule->parent;
-			else
-				parent = NULL;
-		}
-
-		if (process) {
+		if (_rule_applies_to_media(selector->rule, state->media)) {
 			error = match_selector_chain(ctx, selector, state);
 			if (error != CSS_OK)
 				goto cleanup;
Index: src/select/Makefile
===================================================================
--- src/select/Makefile	(revision 13101)
+++ src/select/Makefile	(working copy)
@@ -1,4 +1,4 @@
 # Sources
-DIR_SOURCES := computed.c dispatch.c hash.c select.c
+DIR_SOURCES := computed.c dispatch.c hash.c select.c font_face.c
 
 include build/makefiles/Makefile.subdir
Index: src/stylesheet.h
===================================================================
--- src/stylesheet.h	(revision 13101)
+++ src/stylesheet.h	(working copy)
@@ -141,7 +141,7 @@
 typedef struct css_rule_font_face {
 	css_rule base;
 
-	css_style *style;
+	css_font_face *font_face;
 } css_rule_font_face;
 
 typedef struct css_rule_page {
Index: src/parse/propstrings.h
===================================================================
--- src/parse/propstrings.h	(revision 13101)
+++ src/parse/propstrings.h	(working copy)
@@ -15,7 +15,7 @@
 	UNIVERSAL,
 
 	/* At-rules */
-	CHARSET, LIBCSS_IMPORT, MEDIA, NAMESPACE, PAGE,
+	CHARSET, LIBCSS_IMPORT, MEDIA, NAMESPACE, FONT_FACE, PAGE,
 
 	/* Media types */
 	AURAL, BRAILLE, EMBOSSED, HANDHELD, PRINT, PROJECTION, 
@@ -88,7 +88,8 @@
 	W_RESIZE, LIBCSS_TEXT, WAIT, HELP, PROGRESS, SERIF, SANS_SERIF, CURSIVE,
 	FANTASY, MONOSPACE, MALE, FEMALE, CHILD, MIX, UNDERLINE, OVERLINE, 
 	LINE_THROUGH, BLINK, RGB, RGBA, HSL, HSLA, LIBCSS_LEFT, LIBCSS_CENTER,
-	LIBCSS_RIGHT, CURRENTCOLOR, ODD, EVEN,
+	LIBCSS_RIGHT, CURRENTCOLOR, ODD, EVEN, SRC, LOCAL, INITIAL,
+	FORMAT, WOFF, TRUETYPE, OPENTYPE, EMBEDDED_OPENTYPE, SVG,
 
 	/* Named colours */
 	FIRST_COLOUR,
Index: src/parse/language.c
===================================================================
--- src/parse/language.c	(revision 13101)
+++ src/parse/language.c	(working copy)
@@ -18,6 +18,7 @@
 #include "parse/propstrings.h"
 #include "parse/properties/properties.h"
 #include "parse/properties/utils.h"
+#include "parse/font_face.h"
 
 #include "utils/parserutilserror.h"
 #include "utils/utils.h"
@@ -558,6 +559,27 @@
 		 * so no need to destroy it */
 
 		c->state = HAD_RULE;
+	} else if (lwc_string_caseless_isequal(atkeyword->idata, 
+			c->strings[FONT_FACE], &match) == lwc_error_ok && 
+			match) {
+
+		error = css__stylesheet_rule_create(c->sheet,
+				CSS_RULE_FONT_FACE, &rule);
+		if (error != CSS_OK)
+			return error;
+		
+		consumeWhitespace(vector, &ctx);
+
+		error = css__stylesheet_add_rule(c->sheet, rule, NULL);
+		if (error != CSS_OK) {
+			css__stylesheet_rule_destroy(c->sheet, rule);
+			return error;
+		}
+
+		/* Rule is now owned by the sheet, 
+		 * so no need to destroy it */
+
+		c->state = HAD_RULE;
 	} else if (lwc_string_caseless_isequal(atkeyword->idata, c->strings[PAGE], 
 			&match) == lwc_error_ok && match) {
 		const css_token *token;
@@ -693,9 +715,9 @@
 	context_entry *entry;
 	css_rule *rule;
 
-	/* In CSS 2.1, block content comprises either declarations (if the 
-	 * current block is associated with @page or a selector), or rulesets 
-	 * (if the current block is associated with @media). */
+	/* Block content comprises either declarations (if the current block is
+	 * associated with @page, @font-face or a selector), or rulesets (if the
+	 * current block is associated with @media). */
 
 	entry = parserutils_stack_get_current(c->context);
 	if (entry == NULL || entry->data == NULL)
@@ -704,7 +726,8 @@
 	rule = entry->data;
 	if (rule == NULL || (rule->type != CSS_RULE_SELECTOR && 
 			rule->type != CSS_RULE_PAGE &&
-			rule->type != CSS_RULE_MEDIA))
+			rule->type != CSS_RULE_MEDIA && 
+			rule->type != CSS_RULE_FONT_FACE))
 		return CSS_INVALID;
 
 	if (rule->type == CSS_RULE_MEDIA) {
@@ -729,6 +752,7 @@
 	/* Locations where declarations are permitted:
 	 *
 	 * + In @page
+	 * + In @font-face
 	 * + In ruleset
 	 */
 	entry = parserutils_stack_get_current(c->context);
@@ -737,7 +761,8 @@
 
 	rule = entry->data;
 	if (rule == NULL || (rule->type != CSS_RULE_SELECTOR && 
-			rule->type != CSS_RULE_PAGE))
+				rule->type != CSS_RULE_PAGE && 
+				rule->type != CSS_RULE_FONT_FACE))
 		return CSS_INVALID;
 
 	/* Strip any leading whitespace (can happen if in nested block) */
@@ -759,7 +784,13 @@
 
 	consumeWhitespace(vector, &ctx);
 
-	error = parseProperty(c, ident, vector, &ctx, rule);
+	if(rule->type == CSS_RULE_FONT_FACE) {
+		css_rule_font_face * ff_rule = (css_rule_font_face *) rule;
+		error = css__parse_font_descriptor(c, ident, vector,
+						   	&ctx, ff_rule);
+	} else {
+		error = parseProperty(c, ident, vector, &ctx, rule);
+	}
 	if (error != CSS_OK)
 		return error;
 
Index: src/parse/propstrings.c
===================================================================
--- src/parse/propstrings.c	(revision 13101)
+++ src/parse/propstrings.c	(working copy)
@@ -30,6 +30,7 @@
 	{ "import", SLEN("import") },
 	{ "media", SLEN("media") },
 	{ "namespace", SLEN("namespace") },
+	{ "font-face", SLEN("font-face") },
 	{ "page", SLEN("page") },
 
 	{ "aural", SLEN("aural") },
@@ -372,6 +373,15 @@
 	{ "currentColor", SLEN("currentColor") },
 	{ "odd", SLEN("odd") },
 	{ "even", SLEN("even") },
+	{ "src", SLEN("src") },
+	{ "local", SLEN("local") },
+	{ "initial", SLEN("initial") },
+	{ "format", SLEN("format") },
+	{ "woff", SLEN("woff") },
+	{ "truetype", SLEN("truetype") },
+	{ "opentype", SLEN("opentype") },
+	{ "embedded-opentype", SLEN("embedded-opentype") },
+	{ "svg", SLEN("svg") },
 
 	{ "aliceblue", SLEN("aliceblue") },
 	{ "antiquewhite", SLEN("antiquewhite") },
Index: src/parse/properties/utils.c
===================================================================
--- src/parse/properties/utils.c	(revision 13101)
+++ src/parse/properties/utils.c	(working copy)
@@ -1044,6 +1044,45 @@
 }
 
 /**
+ * Create a string from a list of IDENT/S tokens if the next token is IDENT
+ * or references the next token's stirng if it is a STRING
+ *
+ * \param c          Parsing context
+ * \param vector     Vector containing tokens
+ * \param ctx        Vector iteration context
+ * \param reserved   Callback to determine if an identifier is reserved
+ * \param result     Pointer to location to receive resulting string
+ * \return CSS_OK on success, appropriate error otherwise.
+ *
+ * Post condition: \a *ctx is updated with the next token to process
+ *                 If the input is invalid, then \a *ctx remains unchanged.
+ *
+ *                 The resulting string's reference is passed to the caller
+ */
+ css_error css__ident_list_or_string_to_string(css_language *c,
+		const parserutils_vector *vector, int *ctx,
+		bool (*reserved)(css_language *c, const css_token *ident),
+		lwc_string **result)
+{
+	const css_token *token;
+	
+	token = parserutils_vector_peek(vector, *ctx);
+	if (token == NULL)
+		return CSS_INVALID;
+	
+	if (token->type == CSS_TOKEN_STRING) {
+		token = parserutils_vector_iterate(vector, ctx);
+		*result = lwc_string_ref(token->idata);
+		return CSS_OK;
+	} else 	if(token->type == CSS_TOKEN_IDENT) {
+		return css__ident_list_to_string(c, vector, ctx, reserved,
+							result);
+	}
+	
+	return CSS_INVALID;
+}
+
+/**
  * Create a string from a list of IDENT/S tokens
  *
  * \param c          Parsing context
@@ -1058,7 +1097,7 @@
  *
  *                 The resulting string's reference is passed to the caller
  */
-static css_error ident_list_to_string(css_language *c,
+ css_error css__ident_list_to_string(css_language *c,
 		const parserutils_vector *vector, int *ctx,
 		bool (*reserved)(css_language *c, const css_token *ident),
 		lwc_string **result)
@@ -1084,7 +1123,7 @@
 			token->type == CSS_TOKEN_S)) {
 		if (token->type == CSS_TOKEN_IDENT) {
 			/* IDENT -- if reserved, reject style */
-			if (reserved(c, token)) {
+			if (reserved != NULL && reserved(c, token)) {
 				error = CSS_INVALID;
 				goto cleanup;
 			}
@@ -1175,7 +1214,7 @@
 
 				*ctx = prev_ctx;
 
-				error = ident_list_to_string(c, vector, ctx,
+				error = css__ident_list_to_string(c, vector, ctx,
 						reserved, &str);
 				if (error != CSS_OK)
 					goto cleanup;
Index: src/parse/properties/utils.h
===================================================================
--- src/parse/properties/utils.h	(revision 13101)
+++ src/parse/properties/utils.h	(working copy)
@@ -181,10 +181,22 @@
 css_error css__parse_unit_keyword(const char *ptr, size_t len, 
 		css_unit *unit);
 
+css_error css__ident_list_or_string_to_string(css_language *c,
+		const parserutils_vector *vector, int *ctx,
+		bool (*reserved)(css_language *c, const css_token *ident),
+		lwc_string **result);
+
+css_error css__ident_list_to_string(css_language *c,
+		const parserutils_vector *vector, int *ctx,
+		bool (*reserved)(css_language *c, const css_token *ident),
+		lwc_string **result);
+
 css_error css__comma_list_to_style(css_language *c,
 		const parserutils_vector *vector, int *ctx,
 		bool (*reserved)(css_language *c, const css_token *ident),
-		css_code_t (*get_value)(css_language *c, const css_token *token, bool first),
+		css_code_t (*get_value)(css_language *c,
+						const css_token *token, 
+						bool first),
 		css_style *result);
 
 #endif
Index: src/parse/Makefile
===================================================================
--- src/parse/Makefile	(revision 13101)
+++ src/parse/Makefile	(working copy)
@@ -1,4 +1,4 @@
 # Sources
-DIR_SOURCES := parse.c language.c important.c propstrings.c
+DIR_SOURCES := parse.c language.c important.c propstrings.c font_face.c
 
 include build/makefiles/Makefile.subdir
Index: src/stylesheet.c
===================================================================
--- src/stylesheet.c	(revision 13101)
+++ src/stylesheet.c	(working copy)
@@ -15,6 +15,7 @@
 #include "utils/parserutilserror.h"
 #include "utils/utils.h"
 #include "select/dispatch.h"
+#include "select/font_face.h"
 
 static css_error _add_selectors(css_stylesheet *sheet, css_rule *rule);
 static css_error _remove_selectors(css_stylesheet *sheet, css_rule *rule);
@@ -261,7 +262,7 @@
  */
 css_error css_stylesheet_destroy(css_stylesheet *sheet)
 {
-	uint32_t string_index;
+	uint32_t index;
 	css_rule *r, *s;
 
 	if (sheet == NULL)
@@ -296,17 +297,17 @@
 		css__stylesheet_style_destroy(sheet->cached_style);
 
 	/* destroy string vector */
-	for (string_index = 0;
-	     string_index < sheet->string_vector_c;
-	     string_index++) {
-		lwc_string_unref(sheet->string_vector[string_index]);		
+	for (index = 0;
+	     index < sheet->string_vector_c;
+	     index++) {
+		lwc_string_unref(sheet->string_vector[index]);		
 	}
 
 	if (sheet->string_vector != NULL)
 		sheet->alloc(sheet->string_vector, 0, sheet->pw);
 
 	css__propstrings_unref();
-
+	
 	sheet->alloc(sheet, 0, sheet->pw);
 
 	return CSS_OK;
@@ -625,7 +626,7 @@
 
 		bytes += hash_size;
 	}
-
+	
 	*size = bytes;
 
 	return CSS_OK;
@@ -1194,10 +1195,10 @@
 		break;
 	case CSS_RULE_FONT_FACE:
 	{
-		css_rule_font_face *font_face = (css_rule_font_face *) rule;
+		css_rule_font_face *font_face_r = (css_rule_font_face *) rule;
 
-		if (font_face->style != NULL)
-			css__stylesheet_style_destroy(font_face->style);
+		if (font_face_r->font_face != NULL)
+			css__font_face_destroy(font_face_r->font_face);
 	}
 		break;
 	case CSS_RULE_PAGE:
@@ -1705,8 +1706,8 @@
 
 		bytes += sizeof(css_rule_font_face);
 
-		if (rf->style != NULL)
-			bytes += (rf->style->used * sizeof(css_code_t));
+		if (rf->font_face != NULL)
+			bytes += sizeof(css_font_face);
 	} else if (r->type == CSS_RULE_PAGE) {
 		const css_rule_page *rp = (const css_rule_page *) r;
 		const css_selector *s = rp->selector;
@@ -1731,4 +1732,3 @@
 
 	return bytes;
 }
-
Index: Makefile
===================================================================
--- Makefile	(revision 13101)
+++ Makefile	(working copy)
@@ -46,6 +46,7 @@
 
 INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/libcss/computed.h
 INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/libcss/errors.h
+INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/libcss/font_face.h
 INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/libcss/fpmath.h
 INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/libcss/functypes.h
 INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/libcss/hint.h
