initial checkin
This commit is contained in:
parent
c7fa2a7909
commit
92e7e7a7ff
7 changed files with 1043 additions and 0 deletions
9
vfs-methods/fontilus/.cvsignore
Normal file
9
vfs-methods/fontilus/.cvsignore
Normal file
|
@ -0,0 +1,9 @@
|
|||
Makefile
|
||||
Makefile.in
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
*.so
|
||||
.libs
|
||||
.deps
|
||||
thumbnailer
|
0
vfs-methods/fontilus/ChangeLog
Normal file
0
vfs-methods/fontilus/ChangeLog
Normal file
14
vfs-methods/fontilus/Makefile.am
Normal file
14
vfs-methods/fontilus/Makefile.am
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
INCLUDES = $(FONT_METHOD_CFLAGS) $(THUMBNAILER_CFLAGS)
|
||||
|
||||
moduledir = $(libdir)/gnome-vfs-2.0/modules
|
||||
module_LTLIBRARIES = libfont-method.la
|
||||
|
||||
noinst_PROGRAMS = thumbnailer
|
||||
|
||||
libfont_method_la_LDFLAGS = -module -avoid-version
|
||||
libfont_method_la_LIBS = $(FONT_METHOD_LIBS)
|
||||
libfont_method_la_SOURCES = font-method.c
|
||||
|
||||
thumbnailer_LDADD = $(THUMBNAILER_LIBS)
|
||||
thumbnailer_SOURCES = ftstream-vfs.c thumbnailer.c
|
754
vfs-methods/fontilus/font-method.c
Normal file
754
vfs-methods/fontilus/font-method.c
Normal file
|
@ -0,0 +1,754 @@
|
|||
/* -*- mode: C; c-basic-offset: 4 -*- */
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <fontconfig/fontconfig.h>
|
||||
|
||||
#include <libgnomevfs/gnome-vfs.h>
|
||||
#include <libgnomevfs/gnome-vfs-cancellable-ops.h>
|
||||
#include <libgnomevfs/gnome-vfs-module.h>
|
||||
|
||||
/* this is from gnome-vfs-monitor-private.h */
|
||||
void gnome_vfs_monitor_callback (GnomeVFSMethodHandle *method_handle,
|
||||
GnomeVFSURI *info_uri,
|
||||
GnomeVFSMonitorEventType event_type);
|
||||
|
||||
static void invoke_monitors(void);
|
||||
|
||||
/* -------- code for creating the font list -------- */
|
||||
|
||||
/* list of fonts in fontconfig database */
|
||||
G_LOCK_DEFINE_STATIC(font_list);
|
||||
static FcFontSet *font_list = NULL;
|
||||
static gchar **font_names = NULL;
|
||||
static GHashTable *font_hash = NULL;
|
||||
|
||||
static gchar *
|
||||
get_pango_name(FcPattern *pat)
|
||||
{
|
||||
FcChar8 *family;
|
||||
GString *str;
|
||||
gint i;
|
||||
|
||||
FcPatternGetString(pat, FC_FAMILY, 0, &family);
|
||||
str = g_string_new(family);
|
||||
g_string_append_c(str, ',');
|
||||
|
||||
/* add weight word */
|
||||
if (FcPatternGetInteger(pat, FC_WEIGHT, 0, &i) == FcResultMatch) {
|
||||
gchar *weight = NULL;
|
||||
|
||||
if (i < FC_WEIGHT_LIGHT)
|
||||
weight = " Ultra-Light";
|
||||
else if (i < (FC_WEIGHT_LIGHT + FC_WEIGHT_MEDIUM) / 2)
|
||||
weight = " Light";
|
||||
else if (i < (FC_WEIGHT_MEDIUM + FC_WEIGHT_DEMIBOLD) / 2)
|
||||
weight = NULL;
|
||||
else if (i < (FC_WEIGHT_DEMIBOLD + FC_WEIGHT_BOLD) / 2)
|
||||
weight = " Semi-Bold";
|
||||
else if (i < (FC_WEIGHT_BOLD + FC_WEIGHT_BLACK) / 2)
|
||||
weight = " Bold";
|
||||
else
|
||||
weight = " Ultra-Bold";
|
||||
|
||||
if (weight)
|
||||
g_string_append(str, weight);
|
||||
}
|
||||
|
||||
/* add slant word */
|
||||
if (FcPatternGetInteger(pat, FC_SLANT, 0, &i) == FcResultMatch) {
|
||||
gchar *style = NULL;
|
||||
|
||||
if (i == FC_SLANT_ROMAN)
|
||||
style = NULL;
|
||||
else if (i == FC_SLANT_OBLIQUE)
|
||||
style = " Oblique";
|
||||
else
|
||||
style = " Italic";
|
||||
|
||||
if (style)
|
||||
g_string_append(str, style);
|
||||
}
|
||||
|
||||
/* if ends in a comma, check to see if the last word matches a modifier.
|
||||
* if not, remove the comma. */
|
||||
if (str->str[str->len-1] == ',') {
|
||||
const gchar *lastword;
|
||||
gint wordlen, i;
|
||||
gboolean word_matches;
|
||||
const char *modifier_words[] = {
|
||||
"Oblique", "Italic", "Small-Caps", "Ultra-Light", "Light",
|
||||
"Medium", "Semi-Bold", "Bold", "Ultra-Bold", "Heavy",
|
||||
"Ultra-Condensed", "Extra-Condensed", "Condensed",
|
||||
"Semi-Condensed", "Semi-Expanded", "Expanded",
|
||||
"Extra-Expanded", "Ultra-Expanded" };
|
||||
|
||||
lastword = strrchr(str->str, ' ');
|
||||
if (lastword)
|
||||
lastword++;
|
||||
else
|
||||
lastword = str->str;
|
||||
wordlen = strlen(lastword) - 1; /* exclude comma */
|
||||
|
||||
word_matches = FALSE;
|
||||
for (i = 0; i < G_N_ELEMENTS(modifier_words); i++) {
|
||||
if (g_ascii_strncasecmp(modifier_words[i], lastword, wordlen)==0) {
|
||||
word_matches = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if the last word doesn't match, then we can remove the comma */
|
||||
if (!word_matches)
|
||||
g_string_truncate(str, str->len-1);
|
||||
}
|
||||
|
||||
return g_string_free(str, FALSE);
|
||||
}
|
||||
|
||||
/* make sure the font_list is valid */
|
||||
static gboolean
|
||||
ensure_font_list(void)
|
||||
{
|
||||
gboolean result = FALSE;
|
||||
FcPattern *pat;
|
||||
FcObjectSet *os;
|
||||
gint i;
|
||||
|
||||
G_LOCK(font_list);
|
||||
/* if the config exists, and is up to date, return */
|
||||
if (font_list != NULL) {
|
||||
if (FcInitBringUptoDate()) {
|
||||
result = TRUE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* otherwise, destroy the fonts list and recreate */
|
||||
FcFontSetDestroy(font_list);
|
||||
font_list = NULL;
|
||||
g_strfreev(font_names);
|
||||
font_names = NULL;
|
||||
g_hash_table_destroy(font_hash);
|
||||
font_hash = NULL;
|
||||
}
|
||||
|
||||
pat = FcPatternCreate();
|
||||
os = FcObjectSetBuild(FC_FILE, FC_FAMILY, FC_WEIGHT, FC_SLANT, 0);
|
||||
|
||||
font_list = FcFontList(0, pat, os);
|
||||
|
||||
FcPatternDestroy(pat);
|
||||
FcObjectSetDestroy(os);
|
||||
|
||||
if (!font_list) {
|
||||
result = FALSE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* set up name list and hash */
|
||||
font_names = g_new(gchar *, font_list->nfont);
|
||||
font_hash = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
for (i = 0; i < font_list->nfont; i++) {
|
||||
font_names[i] = get_pango_name(font_list->fonts[i]);
|
||||
g_hash_table_insert(font_hash, font_names[i], font_list->fonts[i]);
|
||||
}
|
||||
|
||||
result = TRUE;
|
||||
|
||||
/* invoke monitors */
|
||||
invoke_monitors();
|
||||
|
||||
end:
|
||||
G_UNLOCK(font_list);
|
||||
return result;
|
||||
}
|
||||
|
||||
static GnomeVFSURI *
|
||||
create_local_uri(const GnomeVFSURI *orig_uri)
|
||||
{
|
||||
gchar *fontsdir, *fontsdir_escaped, *basename;
|
||||
GnomeVFSURI *fontsdir_uri, *new_uri;
|
||||
|
||||
/* make sure ~/.fonts exists ... */
|
||||
fontsdir = g_strconcat(g_get_home_dir(), G_DIR_SEPARATOR_S, ".fonts",NULL);
|
||||
if (mkdir(fontsdir, 0755) && errno != EEXIST) {
|
||||
g_free(fontsdir);
|
||||
return NULL;
|
||||
}
|
||||
/* get URI for fontsdir */
|
||||
fontsdir_escaped = gnome_vfs_get_uri_from_local_path(fontsdir);
|
||||
g_free(fontsdir);
|
||||
fontsdir_uri = gnome_vfs_uri_new(fontsdir_escaped);
|
||||
g_free(fontsdir_escaped);
|
||||
|
||||
basename = gnome_vfs_uri_extract_short_name(orig_uri);
|
||||
new_uri = gnome_vfs_uri_append_file_name(fontsdir_uri, basename);
|
||||
g_free(basename);
|
||||
gnome_vfs_uri_unref(fontsdir_uri);
|
||||
|
||||
return new_uri;
|
||||
}
|
||||
|
||||
/* -------- VFS method ------ */
|
||||
|
||||
static gchar *
|
||||
get_path_from_uri (GnomeVFSURI const *uri)
|
||||
{
|
||||
gchar *path;
|
||||
gint len;
|
||||
|
||||
path = gnome_vfs_unescape_string (uri->text,
|
||||
G_DIR_SEPARATOR_S);
|
||||
|
||||
if (path == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (path[0] != G_DIR_SEPARATOR) {
|
||||
g_free (path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = strlen(path);
|
||||
if (path[len-1] == G_DIR_SEPARATOR) path[len-1] = '\0';
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
static GnomeVFSResult
|
||||
fill_file_info(GnomeVFSFileInfo *file_info, GnomeVFSFileInfoOptions options,
|
||||
FcChar8 *file, gchar *name)
|
||||
{
|
||||
gchar *uri;
|
||||
GnomeVFSResult result;
|
||||
|
||||
uri = gnome_vfs_get_uri_from_local_path(file);
|
||||
result = gnome_vfs_get_file_info(uri, file_info, options);
|
||||
if (result == GNOME_VFS_OK) {
|
||||
g_free(file_info->name);
|
||||
file_info->name = g_strdup(name);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef struct _FontListHandle FontListHandle;
|
||||
struct _FontListHandle {
|
||||
gint font;
|
||||
GnomeVFSFileInfoOptions options;
|
||||
};
|
||||
|
||||
static GnomeVFSResult
|
||||
do_open_directory(GnomeVFSMethod *method,
|
||||
GnomeVFSMethodHandle **method_handle,
|
||||
GnomeVFSURI *uri,
|
||||
GnomeVFSFileInfoOptions options,
|
||||
GnomeVFSContext *context)
|
||||
{
|
||||
GnomeVFSResult result = GNOME_VFS_ERROR_NOT_SUPPORTED;
|
||||
char *path = NULL;
|
||||
FontListHandle *handle;
|
||||
|
||||
path = get_path_from_uri(uri);
|
||||
if (!path) {
|
||||
result = GNOME_VFS_ERROR_INVALID_URI;
|
||||
goto end;
|
||||
}
|
||||
if (strcmp(path, "") != 0) {
|
||||
result = GNOME_VFS_ERROR_NOT_FOUND;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!ensure_font_list()) {
|
||||
result = GNOME_VFS_ERROR_INTERNAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* handle used to iterate over font names */
|
||||
handle = g_new0(FontListHandle, 1);
|
||||
handle->font = 0;
|
||||
handle->options = options;
|
||||
*method_handle = (GnomeVFSMethodHandle *)handle;
|
||||
result = GNOME_VFS_OK;
|
||||
|
||||
end:
|
||||
g_free(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
static GnomeVFSResult
|
||||
do_close_directory(GnomeVFSMethod *method,
|
||||
GnomeVFSMethodHandle *method_handle,
|
||||
GnomeVFSContext *context)
|
||||
{
|
||||
FontListHandle *handle;
|
||||
|
||||
handle = (FontListHandle *)method_handle;
|
||||
g_free(handle);
|
||||
|
||||
return GNOME_VFS_OK;
|
||||
}
|
||||
|
||||
static GnomeVFSResult
|
||||
do_read_directory(GnomeVFSMethod *method,
|
||||
GnomeVFSMethodHandle *method_handle,
|
||||
GnomeVFSFileInfo *file_info,
|
||||
GnomeVFSContext *context)
|
||||
{
|
||||
GnomeVFSResult result = GNOME_VFS_ERROR_NOT_SUPPORTED;
|
||||
FontListHandle *handle;
|
||||
FcChar8 *file;
|
||||
|
||||
handle = (FontListHandle *)method_handle;
|
||||
|
||||
G_LOCK(font_list);
|
||||
if (!font_list) {
|
||||
result = GNOME_VFS_ERROR_INTERNAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (handle->font >= font_list->nfont) {
|
||||
result = GNOME_VFS_ERROR_EOF;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* get information about this font, skipping unfound fonts */
|
||||
result = GNOME_VFS_ERROR_NOT_FOUND;
|
||||
while (handle->font < font_list->nfont &&
|
||||
result == GNOME_VFS_ERROR_NOT_FOUND) {
|
||||
FcPatternGetString(font_list->fonts[handle->font], FC_FILE, 0, &file);
|
||||
result = fill_file_info(file_info, handle->options, file,
|
||||
font_names[handle->font]);
|
||||
|
||||
/* move on to next font */
|
||||
handle->font++;
|
||||
}
|
||||
|
||||
end:
|
||||
G_UNLOCK(font_list);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* -------- handling of file objects -------- */
|
||||
|
||||
static GnomeVFSResult
|
||||
do_open(GnomeVFSMethod *method,
|
||||
GnomeVFSMethodHandle **method_handle,
|
||||
GnomeVFSURI *uri,
|
||||
GnomeVFSOpenMode mode,
|
||||
GnomeVFSContext *context)
|
||||
{
|
||||
GnomeVFSResult result = GNOME_VFS_ERROR_NOT_FOUND;
|
||||
char *path = NULL;
|
||||
FcPattern *font;
|
||||
|
||||
path = get_path_from_uri(uri);
|
||||
if (!path) {
|
||||
result = GNOME_VFS_ERROR_INVALID_URI;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!ensure_font_list()) {
|
||||
result = GNOME_VFS_ERROR_INTERNAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (path[0] == '\0') {
|
||||
result = GNOME_VFS_ERROR_IS_DIRECTORY;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* we don't support openning existing files for writing */
|
||||
if ((mode & GNOME_VFS_OPEN_WRITE) != 0) {
|
||||
result = GNOME_VFS_ERROR_READ_ONLY;
|
||||
goto end;
|
||||
}
|
||||
|
||||
G_LOCK(font_list);
|
||||
font = g_hash_table_lookup(font_hash, &path[1]);
|
||||
if (font) {
|
||||
FcChar8 *file;
|
||||
gchar *text_uri;
|
||||
GnomeVFSURI *font_uri;
|
||||
|
||||
FcPatternGetString(font, FC_FILE, 0, &file);
|
||||
text_uri = gnome_vfs_get_uri_from_local_path(file);
|
||||
font_uri = gnome_vfs_uri_new(text_uri);
|
||||
g_free(text_uri);
|
||||
|
||||
result = gnome_vfs_open_uri_cancellable(
|
||||
(GnomeVFSHandle **)method_handle, font_uri, mode, context);
|
||||
|
||||
gnome_vfs_uri_unref(font_uri);
|
||||
} else {
|
||||
result = GNOME_VFS_ERROR_NOT_FOUND;
|
||||
}
|
||||
G_UNLOCK(font_list);
|
||||
|
||||
end:
|
||||
g_free(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
static GnomeVFSResult
|
||||
do_create(GnomeVFSMethod *method,
|
||||
GnomeVFSMethodHandle **method_handle,
|
||||
GnomeVFSURI *uri,
|
||||
GnomeVFSOpenMode mode,
|
||||
gboolean exclusive,
|
||||
guint perm,
|
||||
GnomeVFSContext *context)
|
||||
{
|
||||
GnomeVFSResult result;
|
||||
GnomeVFSURI *new_uri;
|
||||
|
||||
g_message("font-method: do_create");
|
||||
|
||||
new_uri = create_local_uri(uri);
|
||||
if (!new_uri)
|
||||
return gnome_vfs_result_from_errno();
|
||||
result = gnome_vfs_create_uri_cancellable((GnomeVFSHandle **)method_handle,
|
||||
new_uri, mode, exclusive, perm,
|
||||
context);
|
||||
gnome_vfs_uri_unref(new_uri);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static GnomeVFSResult
|
||||
do_close(GnomeVFSMethod *method,
|
||||
GnomeVFSMethodHandle *method_handle,
|
||||
GnomeVFSContext *context)
|
||||
{
|
||||
g_message("font-method: do_close");
|
||||
|
||||
return gnome_vfs_close_cancellable((GnomeVFSHandle *)method_handle,
|
||||
context);
|
||||
}
|
||||
|
||||
static GnomeVFSResult
|
||||
do_read(GnomeVFSMethod *method,
|
||||
GnomeVFSMethodHandle *method_handle,
|
||||
gpointer buffer,
|
||||
GnomeVFSFileSize bytes,
|
||||
GnomeVFSFileSize *bytes_read,
|
||||
GnomeVFSContext *context)
|
||||
{
|
||||
return gnome_vfs_read_cancellable((GnomeVFSHandle *)method_handle,
|
||||
buffer, bytes, bytes_read, context);
|
||||
}
|
||||
|
||||
static GnomeVFSResult
|
||||
do_write(GnomeVFSMethod *method,
|
||||
GnomeVFSMethodHandle *method_handle,
|
||||
gconstpointer buffer,
|
||||
GnomeVFSFileSize bytes,
|
||||
GnomeVFSFileSize *bytes_written,
|
||||
GnomeVFSContext *context)
|
||||
{
|
||||
return gnome_vfs_write_cancellable((GnomeVFSHandle *)method_handle,
|
||||
buffer, bytes, bytes_written, context);
|
||||
}
|
||||
|
||||
static GnomeVFSResult
|
||||
do_seek(GnomeVFSMethod *method,
|
||||
GnomeVFSMethodHandle *method_handle,
|
||||
GnomeVFSSeekPosition whence,
|
||||
GnomeVFSFileOffset offset,
|
||||
GnomeVFSContext *context)
|
||||
{
|
||||
return gnome_vfs_seek_cancellable((GnomeVFSHandle *)method_handle,
|
||||
whence, offset, context);
|
||||
}
|
||||
|
||||
static GnomeVFSResult
|
||||
do_tell(GnomeVFSMethod *method,
|
||||
GnomeVFSMethodHandle *method_handle,
|
||||
GnomeVFSFileOffset *offset_return)
|
||||
{
|
||||
return gnome_vfs_tell((GnomeVFSHandle *)method_handle, offset_return);
|
||||
}
|
||||
|
||||
static GnomeVFSResult
|
||||
do_get_file_info_from_handle(GnomeVFSMethod *method,
|
||||
GnomeVFSMethodHandle *method_handle,
|
||||
GnomeVFSFileInfo *file_info,
|
||||
GnomeVFSFileInfoOptions options,
|
||||
GnomeVFSContext *context)
|
||||
{
|
||||
return gnome_vfs_get_file_info_from_handle_cancellable
|
||||
((GnomeVFSHandle *)method_handle, file_info, options, context);
|
||||
}
|
||||
|
||||
|
||||
/* -------- file metadata -------- */
|
||||
|
||||
static GnomeVFSResult
|
||||
do_get_file_info(GnomeVFSMethod *method,
|
||||
GnomeVFSURI *uri,
|
||||
GnomeVFSFileInfo *file_info,
|
||||
GnomeVFSFileInfoOptions options,
|
||||
GnomeVFSContext *context)
|
||||
{
|
||||
GnomeVFSResult result = GNOME_VFS_ERROR_NOT_FOUND;
|
||||
char *path = NULL;
|
||||
|
||||
path = get_path_from_uri(uri);
|
||||
if (!path) {
|
||||
result = GNOME_VFS_ERROR_INVALID_URI;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!ensure_font_list()) {
|
||||
result = GNOME_VFS_ERROR_INTERNAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* root directory */
|
||||
if (!strcmp(path, "")) {
|
||||
g_free(file_info->name);
|
||||
file_info->name = g_strdup("Fonts");
|
||||
|
||||
file_info->type = GNOME_VFS_FILE_TYPE_DIRECTORY;
|
||||
file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_TYPE;
|
||||
|
||||
g_free(file_info->mime_type);
|
||||
file_info->mime_type = g_strdup("x-directory/normal");
|
||||
file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE;
|
||||
|
||||
result = GNOME_VFS_OK;
|
||||
} else {
|
||||
FcPattern *font;
|
||||
|
||||
G_LOCK(font_list);
|
||||
font = g_hash_table_lookup(font_hash, &path[1]);
|
||||
if (font) {
|
||||
FcChar8 *file;
|
||||
|
||||
FcPatternGetString(font, FC_FILE, 0, &file);
|
||||
result = fill_file_info(file_info, options, file, &path[1]);
|
||||
}
|
||||
G_UNLOCK(font_list);
|
||||
}
|
||||
|
||||
end:
|
||||
G_UNLOCK(font_list);
|
||||
g_free(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
do_is_local(GnomeVFSMethod *method,
|
||||
const GnomeVFSURI *uri)
|
||||
{
|
||||
gboolean result = FALSE;
|
||||
char *path = NULL;
|
||||
|
||||
path = get_path_from_uri(uri);
|
||||
if (!path) { /* invalid path */
|
||||
goto end;
|
||||
}
|
||||
if (!ensure_font_list()) { /* could not build font list */
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* root directory */
|
||||
if (!strcmp(path, "")) { /* base dir */
|
||||
result = TRUE;
|
||||
} else {
|
||||
FcPattern *font;
|
||||
|
||||
G_LOCK(font_list);
|
||||
font = g_hash_table_lookup(font_hash, &path[1]);
|
||||
if (font) { /* check if underlying uri is local */
|
||||
FcChar8 *file;
|
||||
gchar *file_text_uri;
|
||||
GnomeVFSURI *file_uri;
|
||||
|
||||
FcPatternGetString(font, FC_FILE, 0, &file);
|
||||
file_text_uri = gnome_vfs_get_uri_from_local_path(file);
|
||||
file_uri = gnome_vfs_uri_new(file_text_uri);
|
||||
g_free(file_text_uri);
|
||||
|
||||
result = gnome_vfs_uri_is_local(file_uri);
|
||||
gnome_vfs_uri_unref(file_uri);
|
||||
}
|
||||
G_UNLOCK(font_list);
|
||||
}
|
||||
|
||||
end:
|
||||
g_free(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
static GnomeVFSResult
|
||||
do_unlink(GnomeVFSMethod *method,
|
||||
GnomeVFSURI *uri,
|
||||
GnomeVFSContext *context)
|
||||
{
|
||||
GnomeVFSResult result = GNOME_VFS_ERROR_NOT_SUPPORTED;
|
||||
char *path = NULL;
|
||||
|
||||
path = get_path_from_uri(uri);
|
||||
if (!path) { /* invalid path */
|
||||
result = GNOME_VFS_ERROR_INVALID_URI;
|
||||
goto end;
|
||||
}
|
||||
if (!ensure_font_list()) { /* could not build font list */
|
||||
result = GNOME_VFS_ERROR_INTERNAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!strcmp(path, "")) { /* base dir */
|
||||
result = GNOME_VFS_ERROR_NOT_PERMITTED;
|
||||
} else {
|
||||
FcPattern *font;
|
||||
|
||||
G_LOCK(font_list);
|
||||
font = g_hash_table_lookup(font_hash, &path[1]);
|
||||
if (font) { /* check if underlying uri is local */
|
||||
FcChar8 *file;
|
||||
gchar *file_text_uri;
|
||||
GnomeVFSURI *file_uri;
|
||||
|
||||
FcPatternGetString(font, FC_FILE, 0, &file);
|
||||
file_text_uri = gnome_vfs_get_uri_from_local_path(file);
|
||||
file_uri = gnome_vfs_uri_new(file_text_uri);
|
||||
g_free(file_text_uri);
|
||||
|
||||
result = gnome_vfs_unlink_from_uri_cancellable(file_uri, context);
|
||||
gnome_vfs_uri_unref(file_uri);
|
||||
} else {
|
||||
result = GNOME_VFS_ERROR_NOT_FOUND;
|
||||
}
|
||||
G_UNLOCK(font_list);
|
||||
}
|
||||
end:
|
||||
g_free(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* -------- Directory monitor -------- */
|
||||
|
||||
/* list of monitors attached to fonts:/// */
|
||||
G_LOCK_DEFINE_STATIC(monitor_list);
|
||||
static GList *monitor_list = NULL;
|
||||
|
||||
static void
|
||||
invoke_monitors(void)
|
||||
{
|
||||
GList *tmp;
|
||||
|
||||
G_LOCK(monitor_list);
|
||||
for (tmp = monitor_list; tmp != NULL; tmp = tmp->next) {
|
||||
GnomeVFSURI *uri = tmp->data;
|
||||
|
||||
gnome_vfs_monitor_callback((GnomeVFSMethodHandle *)uri, uri,
|
||||
GNOME_VFS_MONITOR_EVENT_CHANGED);
|
||||
}
|
||||
G_UNLOCK(monitor_list);
|
||||
}
|
||||
|
||||
static GnomeVFSResult
|
||||
do_monitor_add(GnomeVFSMethod *method,
|
||||
GnomeVFSMethodHandle **method_handle,
|
||||
GnomeVFSURI *uri,
|
||||
GnomeVFSMonitorType monitor_type)
|
||||
{
|
||||
char *path = NULL;
|
||||
GnomeVFSURI *uri_copy;
|
||||
|
||||
path = get_path_from_uri(uri);
|
||||
if (!path) { /* invalid path */
|
||||
return GNOME_VFS_ERROR_INVALID_URI;
|
||||
}
|
||||
|
||||
if (path[0] != '\0' || monitor_type != GNOME_VFS_MONITOR_DIRECTORY) {
|
||||
g_free(path);
|
||||
return GNOME_VFS_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
g_free(path);
|
||||
|
||||
/* it is a directory monitor on fonts:/// */
|
||||
uri_copy = gnome_vfs_uri_dup(uri);
|
||||
*method_handle = (GnomeVFSMethodHandle *)uri_copy;
|
||||
G_LOCK(monitor_list);
|
||||
monitor_list = g_list_prepend(monitor_list, uri_copy);
|
||||
G_UNLOCK(monitor_list);
|
||||
|
||||
return GNOME_VFS_OK;
|
||||
}
|
||||
|
||||
static GnomeVFSResult
|
||||
do_monitor_cancel(GnomeVFSMethod *method,
|
||||
GnomeVFSMethodHandle *method_handle)
|
||||
{
|
||||
GnomeVFSURI *uri;
|
||||
|
||||
uri = (GnomeVFSURI *)method_handle;
|
||||
G_LOCK(monitor_list);
|
||||
monitor_list = g_list_remove(monitor_list, uri);
|
||||
G_UNLOCK(monitor_list);
|
||||
gnome_vfs_uri_unref(uri);
|
||||
return GNOME_VFS_OK;
|
||||
}
|
||||
|
||||
|
||||
/* -------- Initialisation of the method -------- */
|
||||
|
||||
static GnomeVFSMethod method = {
|
||||
sizeof(GnomeVFSMethod),
|
||||
|
||||
.open = do_open,
|
||||
.create = do_create,
|
||||
.close = do_close,
|
||||
.read = do_read,
|
||||
.write = do_write,
|
||||
.seek = do_seek,
|
||||
.tell = do_tell,
|
||||
.get_file_info_from_handle = do_get_file_info_from_handle,
|
||||
|
||||
.open_directory = do_open_directory,
|
||||
.close_directory = do_close_directory,
|
||||
.read_directory = do_read_directory,
|
||||
|
||||
.get_file_info = do_get_file_info,
|
||||
.is_local = do_is_local,
|
||||
.unlink = do_unlink,
|
||||
|
||||
.monitor_add = do_monitor_add,
|
||||
.monitor_cancel = do_monitor_cancel
|
||||
};
|
||||
|
||||
GnomeVFSMethod *
|
||||
vfs_module_init(const char *method_name, const char *args)
|
||||
{
|
||||
if (!strcmp(method_name, "fonts")) {
|
||||
if (!FcInit()) {
|
||||
g_warning("can't init fontconfig library");
|
||||
return NULL;
|
||||
}
|
||||
return &method;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
vfs_module_shutdown(GnomeVFSMethod *method)
|
||||
{
|
||||
/* clean up font list */
|
||||
if (font_list) FcFontSetDestroy(font_list);
|
||||
if (font_names) g_strfreev(font_names);
|
||||
if (font_hash) g_hash_table_destroy(font_hash);
|
||||
font_list = NULL;
|
||||
font_names = NULL;
|
||||
font_hash = NULL;
|
||||
}
|
2
vfs-methods/fontilus/font-method.conf
Normal file
2
vfs-methods/fontilus/font-method.conf
Normal file
|
@ -0,0 +1,2 @@
|
|||
fonts: font-method
|
||||
|
118
vfs-methods/fontilus/ftstream-vfs.c
Normal file
118
vfs-methods/fontilus/ftstream-vfs.c
Normal file
|
@ -0,0 +1,118 @@
|
|||
/* -*- mode: C; c-basic-offset: 4 -*- */
|
||||
#include <stdlib.h>
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include <libgnomevfs/gnome-vfs.h>
|
||||
|
||||
static unsigned long
|
||||
vfs_stream_read(FT_Stream stream,
|
||||
unsigned long offset,
|
||||
unsigned char *buffer,
|
||||
unsigned long count)
|
||||
{
|
||||
GnomeVFSHandle *handle = (GnomeVFSHandle *)stream->descriptor.pointer;
|
||||
GnomeVFSFileSize bytes_read = 0;
|
||||
|
||||
if (gnome_vfs_seek(handle, GNOME_VFS_SEEK_START, offset) != GNOME_VFS_OK)
|
||||
return 0;
|
||||
if (count > 0) {
|
||||
if (gnome_vfs_read(handle, buffer, count, &bytes_read) != GNOME_VFS_OK)
|
||||
return 0;
|
||||
}
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
static void
|
||||
vfs_stream_close(FT_Stream stream)
|
||||
{
|
||||
GnomeVFSHandle *handle = (GnomeVFSHandle *)stream->descriptor.pointer;
|
||||
|
||||
g_message("closing handle");
|
||||
if (!handle)
|
||||
return;
|
||||
gnome_vfs_close(handle);
|
||||
|
||||
stream->descriptor.pointer = NULL;
|
||||
stream->size = 0;
|
||||
stream->base = 0;
|
||||
}
|
||||
|
||||
static FT_Error
|
||||
vfs_stream_open(FT_Stream stream,
|
||||
const char *uri)
|
||||
{
|
||||
GnomeVFSHandle *handle;
|
||||
GnomeVFSFileInfo *finfo;
|
||||
|
||||
if (!stream)
|
||||
return FT_Err_Invalid_Stream_Handle;
|
||||
|
||||
if (gnome_vfs_open(&handle, uri,
|
||||
GNOME_VFS_OPEN_READ | GNOME_VFS_OPEN_RANDOM) != GNOME_VFS_OK) {
|
||||
g_message("could not open URI");
|
||||
return FT_Err_Cannot_Open_Resource;
|
||||
}
|
||||
|
||||
finfo = gnome_vfs_file_info_new();
|
||||
if (gnome_vfs_get_file_info_from_handle(handle, finfo,0) != GNOME_VFS_OK) {
|
||||
g_warning("could not get file info");
|
||||
gnome_vfs_file_info_unref(finfo);
|
||||
gnome_vfs_close(handle);
|
||||
return FT_Err_Cannot_Open_Resource;
|
||||
}
|
||||
|
||||
if ((finfo->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) == 0) {
|
||||
g_warning("file info did not include file size");
|
||||
gnome_vfs_file_info_unref(finfo);
|
||||
gnome_vfs_close(handle);
|
||||
return FT_Err_Cannot_Open_Resource;
|
||||
}
|
||||
stream->size = finfo->size;
|
||||
gnome_vfs_file_info_unref(finfo);
|
||||
|
||||
stream->descriptor.pointer = handle;
|
||||
stream->pathname.pointer = NULL;
|
||||
stream->pos = 0;
|
||||
|
||||
stream->read = vfs_stream_read;
|
||||
stream->close = vfs_stream_close;
|
||||
|
||||
return FT_Err_Ok;
|
||||
}
|
||||
|
||||
/* load a typeface from a URI */
|
||||
FT_Error
|
||||
FT_New_URI_Face(FT_Library library,
|
||||
const gchar* uri,
|
||||
FT_Long face_index,
|
||||
FT_Face *aface)
|
||||
{
|
||||
FT_Open_Args args;
|
||||
FT_Stream stream;
|
||||
FT_Error error;
|
||||
|
||||
if ((stream = calloc(1, sizeof(FT_Stream))) == NULL)
|
||||
return FT_Err_Out_Of_Memory;
|
||||
|
||||
error = vfs_stream_open(stream, uri);
|
||||
if (error != FT_Err_Ok) {
|
||||
free(stream);
|
||||
return error;
|
||||
}
|
||||
|
||||
#ifndef FT_OPEN_STREAM
|
||||
# define FT_OPEN_STREAM ft_open_stream
|
||||
#endif
|
||||
args.flags = FT_OPEN_STREAM;
|
||||
args.stream = stream;
|
||||
|
||||
error = FT_Open_Face(library, &args, face_index, aface);
|
||||
|
||||
if (error != FT_Err_Ok) {
|
||||
stream->close(stream);
|
||||
free(stream);
|
||||
return error;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
146
vfs-methods/fontilus/thumbnailer.c
Normal file
146
vfs-methods/fontilus/thumbnailer.c
Normal file
|
@ -0,0 +1,146 @@
|
|||
/* -*- mode: C; c-basic-offset: 4 -*- */
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
#include <libgnomevfs/gnome-vfs.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
FT_Error FT_New_URI_Face(FT_Library library,
|
||||
const gchar *uri,
|
||||
FT_Long face_index,
|
||||
FT_Face *aface);
|
||||
|
||||
static void
|
||||
draw_bitmap(GdkPixbuf *pixbuf, FT_Bitmap *bitmap, gint off_x, gint off_y)
|
||||
{
|
||||
guchar *buffer;
|
||||
gint p_width, p_height, p_rowstride;
|
||||
gint i, j;
|
||||
|
||||
buffer = gdk_pixbuf_get_pixels(pixbuf);
|
||||
p_width = gdk_pixbuf_get_width(pixbuf);
|
||||
p_height = gdk_pixbuf_get_height(pixbuf);
|
||||
p_rowstride = gdk_pixbuf_get_rowstride(pixbuf);
|
||||
|
||||
for (j = 0; j < bitmap->rows; j++) {
|
||||
if (j + off_y < 0 || j + off_y >= p_height)
|
||||
continue;
|
||||
for (i = 0; i < bitmap->width; i++) {
|
||||
guchar pixel;
|
||||
gint pos;
|
||||
|
||||
if (i + off_x < 0 || i + off_x >= p_width)
|
||||
continue;
|
||||
pixel = 255 - bitmap->buffer[j*bitmap->pitch + i];
|
||||
pos = (j + off_y) * p_rowstride + 3 * (i + off_x);
|
||||
buffer[pos] = pixel;
|
||||
buffer[pos+1] = pixel;
|
||||
buffer[pos+2] = pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
FT_Error error;
|
||||
FT_Library library;
|
||||
FT_Face face;
|
||||
FT_GlyphSlot slot;
|
||||
GdkPixbuf *pixbuf, *pixbuf2;
|
||||
guchar *buffer;
|
||||
gint width, height, i, pen_x, pen_y, max_width, max_height;
|
||||
|
||||
if (argc != 3) {
|
||||
g_message("eek: bad args");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!gnome_vfs_init()) {
|
||||
g_message("eek: gnome-vfs init");
|
||||
return 1;
|
||||
}
|
||||
|
||||
error = FT_Init_FreeType(&library);
|
||||
if (error) {
|
||||
g_message("eek: library");
|
||||
return 1;
|
||||
}
|
||||
|
||||
error = FT_New_URI_Face(library, argv[1], 0, &face);
|
||||
if (error) {
|
||||
g_message("eek: face");
|
||||
return 1;
|
||||
}
|
||||
|
||||
slot = face->glyph;
|
||||
|
||||
error = FT_Set_Pixel_Sizes(face, 0, 64);
|
||||
if (error) {
|
||||
g_message("eek: set pixel size");
|
||||
return 1;
|
||||
}
|
||||
error = FT_Load_Char(face, 'A', FT_LOAD_RENDER);
|
||||
if (error) {
|
||||
g_message("eek: load char");
|
||||
return 1;
|
||||
}
|
||||
|
||||
g_assert(slot->bitmap.pixel_mode == ft_pixel_mode_grays);
|
||||
|
||||
width = slot->bitmap.width;
|
||||
height = slot->bitmap.rows;
|
||||
|
||||
pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, width*3, height*1.5);
|
||||
buffer = gdk_pixbuf_get_pixels(pixbuf);
|
||||
|
||||
for (i = gdk_pixbuf_get_rowstride(pixbuf) *
|
||||
gdk_pixbuf_get_height(pixbuf); i >= 0; i--)
|
||||
buffer[i] = 255;
|
||||
|
||||
pen_x = 0;
|
||||
pen_y = slot->bitmap_top;
|
||||
max_height = height;
|
||||
max_width = pen_x + slot->bitmap_left + width;
|
||||
|
||||
draw_bitmap(pixbuf, &slot->bitmap,
|
||||
pen_x + slot->bitmap_left, pen_y - slot->bitmap_top);
|
||||
|
||||
pen_x += slot->advance.x >> 6;
|
||||
|
||||
error = FT_Load_Char(face, 'a', FT_LOAD_RENDER);
|
||||
if (error) {
|
||||
g_message("ekk: load char 2");
|
||||
return 1;
|
||||
}
|
||||
|
||||
max_height = MAX(max_height, pen_y + slot->bitmap.rows -
|
||||
slot->bitmap_top);
|
||||
max_width = pen_x + slot->bitmap_left + slot->bitmap.width;
|
||||
|
||||
draw_bitmap(pixbuf, &slot->bitmap,
|
||||
pen_x + slot->bitmap_left, pen_y - slot->bitmap_top);
|
||||
|
||||
pixbuf2 = gdk_pixbuf_new_subpixbuf(pixbuf, 0,0, max_width,max_height);
|
||||
|
||||
gdk_pixbuf_save(pixbuf2, argv[2], "png", NULL, NULL);
|
||||
gdk_pixbuf_unref(pixbuf2);
|
||||
gdk_pixbuf_unref(pixbuf);
|
||||
|
||||
/* freeing the face causes a crash I haven't tracked down yet */
|
||||
#if 0
|
||||
error = FT_Done_Face(face);
|
||||
if (error) {
|
||||
g_message("eek: done face");
|
||||
return 1;
|
||||
}
|
||||
error = FT_Done_FreeType(library);
|
||||
if (error) {
|
||||
g_message("eek: done library");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue