2018-06-03 03:54:34 +08:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
|
|
|
* gimpfontfactory.c
|
|
|
|
* Copyright (C) 2003-2018 Michael Natterer <mitch@gimp.org>
|
|
|
|
*
|
|
|
|
* Partly based on code Copyright (C) Sven Neumann <sven@gimp.org>
|
|
|
|
* Manish Singh <yosh@gimp.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 3 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, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
|
|
|
#include <pango/pangocairo.h>
|
|
|
|
#include <pango/pangofc-fontmap.h>
|
|
|
|
#include <gegl.h>
|
|
|
|
|
|
|
|
#include "libgimpbase/gimpbase.h"
|
|
|
|
#include "libgimpconfig/gimpconfig.h"
|
|
|
|
|
|
|
|
#include "text-types.h"
|
|
|
|
|
|
|
|
#include "core/gimp.h"
|
|
|
|
#include "core/gimp-parallel.h"
|
|
|
|
#include "core/gimpasync.h"
|
|
|
|
#include "core/gimpasyncset.h"
|
app: a few async font loading fixes
In gimp_data_factory_finalize(), wait on the factory's async set
after canceling it, and before continuing destruction. It's not
generally safe to just abandon an async op without waiting on it
-- this is a font-specific hack, due to the fact we can't actually
cancel font loading, and GimpFontFactory is prepared to handle
this.
Instead, in gimp_font_factory_finalize(), cancel and clear the
async set, so that GimpDataFactory doesn't actually wait for
loading to finish.
In gimp_font_factory_load_async_callback(), don't try to acess the
factory when the operation is canceled, since cancelation means the
factory is already dead. On the other hand, when the opeation
isn't canceled, make sure to thaw the container even when font
loading failed, so that we always match the freeze at the begining
of the operation.
2018-06-29 03:23:12 +08:00
|
|
|
#include "core/gimpcancelable.h"
|
2018-06-03 03:54:34 +08:00
|
|
|
#include "core/gimpcontainer.h"
|
|
|
|
|
|
|
|
#include "gimpfont.h"
|
|
|
|
#include "gimpfontfactory.h"
|
|
|
|
|
|
|
|
#include "gimp-intl.h"
|
|
|
|
|
|
|
|
|
|
|
|
/* Use fontconfig directly for speed. We can use the pango stuff when/if
|
|
|
|
* fontconfig/pango get more efficient.
|
|
|
|
*/
|
|
|
|
#define USE_FONTCONFIG_DIRECTLY
|
|
|
|
|
|
|
|
#ifdef USE_FONTCONFIG_DIRECTLY
|
|
|
|
#include <fontconfig/fontconfig.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define CONF_FNAME "fonts.conf"
|
|
|
|
|
|
|
|
|
|
|
|
struct _GimpFontFactoryPrivate
|
|
|
|
{
|
2018-06-04 04:28:00 +08:00
|
|
|
gpointer foo; /* can't have an empty struct */
|
2018-06-03 03:54:34 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
#define GET_PRIVATE(obj) (((GimpFontFactory *) (obj))->priv)
|
|
|
|
|
|
|
|
|
app: a few async font loading fixes
In gimp_data_factory_finalize(), wait on the factory's async set
after canceling it, and before continuing destruction. It's not
generally safe to just abandon an async op without waiting on it
-- this is a font-specific hack, due to the fact we can't actually
cancel font loading, and GimpFontFactory is prepared to handle
this.
Instead, in gimp_font_factory_finalize(), cancel and clear the
async set, so that GimpDataFactory doesn't actually wait for
loading to finish.
In gimp_font_factory_load_async_callback(), don't try to acess the
factory when the operation is canceled, since cancelation means the
factory is already dead. On the other hand, when the opeation
isn't canceled, make sure to thaw the container even when font
loading failed, so that we always match the freeze at the begining
of the operation.
2018-06-29 03:23:12 +08:00
|
|
|
static void gimp_font_factory_finalize (GObject *object);
|
|
|
|
|
2018-06-03 03:54:34 +08:00
|
|
|
static void gimp_font_factory_data_init (GimpDataFactory *factory,
|
2018-06-04 05:16:29 +08:00
|
|
|
GimpContext *context);
|
2018-06-03 03:54:34 +08:00
|
|
|
static void gimp_font_factory_data_refresh (GimpDataFactory *factory,
|
|
|
|
GimpContext *context);
|
|
|
|
static void gimp_font_factory_data_save (GimpDataFactory *factory);
|
|
|
|
static GimpData * gimp_font_factory_data_duplicate (GimpDataFactory *factory,
|
|
|
|
GimpData *data);
|
|
|
|
static gboolean gimp_font_factory_data_delete (GimpDataFactory *factory,
|
|
|
|
GimpData *data,
|
|
|
|
gboolean delete_from_disk,
|
|
|
|
GError **error);
|
|
|
|
|
|
|
|
static void gimp_font_factory_load (GimpFontFactory *factory,
|
|
|
|
GError **error);
|
|
|
|
static gboolean gimp_font_factory_load_fonts_conf (FcConfig *config,
|
|
|
|
GFile *fonts_conf);
|
|
|
|
static void gimp_font_factory_add_directories (FcConfig *config,
|
|
|
|
GList *path,
|
|
|
|
GError **error);
|
|
|
|
static void gimp_font_factory_recursive_add_fontdir
|
|
|
|
(FcConfig *config,
|
|
|
|
GFile *file,
|
|
|
|
GError **error);
|
|
|
|
static void gimp_font_factory_load_names (GimpContainer *container,
|
|
|
|
PangoFontMap *fontmap,
|
|
|
|
PangoContext *context);
|
|
|
|
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (GimpFontFactory, gimp_font_factory, GIMP_TYPE_DATA_FACTORY)
|
|
|
|
|
|
|
|
#define parent_class gimp_font_factory_parent_class
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_font_factory_class_init (GimpFontFactoryClass *klass)
|
|
|
|
{
|
app: a few async font loading fixes
In gimp_data_factory_finalize(), wait on the factory's async set
after canceling it, and before continuing destruction. It's not
generally safe to just abandon an async op without waiting on it
-- this is a font-specific hack, due to the fact we can't actually
cancel font loading, and GimpFontFactory is prepared to handle
this.
Instead, in gimp_font_factory_finalize(), cancel and clear the
async set, so that GimpDataFactory doesn't actually wait for
loading to finish.
In gimp_font_factory_load_async_callback(), don't try to acess the
factory when the operation is canceled, since cancelation means the
factory is already dead. On the other hand, when the opeation
isn't canceled, make sure to thaw the container even when font
loading failed, so that we always match the freeze at the begining
of the operation.
2018-06-29 03:23:12 +08:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
2018-06-03 03:54:34 +08:00
|
|
|
GimpDataFactoryClass *factory_class = GIMP_DATA_FACTORY_CLASS (klass);
|
|
|
|
|
app: a few async font loading fixes
In gimp_data_factory_finalize(), wait on the factory's async set
after canceling it, and before continuing destruction. It's not
generally safe to just abandon an async op without waiting on it
-- this is a font-specific hack, due to the fact we can't actually
cancel font loading, and GimpFontFactory is prepared to handle
this.
Instead, in gimp_font_factory_finalize(), cancel and clear the
async set, so that GimpDataFactory doesn't actually wait for
loading to finish.
In gimp_font_factory_load_async_callback(), don't try to acess the
factory when the operation is canceled, since cancelation means the
factory is already dead. On the other hand, when the opeation
isn't canceled, make sure to thaw the container even when font
loading failed, so that we always match the freeze at the begining
of the operation.
2018-06-29 03:23:12 +08:00
|
|
|
object_class->finalize = gimp_font_factory_finalize;
|
|
|
|
|
2018-06-03 03:54:34 +08:00
|
|
|
factory_class->data_init = gimp_font_factory_data_init;
|
|
|
|
factory_class->data_refresh = gimp_font_factory_data_refresh;
|
|
|
|
factory_class->data_save = gimp_font_factory_data_save;
|
|
|
|
factory_class->data_duplicate = gimp_font_factory_data_duplicate;
|
|
|
|
factory_class->data_delete = gimp_font_factory_data_delete;
|
|
|
|
|
|
|
|
g_type_class_add_private (klass, sizeof (GimpFontFactoryPrivate));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_font_factory_init (GimpFontFactory *factory)
|
|
|
|
{
|
|
|
|
factory->priv = G_TYPE_INSTANCE_GET_PRIVATE (factory,
|
|
|
|
GIMP_TYPE_FONT_FACTORY,
|
|
|
|
GimpFontFactoryPrivate);
|
|
|
|
}
|
|
|
|
|
app: a few async font loading fixes
In gimp_data_factory_finalize(), wait on the factory's async set
after canceling it, and before continuing destruction. It's not
generally safe to just abandon an async op without waiting on it
-- this is a font-specific hack, due to the fact we can't actually
cancel font loading, and GimpFontFactory is prepared to handle
this.
Instead, in gimp_font_factory_finalize(), cancel and clear the
async set, so that GimpDataFactory doesn't actually wait for
loading to finish.
In gimp_font_factory_load_async_callback(), don't try to acess the
factory when the operation is canceled, since cancelation means the
factory is already dead. On the other hand, when the opeation
isn't canceled, make sure to thaw the container even when font
loading failed, so that we always match the freeze at the begining
of the operation.
2018-06-29 03:23:12 +08:00
|
|
|
static void
|
|
|
|
gimp_font_factory_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
GimpDataFactory *factory = GIMP_DATA_FACTORY (object);
|
|
|
|
GimpAsyncSet *async_set = gimp_data_factory_get_async_set (factory);
|
|
|
|
|
|
|
|
/* the finalize() method of GimpDataFactory normally cancels and waits on the
|
|
|
|
* async set, however, since we can't really cancel font loading, we just let
|
|
|
|
* the factory die without waiting for font loading to finish, by clearing
|
|
|
|
* the async set here. we also cancel the async set beforehand, as a way to
|
|
|
|
* signal to gimp_font_factory_load_async_callback() that the factory is
|
|
|
|
* dead, and that it should just do nothing.
|
|
|
|
*/
|
|
|
|
gimp_cancelable_cancel (GIMP_CANCELABLE (async_set));
|
|
|
|
gimp_async_set_clear (async_set);
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
2018-06-03 03:54:34 +08:00
|
|
|
static void
|
|
|
|
gimp_font_factory_data_init (GimpDataFactory *factory,
|
2018-06-04 05:16:29 +08:00
|
|
|
GimpContext *context)
|
2018-06-03 03:54:34 +08:00
|
|
|
{
|
2018-06-04 05:16:29 +08:00
|
|
|
GError *error = NULL;
|
2018-06-03 03:54:34 +08:00
|
|
|
|
2018-06-04 05:16:29 +08:00
|
|
|
gimp_font_factory_load (GIMP_FONT_FACTORY (factory), &error);
|
2018-06-03 03:54:34 +08:00
|
|
|
|
2018-06-04 05:16:29 +08:00
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
gimp_message_literal (gimp_data_factory_get_gimp (factory), NULL,
|
|
|
|
GIMP_MESSAGE_INFO,
|
|
|
|
error->message);
|
|
|
|
g_error_free (error);
|
2018-06-03 03:54:34 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_font_factory_data_refresh (GimpDataFactory *factory,
|
|
|
|
GimpContext *context)
|
|
|
|
{
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
gimp_font_factory_load (GIMP_FONT_FACTORY (factory), &error);
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
gimp_message_literal (gimp_data_factory_get_gimp (factory), NULL,
|
|
|
|
GIMP_MESSAGE_INFO,
|
|
|
|
error->message);
|
|
|
|
g_error_free (error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_font_factory_data_save (GimpDataFactory *factory)
|
|
|
|
{
|
|
|
|
/* this is not "saving" but this functions is called at the right
|
|
|
|
* time at exit to reset the config
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* if font loading is in progress in another thread, do nothing. calling
|
|
|
|
* FcInitReinitialize() while loading takes place is unsafe.
|
|
|
|
*/
|
2018-06-04 04:28:00 +08:00
|
|
|
if (! gimp_async_set_is_empty (gimp_data_factory_get_async_set (factory)))
|
2018-06-03 03:54:34 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* Reinit the library with defaults. */
|
|
|
|
FcInitReinitialize ();
|
|
|
|
}
|
|
|
|
|
|
|
|
static GimpData *
|
|
|
|
gimp_font_factory_data_duplicate (GimpDataFactory *factory,
|
|
|
|
GimpData *data)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
gimp_font_factory_data_delete (GimpDataFactory *factory,
|
|
|
|
GimpData *data,
|
|
|
|
gboolean delete_from_disk,
|
|
|
|
GError **error)
|
|
|
|
{
|
2018-06-04 19:12:14 +08:00
|
|
|
return TRUE;
|
2018-06-03 03:54:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* public functions */
|
|
|
|
|
|
|
|
GimpDataFactory *
|
|
|
|
gimp_font_factory_new (Gimp *gimp,
|
|
|
|
const gchar *path_property_name)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
|
|
|
|
g_return_val_if_fail (path_property_name != NULL, NULL);
|
|
|
|
|
|
|
|
return g_object_new (GIMP_TYPE_FONT_FACTORY,
|
|
|
|
"gimp", gimp,
|
|
|
|
"data-type", GIMP_TYPE_FONT,
|
|
|
|
"path-property-name", path_property_name,
|
2018-06-04 18:18:13 +08:00
|
|
|
"get-standard-func", gimp_font_get_standard,
|
2018-06-03 03:54:34 +08:00
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* private functions */
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_font_factory_load_async (GimpAsync *async,
|
|
|
|
FcConfig *config)
|
|
|
|
{
|
|
|
|
if (FcConfigBuildFonts (config))
|
|
|
|
{
|
|
|
|
gimp_async_finish (async, config);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FcConfigDestroy (config);
|
|
|
|
|
|
|
|
gimp_async_abort (async);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_font_factory_load_async_callback (GimpAsync *async,
|
|
|
|
GimpFontFactory *factory)
|
|
|
|
{
|
2018-06-04 02:44:28 +08:00
|
|
|
GimpContainer *container;
|
|
|
|
|
app: a few async font loading fixes
In gimp_data_factory_finalize(), wait on the factory's async set
after canceling it, and before continuing destruction. It's not
generally safe to just abandon an async op without waiting on it
-- this is a font-specific hack, due to the fact we can't actually
cancel font loading, and GimpFontFactory is prepared to handle
this.
Instead, in gimp_font_factory_finalize(), cancel and clear the
async set, so that GimpDataFactory doesn't actually wait for
loading to finish.
In gimp_font_factory_load_async_callback(), don't try to acess the
factory when the operation is canceled, since cancelation means the
factory is already dead. On the other hand, when the opeation
isn't canceled, make sure to thaw the container even when font
loading failed, so that we always match the freeze at the begining
of the operation.
2018-06-29 03:23:12 +08:00
|
|
|
/* the operation was canceled during factory destruction. bail. */
|
2018-06-03 03:54:34 +08:00
|
|
|
if (gimp_async_is_canceled (async))
|
app: a few async font loading fixes
In gimp_data_factory_finalize(), wait on the factory's async set
after canceling it, and before continuing destruction. It's not
generally safe to just abandon an async op without waiting on it
-- this is a font-specific hack, due to the fact we can't actually
cancel font loading, and GimpFontFactory is prepared to handle
this.
Instead, in gimp_font_factory_finalize(), cancel and clear the
async set, so that GimpDataFactory doesn't actually wait for
loading to finish.
In gimp_font_factory_load_async_callback(), don't try to acess the
factory when the operation is canceled, since cancelation means the
factory is already dead. On the other hand, when the opeation
isn't canceled, make sure to thaw the container even when font
loading failed, so that we always match the freeze at the begining
of the operation.
2018-06-29 03:23:12 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
container = gimp_data_factory_get_container (GIMP_DATA_FACTORY (factory));
|
2018-06-03 03:54:34 +08:00
|
|
|
|
|
|
|
if (gimp_async_is_finished (async))
|
|
|
|
{
|
2018-06-04 02:44:28 +08:00
|
|
|
FcConfig *config = gimp_async_get_result (async);
|
|
|
|
PangoFontMap *fontmap;
|
|
|
|
PangoContext *context;
|
2018-06-03 03:54:34 +08:00
|
|
|
|
|
|
|
FcConfigSetCurrent (config);
|
|
|
|
|
|
|
|
fontmap = pango_cairo_font_map_new_for_font_type (CAIRO_FONT_TYPE_FT);
|
|
|
|
if (! fontmap)
|
|
|
|
g_error ("You are using a Pango that has been built against a cairo "
|
|
|
|
"that lacks the Freetype font backend");
|
|
|
|
|
|
|
|
pango_cairo_font_map_set_resolution (PANGO_CAIRO_FONT_MAP (fontmap),
|
|
|
|
72.0 /* FIXME */);
|
|
|
|
context = pango_font_map_create_context (fontmap);
|
|
|
|
g_object_unref (fontmap);
|
|
|
|
|
|
|
|
gimp_font_factory_load_names (container, PANGO_FONT_MAP (fontmap), context);
|
|
|
|
g_object_unref (context);
|
|
|
|
}
|
app: a few async font loading fixes
In gimp_data_factory_finalize(), wait on the factory's async set
after canceling it, and before continuing destruction. It's not
generally safe to just abandon an async op without waiting on it
-- this is a font-specific hack, due to the fact we can't actually
cancel font loading, and GimpFontFactory is prepared to handle
this.
Instead, in gimp_font_factory_finalize(), cancel and clear the
async set, so that GimpDataFactory doesn't actually wait for
loading to finish.
In gimp_font_factory_load_async_callback(), don't try to acess the
factory when the operation is canceled, since cancelation means the
factory is already dead. On the other hand, when the opeation
isn't canceled, make sure to thaw the container even when font
loading failed, so that we always match the freeze at the begining
of the operation.
2018-06-29 03:23:12 +08:00
|
|
|
|
|
|
|
gimp_container_thaw (container);
|
2018-06-03 03:54:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_font_factory_load (GimpFontFactory *factory,
|
|
|
|
GError **error)
|
|
|
|
{
|
2018-06-04 04:28:00 +08:00
|
|
|
GimpContainer *container;
|
|
|
|
Gimp *gimp;
|
|
|
|
GimpAsyncSet *async_set;
|
|
|
|
FcConfig *config;
|
|
|
|
GFile *fonts_conf;
|
|
|
|
GList *path;
|
|
|
|
GimpAsync *async;
|
|
|
|
|
|
|
|
async_set = gimp_data_factory_get_async_set (GIMP_DATA_FACTORY (factory));
|
|
|
|
|
|
|
|
if (! gimp_async_set_is_empty (async_set))
|
2018-06-03 03:54:34 +08:00
|
|
|
{
|
|
|
|
/* font loading is already in progress */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
container = gimp_data_factory_get_container (GIMP_DATA_FACTORY (factory));
|
|
|
|
|
|
|
|
gimp = gimp_data_factory_get_gimp (GIMP_DATA_FACTORY (factory));
|
|
|
|
|
|
|
|
if (gimp->be_verbose)
|
|
|
|
g_print ("Loading fonts\n");
|
|
|
|
|
|
|
|
config = FcInitLoadConfig ();
|
|
|
|
|
|
|
|
if (! config)
|
2018-06-04 02:44:28 +08:00
|
|
|
return;
|
2018-06-03 03:54:34 +08:00
|
|
|
|
|
|
|
fonts_conf = gimp_directory_file (CONF_FNAME, NULL);
|
|
|
|
if (! gimp_font_factory_load_fonts_conf (config, fonts_conf))
|
2018-06-04 02:44:28 +08:00
|
|
|
return;
|
2018-06-03 03:54:34 +08:00
|
|
|
|
|
|
|
fonts_conf = gimp_sysconf_directory_file (CONF_FNAME, NULL);
|
|
|
|
if (! gimp_font_factory_load_fonts_conf (config, fonts_conf))
|
2018-06-04 02:44:28 +08:00
|
|
|
return;
|
2018-06-03 03:54:34 +08:00
|
|
|
|
2018-06-04 02:44:28 +08:00
|
|
|
path = gimp_data_factory_get_data_path (GIMP_DATA_FACTORY (factory));
|
|
|
|
if (! path)
|
|
|
|
return;
|
2018-06-03 03:54:34 +08:00
|
|
|
|
2018-06-04 02:44:28 +08:00
|
|
|
gimp_container_freeze (container);
|
|
|
|
gimp_container_clear (container);
|
2018-06-03 03:54:34 +08:00
|
|
|
|
|
|
|
gimp_font_factory_add_directories (config, path, error);
|
|
|
|
g_list_free_full (path, (GDestroyNotify) g_object_unref);
|
|
|
|
|
|
|
|
/* We perform font cache initialization in a separate thread, so
|
|
|
|
* in the case a cache rebuild is to be done it will not block
|
|
|
|
* the UI.
|
|
|
|
*/
|
app: add gimp_parallel_run_async_{full,independent}()
Remove the "independent" parameter of gimp_parallel_run_async(),
and have the function always execute the passed callback in the
shared async thread-pool.
Add a new gimp_parallel_run_async_full() function, taking, in
addition to a callback and a data pointer:
- A priority value, controlling the priority of the callback in
the async thread-pool queue. 0 is the default priority (used
by gimp_parallel_run_async()), negative values have higher
priority, and positive values have lower priority.
- A destructor function for the data pointer. This function is
called to free the user data in case the async operation is
canceled before execution of the callback function begins, and
the operation is dropped from the queue and aborted without
executing the callback. Note that if the callback *is*
executed, the destructor is *not* used -- it's the callback's
responsibility to free/recycle the user data.
Add a separate gimp_parallel_run_async_independent() function,
taking the same parameters, and executing the passed callback in
an independent thread, rather than the thread pool. This function
doesn't take a priority value or a destructor (and there's no
corresponding "_full()" variant that does), since they're pointless
for independent threads.
Adapt the rest of the code to the changes.
2018-07-01 21:57:46 +08:00
|
|
|
async = gimp_parallel_run_async_independent (
|
|
|
|
(GimpParallelRunAsyncFunc) gimp_font_factory_load_async,
|
|
|
|
config);
|
2018-06-03 03:54:34 +08:00
|
|
|
|
|
|
|
gimp_async_add_callback (async,
|
|
|
|
(GimpAsyncCallback) gimp_font_factory_load_async_callback,
|
2018-06-03 05:19:51 +08:00
|
|
|
factory);
|
2018-06-03 03:54:34 +08:00
|
|
|
|
2018-06-04 04:28:00 +08:00
|
|
|
gimp_async_set_add (async_set, async);
|
2018-06-03 03:54:34 +08:00
|
|
|
|
|
|
|
g_object_unref (async);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
gimp_font_factory_load_fonts_conf (FcConfig *config,
|
|
|
|
GFile *fonts_conf)
|
|
|
|
{
|
|
|
|
gchar *path = g_file_get_path (fonts_conf);
|
|
|
|
gboolean ret = TRUE;
|
|
|
|
|
|
|
|
if (! FcConfigParseAndLoad (config, (const guchar *) path, FcFalse))
|
|
|
|
{
|
|
|
|
FcConfigDestroy (config);
|
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (path);
|
|
|
|
g_object_unref (fonts_conf);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_font_factory_add_directories (FcConfig *config,
|
|
|
|
GList *path,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
GList *list;
|
|
|
|
|
|
|
|
for (list = path; list; list = list->next)
|
|
|
|
{
|
|
|
|
/* The configured directories must exist or be created. */
|
|
|
|
g_file_make_directory_with_parents (list->data, NULL, NULL);
|
|
|
|
|
|
|
|
/* Do not use FcConfigAppFontAddDir(). Instead use
|
|
|
|
* FcConfigAppFontAddFile() with our own recursive loop.
|
|
|
|
* Otherwise, when some fonts fail to load (e.g. permission
|
|
|
|
* issues), we end up in weird situations where the fonts are in
|
|
|
|
* the list, but are unusable and output many errors.
|
|
|
|
* See bug 748553.
|
|
|
|
*/
|
|
|
|
gimp_font_factory_recursive_add_fontdir (config, list->data, error);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (error && *error)
|
|
|
|
{
|
|
|
|
gchar *font_list = g_strdup ((*error)->message);
|
|
|
|
|
|
|
|
g_clear_error (error);
|
|
|
|
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
|
|
|
_("Some fonts failed to load:\n%s"), font_list);
|
|
|
|
g_free (font_list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_font_factory_recursive_add_fontdir (FcConfig *config,
|
|
|
|
GFile *file,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
GFileEnumerator *enumerator;
|
|
|
|
|
|
|
|
g_return_if_fail (config != NULL);
|
|
|
|
|
|
|
|
enumerator = g_file_enumerate_children (file,
|
|
|
|
G_FILE_ATTRIBUTE_STANDARD_NAME ","
|
|
|
|
G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN ","
|
|
|
|
G_FILE_ATTRIBUTE_STANDARD_TYPE ","
|
|
|
|
G_FILE_ATTRIBUTE_TIME_MODIFIED,
|
|
|
|
G_FILE_QUERY_INFO_NONE,
|
|
|
|
NULL, NULL);
|
|
|
|
if (enumerator)
|
|
|
|
{
|
|
|
|
GFileInfo *info;
|
|
|
|
|
|
|
|
while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)))
|
|
|
|
{
|
|
|
|
GFileType file_type;
|
|
|
|
GFile *child;
|
|
|
|
|
|
|
|
if (g_file_info_get_is_hidden (info))
|
|
|
|
{
|
|
|
|
g_object_unref (info);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
file_type = g_file_info_get_file_type (info);
|
|
|
|
child = g_file_enumerator_get_child (enumerator, info);
|
|
|
|
|
|
|
|
if (file_type == G_FILE_TYPE_DIRECTORY)
|
|
|
|
{
|
|
|
|
gimp_font_factory_recursive_add_fontdir (config, child, error);
|
|
|
|
}
|
|
|
|
else if (file_type == G_FILE_TYPE_REGULAR)
|
|
|
|
{
|
|
|
|
gchar *path = g_file_get_path (child);
|
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
gchar *tmp = g_win32_locale_filename_from_utf8 (path);
|
|
|
|
|
|
|
|
g_free (path);
|
|
|
|
/* XXX: g_win32_locale_filename_from_utf8() may return
|
|
|
|
* NULL. So we need to check that path is not NULL before
|
|
|
|
* trying to load with fontconfig.
|
|
|
|
*/
|
|
|
|
path = tmp;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (! path ||
|
|
|
|
FcFalse == FcConfigAppFontAddFile (config, (const FcChar8 *) path))
|
|
|
|
{
|
|
|
|
g_printerr ("%s: adding font file '%s' failed.\n",
|
|
|
|
G_STRFUNC, path);
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
if (*error)
|
|
|
|
{
|
|
|
|
gchar *current_message = g_strdup ((*error)->message);
|
|
|
|
|
|
|
|
g_clear_error (error);
|
|
|
|
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
|
|
|
"%s\n- %s", current_message, path);
|
|
|
|
g_free (current_message);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
|
|
|
"- %s", path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-06-24 20:14:07 +08:00
|
|
|
|
2018-06-03 03:54:34 +08:00
|
|
|
g_free (path);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_object_unref (child);
|
|
|
|
g_object_unref (info);
|
|
|
|
}
|
2018-06-24 20:14:07 +08:00
|
|
|
|
|
|
|
g_object_unref (enumerator);
|
2018-06-03 03:54:34 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
gchar *path = g_file_get_path (file);
|
|
|
|
|
|
|
|
if (*error)
|
|
|
|
{
|
|
|
|
gchar *current_message = g_strdup ((*error)->message);
|
|
|
|
|
|
|
|
g_clear_error (error);
|
|
|
|
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
|
|
|
"%s\n- %s%s", current_message, path,
|
|
|
|
G_DIR_SEPARATOR_S);
|
|
|
|
g_free (current_message);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
|
|
|
"- %s%s", path, G_DIR_SEPARATOR_S);
|
|
|
|
}
|
2018-06-24 20:14:07 +08:00
|
|
|
|
2018-06-03 03:54:34 +08:00
|
|
|
g_free (path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_font_factory_add_font (GimpContainer *container,
|
|
|
|
PangoContext *context,
|
|
|
|
PangoFontDescription *desc)
|
|
|
|
{
|
|
|
|
gchar *name;
|
|
|
|
|
|
|
|
if (! desc)
|
|
|
|
return;
|
|
|
|
|
|
|
|
name = pango_font_description_to_string (desc);
|
|
|
|
|
|
|
|
/* It doesn't look like pango_font_description_to_string() could ever
|
|
|
|
* return NULL. But just to be double sure and avoid a segfault, I
|
|
|
|
* check before validating the string.
|
|
|
|
*/
|
|
|
|
if (name && strlen (name) > 0 &&
|
|
|
|
g_utf8_validate (name, -1, NULL))
|
|
|
|
{
|
|
|
|
GimpFont *font;
|
|
|
|
|
|
|
|
font = g_object_new (GIMP_TYPE_FONT,
|
|
|
|
"name", name,
|
|
|
|
"pango-context", context,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
gimp_container_add (container, GIMP_OBJECT (font));
|
|
|
|
g_object_unref (font);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (name);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_FONTCONFIG_DIRECTLY
|
|
|
|
/* We're really chummy here with the implementation. Oh well. */
|
|
|
|
|
|
|
|
/* This is copied straight from make_alias_description in pango, plus
|
|
|
|
* the gimp_font_list_add_font bits.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
gimp_font_factory_make_alias (GimpContainer *container,
|
|
|
|
PangoContext *context,
|
|
|
|
const gchar *family,
|
|
|
|
gboolean bold,
|
|
|
|
gboolean italic)
|
|
|
|
{
|
|
|
|
PangoFontDescription *desc = pango_font_description_new ();
|
|
|
|
|
|
|
|
pango_font_description_set_family (desc, family);
|
|
|
|
pango_font_description_set_style (desc,
|
|
|
|
italic ?
|
|
|
|
PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL);
|
|
|
|
pango_font_description_set_variant (desc, PANGO_VARIANT_NORMAL);
|
|
|
|
pango_font_description_set_weight (desc,
|
|
|
|
bold ?
|
|
|
|
PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL);
|
|
|
|
pango_font_description_set_stretch (desc, PANGO_STRETCH_NORMAL);
|
|
|
|
|
|
|
|
gimp_font_factory_add_font (container, context, desc);
|
|
|
|
|
|
|
|
pango_font_description_free (desc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_font_factory_load_aliases (GimpContainer *container,
|
|
|
|
PangoContext *context)
|
|
|
|
{
|
|
|
|
const gchar *families[] = { "Sans-serif", "Serif", "Monospace" };
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
gimp_font_factory_make_alias (container, context, families[i],
|
|
|
|
FALSE, FALSE);
|
|
|
|
gimp_font_factory_make_alias (container, context, families[i],
|
|
|
|
TRUE, FALSE);
|
|
|
|
gimp_font_factory_make_alias (container, context, families[i],
|
|
|
|
FALSE, TRUE);
|
|
|
|
gimp_font_factory_make_alias (container, context, families[i],
|
|
|
|
TRUE, TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_font_factory_load_names (GimpContainer *container,
|
|
|
|
PangoFontMap *fontmap,
|
|
|
|
PangoContext *context)
|
|
|
|
{
|
|
|
|
FcObjectSet *os;
|
|
|
|
FcPattern *pat;
|
|
|
|
FcFontSet *fontset;
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
os = FcObjectSetBuild (FC_FAMILY, FC_STYLE,
|
|
|
|
FC_SLANT, FC_WEIGHT, FC_WIDTH,
|
|
|
|
NULL);
|
|
|
|
g_return_if_fail (os);
|
|
|
|
|
|
|
|
pat = FcPatternCreate ();
|
|
|
|
if (! pat)
|
|
|
|
{
|
|
|
|
FcObjectSetDestroy (os);
|
|
|
|
g_critical ("%s: FcPatternCreate() returned NULL.", G_STRFUNC);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fontset = FcFontList (NULL, pat, os);
|
|
|
|
|
|
|
|
FcPatternDestroy (pat);
|
|
|
|
FcObjectSetDestroy (os);
|
|
|
|
|
|
|
|
g_return_if_fail (fontset);
|
|
|
|
|
|
|
|
for (i = 0; i < fontset->nfont; i++)
|
|
|
|
{
|
|
|
|
PangoFontDescription *desc;
|
|
|
|
|
|
|
|
desc = pango_fc_font_description_from_pattern (fontset->fonts[i], FALSE);
|
|
|
|
gimp_font_factory_add_font (container, context, desc);
|
|
|
|
pango_font_description_free (desc);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* only create aliases if there is at least one font available */
|
|
|
|
if (fontset->nfont > 0)
|
|
|
|
gimp_font_factory_load_aliases (container, context);
|
|
|
|
|
|
|
|
FcFontSetDestroy (fontset);
|
|
|
|
}
|
|
|
|
|
|
|
|
#else /* ! USE_FONTCONFIG_DIRECTLY */
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_font_factory_load_names (GimpContainer *container,
|
|
|
|
PangoFontMap *fontmap,
|
|
|
|
PangoContext *context)
|
|
|
|
{
|
|
|
|
PangoFontFamily **families;
|
|
|
|
PangoFontFace **faces;
|
|
|
|
gint n_families;
|
|
|
|
gint n_faces;
|
|
|
|
gint i, j;
|
|
|
|
|
|
|
|
pango_font_map_list_families (fontmap, &families, &n_families);
|
|
|
|
|
|
|
|
for (i = 0; i < n_families; i++)
|
|
|
|
{
|
|
|
|
pango_font_family_list_faces (families[i], &faces, &n_faces);
|
|
|
|
|
|
|
|
for (j = 0; j < n_faces; j++)
|
|
|
|
{
|
|
|
|
PangoFontDescription *desc;
|
|
|
|
|
|
|
|
desc = pango_font_face_describe (faces[j]);
|
|
|
|
gimp_font_factory_add_font (container, context, desc);
|
|
|
|
pango_font_description_free (desc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (families);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* USE_FONTCONFIG_DIRECTLY */
|