diff options
-rw-r--r-- | font-viewer/Makefile.am | 8 | ||||
-rw-r--r-- | font-viewer/sushi-font-loader.c | 207 | ||||
-rw-r--r-- | font-viewer/sushi-font-loader.h | 50 | ||||
-rw-r--r-- | font-viewer/sushi-font-widget.c | 648 | ||||
-rw-r--r-- | font-viewer/sushi-font-widget.h | 69 |
5 files changed, 980 insertions, 2 deletions
diff --git a/font-viewer/Makefile.am b/font-viewer/Makefile.am index 5dbf458c..53bd887b 100644 --- a/font-viewer/Makefile.am +++ b/font-viewer/Makefile.am @@ -4,11 +4,15 @@ AM_CPPFLAGS = $(FONT_VIEWER_CFLAGS) $(MATECC_CAPPLETS_CFLAGS) -DDIRECTORY_DIR=\" bin_PROGRAMS = mate-thumbnail-font mate-font-viewer +font_loader_SOURCES = \ + sushi-font-loader.h \ + sushi-font-loader.c + mate_thumbnail_font_LDADD = $(MATECC_CAPPLETS_LIBS) $(FONT_VIEWER_LIBS) -mate_thumbnail_font_SOURCES = ftstream-vfs.c ftstream-vfs.h font-thumbnailer.c totem-resources.c totem-resources.h +mate_thumbnail_font_SOURCES = ftstream-vfs.c ftstream-vfs.h $(font_loader_SOURCES) font-thumbnailer.c totem-resources.c totem-resources.h mate_font_viewer_LDADD = $(MATECC_CAPPLETS_LIBS) $(FONT_VIEWER_LIBS) -mate_font_viewer_SOURCES = ftstream-vfs.c ftstream-vfs.h font-view.c +mate_font_viewer_SOURCES = ftstream-vfs.c ftstream-vfs.h $(font_loader_SOURCES) sushi-font-widget.h sushi-font-widget.c font-view.c thumbnailerdir = $(datadir)/thumbnailers thumbnailer_DATA = mate-font-viewer.thumbnailer diff --git a/font-viewer/sushi-font-loader.c b/font-viewer/sushi-font-loader.c new file mode 100644 index 00000000..9ac319fd --- /dev/null +++ b/font-viewer/sushi-font-loader.c @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * The Sushi project hereby grant permission for non-gpl compatible GStreamer + * plugins to be used and distributed together with GStreamer and Sushi. This + * permission is above and beyond the permissions granted by the GPL license + * Sushi is covered by. + * + * Authors: Cosimo Cecchi <[email protected]> + * + */ + +#include "sushi-font-loader.h" + +#include <stdlib.h> +#include <ft2build.h> +#include FT_FREETYPE_H + +#include <gio/gio.h> + +typedef struct { + FT_Library library; + FT_Long face_index; + GFile *file; + GSimpleAsyncResult *result; + + gchar *face_contents; + gsize face_length; +} FontLoadJob; + +static FontLoadJob * +font_load_job_new (FT_Library library, + const gchar *uri, + GAsyncReadyCallback callback, + gpointer user_data) +{ + FontLoadJob *job = g_slice_new0 (FontLoadJob); + + job->library = library; + job->face_index = 0; + job->file = g_file_new_for_uri (uri); + job->result = g_simple_async_result_new + (NULL, callback, user_data, + sushi_new_ft_face_from_uri_async); + + g_simple_async_result_set_op_res_gpointer (job->result, job, NULL); + + return job; +} + +static void +font_load_job_free (FontLoadJob *job) +{ + g_clear_object (&job->result); + g_clear_object (&job->file); + + g_slice_free (FontLoadJob, job); +} + +static FT_Face +create_face_from_contents (FontLoadJob *job, + gchar **contents, + GError **error) +{ + FT_Error ft_error; + FT_Face retval; + + ft_error = FT_New_Memory_Face (job->library, + (const FT_Byte *) job->face_contents, + (FT_Long) job->face_length, + job->face_index, + &retval); + + if (ft_error != 0) { + g_set_error_literal (error, G_IO_ERROR, 0, + "Unable to read the font face file"); + retval = NULL; + g_free (job->face_contents); + } else { + *contents = job->face_contents; + } + + return retval; +} + +static gboolean +font_load_job_callback (gpointer user_data) +{ + FontLoadJob *job = user_data; + + g_simple_async_result_complete (job->result); + font_load_job_free (job); + + return FALSE; +} + +static void +font_load_job_do_load (FontLoadJob *job, + GError **error) +{ + gchar *contents; + gsize length; + + g_file_load_contents (job->file, NULL, + &contents, &length, NULL, error); + + if ((error != NULL) && (*error == NULL)) { + job->face_contents = contents; + job->face_length = length; + } +} + +static gboolean +font_load_job (GIOSchedulerJob *sched_job, + GCancellable *cancellable, + gpointer user_data) +{ + FontLoadJob *job = user_data; + GError *error = NULL; + + font_load_job_do_load (job, &error); + + if (error != NULL) + g_simple_async_result_take_error (job->result, error); + + g_io_scheduler_job_send_to_mainloop_async (sched_job, + font_load_job_callback, + job, NULL); + + return FALSE; +} + +/** + * sushi_new_ft_face_from_uri: (skip) + * + */ +FT_Face +sushi_new_ft_face_from_uri (FT_Library library, + const gchar *uri, + gchar **contents, + GError **error) +{ + FontLoadJob *job = NULL; + + job = font_load_job_new (library, uri, NULL, NULL); + font_load_job_do_load (job, error); + + if ((error != NULL) && (*error != NULL)) { + g_object_unref (job); + return NULL; + } + + return create_face_from_contents (job, contents, error); +} + +/** + * sushi_new_ft_face_from_uri_async: (skip) + * + */ +void +sushi_new_ft_face_from_uri_async (FT_Library library, + const gchar *uri, + GAsyncReadyCallback callback, + gpointer user_data) +{ + FontLoadJob *job = font_load_job_new (library, uri, callback, user_data); + g_io_scheduler_push_job (font_load_job, + job, NULL, + G_PRIORITY_DEFAULT, + NULL); +} + +/** + * sushi_new_ft_face_from_uri_finish: (skip) + * + */ +FT_Face +sushi_new_ft_face_from_uri_finish (GAsyncResult *result, + gchar **contents, + GError **error) +{ + FontLoadJob *job; + + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), + error)) + return NULL; + + job = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)); + + return create_face_from_contents (job, contents, error); +} + diff --git a/font-viewer/sushi-font-loader.h b/font-viewer/sushi-font-loader.h new file mode 100644 index 00000000..aa63b9b1 --- /dev/null +++ b/font-viewer/sushi-font-loader.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * The Sushi project hereby grant permission for non-gpl compatible GStreamer + * plugins to be used and distributed together with GStreamer and Sushi. This + * permission is above and beyond the permissions granted by the GPL license + * Sushi is covered by. + * + * Authors: Cosimo Cecchi <[email protected]> + * + */ + +#ifndef __SUSHI_FONT_LOADER_H__ +#define __SUSHI_FONT_LOADER_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H +#include <gio/gio.h> + +FT_Face sushi_new_ft_face_from_uri (FT_Library library, + const gchar *uri, + gchar **contents, + GError **error); + +void sushi_new_ft_face_from_uri_async (FT_Library library, + const gchar *uri, + GAsyncReadyCallback callback, + gpointer user_data); + +FT_Face sushi_new_ft_face_from_uri_finish (GAsyncResult *result, + gchar **contents, + GError **error); + +#endif /* __SUSHI_FONT_LOADER_H__ */ + diff --git a/font-viewer/sushi-font-widget.c b/font-viewer/sushi-font-widget.c new file mode 100644 index 00000000..09a4c194 --- /dev/null +++ b/font-viewer/sushi-font-widget.c @@ -0,0 +1,648 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * The Sushi project hereby grant permission for non-gpl compatible GStreamer + * plugins to be used and distributed together with GStreamer and Sushi. This + * permission is above and beyond the permissions granted by the GPL license + * Sushi is covered by. + * + * Authors: Cosimo Cecchi <[email protected]> + * + */ + +#include "sushi-font-widget.h" +#include "sushi-font-loader.h" + +#include <math.h> + +enum { + PROP_URI = 1, + NUM_PROPERTIES +}; + +enum { + LOADED, + NUM_SIGNALS +}; + +struct _SushiFontWidgetPrivate { + gchar *uri; + + FT_Library library; + FT_Face face; + gchar *face_contents; + + const gchar *lowercase_text; + const gchar *uppercase_text; + const gchar *punctuation_text; + + gchar *sample_string; + + gchar *font_name; + gboolean font_supports_title; +}; + +static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; +static guint signals[NUM_SIGNALS] = { 0, }; + +G_DEFINE_TYPE (SushiFontWidget, sushi_font_widget, GTK_TYPE_DRAWING_AREA); + +#define SURFACE_SIZE 4 +#define SECTION_SPACING 16 + +#define TITLE_SIZE 6 + +static const gchar lowercase_text_stock[] = "abcdefghijklmnopqrstuvwxyz"; +static const gchar uppercase_text_stock[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +static const gchar punctuation_text_stock[] = "0123456789.:,;(*!?')"; + +/* adapted from gnome-utils:font-viewer/font-view.c + * + * Copyright (C) 2002-2003 James Henstridge <[email protected]> + * Copyright (C) 2010 Cosimo Cecchi <[email protected]> + * + * License: GPLv2+ + */ +static void +draw_string (cairo_t *cr, + GtkBorder padding, + const gchar *text, + gint *pos_y) +{ + cairo_font_extents_t font_extents; + cairo_text_extents_t extents; + + cairo_font_extents (cr, &font_extents); + cairo_text_extents (cr, text, &extents); + + if (pos_y != NULL) + *pos_y += font_extents.ascent + font_extents.descent + + extents.y_advance + padding.top; + + cairo_move_to (cr, padding.left, *pos_y); + cairo_show_text (cr, text); + + *pos_y += padding.bottom; +} + +static gboolean +check_font_contain_text (FT_Face face, + const gchar *text) +{ + gunichar *string; + glong len, idx, map; + FT_CharMap charmap; + gboolean retval; + + string = g_utf8_to_ucs4_fast (text, -1, &len); + + for (map = 0; map < face->num_charmaps; map++) { + charmap = face->charmaps[map]; + FT_Set_Charmap (face, charmap); + + retval = TRUE; + + for (idx = 0; idx < len; idx++) { + gunichar c = string[idx]; + + if (!FT_Get_Char_Index (face, c)) { + retval = FALSE; + break; + } + } + + if (retval) + break; + } + + g_free (string); + + return retval; +} + +static gchar * +build_charlist_for_face (FT_Face face) +{ + GString *string; + gulong c; + guint glyph; + + string = g_string_new (NULL); + + /* exclude normal ASCII characters here */ + c = 255; + glyph = 0; + + do { + c = FT_Get_Next_Char (face, c, &glyph); + g_string_append_unichar (string, (gunichar) c); + } while (glyph != 0); + + return g_string_free (string, FALSE); +} + +static gchar * +random_string_from_available_chars (FT_Face face, + gint n_chars) +{ + gchar *chars; + gint idx, rand, total_chars; + GString *retval; + gchar *ptr, *end; + + idx = 0; + chars = build_charlist_for_face (face); + + retval = g_string_new (NULL); + total_chars = g_utf8_strlen (chars, -1); + + while (idx < n_chars) { + rand = g_random_int_range (0, total_chars); + + ptr = g_utf8_offset_to_pointer (chars, rand); + end = g_utf8_find_next_char (ptr, NULL); + + g_string_append_len (retval, ptr, end - ptr); + idx++; + } + + return g_string_free (retval, FALSE); +} + +static void +build_strings_for_face (SushiFontWidget *self) +{ + const gchar *sample_string; + + /* if we don't have lowercase/uppercase/punctuation text in the face, + * we omit it directly, and render a random text below. + */ + if (check_font_contain_text (self->priv->face, lowercase_text_stock)) + self->priv->lowercase_text = lowercase_text_stock; + else + self->priv->lowercase_text = NULL; + + if (check_font_contain_text (self->priv->face, uppercase_text_stock)) + self->priv->uppercase_text = uppercase_text_stock; + else + self->priv->uppercase_text = NULL; + + if (check_font_contain_text (self->priv->face, punctuation_text_stock)) + self->priv->punctuation_text = punctuation_text_stock; + else + self->priv->punctuation_text = NULL; + + sample_string = pango_language_get_sample_string (NULL); + + if (check_font_contain_text (self->priv->face, sample_string)) + self->priv->sample_string = g_strdup (sample_string); + else + self->priv->sample_string = random_string_from_available_chars (self->priv->face, 36); + + self->priv->font_name = + g_strconcat (self->priv->face->family_name, " ", + self->priv->face->style_name, NULL); + self->priv->font_supports_title = + check_font_contain_text (self->priv->face, self->priv->font_name); +} + +static gint * +build_sizes_table (FT_Face face, + gint *n_sizes, + gint *alpha_size) +{ + gint *sizes = NULL; + gint i; + + /* work out what sizes to render */ + if (FT_IS_SCALABLE (face)) { + *n_sizes = 14; + sizes = g_new (gint, *n_sizes); + sizes[0] = 8; + sizes[1] = 10; + sizes[2] = 12; + sizes[3] = 18; + sizes[4] = 24; + sizes[5] = 36; + sizes[6] = 48; + sizes[7] = 72; + sizes[8] = 96; + sizes[9] = 120; + sizes[10] = 144; + sizes[11] = 168; + sizes[12] = 192; + sizes[13] = 216; + *alpha_size = 24; + } else { + /* use fixed sizes */ + *n_sizes = face->num_fixed_sizes; + sizes = g_new (gint, *n_sizes); + *alpha_size = 0; + + for (i = 0; i < face->num_fixed_sizes; i++) { + sizes[i] = face->available_sizes[i].height; + + /* work out which font size to render */ + if (face->available_sizes[i].height <= 24) + *alpha_size = face->available_sizes[i].height; + } + } + + return sizes; +} + +static void +sushi_font_widget_size_request (GtkWidget *drawing_area, + gint *width, + gint *height, + gint *min_height) +{ + SushiFontWidget *self = SUSHI_FONT_WIDGET (drawing_area); + SushiFontWidgetPrivate *priv = self->priv; + gint i, pixmap_width, pixmap_height; + cairo_text_extents_t extents; + cairo_font_extents_t font_extents; + cairo_font_face_t *font; + gint *sizes = NULL, n_sizes, alpha_size; + cairo_t *cr; + cairo_surface_t *surface; + FT_Face face = priv->face; + GtkStyleContext *context; + GtkStateFlags state; + GtkBorder padding; + + if (face == NULL) { + if (width != NULL) + *width = 1; + if (height != NULL) + *height = 1; + if (min_height != NULL) + *min_height = 1; + + return; + } + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + SURFACE_SIZE, SURFACE_SIZE); + cr = cairo_create (surface); + context = gtk_widget_get_style_context (drawing_area); + state = gtk_style_context_get_state (context); + gtk_style_context_get_padding (context, state, &padding); + + sizes = build_sizes_table (face, &n_sizes, &alpha_size); + + /* calculate size of pixmap to use */ + pixmap_width = padding.left + padding.right; + pixmap_height = 0; + + font = cairo_ft_font_face_create_for_ft_face (face, 0); + cairo_set_font_face (cr, font); + cairo_font_face_destroy (font); + + if (self->priv->font_supports_title) { + cairo_set_font_size (cr, sizes[TITLE_SIZE]); + cairo_font_extents (cr, &font_extents); + cairo_text_extents (cr, self->priv->font_name, &extents); + pixmap_height += font_extents.ascent + font_extents.descent + + extents.y_advance + padding.top + padding.bottom; + pixmap_width = MAX (pixmap_width, extents.width + padding.left + padding.right); + } + + pixmap_height += SECTION_SPACING / 2; + cairo_set_font_size (cr, alpha_size); + cairo_font_extents (cr, &font_extents); + + if (self->priv->lowercase_text != NULL) { + cairo_text_extents (cr, self->priv->lowercase_text, &extents); + pixmap_height += font_extents.ascent + font_extents.descent + + extents.y_advance + padding.top + padding.bottom; + pixmap_width = MAX (pixmap_width, extents.width + padding.left + padding.right); + } + + if (self->priv->uppercase_text != NULL) { + cairo_text_extents (cr, self->priv->uppercase_text, &extents); + pixmap_height += font_extents.ascent + font_extents.descent + + extents.y_advance + padding.top + padding.bottom; + pixmap_width = MAX (pixmap_width, extents.width + padding.left + padding.right); + } + + if (self->priv->punctuation_text != NULL) { + cairo_text_extents (cr, self->priv->punctuation_text, &extents); + pixmap_height += font_extents.ascent + font_extents.descent + + extents.y_advance + padding.top + padding.bottom; + pixmap_width = MAX (pixmap_width, extents.width + padding.left + padding.right); + } + + pixmap_height += SECTION_SPACING; + + for (i = 0; i < n_sizes; i++) { + cairo_set_font_size (cr, sizes[i]); + cairo_font_extents (cr, &font_extents); + cairo_text_extents (cr, self->priv->sample_string, &extents); + pixmap_height += font_extents.ascent + font_extents.descent + + extents.y_advance + padding.top + padding.bottom; + pixmap_width = MAX (pixmap_width, extents.width + padding.left + padding.right); + + if ((i == 7) && (min_height != NULL)) + *min_height = pixmap_height; + } + + pixmap_height += padding.bottom + SECTION_SPACING; + + if (width != NULL) + *width = pixmap_width; + + if (height != NULL) + *height = pixmap_height; + + cairo_destroy (cr); + cairo_surface_destroy (surface); + g_free (sizes); +} + +static void +sushi_font_widget_get_preferred_width (GtkWidget *drawing_area, + gint *minimum_width, + gint *natural_width) +{ + gint width; + + sushi_font_widget_size_request (drawing_area, &width, NULL, NULL); + + *minimum_width = *natural_width = width; +} + +static void +sushi_font_widget_get_preferred_height (GtkWidget *drawing_area, + gint *minimum_height, + gint *natural_height) +{ + gint height, min_height; + + sushi_font_widget_size_request (drawing_area, NULL, &height, &min_height); + + *minimum_height = min_height; + *natural_height = height; +} + +static gboolean +sushi_font_widget_draw (GtkWidget *drawing_area, + cairo_t *cr) +{ + SushiFontWidget *self = SUSHI_FONT_WIDGET (drawing_area); + SushiFontWidgetPrivate *priv = self->priv; + gint *sizes = NULL, n_sizes, alpha_size, pos_y = 0, i; + cairo_font_face_t *font; + FT_Face face = priv->face; + GtkStyleContext *context; + GdkRGBA color; + GtkBorder padding; + GtkStateFlags state; + gint allocated_height; + + if (face == NULL) + goto end; + + context = gtk_widget_get_style_context (drawing_area); + state = gtk_style_context_get_state (context); + gtk_style_context_get_color (context, state, &color); + gtk_style_context_get_padding (context, state, &padding); + + gdk_cairo_set_source_rgba (cr, &color); + + sizes = build_sizes_table (face, &n_sizes, &alpha_size); + + font = cairo_ft_font_face_create_for_ft_face (face, 0); + cairo_set_font_face (cr, font); + cairo_font_face_destroy (font); + + allocated_height = gtk_widget_get_allocated_height (drawing_area); + + /* draw text */ + + if (self->priv->font_supports_title) { + cairo_set_font_size (cr, sizes[TITLE_SIZE]); + draw_string (cr, padding, self->priv->font_name, &pos_y); + } + + if (pos_y > allocated_height) + goto end; + + pos_y += SECTION_SPACING / 2; + cairo_set_font_size (cr, alpha_size); + + if (self->priv->lowercase_text != NULL) + draw_string (cr, padding, self->priv->lowercase_text, &pos_y); + if (pos_y > allocated_height) + goto end; + + if (self->priv->uppercase_text != NULL) + draw_string (cr, padding, self->priv->uppercase_text, &pos_y); + if (pos_y > allocated_height) + goto end; + + if (self->priv->punctuation_text != NULL) + draw_string (cr, padding, self->priv->punctuation_text, &pos_y); + if (pos_y > allocated_height) + goto end; + + pos_y += SECTION_SPACING; + + for (i = 0; i < n_sizes; i++) { + cairo_set_font_size (cr, sizes[i]); + draw_string (cr, padding, self->priv->sample_string, &pos_y); + if (pos_y > allocated_height) + break; + } + + end: + g_free (sizes); + + return FALSE; +} + +static void +font_face_async_ready_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + SushiFontWidget *self = user_data; + GError *error = NULL; + + self->priv->face = + sushi_new_ft_face_from_uri_finish (result, + &self->priv->face_contents, + &error); + + if (error != NULL) { + /* FIXME: need to signal the error */ + g_print ("Can't load the font face: %s\n", error->message); + g_error_free (error); + + return; + } + + build_strings_for_face (self); + + gtk_widget_queue_resize (GTK_WIDGET (self)); + g_signal_emit (self, signals[LOADED], 0); +} + +static void +load_font_face (SushiFontWidget *self) +{ + sushi_new_ft_face_from_uri_async (self->priv->library, + self->priv->uri, + font_face_async_ready_cb, + self); +} + +static void +sushi_font_widget_set_uri (SushiFontWidget *self, + const gchar *uri) +{ + g_free (self->priv->uri); + self->priv->uri = g_strdup (uri); + + load_font_face (self); +} + +static void +sushi_font_widget_init (SushiFontWidget *self) +{ + FT_Error err; + + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, SUSHI_TYPE_FONT_WIDGET, + SushiFontWidgetPrivate); + + self->priv->face = NULL; + err = FT_Init_FreeType (&self->priv->library); + + if (err != FT_Err_Ok) + g_error ("Unable to initialize FreeType"); +} + +static void +sushi_font_widget_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SushiFontWidget *self = SUSHI_FONT_WIDGET (object); + + switch (prop_id) { + case PROP_URI: + g_value_set_string (value, self->priv->uri); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +sushi_font_widget_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + SushiFontWidget *self = SUSHI_FONT_WIDGET (object); + + switch (prop_id) { + case PROP_URI: + sushi_font_widget_set_uri (self, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +sushi_font_widget_finalize (GObject *object) +{ + SushiFontWidget *self = SUSHI_FONT_WIDGET (object); + + g_free (self->priv->uri); + + if (self->priv->face != NULL) { + FT_Done_Face (self->priv->face); + self->priv->face = NULL; + } + + g_free (self->priv->font_name); + g_free (self->priv->sample_string); + g_free (self->priv->face_contents); + + if (self->priv->library != NULL) { + FT_Done_FreeType (self->priv->library); + self->priv->library = NULL; + } + + G_OBJECT_CLASS (sushi_font_widget_parent_class)->finalize (object); +} + +static void +sushi_font_widget_class_init (SushiFontWidgetClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + GtkWidgetClass *wclass = GTK_WIDGET_CLASS (klass); + + oclass->finalize = sushi_font_widget_finalize; + oclass->set_property = sushi_font_widget_set_property; + oclass->get_property = sushi_font_widget_get_property; + + wclass->draw = sushi_font_widget_draw; + wclass->get_preferred_width = sushi_font_widget_get_preferred_width; + wclass->get_preferred_height = sushi_font_widget_get_preferred_height; + + properties[PROP_URI] = + g_param_spec_string ("uri", + "Uri", "Uri", + NULL, G_PARAM_READWRITE); + + signals[LOADED] = + g_signal_new ("loaded", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); + g_type_class_add_private (klass, sizeof (SushiFontWidgetPrivate)); +} + +SushiFontWidget * +sushi_font_widget_new (const gchar *uri) +{ + return g_object_new (SUSHI_TYPE_FONT_WIDGET, + "uri", uri, + NULL); +} + +/** + * sushi_font_widget_get_ft_face: (skip) + * + */ +FT_Face +sushi_font_widget_get_ft_face (SushiFontWidget *self) +{ + return self->priv->face; +} + diff --git a/font-viewer/sushi-font-widget.h b/font-viewer/sushi-font-widget.h new file mode 100644 index 00000000..d50b734f --- /dev/null +++ b/font-viewer/sushi-font-widget.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * The Sushi project hereby grant permission for non-gpl compatible GStreamer + * plugins to be used and distributed together with GStreamer and Sushi. This + * permission is above and beyond the permissions granted by the GPL license + * Sushi is covered by. + * + * Authors: Cosimo Cecchi <[email protected]> + * + */ + +#ifndef __SUSHI_FONT_WIDGET_H__ +#define __SUSHI_FONT_WIDGET_H__ + +#include <glib-object.h> +#include <gtk/gtk.h> +#include <cairo/cairo-ft.h> + +G_BEGIN_DECLS + +#define SUSHI_TYPE_FONT_WIDGET (sushi_font_widget_get_type ()) +#define SUSHI_FONT_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SUSHI_TYPE_FONT_WIDGET, SushiFontWidget)) +#define SUSHI_IS_FONT_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SUSHI_TYPE_FONT_WIDGET)) +#define SUSHI_FONT_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SUSHI_TYPE_FONT_WIDGET, SushiFontWidgetClass)) +#define SUSHI_IS_FONT_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SUSHI_TYPE_FONT_WIDGET)) +#define SUSHI_FONT_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SUSHI_TYPE_FONT_WIDGET, SushiFontWidgetClass)) + +typedef struct _SushiFontWidget SushiFontWidget; +typedef struct _SushiFontWidgetPrivate SushiFontWidgetPrivate; +typedef struct _SushiFontWidgetClass SushiFontWidgetClass; + +struct _SushiFontWidget +{ + GtkDrawingArea parent_instance; + + SushiFontWidgetPrivate *priv; +}; + +struct _SushiFontWidgetClass +{ + GtkDrawingAreaClass parent_class; +}; + +GType sushi_font_widget_get_type (void) G_GNUC_CONST; + +SushiFontWidget *sushi_font_widget_new (const gchar *uri); + +FT_Face sushi_font_widget_get_ft_face (SushiFontWidget *self); + +G_END_DECLS + +#endif /* __SUSHI_FONT_WIDGET_H__ */ + |