[PATCH weston v2 1/2] Add font entry to shell section for title fonts

Ryo Munakata ryomnktml at gmail.com
Sat Oct 4 04:37:12 PDT 2014


cairo-util has used sans font family for title fonts so far.
But sans doesn't support glyphs of some non-ascii characters.
So now let users choose a font family for titles.

To show texts correctly now using pangocairo for redering fonts.
If any single font in 'fonts' entry doesn't contain all the needed glyphs,
we use the fallback mode of pango.

This pangocairo support is enabled if configure finds pangocairo
on the build environment.
Otherwise fall back to plain cairo rendering.

The entry name is generic, 'fonts' so that other places
where draw texts can use this entry too.

Signed-off-by: Ryo Munakata <ryomnktml at gmail.com>
---
 Makefile.am               |   4 ++
 clients/window.c          |  18 +++--
 configure.ac              |   5 +-
 man/weston.ini.man        |   3 +
 shared/cairo-util.c       | 180 ++++++++++++++++++++++++++++++++++++++++++++--
 shared/cairo-util.h       |   5 ++
 src/compositor-wayland.c  |   9 ++-
 weston.ini.in             |   1 +
 xwayland/window-manager.c |   7 +-
 9 files changed, 216 insertions(+), 16 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 10be920..db3f423 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -829,6 +829,10 @@ libshared_cairo_la_SOURCES =			\
 	shared/frame.c				\
 	shared/cairo-util.h
 
+if HAVE_PANGO
+libshared_cairo_la_CFLAGS += $(PANGO_CFLAGS)
+libshared_cairo_la_LIBADD += $(PANGO_LIBS)
+endif
 
 #
 # tests subdirectory
diff --git a/clients/window.c b/clients/window.c
index 139c7f9..d9cbb9e 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -113,6 +113,8 @@ struct display {
 
 	struct theme *theme;
 
+	struct weston_config *config;
+
 	struct wl_cursor_theme *cursor_theme;
 	struct wl_cursor **cursors;
 
@@ -1279,18 +1281,15 @@ static const struct cursor_alternatives cursors[] = {
 static void
 create_cursors(struct display *display)
 {
-	struct weston_config *config;
 	struct weston_config_section *s;
 	int size;
 	char *theme = NULL;
 	unsigned int i, j;
 	struct wl_cursor *cursor;
 
-	config = weston_config_parse("weston.ini");
-	s = weston_config_get_section(config, "shell", NULL, NULL);
+	s = weston_config_get_section(display->config, "shell", NULL, NULL);
 	weston_config_section_get_string(s, "cursor-theme", &theme, NULL);
 	weston_config_section_get_int(s, "cursor-size", &size, 32);
-	weston_config_destroy(config);
 
 	display->cursor_theme = wl_cursor_theme_load(theme, size, display->shm);
 	if (!display->cursor_theme) {
@@ -5439,6 +5438,8 @@ struct display *
 display_create(int *argc, char *argv[])
 {
 	struct display *d;
+	char *fonts;
+	struct weston_config_section *s;
 
 	wl_log_set_handler_client(log_handler);
 
@@ -5488,9 +5489,14 @@ display_create(int *argc, char *argv[])
 			"falling back to software rendering and wl_shm.\n");
 #endif
 
+	d->config = weston_config_parse("weston.ini");
+
 	create_cursors(d);
 
-	d->theme = theme_create();
+	s = weston_config_get_section(d->config, "shell", NULL, NULL);
+	weston_config_section_get_string(s, "fonts", &fonts, NULL);
+	d->theme = theme_create_with_fonts(fonts);
+	free(fonts);
 
 	wl_list_init(&d->window_list);
 
@@ -5566,6 +5572,8 @@ display_destroy(struct display *display)
 	    !(display->display_fd_events & EPOLLHUP))
 		wl_display_flush(display->display);
 
+	weston_config_destroy(display->config);
+
 	wl_display_disconnect(display->display);
 	free(display);
 }
diff --git a/configure.ac b/configure.ac
index 1c133bd..8b703bd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -272,6 +272,9 @@ PKG_CHECK_MODULES(PNG, [libpng])
 PKG_CHECK_MODULES(WEBP, [libwebp], [have_webp=yes], [have_webp=no])
 AS_IF([test "x$have_webp" = "xyes"],
       [AC_DEFINE([HAVE_WEBP], [1], [Have webp])])
+PKG_CHECK_MODULES(PANGO, [pangocairo], [have_pango=yes], [have_pango=no])
+AS_IF([test "x$have_pango" = "xyes"],
+      [AC_DEFINE([HAVE_PANGO], [1], [Have pango support])])
 
 AC_ARG_ENABLE(vaapi-recorder, [  --enable-vaapi-recorder],,
 	      enable_vaapi_recorder=auto)
@@ -335,8 +338,6 @@ if test x$enable_clients = xyes; then
 	  [AC_DEFINE([HAVE_CAIRO_EGL], [1], [Have cairo-egl])],
 	  [AC_ERROR([cairo-egl not used because $CAIRO_EGL_PKG_ERRORS])])],
   [have_cairo_egl=no])
-
-  PKG_CHECK_MODULES(PANGO, [pangocairo], [have_pango=yes], [have_pango=no])
 fi
 
 AC_ARG_ENABLE(resize-optimization,
diff --git a/man/weston.ini.man b/man/weston.ini.man
index c05a221..73e32d7 100644
--- a/man/weston.ini.man
+++ b/man/weston.ini.man
@@ -260,6 +260,9 @@ sets the path to lock screen background image (string). (tablet shell only)
 .TP 7
 .BI "homescreen=" path
 sets the path to home screen background image (string). (tablet shell only)
+.TP 7
+.BI "fonts=" font-families
+sets the font family nams separated by commas (string). (title fonts only for now)
 .RE
 .SH "LAUNCHER SECTION"
 There can be multiple launcher sections, one for each launcher.
diff --git a/shared/cairo-util.c b/shared/cairo-util.c
index 26286c5..9c9957a 100644
--- a/shared/cairo-util.c
+++ b/shared/cairo-util.c
@@ -33,9 +33,42 @@
 #include "cairo-util.h"
 
 #include "image-loader.h"
-#include "config-parser.h"
+#include "zalloc.h"
 
 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+#define DEFAULT_FONT_FAMILY "sans"
+#define DEFAULT_FONT_SIZE 14
+
+struct font_entry {
+	struct wl_list link;
+	char *name;
+};
+
+static struct font_entry *
+font_entry_create(char *fontname)
+{
+	struct font_entry *font = zalloc(sizeof *font);
+
+	if (!font)
+		return NULL;
+
+	font->name = strdup(fontname);
+	return font;
+}
+
+static void
+font_entry_destroy(struct font_entry *font)
+{
+	free(font->name);
+	free(font);
+}
+
+static struct font_entry *
+font_entry_list_front(struct wl_list *list)
+{
+	struct font_entry *font;
+	return wl_container_of(list, font, link);
+}
 
 void
 surface_flush_device(cairo_surface_t *surface)
@@ -337,8 +370,29 @@ theme_set_background_source(struct theme *t, cairo_t *cr, uint32_t flags)
 	}
 }
 
+static void
+insert_font_family_list(struct wl_list *title_fonts, const char *fonts)
+{
+	char *fontlist, *str, *token, *saveptr;
+	struct wl_list *current = title_fonts;
+
+	if (!fonts || !(fontlist = strdup(fonts)))
+		return;
+
+	for (str = fontlist; (token = strtok_r(str, ",", &saveptr)) != NULL;) {
+		struct font_entry *font = font_entry_create(token);
+
+		if (font) {
+			wl_list_insert(current, &font->link);
+			current = &font->link;
+		}
+		str = NULL;
+	}
+	free(fontlist);
+}
+
 struct theme *
-theme_create(void)
+theme_create_with_fonts(const char *fonts)
 {
 	struct theme *t;
 	cairo_t *cr;
@@ -347,6 +401,10 @@ theme_create(void)
 	if (t == NULL)
 		return NULL;
 
+	wl_list_init(&t->title_fonts);
+	insert_font_family_list(&t->title_fonts,
+		fonts ? fonts : DEFAULT_FONT_FAMILY);
+
 	t->margin = 32;
 	t->width = 6;
 	t->titlebar_height = 27;
@@ -402,25 +460,113 @@ theme_create(void)
 	return NULL;
 }
 
+struct theme *
+theme_create(void)
+{
+	return theme_create_with_fonts(NULL);
+}
+
 void
 theme_destroy(struct theme *t)
 {
+	struct font_entry *font, *next;
+
+	wl_list_for_each_safe(font, next, &t->title_fonts, link)
+		font_entry_destroy(font);
 	cairo_surface_destroy(t->active_frame);
 	cairo_surface_destroy(t->inactive_frame);
 	cairo_surface_destroy(t->shadow);
 	free(t);
 }
 
+#ifdef HAVE_PANGO
+#include <pango/pangocairo.h>
+
+#define DEFAULT_FONT_WEIGHT PANGO_WEIGHT_BOLD
+
+static void
+pango_layout_set_fallback(PangoLayout *layout, gboolean fallback)
+{
+	PangoAttrList *list = pango_layout_get_attributes(layout);
+	PangoAttrList *attr_list = list ? list : pango_attr_list_new();
+
+	if (!attr_list)
+		return;
+
+	PangoAttribute *fb_attr = pango_attr_fallback_new(fallback);
+	pango_attr_list_change(attr_list, fb_attr);
+	pango_layout_set_attributes(layout, attr_list);
+
+	if (!list)
+		pango_attr_list_unref(attr_list);
+}
+
+static PangoFontDescription *
+pango_font_description_create(const char *font,
+			double size, PangoWeight weight)
+{
+	PangoFontDescription *fontdesc =
+		pango_font_description_from_string(font);
+
+	pango_font_description_set_weight(fontdesc, weight);
+	pango_font_description_set_absolute_size(fontdesc, size * PANGO_SCALE);
+	return fontdesc;
+}
+
+static void
+pango_layout_set_best_font(PangoLayout *layout,
+		struct wl_list *fonts, const char *text)
+{
+	struct font_entry *font, *first_font = NULL, *best_font = NULL;
+
+	pango_layout_set_text(layout, text, -1);
+	pango_layout_set_fallback(layout, FALSE);
+
+	wl_list_for_each(font, fonts, link) {
+		PangoFontDescription *fontdesc =
+			pango_font_description_create(font->name,
+				DEFAULT_FONT_SIZE, DEFAULT_FONT_WEIGHT);
+
+		pango_layout_set_font_description(layout, fontdesc);
+		pango_font_description_free(fontdesc);
+		if (!pango_layout_get_unknown_glyphs_count(layout)) {
+			best_font = font;
+			break;
+		}
+
+		if (!first_font)
+			first_font = font;
+	}
+
+	if (!best_font && first_font) {
+		PangoFontDescription *fontdesc =
+			pango_font_description_create(first_font->name,
+				DEFAULT_FONT_SIZE, DEFAULT_FONT_WEIGHT);
+
+		pango_layout_set_font_description(layout, fontdesc);
+		pango_font_description_free(fontdesc);
+	}
+
+	pango_layout_set_fallback(layout, TRUE);
+}
+#endif
+
 void
 theme_render_frame(struct theme *t,
 		   cairo_t *cr, int width, int height,
 		   const char *title, struct wl_list *buttons,
 		   uint32_t flags)
 {
+	cairo_surface_t *source;
+#ifdef HAVE_PANGO
+	PangoLayout *layout = pango_cairo_create_layout(cr);
+	PangoRectangle extents;
+	int x, y, margin, top_margin;
+#else
 	cairo_text_extents_t extents;
 	cairo_font_extents_t font_extents;
-	cairo_surface_t *source;
 	int x, y, margin, top_margin;
+#endif
 
 	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
 	cairo_set_source_rgba(cr, 0, 0, 0, 0);
@@ -458,31 +604,53 @@ theme_render_frame(struct theme *t,
 		cairo_clip(cr);
 
 		cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
-		cairo_select_font_face(cr, "sans",
+#ifdef HAVE_PANGO
+		pango_layout_set_best_font(layout, &t->title_fonts, title);
+		pango_layout_get_pixel_extents(layout, NULL, &extents);
+		x = (width - extents.width) / 2;
+		y = margin + (t->titlebar_height - extents.height) / 2;
+#else
+		cairo_select_font_face(cr,
+				       font_entry_list_front(&t->title_fonts)->name,
 				       CAIRO_FONT_SLANT_NORMAL,
 				       CAIRO_FONT_WEIGHT_BOLD);
-		cairo_set_font_size(cr, 14);
+		cairo_set_font_size(cr, DEFAULT_FONT_SIZE);
 		cairo_text_extents(cr, title, &extents);
 		cairo_font_extents (cr, &font_extents);
 		x = (width - extents.width) / 2;
 		y = margin +
 			(t->titlebar_height -
-			 font_extents.ascent - font_extents.descent) / 2 +
+			font_extents.ascent - font_extents.descent) / 2 +
 			font_extents.ascent;
+#endif
 
 		if (flags & THEME_FRAME_ACTIVE) {
 			cairo_move_to(cr, x + 1, y  + 1);
 			cairo_set_source_rgb(cr, 1, 1, 1);
+#ifdef HAVE_PANGO
+			pango_cairo_show_layout(cr, layout);
+			cairo_move_to(cr, x, y);
+			cairo_set_source_rgb(cr, 0, 0, 0);
+			pango_cairo_show_layout(cr, layout);
+#else
 			cairo_show_text(cr, title);
 			cairo_move_to(cr, x, y);
 			cairo_set_source_rgb(cr, 0, 0, 0);
 			cairo_show_text(cr, title);
+#endif
 		} else {
 			cairo_move_to(cr, x, y);
 			cairo_set_source_rgb(cr, 0.4, 0.4, 0.4);
+#ifdef HAVE_PANGO
+			pango_cairo_show_layout(cr, layout);
+#else
 			cairo_show_text(cr, title);
+#endif
 		}
 	}
+#ifdef HAVE_PANGO
+	g_object_unref(layout);
+#endif
 }
 
 enum theme_location
