Index: pango/pango-modules.h
===================================================================
--- pango/pango-modules.h	(revision 2370)
+++ pango/pango-modules.h	(working copy)
@@ -42,17 +42,24 @@
   PangoEngine *(*create) (const char       *id);
 };
 
-PangoMap *     pango_find_map        (PangoLanguage       *language,
-				      guint                engine_type_id,
-				      guint                render_type_id);
-PangoEngine *  pango_map_get_engine  (PangoMap            *map,
-				      PangoScript          script);
-void           pango_map_get_engines (PangoMap            *map,
-				      PangoScript          script,
-				      GSList             **exact_engines,
-				      GSList             **fallback_engines);
-void           pango_module_register (PangoIncludedModule *module);
+PangoMap *   pango_find_map                (PangoLanguage        *language,
+					    guint                 engine_type_id,
+					    guint                 render_type_id);
+PangoEngine *pango_map_get_engine          (PangoMap             *map,
+					    PangoScript           script);
+void         pango_map_get_ordered_engines (PangoMap             *map,
+					    PangoScript           script,
+					    char                **engine_order,
+					    GSList              **exact_engines,
+					    GSList              **fallback_engines);
+void         pango_map_get_engines         (PangoMap             *map,
+					    PangoScript           script,
+					    GSList              **exact_engines,
+					    GSList              **fallback_engines);
+void         pango_module_register         (PangoIncludedModule  *module);
 
+char **pango_get_default_shape_engine_order (void);
+
 #endif /* PANGO_ENABLE_BACKEND */
 
 G_END_DECLS
Index: pango/fonts.c
===================================================================
--- pango/fonts.c	(revision 2370)
+++ pango/fonts.c	(working copy)
@@ -24,10 +24,12 @@
 #include <math.h>
 #include <string.h>
 
+#include "pango-engine-private.h"
 #include "pango-types.h"
 #include "pango-font.h"
 #include "pango-fontmap.h"
 #include "pango-impl-utils.h"
+#include "pango-modules.h"
 
 static const char bad_font_warning[] = "%s called with null font argument, expect ugly output";
 
@@ -1195,11 +1197,34 @@
   return result;
 }
 
+#define PANGO_FONT_GET_PRIVATE(font) G_TYPE_INSTANCE_GET_PRIVATE (font,              \
+                                                                  PANGO_TYPE_FONT,   \
+                                                                  PangoFontPrivate);
+typedef struct _PangoFontPrivate PangoFontPrivate;
+
+struct _PangoFontPrivate
+{
+  PangoScript engine_script;
+  PangoLanguage *engine_lang;
+  
+  GSList *exact_engines;
+  GSList *fallback_engines;
+};
+
+static void   pango_font_finalize                 (GObject   *object);
+static char **pango_font_default_get_engine_order (PangoFont *font);
+
 G_DEFINE_TYPE (PangoFont, pango_font, G_TYPE_OBJECT)
 
 static void
 pango_font_class_init (PangoFontClass *class)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS(class);
+
+  object_class->finalize = pango_font_finalize;
+  class->get_engine_order = pango_font_default_get_engine_order;
+  
+  g_type_class_add_private (object_class, sizeof (PangoFontPrivate));
 }
 
 static void
