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
|
2018-07-12 05:27:07 +08:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2018-06-03 03:54:34 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#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)
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
app: add gimp_data_factory_data_cancel()
Add a new GimpData::data_cancel() virtual function, and a
corresponding gimp_data_factory_data_cancel() function. This
function should cancel any ongoing async operations related to the
factory (i.e., included in its async set), and wait for the
operations to finish. Provide a default implementation that simply
cancels and waits on the factory's async set.
Use this function to cancel any ongoing operations during factory
destruction, and in gimp_data_factory_data_free().
Override this function in GimpFontFactory, for which we can't
really cancel font loading, and simply cancel and clear the
factory's async set without waiting for loading to finish, making
sure that nothing happens (and, in particular, that the factory
isn't being accessed, since it might be already dead) when loading
does finish.
2018-10-01 15:30:08 +08:00
|
|
|
static void gimp_font_factory_data_cancel (GimpDataFactory *factory);
|
2018-06-03 03:54:34 +08:00
|
|
|
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);
|
|
|
|
|
|
|
|
|
app, libgimp*, modules: don't use g_type_class_add_private() ...
... and G_TYPE_INSTANCE_GET_PRIVATE()
g_type_class_add_private() and G_TYPE_INSTANCE_GET_PRIVATE() were
deprecated in GLib 2.58. Instead, use
G_DEFINE_[ABSTRACT_]TYPE_WITH_PRIVATE(), and
G_ADD_PRIVATE[_DYNAMIC](), and the implictly-defined
foo_get_instance_private() functions, all of which are available in
the GLib versions we depend on.
This commit only covers types registered using one of the
G_DEFINE_FOO() macros (i.e., most types), but not types with a
custom registration function, of which we still have a few -- GLib
currently only provides a (non-deprecated) public API for adding a
private struct using the G_DEFINE_FOO() macros.
Note that this commit was 99% auto-generated (because I'm not
*that* crazy :), so if there are any style mismatches... we'll have
to live with them for now.
2018-09-19 00:09:39 +08:00
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (GimpFontFactory, gimp_font_factory,
|
|
|
|
GIMP_TYPE_DATA_FACTORY)
|
2018-06-03 03:54:34 +08:00
|
|
|
|
|
|
|
#define parent_class gimp_font_factory_parent_class
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_font_factory_class_init (GimpFontFactoryClass *klass)
|
|
|
|
{
|
|
|
|
GimpDataFactoryClass *factory_class = GIMP_DATA_FACTORY_CLASS (klass);
|
|
|
|
|
|
|
|
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;
|
app: add gimp_data_factory_data_cancel()
Add a new GimpData::data_cancel() virtual function, and a
corresponding gimp_data_factory_data_cancel() function. This
function should cancel any ongoing async operations related to the
factory (i.e., included in its async set), and wait for the
operations to finish. Provide a default implementation that simply
cancels and waits on the factory's async set.
Use this function to cancel any ongoing operations during factory
destruction, and in gimp_data_factory_data_free().
Override this function in GimpFontFactory, for which we can't
really cancel font loading, and simply cancel and clear the
factory's async set without waiting for loading to finish, making
sure that nothing happens (and, in particular, that the factory
isn't being accessed, since it might be already dead) when loading
does finish.
2018-10-01 15:30:08 +08:00
|
|
|
factory_class->data_cancel = gimp_font_factory_data_cancel;
|
2018-06-03 03:54:34 +08:00
|
|
|
factory_class->data_duplicate = gimp_font_factory_data_duplicate;
|
|
|
|
factory_class->data_delete = gimp_font_factory_data_delete;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_font_factory_init (GimpFontFactory *factory)
|
|
|
|
{
|
app, libgimp*, modules: don't use g_type_class_add_private() ...
... and G_TYPE_INSTANCE_GET_PRIVATE()
g_type_class_add_private() and G_TYPE_INSTANCE_GET_PRIVATE() were
deprecated in GLib 2.58. Instead, use
G_DEFINE_[ABSTRACT_]TYPE_WITH_PRIVATE(), and
G_ADD_PRIVATE[_DYNAMIC](), and the implictly-defined
foo_get_instance_private() functions, all of which are available in
the GLib versions we depend on.
This commit only covers types registered using one of the
G_DEFINE_FOO() macros (i.e., most types), but not types with a
custom registration function, of which we still have a few -- GLib
currently only provides a (non-deprecated) public API for adding a
private struct using the G_DEFINE_FOO() macros.
Note that this commit was 99% auto-generated (because I'm not
*that* crazy :), so if there are any style mismatches... we'll have
to live with them for now.
2018-09-19 00:09:39 +08:00
|
|
|
factory->priv = gimp_font_factory_get_instance_private (factory);
|
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 ();
|
|
|
|
}
|
|
|
|
|
app: add gimp_data_factory_data_cancel()
Add a new GimpData::data_cancel() virtual function, and a
corresponding gimp_data_factory_data_cancel() function. This
function should cancel any ongoing async operations related to the
factory (i.e., included in its async set), and wait for the
operations to finish. Provide a default implementation that simply
cancels and waits on the factory's async set.
Use this function to cancel any ongoing operations during factory
destruction, and in gimp_data_factory_data_free().
Override this function in GimpFontFactory, for which we can't
really cancel font loading, and simply cancel and clear the
factory's async set without waiting for loading to finish, making
sure that nothing happens (and, in particular, that the factory
isn't being accessed, since it might be already dead) when loading
does finish.
2018-10-01 15:30:08 +08:00
|
|
|
static void
|
|
|
|
gimp_font_factory_data_cancel (GimpDataFactory *factory)
|
|
|
|
{
|
|
|
|
GimpAsyncSet *async_set = gimp_data_factory_get_async_set (factory);
|
|
|
|
|
|
|
|
/* we can't really cancel font loading, so we just clear the async set and
|
|
|
|
* return without waiting for loading to finish. we also cancel the async
|
|
|
|
* set beforehand, as a way to signal to
|
|
|
|
* gimp_font_factory_load_async_callback() that loading was canceled and the
|
|
|
|
* factory might be dead, and that it should just do nothing.
|
|
|
|
*/
|
|
|
|
gimp_cancelable_cancel (GIMP_CANCELABLE (async_set));
|
|
|
|
gimp_async_set_clear (async_set);
|
|
|
|
}
|
|
|
|
|
2018-06-03 03:54:34 +08:00
|
|
|
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: add gimp_data_factory_data_cancel()
Add a new GimpData::data_cancel() virtual function, and a
corresponding gimp_data_factory_data_cancel() function. This
function should cancel any ongoing async operations related to the
factory (i.e., included in its async set), and wait for the
operations to finish. Provide a default implementation that simply
cancels and waits on the factory's async set.
Use this function to cancel any ongoing operations during factory
destruction, and in gimp_data_factory_data_free().
Override this function in GimpFontFactory, for which we can't
really cancel font loading, and simply cancel and clear the
factory's async set without waiting for loading to finish, making
sure that nothing happens (and, in particular, that the factory
isn't being accessed, since it might be already dead) when loading
does finish.
2018-10-01 15:30:08 +08:00
|
|
|
/* the operation was canceled and the factory might be dead (see
|
|
|
|
* gimp_font_factory_data_cancel()). 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_independent_full()
... which is equivalent to gimp_parallel_run_async_independent(),
except that it takes an additional "priority" parameter, which
specifies the task's priority, with 0 being the default priority,
and lower values indicating higher priority. Unlike
gimp_parallel_run_async_full(), the priority parameter doesn't
directly control the task's priority in a queue, but rather, we use
it to control the priority of the task's dedicated thread, on
supported platforms (previously, all independent async tasks would
run with low priority.)
Use low priority when loading fonts, which can take a long time, to
keep the existing behavior.
2019-03-06 12:39:43 +08:00
|
|
|
async = gimp_parallel_run_async_independent_full (
|
|
|
|
+10,
|
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
|
|
|
(GimpParallelRunAsyncFunc) gimp_font_factory_load_async,
|
|
|
|
config);
|
2018-06-03 03:54:34 +08:00
|
|
|
|
2018-11-30 16:32:33 +08:00
|
|
|
gimp_async_add_callback_for_object (
|
|
|
|
async,
|
|
|
|
(GimpAsyncCallback) gimp_font_factory_load_async_callback,
|
|
|
|
factory,
|
|
|
|
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 */
|