+/* ----------------------------------------------------------------------
+ * Multiple-font wrapper. This is a type of unifont which encapsulates
+ * up to two other unifonts, permitting missing glyphs in the main
+ * font to be filled in by a fallback font.
+ *
+ * This is a type of unifont just like the previous two, but it has a
+ * separate constructor which is manually called by the client, so it
+ * doesn't appear in the list of available font types enumerated by
+ * unifont_create. This means it's not used by unifontsel either, so
+ * it doesn't need to support any methods except draw_text and
+ * destroy.
+ */
+
+static void multifont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
+ int x, int y, const wchar_t *string, int len,
+ int wide, int bold, int cellwidth);
+static void multifont_destroy(unifont *font);
+
+struct multifont {
+ struct unifont u;
+ unifont *main;
+ unifont *fallback;
+};
+
+static const struct unifont_vtable multifont_vtable = {
+ NULL, /* creation is done specially */
+ NULL,
+ multifont_destroy,
+ NULL,
+ multifont_draw_text,
+ NULL,
+ NULL,
+ NULL,
+ "client",
+};
+
+unifont *multifont_create(GtkWidget *widget, const char *name,
+ int wide, int bold,
+ int shadowoffset, int shadowalways)
+{
+ int i;
+ unifont *font, *fallback;
+ struct multifont *mfont;
+
+ font = unifont_create(widget, name, wide, bold,
+ shadowoffset, shadowalways);
+ if (!font)
+ return NULL;
+
+ fallback = NULL;
+ if (font->want_fallback) {
+ for (i = 0; i < lenof(unifont_types); i++) {
+ if (unifont_types[i]->create_fallback) {
+ fallback = unifont_types[i]->create_fallback
+ (widget, font->height, wide, bold,
+ shadowoffset, shadowalways);
+ if (fallback)
+ break;
+ }
+ }
+ }
+
+ /*
+ * Construct our multifont. Public members are all copied from the
+ * primary font we're wrapping.
+ */
+ mfont = snew(struct multifont);
+ mfont->u.vt = &multifont_vtable;
+ mfont->u.width = font->width;
+ mfont->u.ascent = font->ascent;
+ mfont->u.descent = font->descent;
+ mfont->u.height = font->height;
+ mfont->u.public_charset = font->public_charset;
+ mfont->u.want_fallback = FALSE; /* shouldn't be needed, but just in case */
+ mfont->main = font;
+ mfont->fallback = fallback;
+
+ return (unifont *)mfont;
+}
+
+static void multifont_destroy(unifont *font)
+{
+ struct multifont *mfont = (struct multifont *)font;
+ unifont_destroy(mfont->main);
+ if (mfont->fallback)
+ unifont_destroy(mfont->fallback);
+ sfree(font);
+}
+
+static void multifont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
+ int x, int y, const wchar_t *string, int len,
+ int wide, int bold, int cellwidth)
+{
+ struct multifont *mfont = (struct multifont *)font;
+ int ok, i;
+
+ while (len > 0) {
+ /*
+ * Find a maximal sequence of characters which are, or are
+ * not, supported by our main font.
+ */
+ ok = mfont->main->vt->has_glyph(mfont->main, string[0]);
+ for (i = 1;
+ i < len &&
+ !mfont->main->vt->has_glyph(mfont->main, string[i]) == !ok;
+ i++);
+
+ /*
+ * Now display it.
+ */
+ unifont_draw_text(target, gc, ok ? mfont->main : mfont->fallback,
+ x, y, string, i, wide, bold, cellwidth);
+ string += i;
+ len -= i;
+ x += i * cellwidth;
+ }
+}
+