@@ -1252,6 +1277,78 @@
 }
 
 /**
+ * pango_font_get_engines:
+ * @map: a #PangoFont
+ * @script: a #PangoScript
+ * @lang: a #PangoLanguage
+ * @wc: The character that will be rendered
+ * @exact: if %TRUE, look only for exact engine matches, if %FALSE, look
+ *   only for approximate engine matches.
+ *
+ * Finds the appropriate engine to use for the font to handle the given script,
+ * language, and character. 
+ *
+ * Return value: The engine to use to render the given character with the given
+ *   font. If the no engine is found, returns %NULL. The returned engine is owned by
+ *   Pango and will be kept around permanently, so should not be unref'ed.
+ *
+ * Since: 1.20
+ **/
+PangoEngineShape *
+pango_font_get_engine(PangoFont        *font,
+		      PangoScript       script,
+		      PangoLanguage    *lang,
+		      gunichar          wc,
+		      gboolean          exact)
+{
+  PangoFontPrivate *priv;
+  GSList *engines;
+  GSList *l;
+
+  g_return_val_if_fail (PANGO_IS_FONT (font), NULL);
+
+  priv = PANGO_FONT_GET_PRIVATE (font);
+
+  if (!(script == priv->engine_script && lang == priv->engine_lang))
+    {
+      PangoFontMap *font_map =  pango_font_get_font_map (font);
+      const char *engine_type = pango_font_map_get_shape_engine_type (font_map);
+      PangoMap *shaper_map = pango_find_map (lang,
+					     g_quark_from_string (PANGO_ENGINE_TYPE_SHAPE),
+					     g_quark_from_string (engine_type));
+      char **engine_order = PANGO_FONT_GET_CLASS(font)->get_engine_order (font);
+
+      if (priv->exact_engines)
+	g_slist_free (priv->exact_engines);
+      if (priv->fallback_engines)
+	g_slist_free (priv->fallback_engines);
+      
+      pango_map_get_ordered_engines (shaper_map, script,
+				     engine_order,
+				     &priv->exact_engines,
+				     &priv->fallback_engines);
+    }
+
+  if (exact)
+    engines = priv->exact_engines;
+  else
+    engines = priv->fallback_engines;
+
+  for (l = engines; l; l = l->next)
+    {
+      PangoEngineShape *engine = l->data;
+      PangoCoverageLevel level;
+
+      level = _pango_engine_shape_covers (engine, font,
+					  lang, wc);
+      if (level != PANGO_COVERAGE_NONE)
+	return engine;
+    }
+
+  return NULL;
+}
+
+/**
  * pango_font_get_coverage:
  * @font: a #PangoFont
  * @language: the language tag
@@ -1390,6 +1487,24 @@
   return PANGO_FONT_GET_CLASS (font)->get_metrics (font, language);
 }
 
+static void
+pango_font_finalize(GObject *object)
+{
+  PangoFont *font = PANGO_FONT(object);
+  PangoFontPrivate *priv = PANGO_FONT_GET_PRIVATE(font);
+
+  if (priv->exact_engines)
+    g_slist_free(priv->exact_engines);
+  if (priv->fallback_engines)
+    g_slist_free(priv->fallback_engines);
+}
+ 
+static char **
+pango_font_default_get_engine_order (PangoFont *font)
+{
+  return pango_get_default_shape_engine_order();
+}
+
 /**
  * pango_font_get_font_map:
  * @font: a #PangoFont
Index: pango/modules.c
===================================================================
--- pango/modules.c	(revision 2370)
+++ pango/modules.c	(working copy)
@@ -92,6 +92,7 @@
 static GSList *registered_engines = NULL;
 static GSList *dlloaded_engines = NULL;
 static GHashTable *dlloaded_modules;
+static char **default_shape_engine_order;
 
 static GObjectClass *parent_class;
 
@@ -678,24 +679,101 @@
     return NULL;
 }
 
+/**
+ * pango_map_get_engines:
+ * @map: a #PangoMap
+ * @script: a #PangoScript
+ * @exact_engines: location to store list of engines that exactly
+ *  handle this script.
+ * @fallback_engines: location to store list of engines that approximately
+ *  handle this script.
+ *
+ * Finds engines in the map that handle the given script. The returned
+ * lists should be freed with g_slist_free, but the engines in the
+ * lists are owned by Pango and will be kept around permanently, so
+ * they should not be unref'ed.
+ *
+ * Since: 1.4
+ **/
+void
+pango_map_get_engines (PangoMap     *map,
+		       PangoScript   script,
+		       GSList      **exact_engines,
+		       GSList      **fallback_engines)
+{
+  return pango_map_get_ordered_engines(map, script, NULL, exact_engines, fallback_engines);
+}
+
+static int
+compare_engines(gconstpointer a,
+		gconstpointer b,
+		gpointer      data)
+{
+  const PangoEnginePair *pair_a = a;
+  const PangoEnginePair *pair_b = b;
+  char **engine_order = data;
+  int a_index = G_MAXINT;
+  int b_index = G_MAXINT;
+  int i;
+  
+  for (i = 0; engine_order[i]; i++)
+    {
+      if (strcmp (engine_order[i], pair_a->info.id) == 0)
+	{
+	  a_index = i;
+	  break;
+	}
+    }
+  
+  for (i = 0; engine_order[i]; i++)
+    {
+      if (strcmp (engine_order[i], pair_b->info.id) == 0)
+	{
+	  b_index = i;
+	  break;
+	}
+    }
+
+  return (a_index < b_index) ? -1 : (a_index == b_index) ? 0 : 1;
+}
+
+static GSList *
+sort_engines(GSList *engine_list,
+	     char  **engine_order)
+{
+  return g_slist_sort_with_data(engine_list, compare_engines, engine_order);
+}
+
 static void
-append_engines (GSList **engine_list,
-		GSList  *pair_list)
+resolve_engines (GSList **pair_list)
 {
   GSList *l;
 
-  for (l = pair_list; l; l = l->next)
+  for (l = *pair_list; l;)
     {
       PangoEngine *engine = pango_engine_pair_get_engine (l->data);
       if (engine)
-	*engine_list = g_slist_append (*engine_list, engine);
+	{
+	  l->data = engine;
+	  l = l->next;
+	}
+      else
+	{
+	  if (l == *pair_list)
+	    *pair_list = l = g_slist_delete_link(l, l);
+	  else
+	    l = g_slist_delete_link(l, l);
+	}
     }
 }
 
 /**
- * pango_map_get_engines:
+ * pango_map_get_ordered_engines:
  * @map: a #PangoMap
  * @script: a #PangoScript
+ * @engine_order: a %NULL-terminated list of engine IDs that provide
+ *   a sort order for the returned engines. If %NULL the returned
+ *   engines will be in arbitrary order
  * @exact_engines: location to store list of engines that exactly
  *  handle this script.
  * @fallback_engines: location to store list of engines that approximately
@@ -703,16 +781,17 @@
  *
  * Finds engines in the map that handle the given script. The returned
  * lists should be freed with g_slist_free, but the engines in the
- * lists are owned by GLib and will be kept around permanently, so
+ * lists are owned by Pango and will be kept around permanently, so
  * they should not be unref'ed.
  *
- * Since: 1.4
+ * Since: 1.20
  **/
 void
