summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJannis Pohlmann <jannis@xfce.org>2009-09-30 02:16:40 +0200
committerJannis Pohlmann <jannis@xfce.org>2009-09-30 02:16:40 +0200
commitd94aa4686d02796116ec69a6a6bdf6d9154d2384 (patch)
treed9aeb6038a003215f16af23289408fbb0702d850
parentbf87845cd35e6db1abe4e497c502993a5296baee (diff)
downloadtumbler-d94aa4686d02796116ec69a6a6bdf6d9154d2384.tar.gz
Implement the font thumbnailer, reusing code from ThunarVFS.
For now this one only works on local paths but this will soon change. If the FUSE daemon of GVfs is available, even non-local files are supported.
-rw-r--r--configure.in.in37
-rw-r--r--plugins/Makefile.am1
-rw-r--r--plugins/font-thumbnailer/Makefile.am58
-rw-r--r--plugins/font-thumbnailer/font-thumbnailer-plugin.c91
-rw-r--r--plugins/font-thumbnailer/font-thumbnailer-provider.c131
-rw-r--r--plugins/font-thumbnailer/font-thumbnailer-provider.h43
-rw-r--r--plugins/font-thumbnailer/font-thumbnailer.c617
-rw-r--r--plugins/font-thumbnailer/font-thumbnailer.h43
-rw-r--r--tumblerd/tumbler-cache-service.c4
-rw-r--r--tumblerd/tumbler-manager.c4
-rw-r--r--tumblerd/tumbler-service.c4
-rw-r--r--tumblerd/tumbler-specialized-thumbnailer.c2
12 files changed, 1028 insertions, 7 deletions
diff --git a/configure.in.in b/configure.in.in
index 149c64e..7e97787 100644
--- a/configure.in.in
+++ b/configure.in.in
@@ -151,6 +151,37 @@ if test x"$enable_pixbuf_thumbnailer" = x"yes"; then
fi
AM_CONDITIONAL([ENABLE_PIXBUF_THUMBNAILER], test x"$enable_pixbuf_thumbnailer" = x"yes")
+dnl *********************************************
+dnl *** Check for the font thumbnailer plugin ***
+dnl *********************************************
+AC_ARG_ENABLE([font-thumbnailer],
+ [AC_HELP_STRING([--enable-font-thumbnailer],
+ [Enable the font thumbnailer plugin @<:@default=yes@:>@])],,
+ [enable_font_thumbnailer=yes])
+if test x"$enable_font_thumbnailer" = x"yes"; then
+ dnl ******************************
+ dnl *** Check for FreeType 2.x ***
+ dnl ******************************
+ FREETYPE_LIBS=""
+ FREETYPE_CFLAGS=""
+ AC_PATH_PROG([FREETYPE_CONFIG], [freetype-config], [no])
+ if test x"$FREETYPE_CONFIG" != x"no"; then
+ AC_MSG_CHECKING([FREETYPE_CFLAGS])
+ FREETYPE_CFLAGS="`$FREETYPE_CONFIG --cflags`"
+ AC_MSG_RESULT([$FREETYPE_CFLAGS])
+
+ AC_MSG_CHECKING([FREETYPE_LIBS])
+ FREETYPE_LIBS="`$FREETYPE_CONFIG --libs`"
+ AC_MSG_RESULT([$FREETYPE_LIBS])
+
+ AC_DEFINE([ENABLE_FONT_THUMBNAILER], [1], [Define if the font thumbnailer plugin is enabled])
+ fi
+ AM_CONDITIONAL([HAVE_FREETYPE], [test x"$FREETYPE_CONFIG" != x"no"])
+ AC_SUBST([FREETYPE_CFLAGS])
+ AC_SUBST([FREETYPE_LIBS])
+fi
+AM_CONDITIONAL([ENABLE_FONT_THUMBNAILER], [test x"$enable_font_thumbnailer" != x"no" && test x"$FREETYPE_CONFIG" != x"no"])
+
dnl ************************************************************
dnl *** Check for thumbnail flavors (normal, large, cropped) ***
dnl ************************************************************
@@ -245,6 +276,7 @@ docs/reference/Makefile
docs/reference/tumbler/Makefile
docs/reference/tumbler/version.xml
plugins/Makefile
+plugins/font-thumbnailer/Makefile
plugins/pixbuf-thumbnailer/Makefile
plugins/xdg-cache/Makefile
po/Makefile.in
@@ -266,6 +298,11 @@ echo " * Pixbuf thumbnailer plugin: yes"
else
echo " * Pixbuf thumbnailer plugin: no"
fi
+if test x"$enable_font_thumbnailer" = x"yes"; then
+echo " * Font thumbnailer plugin: yes"
+else
+echo " * Font thumbnailer plugin: no"
+fi
echo
echo "Supported Thumbnail Flavors:"
echo
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 77f66cf..047ba61 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -18,5 +18,6 @@
# Boston, MA 02110-1301, USA.
SUBDIRS = \
+ font-thumbnailer \
pixbuf-thumbnailer \
xdg-cache
diff --git a/plugins/font-thumbnailer/Makefile.am b/plugins/font-thumbnailer/Makefile.am
new file mode 100644
index 0000000..9c8f855
--- /dev/null
+++ b/plugins/font-thumbnailer/Makefile.am
@@ -0,0 +1,58 @@
+# vi:set ts=8 sw=8 noet ai nocindent:
+# -
+# Copyright (c) 2009 Jannis Pohlmann <jannis@xfce.org>
+#
+# 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., 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+if ENABLE_FONT_THUMBNAILER
+
+tumbler_plugindir = $(libdir)/tumbler-$(TUMBLER_VERSION_API)/plugins
+tumbler_plugin_LTLIBRARIES = \
+ tumbler-font-thumbnailer.la
+
+tumbler_font_thumbnailer_la_SOURCES = \
+ font-thumbnailer-plugin.c \
+ font-thumbnailer-provider.c \
+ font-thumbnailer-provider.h \
+ font-thumbnailer.c \
+ font-thumbnailer.h
+
+tumbler_font_thumbnailer_la_CFLAGS = \
+ -I$(top_builddir) \
+ -I$(top_builddir)/plugins \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/plugins \
+ -DG_LOG_DOMAIN=\"tumbler-font-thumbnailer\" \
+ -DPACKAGE_LOCALE_DIR=\"$(localedir)\" \
+ $(GDK_PIXBUF_CFLAGS) \
+ $(GIO_CFLAGS) \
+ $(GLIB_CFLAGS) \
+ $(FREETYPE_CFLAGS) \
+ $(PLATFORM_CPPFLAGS)
+
+tumbler_font_thumbnailer_la_LDFLAGS = \
+ -avoid-version \
+ -export-dynamic \
+ -module \
+ $(PLATFORM_LDFLAGS)
+
+tumbler_font_thumbnailer_la_LIBADD = \
+ $(GDK_PIXBUF_LIBS) \
+ $(GIO_LIBS) \
+ $(GLIB_LIBS) \
+ $(FREETYPE_LIBS)
+
+endif
diff --git a/plugins/font-thumbnailer/font-thumbnailer-plugin.c b/plugins/font-thumbnailer/font-thumbnailer-plugin.c
new file mode 100644
index 0000000..a240089
--- /dev/null
+++ b/plugins/font-thumbnailer/font-thumbnailer-plugin.c
@@ -0,0 +1,91 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*-
+ * Copyright (c) 2009 Jannis Pohlmann <jannis@xfce.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#include <tumbler/tumbler.h>
+
+#include <font-thumbnailer/font-thumbnailer-provider.h>
+#include <font-thumbnailer/font-thumbnailer.h>
+
+
+
+G_MODULE_EXPORT void tumbler_plugin_initialize (TumblerProviderPlugin *plugin);
+G_MODULE_EXPORT void tumbler_plugin_shutdown (void);
+G_MODULE_EXPORT void tumbler_plugin_get_types (const GType **types,
+ gint *n_types);
+
+
+
+static GType type_list[1];
+
+
+
+void
+tumbler_plugin_initialize (TumblerProviderPlugin *plugin)
+{
+ const gchar *mismatch;
+
+ /* verify that the tumbler versions are compatible */
+ mismatch = tumbler_check_version (TUMBLER_MAJOR_VERSION, TUMBLER_MINOR_VERSION,
+ TUMBLER_MICRO_VERSION);
+ if (G_UNLIKELY (mismatch != NULL))
+ {
+ g_warning (_("Version mismatch: %s"), mismatch);
+ return;
+ }
+
+#ifdef DEBUG
+ g_message (_("Initializing the Tumbler Font Thumbnailer plugin"));
+#endif
+
+ /* register the types provided by this plugin */
+ font_thumbnailer_register (plugin);
+ font_thumbnailer_provider_register (plugin);
+
+ /* set up the plugin provider type list */
+ type_list[0] = TYPE_FONT_THUMBNAILER_PROVIDER;
+}
+
+
+
+void
+tumbler_plugin_shutdown (void)
+{
+#ifdef DEBUG
+ g_message (_("Shutting down the Tumbler Font Thumbnailer plugin"));
+#endif
+}
+
+
+
+void
+tumbler_plugin_get_types (const GType **types,
+ gint *n_types)
+{
+ *types = type_list;
+ *n_types = G_N_ELEMENTS (type_list);
+}
diff --git a/plugins/font-thumbnailer/font-thumbnailer-provider.c b/plugins/font-thumbnailer/font-thumbnailer-provider.c
new file mode 100644
index 0000000..86fcf7c
--- /dev/null
+++ b/plugins/font-thumbnailer/font-thumbnailer-provider.c
@@ -0,0 +1,131 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*-
+ * Copyright (c) 2009 Jannis Pohlmann <jannis@xfce.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include <tumbler/tumbler.h>
+
+#include <font-thumbnailer/font-thumbnailer-provider.h>
+#include <font-thumbnailer/font-thumbnailer.h>
+
+
+
+static void font_thumbnailer_provider_thumbnailer_provider_init (TumblerThumbnailerProviderIface *iface);
+static GList *font_thumbnailer_provider_get_thumbnailers (TumblerThumbnailerProvider *provider);
+
+
+
+struct _FontThumbnailerProviderClass
+{
+ GObjectClass __parent__;
+};
+
+struct _FontThumbnailerProvider
+{
+ GObject __parent__;
+};
+
+
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (FontThumbnailerProvider,
+ font_thumbnailer_provider,
+ G_TYPE_OBJECT,
+ 0,
+ TUMBLER_ADD_INTERFACE (TUMBLER_TYPE_THUMBNAILER_PROVIDER,
+ font_thumbnailer_provider_thumbnailer_provider_init));
+
+
+
+void
+font_thumbnailer_provider_register (TumblerProviderPlugin *plugin)
+{
+ font_thumbnailer_provider_register_type (G_TYPE_MODULE (plugin));
+}
+
+
+
+static void
+font_thumbnailer_provider_class_init (FontThumbnailerProviderClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+}
+
+
+
+static void
+font_thumbnailer_provider_class_finalize (FontThumbnailerProviderClass *klass)
+{
+}
+
+
+
+static void
+font_thumbnailer_provider_thumbnailer_provider_init (TumblerThumbnailerProviderIface *iface)
+{
+ iface->get_thumbnailers = font_thumbnailer_provider_get_thumbnailers;
+}
+
+
+
+static void
+font_thumbnailer_provider_init (FontThumbnailerProvider *provider)
+{
+}
+
+
+
+static GList *
+font_thumbnailer_provider_get_thumbnailers (TumblerThumbnailerProvider *provider)
+{
+ static const gchar *uri_schemes[] =
+ {
+ "file",
+ NULL,
+ };
+ static const gchar *mime_types[] =
+ {
+ "application/x-font-otf",
+ "application/x-font-pcf",
+ "application/x-font-ttf",
+ "application/x-font-type1",
+ NULL,
+ };
+ FontThumbnailer *thumbnailer;
+ GList *thumbnailers = NULL;
+
+ /* create the pixbuf thumbnailer */
+ thumbnailer = g_object_new (TYPE_FONT_THUMBNAILER,
+ "uri-schemes", uri_schemes, "mime-types", mime_types,
+ NULL);
+
+ /* add the thumbnailer to the list */
+ thumbnailers = g_list_append (thumbnailers, thumbnailer);
+
+ return thumbnailers;
+}
diff --git a/plugins/font-thumbnailer/font-thumbnailer-provider.h b/plugins/font-thumbnailer/font-thumbnailer-provider.h
new file mode 100644
index 0000000..24b4142
--- /dev/null
+++ b/plugins/font-thumbnailer/font-thumbnailer-provider.h
@@ -0,0 +1,43 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*-
+ * Copyright (c) 2009 Jannis Pohlmann <jannis@xfce.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __FONT_THUMBNAILER_PROVIDER_H__
+#define __FONT_THUMBNAILER_PROVIDER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS;
+
+#define TYPE_FONT_THUMBNAILER_PROVIDER (font_thumbnailer_provider_get_type ())
+#define FONT_THUMBNAILER_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_FONT_THUMBNAILER_PROVIDER, FontThumbnailerProvider))
+#define FONT_THUMBNAILER_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_FONT_THUMBNAILER_PROVIDER, FontThumbnailerProviderClass))
+#define IS_FONT_THUMBNAILER_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_FONT_THUMBNAILER_PROVIDER))
+#define IS_FONT_THUMBNAILER_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_FONT_THUMBNAILER_PROVIDER)
+#define FONT_THUMBNAILER_PROVIDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_FONT_THUMBNAILER_PROVIDER, FontThumbnailerProviderClass))
+
+typedef struct _FontThumbnailerProviderClass FontThumbnailerProviderClass;
+typedef struct _FontThumbnailerProvider FontThumbnailerProvider;
+
+GType font_thumbnailer_provider_get_type (void) G_GNUC_CONST;
+void font_thumbnailer_provider_register (TumblerProviderPlugin *plugin);
+
+G_END_DECLS;
+
+#endif /* !__FONT_THUMBNAILER_PROVIDER_H__ */
diff --git a/plugins/font-thumbnailer/font-thumbnailer.c b/plugins/font-thumbnailer/font-thumbnailer.c
new file mode 100644
index 0000000..07002e2
--- /dev/null
+++ b/plugins/font-thumbnailer/font-thumbnailer.c
@@ -0,0 +1,617 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*-
+ * Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
+ * Copyright (c) 2009 Jannis Pohlmann <jannis@xfce.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include <tumbler/tumbler.h>
+
+#include <font-thumbnailer/font-thumbnailer.h>
+
+
+
+static void font_thumbnailer_finalize (GObject *object);
+static void font_thumbnailer_create (TumblerAbstractThumbnailer *thumbnailer,
+ const gchar *uri,
+ const gchar *mime_hint);
+
+
+
+struct _FontThumbnailerClass
+{
+ TumblerAbstractThumbnailerClass __parent__;
+};
+
+struct _FontThumbnailer
+{
+ TumblerAbstractThumbnailer __parent__;
+
+ FT_Library library;
+ FT_Error library_error;
+};
+
+
+
+G_DEFINE_DYNAMIC_TYPE (FontThumbnailer,
+ font_thumbnailer,
+ TUMBLER_TYPE_ABSTRACT_THUMBNAILER);
+
+
+
+void
+font_thumbnailer_register (TumblerProviderPlugin *plugin)
+{
+ font_thumbnailer_register_type (G_TYPE_MODULE (plugin));
+}
+
+
+
+static void
+font_thumbnailer_class_init (FontThumbnailerClass *klass)
+{
+ TumblerAbstractThumbnailerClass *abstractthumbnailer_class;
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = font_thumbnailer_finalize;
+
+ abstractthumbnailer_class = TUMBLER_ABSTRACT_THUMBNAILER_CLASS (klass);
+ abstractthumbnailer_class->create = font_thumbnailer_create;
+}
+
+
+
+static void
+font_thumbnailer_class_finalize (FontThumbnailerClass *klass)
+{
+}
+
+
+
+static void
+font_thumbnailer_init (FontThumbnailer *thumbnailer)
+{
+ /* initialize freetype and remember possible errors */
+ thumbnailer->library_error = FT_Init_FreeType (&thumbnailer->library);
+}
+
+
+static void
+font_thumbnailer_finalize (GObject *object)
+{
+ FontThumbnailer *thumbnailer = FONT_THUMBNAILER (object);
+
+ /* release the freetype library object */
+ FT_Done_FreeType (thumbnailer->library);
+
+ (*G_OBJECT_CLASS (font_thumbnailer_parent_class)->finalize) (object);
+}
+
+
+
+static const gchar *
+ft_strerror (FT_Error error)
+{
+#undef __FTERRORS_H__
+#define FT_ERRORDEF(e,v,s) case e: return s;
+#define FT_ERROR_START_LIST
+#define FT_ERROR_END_LIST
+ switch (error)
+ {
+#include FT_ERRORS_H
+ default:
+ return "unknown";
+ }
+}
+
+
+
+
+static FT_Error
+render_glyph (GdkPixbuf *pixbuf,
+ FT_Face face,
+ FT_UInt glyph,
+ gint *pen_x,
+ gint *pen_y)
+{
+ FT_GlyphSlot slot = face->glyph;
+ FT_Error error;
+ guchar *pixels;
+ guchar pixel;
+ gint rowstride;
+ gint height;
+ gint width;
+ gint off_x;
+ gint off_y;
+ gint off;
+ gint i, j;
+
+ /* load the glyph */
+ error = FT_Load_Glyph (face, glyph, FT_LOAD_DEFAULT);
+ if (G_UNLIKELY (error != 0))
+ return error;
+
+ /* render the glyph */
+ error = FT_Render_Glyph (slot, ft_render_mode_normal);
+ if (G_UNLIKELY (error != 0))
+ return error;
+
+ off_x = *pen_x + slot->bitmap_left;
+ off_y = *pen_y - slot->bitmap_top;
+
+ pixels = gdk_pixbuf_get_pixels (pixbuf);
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+
+ for (j = 0; j < slot->bitmap.rows; ++j)
+ {
+ if (j + off_y < 0 || j + off_y >= height)
+ continue;
+
+ for (i = 0; i < slot->bitmap.width; ++i)
+ {
+ if (i + off_x < 0 || i + off_x >= width)
+ continue;
+
+ switch (slot->bitmap.pixel_mode)
+ {
+ case ft_pixel_mode_mono:
+ pixel = slot->bitmap.buffer[j * slot->bitmap.pitch + i / 8];
+ pixel = 255 - ((pixel >> (7 - i % 8)) & 0x1) * 255;
+ break;
+
+ case ft_pixel_mode_grays:
+ pixel = 255 - slot->bitmap.buffer[j * slot->bitmap.pitch + i];
+ break;
+
+ default:
+ pixel = 255;
+ break;
+ }
+
+ off = (j + off_y) * rowstride + 3 * (i + off_x);
+ pixels[off + 0] = pixel;
+ pixels[off + 1] = pixel;
+ pixels[off + 2] = pixel;
+ }
+ }
+
+ *pen_x += slot->advance.x >> 6;
+
+ return 0;
+}
+
+
+
+static GdkPixbuf*
+scale_pixbuf (GdkPixbuf *source,
+ gint dest_width,
+ gint dest_height)
+{
+ gdouble wratio;
+ gdouble hratio;
+ gint source_width;
+ gint source_height;
+
+ /* determine source pixbuf dimensions */
+ source_width = gdk_pixbuf_get_width (source);
+ source_height = gdk_pixbuf_get_height (source);
+
+ /* determine which axis needs to be scaled down more */
+ wratio = (gdouble) source_width / (gdouble) dest_width;
+ hratio = (gdouble) source_height / (gdouble) dest_height;
+
+ /* adjust the other axis */
+ if (hratio > wratio)
+ dest_width = rint (source_width / hratio);
+ else
+ dest_height = rint (source_height / wratio);
+
+ /* scale the pixbuf down to the desired size */
+ return gdk_pixbuf_scale_simple (source, MAX (dest_width, 1), MAX (dest_height, 1),
+ GDK_INTERP_BILINEAR);
+}
+
+
+
+static GdkPixbuf *
+trim_and_scale_pixbuf (GdkPixbuf *pixbuf,
+ gint dest_width,
+ gint dest_height)
+{
+ GdkPixbuf *subpixbuf;
+ GdkPixbuf *scaled;
+ gboolean seen_pixel;
+ guchar *pixels;
+ gint rowstride;
+ gint height;
+ gint width;
+ gint i, j;
+ gint trim_left;
+ gint trim_right;
+ gint trim_top;
+ gint trim_bottom;
+ gint offset;
+
+ pixels = gdk_pixbuf_get_pixels (pixbuf);
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+
+ for (i = 0; i < width; ++i)
+ {
+ seen_pixel = FALSE;
+ for (j = 0; j < height; ++j)
+ {
+ offset = j * rowstride + 3 * i;
+ seen_pixel = (pixels[offset + 0] != 0xff ||
+ pixels[offset + 1] != 0xff ||
+ pixels[offset + 2] != 0xff);
+ if (seen_pixel)
+ break;
+ }
+
+ if (seen_pixel)
+ break;
+ }
+
+ trim_left = MIN (width, i);
+ trim_left = MAX (trim_left - 8, 0);
+
+ for (i = width - 1; i >= trim_left; --i)
+ {
+ seen_pixel = FALSE;
+ for (j = 0; j < height; ++j)
+ {
+ offset = j * rowstride + 3 * i;
+ seen_pixel = (pixels[offset + 0] != 0xff ||
+ pixels[offset+1] != 0xff ||
+ pixels[offset+2] != 0xff);
+ if (seen_pixel)
+ break;
+ }
+
+ if (seen_pixel)
+ break;
+ }
+
+ trim_right = MAX (trim_left, i);
+ trim_right = MIN (trim_right + 8, width - 1);
+
+ for (j = 0; j < height; ++j)
+ {
+ seen_pixel = FALSE;
+ for (i = 0; i < width; ++i)
+ {
+ offset = j * rowstride + 3 * i;
+ seen_pixel = (pixels[offset + 0] != 0xff ||
+ pixels[offset + 1] != 0xff ||
+ pixels[offset + 2] != 0xff);
+ if (seen_pixel)
+ break;
+ }
+
+ if (seen_pixel)
+ break;
+ }
+
+ trim_top = MIN (height, j);
+ trim_top = MAX (trim_top - 8, 0);
+
+ for (j = height - 1; j >= trim_top; --j)
+ {
+ seen_pixel = FALSE;
+ for (i = 0; i < width; ++i)
+ {
+ offset = j * rowstride + 3 * i;
+ seen_pixel = (pixels[offset + 0] != 0xff ||
+ pixels[offset + 1] != 0xff ||
+ pixels[offset + 2] != 0xff);
+ if (seen_pixel)
+ break;
+ }
+
+ if (seen_pixel)
+ break;
+ }
+
+ trim_bottom = MAX (trim_top, j);
+ trim_bottom = MIN (trim_bottom + 8, height - 1);
+
+ /* determine the trimmed subpixbuf */
+ subpixbuf = gdk_pixbuf_new_subpixbuf (pixbuf, trim_left, trim_top,
+ trim_right - trim_left,
+ trim_bottom - trim_top);
+
+ /* check if we still need to scale down */
+ if (gdk_pixbuf_get_width (subpixbuf) > dest_width
+ || gdk_pixbuf_get_height (subpixbuf) > dest_height)
+ {
+ scaled = scale_pixbuf (subpixbuf, dest_width, dest_height);
+ g_object_unref (G_OBJECT (subpixbuf));
+ subpixbuf = scaled;
+ }
+
+ return subpixbuf;
+}
+
+
+
+static GdkPixbuf *
+generate_pixbuf (FT_Face face,
+ TumblerThumbnailFlavor flavor,
+ FT_Error *error)
+{
+ GdkPixbuf *pixbuf = NULL;
+ GdkPixbuf *result = NULL;
+ FT_UInt glyph1;
+ FT_UInt glyph2;
+ gint width;
+ gint height;
+ gint pen_x;
+ gint pen_y;
+
+ /* determine the desired size for this flavor */
+ tumbler_thumbnail_flavor_get_size (flavor, &width, &height);
+
+ /* try to set the pixel size */
+ *error = FT_Set_Pixel_Sizes (face, 0, MIN (width, height));
+ if (G_UNLIKELY (*error != 0))
+ return NULL;
+
+ /* determine prefered glyphs for the thumbnail (with appropriate fallbacks) */
+ glyph1 = FT_Get_Char_Index (face, 'A');
+ if (G_UNLIKELY (glyph1 == 0))
+ glyph1 = MIN (65, face->num_glyphs - 1);
+ glyph2 = FT_Get_Char_Index (face, 'a');
+ if (G_UNLIKELY (glyph2 == 0))
+ glyph2 = MIN (97, face->num_glyphs - 1);
+
+ if (flavor == TUMBLER_THUMBNAIL_FLAVOR_CROPPED)
+ {
+ /* TODO unsupported */
+ }
+ else
+ {
+ /* allocate the pixbuf to render the glyphs to */
+ pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width * 3, (height * 3) / 2);
+ gdk_pixbuf_fill (pixbuf, 0xffffffff);
+
+ /* initial pen position */
+ pen_x = width / 2;
+ pen_y = height;
+
+ /* render the first letter to the pixbuf */
+ *error = render_glyph (pixbuf, face, glyph1, &pen_x, &pen_y);
+ if (G_UNLIKELY (*error != 0))
+ return NULL;
+
+ /* render the second letter to the pixbuf */
+ *error = render_glyph (pixbuf, face, glyph2, &pen_x, &pen_y);
+ if (G_UNLIKELY (*error != 0))
+ return NULL;
+
+ /* trim the pixbuf and rescale if necessary */
+ result = trim_and_scale_pixbuf (pixbuf, width, height);
+ g_object_unref (pixbuf);
+ }
+
+ return result;
+}
+
+
+
+static void
+font_thumbnailer_create (TumblerAbstractThumbnailer *thumbnailer,
+ const gchar *uri,
+ const gchar *mime_hint)
+{
+ TumblerThumbnailFlavor *flavors;
+ TumblerThumbnailFlavor flavor;
+ TumblerFileInfo *info;
+ FontThumbnailer *font_thumbnailer = FONT_THUMBNAILER (thumbnailer);
+ GHashTable *pixbufs;
+ GdkPixbuf *pixbuf;
+ GdkPixbuf *font;
+ FT_Error ft_error;
+ FT_Face face;
+ guint64 mtime;
+ GError *error = NULL;
+ GFile *file;
+ GList *lp;
+ GList *thumbnails;
+ gchar *error_msg;
+ gchar *path;
+ gint n;
+
+ g_return_if_fail (IS_FONT_THUMBNAILER (thumbnailer));
+ g_return_if_fail (uri != NULL && *uri != '\0');
+
+ /* check if we have a valid freetype library object */
+ if (font_thumbnailer->library_error != 0)
+ {
+ /* there was an error in the freetype initialization, abort */
+ error_msg = g_strdup_printf (_("Could not initialize freetype: %s"),
+ ft_strerror (font_thumbnailer->library_error));
+ g_signal_emit_by_name (thumbnailer, "error", uri, 0, error_msg);
+ g_free (error_msg);
+ return;
+ }
+
+ /* create the file info for this URI */
+ info = tumbler_file_info_new (uri);
+
+ /* try to load the file information */
+ if (!tumbler_file_info_load (info, NULL, &error))
+ {
+ g_signal_emit_by_name (thumbnailer, "error", uri, error->code, error->message);
+ g_error_free (error);
+ g_object_unref (info);
+ return;
+ }
+
+ /* determine the local path of the file */
+ file = g_file_new_for_uri (uri);
+ path = g_file_get_path (file);
+ g_object_unref (file);
+
+ /* if the local path is not NULL, then something went wrong, as this thumbnailer
+ * only supports file URIs and all those should also have a local path */
+ g_assert (path != NULL);
+
+ /* try to open the font file */
+ ft_error = FT_New_Face (font_thumbnailer->library, path, 0, &face);
+ if (G_UNLIKELY (ft_error != 0))
+ {
+ /* the font file could not be loaded, emit an error signal */
+ error_msg = g_strdup_printf (_("Could not open font file: %s"),
+ ft_strerror (ft_error));
+ g_signal_emit_by_name (thumbnailer, "error", uri, 0, error_msg);
+ g_free (error_msg);
+
+ /* clean up */
+ g_free (path);
+ g_object_unref (info);
+
+ return;
+ }
+
+ /* free the local path */
+ g_free (path);
+
+ /* try to set the character map */
+ for (n = 0; n < face->num_charmaps; ++n)
+ {
+ /* check for a desired character map */
+ if (face->charmaps[n]->encoding == ft_encoding_latin_1
+ || face->charmaps[n]->encoding == ft_encoding_unicode
+ || face->charmaps[n]->encoding == ft_encoding_apple_roman)
+ {
+ /* try to set the character map */
+ ft_error = FT_Set_Charmap (face, face->charmaps[n]);
+ if (G_UNLIKELY (error != 0))
+ {
+ /* emit an error signal */
+ error_msg = g_strdup_printf (_("Could not set the character map: %s"),
+ ft_strerror (ft_error));
+ g_signal_emit_by_name (thumbnailer, "error", uri, 0, error_msg);
+ g_free (error_msg);
+
+ /* clean up */
+ FT_Done_Face (face);
+ g_object_unref (info);
+
+ return;
+ }
+ }
+ }
+
+ /* determine which flavors we need to generate */
+ flavors = tumbler_thumbnail_get_flavors ();
+
+ /* allocate a hash table in which to store the flavor pixbufs */
+ pixbufs = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
+
+ /* iterate over all flavors */
+ for (n = 0; flavors[n] != TUMBLER_THUMBNAIL_FLAVOR_INVALID; ++n)
+ {
+ /* generate a thumbnail for the current flavor */
+ pixbuf = generate_pixbuf (face, flavors[n], &ft_error);
+
+ /* abort if there was an error */
+ if (G_UNLIKELY (ft_error != 0))
+ {
+ /* emit an error signal */
+ error_msg = g_strdup_printf (_("Could not render glyphs: %s"),
+ ft_strerror (ft_error));
+ g_signal_emit_by_name (thumbnailer, "error", uri, 0, error_msg);
+ g_free (error_msg);
+
+ /* clean up */
+ g_hash_table_unref (pixbufs);
+ FT_Done_Face (face);
+ g_object_unref (info);
+
+ return;
+ }
+ else
+ {
+ /* add the pixbuf to the hash table if it could be generated */
+ g_hash_table_insert (pixbufs, GINT_TO_POINTER (flavors[n]), pixbuf);
+ }
+ }
+
+ /* release the font face */
+ FT_Done_Face (face);
+
+ /* determine when the URI was last modified */
+ mtime = tumbler_file_info_get_mtime (info);
+
+ /* get all thumbnail infos for this URI */
+ thumbnails = tumbler_file_info_get_thumbnails (info);
+
+ /* iterate over all thumbnail infos */
+ for (lp = thumbnails; error == NULL && lp != NULL; lp = lp->next)
+ {
+ /* load the thumbnail information and check if it is possibly outdated */
+ if (tumbler_thumbnail_load (lp->data, NULL, &error))
+ if (tumbler_thumbnail_needs_update (lp->data, uri, mtime))
+ {
+ /* get the pixbuf for the flavor of the thumbnail info */
+ flavor = tumbler_thumbnail_get_flavor (lp->data);
+ pixbuf = g_hash_table_lookup (pixbufs, GINT_TO_POINTER (flavor));
+
+ /* if an image for this flavor was generated, save it now */
+ if (pixbuf != NULL)
+ tumbler_thumbnail_save_pixbuf (lp->data, font, mtime, NULL, &error);
+ }
+ }
+
+ /* check if there was an error */
+ if (error != NULL)
+ {
+ /* emit an error signal */
+ g_signal_emit_by_name (thumbnailer, "error", uri, error->code, error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ /* otherwise, the thumbnail is now ready */
+ g_signal_emit_by_name (thumbnailer, "ready", uri);
+ }
+
+ /* clean up */
+ g_hash_table_unref (pixbufs);
+ g_object_unref (info);
+}
diff --git a/plugins/font-thumbnailer/font-thumbnailer.h b/plugins/font-thumbnailer/font-thumbnailer.h
new file mode 100644
index 0000000..287e927
--- /dev/null
+++ b/plugins/font-thumbnailer/font-thumbnailer.h
@@ -0,0 +1,43 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*-
+ * Copyright (c) 2009 Jannis Pohlmann <jannis@xfce.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __FONT_THUMBNAILER_H__
+#define __FONT_THUMBNAILER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS;
+
+#define TYPE_FONT_THUMBNAILER (font_thumbnailer_get_type ())
+#define FONT_THUMBNAILER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_FONT_THUMBNAILER, FontThumbnailer))
+#define FONT_THUMBNAILER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_FONT_THUMBNAILER, FontThumbnailerClass))
+#define IS_FONT_THUMBNAILER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_FONT_THUMBNAILER))
+#define IS_FONT_THUMBNAILER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_FONT_THUMBNAILER)
+#define FONT_THUMBNAILER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_FONT_THUMBNAILER, FontThumbnailerClass))
+
+typedef struct _FontThumbnailerClass FontThumbnailerClass;
+typedef struct _FontThumbnailer FontThumbnailer;
+
+GType font_thumbnailer_get_type (void) G_GNUC_CONST;
+void font_thumbnailer_register (TumblerProviderPlugin *plugin);
+
+G_END_DECLS;
+
+#endif /* !__FONT_THUMBNAILER_H__ */
diff --git a/tumblerd/tumbler-cache-service.c b/tumblerd/tumbler-cache-service.c
index d3d552c..61a7d6b 100644
--- a/tumblerd/tumbler-cache-service.c
+++ b/tumblerd/tumbler-cache-service.c
@@ -378,7 +378,7 @@ tumbler_cache_service_start (TumblerCacheService *service,
connection = dbus_g_connection_get_connection (service->connection);
/* request ownership for the cache interface */
- result = dbus_bus_request_name (connection, "org.freedesktop.thumbnails.Cache",
+ result = dbus_bus_request_name (connection, "org.xfce.thumbnails.Cache",
DBUS_NAME_FLAG_DO_NOT_QUEUE, &dbus_error);
/* check if that failed */
@@ -409,7 +409,7 @@ tumbler_cache_service_start (TumblerCacheService *service,
/* register the cache instance as a handler of the cache interface */
dbus_g_connection_register_g_object (service->connection,
- "/org/freedesktop/thumbnails/Cache",
+ "/org/xfce/thumbnails/Cache",
G_OBJECT (service));
g_mutex_unlock (service->mutex);
diff --git a/tumblerd/tumbler-manager.c b/tumblerd/tumbler-manager.c
index 95da321..13f37f3 100644
--- a/tumblerd/tumbler-manager.c
+++ b/tumblerd/tumbler-manager.c
@@ -210,7 +210,7 @@ tumbler_manager_start (TumblerManager *manager,
connection = dbus_g_connection_get_connection (manager->connection);
/* request ownership for the manager interface */
- result = dbus_bus_request_name (connection, "org.freedesktop.thumbnails.Manager",
+ result = dbus_bus_request_name (connection, "org.xfce.thumbnails.Manager",
DBUS_NAME_FLAG_DO_NOT_QUEUE, &dbus_error);
/* check if that failed */
@@ -242,7 +242,7 @@ tumbler_manager_start (TumblerManager *manager,
/* register the manager instance as a handler of the manager interface */
dbus_g_connection_register_g_object (manager->connection,
- "/org/freedesktop/thumbnails/Manager",
+ "/org/xfce/thumbnails/Manager",
G_OBJECT (manager));
g_mutex_unlock (manager->mutex);
diff --git a/tumblerd/tumbler-service.c b/tumblerd/tumbler-service.c
index 9be64ce..5f475cc 100644
--- a/tumblerd/tumbler-service.c
+++ b/tumblerd/tumbler-service.c
@@ -363,7 +363,7 @@ tumbler_service_start (TumblerService *service,
connection = dbus_g_connection_get_connection (service->connection);
/* request ownership for the generic thumbnailer interface */
- result = dbus_bus_request_name (connection, "org.freedesktop.thumbnails.Thumbnailer",
+ result = dbus_bus_request_name (connection, "org.xfce.thumbnails.Thumbnailer",
DBUS_NAME_FLAG_DO_NOT_QUEUE, &dbus_error);
/* check if that failed */
@@ -394,7 +394,7 @@ tumbler_service_start (TumblerService *service,
/* register the service instance as a handler of this interface */
dbus_g_connection_register_g_object (service->connection,
- "/org/freedesktop/thumbnails/Thumbnailer",
+ "/org/xfce/thumbnails/Thumbnailer",
G_OBJECT (service));
g_mutex_unlock (service->mutex);
diff --git a/tumblerd/tumbler-specialized-thumbnailer.c b/tumblerd/tumbler-specialized-thumbnailer.c
index 2c4500f..36d7f51 100644
--- a/tumblerd/tumbler-specialized-thumbnailer.c
+++ b/tumblerd/tumbler-specialized-thumbnailer.c
@@ -197,7 +197,7 @@ tumbler_specialized_thumbnailer_constructed (GObject *object)
thumbnailer->proxy = dbus_g_proxy_new_for_name (thumbnailer->connection,
thumbnailer->name,
bus_path,
- "org.freedesktop.thumbnailer.Thumbnailer");
+ "org.xfce.thumbnailer.Thumbnailer");
g_free (bus_path);