summaryrefslogtreecommitdiff
path: root/pango/pangox.c
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@redhat.com>2000-04-05 00:31:59 +0000
committerOwen Taylor <otaylor@src.gnome.org>2000-04-05 00:31:59 +0000
commit613302136667231bcefd772b419369516eb3bf45 (patch)
tree919ed907f3ca69f79210d0778c65df8bec97d4d0 /pango/pangox.c
parent52f2e805bf993f711d09ba6fe4972c7f7ee33eae (diff)
downloadpango-613302136667231bcefd772b419369516eb3bf45.tar.gz
Add user data to PangoContext
Tue Apr 4 20:13:06 2000 Owen Taylor <otaylor@redhat.com> * pango/pango-context.h: Add user data to PangoContext * pango/pangox.[ch] examples/viewer.c: Rework system for create GC's so that the necessary information is stored on the PangoContext instead of being passed to layout_render() * pango/utils.[ch] pango/pango-context.c: fribidi-0.1.9 wants UCS-4 not UCS2; switch accordingly. * pango/fonts.c pango/pango-font.h pango/pangox.c: Add functions to get overall font metrics, possibly per-language. (Right now, just font ascent, descent.) The implementation of this for X is horribly complex.
Diffstat (limited to 'pango/pangox.c')
-rw-r--r--pango/pangox.c377
1 files changed, 338 insertions, 39 deletions
diff --git a/pango/pangox.c b/pango/pangox.c
index 64721c4c..1cfcd004 100644
--- a/pango/pangox.c
+++ b/pango/pangox.c
@@ -20,8 +20,11 @@
*/
#include <X11/Xlib.h>
+#include <fribidi/fribidi.h>
+#include <unicode.h>
#include "modules.h"
#include "pangox.h"
+#include "utils.h"
#include <ctype.h>
#include <math.h>
#include <stdio.h>
@@ -36,9 +39,12 @@ typedef struct _PangoXFontMap PangoXFontMap;
typedef struct _PangoXSubfontInfo PangoXSubfontInfo;
typedef struct _PangoXSizeInfo PangoXSizeInfo;
+typedef struct _PangoXMetricsInfo PangoXMetricsInfo;
typedef struct _PangoXFamilyEntry PangoXFamilyEntry;
typedef struct _PangoXFontEntry PangoXFontEntry;
+typedef struct _PangoXContextInfo PangoXContextInfo;
+
struct _PangoXSizeInfo
{
char *identifier;
@@ -66,6 +72,12 @@ struct _PangoXSubfontInfo
XFontStruct *font_struct;
};
+struct _PangoXMetricsInfo
+{
+ const char *lang;
+ PangoFontMetrics metrics;
+};
+
struct _PangoXFont
{
PangoFont font;
@@ -85,6 +97,8 @@ struct _PangoXFont
int n_subfonts;
int max_subfonts;
+ GSList *metrics_by_lang;
+
PangoXFontEntry *entry; /* Used to remove cached fonts */
};
@@ -102,6 +116,12 @@ struct _PangoXFontMap
double resolution; /* (points / pixel) * PANGO_SCALE */
};
+struct _PangoXContextInfo
+{
+ PangoGetGCFunc get_gc_func;
+ PangoFreeGCFunc free_gc_func;
+};
+
/* This is the largest field length we will accept. If a fontname has a field
larger than this we will skip it. */
#define XLFD_MAX_FIELD_LEN 64
@@ -174,17 +194,20 @@ static void pango_x_font_map_list_families (PangoFontMap *
int *n_families);
static void pango_x_font_map_read_aliases (PangoXFontMap *xfontmap);
-static void pango_x_font_destroy (PangoFont *font);
-static PangoFontDescription *pango_x_font_describe (PangoFont *font);
-static PangoCoverage * pango_x_font_get_coverage (PangoFont *font,
- const char *lang);
-static PangoEngineShape * pango_x_font_find_shaper (PangoFont *font,
- const char *lang,
- guint32 ch);
-static void pango_x_font_get_glyph_extents (PangoFont *font,
- PangoGlyph glyph,
- PangoRectangle *ink_rect,
- PangoRectangle *logical_rect);
+static void pango_x_font_destroy (PangoFont *font);
+static PangoFontDescription *pango_x_font_describe (PangoFont *font);
+static PangoCoverage * pango_x_font_get_coverage (PangoFont *font,
+ const char *lang);
+static PangoEngineShape * pango_x_font_find_shaper (PangoFont *font,
+ const char *lang,
+ guint32 ch);
+static void pango_x_font_get_glyph_extents (PangoFont *font,
+ PangoGlyph glyph,
+ PangoRectangle *ink_rect,
+ PangoRectangle *logical_rect);
+static void pango_x_font_get_metrics (PangoFont *font,
+ const gchar *lang,
+ PangoFontMetrics *metrics);
static PangoXSubfontInfo * pango_x_find_subfont (PangoFont *font,
PangoXSubfont subfont_index);
@@ -225,7 +248,8 @@ PangoFontClass pango_x_font_class = {
pango_x_font_describe,
pango_x_font_get_coverage,
pango_x_font_find_shaper,
- pango_x_font_get_glyph_extents
+ pango_x_font_get_glyph_extents,
+ pango_x_font_get_metrics
};
PangoFontMapClass pango_x_font_map_class = {
@@ -1206,23 +1230,64 @@ pango_x_insert_font (PangoXFontMap *xfontmap,
}
+/**
+ * pango_x_get_context:
+ * @display: an X display (As returned by XOpenDisplay().)
+ *
+ * Retrieves a #PangoContext appropriate for rendering with X fonts on the given display.
+ *
+ * Return value: the new #PangoContext
+ **/
PangoContext *
pango_x_get_context (Display *display)
{
PangoContext *result;
+ PangoXContextInfo *info;
+
+ g_return_val_if_fail (display != NULL, NULL);
result = pango_context_new ();
+
+ info = g_new (PangoXContextInfo, 1);
+ info->get_gc_func = NULL;
+ info->free_gc_func = NULL;
+ pango_context_set_data (result, "pango-x-info", info, (GDestroyNotify)g_free);
+
pango_context_add_font_map (result, pango_x_font_map_for_display (display));
return result;
}
/**
+ * pango_x_context_set_funcs:
+ * @context: a #PangoContext.
+ * @get_gc_func: function called to create a new GC for a given color.
+ * @free_gc_func: function called to free a GC created with @get_gc_func.
+ *
+ * Sets the functions that will be used to get GC's in various colors when
+ * rendering layouts with this context.
+ **/
+void
+pango_x_context_set_funcs (PangoContext *context,
+ PangoGetGCFunc get_gc_func,
+ PangoFreeGCFunc free_gc_func)
+{
+ PangoXContextInfo *info;
+
+ g_return_if_fail (context != NULL);
+
+ info = pango_context_get_data (context, "pango-x-info");
+
+ info->get_gc_func = get_gc_func;
+ info->free_gc_func = free_gc_func;
+}
+
+/**
* pango_x_load_font:
* @display: the X display
* @spec: a comma-separated list of XLFD's
*
- * Load up a logical font based on a "fontset" style
+ * Loads up a logical font based on a "fontset" style
* text specification.
*
* Returns a new #PangoFont
@@ -1254,6 +1319,8 @@ pango_x_load_font (Display *display,
result->n_subfonts = 0;
result->max_subfonts = 1;
+ result->metrics_by_lang = NULL;
+
result->size = -1;
result->entry = NULL;
@@ -1299,6 +1366,8 @@ pango_x_load_font_with_size (Display *display,
result->n_subfonts = 0;
result->max_subfonts = 1;
+ result->metrics_by_lang = NULL;
+
result->size = size;
result->entry = NULL;
@@ -1417,6 +1486,236 @@ pango_x_font_get_glyph_extents (PangoFont *font,
}
}
+/* Get composite font metrics for all subfonts in list
+ */
+static void
+get_font_metrics_from_subfonts (PangoFont *font,
+ GSList *subfonts,
+ PangoFontMetrics *metrics)
+{
+ GSList *tmp_list = subfonts;
+ gboolean first = TRUE;
+
+ metrics->ascent = 0;
+ metrics->descent = 0;
+
+ while (tmp_list)
+ {
+ PangoXSubfontInfo *subfont = pango_x_find_subfont (font, GPOINTER_TO_UINT (tmp_list->data));
+
+ if (subfont)
+ {
+ XFontStruct *fs = pango_x_get_font_struct (font, subfont);
+ if (fs)
+ {
+ if (first)
+ {
+ metrics->ascent = fs->ascent * PANGO_SCALE;
+ metrics->descent = fs->descent * PANGO_SCALE;
+ first = FALSE;
+ }
+ else
+ {
+ metrics->ascent = MAX (fs->ascent * PANGO_SCALE, metrics->ascent);
+ metrics->descent = MAX (fs->descent * PANGO_SCALE, metrics->descent);
+ }
+ }
+ }
+ else
+ g_warning ("Invalid subfont %d in get_font_metrics_from_subfonts", GPOINTER_TO_UINT (tmp_list->data));
+
+ tmp_list = tmp_list->next;
+ }
+}
+
+/* Get composite font metrics for all subfonts resulting from shaping
+ * string str with the given font
+ *
+ * This duplicates quite a bit of code from pango_itemize. This function
+ * should die and we should simply add the ability to specify particular
+ * fonts when itemizing.
+ */
+static void
+get_font_metrics_from_string (PangoFont *font,
+ const char *lang,
+ const char *str,
+ PangoFontMetrics *metrics)
+{
+ const char *start, *p;
+ PangoGlyphString *glyph_str = pango_glyph_string_new ();
+ PangoEngineShape *shaper, *last_shaper;
+ int last_level;
+ GUChar4 *text_ucs4;
+ int n_chars, i;
+ guint8 *embedding_levels;
+ FriBidiCharType base_dir = PANGO_DIRECTION_LTR;
+ GSList *subfonts = NULL;
+
+ n_chars = unicode_strlen (str, -1);
+
+ text_ucs4 = _pango_utf8_to_ucs4 (str, strlen (str));
+ if (!text_ucs4)
+ return;
+
+ embedding_levels = g_new (guint8, n_chars);
+ fribidi_log2vis_get_embedding_levels (text_ucs4, n_chars, &base_dir,
+ embedding_levels);
+ g_free (text_ucs4);
+
+ last_shaper = NULL;
+ last_level = 0;
+
+ i = 0;
+ p = start = str;
+ while (*p)
+ {
+ unicode_char_t wc;
+ p = unicode_get_utf8 (p, &wc);
+
+ shaper = pango_font_find_shaper (font, lang, wc);
+ if (p > start &&
+ (shaper != last_shaper || last_level != embedding_levels[i]))
+ {
+ PangoAnalysis analysis;
+ int j;
+
+ analysis.shape_engine = shaper;
+ analysis.lang_engine = NULL;
+ analysis.font = font;
+ analysis.level = last_level;
+
+ pango_shape (start, p - start, &analysis, glyph_str);
+
+ for (j = 0; j < glyph_str->num_glyphs; j++)
+ {
+ PangoXSubfont subfont = PANGO_X_GLYPH_SUBFONT (glyph_str->glyphs[j].glyph);
+ if (!g_slist_find (subfonts, GUINT_TO_POINTER ((guint)subfont)))
+ subfonts = g_slist_prepend (subfonts, GUINT_TO_POINTER ((guint)subfont));
+ }
+
+ start = p;
+ }
+
+ last_shaper = shaper;
+ last_level = embedding_levels[i];
+ i++;
+ }
+
+ get_font_metrics_from_subfonts (font, subfonts, metrics);
+ g_slist_free (subfonts);
+
+ pango_glyph_string_free (glyph_str);
+ g_free (embedding_levels);
+}
+
+typedef struct {
+ const char *lang;
+ const char *str;
+} LangInfo;
+
+int
+lang_info_compare (const void *key, const void *val)
+{
+ const LangInfo *lang_info = val;
+
+ return strncmp (key, lang_info->lang, 2);
+}
+
+/* The following array is supposed to contain enough text to tickle all necessary fonts for each
+ * of the languages in the following. Yes, it's pretty lame. Not all of the languages
+ * in the following have sufficient text to excercise all the accents for the language, and
+ * there are obviously many more languages to include as well.
+ */
+LangInfo lang_texts[] = {
+ { "ar", "Arabic السلام عليكم" },
+ { "cs", "Czech (česky) Dobrý den" },
+ { "da", "Danish (Dansk) Hej, Goddag" },
+ { "el", "Greek (Ελληνικά) Γειά σας" },
+ { "en", "English Hello" },
+ { "eo", "Esperanto Saluton" },
+ { "es", "Spanish (Español) ¡Hola!" },
+ { "et", "Estonian Tere, Tervist" },
+ { "fi", "Finnish (Suomi) Hei" },
+ { "fr", "French (Français)" },
+ { "de", "German Grüß Gott" },
+ { "iw", "Hebrew שלום" },
+ { "il", "Italiano Ciao, Buon giorno" },
+ { "ja", "Japanese (日本語) こんにちは, コンニチハ" },
+ { "ko", "Korean (한글) 안녕하세요, 안녕하십니까" },
+ { "mt", "Maltese Ċaw, Saħħa" },
+ { "nl", "Nederlands, Vlaams Hallo, Dag" },
+ { "no", "Norwegian (Norsk) Hei, God dag" },
+ { "pl", "Polish Dzień dobry, Hej" },
+ { "ru", "Russian (Русский)" },
+ { "sk", "Slovak Dobrý deň" },
+ { "sv", "Swedish (Svenska) Hej, Goddag" },
+ { "tr", "Turkish (Türkçe) Merhaba" },
+ { "zh", "Chinese (中文,普通话,汉语)" }
+};
+
+static void
+pango_x_font_get_metrics (PangoFont *font,
+ const gchar *lang,
+ PangoFontMetrics *metrics)
+{
+ PangoXMetricsInfo *info;
+ PangoXFont *xfont = (PangoXFont *)font;
+ GSList *tmp_list;
+
+ const char *lookup_lang;
+ const char *str;
+
+ if (lang)
+ {
+ LangInfo *lang_info = bsearch (lang, lang_texts,
+ G_N_ELEMENTS (lang_texts), sizeof (LangInfo),
+ lang_info_compare);
+
+ if (lang_info)
+ {
+ lookup_lang = lang_info->lang;
+ str = lang_info->str;
+ }
+ else
+ {
+ lookup_lang = "UNKNOWN";
+ str = "French (Français)"; /* Assume iso-8859-1 */
+ }
+ }
+ else
+ {
+ lookup_lang = "NONE";
+
+ /* Complete junk
+ */
+ str = "السلام عليكم česky Ελληνικά Français 日本語 한글 Русский 中文,普通话,汉语 Türkçe";
+ }
+
+ tmp_list = xfont->metrics_by_lang;
+ while (tmp_list)
+ {
+ info = tmp_list->data;
+
+ if (info->lang == lookup_lang) /* We _don't_ need strcmp */
+ break;
+
+ tmp_list = tmp_list->next;
+ }
+
+ if (!tmp_list)
+ {
+ info = g_new (PangoXMetricsInfo, 1);
+ info->lang = lookup_lang;
+
+ xfont->metrics_by_lang = g_slist_prepend (xfont->metrics_by_lang, info);
+
+ get_font_metrics_from_string (font, lang, str, &info->metrics);
+ }
+
+ *metrics = info->metrics;
+ return;
+}
+
/* Compare the tail of a to b */
static gboolean
match_end (char *a, char *b)
@@ -1753,6 +2052,9 @@ pango_x_font_destroy (PangoFont *font)
g_hash_table_foreach (xfont->subfonts_by_charset, subfonts_foreach, NULL);
g_hash_table_destroy (xfont->subfonts_by_charset);
+ g_slist_foreach (xfont->metrics_by_lang, (GFunc)g_free, NULL);
+ g_slist_free (xfont->metrics_by_lang);
+
if (xfont->entry)
xfont->entry->cached_fonts = g_slist_remove (xfont->entry->cached_fonts, xfont);
@@ -2013,32 +2315,31 @@ pango_x_get_unknown_glyph (PangoFont *font)
* pango_x_render_layout_line:
* @display: the X display
* @drawable: the drawable on which to draw string
+ * @gc: GC to use for uncolored drawing
* @line: a #PangoLayoutLine
* @x: the x position of start of string (in pixels)
* @y: the y position of baseline (in pixels)
- * @get_gc: function to call to retrieve a GC for a particular color
- * @free_gc: function to call to free a GC retrieved from get_gc
- * @user_data: extra data to pass to get_gc and free_gc
*
* Render a #PangoLayoutLine onto an X drawable
*/
void
pango_x_render_layout_line (Display *display,
Drawable drawable,
+ GC gc,
PangoLayoutLine *line,
int x,
- int y,
- PangoGetGCFunc get_gc,
- PangoFreeGCFunc free_gc,
- gpointer user_data)
+ int y)
{
GSList *tmp_list = line->runs;
+ PangoRectangle overall_rect;
PangoRectangle logical_rect;
PangoRectangle ink_rect;
+ PangoContext *context = pango_layout_get_context (line->layout);
+ PangoXContextInfo *info = pango_context_get_data (context, "pango-x-info");
int x_off = 0;
- pango_layout_line_get_extents (line,NULL, &logical_rect);
+ pango_layout_line_get_extents (line,NULL, &overall_rect);
while (tmp_list)
{
@@ -2052,10 +2353,10 @@ pango_x_render_layout_line (Display *display,
pango_x_get_item_properties (run->item, &uline, &fg_color, &fg_set, &bg_color, &bg_set);
- if (fg_set)
- fg_gc = (*get_gc) (&fg_color, user_data);
+ if (fg_set && info->get_gc_func)
+ fg_gc = info->get_gc_func (context, &fg_color, gc);
else
- fg_gc = (*get_gc) (NULL, user_data);
+ fg_gc = gc;
if (uline == PANGO_UNDERLINE_NONE)
pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
@@ -2064,17 +2365,18 @@ pango_x_render_layout_line (Display *display,
pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
&ink_rect, &logical_rect);
- if (bg_set)
+ if (bg_set && info->get_gc_func)
{
- GC bg_gc = (*get_gc) (&bg_color, user_data);
+ GC bg_gc = info->get_gc_func (context, &bg_color, gc);
XFillRectangle (display, drawable, bg_gc,
x + (x_off + logical_rect.x) / PANGO_SCALE,
- y + logical_rect.y / PANGO_SCALE,
+ y + overall_rect.y / PANGO_SCALE,
logical_rect.width / PANGO_SCALE,
- logical_rect.height / PANGO_SCALE);
+ overall_rect.height / PANGO_SCALE);
- (*free_gc) (bg_gc, user_data);
+ if (info->free_gc_func)
+ info->free_gc_func (context, bg_gc);
}
pango_x_render (display, drawable, fg_gc, run->item->analysis.font, run->glyphs,
@@ -2101,7 +2403,8 @@ pango_x_render_layout_line (Display *display,
break;
}
- (*free_gc) (fg_gc, user_data);
+ if (fg_set && info->get_gc_func && info->free_gc_func)
+ info->free_gc_func (context, fg_gc);
x_off += logical_rect.width;
}
@@ -2111,11 +2414,10 @@ pango_x_render_layout_line (Display *display,
* pango_x_render_layout:
* @display: the X display
* @drawable: the drawable on which to draw string
+ * @gc: GC to use for uncolored drawing
* @layout: a #PangoLayout
* @x: the X position of the left of the layout (in pixels)
* @y: the Y position of the top of the layout (in pixels)
- * @get_gc: function to call to retrieve a GC for a particular color
- * @free_gc: function to call to free a GC retrieved from get_gc
* @user_data: extra data to pass to get_gc and free_gc
*
* Render a #PangoLayoutLine onto an X drawable
@@ -2123,12 +2425,10 @@ pango_x_render_layout_line (Display *display,
void
pango_x_render_layout (Display *display,
Drawable drawable,
+ GC gc,
PangoLayout *layout,
int x,
- int y,
- PangoGetGCFunc get_gc,
- PangoFreeGCFunc free_gc,
- gpointer user_data)
+ int y)
{
PangoRectangle logical_rect;
GSList *tmp_list;
@@ -2190,9 +2490,8 @@ pango_x_render_layout (Display *display,
}
}
- pango_x_render_layout_line (display, drawable,
- line, x + x_offset / PANGO_SCALE, y + (y_offset - logical_rect.y) / PANGO_SCALE,
- get_gc, free_gc, user_data);
+ pango_x_render_layout_line (display, drawable, gc,
+ line, x + x_offset / PANGO_SCALE, y + (y_offset - logical_rect.y) / PANGO_SCALE);
y_offset += logical_rect.height;
tmp_list = tmp_list->next;