diff --git a/pango-1.23.0-g5317893.patch b/pango-1.23.0-g5317893.patch
new file mode 100644
index 0000000..f56277b
--- /dev/null
+++ b/pango-1.23.0-g5317893.patch
@@ -0,0 +1,1937 @@
+diff --git a/docs/pango-sections.txt b/docs/pango-sections.txt
+index 7ed853c..0fbdc22 100644
+--- a/docs/pango-sections.txt
++++ b/docs/pango-sections.txt
+@@ -919,6 +919,7 @@ PangoFcFontMapClass
+ pango_fc_font_map_create_context
+ PangoFcDecoderFindFunc
+ pango_fc_font_map_add_decoder_find_func
++pango_fc_font_map_find_decoder
+ pango_fc_font_map_cache_clear
+ pango_fc_font_map_shutdown
+ pango_fc_font_description_from_pattern
+diff --git a/docs/tmpl/pangofc-font.sgml b/docs/tmpl/pangofc-font.sgml
+index 95ac1dd..a1b055c 100644
+--- a/docs/tmpl/pangofc-font.sgml
++++ b/docs/tmpl/pangofc-font.sgml
+@@ -40,6 +40,11 @@ Fontconfig-based backend involves deriving from both
+
+
+
++
++
++
++
++
+
+
+
+diff --git a/docs/tmpl/pangofc-fontmap.sgml b/docs/tmpl/pangofc-fontmap.sgml
+index bcfae81..ee6cca0 100644
+--- a/docs/tmpl/pangofc-fontmap.sgml
++++ b/docs/tmpl/pangofc-fontmap.sgml
+@@ -86,6 +86,16 @@ Fontconfig-based backend involves deriving from both
+ @dnotify:
+
+
++
++
++
++
++
++@fcfontmap:
++@pattern:
++@Returns:
++
++
+
+
+
+diff --git a/pango-view/Makefile.am b/pango-view/Makefile.am
+index 9780c14..c406975 100644
+--- a/pango-view/Makefile.am
++++ b/pango-view/Makefile.am
+@@ -23,7 +23,6 @@ TEST_TEXTS = \
+ GLASS.txt
+
+ EXTRA_DIST = \
+- viewer-win32.c \
+ $(TEST_TEXTS)
+
+ CLEANFILES = pangorc
+diff --git a/pango-view/viewer-win32.c b/pango-view/viewer-win32.c
+deleted file mode 100644
+index 468a6cc..0000000
+--- a/pango-view/viewer-win32.c
++++ /dev/null
+@@ -1,748 +0,0 @@
+-/* Pango
+- * viewer-win32.c: Example program to view a UTF-8 encoding file
+- * using Pango to render result.
+- *
+- * Copyright (C) 1999 Red Hat Software
+- *
+- * This library is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU Library General Public
+- * License as published by the Free Software Foundation; either
+- * version 2 of the License, or (at your option) any later version.
+- *
+- * This library is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- * Library General Public License for more details.
+- *
+- * You should have received a copy of the GNU Library General Public
+- * License along with this library; if not, write to the
+- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+- * Boston, MA 02111-1307, USA.
+- */
+-#include "config.h"
+-#include
+-#include
+-
+-#include
+-#include
+-
+-#include
+-#include
+-#include
+-#include
+-
+-#define BUFSIZE 1024
+-
+-typedef struct _Paragraph Paragraph;
+-
+-/* Structure representing a paragraph
+- */
+-struct _Paragraph {
+- char *text;
+- int length;
+- int height; /* Height, in pixels */
+- PangoLayout *layout;
+-};
+-
+-GList *paragraphs;
+-
+-static PangoFontDescription *font_description;
+-static Paragraph *highlight_para;
+-static int highlight_offset;
+-
+-GtkWidget *styles_combo;
+-
+-static GtkWidget *message_label;
+-GtkWidget *layout;
+-
+-PangoContext *context;
+-
+-static void fill_styles_combo (GtkWidget *combo);
+-
+-/* Read an entire file into a string
+- */
+-static char *
+-read_file(char *name)
+-{
+- GString *inbuf;
+- FILE *file;
+- char *text;
+- char buffer[BUFSIZE];
+-
+- file = fopen (name, "r");
+- if (!file)
+- {
+- fprintf (stderr, "%s: Cannot open %s\n", g_get_prgname (), name);
+- return NULL;
+- }
+-
+- inbuf = g_string_new (NULL);
+- while (1)
+- {
+- char *bp = fgets (buffer, BUFSIZE-1, file);
+- if (ferror (file))
+- {
+- fprintf (stderr, "%s: Error reading %s\n", g_get_prgname (), name);
+- g_string_free (inbuf, TRUE);
+- return NULL;
+- }
+- else if (bp == NULL)
+- break;
+-
+- g_string_append (inbuf, buffer);
+- }
+-
+- fclose (file);
+-
+- text = inbuf->str;
+- g_string_free (inbuf, FALSE);
+-
+- return text;
+-}
+-
+-/* Take a UTF8 string and break it into paragraphs on \n characters
+- */
+-static GList *
+-split_paragraphs (char *text)
+-{
+- char *p = text;
+- char *next;
+- gunichar wc;
+- GList *result = NULL;
+- char *last_para = text;
+-
+- while (*p)
+- {
+- wc = g_utf8_get_char (p);
+- next = g_utf8_next_char (p);
+- if (wc == (gunichar)-1)
+- {
+- fprintf (stderr, "%s: Invalid character in input\n", g_get_prgname ());
+- g_list_foreach (result, (GFunc)g_free, NULL);
+- return NULL;
+- }
+- if (!*p || !wc || wc == '\n')
+- {
+- Paragraph *para = g_new (Paragraph, 1);
+- para->text = last_para;
+- para->length = p - last_para;
+- para->layout = pango_layout_new (context);
+- pango_layout_set_text (para->layout, para->text, para->length);
+- para->height = 0;
+-
+- last_para = next;
+-
+- result = g_list_prepend (result, para);
+- }
+- if (!wc) /* incomplete character at end */
+- break;
+- p = next;
+- }
+-
+- return g_list_reverse (result);
+-}
+-
+-/* Given an x-y position, return the paragraph and offset
+- * within the paragraph of the click.
+- */
+-gboolean
+-xy_to_cp (int width, int x, int y, Paragraph **para_return, int *index)
+-{
+- GList *para_list;
+- int height = 0;
+-
+- *para_return = NULL;
+-
+- para_list = paragraphs;
+- while (para_list && height < y)
+- {
+- Paragraph *para = para_list->data;
+-
+- if (height + para->height >= y)
+- {
+- gboolean result = pango_layout_xy_to_index (para->layout,
+- x * PANGO_SCALE,
+- (y - height) * PANGO_SCALE,
+- index, NULL);
+- if (result && para_return)
+- *para_return = para;
+-
+- return result;
+- }
+-
+- height += para->height;
+- para_list = para_list->next;
+- }
+-
+- return FALSE;
+-}
+-
+-/* Given a paragraph and offset in that paragraph, find the
+- * bounding rectangle for the character at the offset.
+- */
+-void
+-char_bounds (Paragraph *para, int index, int width, PangoRectangle *rect)
+-{
+- GList *para_list;
+-
+- int height = 0;
+-
+- para_list = paragraphs;
+- while (para_list)
+- {
+- Paragraph *cur_para = para_list->data;
+-
+- if (cur_para == para)
+- {
+- PangoRectangle pos;
+-
+- pango_layout_index_to_pos (cur_para->layout, index, &pos);
+-
+- rect->x = PANGO_PIXELS (MIN (pos.x, pos.x + pos.width));
+- rect->width = PANGO_PIXELS (ABS (pos.width));
+- rect->y = height + PANGO_PIXELS (pos.y);
+- rect->height = PANGO_PIXELS (pos.height);
+- }
+-
+- height += cur_para->height;
+- para_list = para_list->next;
+- }
+-}
+-
+-/* XOR a rectangle over a given character
+- */
+-void
+-xor_char (GtkWidget *layout, GdkRectangle *clip_rect,
+- Paragraph *para, int offset)
+-{
+- static GdkGC *gc;
+- PangoRectangle rect; /* GdkRectangle in 1.2 is too limited
+- */
+- if (!gc)
+- {
+- GdkGCValues values;
+- values.foreground = layout->style->white.pixel ?
+- layout->style->white : layout->style->black;
+- values.function = GDK_XOR;
+- gc = gdk_gc_new_with_values (GTK_LAYOUT (layout)->bin_window,
+- &values,
+- GDK_GC_FOREGROUND | GDK_GC_FUNCTION);
+- }
+-
+- gdk_gc_set_clip_rectangle (gc, clip_rect);
+-
+- char_bounds (para, offset, layout->allocation.width, &rect);
+-
+- rect.y -= GTK_LAYOUT (layout)->yoffset;
+-
+- if ((rect.y + rect.height >= 0) && (rect.y < layout->allocation.height))
+- gdk_draw_rectangle (GTK_LAYOUT (layout)->bin_window, gc, TRUE,
+- rect.x, rect.y, rect.width, rect.height);
+-}
+-
+-/* Handle a size allocation by re-laying-out each paragraph to
+- * the new width, setting the new size for the layout and
+- * then queing a redraw
+- */
+-void
+-size_allocate (GtkWidget *layout, GtkAllocation *allocation)
+-{
+- GList *tmp_list;
+- guint height = 0;
+- PangoDirection base_dir = pango_context_get_base_dir (context);
+-
+- tmp_list = paragraphs;
+- while (tmp_list)
+- {
+- Paragraph *para = tmp_list->data;
+- PangoRectangle logical_rect;
+-
+- tmp_list = tmp_list->next;
+-
+- pango_layout_set_alignment (para->layout,
+- base_dir == PANGO_DIRECTION_LTR ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT);
+- pango_layout_set_width (para->layout, layout->allocation.width * PANGO_SCALE);
+-
+- pango_layout_get_extents (para->layout, NULL, &logical_rect);
+- para->height = PANGO_PIXELS (logical_rect.height);
+-
+- height += para->height;
+- }
+-
+- gtk_layout_set_size (GTK_LAYOUT (layout), allocation->width, height);
+-
+- if (GTK_LAYOUT (layout)->yoffset + allocation->height > height)
+- gtk_adjustment_set_value (GTK_LAYOUT (layout)->vadjustment, (float)(height - allocation->height));
+-}
+-
+-/* Handle a draw/expose by finding the paragraphs that intersect
+- * the region and reexposing them.
+- */
+-void
+-draw (GtkWidget *layout, GdkRectangle *area)
+-{
+- GList *tmp_list;
+- guint height = 0;
+- HDC hdc;
+- const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_BACKGROUND|GDK_GC_FONT;
+-
+- gdk_draw_rectangle (GTK_LAYOUT (layout)->bin_window,
+- layout->style->base_gc[layout->state],
+- TRUE,
+- area->x, area->y,
+- area->width, area->height);
+-
+- gdk_gc_set_clip_rectangle (layout->style->text_gc[layout->state], area);
+-
+- hdc = gdk_win32_hdc_get (GTK_LAYOUT (layout)->bin_window,
+- layout->style->text_gc[GTK_STATE_NORMAL],
+- mask);
+- tmp_list = paragraphs;
+- while (tmp_list &&
+- height < area->y + area->height + GTK_LAYOUT (layout)->yoffset)
+- {
+- Paragraph *para = tmp_list->data;
+- tmp_list = tmp_list->next;
+-
+- if (height + para->height >= GTK_LAYOUT (layout)->yoffset + area->y)
+- pango_win32_render_layout (hdc, para->layout,
+- 0, height - GTK_LAYOUT (layout)->yoffset);
+- height += para->height;
+- }
+-
+- gdk_win32_hdc_release (GTK_LAYOUT (layout)->bin_window,
+- layout->style->text_gc[GTK_STATE_NORMAL],
+- mask);
+- gdk_gc_set_clip_rectangle (layout->style->text_gc[layout->state], NULL);
+-
+- if (highlight_para)
+- xor_char (layout, area, highlight_para, highlight_offset);
+-}
+-
+-gboolean
+-expose (GtkWidget *layout, GdkEventExpose *event)
+-{
+- if (event->window == GTK_LAYOUT (layout)->bin_window)
+- draw (layout, &event->area);
+-
+- return TRUE;
+-}
+-
+-void
+-button_press (GtkWidget *layout, GdkEventButton *event)
+-{
+- Paragraph *para = NULL;
+- int offset;
+- gchar *message;
+-
+- xy_to_cp (layout->allocation.width,
+- event->x, event->y + GTK_LAYOUT (layout)->yoffset,
+- ¶, &offset);
+-
+- if (highlight_para)
+- xor_char (layout, NULL, highlight_para, highlight_offset);
+-
+- highlight_para = para;
+- highlight_offset = offset;
+-
+- if (para)
+- {
+- gunichar wc;
+-
+- wc = g_utf8_get_char (para->text + offset);
+- message = g_strdup_printf ("Current char: U%04x", wc);
+-
+- xor_char (layout, NULL, highlight_para, highlight_offset);
+- }
+- else
+- message = g_strdup_printf ("Current char:");
+-
+- gtk_label_set_text (GTK_LABEL (message_label), message);
+- g_free (message);
+-}
+-
+-static void
+-checkbutton_toggled (GtkWidget *widget, gpointer data)
+-{
+- GList *para_list;
+-
+- pango_context_set_base_dir (context, GTK_TOGGLE_BUTTON (widget)->active ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR);
+-
+- para_list = paragraphs;
+- while (para_list)
+- {
+- Paragraph *para = para_list->data;
+-
+- pango_layout_context_changed (para->layout);
+- para_list = para_list->next;
+- }
+-
+- gtk_widget_queue_resize (layout);
+-}
+-
+-static void
+-reload_font ()
+-{
+- GList *para_list;
+-
+- pango_context_set_font_description (context, font_description);
+-
+- para_list = paragraphs;
+- while (para_list)
+- {
+- Paragraph *para = para_list->data;
+-
+- pango_layout_context_changed (para->layout);
+- para_list = para_list->next;
+- }
+-
+- if (layout)
+- gtk_widget_queue_resize (layout);
+-}
+-
+-void
+-set_family (GtkWidget *entry, gpointer data)
+-{
+- gchar *family_name = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
+- if (!family_name || family_name[0] == '\0')
+- return;
+- pango_font_description_set_family(font_description, family_name);
+- fill_styles_combo (styles_combo);
+-}
+-
+-void
+-set_style (GtkWidget *entry, gpointer data)
+-{
+- char *str = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
+- PangoFontDescription *tmp_desc;
+-
+- tmp_desc = pango_font_description_from_string (str);
+-
+- pango_font_description_set_style(font_description, pango_font_description_get_style(tmp_desc));
+- pango_font_description_set_variant(font_description, pango_font_description_get_variant(tmp_desc));
+- pango_font_description_set_weight(font_description, pango_font_description_get_weight(tmp_desc));
+- pango_font_description_set_stretch(font_description, pango_font_description_get_stretch(tmp_desc));
+-
+- pango_font_description_free (tmp_desc);
+- g_free (str);
+-
+- reload_font ();
+-}
+-
+-void
+-font_size_changed (GtkAdjustment *adj)
+-{
+- pango_font_description_set_size(font_description, (int)(adj->value * PANGO_SCALE + 0.5));
+- reload_font();
+-}
+-
+-static int
+-compare_font_descriptions (const PangoFontDescription *a, const PangoFontDescription *b)
+-{
+- int val = strcmp (pango_font_description_get_family(a), pango_font_description_get_family(b));
+- if (val != 0)
+- return val;
+-
+- if (pango_font_description_get_weight(a) != pango_font_description_get_weight(b))
+- return pango_font_description_get_weight(a) - pango_font_description_get_weight(b);
+-
+- if (pango_font_description_get_style(a) != pango_font_description_get_style(b))
+- return pango_font_description_get_style(a) - pango_font_description_get_style(b);
+-
+- if (pango_font_description_get_stretch(a) != pango_font_description_get_stretch(b))
+- return pango_font_description_get_stretch(a) - pango_font_description_get_stretch(b);
+-
+- if (pango_font_description_get_stretch(a) != pango_font_description_get_stretch(b))
+- return pango_font_description_get_stretch(a) - pango_font_description_get_stretch(b);
+-
+- return 0;
+-}
+-
+-static int
+-font_description_sort_func (const void *a, const void *b)
+-{
+- return compare_font_descriptions (*(PangoFontDescription **)a, *(PangoFontDescription **)b);
+-}
+-
+-typedef struct
+-{
+- PangoFontDescription **descs;
+- int n_descs;
+-} FontDescInfo;
+-
+-static void
+-free_info (FontDescInfo *info)
+-{
+- pango_font_descriptions_free (info->descs, info->n_descs);
+-}
+-
+-static void
+-fill_styles_combo (GtkWidget *combo)
+-{
+- int i;
+- GList *style_list = NULL;
+- PangoFontFace **faces;
+- PangoFontFamily *family, **families;
+- FontDescInfo *info;
+- int n_families;
+- const char *family_name = pango_font_description_get_family(font_description);
+-
+- /*
+- * Now map back the given family name to the family. There are more efficient
+- * ways to handle this but it should not matter much ...
+- */
+- pango_context_list_families (context, &families, &n_families);
+- g_assert(n_families > 0);
+- family = families[0]; /* just in case */
+- for (i = 0; i < n_families; i++)
+- {
+- if (0 == g_strcasecmp(pango_font_family_get_name(families[i]), family_name))
+- {
+- family = families[i];
+- break;
+- }
+- }
+- g_free (families);
+-
+- info = g_new (FontDescInfo, 1);
+- pango_font_family_list_faces (family, &faces, &info->n_descs);
+-
+- info->descs = g_new0 (PangoFontDescription*, info->n_descs);
+- for (i = 0; i < info->n_descs; i++)
+- {
+- info->descs[i] = pango_font_face_describe(faces[i]);
+- }
+- g_free (faces);
+-
+- gtk_object_set_data_full (GTK_OBJECT (combo), "descs", info, (GtkDestroyNotify)free_info);
+-
+- qsort (info->descs, info->n_descs, sizeof(PangoFontDescription *), font_description_sort_func);
+-
+- for (i=0; in_descs; i++)
+- {
+- char *str;
+-
+- PangoFontDescription *tmp_desc;
+-
+- tmp_desc = info->descs[i];
+- pango_font_description_set_family(tmp_desc, NULL);
+- pango_font_description_unset_fields(tmp_desc, PANGO_FONT_MASK_SIZE);
+-
+- str = pango_font_description_to_string (tmp_desc);
+- style_list = g_list_prepend (style_list, str);
+- }
+-
+- style_list = g_list_reverse (style_list);
+-
+- gtk_combo_set_popdown_strings (GTK_COMBO (combo), style_list);
+- g_list_foreach (style_list, (GFunc)g_free, NULL);
+-}
+-
+-static GtkWidget *
+-make_styles_combo ()
+-{
+- GtkWidget *combo;
+-
+- combo = gtk_combo_new ();
+- gtk_combo_set_value_in_list (GTK_COMBO (combo), TRUE, FALSE);
+- gtk_editable_set_editable (GTK_EDITABLE (GTK_COMBO (combo)->entry), FALSE);
+-
+- gtk_signal_connect (GTK_OBJECT (GTK_COMBO (combo)->entry), "changed",
+- GTK_SIGNAL_FUNC (set_style), NULL);
+-
+- styles_combo = combo;
+- fill_styles_combo (combo);
+-
+- return combo;
+-}
+-
+-static int
+-cmp_families (const PangoFontFamily** a, const PangoFontFamily** b)
+-{
+- return strcmp (pango_font_family_get_name (*a), pango_font_family_get_name (*b));
+-}
+-
+-GtkWidget *
+-make_families_menu ()
+-{
+- GtkWidget *combo;
+- int n_families;
+- PangoFontFamily **families;
+- GList *family_list = NULL;
+- int i;
+-
+- pango_context_list_families (context, &families, &n_families);
+- qsort (families, n_families, sizeof(char *), cmp_families);
+-
+- for (i=0; ientry), FALSE);
+-
+- gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (combo)->entry), pango_font_description_get_family(font_description));
+-
+- gtk_signal_connect (GTK_OBJECT (GTK_COMBO (combo)->entry), "changed",
+- GTK_SIGNAL_FUNC (set_family), NULL);
+-
+- g_list_free (family_list);
+-
+- return combo;
+-}
+-
+-
+-GtkWidget *
+-make_font_selector (void)
+-{
+- GtkWidget *hbox;
+- GtkWidget *util_hbox;
+- GtkWidget *label;
+- GtkWidget *option_menu;
+- GtkWidget *spin_button;
+- GtkAdjustment *adj;
+-
+- hbox = gtk_hbox_new (FALSE, 4);
+-
+- util_hbox = gtk_hbox_new (FALSE, 2);
+- label = gtk_label_new ("Family:");
+- gtk_box_pack_start (GTK_BOX (util_hbox), label, FALSE, FALSE, 0);
+- option_menu = make_families_menu ();
+- gtk_box_pack_start (GTK_BOX (util_hbox), option_menu, FALSE, FALSE, 0);
+-
+- gtk_box_pack_start (GTK_BOX (hbox), util_hbox, FALSE, FALSE, 0);
+-
+- util_hbox = gtk_hbox_new (FALSE, 2);
+- label = gtk_label_new ("Style:");
+- gtk_box_pack_start (GTK_BOX (util_hbox), label, FALSE, FALSE, 0);
+- option_menu = make_styles_combo ();
+- gtk_box_pack_start (GTK_BOX (util_hbox), option_menu, FALSE, FALSE, 0);
+-
+- gtk_box_pack_start (GTK_BOX (hbox), util_hbox, FALSE, FALSE, 0);
+-
+- util_hbox = gtk_hbox_new (FALSE, 2);
+- label = gtk_label_new ("Size:");
+- gtk_box_pack_start (GTK_BOX (util_hbox), label, FALSE, FALSE, 0);
+- spin_button = gtk_spin_button_new (NULL, 1., 0);
+- gtk_box_pack_start (GTK_BOX (util_hbox), spin_button, FALSE, FALSE, 0);
+-
+- gtk_box_pack_start (GTK_BOX (hbox), util_hbox, FALSE, FALSE, 0);
+-
+- adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin_button));
+- adj->value = PANGO_PIXELS (pango_font_description_get_size(font_description));
+- adj->lower = 0;
+- adj->upper = 1024;
+- adj->step_increment = 1;
+- adj->page_size = 10;
+- gtk_adjustment_changed (adj);
+- gtk_adjustment_value_changed (adj);
+-
+- gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
+- GTK_SIGNAL_FUNC (font_size_changed), NULL);
+-
+- return hbox;
+-}
+-
+-int
+-main (int argc, char **argv)
+-{
+- char *text;
+- GtkWidget *window;
+- GtkWidget *scrollwin;
+- GtkWidget *vbox, *hbox;
+- GtkWidget *frame;
+- GtkWidget *checkbutton;
+-
+- gtk_init (&argc, &argv);
+-
+- if (argc != 2)
+- {
+- fprintf (stderr, "Usage: %s FILE\n", g_get_prgname ());
+- exit(1);
+- }
+-
+- /* Create the list of paragraphs from the supplied file
+- */
+- text = read_file (argv[1]);
+- if (!text)
+- exit(1);
+-
+- context = pango_win32_get_context ();
+-
+- paragraphs = split_paragraphs (text);
+-
+- pango_context_set_language (context, pango_language_from_string ("en_US"));
+- pango_context_set_base_dir (context, PANGO_DIRECTION_LTR);
+-
+- font_description = pango_font_description_new ();
+- pango_font_description_set_family(font_description, "sans");
+- pango_font_description_set_size(font_description, 16 * PANGO_SCALE);
+-#if 0 /* default init ok? */
+- font_description.style = PANGO_STYLE_NORMAL;
+- font_description.variant = PANGO_VARIANT_NORMAL;
+- font_description.weight = 500;
+- font_description.stretch = PANGO_STRETCH_NORMAL;
+-#endif
+-
+- pango_context_set_font_description (context, font_description);
+-
+- /* Create the user interface
+- */
+- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+- gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
+-
+- gtk_signal_connect (GTK_OBJECT (window), "destroy",
+- GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
+-
+- vbox = gtk_vbox_new (FALSE, 4);
+- gtk_container_add (GTK_CONTAINER (window), vbox);
+-
+- hbox = make_font_selector ();
+- gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+-
+- scrollwin = gtk_scrolled_window_new (NULL, NULL);
+- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollwin),
+- GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+-
+- gtk_box_pack_start (GTK_BOX (vbox), scrollwin, TRUE, TRUE, 0);
+-
+- layout = gtk_layout_new (NULL, NULL);
+- gtk_widget_set_events (layout, GDK_BUTTON_PRESS_MASK);
+- gtk_widget_set_app_paintable (layout, TRUE);
+-
+- gtk_signal_connect (GTK_OBJECT (layout), "size_allocate",
+- GTK_SIGNAL_FUNC (size_allocate), paragraphs);
+- gtk_signal_connect (GTK_OBJECT (layout), "expose_event",
+- GTK_SIGNAL_FUNC (expose), paragraphs);
+- gtk_signal_connect (GTK_OBJECT (layout), "draw",
+- GTK_SIGNAL_FUNC (draw), paragraphs);
+- gtk_signal_connect (GTK_OBJECT (layout), "button_press_event",
+- GTK_SIGNAL_FUNC (button_press), paragraphs);
+-#if GTK_CHECK_VERSION (1,3,2)
+- gtk_widget_set_double_buffered (layout, FALSE);
+-#endif
+- gtk_container_add (GTK_CONTAINER (scrollwin), layout);
+-
+- frame = gtk_frame_new (NULL);
+- gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+- gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+-
+- message_label = gtk_label_new ("Current char:");
+- gtk_misc_set_padding (GTK_MISC (message_label), 1, 1);
+- gtk_misc_set_alignment (GTK_MISC (message_label), 0.0, 0.5);
+- gtk_container_add (GTK_CONTAINER (frame), message_label);
+-
+- checkbutton = gtk_check_button_new_with_label ("Use RTL global direction");
+- gtk_signal_connect (GTK_OBJECT (checkbutton), "toggled",
+- GTK_SIGNAL_FUNC (checkbutton_toggled), NULL);
+- gtk_box_pack_start (GTK_BOX (vbox), checkbutton, FALSE, FALSE, 0);
+-
+- gtk_widget_show_all (window);
+-
+- gtk_main ();
+-
+- return 0;
+-}
+diff --git a/pango/glyphstring.c b/pango/glyphstring.c
+index 42601d5..8fb7031 100644
+--- a/pango/glyphstring.c
++++ b/pango/glyphstring.c
+@@ -61,14 +61,28 @@ pango_glyph_string_set_size (PangoGlyphString *string, gint new_len)
+ while (new_len > string->space)
+ {
+ if (string->space == 0)
+- string->space = 1;
++ {
++ string->space = 4;
++ }
+ else
+- string->space *= 2;
+-
+- if (string->space < 0)
+ {
+- g_warning ("glyph string length overflows maximum integer size, truncated");
+- new_len = string->space = G_MAXINT - 8;
++ const guint max_space =
++ MIN (G_MAXINT, G_MAXSIZE / MAX (sizeof(PangoGlyphInfo), sizeof(gint)));
++
++ guint more_space = (guint)string->space * 2;
++
++ if (more_space > max_space)
++ {
++ more_space = max_space;
++
++ if ((guint)new_len > max_space)
++ {
++ g_error ("%s: failed to allocate glyph string of length %i\n",
++ G_STRLOC, new_len);
++ }
++ }
++
++ string->space = more_space;
+ }
+ }
+
+diff --git a/pango/opentype/Makefile.am b/pango/opentype/Makefile.am
+index 5cf0f13..b845eb6 100644
+--- a/pango/opentype/Makefile.am
++++ b/pango/opentype/Makefile.am
+@@ -1,8 +1,8 @@
+ ## Process this file with automake to produce Makefile.in
+
+ INCLUDES = \
+- $(FREETYPE_CFLAGS) \
+- -I $(srcdir)
++ -I $(srcdir) \
++ $(FREETYPE_CFLAGS)
+
+ noinst_LTLIBRARIES = libharfbuzz-1.la
+
+diff --git a/pango/opentype/harfbuzz-gpos.c b/pango/opentype/harfbuzz-gpos.c
+index 2961940..c78dcba 100644
+--- a/pango/opentype/harfbuzz-gpos.c
++++ b/pango/opentype/harfbuzz-gpos.c
+@@ -2080,9 +2080,13 @@ static void Free_BaseArray( HB_BaseArray* ba,
+ if ( ba->BaseRecord )
+ {
+ br = ba->BaseRecord;
+- bans = br[0].BaseAnchor;
+
+- FREE( bans );
++ if ( ba->BaseCount )
++ {
++ bans = br[0].BaseAnchor;
++ FREE( bans );
++ }
++
+ FREE( br );
+ }
+ }
+@@ -2811,9 +2815,13 @@ static void Free_Mark2Array( HB_Mark2Array* m2a,
+ if ( m2a->Mark2Record )
+ {
+ m2r = m2a->Mark2Record;
+- m2ans = m2r[0].Mark2Anchor;
+
+- FREE( m2ans );
++ if ( m2a->Mark2Count )
++ {
++ m2ans = m2r[0].Mark2Anchor;
++ FREE( m2ans );
++ }
++
+ FREE( m2r );
+ }
+ }
+@@ -3857,6 +3865,9 @@ static HB_Error Lookup_ContextPos2( GPOS_Instance* gpi,
+ if ( error )
+ return error;
+
++ if (cpf2->MaxContextLength < 1)
++ return HB_Err_Not_Covered;
++
+ if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, HB_UShort ) )
+ return error;
+
+@@ -5139,6 +5150,9 @@ static HB_Error Lookup_ChainContextPos2(
+ return error;
+ known_backtrack_classes = 0;
+
++ if (ccpf2->MaxInputLength < 1)
++ return HB_Err_Not_Covered;
++
+ if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, HB_UShort ) )
+ goto End3;
+ known_input_classes = 1;
+diff --git a/pango/opentype/harfbuzz-gsub.c b/pango/opentype/harfbuzz-gsub.c
+index f504bf0..c05f20d 100644
+--- a/pango/opentype/harfbuzz-gsub.c
++++ b/pango/opentype/harfbuzz-gsub.c
+@@ -1896,6 +1896,9 @@ static HB_Error Lookup_ContextSubst2( HB_GSUBHeader* gsub,
+ if ( error )
+ return error;
+
++ if (csf2->MaxContextLength < 1)
++ return HB_Err_Not_Covered;
++
+ if ( ALLOC_ARRAY( classes, csf2->MaxContextLength, HB_UShort ) )
+ return error;
+
+@@ -3159,6 +3162,9 @@ static HB_Error Lookup_ChainContextSubst2( HB_GSUBHeader* gsub,
+ return error;
+ known_backtrack_classes = 0;
+
++ if (ccsf2->MaxInputLength < 1)
++ return HB_Err_Not_Covered;
++
+ if ( ALLOC_ARRAY( input_classes, ccsf2->MaxInputLength, HB_UShort ) )
+ goto End3;
+ known_input_classes = 1;
+diff --git a/pango/opentype/harfbuzz-impl.c b/pango/opentype/harfbuzz-impl.c
+index a3a5589..ffcef80 100644
+--- a/pango/opentype/harfbuzz-impl.c
++++ b/pango/opentype/harfbuzz-impl.c
+@@ -30,7 +30,7 @@
+
+
+ HB_INTERNAL HB_Pointer
+-_hb_alloc( HB_UInt size,
++_hb_alloc( size_t size,
+ HB_Error *perror )
+ {
+ HB_Error error = 0;
+@@ -50,7 +50,7 @@ _hb_alloc( HB_UInt size,
+
+ HB_INTERNAL HB_Pointer
+ _hb_realloc( HB_Pointer block,
+- HB_UInt new_size,
++ size_t new_size,
+ HB_Error *perror )
+ {
+ HB_Pointer block2 = NULL;
+diff --git a/pango/opentype/harfbuzz-impl.h b/pango/opentype/harfbuzz-impl.h
+index 0442e4e..f886e67 100644
+--- a/pango/opentype/harfbuzz-impl.h
++++ b/pango/opentype/harfbuzz-impl.h
+@@ -32,6 +32,8 @@
+
+ #include "harfbuzz-global.h"
+
++#include
++
+ HB_BEGIN_HEADER
+
+ #ifndef HB_INTERNAL
+@@ -95,12 +97,12 @@ HB_BEGIN_HEADER
+
+
+ HB_INTERNAL HB_Pointer
+-_hb_alloc( HB_UInt size,
++_hb_alloc( size_t size,
+ HB_Error *perror_ );
+
+ HB_INTERNAL HB_Pointer
+ _hb_realloc( HB_Pointer block,
+- HB_UInt new_size,
++ size_t new_size,
+ HB_Error *perror_ );
+
+ HB_INTERNAL void
+diff --git a/pango/pango-coverage.c b/pango/pango-coverage.c
+index 73fb147..7637117 100644
+--- a/pango/pango-coverage.c
++++ b/pango/pango-coverage.c
+@@ -42,7 +42,6 @@ struct _PangoCoverage
+ {
+ guint ref_count;
+ int n_blocks;
+- int data_size;
+
+ PangoBlockInfo *blocks;
+ };
+@@ -145,7 +144,7 @@ pango_coverage_unref (PangoCoverage *coverage)
+ if (g_atomic_int_dec_and_test ((int *) &coverage->ref_count))
+ {
+ for (i=0; in_blocks; i++)
+- g_free (coverage->blocks[i].data);
++ g_slice_free1 (64, coverage->blocks[i].data);
+
+ g_free (coverage->blocks);
+ g_slice_free (PangoCoverage, coverage);
+@@ -236,7 +235,7 @@ pango_coverage_set (PangoCoverage *coverage,
+ if (level == coverage->blocks[block_index].level)
+ return;
+
+- data = g_new (guchar, 64);
++ data = g_slice_alloc (64);
+ coverage->blocks[block_index].data = data;
+
+ byte = coverage->blocks[block_index].level |
+@@ -393,15 +392,18 @@ pango_coverage_to_bytes (PangoCoverage *coverage,
+ guchar *data = coverage->blocks[i].data;
+ guchar first_val = data[0];
+
+- for (j = 1 ; j < 64; j++)
+- if (data[j] != first_val)
+- break;
+-
+- if (j == 64)
++ if (first_val == 0 || first_val == 0xff)
+ {
+- g_free (data);
+- coverage->blocks[i].data = NULL;
+- coverage->blocks[i].level = first_val & 0x3;
++ for (j = 1 ; j < 64; j++)
++ if (data[j] != first_val)
++ break;
++
++ if (j == 64)
++ {
++ g_slice_free1 (64, data);
++ coverage->blocks[i].data = NULL;
++ coverage->blocks[i].level = first_val & 0x3;
++ }
+ }
+ }
+
+diff --git a/pango/pango-language.c b/pango/pango-language.c
+index cae27ef..bfde308 100644
+--- a/pango/pango-language.c
++++ b/pango/pango-language.c
+@@ -688,7 +688,7 @@ pango_language_includes_script (PangoLanguage *language,
+ static PangoLanguage **
+ parse_default_languages (void)
+ {
+- char *p;
++ char *p, *p_copy;
+ gboolean done = FALSE;
+ GArray *langs;
+
+@@ -700,7 +700,7 @@ parse_default_languages (void)
+ if (p == NULL)
+ return NULL;
+
+- p = g_strdup (p);
++ p_copy = p = g_strdup (p);
+
+ langs = g_array_new (TRUE, FALSE, sizeof (PangoLanguage *));
+
+@@ -727,6 +727,8 @@ parse_default_languages (void)
+ p = end + 1;
+ }
+
++ g_free (p_copy);
++
+ return (PangoLanguage **) g_array_free (langs, FALSE);
+ }
+
+diff --git a/pango/pangocairo-fcfont.c b/pango/pangocairo-fcfont.c
+index 3039f9f..3ac166e 100644
+--- a/pango/pangocairo-fcfont.c
++++ b/pango/pangocairo-fcfont.c
+@@ -223,6 +223,7 @@ _pango_cairo_fc_font_new (PangoCairoFcFontMap *cffontmap,
+
+ cffont = g_object_new (PANGO_TYPE_CAIRO_FC_FONT,
+ "pattern", pattern,
++ "fontmap", cffontmap,
+ NULL);
+
+ size = get_font_size (pattern) /
+diff --git a/pango/pangofc-font.c b/pango/pangofc-font.c
+index 133a4df..976b0d8 100644
+--- a/pango/pangofc-font.c
++++ b/pango/pangofc-font.c
+@@ -34,22 +34,8 @@
+
+ enum {
+ PROP_0,
+- PROP_PATTERN
+-};
+-
+-typedef struct _GUnicharToGlyphCacheEntry GUnicharToGlyphCacheEntry;
+-
+-/* An entry in the fixed-size cache for the gunichar -> glyph mapping.
+- * The cache is indexed by the lower N bits of the gunichar (see
+- * GLYPH_CACHE_NUM_ENTRIES). For scripts with few code points,
+- * this should provide pretty much instant lookups.
+- *
+- * The "ch" field is zero if that cache entry is invalid.
+- */
+-struct _GUnicharToGlyphCacheEntry
+-{
+- gunichar ch;
+- PangoGlyph glyph;
++ PROP_PATTERN,
++ PROP_FONTMAP
+ };
+
+ typedef struct _PangoFcFontPrivate PangoFcFontPrivate;
+@@ -58,12 +44,9 @@ struct _PangoFcFontPrivate
+ {
+ PangoFcDecoder *decoder;
+ PangoFcFontKey *key;
+- GUnicharToGlyphCacheEntry *char_to_glyph_cache;
++ PangoFcCmapCache *cmap_cache;
+ };
+
+-#define GLYPH_CACHE_NUM_ENTRIES 256 /* should be power of two */
+-#define GLYPH_CACHE_MASK (GLYPH_CACHE_NUM_ENTRIES - 1)
+-
+ static gboolean pango_fc_font_real_has_char (PangoFcFont *font,
+ gunichar wc);
+ static guint pango_fc_font_real_get_glyph (PangoFcFont *font,
+@@ -121,6 +104,13 @@ pango_fc_font_class_init (PangoFcFontClass *class)
+ "The fontconfig pattern for this font",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
++ g_object_class_install_property (object_class, PROP_FONTMAP,
++ g_param_spec_object ("fontmap",
++ "Font Map",
++ "The PangoFc font map this font is associated with",
++ PANGO_TYPE_FC_FONT_MAP,
++ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
++ G_PARAM_STATIC_STRINGS));
+
+ g_type_class_add_private (object_class, sizeof (PangoFcFontPrivate));
+ }
+@@ -158,7 +148,8 @@ pango_fc_font_finalize (GObject *object)
+ if (priv->decoder)
+ _pango_fc_font_set_decoder (fcfont, NULL);
+
+- g_free (priv->char_to_glyph_cache);
++ if (priv->cmap_cache)
++ _pango_fc_cmap_cache_unref (priv->cmap_cache);
+
+ G_OBJECT_CLASS (pango_fc_font_parent_class)->finalize (object);
+ }
+@@ -203,11 +194,12 @@ pango_fc_font_set_property (GObject *object,
+ const GValue *value,
+ GParamSpec *pspec)
+ {
++ PangoFcFont *fcfont = PANGO_FC_FONT (object);
++
+ switch (prop_id)
+ {
+ case PROP_PATTERN:
+ {
+- PangoFcFont *fcfont = PANGO_FC_FONT (object);
+ FcPattern *pattern = g_value_get_pointer (value);
+
+ g_return_if_fail (pattern != NULL);
+@@ -219,11 +211,30 @@ pango_fc_font_set_property (GObject *object,
+ fcfont->is_hinted = pattern_is_hinted (pattern);
+ fcfont->is_transformed = pattern_is_transformed (pattern);
+ }
+- break;
++ goto set_decoder;
++
++ case PROP_FONTMAP:
++ {
++ PangoFcFontMap *fcfontmap = PANGO_FC_FONT_MAP (g_value_get_object (value));
++
++ g_return_if_fail (fcfont->fontmap == NULL);
++ fcfont->fontmap = (PangoFontMap *) fcfontmap;
++ if (fcfont->fontmap)
++ g_object_add_weak_pointer (G_OBJECT (fcfont->fontmap), (gpointer *) (gpointer) &fcfont->fontmap);
++ }
++ goto set_decoder;
++
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+- break;
++ return;
+ }
++
++set_decoder:
++ /* set decoder if both pattern and fontmap are set now */
++ if (fcfont->font_pattern && fcfont->fontmap)
++ _pango_fc_font_set_decoder (fcfont,
++ pango_fc_font_map_find_decoder ((PangoFcFontMap *) fcfont->fontmap,
++ fcfont->font_pattern));
+ }
+
+ static void
+@@ -240,6 +251,12 @@ pango_fc_font_get_property (GObject *object,
+ g_value_set_pointer (value, fcfont->font_pattern);
+ }
+ break;
++ case PROP_FONTMAP:
++ {
++ PangoFcFont *fcfont = PANGO_FC_FONT (object);
++ g_value_set_object (value, fcfont->fontmap);
++ }
++ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+@@ -585,23 +602,25 @@ static guint
+ pango_fc_font_real_get_glyph (PangoFcFont *font,
+ gunichar wc)
+ {
++ PangoFcFontPrivate *priv = font->priv;
+ FT_Face face;
+ FT_UInt index;
+
+ guint idx;
+- GUnicharToGlyphCacheEntry *entry;
++ PangoFcCmapCacheEntry *entry;
+
+- PangoFcFontPrivate *priv = font->priv;
+
+- if (G_UNLIKELY (priv->char_to_glyph_cache == NULL))
++ if (G_UNLIKELY (priv->cmap_cache == NULL))
+ {
+- priv->char_to_glyph_cache = g_new0 (GUnicharToGlyphCacheEntry, GLYPH_CACHE_NUM_ENTRIES);
+- /* Make sure all cache entries are invalid initially */
+- priv->char_to_glyph_cache[0].ch = 1; /* char 1 cannot happen in bucket 0 */
++ priv->cmap_cache = _pango_fc_font_map_get_cmap_cache ((PangoFcFontMap *) font->fontmap,
++ font);
++
++ if (G_UNLIKELY (!priv->cmap_cache))
++ return 0;
+ }
+
+- idx = wc & GLYPH_CACHE_MASK;
+- entry = priv->char_to_glyph_cache + idx;
++ idx = wc & CMAP_CACHE_MASK;
++ entry = priv->cmap_cache->entries + idx;
+
+ if (entry->ch != wc)
+ {
+diff --git a/pango/pangofc-fontmap.c b/pango/pangofc-fontmap.c
+index 491b912..28acdf7 100644
+--- a/pango/pangofc-fontmap.c
++++ b/pango/pangofc-fontmap.c
+@@ -19,7 +19,7 @@
+ * Boston, MA 02111-1307, USA.
+ */
+
+-#define FONTSET_CACHE_SIZE 64
++#define FONTSET_CACHE_SIZE 256
+
+ #include "config.h"
+ #include
+@@ -31,7 +31,7 @@
+ #include "modules.h"
+ #include "pango-enum-types.h"
+
+-typedef struct _PangoFcCoverageKey PangoFcCoverageKey;
++typedef struct _PangoFcFontFaceData PangoFcFontFaceData;
+ typedef struct _PangoFcFace PangoFcFace;
+ typedef struct _PangoFcFamily PangoFcFamily;
+ typedef struct _PangoFcFindFuncInfo PangoFcFindFuncInfo;
+@@ -64,7 +64,7 @@ struct _PangoFcFontMapPrivate
+ */
+ GHashTable *pattern_hash;
+
+- GHashTable *coverage_hash; /* Maps font file name/id -> PangoCoverage */
++ GHashTable *font_face_data_hash; /* Maps font file name/id -> data */
+
+ /* List of all families availible */
+ PangoFcFamily **families;
+@@ -78,10 +78,16 @@ struct _PangoFcFontMapPrivate
+ guint closed : 1;
+ };
+
+-struct _PangoFcCoverageKey
++struct _PangoFcFontFaceData
+ {
++ /* Key */
+ char *filename;
+ int id; /* needed to handle TTC files with multiple faces */
++
++ /* Data */
++ FcPattern *pattern; /* Referenced pattern that owns filename */
++ PangoCoverage *coverage;
++ PangoFcCmapCache *cmap_cache;
+ };
+
+ struct _PangoFcFace
+@@ -137,9 +143,9 @@ static PangoFont *pango_fc_font_map_new_font (PangoFcFontMap *fontmap,
+ PangoFcFontsetKey *fontset_key,
+ FcPattern *match);
+
+-static guint pango_fc_coverage_key_hash (PangoFcCoverageKey *key);
+-static gboolean pango_fc_coverage_key_equal (PangoFcCoverageKey *key1,
+- PangoFcCoverageKey *key2);
++static guint pango_fc_font_face_data_hash (PangoFcFontFaceData *key);
++static gboolean pango_fc_font_face_data_equal (PangoFcFontFaceData *key1,
++ PangoFcFontFaceData *key2);
+
+ static void pango_fc_fontset_key_init (PangoFcFontsetKey *key,
+ PangoFcFontMap *fcfontmap,
+@@ -184,16 +190,31 @@ get_gravity_class (void)
+ }
+
+ static guint
+-pango_fc_coverage_key_hash (PangoFcCoverageKey *key)
++pango_fc_font_face_data_hash (PangoFcFontFaceData *key)
+ {
+ return g_str_hash (key->filename) ^ key->id;
+ }
+
+ static gboolean
+-pango_fc_coverage_key_equal (PangoFcCoverageKey *key1,
+- PangoFcCoverageKey *key2)
++pango_fc_font_face_data_equal (PangoFcFontFaceData *key1,
++ PangoFcFontFaceData *key2)
++{
++ return key1->id == key2->id &&
++ (key1 == key2 || 0 == strcmp (key1->filename, key2->filename));
++}
++
++static void
++pango_fc_font_face_data_free (PangoFcFontFaceData *data)
+ {
+- return key1->id == key2->id && strcmp (key1->filename, key2->filename) == 0;
++ FcPatternDestroy (data->pattern);
++
++ if (data->coverage)
++ pango_coverage_unref (data->coverage);
++
++ if (data->cmap_cache)
++ _pango_fc_cmap_cache_unref (data->cmap_cache);
++
++ g_slice_free (PangoFcFontFaceData, data);
+ }
+
+ /* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
+@@ -839,7 +860,11 @@ pango_fc_fontset_finalize (GObject *object)
+ unsigned int i;
+
+ for (i = 0; i < fontset->fonts->len; i++)
+- g_object_unref (g_ptr_array_index(fontset->fonts, i));
++ {
++ PangoFont *font = g_ptr_array_index(fontset->fonts, i);
++ if (font)
++ g_object_unref (font);
++ }
+ g_ptr_array_free (fontset->fonts, TRUE);
+
+ for (i = 0; i < fontset->coverages->len; i++)
+@@ -977,10 +1002,10 @@ pango_fc_font_map_init (PangoFcFontMap *fcfontmap)
+ (GDestroyNotify) FcPatternDestroy,
+ NULL);
+
+- priv->coverage_hash = g_hash_table_new_full ((GHashFunc)pango_fc_coverage_key_hash,
+- (GEqualFunc)pango_fc_coverage_key_equal,
+- (GDestroyNotify)g_free,
+- (GDestroyNotify)pango_coverage_unref);
++ priv->font_face_data_hash = g_hash_table_new_full ((GHashFunc)pango_fc_font_face_data_hash,
++ (GEqualFunc)pango_fc_font_face_data_equal,
++ (GDestroyNotify)pango_fc_font_face_data_free,
++ NULL);
+ priv->dpi = -1;
+ }
+
+@@ -1002,8 +1027,8 @@ pango_fc_font_map_fini (PangoFcFontMap *fcfontmap)
+ g_hash_table_destroy (priv->font_hash);
+ priv->font_hash = NULL;
+
+- g_hash_table_destroy (priv->coverage_hash);
+- priv->coverage_hash = NULL;
++ g_hash_table_destroy (priv->font_face_data_hash);
++ priv->font_face_data_hash = NULL;
+
+ g_hash_table_destroy (priv->pattern_hash);
+ priv->pattern_hash = NULL;
+@@ -1054,9 +1079,13 @@ pango_fc_font_map_add_decoder_find_func (PangoFcFontMap *fcfontmap,
+ gpointer user_data,
+ GDestroyNotify dnotify)
+ {
+- PangoFcFontMapPrivate *priv = fcfontmap->priv;
++ PangoFcFontMapPrivate *priv;
+ PangoFcFindFuncInfo *info;
+
++ g_return_if_fail (PANGO_IS_FC_FONT_MAP (fcfontmap));
++
++ priv = fcfontmap->priv;
++
+ info = g_slice_new (PangoFcFindFuncInfo);
+
+ info->findfunc = findfunc;
+@@ -1066,6 +1095,41 @@ pango_fc_font_map_add_decoder_find_func (PangoFcFontMap *fcfontmap,
+ priv->findfuncs = g_slist_append (priv->findfuncs, info);
+ }
+
++/**
++ * pango_fc_font_map_find_decoder:
++ * @fcfontmap: The #PangoFcFontMap to use.
++ * @pattern: The #FcPattern to find the decoder for.
++ *
++ * Finds the decoder to use for @pattern. Decoders can be added to
++ * a font map using pango_fc_font_map_add_decoder_find_func().
++ *
++ * Returns: a newly created #PangoFcDecoder object or %NULL if
++ * no decoder is set for @pattern.
++ *
++ * Since: 1.24.
++ **/
++PangoFcDecoder *
++pango_fc_font_map_find_decoder (PangoFcFontMap *fcfontmap,
++ FcPattern *pattern)
++{
++ GSList *l;
++
++ g_return_val_if_fail (PANGO_IS_FC_FONT_MAP (fcfontmap), NULL);
++ g_return_val_if_fail (pattern != NULL, NULL);
++
++ for (l = fcfontmap->priv->findfuncs; l && l->data; l = l->next)
++ {
++ PangoFcFindFuncInfo *info = l->data;
++ PangoFcDecoder *decoder;
++
++ decoder = info->findfunc (pattern, info->user_data);
++ if (decoder)
++ return decoder;
++ }
++
++ return NULL;
++}
++
+ static void
+ pango_fc_font_map_finalize (GObject *object)
+ {
+@@ -1085,13 +1149,6 @@ pango_fc_font_map_add (PangoFcFontMap *fcfontmap,
+ PangoFcFontMapPrivate *priv = fcfontmap->priv;
+ PangoFcFontKey *key_copy;
+
+- g_assert (fcfont->fontmap == NULL);
+- fcfont->fontmap = (PangoFontMap *) fcfontmap;
+- /* In other fontmaps we add a weak pointer on ->fontmap so the
+- * field is unset when fontmap is finalized. We don't need it
+- * here though as PangoFcFontMap already cleans up fcfont->fontmap
+- * as part of it's caching scheme. */
+-
+ key_copy = pango_fc_font_key_copy (key);
+ _pango_fc_font_set_font_key (fcfont, key_copy);
+ g_hash_table_insert (priv->font_hash, key_copy, fcfont);
+@@ -1105,8 +1162,6 @@ _pango_fc_font_map_remove (PangoFcFontMap *fcfontmap,
+ PangoFcFontMapPrivate *priv = fcfontmap->priv;
+ PangoFcFontKey *key;
+
+- fcfont->fontmap = NULL;
+-
+ key = _pango_fc_font_get_font_key (fcfont);
+ if (key)
+ {
+@@ -1407,7 +1462,6 @@ pango_fc_font_map_new_font (PangoFcFontMap *fcfontmap,
+ PangoFcFontMapPrivate *priv = fcfontmap->priv;
+ FcPattern *pattern;
+ PangoFcFont *fcfont;
+- GSList *l;
+ PangoFcFontKey key;
+
+ if (priv->closed)
+@@ -1458,25 +1512,9 @@ pango_fc_font_map_new_font (PangoFcFontMap *fcfontmap,
+
+ fcfont->matrix = key.matrix;
+
++ /* cache it on fontmap */
+ pango_fc_font_map_add (fcfontmap, &key, fcfont);
+
+- /*
+- * Give any custom decoders a crack at this font now that it's been
+- * created.
+- */
+- for (l = priv->findfuncs; l && l->data; l = l->next)
+- {
+- PangoFcFindFuncInfo *info = l->data;
+- PangoFcDecoder *decoder;
+-
+- decoder = info->findfunc (match, info->user_data);
+- if (decoder)
+- {
+- _pango_fc_font_set_decoder (fcfont, decoder);
+- break;
+- }
+- }
+-
+ return (PangoFont *)fcfont;
+ }
+
+@@ -1682,21 +1720,85 @@ pango_fc_font_map_cache_clear (PangoFcFontMap *fcfontmap)
+ pango_fc_font_map_init (fcfontmap);
+ }
+
+-static void
+-pango_fc_font_map_set_coverage (PangoFcFontMap *fcfontmap,
+- PangoFcCoverageKey *key,
+- PangoCoverage *coverage)
++static PangoFcFontFaceData *
++pango_fc_font_map_get_font_face_data (PangoFcFontMap *fcfontmap,
++ FcPattern *font_pattern)
+ {
+ PangoFcFontMapPrivate *priv = fcfontmap->priv;
+- PangoFcCoverageKey *key_dup;
++ PangoFcFontFaceData key;
++ PangoFcFontFaceData *data;
+
+- key_dup = g_malloc (sizeof (PangoFcCoverageKey) + strlen (key->filename) + 1);
+- key_dup->id = key->id;
+- key_dup->filename = (char *) (key_dup + 1);
+- strcpy (key_dup->filename, key->filename);
++ if (FcPatternGetString (font_pattern, FC_FILE, 0, (FcChar8 **)(void*)&key.filename) != FcResultMatch)
++ return NULL;
++
++ if (FcPatternGetInteger (font_pattern, FC_INDEX, 0, &key.id) != FcResultMatch)
++ return NULL;
++
++ data = g_hash_table_lookup (priv->font_face_data_hash, &key);
++ if (G_LIKELY (data))
++ return data;
++
++ data = g_slice_new0 (PangoFcFontFaceData);
++ data->filename = key.filename;
++ data->id = key.id;
++
++ data->pattern = font_pattern;
++ FcPatternReference (data->pattern);
++
++ g_hash_table_insert (priv->font_face_data_hash, data, data);
++
++ return data;
++}
++
++PangoFcCmapCache *
++_pango_fc_cmap_cache_ref (PangoFcCmapCache *cmap_cache)
++{
++ g_atomic_int_inc ((int *) &cmap_cache->ref_count);
++
++ return cmap_cache;
++}
++
++void
++_pango_fc_cmap_cache_unref (PangoFcCmapCache *cmap_cache)
++{
++ g_return_if_fail (cmap_cache->ref_count > 0);
++
++ if (g_atomic_int_dec_and_test ((int *) &cmap_cache->ref_count))
++ {
++ g_free (cmap_cache);
++ }
++}
++
++PangoFcCmapCache *
++_pango_fc_font_map_get_cmap_cache (PangoFcFontMap *fcfontmap,
++ PangoFcFont *fcfont)
++{
++ PangoFcFontMapPrivate *priv;
++ PangoFcFontFaceData *data;
++ PangoFcCmapCache *cmap_cache;
++
++ if (G_UNLIKELY (fcfontmap == NULL))
++ return NULL;
++
++ if (G_UNLIKELY (!fcfont->font_pattern))
++ return NULL;
++
++ priv = fcfontmap->priv;
++
++ data = pango_fc_font_map_get_font_face_data (fcfontmap, fcfont->font_pattern);
++ if (G_UNLIKELY (!data))
++ return NULL;
++
++ if (G_UNLIKELY (data->cmap_cache == NULL))
++ {
++ data->cmap_cache = g_new0 (PangoFcCmapCache, 1);
++ data->cmap_cache->ref_count = 1;
+
+- g_hash_table_insert (priv->coverage_hash,
+- key_dup, pango_coverage_ref (coverage));
++ /* Make sure all cache entries are invalid initially */
++ data->cmap_cache->entries[0].ch = 1; /* char 1 cannot happen in bucket 0 */
++ }
++
++ return _pango_fc_cmap_cache_ref (data->cmap_cache);
+ }
+
+ PangoCoverage *
+@@ -1704,37 +1806,30 @@ _pango_fc_font_map_get_coverage (PangoFcFontMap *fcfontmap,
+ PangoFcFont *fcfont)
+ {
+ PangoFcFontMapPrivate *priv = fcfontmap->priv;
+- PangoFcCoverageKey key;
++ PangoFcFontFaceData *data;
+ PangoCoverage *coverage;
+ FcCharSet *charset;
+
+- /*
+- * Assume that coverage information is identified by
+- * a filename/index pair; there shouldn't be any reason
+- * this isn't true, but it's not specified anywhere
+- */
+- if (FcPatternGetString (fcfont->font_pattern, FC_FILE, 0, (FcChar8 **)(void*)&key.filename) != FcResultMatch)
+- return NULL;
+-
+- if (FcPatternGetInteger (fcfont->font_pattern, FC_INDEX, 0, &key.id) != FcResultMatch)
++ if (G_UNLIKELY (!fcfont->font_pattern))
+ return NULL;
+
+- coverage = g_hash_table_lookup (priv->coverage_hash, &key);
+- if (G_LIKELY (coverage))
+- return pango_coverage_ref (coverage);
+-
+- /*
+- * Pull the coverage out of the pattern, this
+- * doesn't require loading the font
+- */
+- if (FcPatternGetCharSet (fcfont->font_pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
++ data = pango_fc_font_map_get_font_face_data (fcfontmap, fcfont->font_pattern);
++ if (G_UNLIKELY (!data))
+ return NULL;
+
+- coverage = _pango_fc_font_map_fc_to_coverage (charset);
++ if (G_UNLIKELY (data->coverage == NULL))
++ {
++ /*
++ * Pull the coverage out of the pattern, this
++ * doesn't require loading the font
++ */
++ if (FcPatternGetCharSet (fcfont->font_pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
++ return NULL;
+
+- pango_fc_font_map_set_coverage (fcfontmap, &key, coverage);
++ data->coverage = _pango_fc_font_map_fc_to_coverage (charset);
++ }
+
+- return coverage;
++ return pango_coverage_ref (data->coverage);
+ }
+
+ /**
+@@ -1821,9 +1916,15 @@ pango_fc_font_map_create_context (PangoFcFontMap *fcfontmap)
+
+ static void
+ shutdown_font (gpointer key G_GNUC_UNUSED,
+- PangoFcFont *fcfont)
++ PangoFcFont *fcfont,
++ PangoFcFontMap *fcfontmap)
+ {
+ _pango_fc_font_shutdown (fcfont);
++
++ /* While _pango_fc_font_shutdown() tries to call the following
++ * function, it's too late as the fontmap weakref has already
++ * NULL'ed fcfont->fontmap, so we do it ourselves. */
++ _pango_fc_font_map_remove (fcfontmap, fcfont);
+ }
+
+ /**
+@@ -1848,7 +1949,7 @@ pango_fc_font_map_shutdown (PangoFcFontMap *fcfontmap)
+ if (priv->closed)
+ return;
+
+- g_hash_table_foreach (priv->font_hash, (GHFunc) shutdown_font, NULL);
++ g_hash_table_foreach (priv->font_hash, (GHFunc) shutdown_font, fcfontmap);
+ for (i = 0; i < priv->n_families; i++)
+ priv->families[i]->fontmap = NULL;
+
+diff --git a/pango/pangofc-fontmap.h b/pango/pangofc-fontmap.h
+index d3f113a..8d496eb 100644
+--- a/pango/pangofc-fontmap.h
++++ b/pango/pangofc-fontmap.h
+@@ -213,6 +213,8 @@ void pango_fc_font_map_add_decoder_find_func (PangoFcFontMap *fcfontmap,
+ PangoFcDecoderFindFunc findfunc,
+ gpointer user_data,
+ GDestroyNotify dnotify);
++PangoFcDecoder *pango_fc_font_map_find_decoder (PangoFcFontMap *fcfontmap,
++ FcPattern *pattern);
+
+ PangoFontDescription *pango_fc_font_description_from_pattern (FcPattern *pattern,
+ gboolean include_size);
+diff --git a/pango/pangofc-private.h b/pango/pangofc-private.h
+index bc67ffb..0612a69 100644
+--- a/pango/pangofc-private.h
++++ b/pango/pangofc-private.h
+@@ -27,6 +27,7 @@
+
+ G_BEGIN_DECLS
+
++
+ typedef struct _PangoFcMetricsInfo PangoFcMetricsInfo;
+
+ struct _PangoFcMetricsInfo
+@@ -35,6 +36,26 @@ struct _PangoFcMetricsInfo
+ PangoFontMetrics *metrics;
+ };
+
++
++typedef struct _PangoFcCmapCacheEntry PangoFcCmapCacheEntry;
++typedef struct _PangoFcCmapCache PangoFcCmapCache;
++
++#define CMAP_CACHE_NUM_ENTRIES 256 /* should be power of two */
++#define CMAP_CACHE_MASK (CMAP_CACHE_NUM_ENTRIES - 1)
++
++struct _PangoFcCmapCacheEntry
++{
++ gunichar ch;
++ PangoGlyph glyph;
++};
++
++struct _PangoFcCmapCache
++{
++ guint ref_count;
++ PangoFcCmapCacheEntry entries[CMAP_CACHE_NUM_ENTRIES];
++};
++
++
+ #define PANGO_SCALE_26_6 (PANGO_SCALE / (1<<6))
+ #define PANGO_PIXELS_26_6(d) \
+ (((d) >= 0) ? \
+@@ -46,10 +67,15 @@ void _pango_fc_font_shutdown (PangoFcFont *fcfont);
+
+ void _pango_fc_font_map_remove (PangoFcFontMap *fcfontmap,
+ PangoFcFont *fcfont);
++
+ PangoCoverage *_pango_fc_font_map_get_coverage (PangoFcFontMap *fcfontmap,
+ PangoFcFont *fcfont);
+ PangoCoverage *_pango_fc_font_map_fc_to_coverage (FcCharSet *charset);
+
++PangoFcCmapCache *_pango_fc_font_map_get_cmap_cache (PangoFcFontMap *fcfontmap,
++ PangoFcFont *fcfont);
++void _pango_fc_cmap_cache_unref (PangoFcCmapCache *cmap_cache);
++
+ PangoFcDecoder *_pango_fc_font_get_decoder (PangoFcFont *font);
+ void _pango_fc_font_set_decoder (PangoFcFont *font,
+ PangoFcDecoder *decoder);
+diff --git a/pango/pangoft2.c b/pango/pangoft2.c
+index d13dc69..224f6a0 100644
+--- a/pango/pangoft2.c
++++ b/pango/pangoft2.c
+@@ -73,6 +73,7 @@ _pango_ft2_font_new (PangoFT2FontMap *ft2fontmap,
+
+ ft2font = (PangoFT2Font *)g_object_new (PANGO_TYPE_FT2_FONT,
+ "pattern", pattern,
++ "fontmap", fontmap,
+ NULL);
+
+ if (FcPatternGetDouble (pattern, FC_PIXEL_SIZE, 0, &d) == FcResultMatch)
+diff --git a/pango/pangoft2.def b/pango/pangoft2.def
+index f22d4ec..4cfa0d1 100644
+--- a/pango/pangoft2.def
++++ b/pango/pangoft2.def
+@@ -17,9 +17,16 @@ EXPORTS
+ pango_fc_font_map_add_decoder_find_func
+ pango_fc_font_map_cache_clear
+ pango_fc_font_map_create_context
++ pango_fc_font_map_find_decoder
+ pango_fc_font_map_get_type
+ pango_fc_font_map_shutdown
+ pango_fc_font_unlock_face
++ pango_fc_fontset_key_get_absolute_size
++ pango_fc_fontset_key_get_context_key
++ pango_fc_fontset_key_get_description
++ pango_fc_fontset_key_get_language
++ pango_fc_fontset_key_get_matrix
++ pango_fc_fontset_key_get_resolution
+ pango_ft2_font_get_coverage
+ pango_ft2_font_get_face
+ pango_ft2_font_get_kerning
+diff --git a/pango/pangowin32-fontmap.c b/pango/pangowin32-fontmap.c
+index 28e0ebd..833219a 100644
+--- a/pango/pangowin32-fontmap.c
++++ b/pango/pangowin32-fontmap.c
+@@ -1069,63 +1069,9 @@ pango_win32_font_description_from_logfontw (const LOGFONTW *lfp)
+ gchar *family;
+ PangoStyle style;
+ PangoVariant variant;
+- PangoWeight weight, name_weight;
++ PangoWeight weight;
+ PangoStretch stretch;
+
+- static const struct {
+- const char *marker;
+- int marker_len;
+- int remove_len;
+- PangoWeight weight;
+- } weight_names[] = {
+-#define ENTRY(n, s) ENTRY2 (n, sizeof (#n) - 1, s)
+-#define ENTRY2(n, l, s) ENTRY3 (n, l, l, s)
+-#define ENTRY3(n, marker_len, remove_len, s) { #n, marker_len, remove_len, PANGO_WEIGHT_##s }
+- ENTRY (Ultra Light, ULTRALIGHT),
+- ENTRY (UltraLight, ULTRALIGHT),
+- ENTRY (Light, LIGHT),
+- ENTRY (Medium, NORMAL),
+- ENTRY (Demi Bold, SEMIBOLD),
+- ENTRY (Demi, SEMIBOLD),
+- ENTRY (Ultra Bold, ULTRABOLD),
+- ENTRY (Extra Bold, ULTRABOLD),
+- ENTRY (SemiBold, SEMIBOLD),
+- ENTRY (DemiBold, SEMIBOLD),
+- ENTRY (UltraBold, ULTRABOLD),
+- ENTRY (ExtraBold, ULTRABOLD),
+- ENTRY (Bold, BOLD),
+- ENTRY (Heavy, HEAVY),
+- ENTRY (Black, HEAVY),
+-#undef ENTRY
+-#undef ENTRY2
+-#undef ENTRY3
+- };
+-
+- static const struct {
+- const char *marker;
+- int marker_len;
+- PangoStretch stretch;
+- } stretch_names[] = {
+-#define ENTRY(n, s) { #n, sizeof (#n) - 1, PANGO_STRETCH_##s }
+- ENTRY (Ext Condensed, EXTRA_CONDENSED),
+- ENTRY (Extra Condensed, EXTRA_CONDENSED),
+- ENTRY (UltraCondensed, ULTRA_CONDENSED),
+- ENTRY (ExtraCondensed, EXTRA_CONDENSED),
+- ENTRY (Condensed, CONDENSED),
+- ENTRY (Cond, CONDENSED),
+- ENTRY (Narrow, CONDENSED),
+- ENTRY (Ext Expanded, EXTRA_EXPANDED),
+- ENTRY (Extra Expanded, EXTRA_EXPANDED),
+- ENTRY (Ultra Expanded, ULTRA_EXPANDED),
+- ENTRY (ExtraExpanded, EXTRA_EXPANDED),
+- ENTRY (UltraExpanded, ULTRA_EXPANDED),
+- ENTRY (Expanded, EXPANDED),
+-#undef ENTRY
+- };
+-
+- int i;
+- char *p;
+-
+ family = get_family_nameW (lfp);
+
+ if ((lfp->lfPitchAndFamily & 0xF0) == FF_ROMAN && lfp->lfItalic)
+@@ -1158,51 +1104,9 @@ pango_win32_font_description_from_logfontw (const LOGFONTW *lfp)
+ else
+ weight = PANGO_WEIGHT_HEAVY;
+
+- name_weight = 0;
+-
+- p = family;
+- while ((p = strchr (p, ' ')) != NULL)
+- {
+- for (i = 0; i < G_N_ELEMENTS (weight_names); i++)
+- {
+- if (g_ascii_strncasecmp (p + 1, weight_names[i].marker, weight_names[i].marker_len) == 0 &&
+- (p[1 + weight_names[i].marker_len] == '\0' ||
+- p[1 + weight_names[i].marker_len] == ' '))
+- {
+- strcpy (p, p + 1 + weight_names[i].remove_len);
+- name_weight = weight_names[i].weight;
+- break;
+- }
+- }
+- if (i < G_N_ELEMENTS (weight_names))
+- break;
+- p++;
+- }
+-
+- if (weight == PANGO_WEIGHT_NORMAL && name_weight > 0)
+- weight = name_weight;
+-
++ /* XXX No idea how to figure out the stretch */
+ stretch = PANGO_STRETCH_NORMAL;
+
+- p = family;
+- while ((p = strchr (p, ' ')) != NULL)
+- {
+- for (i = 0; i < G_N_ELEMENTS (stretch_names); i++)
+- {
+- if (g_ascii_strncasecmp (p + 1, stretch_names[i].marker, stretch_names[i].marker_len) == 0 &&
+- (p[1 + stretch_names[i].marker_len] == '\0' ||
+- p[1 + stretch_names[i].marker_len] == ' '))
+- {
+- strcpy (p, p + 1 + stretch_names[i].marker_len);
+- stretch = stretch_names[i].stretch;
+- break;
+- }
+- }
+- if (i < G_N_ELEMENTS (stretch_names))
+- break;
+- p++;
+- }
+-
+ description = pango_font_description_new ();
+ pango_font_description_set_family (description, family);
+ g_free(family);
+diff --git a/pango/pangoxft-font.c b/pango/pangoxft-font.c
+index ce633f7..6865490 100644
+--- a/pango/pangoxft-font.c
++++ b/pango/pangoxft-font.c
+@@ -92,6 +92,7 @@ _pango_xft_font_new (PangoXftFontMap *xftfontmap,
+
+ xfont = (PangoXftFont *)g_object_new (PANGO_TYPE_XFT_FONT,
+ "pattern", pattern,
++ "fontmap", fontmap,
+ NULL);
+
+ /* Hack to force hinting of vertical metrics; hinting off for
+diff --git a/tests/gen-all-unicode.c b/tests/gen-all-unicode.c
+index 90ff4db..4139f23 100644
+--- a/tests/gen-all-unicode.c
++++ b/tests/gen-all-unicode.c
+@@ -2,7 +2,8 @@
+ #include
+
+ int
+-main (int argc, char **argv)
++main (int argc G_GNUC_UNUSED,
++ char **argv G_GNUC_UNUSED)
+ {
+ gunichar i;
+ gint j;
diff --git a/pango.spec b/pango.spec
index 0ab45ed..d85fd5b 100644
--- a/pango.spec
+++ b/pango.spec
@@ -9,7 +9,7 @@
Summary: System for layout and rendering of internationalized text
Name: pango
Version: 1.23.0
-Release: 3%{?dist}
+Release: 4.g5317893%{?dist}
License: LGPLv2+
Group: System Environment/Libraries
Source: http://download.gnome.org/sources/pango/1.23/pango-%{version}.tar.bz2
@@ -39,6 +39,8 @@ BuildRequires: gtk-doc
# Look for pango.modules in an arch-specific directory
Patch0: pango-1.21.4-lib64.patch
+Patch1: pango-1.23.0-g5317893.patch
+
%description
Pango is a library for laying out and rendering of text, with an emphasis
on internationalization. Pango can be used anywhere that text layout is needed,
@@ -75,6 +77,8 @@ for the pango package.
%patch0 -p1 -b .lib64
+%patch0 -p1 -b .git
+
%build
%configure --enable-gtk-doc --enable-doc-cross-references --with-included-modules=basic-fc
@@ -224,6 +228,9 @@ fi
%changelog
+* Wed Mar 11 2009 Behdad Esfahbod - 1.23.0-4.g5317893
+- Push changes from git
+
* Thu Feb 26 2009 Fedora Release Engineering - 1.23.0-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild