From 2a73e722a55bc8e2dd2a6159b9d9ea107d8924fd Mon Sep 17 00:00:00 2001 From: Roy Zhang Date: Tue, 18 Aug 2015 23:25:57 +0800 Subject: appearance-font: Use pango and cairo to rander fonts This patch fixes #135 --- capplets/appearance/appearance-font.c | 308 ++++++++++------------------------ 1 file changed, 85 insertions(+), 223 deletions(-) diff --git a/capplets/appearance/appearance-font.c b/capplets/appearance/appearance-font.c index 21d41e58..19583a4f 100644 --- a/capplets/appearance/appearance-font.c +++ b/capplets/appearance/appearance-font.c @@ -25,17 +25,11 @@ #include #include -#ifdef HAVE_XFT2 - #include - #include -#endif /* HAVE_XFT2 */ - #include #include #include "capplet-util.h" -#ifdef HAVE_XFT2 /* X servers sometimes lie about the screen's physical dimensions, so we cannot * compute an accurate DPI value. When this happens, the user gets fonts that * are too huge or too tiny. So, we see what the server returns: if it reports @@ -49,61 +43,40 @@ #define DPI_FALLBACK 96 #define DPI_LOW_REASONABLE_VALUE 50 #define DPI_HIGH_REASONABLE_VALUE 500 -#endif /* HAVE_XFT2 */ static gboolean in_change = FALSE; -#define MAX_FONT_POINT_WITHOUT_WARNING 32 -#define MAX_FONT_SIZE_WITHOUT_WARNING MAX_FONT_POINT_WITHOUT_WARNING * 1024 - -#ifdef HAVE_XFT2 - -#if !GTK_CHECK_VERSION (3, 0, 0) -/* - * Code for displaying previews of font rendering with various Xft options - */ - -static void sample_size_request(GtkWidget* darea, GtkRequisition* requisition) -{ - GdkPixbuf* pixbuf = g_object_get_data(G_OBJECT(darea), "sample-pixbuf"); - - requisition->width = gdk_pixbuf_get_width(pixbuf) + 2; - requisition->height = gdk_pixbuf_get_height(pixbuf) + 2; -} -#endif - #if GTK_CHECK_VERSION (3, 0, 0) static void sample_draw(GtkWidget* darea, cairo_t* cr) #else static void sample_expose(GtkWidget* darea, GdkEventExpose* expose) #endif { + cairo_surface_t* surface = g_object_get_data(G_OBJECT(darea), "sample-surface"); GtkAllocation allocation; - GdkPixbuf* pixbuf = g_object_get_data(G_OBJECT(darea), "sample-pixbuf"); - int width = gdk_pixbuf_get_width(pixbuf); - int height = gdk_pixbuf_get_height(pixbuf); + int x, y, w, h; gtk_widget_get_allocation (darea, &allocation); - int x = (allocation.width - width) / 2; - int y = (allocation.height - height) / 2; - - GdkColor black, white; - gdk_color_parse ("black", &black); - gdk_color_parse ("white", &white); + x = allocation.width; + y = allocation.height; + w = cairo_image_surface_get_width (surface); + h = cairo_image_surface_get_height (surface); #if !GTK_CHECK_VERSION (3, 0, 0) cairo_t *cr = gdk_cairo_create (expose->window); #endif + cairo_set_line_width (cr, 1); cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); - gdk_cairo_set_source_color (cr, &white); - cairo_rectangle (cr, 0, 0, allocation.width, allocation.height); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + cairo_rectangle (cr, 0, 0, x, y); cairo_fill_preserve (cr); - gdk_cairo_set_source_color (cr, &black); + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); cairo_stroke (cr); - gdk_cairo_set_source_pixbuf(cr, pixbuf, x, y); + cairo_set_source_surface (cr, surface, (x - w) / 2, (y - h) / 2); + cairo_paint(cr); #if !GTK_CHECK_VERSION (3, 0, 0) @@ -131,203 +104,99 @@ typedef enum { RGBA_VBGR } RgbaOrder; -static XftFont* open_pattern(FcPattern* pattern, Antialiasing antialiasing, Hinting hinting) +static void set_fontoptions(PangoContext *context, Antialiasing antialiasing, Hinting hinting) { - #ifdef FC_HINT_STYLE - static const int hintstyles[] = { - FC_HINT_NONE, FC_HINT_SLIGHT, FC_HINT_MEDIUM, FC_HINT_FULL - }; - #endif /* FC_HINT_STYLE */ - - FcPattern* res_pattern; - FcResult result; - XftFont* font; - - Display* xdisplay = gdk_x11_get_default_xdisplay(); - int screen = gdk_x11_get_default_screen(); - - res_pattern = XftFontMatch(xdisplay, screen, pattern, &result); + cairo_font_options_t *opt; + cairo_antialias_t aa; + cairo_hint_style_t hs; - if (res_pattern == NULL) - { - return NULL; + switch (antialiasing) { + case ANTIALIAS_NONE: + aa = CAIRO_ANTIALIAS_NONE; + break; + case ANTIALIAS_GRAYSCALE: + aa = CAIRO_ANTIALIAS_GRAY; + break; + case ANTIALIAS_RGBA: + aa = CAIRO_ANTIALIAS_SUBPIXEL; + break; + default: + aa = CAIRO_ANTIALIAS_DEFAULT; + break; } - FcPatternDel(res_pattern, FC_HINTING); - FcPatternAddBool(res_pattern, FC_HINTING, hinting != HINT_NONE); - - #ifdef FC_HINT_STYLE - FcPatternDel(res_pattern, FC_HINT_STYLE); - FcPatternAddInteger(res_pattern, FC_HINT_STYLE, hintstyles[hinting]); - #endif /* FC_HINT_STYLE */ - - FcPatternDel(res_pattern, FC_ANTIALIAS); - FcPatternAddBool(res_pattern, FC_ANTIALIAS, antialiasing != ANTIALIAS_NONE); - - FcPatternDel(res_pattern, FC_RGBA); - FcPatternAddInteger(res_pattern, FC_RGBA, antialiasing == ANTIALIAS_RGBA ? FC_RGBA_RGB : FC_RGBA_NONE); - - FcPatternDel(res_pattern, FC_DPI); - FcPatternAddInteger(res_pattern, FC_DPI, 96); - - font = XftFontOpenPattern(xdisplay, res_pattern); - - if (!font) - { - FcPatternDestroy(res_pattern); + switch (hinting) { + case HINT_NONE: + hs = CAIRO_HINT_STYLE_NONE; + break; + case HINT_SLIGHT: + hs = CAIRO_HINT_STYLE_SLIGHT; + break; + case HINT_MEDIUM: + hs = CAIRO_HINT_STYLE_MEDIUM; + break; + case HINT_FULL: + hs = CAIRO_HINT_STYLE_FULL; + break; + default: + hs = CAIRO_HINT_STYLE_DEFAULT; + break; } - return font; + opt = cairo_font_options_create (); + cairo_font_options_set_antialias (opt, aa); + cairo_font_options_set_hint_style (opt, hs); + pango_cairo_context_set_font_options (context, opt); + cairo_font_options_destroy (opt); } static void setup_font_sample(GtkWidget* darea, Antialiasing antialiasing, Hinting hinting) { - const char* string1 = "abcfgop AO "; - const char* string2 = "abcfgop"; - - XftColor black, white; - XRenderColor rendcolor; - - Display* xdisplay = gdk_x11_get_default_xdisplay(); - -#if GTK_CHECK_VERSION (3, 0, 0) - Colormap xcolormap = DefaultColormap(xdisplay, 0); -#else - GdkColormap* colormap = gdk_rgb_get_colormap(); - Colormap xcolormap = GDK_COLORMAP_XCOLORMAP(colormap); -#endif - -#if GTK_CHECK_VERSION (3, 0, 0) - GdkVisual* visual = gdk_visual_get_system (); -#else - GdkVisual* visual = gdk_colormap_get_visual(colormap); -#endif - Visual* xvisual = GDK_VISUAL_XVISUAL(visual); - - FcPattern* pattern; - XftFont* font1; - XftFont* font2; - XGlyphInfo extents1 = { 0 }; - XGlyphInfo extents2 = { 0 }; -#if !GTK_CHECK_VERSION (3, 0, 0) - GdkPixmap* pixmap; -#endif - XftDraw* draw; - GdkPixbuf* tmp_pixbuf; - GdkPixbuf* pixbuf; - + const char *str = "abcfgop AO " + "abcfgop"; + + PangoContext *context; + PangoLayout *layout; + PangoFontDescription *fd; + PangoRectangle extents; + cairo_surface_t *surface; + cairo_t *cr; int width, height; - int ascent, descent; - - pattern = FcPatternBuild (NULL, - FC_FAMILY, FcTypeString, "Serif", - FC_SLANT, FcTypeInteger, FC_SLANT_ROMAN, - FC_SIZE, FcTypeDouble, 18., - NULL); - font1 = open_pattern (pattern, antialiasing, hinting); - FcPatternDestroy (pattern); - - pattern = FcPatternBuild (NULL, - FC_FAMILY, FcTypeString, "Serif", - FC_SLANT, FcTypeInteger, FC_SLANT_ITALIC, - FC_SIZE, FcTypeDouble, 20., - NULL); - font2 = open_pattern (pattern, antialiasing, hinting); - FcPatternDestroy (pattern); - - ascent = 0; - descent = 0; - - if (font1) - { - XftTextExtentsUtf8 (xdisplay, font1, (unsigned char*) string1, - strlen (string1), &extents1); - ascent = MAX (ascent, font1->ascent); - descent = MAX (descent, font1->descent); - } - - if (font2) - { - XftTextExtentsUtf8 (xdisplay, font2, (unsigned char*) string2, strlen (string2), &extents2); - ascent = MAX (ascent, font2->ascent); - descent = MAX (descent, font2->descent); - } - - width = extents1.xOff + extents2.xOff + 4; - height = ascent + descent + 2; - -#if !GTK_CHECK_VERSION (3, 0, 0) - pixmap = gdk_pixmap_new (NULL, width, height, gdk_visual_get_depth (visual)); -#endif - -#if GTK_CHECK_VERSION (3, 0, 0) - draw = XftDrawCreate (xdisplay, GDK_WINDOW_XID (gdk_screen_get_root_window (gdk_screen_get_default ())), xvisual, xcolormap); -#else - draw = XftDrawCreate (xdisplay, GDK_DRAWABLE_XID (pixmap), xvisual, xcolormap); -#endif - rendcolor.red = 0; - rendcolor.green = 0; - rendcolor.blue = 0; - rendcolor.alpha = 0xffff; - - XftColorAllocValue(xdisplay, xvisual, xcolormap, &rendcolor, &black); + context = gtk_widget_get_pango_context (darea); + set_fontoptions (context, antialiasing, hinting); + layout = pango_layout_new (context); - rendcolor.red = 0xffff; - rendcolor.green = 0xffff; - rendcolor.blue = 0xffff; - rendcolor.alpha = 0xffff; - - XftColorAllocValue(xdisplay, xvisual, xcolormap, &rendcolor, &white); - XftDrawRect(draw, &white, 0, 0, width, height); - - if (font1) - { - XftDrawStringUtf8(draw, &black, font1, 2, 2 + ascent, (unsigned char*) string1, strlen(string1)); - } - - if (font2) - { - XftDrawStringUtf8(draw, &black, font2, 2 + extents1.xOff, 2 + ascent, (unsigned char*) string2, strlen(string2)); - } + fd = pango_font_description_from_string ("Serif"); + pango_layout_set_font_description (layout, fd); + pango_font_description_free (fd); - XftDrawDestroy(draw); + pango_layout_set_markup (layout, str, -1); - if (font1) - { - XftFontClose(xdisplay, font1); - } - - if (font2) - { - XftFontClose(xdisplay, font2); - } + pango_layout_get_extents (layout, NULL, &extents); + width = PANGO_PIXELS(extents.width) + 4; + height = PANGO_PIXELS(extents.height) + 2; -#if GTK_CHECK_VERSION (3, 0, 0) - tmp_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE,8, width, height); -#else - tmp_pixbuf = gdk_pixbuf_get_from_drawable(NULL, pixmap, colormap, 0, 0, 0, 0, width, height); -#endif - pixbuf = gdk_pixbuf_scale_simple(tmp_pixbuf, 1 * width, 1 * height, GDK_INTERP_TILES); + surface = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); + cr = cairo_create (surface); -#if !GTK_CHECK_VERSION (3, 0, 0) - g_object_unref(pixmap); -#endif - g_object_unref(tmp_pixbuf); + cairo_move_to (cr, 2, 1); + pango_cairo_show_layout (cr, layout); + g_object_unref (layout); + cairo_destroy (cr); - g_object_set_data_full(G_OBJECT(darea), "sample-pixbuf", pixbuf, (GDestroyNotify) g_object_unref); + g_object_set_data_full(G_OBJECT(darea), "sample-surface", surface, (GDestroyNotify) cairo_surface_destroy); + gtk_widget_set_size_request (GTK_WIDGET(darea), width + 2, height + 2); #if GTK_CHECK_VERSION (3, 0, 0) - gtk_widget_set_size_request (GTK_WIDGET(darea), width + 2, height + 2); g_signal_connect(darea, "draw", G_CALLBACK(sample_draw), NULL); #else - g_signal_connect(darea, "size_request", G_CALLBACK(sample_size_request), NULL); g_signal_connect(darea, "expose_event", G_CALLBACK(sample_expose), NULL); #endif } /* - * Code implementing a group of radio buttons with different Xft option combinations. + * Code implementing a group of radio buttons with different cairo option combinations. * If one of the buttons is matched by the GSettings key, we pick it. Otherwise we * show the group as inconsistent. */ @@ -414,7 +283,6 @@ setup_font_pair (GtkWidget *radio, g_signal_connect (radio, "toggled", G_CALLBACK (font_radio_toggled), pair); } -#endif /* HAVE_XFT2 */ static void marco_titlebar_load_sensitivity (AppearanceData *data) @@ -432,7 +300,6 @@ marco_changed (GSettings *settings, marco_titlebar_load_sensitivity (user_data); } -#ifdef HAVE_XFT2 /* * EnumGroup - a group of radio buttons for a gsettings enum */ @@ -735,7 +602,6 @@ cb_show_details (GtkWidget *button, gtk_window_present (GTK_WINDOW (data->font_details)); } -#endif /* HAVE_XFT2 */ void font_init(AppearanceData* data) { @@ -790,20 +656,16 @@ void font_init(AppearanceData* data) marco_titlebar_load_sensitivity(data); - #ifdef HAVE_XFT2 - setup_font_pair(appearance_capplet_get_widget(data, "monochrome_radio"), appearance_capplet_get_widget (data, "monochrome_sample"), ANTIALIAS_NONE, HINT_FULL); - setup_font_pair(appearance_capplet_get_widget(data, "best_shapes_radio"), appearance_capplet_get_widget (data, "best_shapes_sample"), ANTIALIAS_GRAYSCALE, HINT_MEDIUM); - setup_font_pair(appearance_capplet_get_widget(data, "best_contrast_radio"), appearance_capplet_get_widget (data, "best_contrast_sample"), ANTIALIAS_GRAYSCALE, HINT_FULL); - setup_font_pair(appearance_capplet_get_widget(data, "subpixel_radio"), appearance_capplet_get_widget (data, "subpixel_sample"), ANTIALIAS_RGBA, HINT_FULL); + setup_font_pair(appearance_capplet_get_widget(data, "monochrome_radio"), appearance_capplet_get_widget (data, "monochrome_sample"), ANTIALIAS_NONE, HINT_FULL); + setup_font_pair(appearance_capplet_get_widget(data, "best_shapes_radio"), appearance_capplet_get_widget (data, "best_shapes_sample"), ANTIALIAS_GRAYSCALE, HINT_MEDIUM); + setup_font_pair(appearance_capplet_get_widget(data, "best_contrast_radio"), appearance_capplet_get_widget (data, "best_contrast_sample"), ANTIALIAS_GRAYSCALE, HINT_FULL); + setup_font_pair(appearance_capplet_get_widget(data, "subpixel_radio"), appearance_capplet_get_widget (data, "subpixel_sample"), ANTIALIAS_RGBA, HINT_FULL); - font_render_load (data->font_settings); + font_render_load (data->font_settings); - g_signal_connect (data->font_settings, "changed", G_CALLBACK (font_render_changed), NULL); + g_signal_connect (data->font_settings, "changed", G_CALLBACK (font_render_changed), NULL); - g_signal_connect (appearance_capplet_get_widget (data, "details_button"), "clicked", G_CALLBACK (cb_show_details), data); - #else /* !HAVE_XFT2 */ - gtk_widget_hide (appearance_capplet_get_widget (data, "font_render_frame")); - #endif /* HAVE_XFT2 */ + g_signal_connect (appearance_capplet_get_widget (data, "details_button"), "clicked", G_CALLBACK (cb_show_details), data); } void font_shutdown(AppearanceData* data) -- cgit v1.2.1