Implement support for custom fonts

Remap font names to unique generated names
so that pango sees them.

keep the font name for display and the internal
name for everything else.

* Fonts are still broken When exporting to pdf

* Not sure if xcf files would be usable on other systems
maybe use hash of psname internally instead

* Not sure if plug-ins using text layer work correctly
(do they use internal font name or the actual name?)
This commit is contained in:
Idriss Fekir 2023-05-15 21:03:54 +01:00 committed by Jehan
parent d337d2d196
commit 5972d8d97f
5 changed files with 224 additions and 22 deletions

View file

@ -3224,7 +3224,9 @@ gimp_context_set_font_name (GimpContext *context,
g_return_if_fail (GIMP_IS_CONTEXT (context));
container = gimp_data_factory_get_container (context->gimp->font_factory);
font = gimp_container_get_child_by_name (container, name);
font = gimp_container_search (container,
(GimpContainerSearchFunc) gimp_font_match_by_lookup_name,
(gpointer) name);
if (font)
{
@ -3324,7 +3326,7 @@ gimp_context_real_set_font (GimpContext *context,
0);
if (font != GIMP_FONT (gimp_font_get_standard ()))
context->font_name = g_strdup (gimp_object_get_name (font));
context->font_name = g_strdup (gimp_font_get_lookup_name (font));
}
g_object_notify (G_OBJECT (context), "font");

View file

@ -71,6 +71,7 @@ struct _GimpFont
PangoLayout *popup_layout;
gint popup_width;
gint popup_height;
gchar *lookup_name;
};
struct _GimpFontClass
@ -111,6 +112,25 @@ G_DEFINE_TYPE (GimpFont, gimp_font, GIMP_TYPE_DATA)
#define parent_class gimp_font_parent_class
void
gimp_font_set_lookup_name (GimpFont *font,
gchar *name)
{
font->lookup_name = name;
}
gboolean
gimp_font_match_by_lookup_name (GimpFont *font,
const gchar *name)
{
return !g_strcmp0 (gimp_font_get_lookup_name (font), name);
}
const gchar*
gimp_font_get_lookup_name (GimpFont *font)
{
return font->lookup_name;
}
static void
gimp_font_class_init (GimpFontClass *klass)
@ -156,6 +176,7 @@ gimp_font_finalize (GObject *object)
g_clear_object (&font->pango_context);
g_clear_object (&font->popup_layout);
g_free (font->lookup_name);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@ -211,7 +232,7 @@ gimp_font_get_popup_size (GimpViewable *viewable,
if (! font->pango_context)
return FALSE;
name = gimp_object_get_name (font);
name = gimp_font_get_lookup_name (font);
font_desc = pango_font_description_from_string (name);
g_return_val_if_fail (font_desc != NULL, FALSE);
@ -266,7 +287,7 @@ gimp_font_get_new_preview (GimpViewable *viewable,
PangoFontDescription *font_desc;
const gchar *name;
name = gimp_object_get_name (font);
name = gimp_font_get_lookup_name (font);
DEBUGPRINT (("%s: ", name));

View file

@ -37,9 +37,13 @@
typedef struct _GimpFontClass GimpFontClass;
GType gimp_font_get_type (void) G_GNUC_CONST;
GimpData * gimp_font_get_standard (void);
GType gimp_font_get_type (void) G_GNUC_CONST;
GimpData * gimp_font_get_standard (void);
const gchar * gimp_font_get_lookup_name (GimpFont *font);
void gimp_font_set_lookup_name (GimpFont *font,
gchar *name);
gboolean gimp_font_match_by_lookup_name (GimpFont *font,
const gchar *name);
#endif /* __GIMP_FONT_H__ */

View file

@ -516,14 +516,16 @@ gimp_font_factory_recursive_add_fontdir (FcConfig *config,
static void
gimp_font_factory_add_font (GimpContainer *container,
PangoContext *context,
PangoFontDescription *desc)
PangoFontDescription *desc,
gchar *full_name)
{
gchar *name;
gchar *name = full_name;
if (! desc)
if (! desc && ! full_name)
return;
name = pango_font_description_to_string (desc);
if (! full_name)
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
@ -538,12 +540,13 @@ gimp_font_factory_add_font (GimpContainer *container,
"name", name,
"pango-context", context,
NULL);
gimp_font_set_lookup_name (font, pango_font_description_to_string (desc));
gimp_container_add (container, GIMP_OBJECT (font));
g_object_unref (font);
}
g_free (name);
if (!full_name)
g_free (name);
}
#ifdef USE_FONTCONFIG_DIRECTLY
@ -571,7 +574,7 @@ gimp_font_factory_make_alias (GimpContainer *container,
PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL);
pango_font_description_set_stretch (desc, PANGO_STRETCH_NORMAL);
gimp_font_factory_add_font (container, context, desc);
gimp_font_factory_add_font (container, context, desc, NULL);
pango_font_description_free (desc);
}
@ -606,8 +609,17 @@ gimp_font_factory_load_names (GimpContainer *container,
FcFontSet *fontset;
gint i;
os = FcObjectSetBuild (FC_FAMILY, FC_STYLE,
FC_SLANT, FC_WEIGHT, FC_WIDTH,
os = FcObjectSetBuild (FC_FAMILY,
FC_STYLE,
FC_POSTSCRIPT_NAME,
FC_FULLNAME,
FC_FILE,
FC_WEIGHT,
FC_SLANT,
FC_WIDTH,
FC_INDEX,
FC_FONTVERSION,
FC_FONTFORMAT,
NULL);
g_return_if_fail (os);
@ -628,11 +640,173 @@ gimp_font_factory_load_names (GimpContainer *container,
for (i = 0; i < fontset->nfont; i++)
{
PangoFontDescription *desc;
PangoFcFont *font;
PangoFontDescription *pfd;
GString *xml;
gchar *fontformat;
gchar *family;
gchar *style;
gchar *psname;
gchar *newname;
gchar *escaped_fullname;
gchar *fullname;
gchar *fullname2;
gchar *desc_fullname;
gchar *desc_file;
gchar *file;
gint index;
gint weight;
gint width;
gint slant;
gint fontversion;
desc = pango_fc_font_description_from_pattern (fontset->fonts[i], FALSE);
gimp_font_factory_add_font (container, context, desc);
pango_font_description_free (desc);
FcPatternGetString (fontset->fonts[i], FC_FILE, 0, (FcChar8 **) &file);
/*
* woff and woff2 cause problems with pango (probably with harfbuzz).
* pcf,pcf.gz are bitmap font formats, not supported by pango (because of harfbuzz).
* afm, pfm, pfb are type1 font formats, not supported by pango (because of harfbuzz).
*/
if (g_str_has_suffix (file, ".woff") ||
g_str_has_suffix (file, ".woff2") ||
g_str_has_suffix (file, ".pcf") ||
g_str_has_suffix (file, ".pcf.gz") ||
g_str_has_suffix (file, ".afm") ||
g_str_has_suffix (file, ".pfm") ||
g_str_has_suffix (file, ".pfb"))
{
g_printerr("Font file: %s is not supported by Pango, it can not be loaded.\n",
file);
continue;
}
/* Pango doesn't support non SFNT fonts because harfbuzz doesn't support them. */
if (FcPatternGetString (fontset->fonts[i], FC_FONTFORMAT, 0, (FcChar8 **) &fontformat) != FcResultMatch ||
(g_ascii_strcasecmp (fontformat, "TrueType") != 0 &&
g_ascii_strcasecmp (fontformat, "CFF") != 0))
continue;
/* Some variable fonts have only a family name and a font version. */
if (FcPatternGetString (fontset->fonts[i], FC_FULLNAME, 0, (FcChar8 **) &fullname) != FcResultMatch)
continue;
/* Sometimes a font has more than one fullname,
* sometimes the second is more appropriate for display,
* in such cases we use it instead of the first.
*/
if (FcPatternGetString (fontset->fonts[i], FC_FULLNAME, 1, (FcChar8 **) &fullname2) != FcResultMatch)
fullname2 = NULL;
/*
* In case the pango font description constructed from the fc pattern is correct,
* we use it instead of renaming the font in fontconfig.
*/
pfd = pango_fc_font_description_from_pattern (fontset->fonts[i], FALSE);
font = PANGO_FC_FONT (pango_context_load_font (context, pfd));
FcPatternGetString (pango_fc_font_get_pattern (font), FC_FULLNAME, 0, (FcChar8 **) &desc_fullname);
FcPatternGetString (pango_fc_font_get_pattern (font), FC_FILE, 0, (FcChar8 **) &desc_file);
g_object_unref (font);
if (!g_strcmp0 (desc_fullname, fullname) && !g_strcmp0 (desc_file, file))
{
if (fullname2 != NULL && g_str_is_ascii (fullname2))
fullname = fullname2;
gimp_font_factory_add_font (container, context, pfd, fullname);
pango_font_description_free (pfd);
continue;
}
pango_font_description_free (pfd);
newname = g_strdup_printf ("gimpfont%i", i);
xml = g_string_new ("<?xml version=\"1.0\"?>\n<match>");
g_string_append_printf (xml,
"<test name=\"family\"><string>%s</string></test>",
newname);
escaped_fullname = g_markup_escape_text (fullname, -1);
g_string_append_printf (xml,
"<edit name=\"fullname\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
escaped_fullname);
g_free (escaped_fullname);
FcPatternGetString (fontset->fonts[i], FC_FAMILY, 0, (FcChar8 **) &family);
family = g_markup_escape_text (family, -1);
g_string_append_printf (xml,
"<edit name=\"family\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
family);
g_free (family);
file = g_markup_escape_text (file, -1);
g_string_append_printf (xml,
"<edit name=\"file\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
file);
g_free (file);
if (FcPatternGetString (fontset->fonts[i], FC_POSTSCRIPT_NAME, 0, (FcChar8 **) &psname) == FcResultMatch)
{
psname = g_markup_escape_text (psname, -1);
g_string_append_printf (xml,
"<edit name=\"postscriptname\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
psname);
g_free (psname);
}
if (FcPatternGetString (fontset->fonts[i], FC_STYLE, 0, (FcChar8 **) &style) == FcResultMatch)
{
style = g_markup_escape_text (style, -1);
g_string_append_printf (xml,
"<edit name=\"style\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
style);
g_free (style);
}
if (FcPatternGetInteger (fontset->fonts[i], FC_WEIGHT, 0, &weight) == FcResultMatch)
g_string_append_printf (xml,
"<edit name=\"weight\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>",
weight);
if (FcPatternGetInteger (fontset->fonts[i], FC_WIDTH, 0, &width) == FcResultMatch)
g_string_append_printf (xml,
"<edit name=\"width\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>",
width);
if (FcPatternGetInteger (fontset->fonts[i], FC_SLANT, 0, &slant) == FcResultMatch)
g_string_append_printf (xml,
"<edit name=\"slant\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>",
slant);
if (FcPatternGetInteger (fontset->fonts[i], FC_FONTVERSION, 0, &fontversion) == FcResultMatch)
g_string_append_printf (xml,
"<edit name=\"fontversion\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>",
fontversion);
if (FcPatternGetInteger (fontset->fonts[i], FC_INDEX, 0, &index) == FcResultMatch)
g_string_append_printf (xml,
"<edit name=\"index\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>",
index);
g_string_append (xml, "</match>\n");
FcConfigParseAndLoadFromMemory (FcConfigGetCurrent (), (const FcChar8 *) xml->str, FcTrue);
pfd = pango_font_description_from_string (newname);
if (fullname2 != NULL && g_str_is_ascii (fullname2))
fullname = fullname2;
gimp_font_factory_add_font (container, context, pfd, fullname);
pango_font_description_free (pfd);
g_free (newname);
g_string_free (xml, TRUE);
}
/* only create aliases if there is at least one font available */
@ -666,7 +840,7 @@ gimp_font_factory_load_names (GimpContainer *container,
PangoFontDescription *desc;
desc = pango_font_face_describe (faces[j]);
gimp_font_factory_add_font (container, context, desc);
gimp_font_factory_add_font (container, context, desc, NULL);
pango_font_description_free (desc);
}
}

View file

@ -34,6 +34,7 @@
#include "core/gimpcontext.h"
#include "text/gimptext.h"
#include "text/gimpfont.h"
#include "gimpcolorpanel.h"
#include "gimpcontainerentry.h"
@ -1308,7 +1309,7 @@ gimp_text_style_editor_update_idle (GimpTextStyleEditor *editor)
if (editor->context->font_name &&
g_strcmp0 (editor->context->font_name,
gimp_object_get_name (gimp_context_get_font (editor->context))))
gimp_font_get_lookup_name (gimp_context_get_font (editor->context))))
{
/* A font is set, but is unavailable; change the help text. */
gchar *help_text;