+#ifndef HAVE_OTF
+static OTF_Tag
+OTF_tag (char *name)
+{
+ unsigned char *p = (unsigned char *) name;
+
+ if (! name)
+ return (OTF_Tag) 0;
+ return (OTF_Tag) ((p[0] << 24)
+ | (! p[1] ? 0
+ : ((p[1] << 16)
+ | (! p[2] ? 0
+ : (p[2] << 8) | p[3]))));
+}
+#endif /* not HAVE_OTF */
+
+static MPlist *otf_script_list;
+
+static int
+load_otf_script_list ()
+{
+ MDatabase *mdb;
+ MPlist *plist, *pl;
+
+ otf_script_list = mplist ();
+ mdb = mdatabase_find (msymbol ("standard"), Mscript, msymbol ("otf"), Mnil);
+ if (! mdb
+ || ! (plist = mdatabase_load (mdb)))
+ MERROR (MERROR_FONT, -1);
+ MPLIST_DO (pl, plist)
+ {
+ MPlist *p;
+ MSymbol script, otf_script;
+ OTF_Tag tag;
+
+ if (! MPLIST_PLIST_P (pl))
+ continue;
+ p = MPLIST_PLIST (pl);
+ if (! MPLIST_SYMBOL_P (p))
+ continue;
+ script = MPLIST_SYMBOL (p);
+ p = MPLIST_NEXT (p);
+ if (! MPLIST_SYMBOL_P (p))
+ continue;
+ otf_script = MPLIST_SYMBOL (p);
+ tag = OTF_tag (MSYMBOL_NAME (otf_script));
+ mplist_push (otf_script_list, script, (void *) tag);
+ }
+ M17N_OBJECT_UNREF (plist);
+ return 0;
+}
+
+static MSymbol
+find_script_from_otf_tag (OTF_Tag tag)
+{
+ MPlist *plist;
+
+ if (! otf_script_list)
+ load_otf_script_list ();
+ plist = mplist_find_by_value (otf_script_list, (void *) tag);
+ return (plist ? MPLIST_KEY (plist) : Mnil);
+}
+
+
+/* XLFD parser/generator */
+
+/** Indices to each field of split font name. */
+
+enum xlfd_field_idx
+ {
+ XLFD_FOUNDRY,
+ XLFD_FAMILY,
+ XLFD_WEIGHT,
+ XLFD_SLANT,
+ XLFD_SWIDTH,
+ XLFD_ADSTYLE,
+ XLFD_PIXEL,
+ XLFD_POINT,
+ XLFD_RESX,
+ XLFD_RESY,
+ XLFD_SPACING,
+ XLFD_AVGWIDTH,
+ XLFD_REGISTRY, /* This contains ENCODING. */
+ /* anchor */
+ XLFD_FIELD_MAX
+ };
+
+static int
+xlfd_parse_name (char *name, MFont *font)
+{
+ char *field[XLFD_FIELD_MAX];
+ unsigned short resy, avgwidth;
+ unsigned size;
+ MSymbol attrs[MFONT_PROPERTY_MAX];
+ char copy[513];
+ int i;
+ char *p;
+
+ if (name[0] != '-')
+ return -1;
+
+ field[0] = copy;
+ for (i = 1, p = copy, name++; *name; p++, name++)
+ {
+ if (p - copy > 512)
+ return -1;
+ if (*name == '-'
+ && i < XLFD_FIELD_MAX)
+ {
+ *p = '\0';
+ if (field[i - 1][0] == '*')
+ field[i - 1] = NULL;
+ field[i++] = p + 1;
+ }
+ else
+ *p = tolower (*name);
+ }
+ *p = '\0';
+ if (field[i - 1][0] == '*')
+ field[i - 1] = NULL;
+ while (i < XLFD_FIELD_MAX)
+ field[i++] = NULL;
+
+ resy = field[XLFD_RESY] ? atoi (field[XLFD_RESY]) : 0;
+ avgwidth = ((field[XLFD_AVGWIDTH] && isdigit (field[XLFD_AVGWIDTH][0]))
+ ? atoi (field[XLFD_AVGWIDTH]) : 1);
+ if (! avgwidth)
+ size = 0;
+ else if (! field[XLFD_PIXEL])
+ size = field[XLFD_POINT] ? atoi (field[XLFD_POINT]) * resy / 72 : 0;
+ else if (field[XLFD_PIXEL][0] == '[')
+ {
+ /* The pixel size field specifies a transformation matrix of the
+ form "[A B C D]". The XLFD spec says that the scalar value N
+ for the pixel size is equivalent to D. */
+ char *p0 = field[XLFD_PIXEL] + 1, *p1;
+ double d;
+
+ for (i = 0; i < 4; i++, p0 = p1)
+ d = strtod (p0, &p1);
+ size = d * 10;
+ }
+ else
+ size = atoi (field[XLFD_PIXEL]) * 10;
+
+ attrs[MFONT_FOUNDRY]
+ = field[XLFD_FOUNDRY] ? msymbol (field[XLFD_FOUNDRY]) : Mnil;
+ attrs[MFONT_FAMILY]
+ = field[XLFD_FAMILY] ? msymbol (field[XLFD_FAMILY]) : Mnil;
+ attrs[MFONT_WEIGHT]
+ = field[XLFD_WEIGHT] ? msymbol (field[XLFD_WEIGHT]) : Mnil;
+ attrs[MFONT_STYLE]
+ = field[XLFD_SLANT] ? msymbol (field[XLFD_SLANT]) : Mnil;
+ attrs[MFONT_STRETCH]
+ = field[XLFD_SWIDTH] ? msymbol (field[XLFD_SWIDTH]) : Mnil;
+ attrs[MFONT_ADSTYLE]
+ = field[XLFD_ADSTYLE] ? msymbol (field[XLFD_ADSTYLE]) : Mnil;
+ attrs[MFONT_REGISTRY]
+ = field[XLFD_REGISTRY] ? msymbol (field[XLFD_REGISTRY]) : Mnil;
+ mfont__set_spec (font, attrs, size, resy);
+ font->type = MFONT_TYPE_SPEC;
+ font->source = MFONT_SOURCE_X;
+ return 0;
+}
+
+static char *
+xlfd_unparse_name (MFont *font)
+{
+ MSymbol prop[7];
+ char name[513];
+ char *str[7];
+ int len, i;
+ unsigned short size, resy;
+
+ prop[0] = (MSymbol) mfont_get_prop (font, Mfoundry);
+ prop[1] = (MSymbol) mfont_get_prop (font, Mfamily);
+ prop[2] = (MSymbol) mfont_get_prop (font, Mweight);
+ prop[3] = (MSymbol) mfont_get_prop (font, Mstyle);
+ prop[4] = (MSymbol) mfont_get_prop (font, Mstretch);
+ prop[5] = (MSymbol) mfont_get_prop (font, Madstyle);
+ prop[6] = (MSymbol) mfont_get_prop (font, Mregistry);
+ for (len = 0, i = 0; i < 7; i++)
+ {
+ if (prop[i] != Mnil)
+ {
+ str[i] = msymbol_name (prop[i]);
+ len += strlen (str[i]);
+ }
+ else
+ {
+ str[i] = "*";
+ len++;
+ }
+ }
+ if ((len
+ + 12 /* 12 dashes */
+ + 3 /* 3 asterisks */
+ + 30 /* 3 integers (each 10 digits) */
+ + 1) /* '\0' terminal */
+ > 513)
+ return NULL;
+
+ resy = (int) mfont_get_prop (font, Mresolution);
+ size = font->size;
+ if ((size % 10) < 5)
+ size /= 10;
+ else
+ size = size / 10 + 1;
+
+ sprintf (name, "-%s-%s-%s-%s-%s-%s-%d-*-%d-%d-*-*-%s",
+ str[0], str[1], str[2], str[3], str[4], str[5],
+ size, resy, resy, str[6]);
+ return strdup (name);
+}
+
+/* Compare FONT with REQUEST and return how much they differs. */
+
+static int
+font_score (MFont *font, MFont *request)
+{
+ int score = 0;
+ int i = FONT_SCORE_PRIORITY_SIZE;
+
+ while (--i >= 0)
+ {
+ enum MFontProperty prop = font_score_priority[i];
+ int val;
+
+ if (prop == MFONT_SIZE)
+ {
+ if (font->size && request->size)
+ {
+ val = font->size - request->size;
+ if (val)
+ {
+ if (val < 0)
+ val = - val;
+ if (val >= 0x10000)
+ val = 0xFFFF;
+ score |= (val << font_score_shift_bits[MFONT_SIZE]);
+ }
+ }
+ }
+ else if (font->property[prop] && request->property[prop]
+ && font->property[prop] != request->property[prop])
+ {
+ if (prop <= MFONT_FAMILY)
+ val = 1;
+ else if (prop == MFONT_WEIGHT)
+ {
+ unsigned short v1 = font->property[prop];
+ unsigned short v2 = request->property[prop];
+
+ if (v1 == font_weight_regular || v1 == font_weight_normal)
+ v1 = font_weight_medium;
+ if (v2 == font_weight_regular || v2 == font_weight_normal)
+ v2 = font_weight_medium;
+ val = v1 > v2 ? v1 - v2 : v2 - v1;
+ }
+ else
+ {
+ val = font->property[prop] - request->property[prop];
+ if (val < 0)
+ val = - val;
+ if (val > 3)
+ val = 3;
+ }
+ score |= val << font_score_shift_bits[prop];
+ }
+ }
+ if (request->file != Mnil && request->file != font->file)
+ score |= 40000000;
+ return score;
+}