summaryrefslogtreecommitdiff
path: root/pango/pangox.c
diff options
context:
space:
mode:
Diffstat (limited to 'pango/pangox.c')
-rw-r--r--pango/pangox.c757
1 files changed, 757 insertions, 0 deletions
diff --git a/pango/pangox.c b/pango/pangox.c
new file mode 100644
index 00000000..21c2d24d
--- /dev/null
+++ b/pango/pangox.c
@@ -0,0 +1,757 @@
+/* Pango
+ * gscriptx.c:
+ *
+ * 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 <X11/Xlib.h>
+#include "pangox.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+typedef struct _PangoXFont PangoXFont;
+typedef struct _XLFDInfo XLFDInfo;
+
+struct _PangoXFont {
+ PangoFont font;
+ Display *display;
+ gchar **fonts;
+ gint n_fonts;
+ GHashTable *name_hash;
+ GHashTable *xlfd_hash;
+};
+
+struct _XLFDInfo {
+ XFontStruct *font_struct;
+ PangoCFont *cfont;
+};
+
+static void pango_x_font_destroy (PangoFont *font);
+static void pango_x_cfont_destroy (PangoCFont *cfont);
+
+PangoFontClass pango_x_font_class = {
+ pango_x_font_destroy
+};
+
+PangoCFontClass pango_x_cfont_class = {
+ pango_x_cfont_destroy
+};
+
+/**
+ * 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
+ * text specification.
+ *
+ * Returns a new #PangoFont
+ */
+PangoFont *
+pango_x_load_font (Display *display,
+ gchar *spec)
+{
+ PangoXFont *result;
+
+ g_return_val_if_fail (display != NULL, NULL);
+ g_return_val_if_fail (spec != NULL, NULL);
+
+ result = g_new (PangoXFont, 1);
+
+ result->display = display;
+
+ pango_font_init (&result->font);
+ result->font.klass = &pango_x_font_class;
+
+ result->fonts = g_strsplit(spec, ",", -1);
+ result->n_fonts = 0;
+ while (result->fonts[result->n_fonts])
+ result->n_fonts++;
+
+ result->name_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ result->xlfd_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+ return (PangoFont *)result;
+}
+
+/**
+ * pango_x_render:
+ * @display: the X display
+ * @d: the drawable on which to draw string
+ * @gc: the graphics context
+ * @glyphs: the glyph string to draw
+ * @x: the x position of start of string
+ * @y: the y position of baseline
+ *
+ * Render a PangoGlyphString onto an X drawable
+ */
+void
+pango_x_render (Display *display,
+ Drawable d,
+ GC gc,
+ PangoGlyphString *glyphs,
+ gint x,
+ gint y)
+{
+ /* Slow initial implementation. For speed, it should really
+ * collect the characters into runs, and draw multiple
+ * characters with each XDrawString16 call.
+ */
+ XChar2b c;
+ PangoXCFont *cfont;
+ Font old_fid = None;
+ XFontStruct *fs;
+ int i;
+
+ for (i=0; i<glyphs->num_glyphs; i++)
+ {
+ c.byte1 = glyphs->glyphs[i].glyph / 256;
+ c.byte2 = glyphs->glyphs[i].glyph % 256;
+ cfont = (PangoXCFont *)glyphs->glyphs[i].font;
+ fs = cfont->font_struct;
+
+ if (fs->fid != old_fid)
+ {
+ XSetFont (display, gc, fs->fid);
+ old_fid = fs->fid;
+ }
+
+ XDrawString16 (display, d, gc,
+ x + glyphs->geometry[i].x_offset / 72,
+ y + glyphs->geometry[i].y_offset / 72,
+ &c, 1);
+
+ x += glyphs->geometry[i].width / 72;
+
+ }
+}
+
+/**
+ * pango_x_glyph_extents:
+ * @glyph: the glyph to measure
+ * @lbearing: left bearing of glyph (result)
+ * @rbearing: right bearing of glyph (result)
+ * @width: width of glyph (result)
+ * @ascent: ascent of glyph (result)
+ * @descent: descent of glyph (result)
+ * @logical_ascent: The vertical distance from the baseline to the
+ * bottom of the line above.
+ * @logical_descent: The vertical distance from the baseline to the
+ * top of the line below.
+ *
+ * Compute the measurements of a single glyph in pixels.
+ */
+void
+pango_x_glyph_extents (PangoGlyph *glyph,
+ gint *lbearing,
+ gint *rbearing,
+ gint *width,
+ gint *ascent,
+ gint *descent,
+ gint *logical_ascent,
+ gint *logical_descent)
+{
+ int index;
+
+ PangoXCFont *cfont;
+ XFontStruct *fs;
+ XCharStruct *cs;
+ XChar2b c;
+
+ c.byte1 = glyph->glyph / 256;
+ c.byte2 = glyph->glyph % 256;
+ cfont = (PangoXCFont *)glyph->font;
+ fs = cfont->font_struct;
+
+ if ((fs->min_byte1 == 0) && (fs->max_byte1 == 0))
+ index = c.byte2 - fs->min_char_or_byte2;
+ else
+ {
+ index = ((c.byte1 - fs->min_byte1) *
+ (fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1)) +
+ c.byte2 - fs->min_char_or_byte2;
+ }
+
+ if (fs->per_char)
+ cs = &fs->per_char[index];
+ else
+ cs = &fs->min_bounds;
+
+ if (lbearing)
+ *lbearing = cs->lbearing;
+ if (rbearing)
+ *rbearing = cs->rbearing;
+ if (width)
+ *width = cs->width;
+ if (ascent)
+ *ascent = cs->ascent;
+ if (descent)
+ *descent = cs->descent;
+ if (logical_ascent)
+ *logical_ascent = fs->ascent;
+ if (logical_descent)
+ *logical_descent = fs->descent;
+}
+
+/**
+ * pango_x_extents:
+ * @glyphs: the glyph string to measure
+ * @lbearing: left bearing of string (result)
+ * @rbearing: right bearing of string (result)
+ * @width: width of string (result)
+ * @ascent: ascent of string (result)
+ * @descent: descent of string (result)
+ * @logical_ascent: The vertical distance from the baseline to the
+ * bottom of the line above.
+ * @logical_descent: The vertical distance from the baseline to the
+ * top of the line below.
+ *
+ * Compute the measurements of a glyph string in pixels.
+ * The number of parameters here is clunky - it might be
+ * nicer to use structures as in XmbTextExtents.
+ */
+void
+pango_x_extents (PangoGlyphString *glyphs,
+ gint *lbearing,
+ gint *rbearing,
+ gint *width,
+ gint *ascent,
+ gint *descent,
+ gint *logical_ascent,
+ gint *logical_descent)
+{
+ int index;
+
+ PangoXCFont *cfont;
+ XFontStruct *fs;
+ XCharStruct *cs;
+ PangoGlyphGeometry *geometry;
+ XChar2b c;
+
+ int i;
+
+ int t_lbearing = 0;
+ int t_rbearing = 0;
+ int t_ascent = 0;
+ int t_descent = 0;
+ int t_logical_ascent = 0;
+ int t_logical_descent = 0;
+ int t_width = 0;
+
+ for (i=0; i<glyphs->num_glyphs; i++)
+ {
+ c.byte1 = glyphs->glyphs[i].glyph / 256;
+ c.byte2 = glyphs->glyphs[i].glyph % 256;
+ cfont = (PangoXCFont *)glyphs->glyphs[i].font;
+ fs = cfont->font_struct;
+
+ if ((fs->min_byte1 == 0) && (fs->min_byte1 == 0))
+ index = c.byte2 - fs->min_char_or_byte2;
+ else
+ {
+ index = ((c.byte1 - fs->min_byte1) *
+ (fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1)) +
+ c.byte2 - fs->min_char_or_byte2;
+ }
+
+ if (fs->per_char)
+ cs = &fs->per_char[index];
+ else
+ cs = &fs->min_bounds;
+
+ geometry = &glyphs->geometry[i];
+
+ if (i == 0)
+ {
+ t_lbearing = cs->lbearing - geometry->x_offset / 72;
+ t_rbearing = cs->rbearing + geometry->x_offset / 72;
+ t_ascent = cs->ascent + geometry->y_offset / 72;
+ t_descent = cs->descent - geometry->y_offset / 72;
+ t_logical_ascent = fs->ascent + geometry->y_offset / 72;
+ t_logical_descent = fs->descent - geometry->y_offset / 72;
+ }
+ else
+ {
+ t_lbearing = MAX (t_lbearing,
+ cs->lbearing - geometry->x_offset / 72 - t_width);
+ t_rbearing = MAX (t_rbearing,
+ t_width + cs->rbearing + geometry->x_offset / 72);
+ t_ascent = MAX (t_ascent, cs->ascent + geometry->y_offset / 72);
+ t_descent = MAX (t_descent, cs->descent - geometry->y_offset / 72);
+ t_logical_ascent = MAX (t_logical_ascent, fs->ascent + geometry->y_offset / 72);
+ t_logical_descent = MAX (t_logical_descent, fs->descent - geometry->y_offset / 72);
+ }
+
+ t_width += geometry->width / 72;
+ }
+
+ if (lbearing)
+ *lbearing = t_lbearing;
+ if (rbearing)
+ *rbearing = t_rbearing;
+ if (width)
+ *width = t_width;
+ if (ascent)
+ *ascent = t_ascent;
+ if (descent)
+ *descent = t_descent;
+ if (logical_ascent)
+ *logical_ascent = t_logical_ascent;
+ if (logical_descent)
+ *logical_descent = t_logical_descent;
+}
+
+/* Compare the tail of a to b */
+static gboolean
+match_end (char *a, char *b)
+{
+ size_t len_a = strlen (a);
+ size_t len_b = strlen (b);
+
+ if (len_b > len_a)
+ return FALSE;
+ else
+ return (strcmp (a + len_a - len_b, b) == 0);
+}
+
+/* Substitute in a charset into an XLFD. Return the
+ * (g_malloc'd) new name, or NULL if the XLFD cannot
+ * match the charset
+ */
+static gchar *
+name_for_charset (char *xlfd, char *charset)
+{
+ char *p;
+ char *dash_charset = g_strconcat ("-", charset, NULL);
+ char *result = NULL;
+ gint ndashes = 0;
+
+ for (p = xlfd; *p; p++)
+ if (*p == '-')
+ ndashes++;
+
+ if (ndashes == 14) /* Complete XLFD */
+ {
+ if (match_end (xlfd, "-*-*"))
+ {
+ result = g_malloc (strlen (xlfd) - 4 + strlen (dash_charset) + 1);
+ strncpy (result, xlfd, strlen (xlfd) - 4);
+ strcpy (result + strlen (xlfd) - 4, dash_charset);
+ }
+ if (match_end (xlfd, dash_charset))
+ result = g_strdup (xlfd);
+ }
+ else if (ndashes == 13)
+ {
+ if (match_end (xlfd, "-*"))
+ {
+ result = g_malloc (strlen (xlfd) - 2 + strlen (dash_charset) + 1);
+ strncpy (result, xlfd, strlen (xlfd) - 2);
+ strcpy (result + strlen (xlfd) - 2, dash_charset);
+ }
+ if (match_end (xlfd, dash_charset))
+ result = g_strdup (xlfd);
+ }
+ else
+ {
+ if (match_end (xlfd, "*"))
+ {
+ result = g_malloc (strlen (xlfd) + strlen (dash_charset) + 1);
+ strcpy (result, xlfd);
+ strcpy (result + strlen (xlfd), dash_charset);
+ }
+ if (match_end (xlfd, dash_charset))
+ result = g_strdup (xlfd);
+ }
+
+ g_free (dash_charset);
+ return result;
+}
+
+/**
+ * pango_x_load_xlfd:
+ * @font: a #PangoFont
+ * @xlfd: the XLFD of a component font to load
+ *
+ * Create a component font from a XLFD. It is assumed that
+ * the xlfd matches a font matching one of the names
+ * of @font, but this is not currently required.
+ *
+ * Returns the new #PangoXCFont
+ */
+PangoCFont *
+pango_x_load_xlfd (PangoFont *font,
+ gchar *xlfd)
+{
+ XFontStruct *fs;
+ PangoXFont *xfont = (PangoXFont *)font;
+ XLFDInfo *info;
+
+ g_return_val_if_fail (font != NULL, NULL);
+
+ info = g_hash_table_lookup (xfont->xlfd_hash, xlfd);
+ if (!info)
+ {
+ info = g_new (XLFDInfo, 1);
+ info->cfont = NULL;
+ info->font_struct = NULL;
+
+ g_hash_table_insert (xfont->xlfd_hash, g_strdup(xlfd), info);
+ }
+
+ if (!info->cfont)
+ {
+ fs = XLoadQueryFont (xfont->display, xlfd);
+ if (fs)
+ {
+ PangoXCFont *cfont = g_new (PangoXCFont, 1);
+ cfont->display = xfont->display;
+ cfont->font_struct = fs;
+ cfont->font.klass = &pango_x_cfont_class;
+
+ info->cfont = (PangoCFont *)cfont;
+
+ pango_cfont_init (info->cfont);
+ pango_cfont_ref (info->cfont);
+
+ if (info->font_struct)
+ XFreeFontInfo (NULL, info->font_struct, 1);
+
+ info->font_struct = fs;
+ }
+ }
+
+ return info->cfont;
+}
+
+static gchar **
+find_cfonts (PangoFont *font, gchar *charset)
+{
+ PangoXFont *xfont = (PangoXFont *)font;
+ gchar **cfonts;
+ int i;
+
+ cfonts = g_hash_table_lookup (xfont->name_hash, charset);
+ if (!cfonts)
+ {
+ cfonts = g_new (gchar *, xfont->n_fonts + 1);
+ for (i=0; i<xfont->n_fonts; i++)
+ {
+ char *xlfd = name_for_charset (xfont->fonts[i], charset);
+ gchar **names;
+ gint count;
+
+ cfonts[i] = NULL;
+ if (xlfd)
+ {
+ names = XListFonts (xfont->display, xlfd, 1, &count);
+ if (count > 0)
+ cfonts[i] = g_strdup (names[0]);
+
+ XFreeFontNames (names);
+ g_free (xlfd);
+ }
+ }
+
+ g_hash_table_insert (xfont->name_hash, g_strdup(charset), cfonts);
+ }
+
+ return cfonts;
+}
+
+/**
+ * pango_x_find_cfont:
+ * @font: A font from pango_x_load_font()
+ * @charset: characterset descript (last two components of XLFD)
+ *
+ * Find a component font of a #PangoFont.
+ *
+ * Returns the #PangoCFont for @charset, or NULL, if no appropriate
+ * font could be found.
+ */
+PangoCFont *
+pango_x_find_cfont (PangoFont *font,
+ gchar *charset)
+{
+ PangoXFont *xfont = (PangoXFont *)font;
+ gchar **names;
+ int i;
+
+ names = find_cfonts (font, charset);
+ for (i=0; i<xfont->n_fonts; i++)
+ if (names[i])
+ return pango_x_load_xlfd (font, names[i]);
+
+ return NULL;
+}
+
+void
+font_struct_get_ranges (Display *display,
+ XFontStruct *fs,
+ gint **ranges,
+ gint *n_ranges)
+{
+ gint i, j;
+ static Atom bounds_atom = None;
+ gint *range_buf = NULL;
+ size_t range_buf_size = 8;
+
+ if (bounds_atom == None)
+ bounds_atom = XInternAtom (display, "_XFREE86_GLYPH_RANGES", False);
+
+ j = 0;
+ for (i=0; i<fs->n_properties; i++)
+ {
+ if (fs->properties[i].name == bounds_atom)
+ {
+ char *val = XGetAtomName (display, fs->properties[i].card32);
+ char *p;
+ guint start, end;
+
+ p = val;
+ while (*p)
+ {
+ int count;
+
+ while (*p && isspace (*p))
+ p++;
+
+ count = sscanf (p, "%u_%u", &start, &end);
+
+ if (count > 0)
+ {
+ if (count == 1)
+ end = start;
+
+ if (!range_buf || (2*j+1) >= range_buf_size)
+ {
+ size_t new_size = range_buf_size * 2;
+ if (new_size < range_buf_size) /* Paranoia */
+ {
+ XFree (val);
+ *ranges = NULL;
+ *n_ranges = 0;
+
+ return;
+ }
+ range_buf_size = new_size;
+ range_buf = g_realloc (range_buf, sizeof(gint) * range_buf_size);
+ }
+
+ range_buf[2*j] = start;
+ range_buf[2*j + 1] = end;
+ j++;
+ }
+ else
+ {
+ goto error;
+ }
+
+ while (*p && !isspace (*p))
+ p++;
+ }
+
+ error:
+ XFree (val);
+ }
+
+ }
+
+ if (j > 0)
+ {
+ *n_ranges = j;
+ *ranges = g_malloc (sizeof(gint) * 2*j);
+ memcpy (*ranges, range_buf, sizeof(gint) * 2*j);
+ }
+ else
+ {
+ *n_ranges = 1;
+ *ranges = g_malloc (sizeof(gint) * 2);
+
+ (*ranges)[0] = fs->min_byte1 * 256 + fs->min_char_or_byte2;
+ (*ranges)[1] = fs->max_byte1 * 256 + fs->max_char_or_byte2;
+ }
+
+ g_free (range_buf);
+}
+
+/**
+ * pango_x_xlfd_get_ranges:
+ * @font: a #PangoFont.
+ * @xlfd: a XLFD of a component font.
+ * @ranges: location to store returned ranges.
+ * @n_ranges: location to store the number of ranges.
+ *
+ * Find the range of valid characters for a particular
+ * XLFD representing a component of the given font.
+ *
+ * Returns %TRUE if the XLFD matches a font, FALSE otherwise.
+ * in the latter case, @ranges and @n_ranges are unchanged.
+ */
+gboolean
+pango_x_xlfd_get_ranges (PangoFont *font,
+ gchar *xlfd,
+ gint **ranges,
+ gint *n_ranges)
+{
+ PangoXFont *xfont = (PangoXFont *)font;
+ gchar **names;
+ gint count;
+ XLFDInfo *info;
+
+ info = g_hash_table_lookup (xfont->xlfd_hash, xlfd);
+ if (!info)
+ {
+ info = g_new (XLFDInfo, 1);
+ info->cfont = NULL;
+ info->font_struct = NULL;
+ g_hash_table_insert (xfont->xlfd_hash, g_strdup(xlfd), info);
+ }
+
+ if (!info->font_struct)
+ {
+ names = XListFontsWithInfo (xfont->display, xlfd, 1, &count, &info->font_struct);
+
+ if (count == 0)
+ info->font_struct = NULL;
+
+ XFreeFontNames (names);
+ }
+
+ if (info->font_struct)
+ {
+ font_struct_get_ranges (xfont->display, info->font_struct, ranges, n_ranges);
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+/**
+ * pango_x_xlfd_list_cfonts:
+ * @font: a #PangoFont.
+ * @charsets: the list of character sets to match against.
+ * @n_charsets: the number of elements in @charsets.
+ * @xlfds: location to store a pointer to an array of returned XLFDs.
+ * @n_xlfds: location to store the number of XLFDs.
+ *
+ * List all possible XLFDs that can match a particular set
+ * of character sets for the given #PangoFont. The
+ * returned values are sorted at highest priority by
+ * the order of the names in fontlist used to create
+ * the #PangoFont, and then sorted by the ordering
+ * of the character sets in @charsets.
+ *
+ */
+void
+pango_x_list_cfonts (PangoFont *font,
+ gchar **charsets,
+ gint n_charsets,
+ gchar ***xlfds,
+ gint *n_xlfds)
+{
+ PangoXFont *xfont = (PangoXFont *)font;
+
+ int i, j;
+
+ GSList *result = NULL;
+ GSList *tmp_list;
+
+ gchar ***names = g_new (gchar **, n_charsets);
+
+ *n_xlfds = 0;
+ for (j=0; j<n_charsets; j++)
+ names[j] = find_cfonts (font, charsets[j]);
+
+ for (i=0; i < xfont->n_fonts; i++)
+ for (j=0; j < n_charsets; j++)
+ if (names[j][i] != 0)
+ {
+ (*n_xlfds)++;
+ result = g_slist_prepend (result, g_strdup (names[j][i]));
+ }
+
+ result = g_slist_reverse (result);
+ *xlfds = g_new (gchar *, *n_xlfds);
+
+ tmp_list = result;
+ for (i=0; i< *n_xlfds; i++)
+ {
+ (*xlfds)[i] = tmp_list->data;
+ tmp_list = tmp_list->next;
+ }
+
+ g_slist_free (result);
+ g_free (names);
+}
+
+void
+name_hash_foreach (gpointer key, gpointer value, gpointer data)
+{
+ gchar *charset = key;
+ gchar **names = value;
+ PangoXFont *xfont = data;
+ int i;
+
+ for (i=0; i<xfont->n_fonts; i++)
+ g_free (names[i]);
+ g_free (names);
+ g_free (charset);
+}
+
+void
+xlfd_hash_foreach (gpointer key, gpointer value, gpointer data)
+{
+ gchar *xlfd = key;
+ XLFDInfo *info = value;
+
+ if (info->cfont)
+ pango_cfont_unref (info->cfont);
+ else if (info->font_struct)
+ XFreeFontInfo (NULL, info->font_struct, 1);
+
+ g_free (info);
+
+ g_free (xlfd);
+}
+
+static void
+pango_x_font_destroy (PangoFont *font)
+{
+ PangoXFont *xfont = (PangoXFont *)font;
+
+ g_hash_table_foreach (xfont->name_hash, name_hash_foreach, xfont);
+ g_hash_table_destroy (xfont->name_hash);
+
+ g_hash_table_foreach (xfont->xlfd_hash, xlfd_hash_foreach, xfont);
+ g_hash_table_destroy (xfont->xlfd_hash);
+
+ g_strfreev (xfont->fonts);
+ g_free (font);
+}
+
+static void
+pango_x_cfont_destroy (PangoCFont *font)
+{
+ PangoXCFont *xcfont = (PangoXCFont *)font;
+
+ XFreeFont (xcfont->display, xcfont->font_struct);
+
+ g_free (font);
+}