-pango_map_get_engines (PangoMap     *map,
-		       PangoScript   script,
-		       GSList      **exact_engines,
-		       GSList      **fallback_engines)
+pango_map_get_ordered_engines (PangoMap     *map,
+			       PangoScript   script,
+			       char        **engine_order,
+			       GSList      **exact_engines,
+			       GSList      **fallback_engines)
 {
   PangoMapEntry *entry = NULL;
   PangoMapEntry *common_entry = NULL;
@@ -727,22 +806,70 @@
     {
       *exact_engines = NULL;
       if (entry && entry->exact)
-	append_engines (exact_engines, entry->exact);
+	*exact_engines = g_slist_concat (*exact_engines, g_slist_copy(entry->exact));
       else if (common_entry && common_entry->exact)
-	append_engines (exact_engines, common_entry->exact);
+	*exact_engines = g_slist_concat (*exact_engines, g_slist_copy(common_entry->exact));
+
+      if (engine_order)
+	sort_engines (*exact_engines, engine_order);
+
+      resolve_engines (exact_engines);
     }
 
   if (fallback_engines)
     {
       *fallback_engines = NULL;
       if (entry && entry->fallback)
-	append_engines (fallback_engines, entry->fallback);
+	*fallback_engines = g_slist_concat (*exact_engines, g_slist_copy(entry->fallback));
       else if (common_entry && common_entry->fallback)
-	append_engines (fallback_engines, common_entry->fallback);
+	*fallback_engines = g_slist_concat (*exact_engines, g_slist_copy(common_entry->fallback));
+      
+      if (engine_order)
+	sort_engines (*fallback_engines, engine_order);
+
+      resolve_engines (fallback_engines);
     }
 }
 
 /**
+ * pango_get_default_shape_engine_order:
+ *
+ * Gets a list of shape engine IDs in the order they should be used
+ * if there are no font-specific preferences in place. See
+ * pango_map_get_ordered_engines().
+ * 
+ * Return value: a null-terminated list of strings. The value is
+ * owned by Pango and should not be modified or freed.
+ *
+ * Since: 1.20
+ */
+char **
+pango_get_default_shape_engine_order (void)
+{
+  if (default_shape_engine_order == NULL)
+    {
+      char *order_string = pango_config_key_get ("Pango/ShapeEngineOrder");
+      if (order_string == NULL)
+	{
+	  default_shape_engine_order = g_new(char *, 1);
+	  default_shape_engine_order[0] = NULL;
+	}
+      else
+	{
+	  int i;
+	
+	  default_shape_engine_order = g_strsplit(order_string, ",", -1);
+	  for (i = 0; default_shape_engine_order[i]; i++)
+	    g_strchomp(default_shape_engine_order[i]); /* Trim leading/trailing spaces */
+
+	  g_free(order_string);
+	}
+    }
+
+  return default_shape_engine_order;
+}
+
+/**
  * pango_module_register:
  * @module: a #PangoIncludedModule
  *
Index: pango/pango-font.h
===================================================================
--- pango/pango-font.h	(revision 2370)
+++ pango/pango-font.h	(working copy)
@@ -356,10 +356,12 @@
 					       PangoLanguage  *language);
   PangoFontMap *        (*get_font_map)       (PangoFont      *font);
   PangoFontDescription *(*describe_absolute)  (PangoFont      *font);
+  /* Result is owned by the font and should not be modified/freed */
+  char **               (*get_engine_order)   (PangoFont      *font);
+
   /*< private >*/
 
   /* Padding for future expansion */
-  void (*_pango_reserved1) (void);
   void (*_pango_reserved2) (void);
 };
 
@@ -371,13 +373,20 @@
 
 #endif /* PANGO_ENABLE_BACKEND */
 
+#ifdef PANGO_ENABLE_ENGINE
+PangoEngineShape     *pango_font_get_engine        (PangoFont        *font,
+						    PangoScript       script,
+						    PangoLanguage    *lang,
+						    gunichar          wc,
+						    gboolean          exact);
+#endif /* PANGO_ENABLE_ENGINE */
+
 #if defined(PANGO_ENABLE_ENGINE) || defined(PANGO_ENABLE_BACKEND)
 #define PANGO_GLYPH_EMPTY           ((PangoGlyph)0x0FFFFFFF)
 #define PANGO_GLYPH_UNKNOWN_FLAG    ((PangoGlyph)0x10000000)
 #define PANGO_GET_UNKNOWN_GLYPH(wc) ((PangoGlyph)(wc)|PANGO_GLYPH_UNKNOWN_FLAG)
 #endif
 
-
 G_END_DECLS
 
 #endif /* __PANGO_FONT_H__ */
Index: pango/pangofc-font.c
===================================================================
--- pango/pangofc-font.c	(revision 2370)
+++ pango/pangofc-font.c	(working copy)
@@ -59,6 +59,7 @@
   PangoFcDecoder *decoder;
   gpointer context_key;
   GUnicharToGlyphCacheEntry *char_to_glyph_cache;
+  char **engine_order;
 };
 
 #define GLYPH_CACHE_NUM_ENTRIES 256 /* should be power of two */
@@ -84,8 +85,8 @@
 static PangoFontMap *        pango_fc_font_get_font_map (PangoFont        *font);
 static PangoFontDescription *pango_fc_font_describe     (PangoFont        *font);
 static PangoFontDescription *pango_fc_font_describe_absolute (PangoFont        *font);
+static char                **pango_fc_font_get_engine_order  (PangoFont   *font);
 
-
 #define PANGO_FC_FONT_LOCK_FACE(font)	(PANGO_FC_FONT_GET_CLASS (font)->lock_face (font))
 #define PANGO_FC_FONT_UNLOCK_FACE(font)	(PANGO_FC_FONT_GET_CLASS (font)->unlock_face (font))
 
