mirror of
https://github.com/love2d/megasource.git
synced 2026-08-20 04:30:45 +02:00
update harfbuzz to 10.1.0
This commit is contained in:
@@ -1,80 +0,0 @@
|
||||
# Process this file with automake to produce Makefile.in
|
||||
|
||||
NULL =
|
||||
EXTRA_DIST =
|
||||
CLEANFILES =
|
||||
DISTCLEANFILES =
|
||||
MAINTAINERCLEANFILES =
|
||||
|
||||
EXTRA_DIST += meson.build
|
||||
|
||||
include Makefile.sources
|
||||
|
||||
# Convenience targets:
|
||||
lib:
|
||||
@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
|
||||
libs:
|
||||
@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src libs
|
||||
|
||||
bin_PROGRAMS =
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-DHB_DISABLE_DEPRECATED \
|
||||
-I$(top_srcdir)/src/ \
|
||||
-I$(top_builddir)/src/ \
|
||||
$(GLIB_CFLAGS) \
|
||||
$(FREETYPE_CFLAGS) \
|
||||
$(CAIRO_FT_CFLAGS) \
|
||||
$(CHAFA_CFLAGS) \
|
||||
$(NULL)
|
||||
LDADD = \
|
||||
$(top_builddir)/src/libharfbuzz.la \
|
||||
-lm \
|
||||
$(GLIB_LIBS) \
|
||||
$(FREETYPE_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
if HAVE_GLIB
|
||||
|
||||
if HAVE_FREETYPE
|
||||
if HAVE_CAIRO_FT
|
||||
hb_view_SOURCES = $(HB_VIEW_sources)
|
||||
hb_view_LDADD = \
|
||||
$(LDADD) \
|
||||
$(CAIRO_LIBS) \
|
||||
$(CAIRO_FT_LIBS) \
|
||||
$(CHAFA_LIBS) \
|
||||
$(NULL)
|
||||
bin_PROGRAMS += hb-view
|
||||
endif # HAVE_CAIRO_FT
|
||||
endif # HAVE_FREETYPE
|
||||
|
||||
hb_shape_SOURCES = $(HB_SHAPE_sources)
|
||||
bin_PROGRAMS += hb-shape
|
||||
|
||||
hb_subset_SOURCES = $(HB_SUBSET_CLI_sources)
|
||||
hb_subset_LDADD = \
|
||||
$(top_builddir)/src/libharfbuzz-subset.la \
|
||||
$(LDADD)
|
||||
|
||||
bin_PROGRAMS += hb-subset
|
||||
|
||||
hb_ot_shape_closure_SOURCES = $(HB_OT_SHAPE_CLOSURE_sources)
|
||||
bin_PROGRAMS += hb-ot-shape-closure
|
||||
|
||||
endif # HAVE_GLIB
|
||||
|
||||
#if HAVE_FONTCONFIG
|
||||
#hb_fc_list_SOURCES = \
|
||||
# hb-fc.cc \
|
||||
# hb-fc.h \
|
||||
# hb-fc-list.c \
|
||||
# $(NULL)
|
||||
#hb_fc_list_LDADD = \
|
||||
# $(LDADD) \
|
||||
# $(FONTCONFIG_LIBS) \
|
||||
# $(NULL)
|
||||
#bin_PROGRAMS += hb-fc-list
|
||||
#endif # HAVE_FONTCONFIG
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
||||
@@ -1,52 +0,0 @@
|
||||
HB_VIEW_sources = \
|
||||
ansi-print.hh \
|
||||
face-options.hh \
|
||||
font-options.hh \
|
||||
hb-view.cc \
|
||||
helper-cairo-ansi.hh \
|
||||
helper-cairo-ft.hh \
|
||||
helper-cairo-user.hh \
|
||||
helper-cairo.hh \
|
||||
main-font-text.hh \
|
||||
options.hh \
|
||||
output-options.hh \
|
||||
shape-consumer.hh \
|
||||
shape-options.hh \
|
||||
text-options.hh \
|
||||
view-cairo.hh \
|
||||
view-options.hh \
|
||||
$(NULL)
|
||||
|
||||
HB_SHAPE_sources = \
|
||||
batch.hh \
|
||||
face-options.hh \
|
||||
font-options.hh \
|
||||
hb-shape.cc \
|
||||
main-font-text.hh \
|
||||
options.hh \
|
||||
output-options.hh \
|
||||
shape-consumer.hh \
|
||||
shape-format.hh \
|
||||
shape-options.hh \
|
||||
shape-output.hh \
|
||||
text-options.hh \
|
||||
$(NULL)
|
||||
|
||||
HB_SUBSET_CLI_sources = \
|
||||
batch.hh \
|
||||
face-options.hh \
|
||||
hb-subset.cc \
|
||||
main-font-text.hh \
|
||||
options.hh \
|
||||
output-options.hh \
|
||||
text-options.hh \
|
||||
$(NULL)
|
||||
|
||||
HB_OT_SHAPE_CLOSURE_sources = \
|
||||
face-options.hh \
|
||||
font-options.hh \
|
||||
hb-ot-shape-closure.cc \
|
||||
main-font-text.hh \
|
||||
options.hh \
|
||||
text-options.hh \
|
||||
$(NULL)
|
||||
@@ -29,16 +29,13 @@
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#include <cairo.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h> /* for isatty() */
|
||||
#endif
|
||||
|
||||
#if defined (_MSC_VER) && (_MSC_VER < 1800)
|
||||
static inline long int
|
||||
@@ -51,8 +48,6 @@ lround (double x)
|
||||
}
|
||||
#endif
|
||||
|
||||
#define ESC_E (char)27
|
||||
|
||||
#define CELL_W 8
|
||||
#define CELL_H (2 * CELL_W)
|
||||
|
||||
@@ -379,7 +374,9 @@ static inline void
|
||||
ansi_print_image_rgb24 (const uint32_t *data,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned int stride)
|
||||
unsigned int stride,
|
||||
cairo_write_func_t write_func,
|
||||
void *closure)
|
||||
{
|
||||
image_t image (width, height, data, stride);
|
||||
|
||||
@@ -388,37 +385,56 @@ ansi_print_image_rgb24 (const uint32_t *data,
|
||||
image_t cell (CELL_W, CELL_H);
|
||||
biimage_t bi (CELL_W, CELL_H);
|
||||
unsigned int last_bg = -1, last_fg = -1;
|
||||
for (unsigned int row = 0; row < rows; row++) {
|
||||
for (unsigned int col = 0; col < cols; col++) {
|
||||
for (unsigned int row = 0; row < rows; row++)
|
||||
{
|
||||
for (unsigned int col = 0; col < cols; col++)
|
||||
{
|
||||
image.copy_sub_image (cell, col * CELL_W, row * CELL_H, CELL_W, CELL_H);
|
||||
bi.set (cell);
|
||||
if (bi.unicolor) {
|
||||
if (last_bg != bi.bg) {
|
||||
printf ("%c[%dm", ESC_E, 40 + bi.bg);
|
||||
if (bi.unicolor)
|
||||
{
|
||||
if (last_bg != bi.bg)
|
||||
{
|
||||
char buf[] = "\033[40m";
|
||||
buf[3] += bi.bg;
|
||||
write_func (closure, (unsigned char *) buf, 5);
|
||||
last_bg = bi.bg;
|
||||
}
|
||||
printf (" ");
|
||||
} else {
|
||||
write_func (closure, (unsigned char *) " ", 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Figure out the closest character to the biimage */
|
||||
bool inverse = false;
|
||||
const char *c = block_best (bi, &inverse);
|
||||
if (inverse) {
|
||||
if (last_bg != bi.fg || last_fg != bi.bg) {
|
||||
printf ("%c[%d;%dm", ESC_E, 30 + bi.bg, 40 + bi.fg);
|
||||
if (inverse)
|
||||
{
|
||||
if (last_bg != bi.fg || last_fg != bi.bg)
|
||||
{
|
||||
char buf[] = "\033[30;40m";
|
||||
buf[3] += bi.bg;
|
||||
buf[6] += bi.fg;
|
||||
write_func (closure, (unsigned char *) buf, 8);
|
||||
last_bg = bi.fg;
|
||||
last_fg = bi.bg;
|
||||
}
|
||||
} else {
|
||||
if (last_bg != bi.bg || last_fg != bi.fg) {
|
||||
printf ("%c[%d;%dm", ESC_E, 40 + bi.bg, 30 + bi.fg);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (last_bg != bi.bg || last_fg != bi.fg)
|
||||
{
|
||||
char buf[] = "\033[40;30m";
|
||||
buf[3] += bi.bg;
|
||||
buf[6] += bi.fg;
|
||||
write_func (closure, (unsigned char *) buf, 8);
|
||||
last_bg = bi.bg;
|
||||
last_fg = bi.fg;
|
||||
}
|
||||
}
|
||||
printf ("%s", c);
|
||||
write_func (closure, (unsigned char *) c, strlen (c));
|
||||
}
|
||||
}
|
||||
printf ("%c[0m\n", ESC_E); /* Reset */
|
||||
write_func (closure, (unsigned char *) "\033[0m\n", 5); /* Reset */
|
||||
last_bg = last_fg = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,10 +29,18 @@
|
||||
|
||||
#include "options.hh"
|
||||
|
||||
#ifdef HAVE_FREETYPE
|
||||
#include <hb-ft.h>
|
||||
#endif
|
||||
#ifdef HAVE_CORETEXT
|
||||
#include <hb-coretext.h>
|
||||
#endif
|
||||
|
||||
struct face_options_t
|
||||
{
|
||||
~face_options_t ()
|
||||
{
|
||||
g_free (face_loader);
|
||||
g_free (font_file);
|
||||
}
|
||||
|
||||
@@ -48,26 +56,38 @@ struct face_options_t
|
||||
~cache_t ()
|
||||
{
|
||||
g_free (font_path);
|
||||
hb_blob_destroy (blob);
|
||||
hb_face_destroy (face);
|
||||
}
|
||||
|
||||
char *font_path = nullptr;
|
||||
hb_blob_t *blob = nullptr;
|
||||
unsigned face_index = (unsigned) -1;
|
||||
hb_face_t *face = nullptr;
|
||||
} cache;
|
||||
|
||||
char *font_file = nullptr;
|
||||
unsigned face_index = 0;
|
||||
char *face_loader = nullptr;
|
||||
|
||||
hb_blob_t *blob = nullptr;
|
||||
hb_face_t *face = nullptr;
|
||||
};
|
||||
|
||||
|
||||
face_options_t::cache_t face_options_t::cache {};
|
||||
|
||||
static struct supported_face_loaders_t {
|
||||
char name[9];
|
||||
hb_face_t * (*func) (const char *font_file, unsigned face_index);
|
||||
} supported_face_loaders[] =
|
||||
{
|
||||
{"ot", hb_face_create_from_file_or_fail},
|
||||
#ifdef HAVE_FREETYPE
|
||||
{"ft", hb_ft_face_create_from_file_or_fail},
|
||||
#endif
|
||||
#ifdef HAVE_CORETEXT
|
||||
{"coretext", hb_coretext_face_create_from_file_or_fail},
|
||||
#endif
|
||||
};
|
||||
|
||||
void
|
||||
face_options_t::post_parse (GError **error)
|
||||
{
|
||||
@@ -92,44 +112,87 @@ face_options_t::post_parse (GError **error)
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!cache.font_path || 0 != strcmp (cache.font_path, font_path))
|
||||
hb_face_t * (*face_load) (const char *file_name, unsigned face_index) = nullptr;
|
||||
if (!face_loader)
|
||||
{
|
||||
hb_blob_destroy (cache.blob);
|
||||
cache.blob = hb_blob_create_from_file_or_fail (font_path);
|
||||
face_load = supported_face_loaders[0].func;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
|
||||
if (0 == g_ascii_strcasecmp (face_loader, supported_face_loaders[i].name))
|
||||
{
|
||||
face_load = supported_face_loaders[i].func;
|
||||
break;
|
||||
}
|
||||
if (!face_load)
|
||||
{
|
||||
GString *s = g_string_new (nullptr);
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
|
||||
{
|
||||
if (i)
|
||||
g_string_append_c (s, '/');
|
||||
g_string_append (s, supported_face_loaders[i].name);
|
||||
}
|
||||
g_string_append_c (s, '\n');
|
||||
char *p = g_string_free (s, FALSE);
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Unknown face loader `%s'; supported values are: %s; default is %s",
|
||||
face_loader,
|
||||
p,
|
||||
supported_face_loaders[0].name);
|
||||
free (p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cache.font_path ||
|
||||
0 != strcmp (cache.font_path, font_path) ||
|
||||
cache.face_index != face_index)
|
||||
{
|
||||
hb_face_destroy (cache.face);
|
||||
cache.face = face_load (font_path, face_index);
|
||||
cache.face_index = face_index;
|
||||
|
||||
free ((char *) cache.font_path);
|
||||
cache.font_path = g_strdup (font_path);
|
||||
|
||||
if (!cache.blob)
|
||||
if (!cache.face)
|
||||
{
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
|
||||
"%s: Failed reading file", font_path);
|
||||
"%s: Failed loading font face", font_path);
|
||||
return;
|
||||
}
|
||||
|
||||
hb_face_destroy (cache.face);
|
||||
cache.face = nullptr;
|
||||
cache.face_index = (unsigned) -1;
|
||||
}
|
||||
|
||||
if (cache.face_index != face_index)
|
||||
{
|
||||
hb_face_destroy (cache.face);
|
||||
cache.face = hb_face_create (cache.blob, face_index);
|
||||
cache.face_index = face_index;
|
||||
}
|
||||
|
||||
blob = cache.blob;
|
||||
face = cache.face;
|
||||
}
|
||||
|
||||
void
|
||||
face_options_t::add_options (option_parser_t *parser)
|
||||
{
|
||||
char *face_loaders_text = nullptr;
|
||||
{
|
||||
static_assert ((ARRAY_LENGTH_CONST (supported_face_loaders) > 0),
|
||||
"No supported face-loaders found.");
|
||||
GString *s = g_string_new (nullptr);
|
||||
g_string_printf (s, "Set face loader to use (default: %s)\n\n Supported face loaders are: %s",
|
||||
supported_face_loaders[0].name,
|
||||
supported_face_loaders[0].name);
|
||||
for (unsigned int i = 1; i < ARRAY_LENGTH (supported_face_loaders); i++)
|
||||
{
|
||||
g_string_append_c (s, '/');
|
||||
g_string_append (s, supported_face_loaders[i].name);
|
||||
}
|
||||
face_loaders_text = g_string_free (s, FALSE);
|
||||
parser->free_later (face_loaders_text);
|
||||
}
|
||||
|
||||
GOptionEntry entries[] =
|
||||
{
|
||||
{"font-file", 0, 0, G_OPTION_ARG_STRING, &this->font_file, "Set font file-name", "filename"},
|
||||
{"face-index", 0, 0, G_OPTION_ARG_INT, &this->face_index, "Set face index (default: 0)", "index"},
|
||||
{"face-index", 'y', 0, G_OPTION_ARG_INT, &this->face_index, "Set face index (default: 0)", "index"},
|
||||
{"face-loader", 0, 0, G_OPTION_ARG_STRING, &this->face_loader, face_loaders_text, "loader"},
|
||||
{nullptr}
|
||||
};
|
||||
parser->add_group (entries,
|
||||
|
||||
@@ -29,10 +29,13 @@
|
||||
|
||||
#include "face-options.hh"
|
||||
|
||||
#include <hb-ot.h>
|
||||
#ifdef HAVE_FREETYPE
|
||||
#include <hb-ft.h>
|
||||
#endif
|
||||
#include <hb-ot.h>
|
||||
#ifdef HAVE_CORETEXT
|
||||
#include <hb-coretext.h>
|
||||
#endif
|
||||
|
||||
#define FONT_SIZE_UPEM 0x7FFFFFFF
|
||||
#define FONT_SIZE_NONE 0
|
||||
@@ -63,19 +66,23 @@ struct font_options_t : face_options_t
|
||||
int x_ppem = 0;
|
||||
int y_ppem = 0;
|
||||
double ptem = 0.;
|
||||
double x_embolden = 0.;
|
||||
double y_embolden = 0.;
|
||||
hb_bool_t embolden_in_place = false;
|
||||
double slant = 0.;
|
||||
unsigned int subpixel_bits = SUBPIXEL_BITS;
|
||||
mutable double font_size_x = DEFAULT_FONT_SIZE;
|
||||
mutable double font_size_y = DEFAULT_FONT_SIZE;
|
||||
char *font_funcs = nullptr;
|
||||
int ft_load_flags = 2;
|
||||
unsigned int named_instance = HB_FONT_NO_VAR_NAMED_INSTANCE;
|
||||
|
||||
hb_font_t *font = nullptr;
|
||||
};
|
||||
|
||||
|
||||
static struct supported_font_funcs_t {
|
||||
char name[4];
|
||||
char name[9];
|
||||
void (*func) (hb_font_t *);
|
||||
} supported_font_funcs[] =
|
||||
{
|
||||
@@ -83,6 +90,9 @@ static struct supported_font_funcs_t {
|
||||
#ifdef HAVE_FREETYPE
|
||||
{"ft", hb_ft_font_set_funcs},
|
||||
#endif
|
||||
#ifdef HAVE_CORETEXT
|
||||
{"coretext", hb_coretext_font_set_funcs},
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -100,6 +110,9 @@ font_options_t::post_parse (GError **error)
|
||||
hb_font_set_ppem (font, x_ppem, y_ppem);
|
||||
hb_font_set_ptem (font, ptem);
|
||||
|
||||
hb_font_set_synthetic_bold (font,
|
||||
(float) x_embolden, (float) y_embolden,
|
||||
embolden_in_place);
|
||||
hb_font_set_synthetic_slant (font, slant);
|
||||
|
||||
int scale_x = (int) scalbnf (font_size_x, subpixel_bits);
|
||||
@@ -107,6 +120,7 @@ font_options_t::post_parse (GError **error)
|
||||
hb_font_set_scale (font, scale_x, scale_y);
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
hb_font_set_var_named_instance (font, named_instance);
|
||||
hb_font_set_variations (font, variations, num_variations);
|
||||
#endif
|
||||
|
||||
@@ -157,7 +171,6 @@ font_options_t::post_parse (GError **error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
static gboolean
|
||||
parse_variations (const char *name G_GNUC_UNUSED,
|
||||
@@ -244,13 +257,52 @@ parse_font_ppem (const char *name G_GNUC_UNUSED,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_font_embolden (const char *name G_GNUC_UNUSED,
|
||||
const char *arg,
|
||||
gpointer data,
|
||||
GError **error G_GNUC_UNUSED)
|
||||
{
|
||||
font_options_t *font_opts = (font_options_t *) data;
|
||||
switch (sscanf (arg, "%lf%*[ ,]%lf", &font_opts->x_embolden, &font_opts->y_embolden)) {
|
||||
case 1: font_opts->y_embolden = font_opts->x_embolden; HB_FALLTHROUGH;
|
||||
case 2: return true;
|
||||
default:
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"%s argument should be one or two space-separated numbers",
|
||||
name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_font_bold (const char *name G_GNUC_UNUSED,
|
||||
const char *arg,
|
||||
gpointer data,
|
||||
GError **error G_GNUC_UNUSED)
|
||||
{
|
||||
font_options_t *font_opts = (font_options_t *) data;
|
||||
font_opts->embolden_in_place = false;
|
||||
return parse_font_embolden ( name, arg, data, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_font_grade (const char *name G_GNUC_UNUSED,
|
||||
const char *arg,
|
||||
gpointer data,
|
||||
GError **error G_GNUC_UNUSED)
|
||||
{
|
||||
font_options_t *font_opts = (font_options_t *) data;
|
||||
font_opts->embolden_in_place = true;
|
||||
return parse_font_embolden ( name, arg, data, error);
|
||||
}
|
||||
|
||||
void
|
||||
font_options_t::add_options (option_parser_t *parser)
|
||||
{
|
||||
face_options_t::add_options (parser);
|
||||
|
||||
char *text = nullptr;
|
||||
|
||||
char *font_funcs_text = nullptr;
|
||||
{
|
||||
static_assert ((ARRAY_LENGTH_CONST (supported_font_funcs) > 0),
|
||||
"No supported font-funcs found.");
|
||||
@@ -263,8 +315,8 @@ font_options_t::add_options (option_parser_t *parser)
|
||||
g_string_append_c (s, '/');
|
||||
g_string_append (s, supported_font_funcs[i].name);
|
||||
}
|
||||
text = g_string_free (s, FALSE);
|
||||
parser->free_later (text);
|
||||
font_funcs_text = g_string_free (s, FALSE);
|
||||
parser->free_later (font_funcs_text);
|
||||
}
|
||||
|
||||
char *font_size_text;
|
||||
@@ -272,7 +324,7 @@ font_options_t::add_options (option_parser_t *parser)
|
||||
font_size_text = (char *) "Font size (default: upem)";
|
||||
else
|
||||
{
|
||||
font_size_text = g_strdup_printf ("Font size (default: %d)", DEFAULT_FONT_SIZE);
|
||||
font_size_text = g_strdup_printf ("Font size (default: %u)", DEFAULT_FONT_SIZE);
|
||||
parser->free_later (font_size_text);
|
||||
}
|
||||
|
||||
@@ -283,11 +335,15 @@ font_options_t::add_options (option_parser_t *parser)
|
||||
G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_size, font_size_text, "1/2 integers or 'upem'"},
|
||||
{"font-ppem", 0, font_size_flags,
|
||||
G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_ppem, "Set x,y pixels per EM (default: 0; disabled)", "1/2 integers"},
|
||||
{"font-ptem", 0, 0,
|
||||
{"font-ptem", 0, font_size_flags,
|
||||
G_OPTION_ARG_DOUBLE, &this->ptem, "Set font point-size (default: 0; disabled)", "point-size"},
|
||||
{"font-slant", 0, 0,
|
||||
{"font-bold", 0, font_size_flags,
|
||||
G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_bold, "Set synthetic bold (default: 0)", "1/2 numbers; eg. 0.05"},
|
||||
{"font-grade", 0, font_size_flags,
|
||||
G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_grade, "Set synthetic grade (default: 0)", "1/2 numbers; eg. 0.05"},
|
||||
{"font-slant", 0, font_size_flags,
|
||||
G_OPTION_ARG_DOUBLE, &this->slant, "Set synthetic slant (default: 0)", "slant ratio; eg. 0.2"},
|
||||
{"font-funcs", 0, 0, G_OPTION_ARG_STRING, &this->font_funcs, text, "impl"},
|
||||
{"font-funcs", 0, 0, G_OPTION_ARG_STRING, &this->font_funcs, font_funcs_text, "impl"},
|
||||
{"sub-font", 0, G_OPTION_FLAG_HIDDEN,
|
||||
G_OPTION_ARG_NONE, &this->sub_font, "Create a sub-font (default: false)", "boolean"},
|
||||
{"ft-load-flags", 0, 0, G_OPTION_ARG_INT, &this->ft_load_flags, "Set FreeType load-flags (default: 2)", "integer"},
|
||||
@@ -315,6 +371,7 @@ font_options_t::add_options (option_parser_t *parser)
|
||||
|
||||
GOptionEntry entries2[] =
|
||||
{
|
||||
{"named-instance", 0, 0, G_OPTION_ARG_INT, &this->named_instance, "Set named-instance index (default: none)", "index"},
|
||||
{"variations", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_variations, variations_help, "list"},
|
||||
{nullptr}
|
||||
};
|
||||
|
||||
@@ -76,9 +76,7 @@ _hb_fc_get_font_funcs ()
|
||||
{
|
||||
static const hb_font_funcs_t *fc_ffuncs;
|
||||
|
||||
const hb_font_funcs_t *ffuncs;
|
||||
|
||||
if (!(ffuncs = fc_ffuncs))
|
||||
if (!fc_ffuncs)
|
||||
{
|
||||
hb_font_funcs_t *newfuncs = hb_font_funcs_create ();
|
||||
|
||||
@@ -88,7 +86,7 @@ _hb_fc_get_font_funcs ()
|
||||
if (fc_ffuncs)
|
||||
hb_font_funcs_destroy (newfuncs);
|
||||
else
|
||||
fc_ffuncs = ffuncs = newfuncs;
|
||||
fc_ffuncs = newfuncs;
|
||||
}
|
||||
|
||||
return const_cast<hb_font_funcs_t *> (fc_ffuncs);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -27,18 +27,16 @@
|
||||
|
||||
#include "batch.hh"
|
||||
#include "face-options.hh"
|
||||
#include "glib.h"
|
||||
#include "main-font-text.hh"
|
||||
#include "output-options.hh"
|
||||
#include "helper-subset.hh"
|
||||
|
||||
#include <hb-subset.h>
|
||||
|
||||
static hb_face_t* preprocess_face(hb_face_t* face)
|
||||
{
|
||||
#ifdef HB_EXPERIMENTAL_API
|
||||
return hb_subset_preprocess (face);
|
||||
#else
|
||||
return hb_face_reference(face);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -120,7 +118,7 @@ struct subset_main_t : option_parser_t, face_options_t, output_options_t<false>
|
||||
for (unsigned i = 0; i < num_iterations; i++)
|
||||
{
|
||||
hb_face_destroy (new_face);
|
||||
new_face = hb_subset_or_fail (face, input);
|
||||
new_face = hb_subset_or_fail (orig_face, input);
|
||||
}
|
||||
|
||||
bool success = new_face;
|
||||
@@ -130,6 +128,8 @@ struct subset_main_t : option_parser_t, face_options_t, output_options_t<false>
|
||||
write_file (output_file, result);
|
||||
hb_blob_destroy (result);
|
||||
}
|
||||
else if (hb_face_get_glyph_count (orig_face) == 0)
|
||||
fail (false, "Invalid font file.");
|
||||
|
||||
hb_face_destroy (new_face);
|
||||
if (preprocess)
|
||||
@@ -175,7 +175,7 @@ struct subset_main_t : option_parser_t, face_options_t, output_options_t<false>
|
||||
public:
|
||||
|
||||
unsigned num_iterations = 1;
|
||||
gboolean preprocess;
|
||||
gboolean preprocess = false;
|
||||
hb_subset_input_t *input = nullptr;
|
||||
};
|
||||
|
||||
@@ -532,6 +532,19 @@ parse_name_languages (const char *name,
|
||||
return true;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_keep_everything (const char *name,
|
||||
const char *arg,
|
||||
gpointer data,
|
||||
GError **error G_GNUC_UNUSED)
|
||||
{
|
||||
subset_main_t *subset_main = (subset_main_t *) data;
|
||||
|
||||
hb_subset_input_keep_everything (subset_main->input);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <hb_subset_flags_t flag>
|
||||
static gboolean
|
||||
set_flag (const char *name,
|
||||
@@ -664,8 +677,8 @@ parse_drop_tables (const char *name,
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef HB_EXPERIMENTAL_API
|
||||
#ifndef HB_NO_VAR
|
||||
|
||||
static gboolean
|
||||
parse_instance (const char *name,
|
||||
const char *arg,
|
||||
@@ -673,63 +686,71 @@ parse_instance (const char *name,
|
||||
GError **error)
|
||||
{
|
||||
subset_main_t *subset_main = (subset_main_t *) data;
|
||||
if (!subset_main->face) {
|
||||
// There is no face, which is needed to set up instancing. Skip parsing these options.
|
||||
return true;
|
||||
}
|
||||
|
||||
char *s = strtok((char *) arg, "=");
|
||||
while (s)
|
||||
return parse_instancing_spec(arg, subset_main->face, subset_main->input, error);
|
||||
}
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
parse_glyph_map (const char *name,
|
||||
const char *arg,
|
||||
gpointer data,
|
||||
GError **error)
|
||||
{
|
||||
// Glyph map has the following format:
|
||||
// <entry 1>,<entry 2>,...,<entry n>
|
||||
// <entry> = <old gid>:<new gid>
|
||||
subset_main_t *subset_main = (subset_main_t *) data;
|
||||
hb_subset_input_t* input = subset_main->input;
|
||||
hb_set_t *glyphs = hb_subset_input_glyph_set(input);
|
||||
|
||||
char *s = (char *) arg;
|
||||
char *p;
|
||||
|
||||
while (s && *s)
|
||||
{
|
||||
unsigned len = strlen (s);
|
||||
if (len > 4) //Axis tags are 4 bytes.
|
||||
while (*s && strchr (", ", *s))
|
||||
s++;
|
||||
if (!*s)
|
||||
break;
|
||||
|
||||
errno = 0;
|
||||
hb_codepoint_t start_code = strtoul (s, &p, 10);
|
||||
if (s[0] == '-' || errno || s == p)
|
||||
{
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Failed parsing axis tag at: '%s'", s);
|
||||
"Failed parsing glyph map at: '%s'", s);
|
||||
return false;
|
||||
}
|
||||
|
||||
hb_tag_t axis_tag = hb_tag_from_string (s, len);
|
||||
|
||||
s = strtok(nullptr, ", ");
|
||||
if (!s)
|
||||
if (!p || p[0] != ':') // ranges
|
||||
{
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Value not specified for axis: %c%c%c%c", HB_UNTAG (axis_tag));
|
||||
"Failed parsing glyph map at: '%s'", s);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp (s, "drop") == 0)
|
||||
s = ++p;
|
||||
hb_codepoint_t end_code = strtoul (s, &p, 10);
|
||||
if (s[0] == '-' || errno || s == p)
|
||||
{
|
||||
if (!hb_subset_input_pin_axis_to_default (subset_main->input, subset_main->face, axis_tag))
|
||||
{
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag));
|
||||
return false;
|
||||
}
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Failed parsing glyph map at: '%s'", s);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = 0;
|
||||
char *p;
|
||||
float axis_value = strtof (s, &p);
|
||||
if (errno || s == p)
|
||||
{
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Failed parsing axis value at: '%s'", s);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hb_subset_input_pin_axis_location (subset_main->input, subset_main->face, axis_tag, axis_value))
|
||||
{
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
s = strtok(nullptr, "=");
|
||||
hb_set_add(glyphs, start_code);
|
||||
hb_map_set (hb_subset_input_old_to_new_glyph_mapping (input), start_code, end_code);
|
||||
|
||||
s = p;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
template <GOptionArgFunc line_parser, bool allow_comments=true>
|
||||
static gboolean
|
||||
@@ -773,6 +794,7 @@ parse_file_for (const char *name,
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
|
||||
"Failed reading file `%s': %s",
|
||||
arg, strerror (errno));
|
||||
fclose (fp);
|
||||
return false;
|
||||
}
|
||||
g_string_append_c (gs, '\0');
|
||||
@@ -793,6 +815,8 @@ parse_file_for (const char *name,
|
||||
|
||||
g_string_free (gs, false);
|
||||
|
||||
fclose (fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -840,9 +864,9 @@ subset_main_t::add_options ()
|
||||
|
||||
GOptionEntry glyphset_entries[] =
|
||||
{
|
||||
{"gids", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_gids,
|
||||
{"gids", 'g', 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_gids,
|
||||
"Specify glyph IDs or ranges to include in the subset.\n"
|
||||
" "
|
||||
" "
|
||||
"Use --gids-=... to subtract codepoints from the current set.", "list of glyph indices/ranges or *"},
|
||||
{"gids-", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_gids, "Specify glyph IDs or ranges to remove from the subset", "list of glyph indices/ranges or *"},
|
||||
{"gids+", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_gids, "Specify glyph IDs or ranges to include in the subset", "list of glyph indices/ranges or *"},
|
||||
@@ -854,19 +878,19 @@ subset_main_t::add_options ()
|
||||
|
||||
{"glyphs-file", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_file_for<parse_glyphs>, "Specify file to read glyph names from", "filename"},
|
||||
|
||||
{"text", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text, "Specify text to include in the subset. Use --text-=... to subtract codepoints from the current set.", "string"},
|
||||
{"text", 't', 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text, "Specify text to include in the subset. Use --text-=... to subtract codepoints from the current set.", "string"},
|
||||
{"text-", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text, "Specify text to remove from the subset", "string"},
|
||||
{"text+", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text, "Specify text to include in the subset", "string"},
|
||||
|
||||
|
||||
{"text-file", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_file_for<parse_text, false>,"Specify file to read text from", "filename"},
|
||||
{"unicodes", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes,
|
||||
{"unicodes", 'u', 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes,
|
||||
"Specify Unicode codepoints or ranges to include in the subset. Use * to include all codepoints.\n"
|
||||
" "
|
||||
" "
|
||||
"--unicodes-=... can be used to subtract codepoints from the current set.\n"
|
||||
" "
|
||||
" "
|
||||
"For example: --unicodes=* --unicodes-=41,42,43 would create a subset with all codepoints\n"
|
||||
" "
|
||||
" "
|
||||
"except for 41, 42, 43.",
|
||||
"list of hex numbers/ranges or *"},
|
||||
{"unicodes-", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes, "Specify Unicode codepoints or ranges to remove from the subset", "list of hex numbers/ranges or *"},
|
||||
@@ -883,6 +907,7 @@ subset_main_t::add_options ()
|
||||
|
||||
GOptionEntry other_entries[] =
|
||||
{
|
||||
{"gid-map", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_glyph_map, "Specify a glyph mapping to use, any unmapped gids will be automatically assigned.", "List of pairs old_gid1:new_gid1,old_gid2:new_gid2,..."},
|
||||
{"name-IDs", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_nameids, "Subset specified nameids. Use --name-IDs-=... to subtract from the current set.", "list of int numbers or *"},
|
||||
{"name-IDs-", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_nameids, "Subset specified nameids", "list of int numbers or *"},
|
||||
{"name-IDs+", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_nameids, "Subset specified nameids", "list of int numbers or *"},
|
||||
@@ -901,16 +926,16 @@ subset_main_t::add_options ()
|
||||
{"drop-tables", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables. Use --drop-tables-=... to subtract from the current set.", "list of string table tags or *"},
|
||||
{"drop-tables+", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables.", "list of string table tags or *"},
|
||||
{"drop-tables-", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables.", "list of string table tags or *"},
|
||||
#ifdef HB_EXPERIMENTAL_API
|
||||
#ifndef HB_NO_VAR
|
||||
{"instance", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_instance,
|
||||
"(Partially|Fully) Instantiate a variable font. A location consists of the tag of a variation axis, followed by '=', followed by a\n"
|
||||
"number or the literal string 'drop'\n"
|
||||
" "
|
||||
"For example: --instance=\"wdth=100 wght=200\" or --instance=\"wdth=drop\"\n"
|
||||
"Note: currently only fully instancing to the default location is supported\n",
|
||||
"list of comma separated axis-locations"},
|
||||
#endif
|
||||
{"variations", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_instance,
|
||||
"(Partially|Fully) Instantiate a variable font. A location consists of the tag "
|
||||
"of a variation axis, followed by '=', followed by a number or the literal "
|
||||
"string 'drop'. For example: --variations=\"wdth=100 wght=200\" or --variations=\"wdth=drop\""
|
||||
,
|
||||
"list of comma separated axis-locations."
|
||||
},
|
||||
{"instance", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_instance,
|
||||
"Alias for --variations.", "list of comma separated axis-locations"},
|
||||
#endif
|
||||
{nullptr}
|
||||
};
|
||||
@@ -922,6 +947,8 @@ subset_main_t::add_options ()
|
||||
|
||||
GOptionEntry flag_entries[] =
|
||||
{
|
||||
{"keep-everything", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &_keep_everything,
|
||||
"Keep everything by default. Options after this can override the operation.", nullptr},
|
||||
{"no-hinting", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NO_HINTING>, "Whether to drop hints", nullptr},
|
||||
{"retain-gids", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_RETAIN_GIDS>, "If set don't renumber glyph ids in the subset.", nullptr},
|
||||
{"desubroutinize", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_DESUBROUTINIZE>, "Remove CFF/CFF2 use of subroutines", nullptr},
|
||||
@@ -929,10 +956,17 @@ subset_main_t::add_options ()
|
||||
{"set-overlaps-flag", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG>, "Set the overlaps flag on each glyph.", nullptr},
|
||||
{"notdef-outline", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NOTDEF_OUTLINE>, "Keep the outline of \'.notdef\' glyph", nullptr},
|
||||
{"no-prune-unicode-ranges", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES>, "Don't change the 'OS/2 ulUnicodeRange*' bits.", nullptr},
|
||||
{"no-layout-closure", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE>, "Don't perform glyph closure for layout substitution (GSUB).", nullptr},
|
||||
{"glyph-names", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_GLYPH_NAMES>, "Keep PS glyph names in TT-flavored fonts. ", nullptr},
|
||||
{"passthrough-tables", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED>, "Do not drop tables that the tool does not know how to subset.", nullptr},
|
||||
{"preprocess-face", 0, 0, G_OPTION_ARG_NONE, &this->preprocess,
|
||||
{"preprocess-face", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &this->preprocess,
|
||||
"Alternative name for --preprocess.", nullptr},
|
||||
{"preprocess", 0, 0, G_OPTION_ARG_NONE, &this->preprocess,
|
||||
"If set preprocesses the face with the add accelerator option before actually subsetting.", nullptr},
|
||||
#ifdef HB_EXPERIMENTAL_API
|
||||
{"iftb-requirements", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_IFTB_REQUIREMENTS>, "Enforce requirements needed to use the subset with incremental font transfer IFTB patches.", nullptr},
|
||||
#endif
|
||||
{"optimize", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS>, "Perform IUP delta optimization on the resulting gvar table's deltas", nullptr},
|
||||
{nullptr}
|
||||
};
|
||||
add_group (flag_entries,
|
||||
|
||||
@@ -41,7 +41,9 @@
|
||||
# define CELL_H (2 * CELL_W)
|
||||
|
||||
static void
|
||||
chafa_print_image_rgb24 (const void *data, int width, int height, int stride, int level)
|
||||
chafa_print_image_rgb24 (const void *data, int width, int height, int stride, int level,
|
||||
cairo_write_func_t write_func,
|
||||
void *closure)
|
||||
{
|
||||
ChafaTermInfo *term_info;
|
||||
ChafaSymbolMap *symbol_map;
|
||||
@@ -57,6 +59,8 @@ chafa_print_image_rgb24 (const void *data, int width, int height, int stride, in
|
||||
/* Adapt to terminal; use sixels if available, and fall back to symbols
|
||||
* with as many colors as are supported */
|
||||
|
||||
chafa_set_n_threads (1); // https://github.com/hpjansson/chafa/issues/125#issuecomment-1397475217
|
||||
|
||||
environ = g_get_environ ();
|
||||
term_info = chafa_term_db_detect (chafa_term_db_get_default (),
|
||||
environ);
|
||||
@@ -68,8 +72,8 @@ chafa_print_image_rgb24 (const void *data, int width, int height, int stride, in
|
||||
pixel_mode = CHAFA_PIXEL_MODE_SIXELS;
|
||||
mode = CHAFA_CANVAS_MODE_TRUECOLOR;
|
||||
}
|
||||
// else if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_SET_COLOR_FGBG_DIRECT))
|
||||
// mode = CHAFA_CANVAS_MODE_TRUECOLOR;
|
||||
else if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_SET_COLOR_FGBG_DIRECT))
|
||||
mode = CHAFA_CANVAS_MODE_TRUECOLOR;
|
||||
else if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_SET_COLOR_FGBG_256))
|
||||
mode = CHAFA_CANVAS_MODE_INDEXED_240;
|
||||
else if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_SET_COLOR_FGBG_16))
|
||||
@@ -114,10 +118,10 @@ chafa_print_image_rgb24 (const void *data, int width, int height, int stride, in
|
||||
|
||||
/* Print the string */
|
||||
|
||||
fwrite (gs->str, sizeof (char), gs->len, stdout);
|
||||
write_func (closure, (const unsigned char *) gs->str, gs->len);
|
||||
|
||||
if (pixel_mode != CHAFA_PIXEL_MODE_SIXELS)
|
||||
fputc ('\n', stdout);
|
||||
write_func (closure, (const unsigned char *) "\n", 1);
|
||||
|
||||
/* Free resources */
|
||||
|
||||
@@ -209,10 +213,12 @@ helper_cairo_surface_write_to_ansi_stream (cairo_surface_t *surface,
|
||||
if (env)
|
||||
chafa_level = atoi (env);
|
||||
if (chafa_level)
|
||||
chafa_print_image_rgb24 (data, width, height, stride, chafa_level);
|
||||
chafa_print_image_rgb24 (data, width, height, stride, chafa_level,
|
||||
write_func, closure);
|
||||
else
|
||||
#endif
|
||||
ansi_print_image_rgb24 (data, width, height, stride / 4);
|
||||
ansi_print_image_rgb24 (data, width, height, stride / 4,
|
||||
write_func, closure);
|
||||
}
|
||||
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
@@ -61,15 +61,11 @@ helper_cairo_create_ft_font_face (const font_options_t *font_opts)
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned int blob_length;
|
||||
const char *blob_data = hb_blob_get_data (font_opts->blob, &blob_length);
|
||||
|
||||
if (FT_New_Memory_Face (ft_library,
|
||||
(const FT_Byte *) blob_data,
|
||||
blob_length,
|
||||
font_opts->face_index,
|
||||
&ft_face))
|
||||
fail (false, "FT_New_Memory_Face fail");
|
||||
if (FT_New_Face (ft_library,
|
||||
font_opts->font_file,
|
||||
font_opts->face_index,
|
||||
&ft_face))
|
||||
fail (false, "FT_New_Face fail");
|
||||
}
|
||||
if (!ft_face)
|
||||
{
|
||||
|
||||
@@ -1,316 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2022 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HELPER_CAIRO_USER_HH
|
||||
#define HELPER_CAIRO_USER_HH
|
||||
|
||||
#include "font-options.hh"
|
||||
|
||||
#include <cairo.h>
|
||||
#include <hb.h>
|
||||
|
||||
#include "hb-blob.hh"
|
||||
|
||||
static void
|
||||
move_to (hb_draw_funcs_t *dfuncs,
|
||||
cairo_t *cr,
|
||||
hb_draw_state_t *st,
|
||||
float to_x, float to_y,
|
||||
void *)
|
||||
{
|
||||
cairo_move_to (cr,
|
||||
(double) to_x, (double) to_y);
|
||||
}
|
||||
|
||||
static void
|
||||
line_to (hb_draw_funcs_t *dfuncs,
|
||||
cairo_t *cr,
|
||||
hb_draw_state_t *st,
|
||||
float to_x, float to_y,
|
||||
void *)
|
||||
{
|
||||
cairo_line_to (cr,
|
||||
(double) to_x, (double) to_y);
|
||||
}
|
||||
|
||||
static void
|
||||
cubic_to (hb_draw_funcs_t *dfuncs,
|
||||
cairo_t *cr,
|
||||
hb_draw_state_t *st,
|
||||
float control1_x, float control1_y,
|
||||
float control2_x, float control2_y,
|
||||
float to_x, float to_y,
|
||||
void *)
|
||||
{
|
||||
cairo_curve_to (cr,
|
||||
(double) control1_x, (double) control1_y,
|
||||
(double) control2_x, (double) control2_y,
|
||||
(double) to_x, (double) to_y);
|
||||
}
|
||||
|
||||
static void
|
||||
close_path (hb_draw_funcs_t *dfuncs,
|
||||
cairo_t *cr,
|
||||
hb_draw_state_t *st,
|
||||
void *)
|
||||
{
|
||||
cairo_close_path (cr);
|
||||
}
|
||||
|
||||
|
||||
static hb_draw_funcs_t *
|
||||
get_cairo_draw_funcs ()
|
||||
{
|
||||
static hb_draw_funcs_t *funcs;
|
||||
|
||||
if (!funcs)
|
||||
{
|
||||
funcs = hb_draw_funcs_create ();
|
||||
hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) move_to, nullptr, nullptr);
|
||||
hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) line_to, nullptr, nullptr);
|
||||
hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) cubic_to, nullptr, nullptr);
|
||||
hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) close_path, nullptr, nullptr);
|
||||
}
|
||||
|
||||
return funcs;
|
||||
}
|
||||
|
||||
static const cairo_user_data_key_t _hb_font_cairo_user_data_key = {0};
|
||||
|
||||
static cairo_status_t
|
||||
render_glyph (cairo_scaled_font_t *scaled_font,
|
||||
unsigned long glyph,
|
||||
cairo_t *cr,
|
||||
cairo_text_extents_t *extents)
|
||||
{
|
||||
hb_font_t *font = (hb_font_t *) (cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
|
||||
&_hb_font_cairo_user_data_key));
|
||||
|
||||
hb_position_t x_scale, y_scale;
|
||||
hb_font_get_scale (font, &x_scale, &y_scale);
|
||||
cairo_scale (cr, +1./x_scale, -1./y_scale);
|
||||
|
||||
hb_font_get_glyph_shape (font, glyph, get_cairo_draw_funcs (), cr);
|
||||
cairo_fill (cr);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
|
||||
|
||||
#ifdef CAIRO_HAS_PNG_FUNCTIONS
|
||||
static inline cairo_status_t
|
||||
_hb_bytes_read_func (hb_bytes_t *src,
|
||||
char *data,
|
||||
unsigned length)
|
||||
{
|
||||
if (unlikely (src->length < length))
|
||||
return CAIRO_STATUS_READ_ERROR;
|
||||
|
||||
memcpy (data, src->arrayZ, length);
|
||||
*src += length;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
render_color_glyph_png (cairo_scaled_font_t *scaled_font,
|
||||
unsigned long glyph,
|
||||
cairo_t *cr,
|
||||
cairo_text_extents_t *extents)
|
||||
{
|
||||
hb_font_t *font = (hb_font_t *) (cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
|
||||
&_hb_font_cairo_user_data_key));
|
||||
|
||||
hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, glyph);
|
||||
if (blob == hb_blob_get_empty ())
|
||||
return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
|
||||
|
||||
hb_position_t x_scale, y_scale;
|
||||
hb_font_get_scale (font, &x_scale, &y_scale);
|
||||
cairo_scale (cr, +1./x_scale, -1./y_scale);
|
||||
|
||||
/* Draw PNG. */
|
||||
hb_bytes_t bytes = blob->as_bytes ();
|
||||
cairo_surface_t *surface = cairo_image_surface_create_from_png_stream ((cairo_read_func_t) _hb_bytes_read_func,
|
||||
std::addressof (bytes));
|
||||
hb_blob_destroy (blob);
|
||||
|
||||
if (unlikely (cairo_surface_status (surface)) != CAIRO_STATUS_SUCCESS)
|
||||
{
|
||||
cairo_surface_destroy (surface);
|
||||
return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
int width = cairo_image_surface_get_width (surface);
|
||||
int height = cairo_image_surface_get_width (surface);
|
||||
|
||||
hb_glyph_extents_t hb_extents;
|
||||
if (unlikely (!hb_font_get_glyph_extents (font, glyph, &hb_extents)))
|
||||
{
|
||||
cairo_surface_destroy (surface);
|
||||
return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface);
|
||||
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
|
||||
|
||||
cairo_matrix_t matrix = {(double) width, 0, 0, (double) height, 0, 0};
|
||||
cairo_pattern_set_matrix (pattern, &matrix);
|
||||
|
||||
cairo_translate (cr, hb_extents.x_bearing, hb_extents.y_bearing);
|
||||
cairo_scale (cr, hb_extents.width, hb_extents.height);
|
||||
cairo_set_source (cr, pattern);
|
||||
|
||||
cairo_rectangle (cr, 0, 0, 1, 1);
|
||||
cairo_fill (cr);
|
||||
cairo_pattern_destroy (pattern);
|
||||
|
||||
cairo_surface_destroy (surface);
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
static cairo_status_t
|
||||
render_color_glyph_layers (cairo_scaled_font_t *scaled_font,
|
||||
unsigned long glyph,
|
||||
cairo_t *cr,
|
||||
cairo_text_extents_t *extents)
|
||||
{
|
||||
hb_font_t *font = (hb_font_t *) (cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
|
||||
&_hb_font_cairo_user_data_key));
|
||||
hb_face_t *face = hb_font_get_face (font);
|
||||
|
||||
unsigned count = hb_ot_color_glyph_get_layers (face, glyph, 0, nullptr, nullptr);
|
||||
if (!count)
|
||||
return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
|
||||
|
||||
hb_ot_color_layer_t layers[16];
|
||||
unsigned offset = 0, len;
|
||||
do {
|
||||
len = ARRAY_LENGTH (layers);
|
||||
hb_ot_color_glyph_get_layers (face, glyph,
|
||||
offset,
|
||||
&len,
|
||||
layers);
|
||||
for (unsigned i = 0; i < len; i++)
|
||||
{
|
||||
hb_color_t color;
|
||||
unsigned clen = 1;
|
||||
unsigned color_index = layers[i].color_index;
|
||||
bool is_foreground = color_index == 65535;
|
||||
|
||||
if (!is_foreground)
|
||||
{
|
||||
hb_ot_color_palette_get_colors (face,
|
||||
0/*palette_index*/,
|
||||
color_index/*start_offset*/,
|
||||
&clen/*color_count*/,
|
||||
&color);
|
||||
if (clen < 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
cairo_save (cr);
|
||||
{
|
||||
if (!is_foreground)
|
||||
cairo_set_source_rgba (cr,
|
||||
hb_color_get_red (color) / 255.,
|
||||
hb_color_get_green (color) / 255.,
|
||||
hb_color_get_blue (color) / 255.,
|
||||
hb_color_get_alpha (color) / 255.);
|
||||
|
||||
cairo_status_t ret = render_glyph (scaled_font, layers[i].glyph, cr, extents);
|
||||
if (ret != CAIRO_STATUS_SUCCESS)
|
||||
return ret;
|
||||
}
|
||||
cairo_restore (cr);
|
||||
}
|
||||
}
|
||||
while (len == ARRAY_LENGTH (layers));
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
render_color_glyph (cairo_scaled_font_t *scaled_font,
|
||||
unsigned long glyph,
|
||||
cairo_t *cr,
|
||||
cairo_text_extents_t *extents)
|
||||
{
|
||||
cairo_status_t ret = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
|
||||
|
||||
#ifdef CAIRO_HAS_PNG_FUNCTIONS
|
||||
ret = render_color_glyph_png (scaled_font, glyph, cr, extents);
|
||||
if (ret != CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED)
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
ret = render_color_glyph_layers (scaled_font, glyph, cr, extents);
|
||||
if (ret != CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED)
|
||||
return ret;
|
||||
|
||||
return render_glyph (scaled_font, glyph, cr, extents);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline cairo_font_face_t *
|
||||
helper_cairo_create_user_font_face (const font_options_t *font_opts)
|
||||
{
|
||||
cairo_font_face_t *cairo_face = cairo_user_font_face_create ();
|
||||
|
||||
cairo_font_face_set_user_data (cairo_face,
|
||||
&_hb_font_cairo_user_data_key,
|
||||
hb_font_reference (font_opts->font),
|
||||
(cairo_destroy_func_t) hb_font_destroy);
|
||||
|
||||
cairo_user_font_face_set_render_glyph_func (cairo_face, render_glyph);
|
||||
#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
|
||||
hb_face_t *face = hb_font_get_face (font_opts->font);
|
||||
if (hb_ot_color_has_png (face) || hb_ot_color_has_layers (face))
|
||||
cairo_user_font_face_set_render_color_glyph_func (cairo_face, render_color_glyph);
|
||||
#endif
|
||||
|
||||
return cairo_face;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
helper_cairo_user_font_face_has_data (cairo_font_face_t *font_face)
|
||||
{
|
||||
return cairo_font_face_get_user_data (font_face, &_hb_font_cairo_user_data_key);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
helper_cairo_user_scaled_font_has_color (cairo_scaled_font_t *scaled_font)
|
||||
{
|
||||
/* Ignoring SVG for now, since we cannot render it. */
|
||||
hb_font_t *font = (hb_font_t *) (cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
|
||||
&_hb_font_cairo_user_data_key));
|
||||
hb_face_t *face = hb_font_get_face (font);
|
||||
return hb_ot_color_has_png (face) || hb_ot_color_has_layers (face);
|
||||
}
|
||||
|
||||
#endif
|
||||
+130
-125
@@ -29,11 +29,13 @@
|
||||
|
||||
#include "view-options.hh"
|
||||
#include "output-options.hh"
|
||||
#include "helper-cairo-ft.hh"
|
||||
#include "helper-cairo-user.hh"
|
||||
#ifdef HAVE_CAIRO_FT
|
||||
# include "helper-cairo-ft.hh"
|
||||
#endif
|
||||
|
||||
#include <cairo.h>
|
||||
#include <hb.h>
|
||||
#include <hb-cairo.h>
|
||||
|
||||
#include "helper-cairo-ansi.hh"
|
||||
#ifdef CAIRO_HAS_SVG_SURFACE
|
||||
@@ -65,27 +67,47 @@ _cairo_eps_surface_create_for_stream (cairo_write_func_t write_func,
|
||||
# undef HAS_EPS
|
||||
# endif
|
||||
#endif
|
||||
#ifdef CAIRO_HAS_SCRIPT_SURFACE
|
||||
# include <cairo-script.h>
|
||||
#endif
|
||||
|
||||
static inline bool
|
||||
helper_cairo_use_hb_draw (const font_options_t *font_opts)
|
||||
{
|
||||
const char *env = getenv ("HB_DRAW");
|
||||
if (!env)
|
||||
/* Older cairo had a bug in rendering COLRv0 fonts in
|
||||
* right-to-left direction as well as clipping issue
|
||||
* with user-fonts.
|
||||
*
|
||||
* https://github.com/harfbuzz/harfbuzz/issues/4051 */
|
||||
return cairo_version () >= CAIRO_VERSION_ENCODE (1, 17, 5);
|
||||
|
||||
return atoi (env);
|
||||
}
|
||||
|
||||
static inline cairo_scaled_font_t *
|
||||
helper_cairo_create_scaled_font (const font_options_t *font_opts)
|
||||
helper_cairo_create_scaled_font (const font_options_t *font_opts,
|
||||
const view_options_t *view_opts)
|
||||
{
|
||||
bool use_hb_draw = helper_cairo_use_hb_draw (font_opts);
|
||||
hb_font_t *font = hb_font_reference (font_opts->font);
|
||||
hb_font_t *font = font_opts->font;
|
||||
bool use_hb_draw = true;
|
||||
|
||||
cairo_font_face_t *cairo_face;
|
||||
#ifdef HAVE_CAIRO_FT
|
||||
use_hb_draw = helper_cairo_use_hb_draw (font_opts);
|
||||
#endif
|
||||
|
||||
|
||||
cairo_font_face_t *cairo_face = nullptr;
|
||||
if (use_hb_draw)
|
||||
cairo_face = helper_cairo_create_user_font_face (font_opts);
|
||||
{
|
||||
cairo_face = hb_cairo_font_face_create_for_font (font);
|
||||
hb_cairo_font_face_set_scale_factor (cairo_face, 1 << font_opts->subpixel_bits);
|
||||
}
|
||||
#ifdef HAVE_CAIRO_FT
|
||||
else
|
||||
cairo_face = helper_cairo_create_ft_font_face (font_opts);
|
||||
#endif
|
||||
|
||||
cairo_matrix_t ctm, font_matrix;
|
||||
cairo_font_options_t *font_options;
|
||||
@@ -94,12 +116,41 @@ helper_cairo_create_scaled_font (const font_options_t *font_opts)
|
||||
cairo_matrix_init_scale (&font_matrix,
|
||||
font_opts->font_size_x,
|
||||
font_opts->font_size_y);
|
||||
if (use_hb_draw)
|
||||
if (!use_hb_draw)
|
||||
font_matrix.xy = -font_opts->slant * font_opts->font_size_x;
|
||||
|
||||
font_options = cairo_font_options_create ();
|
||||
cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
|
||||
cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF);
|
||||
#ifdef CAIRO_COLOR_PALETTE_DEFAULT
|
||||
cairo_font_options_set_color_palette (font_options, view_opts->palette);
|
||||
#endif
|
||||
#ifdef HAVE_CAIRO_FONT_OPTIONS_GET_CUSTOM_PALETTE_COLOR
|
||||
if (view_opts->custom_palette)
|
||||
{
|
||||
char **entries = g_strsplit (view_opts->custom_palette, ",", -1);
|
||||
unsigned idx = 0;
|
||||
for (unsigned i = 0; entries[i]; i++)
|
||||
{
|
||||
const char *p = strchr (entries[i], '=');
|
||||
if (!p)
|
||||
p = entries[i];
|
||||
else
|
||||
{
|
||||
sscanf (entries[i], "%u", &idx);
|
||||
p++;
|
||||
}
|
||||
|
||||
unsigned fr, fg, fb, fa;
|
||||
fr = fg = fb = fa = 0;
|
||||
if (parse_color (p, fr, fg,fb, fa))
|
||||
cairo_font_options_set_custom_palette_color (font_options, idx, fr / 255., fg / 255., fb / 255., fa / 255.);
|
||||
|
||||
idx++;
|
||||
}
|
||||
g_strfreev (entries);
|
||||
}
|
||||
#endif
|
||||
|
||||
cairo_scaled_font_t *scaled_font = cairo_scaled_font_create (cairo_face,
|
||||
&font_matrix,
|
||||
@@ -109,23 +160,24 @@ helper_cairo_create_scaled_font (const font_options_t *font_opts)
|
||||
cairo_font_options_destroy (font_options);
|
||||
cairo_font_face_destroy (cairo_face);
|
||||
|
||||
static cairo_user_data_key_t key;
|
||||
if (cairo_scaled_font_set_user_data (scaled_font,
|
||||
&key,
|
||||
(void *) font,
|
||||
(cairo_destroy_func_t) hb_font_destroy))
|
||||
hb_font_destroy (font);
|
||||
|
||||
return scaled_font;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
helper_cairo_scaled_font_has_color (cairo_scaled_font_t *scaled_font)
|
||||
{
|
||||
if (helper_cairo_user_font_face_has_data (cairo_scaled_font_get_font_face (scaled_font)))
|
||||
return helper_cairo_user_scaled_font_has_color (scaled_font);
|
||||
else
|
||||
hb_font_t *font = hb_cairo_font_face_get_font (cairo_scaled_font_get_font_face (scaled_font));
|
||||
|
||||
#ifdef HAVE_CAIRO_FT
|
||||
if (!font)
|
||||
return helper_cairo_ft_scaled_font_has_color (scaled_font);
|
||||
#endif
|
||||
|
||||
hb_face_t *face = hb_font_get_face (font);
|
||||
|
||||
return hb_ot_color_has_png (face) ||
|
||||
hb_ot_color_has_layers (face) ||
|
||||
hb_ot_color_has_paint (face);
|
||||
}
|
||||
|
||||
|
||||
@@ -337,6 +389,24 @@ _cairo_png_surface_create_for_stream (cairo_write_func_t write_func,
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CAIRO_HAS_SCRIPT_SURFACE
|
||||
|
||||
static cairo_surface_t *
|
||||
_cairo_script_surface_create_for_stream (cairo_write_func_t write_func,
|
||||
void *closure,
|
||||
double width,
|
||||
double height,
|
||||
cairo_content_t content,
|
||||
image_protocol_t protocol HB_UNUSED)
|
||||
{
|
||||
cairo_device_t *script = cairo_script_create_for_stream (write_func, closure);
|
||||
cairo_surface_t *surface = cairo_script_surface_create (script, content, width, height);
|
||||
cairo_device_destroy (script);
|
||||
return surface;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static cairo_status_t
|
||||
stdio_write_func (void *closure,
|
||||
const unsigned char *data,
|
||||
@@ -373,6 +443,9 @@ static const char *helper_cairo_supported_formats[] =
|
||||
"eps",
|
||||
#endif
|
||||
#endif
|
||||
#ifdef CAIRO_HAS_SCRIPT_SURFACE
|
||||
"script",
|
||||
#endif
|
||||
nullptr
|
||||
};
|
||||
|
||||
@@ -461,21 +534,25 @@ helper_cairo_create_context (double w, double h,
|
||||
else if (0 == g_ascii_strcasecmp (extension, "eps"))
|
||||
constructor = _cairo_eps_surface_create_for_stream;
|
||||
#endif
|
||||
#ifdef CAIRO_HAS_SCRIPT_SURFACE
|
||||
else if (0 == g_ascii_strcasecmp (extension, "script"))
|
||||
constructor2 = _cairo_script_surface_create_for_stream;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
unsigned int fr, fg, fb, fa, br, bg, bb, ba;
|
||||
const char *color;
|
||||
br = bg = bb = 0; ba = 255;
|
||||
br = bg = bb = ba = 255;
|
||||
color = view_opts->back ? view_opts->back : DEFAULT_BACK;
|
||||
sscanf (color + (*color=='#'), "%2x%2x%2x%2x", &br, &bg, &bb, &ba);
|
||||
parse_color (color, br, bg, bb, ba);
|
||||
fr = fg = fb = 0; fa = 255;
|
||||
color = view_opts->fore ? view_opts->fore : DEFAULT_FORE;
|
||||
sscanf (color + (*color=='#'), "%2x%2x%2x%2x", &fr, &fg, &fb, &fa);
|
||||
parse_color (color, fr, fg, fb, fa);
|
||||
|
||||
if (content == CAIRO_CONTENT_ALPHA)
|
||||
{
|
||||
if (view_opts->annotate ||
|
||||
if (view_opts->show_extents ||
|
||||
br != bg || bg != bb ||
|
||||
fr != fg || fg != fb)
|
||||
content = CAIRO_CONTENT_COLOR;
|
||||
@@ -510,10 +587,9 @@ helper_cairo_create_context (double w, double h,
|
||||
default:
|
||||
case CAIRO_CONTENT_COLOR:
|
||||
case CAIRO_CONTENT_COLOR_ALPHA:
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
cairo_set_source_rgba (cr, br / 255., bg / 255., bb / 255., ba / 255.);
|
||||
cairo_paint (cr);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
cairo_set_source_rgba (cr, fr / 255., fg / 255., fb / 255., fa / 255.);
|
||||
break;
|
||||
}
|
||||
@@ -540,117 +616,46 @@ helper_cairo_destroy_context (cairo_t *cr)
|
||||
|
||||
|
||||
struct helper_cairo_line_t {
|
||||
cairo_glyph_t *glyphs;
|
||||
unsigned int num_glyphs;
|
||||
char *utf8;
|
||||
unsigned int utf8_len;
|
||||
cairo_text_cluster_t *clusters;
|
||||
unsigned int num_clusters;
|
||||
cairo_text_cluster_flags_t cluster_flags;
|
||||
cairo_glyph_t *glyphs = nullptr;
|
||||
unsigned int num_glyphs = 0;
|
||||
char *utf8 = nullptr;
|
||||
unsigned int utf8_len = 0;
|
||||
cairo_text_cluster_t *clusters = nullptr;
|
||||
unsigned int num_clusters = 0;
|
||||
cairo_text_cluster_flags_t cluster_flags = (cairo_text_cluster_flags_t) 0;
|
||||
|
||||
void finish () {
|
||||
helper_cairo_line_t (const char *utf8_,
|
||||
unsigned utf8_len_,
|
||||
hb_buffer_t *buffer,
|
||||
hb_bool_t utf8_clusters,
|
||||
unsigned subpixel_bits) :
|
||||
utf8 (utf8_ ? g_strndup (utf8_, utf8_len_) : nullptr),
|
||||
utf8_len (utf8_len_)
|
||||
{
|
||||
hb_cairo_glyphs_from_buffer (buffer,
|
||||
utf8_clusters,
|
||||
1 << subpixel_bits, 1 << subpixel_bits,
|
||||
0., 0.,
|
||||
utf8, utf8_len,
|
||||
&glyphs, &num_glyphs,
|
||||
&clusters, &num_clusters,
|
||||
&cluster_flags);
|
||||
}
|
||||
|
||||
void finish ()
|
||||
{
|
||||
if (glyphs)
|
||||
cairo_glyph_free (glyphs);
|
||||
if (clusters)
|
||||
cairo_text_cluster_free (clusters);
|
||||
if (utf8)
|
||||
g_free (utf8);
|
||||
g_free (utf8);
|
||||
}
|
||||
|
||||
void get_advance (double *x_advance, double *y_advance) {
|
||||
void get_advance (double *x_advance, double *y_advance)
|
||||
{
|
||||
*x_advance = glyphs[num_glyphs].x;
|
||||
*y_advance = glyphs[num_glyphs].y;
|
||||
}
|
||||
};
|
||||
|
||||
static inline void
|
||||
helper_cairo_line_from_buffer (helper_cairo_line_t *l,
|
||||
hb_buffer_t *buffer,
|
||||
const char *text,
|
||||
unsigned int text_len,
|
||||
int scale_bits,
|
||||
hb_bool_t utf8_clusters)
|
||||
{
|
||||
memset (l, 0, sizeof (*l));
|
||||
|
||||
l->num_glyphs = hb_buffer_get_length (buffer);
|
||||
hb_glyph_info_t *hb_glyph = hb_buffer_get_glyph_infos (buffer, nullptr);
|
||||
hb_glyph_position_t *hb_position = hb_buffer_get_glyph_positions (buffer, nullptr);
|
||||
l->glyphs = cairo_glyph_allocate (l->num_glyphs + 1);
|
||||
|
||||
if (text) {
|
||||
l->utf8 = g_strndup (text, text_len);
|
||||
l->utf8_len = text_len;
|
||||
l->num_clusters = l->num_glyphs ? 1 : 0;
|
||||
for (unsigned int i = 1; i < l->num_glyphs; i++)
|
||||
if (hb_glyph[i].cluster != hb_glyph[i-1].cluster)
|
||||
l->num_clusters++;
|
||||
l->clusters = cairo_text_cluster_allocate (l->num_clusters);
|
||||
}
|
||||
|
||||
if ((l->num_glyphs && !l->glyphs) ||
|
||||
(l->utf8_len && !l->utf8) ||
|
||||
(l->num_clusters && !l->clusters))
|
||||
{
|
||||
l->finish ();
|
||||
return;
|
||||
}
|
||||
|
||||
hb_position_t x = 0, y = 0;
|
||||
int i;
|
||||
for (i = 0; i < (int) l->num_glyphs; i++)
|
||||
{
|
||||
l->glyphs[i].index = hb_glyph[i].codepoint;
|
||||
l->glyphs[i].x = scalbn ((double) hb_position->x_offset + x, scale_bits);
|
||||
l->glyphs[i].y = scalbn ((double) -hb_position->y_offset + y, scale_bits);
|
||||
x += hb_position->x_advance;
|
||||
y += -hb_position->y_advance;
|
||||
|
||||
hb_position++;
|
||||
}
|
||||
l->glyphs[i].index = -1;
|
||||
l->glyphs[i].x = scalbn ((double) x, scale_bits);
|
||||
l->glyphs[i].y = scalbn ((double) y, scale_bits);
|
||||
|
||||
if (l->num_clusters) {
|
||||
memset ((void *) l->clusters, 0, l->num_clusters * sizeof (l->clusters[0]));
|
||||
hb_bool_t backward = HB_DIRECTION_IS_BACKWARD (hb_buffer_get_direction (buffer));
|
||||
l->cluster_flags = backward ? CAIRO_TEXT_CLUSTER_FLAG_BACKWARD : (cairo_text_cluster_flags_t) 0;
|
||||
unsigned int cluster = 0;
|
||||
const char *start = l->utf8, *end;
|
||||
l->clusters[cluster].num_glyphs++;
|
||||
if (backward) {
|
||||
for (i = l->num_glyphs - 2; i >= 0; i--) {
|
||||
if (hb_glyph[i].cluster != hb_glyph[i+1].cluster) {
|
||||
g_assert (hb_glyph[i].cluster > hb_glyph[i+1].cluster);
|
||||
if (utf8_clusters)
|
||||
end = start + hb_glyph[i].cluster - hb_glyph[i+1].cluster;
|
||||
else
|
||||
end = g_utf8_offset_to_pointer (start, hb_glyph[i].cluster - hb_glyph[i+1].cluster);
|
||||
l->clusters[cluster].num_bytes = end - start;
|
||||
start = end;
|
||||
cluster++;
|
||||
}
|
||||
l->clusters[cluster].num_glyphs++;
|
||||
}
|
||||
l->clusters[cluster].num_bytes = l->utf8 + text_len - start;
|
||||
} else {
|
||||
for (i = 1; i < (int) l->num_glyphs; i++) {
|
||||
if (hb_glyph[i].cluster != hb_glyph[i-1].cluster) {
|
||||
g_assert (hb_glyph[i].cluster > hb_glyph[i-1].cluster);
|
||||
if (utf8_clusters)
|
||||
end = start + hb_glyph[i].cluster - hb_glyph[i-1].cluster;
|
||||
else
|
||||
end = g_utf8_offset_to_pointer (start, hb_glyph[i].cluster - hb_glyph[i-1].cluster);
|
||||
l->clusters[cluster].num_bytes = end - start;
|
||||
start = end;
|
||||
cluster++;
|
||||
}
|
||||
l->clusters[cluster].num_glyphs++;
|
||||
}
|
||||
l->clusters[cluster].num_bytes = l->utf8 + text_len - start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright © 2023 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Garret Rieger
|
||||
*/
|
||||
#ifndef HELPER_SUBSET_HH
|
||||
#define HELPER_SUBSET_HH
|
||||
|
||||
#include "glib.h"
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include "hb-subset.h"
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
|
||||
// Parses an axis position string and sets min, default, and max to
|
||||
// the requested values. If a value should be set to it's default value
|
||||
// then it will be set to NaN.
|
||||
static gboolean
|
||||
parse_axis_position(const char* s,
|
||||
float* min,
|
||||
float* def,
|
||||
float* max,
|
||||
gboolean* drop,
|
||||
GError **error)
|
||||
{
|
||||
const char* part = strpbrk(s, ":");
|
||||
*drop = false;
|
||||
if (!part) {
|
||||
// Single value.
|
||||
if (strcmp (s, "drop") == 0)
|
||||
{
|
||||
*min = NAN;
|
||||
*def = NAN;
|
||||
*max = NAN;
|
||||
*drop = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
char *p;
|
||||
float axis_value = strtof (s, &p);
|
||||
if (errno || s == p)
|
||||
{
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Failed parsing axis value at: '%s'", s);
|
||||
return false;
|
||||
}
|
||||
|
||||
*min = axis_value;
|
||||
*def = axis_value;
|
||||
*max = axis_value;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
float values[3];
|
||||
int count = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
errno = 0;
|
||||
count++;
|
||||
if (!*s || part == s) {
|
||||
values[i] = NAN;
|
||||
|
||||
if (part == NULL) break;
|
||||
s = part + 1;
|
||||
part = strpbrk(s, ":");
|
||||
continue;
|
||||
}
|
||||
|
||||
char *pend;
|
||||
values[i] = strtof (s, &pend);
|
||||
if (errno || s == pend || (part && pend != part))
|
||||
{
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Failed parsing axis value at: '%s'", s);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (part == NULL) break;
|
||||
s = pend + 1;
|
||||
part = strpbrk(s, ":");
|
||||
}
|
||||
|
||||
if (count == 2) {
|
||||
*min = values[0];
|
||||
*def = NAN;
|
||||
*max = values[1];
|
||||
return true;
|
||||
} else if (count == 3) {
|
||||
*min = values[0];
|
||||
*def = values[1];
|
||||
*max = values[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Failed parsing axis value at: '%s'", s);
|
||||
return false;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_instancing_spec (const char *arg,
|
||||
hb_face_t* face,
|
||||
hb_subset_input_t* input,
|
||||
GError **error)
|
||||
{
|
||||
char* s;
|
||||
while ((s = strtok((char *) arg, "=")))
|
||||
{
|
||||
arg = NULL;
|
||||
unsigned len = strlen (s);
|
||||
if (len > 4) //Axis tags are 4 bytes.
|
||||
{
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Failed parsing axis tag at: '%s'", s);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* support *=drop */
|
||||
if (0 == strcmp (s, "*"))
|
||||
{
|
||||
s = strtok(NULL, ", ");
|
||||
if (0 != strcmp (s, "drop"))
|
||||
{
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Failed parsing axis position at: '%s'", s);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hb_subset_input_pin_all_axes_to_default (input, face))
|
||||
{
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Failed pinning all axes to default.");
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
hb_tag_t axis_tag = hb_tag_from_string (s, len);
|
||||
|
||||
s = strtok(NULL, ", ");
|
||||
if (!s)
|
||||
{
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Value not specified for axis: %c%c%c%c", HB_UNTAG (axis_tag));
|
||||
return false;
|
||||
}
|
||||
|
||||
gboolean drop;
|
||||
float min, def, max;
|
||||
if (!parse_axis_position(s, &min, &def, &max, &drop, error))
|
||||
return false;
|
||||
|
||||
if (drop)
|
||||
{
|
||||
if (!hb_subset_input_pin_axis_to_default (input,
|
||||
face,
|
||||
axis_tag))
|
||||
{
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag));
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (min == def && def == max) {
|
||||
if (!hb_subset_input_pin_axis_location (input,
|
||||
face, axis_tag,
|
||||
def))
|
||||
{
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag));
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!hb_subset_input_set_axis_range (input,
|
||||
face, axis_tag,
|
||||
min, max, def))
|
||||
{
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag));
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Partial instancing is not supported.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -6,26 +6,31 @@ hb_shape_sources = [
|
||||
'hb-shape.cc',
|
||||
]
|
||||
|
||||
hb_info_sources = [
|
||||
'hb-info.cc',
|
||||
]
|
||||
|
||||
hb_ot_shape_closure_sources = [
|
||||
'hb-ot-shape-closure.cc',
|
||||
]
|
||||
|
||||
hb_subset_cli_sources = [
|
||||
'hb-subset.cc',
|
||||
'helper-subset.hh',
|
||||
]
|
||||
|
||||
util_deps = [freetype_dep, cairo_dep, cairo_ft_dep, glib_dep]
|
||||
|
||||
if conf.get('HAVE_GLIB', 0) == 1
|
||||
if conf.get('HAVE_FREETYPE', 0) == 1 and conf.get('HAVE_CAIRO_FT', 0) == 1
|
||||
|
||||
if conf.get('HAVE_CAIRO', 0) == 1
|
||||
hb_view = executable('hb-view', hb_view_sources,
|
||||
cpp_args: cpp_args,
|
||||
include_directories: [incconfig, incsrc],
|
||||
dependencies: [util_deps, chafa_dep],
|
||||
link_with: [libharfbuzz],
|
||||
link_with: [libharfbuzz, libharfbuzz_cairo],
|
||||
install: true,
|
||||
)
|
||||
meson.override_find_program('hb-view', hb_view)
|
||||
endif
|
||||
|
||||
hb_shape = executable('hb-shape', hb_shape_sources,
|
||||
@@ -35,6 +40,16 @@ if conf.get('HAVE_GLIB', 0) == 1
|
||||
link_with: [libharfbuzz],
|
||||
install: true,
|
||||
)
|
||||
meson.override_find_program('hb-shape', hb_shape)
|
||||
|
||||
hb_info = executable('hb-info', [hb_info_sources, gobject_enums_h],
|
||||
cpp_args: cpp_args,
|
||||
include_directories: [incconfig, incsrc],
|
||||
dependencies: [util_deps, libharfbuzz_gobject_dep, chafa_dep],
|
||||
link_with: [libharfbuzz],
|
||||
install: true,
|
||||
)
|
||||
meson.override_find_program('hb-info', hb_info)
|
||||
|
||||
hb_subset = executable('hb-subset', hb_subset_cli_sources,
|
||||
cpp_args: cpp_args,
|
||||
@@ -43,6 +58,7 @@ if conf.get('HAVE_GLIB', 0) == 1
|
||||
link_with: [libharfbuzz, libharfbuzz_subset],
|
||||
install: true,
|
||||
)
|
||||
meson.override_find_program('hb-subset', hb_subset)
|
||||
|
||||
hb_ot_shape_closure = executable('hb-ot-shape-closure', hb_ot_shape_closure_sources,
|
||||
cpp_args: cpp_args,
|
||||
@@ -51,6 +67,22 @@ if conf.get('HAVE_GLIB', 0) == 1
|
||||
link_with: [libharfbuzz],
|
||||
install: true,
|
||||
)
|
||||
meson.override_find_program('hb-ot-shape-closure', hb_ot_shape_closure)
|
||||
|
||||
if get_option('experimental_api')
|
||||
test('test-hb-subset-parsing',
|
||||
executable('test-hb-subset-parsing',
|
||||
['test-hb-subset-parsing.c', 'helper-subset.hh'],
|
||||
cpp_args: cpp_args,
|
||||
c_args: ['-DHB_EXPERIMENTAL_API'],
|
||||
include_directories: [incconfig, incsrc],
|
||||
dependencies: util_deps,
|
||||
link_with: [libharfbuzz, libharfbuzz_subset],
|
||||
install: false,
|
||||
),
|
||||
workdir : meson.current_source_dir(),
|
||||
suite: ['util'])
|
||||
endif
|
||||
else
|
||||
# Disable tests that use this
|
||||
hb_shape = disabler()
|
||||
|
||||
@@ -38,19 +38,23 @@
|
||||
#include <locale.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h> /* for isatty() */
|
||||
#endif
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#include <io.h> /* for setmode() under Windows */
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h> /* for isatty() */
|
||||
#endif
|
||||
|
||||
|
||||
#include <hb-features.h>
|
||||
#include <hb.h>
|
||||
#include <hb-ot.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gprintf.h>
|
||||
|
||||
|
||||
|
||||
static inline void fail (hb_bool_t suggest_help, const char *format, ...) G_GNUC_NORETURN G_GNUC_PRINTF (2, 3);
|
||||
|
||||
static inline void
|
||||
@@ -241,4 +245,44 @@ __inline float scalbnf (float x, int exp)
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline bool
|
||||
parse_color (const char *s,
|
||||
unsigned &r,
|
||||
unsigned &g,
|
||||
unsigned &b,
|
||||
unsigned &a)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
while (*s == ' ') s++;
|
||||
if (*s == '#') s++;
|
||||
|
||||
unsigned sr, sg, sb, sa;
|
||||
sa = 255;
|
||||
if (sscanf (s, "%2x%2x%2x%2x", &sr, &sg, &sb, &sa) <= 2)
|
||||
{
|
||||
if (sscanf (s, "%1x%1x%1x%1x", &sr, &sg, &sb, &sa) >= 3)
|
||||
{
|
||||
sr *= 17;
|
||||
sg *= 17;
|
||||
sb *= 17;
|
||||
sa *= 17;
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
ret = true;
|
||||
|
||||
if (ret)
|
||||
{
|
||||
r = sr;
|
||||
g = sg;
|
||||
b = sb;
|
||||
a = sa;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -61,11 +61,11 @@ struct shape_consumer_t : shape_options_t
|
||||
|
||||
for (unsigned int n = num_iterations; n; n--)
|
||||
{
|
||||
const char *error = nullptr;
|
||||
|
||||
populate_buffer (buffer, text, text_len, app.text_before, app.text_after);
|
||||
populate_buffer (buffer, text, text_len, app.text_before, app.text_after, app.font);
|
||||
if (n == 1)
|
||||
output.consume_text (buffer, text, text_len, utf8_clusters);
|
||||
|
||||
const char *error = nullptr;
|
||||
if (!shape (app.font, buffer, &error))
|
||||
{
|
||||
failed = true;
|
||||
@@ -77,7 +77,10 @@ struct shape_consumer_t : shape_options_t
|
||||
}
|
||||
}
|
||||
|
||||
output.consume_glyphs (buffer, text, text_len, utf8_clusters);
|
||||
if (glyphs)
|
||||
output.consume_glyphs (buffer, nullptr, 0, false);
|
||||
else
|
||||
output.consume_glyphs (buffer, text, text_len, utf8_clusters);
|
||||
return true;
|
||||
}
|
||||
template <typename app_t>
|
||||
|
||||
@@ -124,7 +124,7 @@ shape_format_options_t::serialize_line_no (unsigned int line_no,
|
||||
GString *gs)
|
||||
{
|
||||
if (show_line_num)
|
||||
g_string_append_printf (gs, "%d: ", line_no);
|
||||
g_string_append_printf (gs, "%u: ", line_no);
|
||||
}
|
||||
inline void
|
||||
shape_format_options_t::serialize_buffer_of_text (hb_buffer_t *buffer,
|
||||
|
||||
@@ -59,14 +59,61 @@ struct shape_options_t
|
||||
0));
|
||||
hb_buffer_set_invisible_glyph (buffer, invisible_glyph);
|
||||
hb_buffer_set_not_found_glyph (buffer, not_found_glyph);
|
||||
hb_buffer_set_not_found_variation_selector_glyph (buffer, not_found_variation_selector_glyph);
|
||||
hb_buffer_set_cluster_level (buffer, cluster_level);
|
||||
hb_buffer_guess_segment_properties (buffer);
|
||||
}
|
||||
|
||||
void populate_buffer (hb_buffer_t *buffer, const char *text, int text_len,
|
||||
const char *text_before, const char *text_after)
|
||||
const char *text_before, const char *text_after,
|
||||
hb_font_t *font)
|
||||
{
|
||||
hb_buffer_clear_contents (buffer);
|
||||
|
||||
if (glyphs)
|
||||
{
|
||||
/* Call the setup_buffer first while the buffer is empty,
|
||||
* as guess_segment_properties doesn't like glyphs in the buffer. */
|
||||
|
||||
setup_buffer (buffer);
|
||||
char *glyphs_text = (char *) text;
|
||||
int glyphs_len = text_len;
|
||||
if (glyphs_len < 0)
|
||||
glyphs_len = strlen (glyphs_text);
|
||||
|
||||
if (glyphs_len && glyphs_text[glyphs_len - 1] != ']')
|
||||
{
|
||||
glyphs_text = g_strdup_printf ("%*s]", glyphs_len, glyphs_text);
|
||||
glyphs_len = -1;
|
||||
}
|
||||
|
||||
hb_buffer_deserialize_glyphs (buffer,
|
||||
glyphs_text, glyphs_len,
|
||||
nullptr,
|
||||
font,
|
||||
HB_BUFFER_SERIALIZE_FORMAT_TEXT);
|
||||
|
||||
if (!strchr (glyphs_text, '+'))
|
||||
{
|
||||
scale_advances = false;
|
||||
unsigned count;
|
||||
hb_direction_t direction = hb_buffer_get_direction (buffer);
|
||||
hb_glyph_info_t *infos = hb_buffer_get_glyph_infos (buffer, &count);
|
||||
hb_glyph_position_t *positions = hb_buffer_get_glyph_positions (buffer, &count);
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
hb_font_get_glyph_advance_for_direction (font,
|
||||
infos[i].codepoint,
|
||||
direction,
|
||||
&positions[i].x_advance,
|
||||
&positions[i].y_advance);
|
||||
}
|
||||
|
||||
if (glyphs_text != text)
|
||||
g_free (glyphs_text);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (text_before) {
|
||||
unsigned int len = strlen (text_before);
|
||||
hb_buffer_add_utf8 (buffer, text_before, len, len, 0);
|
||||
@@ -93,11 +140,74 @@ struct shape_options_t
|
||||
|
||||
hb_bool_t shape (hb_font_t *font, hb_buffer_t *buffer, const char **error=nullptr)
|
||||
{
|
||||
if (!hb_shape_full (font, buffer, features, num_features, shapers))
|
||||
if (glyphs)
|
||||
{
|
||||
if (error)
|
||||
*error = "Shaping failed.";
|
||||
goto fail;
|
||||
/* Scale positions. */
|
||||
int x_scale, y_scale;
|
||||
hb_font_get_scale (font, &x_scale, &y_scale);
|
||||
unsigned upem = hb_face_get_upem (hb_font_get_face (font));
|
||||
unsigned count;
|
||||
auto *positions = hb_buffer_get_glyph_positions (buffer, &count);
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
{
|
||||
auto &pos = positions[i];
|
||||
pos.x_offset = pos.x_offset * x_scale / upem;
|
||||
pos.y_offset = pos.y_offset * y_scale / upem;
|
||||
if (scale_advances)
|
||||
{
|
||||
pos.x_advance = pos.x_advance * x_scale / upem;
|
||||
pos.y_advance = pos.y_advance * y_scale / upem;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (advance <= 0)
|
||||
{
|
||||
if (!hb_shape_full (font, buffer, features, num_features, shapers))
|
||||
{
|
||||
if (error)
|
||||
*error = "Shaping failed.";
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (advance < 0)
|
||||
{
|
||||
float unit = (1 << SUBPIXEL_BITS);
|
||||
|
||||
/* Calculate buffer advance */
|
||||
float w = 0;
|
||||
unsigned count = 0;
|
||||
hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &count);
|
||||
if (HB_DIRECTION_IS_HORIZONTAL (hb_buffer_get_direction (buffer)))
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
w += pos[i].x_advance;
|
||||
else
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
w += pos[i].y_advance;
|
||||
|
||||
printf ("Default size: %u\n", (unsigned) roundf (w / unit));
|
||||
exit (0);
|
||||
}
|
||||
}
|
||||
#ifdef HB_EXPERIMENTAL_API
|
||||
else
|
||||
{
|
||||
float unit = (1 << SUBPIXEL_BITS);
|
||||
float target_advance = advance * unit;
|
||||
float w = 0;
|
||||
hb_tag_t var_tag;
|
||||
float var_value;
|
||||
if (!hb_shape_justify (font, buffer, features, num_features, shapers,
|
||||
target_advance - unit * 0.5f, target_advance + unit * 0.5f,
|
||||
&w, &var_tag, &var_value))
|
||||
{
|
||||
if (error)
|
||||
*error = "Shaping failed.";
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (normalize_glyphs)
|
||||
@@ -133,11 +243,15 @@ struct shape_options_t
|
||||
hb_feature_t *features = nullptr;
|
||||
unsigned int num_features = 0;
|
||||
char **shapers = nullptr;
|
||||
signed advance = 0;
|
||||
hb_bool_t utf8_clusters = false;
|
||||
hb_codepoint_t invisible_glyph = 0;
|
||||
hb_codepoint_t not_found_glyph = 0;
|
||||
hb_codepoint_t not_found_variation_selector_glyph = HB_CODEPOINT_INVALID;
|
||||
hb_buffer_cluster_level_t cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT;
|
||||
hb_bool_t normalize_glyphs = false;
|
||||
hb_bool_t glyphs = false;
|
||||
bool scale_advances = true;
|
||||
hb_bool_t verify = false;
|
||||
hb_bool_t unsafe_to_concat = false;
|
||||
hb_bool_t safe_to_insert_tatweel = false;
|
||||
@@ -257,17 +371,25 @@ shape_options_t::add_options (option_parser_t *parser)
|
||||
{"script", 0, 0, G_OPTION_ARG_STRING, &this->script, "Set text script (default: auto)", "ISO-15924 tag"},
|
||||
{"bot", 0, 0, G_OPTION_ARG_NONE, &this->bot, "Treat text as beginning-of-paragraph", nullptr},
|
||||
{"eot", 0, 0, G_OPTION_ARG_NONE, &this->eot, "Treat text as end-of-paragraph", nullptr},
|
||||
#ifdef HB_EXPERIMENTAL_API
|
||||
{"justify-to", 0, 0,
|
||||
G_OPTION_ARG_INT, &this->advance, "Target size to justify to", "SIZE, or -1"},
|
||||
#endif
|
||||
{"preserve-default-ignorables",0, 0, G_OPTION_ARG_NONE, &this->preserve_default_ignorables, "Preserve Default-Ignorable characters", nullptr},
|
||||
{"remove-default-ignorables",0, 0, G_OPTION_ARG_NONE, &this->remove_default_ignorables, "Remove Default-Ignorable characters", nullptr},
|
||||
{"invisible-glyph", 0, 0, G_OPTION_ARG_INT, &this->invisible_glyph, "Glyph value to replace Default-Ignorables with", nullptr},
|
||||
{"not-found-glyph", 0, 0, G_OPTION_ARG_INT, &this->not_found_glyph, "Glyph value to replace not-found characters with", nullptr},
|
||||
{"not-found-variation-selector-glyph",
|
||||
0, 0, G_OPTION_ARG_INT, &this->not_found_variation_selector_glyph,
|
||||
"Glyph value to replace not-found variation-selector characters with", nullptr},
|
||||
{"utf8-clusters", 0, 0, G_OPTION_ARG_NONE, &this->utf8_clusters, "Use UTF8 byte indices, not char indices", nullptr},
|
||||
{"cluster-level", 0, 0, G_OPTION_ARG_INT, &this->cluster_level, "Cluster merging level (default: 0)", "0/1/2"},
|
||||
{"normalize-glyphs",0, 0, G_OPTION_ARG_NONE, &this->normalize_glyphs, "Rearrange glyph clusters in nominal order", nullptr},
|
||||
{"unsafe-to-concat",0, 0, G_OPTION_ARG_NONE, &this->unsafe_to_concat, "Produce unsafe-to-concat glyph flag", nullptr},
|
||||
{"safe-to-insert-tatweel",0, 0, G_OPTION_ARG_NONE, &this->safe_to_insert_tatweel, "Produce safe-to-insert-tatweel glyph flag", nullptr},
|
||||
{"glyphs", 0, 0, G_OPTION_ARG_NONE, &this->glyphs, "Interpret input as glyph string", nullptr},
|
||||
{"verify", 0, 0, G_OPTION_ARG_NONE, &this->verify, "Perform sanity checks on shaping results", nullptr},
|
||||
{"num-iterations", 'n', G_OPTION_FLAG_IN_MAIN,
|
||||
{"num-iterations", 'n',G_OPTION_FLAG_IN_MAIN,
|
||||
G_OPTION_ARG_INT, &this->num_iterations, "Run shaper N times (default: 1)", "N"},
|
||||
{nullptr}
|
||||
};
|
||||
|
||||
@@ -140,7 +140,7 @@ struct shape_output_t : output_options_t<>
|
||||
g_string_append_printf (gs, "trace: %s buffer: ", message);
|
||||
format.serialize (buffer, font, serialize_format, serialize_flags, gs);
|
||||
g_string_append_c (gs, '\n');
|
||||
fprintf (out_fp, "%s", gs->str);
|
||||
fprintf (stderr, "%s", gs->str);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include "glib.h"
|
||||
#include "hb-subset.h"
|
||||
#include "helper-subset.hh"
|
||||
|
||||
static
|
||||
hb_face_t* open_font(const char* path)
|
||||
{
|
||||
hb_face_t *face = hb_face_create_from_file_or_fail (path, 0);
|
||||
g_assert (face);
|
||||
return face;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean check_parsing(hb_face_t* face, const char* spec, hb_tag_t axis, float exp_min, float exp_def, float exp_max)
|
||||
{
|
||||
printf(">> testing spec: %s\n", spec);
|
||||
hb_subset_input_t* input = hb_subset_input_create_or_fail();
|
||||
g_assert(input);
|
||||
|
||||
{
|
||||
GError* error;
|
||||
char *spec_copy = g_strdup (spec);
|
||||
gboolean res = parse_instancing_spec(spec_copy, face, input, &error);
|
||||
g_free(spec_copy);
|
||||
if (!res) {
|
||||
hb_subset_input_destroy(input);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
float act_min = 0.0, act_def = 0.0, act_max = 0.0;
|
||||
hb_bool_t res = hb_subset_input_get_axis_range(input, axis, &act_min, &act_max, &act_def);
|
||||
if (!res) {
|
||||
hb_subset_input_destroy(input);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
g_assert_cmpuint(exp_min, ==, act_min);
|
||||
g_assert_cmpuint(exp_def, ==, act_def);
|
||||
g_assert_cmpuint(exp_max, ==, act_max);
|
||||
|
||||
hb_subset_input_destroy(input);
|
||||
return true;
|
||||
}
|
||||
|
||||
static hb_tag_t wght = HB_TAG('w', 'g', 'h', 't');
|
||||
static hb_tag_t xxxx = HB_TAG('x', 'x', 'x', 'x');
|
||||
|
||||
static void
|
||||
test_parse_instancing_spec (void)
|
||||
{
|
||||
hb_face_t* face = open_font("../test/api/fonts/AdobeVFPrototype-Subset.otf");
|
||||
hb_face_t* roboto = open_font("../test/api/fonts/Roboto-Variable.abc.ttf");
|
||||
|
||||
g_assert(check_parsing(face, "wght=300", wght, 300, 300, 300));
|
||||
g_assert(check_parsing(face, "wght=100:200:300", wght, 100, 200, 300));
|
||||
g_assert(check_parsing(face, "wght=:500:", wght, 0, 500, 1000));
|
||||
g_assert(check_parsing(face, "wght=::700", wght, 0, 700, 700));
|
||||
g_assert(check_parsing(face, "wght=200::", wght, 200, 1000, 1000));
|
||||
g_assert(check_parsing(face, "wght=200:300:", wght, 200, 300, 1000));
|
||||
g_assert(check_parsing(face, "wght=:300:500", wght, 0, 300, 500));
|
||||
g_assert(check_parsing(face, "wght=300::700", wght, 300, 700, 700));
|
||||
g_assert(check_parsing(face, "wght=300:700", wght, 300, 700, 700));
|
||||
g_assert(check_parsing(face, "wght=:700", wght, 0, 700, 700));
|
||||
g_assert(check_parsing(face, "wght=200:", wght, 200, 1000, 1000));
|
||||
|
||||
g_assert(check_parsing(face, "wght=200: xxxx=50", wght, 200, 1000, 1000));
|
||||
g_assert(check_parsing(face, "wght=200: xxxx=50", xxxx, 50, 50, 50));
|
||||
g_assert(check_parsing(face, "wght=200:,xxxx=50", wght, 200, 1000, 1000));
|
||||
g_assert(check_parsing(face, "wght=200:,xxxx=50", xxxx, 50, 50, 50));
|
||||
|
||||
g_assert(check_parsing(face, "wght=200,*=drop", wght, 1000, 1000, 1000));
|
||||
g_assert(check_parsing(face, "wght=200,*=drop", xxxx, 0, 0, 0));
|
||||
g_assert(check_parsing(face, "*=drop,wght=200", wght, 200, 200, 200));
|
||||
g_assert(check_parsing(face, "*=drop,wght=200", xxxx, 0, 0, 0));
|
||||
g_assert(check_parsing(face, "*=drop,wght=200,xxxx=50", wght, 200, 200, 200));
|
||||
g_assert(check_parsing(face, "*=drop,wght=200,xxxx=50", xxxx, 50, 50, 50));
|
||||
g_assert(check_parsing(face, "xxxx=50,*=drop,wght=200", wght, 200, 200, 200));
|
||||
g_assert(check_parsing(face, "xxxx=50,*=drop,wght=200", xxxx, 0, 0, 0));
|
||||
g_assert(check_parsing(face, "*=drop", wght, 1000, 1000, 1000));
|
||||
g_assert(check_parsing(face, "*=drop", xxxx, 0, 0, 0));
|
||||
|
||||
g_assert(check_parsing(roboto, "wght=300", wght, 300, 300, 300));
|
||||
g_assert(check_parsing(roboto, "wght=100:200:300", wght, 100, 200, 300));
|
||||
g_assert(check_parsing(roboto, "wght=:500:", wght, 100, 500, 900));
|
||||
g_assert(check_parsing(roboto, "wght=::850", wght, 100, 400, 850));
|
||||
g_assert(check_parsing(roboto, "wght=200::", wght, 200, 400, 900));
|
||||
g_assert(check_parsing(roboto, "wght=200:300:", wght, 200, 300, 900));
|
||||
g_assert(check_parsing(roboto, "wght=:300:500", wght, 100, 300, 500));
|
||||
g_assert(check_parsing(roboto, "wght=300::700", wght, 300, 400, 700));
|
||||
g_assert(check_parsing(roboto, "wght=300:700", wght, 300, 400, 700));
|
||||
g_assert(check_parsing(roboto, "wght=:700", wght, 100, 400, 700));
|
||||
g_assert(check_parsing(roboto, "wght=200:", wght, 200, 400, 900));
|
||||
|
||||
hb_face_destroy(face);
|
||||
hb_face_destroy(roboto);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
test_parse_instancing_spec();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -48,7 +48,7 @@ struct view_cairo_t : view_options_t, output_options_t<>
|
||||
void init (hb_buffer_t *buffer, const font_options_t *font_opts)
|
||||
{
|
||||
lines = g_array_new (false, false, sizeof (helper_cairo_line_t));
|
||||
scale_bits = - (int) font_opts->subpixel_bits;
|
||||
subpixel_bits = font_opts->subpixel_bits;
|
||||
}
|
||||
void new_line () {}
|
||||
void consume_text (hb_buffer_t *buffer,
|
||||
@@ -63,8 +63,7 @@ struct view_cairo_t : view_options_t, output_options_t<>
|
||||
hb_bool_t utf8_clusters)
|
||||
{
|
||||
direction = hb_buffer_get_direction (buffer);
|
||||
helper_cairo_line_t l;
|
||||
helper_cairo_line_from_buffer (&l, buffer, text, text_len, scale_bits, utf8_clusters);
|
||||
helper_cairo_line_t l (text, text_len, buffer, utf8_clusters, subpixel_bits);
|
||||
g_array_append_val (lines, l);
|
||||
}
|
||||
void finish (hb_buffer_t *buffer, const font_options_t *font_opts)
|
||||
@@ -88,7 +87,7 @@ struct view_cairo_t : view_options_t, output_options_t<>
|
||||
|
||||
hb_direction_t direction = HB_DIRECTION_INVALID; // Remove this, make segment_properties accessible
|
||||
GArray *lines = nullptr;
|
||||
int scale_bits = 0;
|
||||
unsigned subpixel_bits = 0;
|
||||
};
|
||||
|
||||
inline void
|
||||
@@ -107,9 +106,9 @@ view_cairo_t::render (const font_options_t *font_opts)
|
||||
{
|
||||
hb_font_extents_t hb_extents;
|
||||
hb_font_get_extents_for_direction (font, direction, &hb_extents);
|
||||
font_extents.ascent = scalbn ((double) hb_extents.ascender, scale_bits);
|
||||
font_extents.descent = -scalbn ((double) hb_extents.descender, scale_bits);
|
||||
font_extents.line_gap = scalbn ((double) hb_extents.line_gap, scale_bits);
|
||||
font_extents.ascent = scalbn ((double) hb_extents.ascender, - (int) subpixel_bits);
|
||||
font_extents.descent = -scalbn ((double) hb_extents.descender, - (int) subpixel_bits);
|
||||
font_extents.line_gap = scalbn ((double) hb_extents.line_gap, - (int) subpixel_bits);
|
||||
have_font_extents = true;
|
||||
}
|
||||
|
||||
@@ -132,7 +131,8 @@ view_cairo_t::render (const font_options_t *font_opts)
|
||||
w = MAX (w, x_sign * x_advance);
|
||||
}
|
||||
|
||||
cairo_scaled_font_t *scaled_font = helper_cairo_create_scaled_font (font_opts);
|
||||
cairo_scaled_font_t *scaled_font = helper_cairo_create_scaled_font (font_opts,
|
||||
this);
|
||||
|
||||
/* See if font needs color. */
|
||||
cairo_content_t content = CAIRO_CONTENT_ALPHA;
|
||||
@@ -168,12 +168,12 @@ view_cairo_t::render (const font_options_t *font_opts)
|
||||
|
||||
cairo_translate (cr, -vert * leading, +horiz * leading);
|
||||
|
||||
if (annotate) {
|
||||
if (show_extents)
|
||||
{
|
||||
cairo_save (cr);
|
||||
|
||||
/* Draw actual glyph origins */
|
||||
cairo_set_source_rgba (cr, 1., 0., 0., .5);
|
||||
cairo_set_line_width (cr, 5);
|
||||
cairo_set_line_width (cr, 10);
|
||||
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
|
||||
for (unsigned i = 0; i < l.num_glyphs; i++) {
|
||||
cairo_move_to (cr, l.glyphs[i].x, l.glyphs[i].y);
|
||||
@@ -181,20 +181,37 @@ view_cairo_t::render (const font_options_t *font_opts)
|
||||
}
|
||||
cairo_stroke (cr);
|
||||
|
||||
cairo_restore (cr);
|
||||
cairo_save (cr);
|
||||
|
||||
cairo_set_source_rgba (cr, 1., 0., 1., .5);
|
||||
cairo_set_line_width (cr, 3);
|
||||
for (unsigned i = 0; i < l.num_glyphs; i++)
|
||||
{
|
||||
hb_glyph_extents_t hb_extents;
|
||||
hb_font_get_glyph_extents (font, l.glyphs[i].index, &hb_extents);
|
||||
double x1 = scalbn ((double) hb_extents.x_bearing, - (int) subpixel_bits);
|
||||
double y1 = -scalbn ((double) hb_extents.y_bearing, - (int) subpixel_bits);
|
||||
double width = scalbn ((double) hb_extents.width, - (int) subpixel_bits);
|
||||
double height = -scalbn ((double) hb_extents.height, - (int) subpixel_bits);
|
||||
|
||||
cairo_rectangle (cr, l.glyphs[i].x + x1, l.glyphs[i].y + y1, width, height);
|
||||
}
|
||||
cairo_stroke (cr);
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
if (0 && cairo_surface_get_type (cairo_get_target (cr)) == CAIRO_SURFACE_TYPE_IMAGE) {
|
||||
/* cairo_show_glyphs() doesn't support subpixel positioning */
|
||||
cairo_glyph_path (cr, l.glyphs, l.num_glyphs);
|
||||
cairo_fill (cr);
|
||||
} else if (l.num_clusters)
|
||||
// https://github.com/harfbuzz/harfbuzz/issues/4378
|
||||
#if CAIRO_VERSION >= 11705
|
||||
if (l.num_clusters)
|
||||
cairo_show_text_glyphs (cr,
|
||||
l.utf8, l.utf8_len,
|
||||
l.glyphs, l.num_glyphs,
|
||||
l.clusters, l.num_clusters,
|
||||
l.cluster_flags);
|
||||
else
|
||||
#endif
|
||||
cairo_show_glyphs (cr, l.glyphs, l.num_glyphs);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,13 +39,15 @@ struct view_options_t
|
||||
{
|
||||
g_free (fore);
|
||||
g_free (back);
|
||||
g_free (custom_palette);
|
||||
}
|
||||
|
||||
void add_options (option_parser_t *parser);
|
||||
|
||||
hb_bool_t annotate = false;
|
||||
char *fore = nullptr;
|
||||
char *back = nullptr;
|
||||
unsigned int palette = 0;
|
||||
char *custom_palette = nullptr;
|
||||
double line_space = 0;
|
||||
bool have_font_extents = false;
|
||||
struct font_extents_t {
|
||||
@@ -54,6 +56,7 @@ struct view_options_t
|
||||
struct margin_t {
|
||||
double t, r, b, l;
|
||||
} margin = {DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN};
|
||||
hb_bool_t show_extents = false;
|
||||
};
|
||||
|
||||
|
||||
@@ -105,12 +108,16 @@ view_options_t::add_options (option_parser_t *parser)
|
||||
{
|
||||
GOptionEntry entries[] =
|
||||
{
|
||||
{"annotate", 0, 0, G_OPTION_ARG_NONE, &this->annotate, "Annotate output rendering", nullptr},
|
||||
{"annotate", 0, G_OPTION_FLAG_HIDDEN,
|
||||
G_OPTION_ARG_NONE, &this->show_extents, "Annotate output rendering", nullptr},
|
||||
{"background", 0, 0, G_OPTION_ARG_STRING, &this->back, "Set background color (default: " DEFAULT_BACK ")", "rrggbb/rrggbbaa"},
|
||||
{"foreground", 0, 0, G_OPTION_ARG_STRING, &this->fore, "Set foreground color (default: " DEFAULT_FORE ")", "rrggbb/rrggbbaa"},
|
||||
{"font-palette", 0, 0, G_OPTION_ARG_INT, &this->palette, "Set font palette (default: 0)", "index"},
|
||||
{"custom-palette", 0, 0, G_OPTION_ARG_STRING, &this->custom_palette, "Custom palette", "comma-separated colors"},
|
||||
{"line-space", 0, 0, G_OPTION_ARG_DOUBLE, &this->line_space, "Set space between lines (default: 0)", "units"},
|
||||
{"font-extents", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_extents, "Set font ascent/descent/line-gap (default: auto)","one to three numbers"},
|
||||
{"margin", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_margin, "Margin around output (default: " G_STRINGIFY(DEFAULT_MARGIN) ")","one to four numbers"},
|
||||
{"show-extents", 0, 0, G_OPTION_ARG_NONE, &this->show_extents, "Draw glyph extents", nullptr},
|
||||
{nullptr}
|
||||
};
|
||||
parser->add_group (entries,
|
||||
|
||||
Reference in New Issue
Block a user