+#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 (const char *name, MFont *font)
+{
+ char *field[XLFD_FIELD_MAX];
+ unsigned short resy, avgwidth;
+ unsigned size;
+ 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;
+
+ if (field[XLFD_FOUNDRY])
+ mfont__set_property (font, MFONT_FOUNDRY, msymbol (field[XLFD_FOUNDRY]));
+ if (field[XLFD_FAMILY])
+ mfont__set_property (font, MFONT_FAMILY, msymbol (field[XLFD_FAMILY]));
+ if (field[XLFD_WEIGHT])
+ mfont__set_property (font, MFONT_WEIGHT, msymbol (field[XLFD_WEIGHT]));
+ if (field[XLFD_SLANT])
+ mfont__set_property (font, MFONT_STYLE, msymbol (field[XLFD_SLANT]));
+ if (field[XLFD_SWIDTH])
+ mfont__set_property (font, MFONT_STRETCH, msymbol (field[XLFD_SWIDTH]));
+ if (field[XLFD_ADSTYLE])
+ mfont__set_property (font, MFONT_ADSTYLE, msymbol (field[XLFD_ADSTYLE]));
+ font->property[MFONT_RESY] = resy;
+ font->size = size;
+ if (field[XLFD_SPACING])
+ font->spacing
+ = ((field[XLFD_SPACING][0] == 'p' || field[XLFD_SPACING][0] == 'P')
+ ? MFONT_SPACING_PROPORTIONAL
+ : (field[XLFD_SPACING][0] == 'm' || field[XLFD_SPACING][0] == 'M')
+ ? MFONT_SPACING_MONO : MFONT_SPACING_CHARCELL);
+ if (field[XLFD_REGISTRY])
+ mfont__set_property (font, MFONT_REGISTRY, msymbol (field[XLFD_REGISTRY]));
+ 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;
+ char spacing;
+ 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++;
+ }
+ }
+ spacing = (font->spacing == MFONT_SPACING_UNDECIDED ? '*'
+ : font->spacing == MFONT_SPACING_PROPORTIONAL ? 'p'
+ : font->spacing == MFONT_SPACING_MONO ? 'm'
+ : 'c');
+
+ if ((len
+ + 13 /* 13 dashes */
+ + 2 /* 2 asterisks */
+ + 30 /* 3 integers (each 10 digits) */
+ + 1 /* 1 spacing char */
+ + 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-%c-*-%s",
+ str[0], str[1], str[2], str[3], str[4], str[5],
+ size, resy, resy, spacing, 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;
+}