@@ -109,6 +110,7 @@
   font_class->get_coverage = pango_fc_font_get_coverage;
   font_class->get_metrics = pango_fc_font_get_metrics;
   font_class->get_font_map = pango_fc_font_get_font_map;
+  font_class->get_engine_order = pango_fc_font_get_engine_order;
 
   g_object_class_install_property (object_class, PROP_PATTERN,
 				   g_param_spec_pointer ("pattern",
@@ -154,6 +156,9 @@
 
   g_free (priv->char_to_glyph_cache);
 
+  if (priv->engine_order)
+    g_strfreev(priv->engine_order);
+
   G_OBJECT_CLASS (pango_fc_font_parent_class)->finalize (object);
 }
 
@@ -241,6 +246,51 @@
   return desc;
 }
 
+static char **
+pango_fc_font_get_engine_order (PangoFont *font)
+{
+  PangoFcFont *fcfont = PANGO_FC_FONT (font);
+  PangoFcFontPrivate *priv = fcfont->priv;
+
+  if (!priv->engine_order)
+    {
+      char **default_orders = pango_get_default_shape_engine_order();
+      GSList *orders = NULL;
+      int order_count = 0;
+      int i;
+      FcChar8 *engine_id;
+      GSList *l;
+
+      i = 0;
+      while (FcPatternGetString (fcfont->font_pattern,
+				 "pango-engine", i, &engine_id) == FcResultMatch)
+	{
+	  orders = g_slist_prepend (orders, engine_id);
+	  order_count++;
+	  i++;
+	}
+
+      for (i = 0; default_orders[i]; i++)
+	{
+	  orders = g_slist_prepend (orders, default_orders[i]);
+	  order_count++;
+	}
+
+      priv->engine_order = g_new(char *, order_count + 1);
+      
+      priv->engine_order[order_count] = NULL;
+      
+      i = order_count - 1;
+      for (l = orders; l; l = l->next)
+	{
+	  priv->engine_order[i] = g_strdup(l->data);
+	  i--;
+	}
+    }
+
+  return priv->engine_order;
+}
+
 static PangoMap *
 pango_fc_get_shaper_map (PangoLanguage *language)
 {
@@ -441,7 +491,7 @@
   PangoRectangle extents;
   PangoLanguage *language = pango_context_get_language (context);
   const char *sample_str = pango_language_get_sample_string (language);
-  PangoFontDescription *desc = pango_font_describe_with_absolute_size (fcfont);
+  PangoFontDescription *desc = pango_font_describe_with_absolute_size (PANGO_FONT(fcfont));
 
   metrics = pango_font_metrics_new ();
 
Index: pango/pango-context.c
===================================================================
--- pango/pango-context.c	(revision 2370)
+++ pango/pango-context.c	(working copy)
@@ -695,9 +695,6 @@
   ShaperFontCache *cache;
   PangoFont *base_font;
   gboolean enable_fallback;
-
-  GSList *exact_engines;
-  GSList *fallback_engines;
 };
 
 static void
@@ -868,8 +865,6 @@
   state->lang_engine = NULL;
   state->current_fonts = NULL;
   state->cache = NULL;
-  state->exact_engines = NULL;
-  state->fallback_engines = NULL;
   state->base_font = NULL;
 
   state->changed = EMBEDDING_CHANGED | SCRIPT_CHANGED | LANG_CHANGED | FONT_CHANGED;
@@ -1035,25 +1030,11 @@
   state->result = g_list_prepend (state->result, state->item);
 }
 
-static void
-get_engines (PangoContext  *context,
-	     PangoLanguage *lang,
-	     PangoScript    script,
-	     GSList       **exact_engines,
-	     GSList       **fallback_engines)
-{
-  const char *engine_type = pango_font_map_get_shape_engine_type (context->font_map);
-  PangoMap *shaper_map = pango_find_map (lang,
-					 g_quark_from_string (PANGO_ENGINE_TYPE_SHAPE),
-					 g_quark_from_string (engine_type));
-  pango_map_get_engines (shaper_map, script,
-			 exact_engines, fallback_engines);
-}
-
 typedef struct {
+  PangoScript script;
   PangoLanguage *lang;
+  gboolean exact_engine_pass;
   gunichar wc;
-  GSList *engines;
   PangoEngineShape *shape_engine;
   PangoFont *font;
 } GetShaperFontInfo;
