/* * 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 * */ #include "sushi-font-loader.h" #include #include #include FT_FREETYPE_H #include typedef struct { FT_Library library; FT_Long face_index; GFile *file; gchar *face_contents; gsize face_length; } FontLoadJob; static FontLoadJob * font_load_job_new (FT_Library library, const gchar *uri, gint face_index, GAsyncReadyCallback callback, gpointer user_data) { FontLoadJob *job = g_slice_new0 (FontLoadJob); job->library = library; job->face_index = (FT_Long) face_index; job->file = g_file_new_for_uri (uri); return job; } static void font_load_job_free (FontLoadJob *job) { 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) { gchar *uri; uri = g_file_get_uri (job->file); g_set_error (error, G_IO_ERROR, 0, "Unable to read the font face file '%s'", uri); retval = NULL; g_free (job->face_contents); g_free (uri); } else { *contents = job->face_contents; } return retval; } 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 void font_load_job (GTask *task, gpointer source_object, gpointer user_data, GCancellable *cancellable) { FontLoadJob *job = user_data; GError *error = NULL; font_load_job_do_load (job, &error); if (error != NULL) g_task_return_error (task, error); else g_task_return_boolean (task, TRUE); } /** * sushi_new_ft_face_from_uri: (skip) * */ FT_Face sushi_new_ft_face_from_uri (FT_Library library, const gchar *uri, gint face_index, gchar **contents, GError **error) { FontLoadJob *job = NULL; FT_Face face; job = font_load_job_new (library, uri, face_index, NULL, NULL); font_load_job_do_load (job, error); if ((error != NULL) && (*error != NULL)) { font_load_job_free (job); return NULL; } face = create_face_from_contents (job, contents, error); font_load_job_free (job); return face; } /** * sushi_new_ft_face_from_uri_async: (skip) * */ void sushi_new_ft_face_from_uri_async (FT_Library library, const gchar *uri, gint face_index, GAsyncReadyCallback callback, gpointer user_data) { FontLoadJob *job = font_load_job_new (library, uri, face_index, callback, user_data); GTask *task; task = g_task_new (NULL, NULL, callback, user_data); g_task_set_task_data (task, job, (GDestroyNotify) font_load_job_free); g_task_run_in_thread (task, font_load_job); g_object_unref (task); } /** * 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_task_propagate_boolean (G_TASK (result), error)) return NULL; job = g_task_get_task_data (G_TASK (result)); return create_face_from_contents (job, contents, error); }