From 18385550dd9326b953c9108a0ddb17ca5f776272 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Tue, 21 Jun 2022 16:50:58 -0700 Subject: Add a userfont to pango-view To use it, call pango-view with --userfont --font "Userfont 20" --- utils/meson.build | 1 + utils/userfont.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++ utils/userfont.h | 1 + utils/viewer-pangocairo.c | 8 ++ 4 files changed, 192 insertions(+) create mode 100644 utils/userfont.c create mode 100644 utils/userfont.h diff --git a/utils/meson.build b/utils/meson.build index f3db3492..0d2e0d51 100644 --- a/utils/meson.build +++ b/utils/meson.build @@ -2,6 +2,7 @@ pango_view_sources = [ 'pango-view.c', 'viewer-main.c', 'viewer-render.c', + 'userfont.c', ] pango_view_deps = [ diff --git a/utils/userfont.c b/utils/userfont.c new file mode 100644 index 00000000..f5fbf795 --- /dev/null +++ b/utils/userfont.c @@ -0,0 +1,182 @@ +#include +#include + +#include +#include "userfont.h" + +#define END_GLYPH 0 +#define STROKE 126 +#define CLOSE 127 + +/* Simple glyph definition: 1 - 15 means lineto (or moveto for first + * point) for one of the points on this grid: + * + * 1 2 3 + * 4 5 6 + * 7 8 9 + * ----10 11 12----(baseline) + * 13 14 15 + */ +typedef struct +{ + gunichar ucs4; + int width; + char data[16]; +} test_scaled_font_glyph_t; + +/* Simple glyph definition: 1 - 15 means lineto (or moveto for first + * point) for one of the points on this grid: + * + * 1 2 3 + * 4 5 6 + * 7 8 9 + * ----10 11 12----(baseline) + * 13 14 15 + */ +static const test_scaled_font_glyph_t glyphs [] = { + { 'a', 3, { 4, 6, 12, 10, 7, 9, STROKE, END_GLYPH } }, + { 'c', 3, { 6, 4, 10, 12, STROKE, END_GLYPH } }, + { 'e', 3, { 12, 10, 4, 6, 9, 7, STROKE, END_GLYPH } }, + { 'f', 3, { 3, 2, 11, STROKE, 4, 6, STROKE, END_GLYPH } }, + { 'g', 3, { 12, 10, 4, 6, 15, 13, STROKE, END_GLYPH } }, + { 'h', 3, { 1, 10, STROKE, 7, 5, 6, 12, STROKE, END_GLYPH } }, + { 'i', 1, { 1, 1, STROKE, 4, 10, STROKE, END_GLYPH } }, + { 'l', 1, { 1, 10, STROKE, END_GLYPH } }, + { 'n', 3, { 10, 4, STROKE, 7, 5, 6, 12, STROKE, END_GLYPH } }, + { 'o', 3, { 4, 10, 12, 6, CLOSE, END_GLYPH } }, + { 'p', 3, { 4, 10, 12, 6, CLOSE, 4, 13, STROKE, END_GLYPH } }, + { 'r', 3, { 4, 10, STROKE, 7, 5, 6, STROKE, END_GLYPH } }, + { 's', 3, { 6, 4, 7, 9, 12, 10, STROKE, END_GLYPH } }, + { 't', 3, { 2, 11, 12, STROKE, 4, 6, STROKE, END_GLYPH } }, + { 'u', 3, { 4, 10, 12, 6, STROKE, END_GLYPH } }, + { 'y', 3, { 4, 10, 12, 6, STROKE, 12, 15, 13, STROKE, END_GLYPH } }, + { 'z', 3, { 4, 6, 10, 12, STROKE, END_GLYPH } }, + { ' ', 1, { END_GLYPH } }, + { '-', 2, { 7, 8, STROKE, END_GLYPH } }, + { '.', 1, { 10, 10, STROKE, END_GLYPH } }, + { 0xe000, 3, { 3, 2, 11, STROKE, 4, 6, STROKE, 3, 3, STROKE, 6, 12, STROKE, END_GLYPH } }, /* fi */ + { -1, 0, { END_GLYPH } }, +}; + +static gboolean +glyph_cb (PangoUserFace *face, + hb_codepoint_t unicode, + hb_codepoint_t *glyph, + gpointer user_data) +{ + test_scaled_font_glyph_t *glyphs = user_data; + + for (int i = 0; glyphs[i].ucs4 != (gunichar) -1; i++) + { + if (glyphs[i].ucs4 == unicode) + { + *glyph = i; + return TRUE; + } + } + + return FALSE; +} + +static gboolean +glyph_info_cb (PangoUserFace *face, + int size, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + hb_position_t *h_advance, + hb_position_t *v_advance, + gboolean *is_color, + gpointer user_data) +{ + test_scaled_font_glyph_t *glyphs = user_data; + + extents->x_bearing = 0; + extents->y_bearing = - 0.75 * size; + extents->width = glyphs[glyph].width / 4.0 * size; + extents->height = size; + + *h_advance = *v_advance = glyphs[glyph].width / 4.0 * size; + + *is_color = FALSE; + + return TRUE; +} + +static gboolean +font_info_cb (PangoUserFace *face, + int size, + hb_font_extents_t *extents, + gpointer user_data) +{ + extents->ascender = - 0.75 * size; + extents->descender = 0.25 * size; + extents->line_gap = 0; + + return TRUE; +} + +static gboolean +render_cb (PangoUserFace *face, + int size, + hb_codepoint_t glyph, + gpointer user_data, + const char *backend_id, + gpointer backend_data) +{ + test_scaled_font_glyph_t *glyphs = user_data; + cairo_t *cr = backend_data; + const char *data; + div_t d; + double x, y; + + if (strcmp (backend_id, "cairo") != 0) + return FALSE; + + cairo_set_line_width (cr, 0.1); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + + data = glyphs[glyph].data; + for (int i = 0; data[i] != END_GLYPH; i++) + { + switch (data[i]) + { + case STROKE: + cairo_new_sub_path (cr); + break; + + case CLOSE: + cairo_close_path (cr); + break; + + default: + d = div (data[i] - 1, 3); + x = d.rem / 4.0 + 0.125; + y = d.quot / 5.0 + 0.4 - 1.0; + cairo_line_to (cr, x, y); + } + } + + cairo_stroke (cr); + + return TRUE; +} + +void +add_userfont (PangoFontMap *fontmap) +{ + PangoFontDescription *desc; + PangoUserFace *face; + + desc = pango_font_description_new (); + pango_font_description_set_family (desc, "Userfont"); + face = pango_user_face_new (font_info_cb, + glyph_cb, + glyph_info_cb, + NULL, + render_cb, + (gpointer) glyphs, NULL, + "Black", desc); + pango_font_map_add_face (fontmap, PANGO_FONT_FACE (face)); + pango_font_description_free (desc); +} diff --git a/utils/userfont.h b/utils/userfont.h new file mode 100644 index 00000000..f4d4f8be --- /dev/null +++ b/utils/userfont.h @@ -0,0 +1 @@ +void add_userfont (PangoFontMap *map); diff --git a/utils/viewer-pangocairo.c b/utils/viewer-pangocairo.c index 2851fc08..2bf2e0d6 100644 --- a/utils/viewer-pangocairo.c +++ b/utils/viewer-pangocairo.c @@ -23,13 +23,16 @@ #include "viewer-render.h" #include "viewer-cairo.h" +#include "userfont.h" #include #include #include + static int opt_annotate = 0; +static gboolean opt_userfont = 0; static char **opt_font_file = NULL; typedef struct @@ -86,8 +89,12 @@ pangocairo_view_create (const PangoViewer *klass G_GNUC_UNUSED) { instance->fontmap = pango_font_map_new_default (); } + pango_font_map_set_resolution (PANGO_FONT_MAP (instance->fontmap), opt_dpi); + if (opt_userfont) + add_userfont (instance->fontmap); + instance->font_options = cairo_font_options_create (); if (opt_hinting != HINT_DEFAULT) { @@ -965,6 +972,7 @@ pangocairo_view_get_option_group (const PangoViewer *klass G_GNUC_UNUSED) { {"annotate", 0, 0, G_OPTION_ARG_CALLBACK, parse_annotate_arg, annotate_arg_help, "FLAGS"}, { "font-file", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_font_file, "Create a fontmap with this font", "FILE" }, + { "userfont", 0, 0, G_OPTION_ARG_NONE, &opt_userfont, "Add userfont" }, {NULL} }; GOptionGroup *group; -- cgit v1.2.1