@@ -1064,21 +1045,17 @@
 			     gpointer      data)
 {
   GetShaperFontInfo *info = data;
-  GSList *l;
+  PangoEngine *engine;
 
-  for (l = info->engines; l; l = l->next)
-    {
-      PangoEngineShape *engine = l->data;
-      PangoCoverageLevel level;
+  engine = pango_font_get_engine(font, info->script, info->lang,
+				 info->wc, info->exact_engine_pass);
 
-      level = _pango_engine_shape_covers (engine, font,
-					  info->lang, info->wc);
-      if (level != PANGO_COVERAGE_NONE)
-	{
-	  info->shape_engine = engine;
-	  info->font = g_object_ref (font);
-	  return TRUE;
-	}
+  if (engine)
+    {
+      info->shape_engine = engine;
+      info->font = g_object_ref (font);
+      
+      return TRUE;
     }
 
   return FALSE;
@@ -1107,28 +1084,20 @@
   if (state->enable_fallback && shaper_font_cache_get (state->cache, wc, shape_engine, font))
     return *shape_engine != NULL;
 
-  if (!state->exact_engines && !state->fallback_engines)
-    {
-      /* Always use a basic shaper for vertical layout (ie, east/west gravity)
-       * as we do not support vertical shaping as of now.
-       */
-      PangoScript script;
+  /* Always use a basic shaper for vertical layout (ie, east/west gravity)
+   * as we do not support vertical shaping as of now.
+   */
+  if (PANGO_GRAVITY_IS_VERTICAL (state->resolved_gravity))
+    info.script = PANGO_SCRIPT_COMMON;
+  else
+    info.script = state->script;
 
-      if (PANGO_GRAVITY_IS_VERTICAL (state->resolved_gravity))
-	script = PANGO_SCRIPT_COMMON;
-      else
-	script = state->script;
-
-      get_engines (state->context, state->derived_lang, script,
-		   &state->exact_engines, &state->fallback_engines);
-    }
-
   info.lang = state->derived_lang;
   info.wc = wc;
   info.shape_engine = NULL;
   info.font = NULL;
 
-  info.engines = state->exact_engines;
+  info.exact_engine_pass = TRUE;
   if (state->enable_fallback)
     pango_fontset_foreach (state->current_fonts, get_shaper_and_font_foreach, &info);
   else
@@ -1146,7 +1115,7 @@
       return TRUE;
     }
 
-  info.engines = state->fallback_engines;
+  info.exact_engine_pass = FALSE;
   if (state->enable_fallback)
     pango_fontset_foreach (state->current_fonts, get_shaper_and_font_foreach, &info);
   else
@@ -1162,15 +1131,6 @@
   return *shape_engine != NULL;
 }
 
-static void
-itemize_state_reset_shape_engines (ItemizeState *state)
-{
-  g_slist_free (state->exact_engines);
-  state->exact_engines = NULL;
-  g_slist_free (state->fallback_engines);
-  state->fallback_engines = NULL;
-}
-
 static PangoLanguage *
 compute_derived_language (PangoLanguage *lang,
 			  PangoScript    script)
@@ -1262,9 +1222,6 @@
       state->lang_engine = (PangoEngineLang *)pango_map_get_engine (lang_map, state->script);
     }
 
-  if (state->changed & (SCRIPT_CHANGED | DERIVED_LANG_CHANGED))
-    itemize_state_reset_shape_engines (state);
-
   if (state->changed & (FONT_CHANGED | DERIVED_LANG_CHANGED) &&
       state->current_fonts)
     {
@@ -1371,7 +1328,6 @@
   pango_script_iter_free (state->script_iter);
   pango_font_description_free (state->font_desc);
 
-  itemize_state_reset_shape_engines (state);
   if (state->current_fonts)
     g_object_unref (state->current_fonts);
   if (state->base_font)
