mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-09 10:20:07 +00:00
gsk: Allow custom fonts in node files
This will let us store complete test fonts inside node files, as data: urls. You can also use a file: url to refer to a local file. The syntax is as follows: text { font: "FONT DESCRIPTION" url("data:font/ttf;base64,FONT DATA"); } with the url being optional.
This commit is contained in:
parent
1c85141612
commit
8158945de9
@ -323,14 +323,22 @@ stroke bounds of the path.
|
||||
### text
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| -------- | ---------------- | ---------------------- | ----------- |
|
||||
| -------- | ------------------- | ------------------- | ----------- |
|
||||
| color | `<color>` | black | non-default |
|
||||
| font | `<string>` | "Cantarell 11" | always |
|
||||
| font | `<string>` `<url>`? | "Cantarell 11" | always |
|
||||
| glyphs | `<glyphs>` | "Hello" | always |
|
||||
| offset | `<point>` | 0 0 | non-default |
|
||||
|
||||
Creates a node like `gsk_text_node_new()` with the given properties.
|
||||
|
||||
If a url is specified for the font, it must point to a font file for the
|
||||
font that is specified in the string. It can be either a data url containing
|
||||
a base64-encoded font file, or a regular url that points to a font file.
|
||||
|
||||
Glyphs can be specified as an ASCII string, or as a comma-separated list of
|
||||
their glyph ID and advance width. Optionally, x and y offsets and flags can
|
||||
be specified as well, like this: 40 10 0 0 color.
|
||||
|
||||
If the given font does not exist or the given glyphs are invalid for the given
|
||||
font, an error node will be returned.
|
||||
|
||||
|
@ -46,12 +46,20 @@
|
||||
#include <cairo-script-interpreter.h>
|
||||
#endif
|
||||
|
||||
#include <pango/pangocairo.h>
|
||||
#ifdef HAVE_PANGOFT
|
||||
#include <pango/pangofc-fontmap.h>
|
||||
#endif
|
||||
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
typedef struct _Context Context;
|
||||
|
||||
struct _Context
|
||||
{
|
||||
GHashTable *named_nodes;
|
||||
GHashTable *named_textures;
|
||||
PangoFontMap *fontmap;
|
||||
};
|
||||
|
||||
typedef struct _Declaration Declaration;
|
||||
@ -75,6 +83,7 @@ context_finish (Context *context)
|
||||
{
|
||||
g_clear_pointer (&context->named_nodes, g_hash_table_unref);
|
||||
g_clear_pointer (&context->named_textures, g_hash_table_unref);
|
||||
g_clear_object (&context->fontmap);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -844,20 +853,35 @@ parse_mask_mode (GtkCssParser *parser,
|
||||
}
|
||||
|
||||
static PangoFont *
|
||||
font_from_string (const char *string)
|
||||
font_from_string (PangoFontMap *fontmap,
|
||||
const char *string)
|
||||
{
|
||||
PangoFontDescription *desc;
|
||||
PangoFontMap *font_map;
|
||||
PangoContext *context;
|
||||
PangoContext *ctx;
|
||||
PangoFont *font;
|
||||
|
||||
desc = pango_font_description_from_string (string);
|
||||
font_map = pango_cairo_font_map_get_default ();
|
||||
context = pango_font_map_create_context (font_map);
|
||||
font = pango_font_map_load_font (font_map, context, desc);
|
||||
ctx = pango_font_map_create_context (fontmap);
|
||||
font = pango_font_map_load_font (fontmap, ctx, desc);
|
||||
g_object_unref (ctx);
|
||||
|
||||
if (font)
|
||||
{
|
||||
PangoFontDescription *desc2;
|
||||
const char *family, *family2;
|
||||
|
||||
desc2 = pango_font_describe (font);
|
||||
|
||||
family = pango_font_description_get_family (desc);
|
||||
family2 = pango_font_description_get_family (desc2);
|
||||
|
||||
if (g_strcmp0 (family, family2) != 0)
|
||||
g_clear_object (&font);
|
||||
|
||||
pango_font_description_free (desc2);
|
||||
}
|
||||
|
||||
pango_font_description_free (desc);
|
||||
g_object_unref (context);
|
||||
|
||||
return font;
|
||||
}
|
||||
@ -926,22 +950,204 @@ create_ascii_glyphs (PangoFont *font)
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PANGOFT
|
||||
|
||||
static void
|
||||
delete_file (gpointer data)
|
||||
{
|
||||
char *path = data;
|
||||
|
||||
g_remove (path);
|
||||
g_free (path);
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_fontmap (Context *context)
|
||||
{
|
||||
FcConfig *config;
|
||||
GPtrArray *files;
|
||||
|
||||
if (context->fontmap)
|
||||
return;
|
||||
|
||||
context->fontmap = pango_cairo_font_map_new ();
|
||||
|
||||
config = FcInitLoadConfig ();
|
||||
pango_fc_font_map_set_config (PANGO_FC_FONT_MAP (context->fontmap), config);
|
||||
FcConfigDestroy (config);
|
||||
|
||||
files = g_ptr_array_new_with_free_func (delete_file);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (context->fontmap), "font-files", files, (GDestroyNotify) g_ptr_array_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
add_font_from_file (Context *context,
|
||||
const char *path,
|
||||
GError **error)
|
||||
{
|
||||
FcConfig *config;
|
||||
GPtrArray *files;
|
||||
|
||||
ensure_fontmap (context);
|
||||
|
||||
if (!PANGO_IS_FC_FONT_MAP (context->fontmap))
|
||||
{
|
||||
g_set_error (error,
|
||||
GTK_CSS_PARSER_ERROR,
|
||||
GTK_CSS_PARSER_ERROR_FAILED,
|
||||
"Custom fonts are not implemented for %s", G_OBJECT_TYPE_NAME (context->fontmap));
|
||||
return;
|
||||
}
|
||||
|
||||
config = pango_fc_font_map_get_config (PANGO_FC_FONT_MAP (context->fontmap));
|
||||
|
||||
if (!FcConfigAppFontAddFile (config, (FcChar8 *) path))
|
||||
{
|
||||
g_set_error (error,
|
||||
GTK_CSS_PARSER_ERROR,
|
||||
GTK_CSS_PARSER_ERROR_FAILED,
|
||||
"Failed to add %s to FcConfig", path);
|
||||
return;
|
||||
}
|
||||
|
||||
files = (GPtrArray *) g_object_get_data (G_OBJECT (context->fontmap), "font-files");
|
||||
g_ptr_array_add (files, g_strdup (path));
|
||||
|
||||
pango_fc_font_map_config_changed (PANGO_FC_FONT_MAP (context->fontmap));
|
||||
}
|
||||
|
||||
static void
|
||||
add_font_from_bytes (Context *context,
|
||||
GBytes *bytes,
|
||||
GError **error)
|
||||
{
|
||||
GFile *file;
|
||||
GIOStream *iostream;
|
||||
GOutputStream *ostream;
|
||||
|
||||
file = g_file_new_tmp ("gtk4-font-XXXXXX.ttf", (GFileIOStream **) &iostream, error);
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
ostream = g_io_stream_get_output_stream (iostream);
|
||||
if (g_output_stream_write_bytes (ostream, bytes, NULL, error) == -1)
|
||||
{
|
||||
g_object_unref (file);
|
||||
g_object_unref (iostream);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
g_io_stream_close (iostream, NULL, NULL);
|
||||
g_object_unref (iostream);
|
||||
|
||||
add_font_from_file (context, g_file_peek_path (file), error);
|
||||
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
#else /* !HAVE_PANGOFT */
|
||||
|
||||
static void
|
||||
add_font_from_bytes (Context *context,
|
||||
GBytes *bytes,
|
||||
GError **error)
|
||||
{
|
||||
g_set_error (error,
|
||||
GTK_CSS_PARSER_ERROR,
|
||||
GTK_CSS_PARSER_ERROR_FAILED,
|
||||
"Not implemented");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
parse_font (GtkCssParser *parser,
|
||||
Context *context,
|
||||
gpointer out_font)
|
||||
{
|
||||
PangoFont *font;
|
||||
PangoFont *font = NULL;
|
||||
char *s;
|
||||
GtkCssLocation start_location;
|
||||
PangoFontMap *fontmap;
|
||||
|
||||
fontmap = pango_cairo_font_map_get_default ();
|
||||
|
||||
s = gtk_css_parser_consume_string (parser);
|
||||
if (s == NULL)
|
||||
return FALSE;
|
||||
|
||||
font = font_from_string (s);
|
||||
if (font == NULL)
|
||||
start_location = *gtk_css_parser_get_start_location (parser);
|
||||
|
||||
if (gtk_css_parser_try_token (parser, GTK_CSS_TOKEN_URL) ||
|
||||
gtk_css_parser_has_function (parser, "url"))
|
||||
{
|
||||
gtk_css_parser_error_syntax (parser, "This font does not exist.");
|
||||
char *url;
|
||||
char *scheme;
|
||||
GBytes *bytes = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
/* If we have a url, it is a bug if the font already exists in our custom fontmap */
|
||||
if (context->fontmap)
|
||||
{
|
||||
font = font_from_string (context->fontmap, s);
|
||||
if (font)
|
||||
{
|
||||
g_object_unref (font);
|
||||
gtk_css_parser_error_value (parser, "This font already exists.");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
url = gtk_css_parser_consume_url (parser);
|
||||
|
||||
scheme = g_uri_parse_scheme (url);
|
||||
if (scheme && g_ascii_strcasecmp (scheme, "data") == 0)
|
||||
{
|
||||
bytes = gtk_css_data_url_parse (url, NULL, &error);
|
||||
}
|
||||
else
|
||||
{
|
||||
GFile *file;
|
||||
|
||||
file = g_file_new_for_uri (url);
|
||||
bytes = g_file_load_bytes (file, NULL, NULL, &error);
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
g_free (scheme);
|
||||
g_free (url);
|
||||
|
||||
if (bytes)
|
||||
{
|
||||
add_font_from_bytes (context, bytes, &error);
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
fontmap = context->fontmap;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert (error != NULL);
|
||||
|
||||
gtk_css_parser_emit_error (parser,
|
||||
&start_location,
|
||||
gtk_css_parser_get_end_location (parser),
|
||||
error);
|
||||
g_clear_error (&error);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
font = font_from_string (fontmap, s);
|
||||
|
||||
if (!font && context->fontmap && fontmap != context->fontmap)
|
||||
font = font_from_string (context->fontmap, s);
|
||||
|
||||
if (!font)
|
||||
{
|
||||
gtk_css_parser_error_value (parser, "This font does not exist.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -2013,7 +2219,7 @@ parse_text_node (GtkCssParser *parser,
|
||||
|
||||
if (font == NULL)
|
||||
{
|
||||
font = font_from_string ("Cantarell 11");
|
||||
font = font_from_string (pango_cairo_font_map_get_default (), "Cantarell 11");
|
||||
g_assert (font);
|
||||
}
|
||||
|
||||
|
@ -6,4 +6,3 @@
|
||||
GskRenderNode * gsk_render_node_deserialize_from_bytes (GBytes *bytes,
|
||||
GskParseErrorFunc error_func,
|
||||
gpointer user_data);
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
<data>:4:3-7: error: GTK_CSS_PARSER_WARNING_SYNTAX
|
||||
<data>:3:11-12: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
|
||||
<data>:4:11-12: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
|
||||
<data>:6:3-9: error: GTK_CSS_PARSER_WARNING_SYNTAX
|
||||
<data>:8:1-2: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
|
||||
|
@ -1,4 +1,6 @@
|
||||
color {
|
||||
bounds: 0 0 50 50;
|
||||
color: rgb(255,0,204);
|
||||
text {
|
||||
color: rgb(50,50,50);
|
||||
font: "Cantarell 11";
|
||||
glyphs: "N";
|
||||
offset: 0 32.0186;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user