diff --git a/shared/cairo-util.h b/shared/cairo-util.h
index 11d11d1..db10140 100644
--- a/shared/cairo-util.h
+++ b/shared/cairo-util.h
@@ -53,10 +53,15 @@ struct theme {
 	int margin;
 	int width;
 	int titlebar_height;
+	struct wl_list title_fonts;
 };
 
 struct theme *
 theme_create(void);
+
+struct theme *
+theme_create_with_fonts(const char *fonts);
+
 void
 theme_destroy(struct theme *t);
 
diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
index bf71a76..7cf002c 100644
--- a/src/compositor-wayland.c
+++ b/src/compositor-wayland.c
@@ -738,7 +738,8 @@ wayland_output_set_windowed(struct wayland_output *output)
 	struct wayland_compositor *c =
 		(struct wayland_compositor *)output->base.compositor;
 	int tlen;
-	char *title;
+	char *title, *fonts;
+	struct weston_config_section *s;
 
 	if (output->frame)
 		return 0;
@@ -755,7 +756,11 @@ wayland_output_set_windowed(struct wayland_output *output)
 	}
 
 	if (!c->theme) {
-		c->theme = theme_create();
+		s = weston_config_get_section(c->base.config, "shell", NULL, NULL);
+		weston_config_section_get_string(s, "fonts", &fonts, "");
+		c->theme = theme_create_with_fonts(fonts);
+		free(fonts);
+
 		if (!c->theme) {
 			free(title);
 			return -1;
diff --git a/weston.ini.in b/weston.ini.in
index 4fca0bb..26192da 100644
--- a/weston.ini.in
+++ b/weston.ini.in
@@ -15,6 +15,7 @@ startup-animation=fade
 #num-workspaces=6
 #cursor-theme=whiteglass
 #cursor-size=24
+#fonts=sans
 
 #lockscreen-icon=/usr/share/icons/gnome/256x256/actions/lock.png
 #lockscreen=/usr/share/backgrounds/gnome/Garden.jpg
diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c
index 4e91f9d..a1b3094 100644
--- a/xwayland/window-manager.c
+++ b/xwayland/window-manager.c
@@ -2031,6 +2031,8 @@ weston_wm_create(struct weston_xserver *wxs, int fd)
 	xcb_screen_iterator_t s;
 	uint32_t values[1];
 	xcb_atom_t supported[3];
+	char *fonts;
+	struct weston_config_section *section;
 
 	wm = zalloc(sizeof *wm);
 	if (wm == NULL)
@@ -2076,7 +2078,10 @@ weston_wm_create(struct weston_xserver *wxs, int fd)
 	xcb_composite_redirect_subwindows(wm->conn, wm->screen->root,
 					  XCB_COMPOSITE_REDIRECT_MANUAL);
 
-	wm->theme = theme_create();
+	section = weston_config_get_section(wxs->compositor->config, "shell", NULL, NULL);
+	weston_config_section_get_string(section, "fonts", &fonts, NULL);
+	wm->theme = theme_create_with_fonts(fonts);
+	free(fonts);
 
 	supported[0] = wm->atom.net_wm_moveresize;
 	supported[1] = wm->atom.net_wm_state;
-- 
2.1.2



More information about the wayland-devel mailing list