2011-08-11 11:54:31 +02:00
/*
2012-05-25 20:30:24 +02:00
* Copyright © 2011 , 2012 Google , Inc .
2011-08-11 11:54:31 +02:00
*
* 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
*/
# include "options.hh"
2011-09-16 22:40:44 +02:00
# ifdef HAVE_FREETYPE
2011-09-13 19:30:39 +02:00
# include <hb-ft.h>
2014-07-05 21:50:18 +02:00
# endif
2015-06-03 21:07:46 +02:00
# include <hb-ot.h>
2011-08-11 11:54:31 +02:00
2019-05-17 00:13:39 +02:00
# define DELIMITERS "<+>{},;&#\\xXuUnNiI\n\t\v\f\r "
2018-09-30 11:47:36 +02:00
static struct supported_font_funcs_t {
2014-07-05 21:50:18 +02:00
char name [ 4 ] ;
void ( * func ) ( hb_font_t * ) ;
} supported_font_funcs [ ] =
{
# ifdef HAVE_FREETYPE
{ " ft " , hb_ft_font_set_funcs } ,
# endif
{ " ot " , hb_ot_font_set_funcs } ,
} ;
2011-08-11 11:54:31 +02:00
2011-09-19 22:41:17 +02:00
void
fail ( hb_bool_t suggest_help , const char * format , . . . )
{
const char * msg ;
va_list vap ;
va_start ( vap , format ) ;
msg = g_strdup_vprintf ( format , vap ) ;
2015-01-02 23:09:23 +01:00
va_end ( vap ) ;
2011-09-19 22:41:17 +02:00
const char * prgname = g_get_prgname ( ) ;
g_printerr ( " %s: %s \n " , prgname , msg ) ;
if ( suggest_help )
g_printerr ( " Try `%s --help' for more information. \n " , prgname ) ;
exit ( 1 ) ;
}
2011-09-13 19:30:39 +02:00
static gchar *
2018-12-17 19:01:01 +01:00
shapers_to_string ( )
2011-09-13 19:30:39 +02:00
{
2017-10-15 12:11:08 +02:00
GString * shapers = g_string_new ( nullptr ) ;
2011-09-13 19:30:39 +02:00
const char * * shaper_list = hb_shape_list_shapers ( ) ;
for ( ; * shaper_list ; shaper_list + + ) {
g_string_append ( shapers , * shaper_list ) ;
g_string_append_c ( shapers , ' , ' ) ;
}
g_string_truncate ( shapers , MAX ( 0 , ( gint ) shapers - > len - 1 ) ) ;
2012-06-06 02:35:40 +02:00
return g_string_free ( shapers , false ) ;
2011-09-13 19:30:39 +02:00
}
static G_GNUC_NORETURN gboolean
show_version ( const char * name G_GNUC_UNUSED ,
const char * arg G_GNUC_UNUSED ,
gpointer data G_GNUC_UNUSED ,
GError * * error G_GNUC_UNUSED )
{
g_printf ( " %s (%s) %s \n " , g_get_prgname ( ) , PACKAGE_NAME , PACKAGE_VERSION ) ;
char * shapers = shapers_to_string ( ) ;
g_printf ( " Available shapers: %s \n " , shapers ) ;
g_free ( shapers ) ;
if ( strcmp ( HB_VERSION_STRING , hb_version_string ( ) ) )
g_printf ( " Linked HarfBuzz library has a different version: %s \n " , hb_version_string ( ) ) ;
exit ( 0 ) ;
}
void
2018-12-17 19:01:01 +01:00
option_parser_t : : add_main_options ( )
2011-09-13 19:30:39 +02:00
{
GOptionEntry entries [ ] =
{
{ " version " , 0 , G_OPTION_FLAG_NO_ARG ,
2017-10-15 12:11:08 +02:00
G_OPTION_ARG_CALLBACK , ( gpointer ) & show_version , " Show version numbers " , nullptr } ,
{ nullptr }
2011-09-13 19:30:39 +02:00
} ;
2017-10-15 12:11:08 +02:00
g_option_context_add_main_entries ( context , entries , nullptr ) ;
2011-09-13 19:30:39 +02:00
}
static gboolean
pre_parse ( GOptionContext * context G_GNUC_UNUSED ,
GOptionGroup * group G_GNUC_UNUSED ,
gpointer data ,
GError * * error )
{
option_group_t * option_group = ( option_group_t * ) data ;
option_group - > pre_parse ( error ) ;
2017-10-15 12:11:08 +02:00
return * error = = nullptr ;
2011-09-13 19:30:39 +02:00
}
static gboolean
post_parse ( GOptionContext * context G_GNUC_UNUSED ,
GOptionGroup * group G_GNUC_UNUSED ,
gpointer data ,
GError * * error )
{
option_group_t * option_group = static_cast < option_group_t * > ( data ) ;
option_group - > post_parse ( error ) ;
2017-10-15 12:11:08 +02:00
return * error = = nullptr ;
2011-09-13 19:30:39 +02:00
}
void
option_parser_t : : add_group ( GOptionEntry * entries ,
const gchar * name ,
const gchar * description ,
const gchar * help_description ,
option_group_t * option_group )
{
GOptionGroup * group = g_option_group_new ( name , description , help_description ,
2017-10-15 12:11:08 +02:00
static_cast < gpointer > ( option_group ) , nullptr ) ;
2011-09-13 19:30:39 +02:00
g_option_group_add_entries ( group , entries ) ;
g_option_group_set_parse_hooks ( group , pre_parse , post_parse ) ;
g_option_context_add_group ( context , group ) ;
}
void
option_parser_t : : parse ( int * argc , char * * * argv )
{
2011-09-19 22:41:17 +02:00
setlocale ( LC_ALL , " " ) ;
2017-10-15 12:11:08 +02:00
GError * parse_error = nullptr ;
2011-09-13 19:30:39 +02:00
if ( ! g_option_context_parse ( context , argc , argv , & parse_error ) )
{
2017-10-15 12:11:08 +02:00
if ( parse_error ! = nullptr ) {
2012-06-06 02:35:40 +02:00
fail ( true , " %s " , parse_error - > message ) ;
2011-09-16 07:16:41 +02:00
//g_error_free (parse_error);
} else
2012-06-06 02:35:40 +02:00
fail ( true , " Option parse error " ) ;
2011-09-13 19:30:39 +02:00
}
}
2011-08-11 11:54:31 +02:00
static gboolean
parse_margin ( const char * name G_GNUC_UNUSED ,
const char * arg ,
2011-09-08 23:08:32 +02:00
gpointer data ,
2011-08-11 11:54:31 +02:00
GError * * error G_GNUC_UNUSED )
{
2011-09-08 23:08:32 +02:00
view_options_t * view_opts = ( view_options_t * ) data ;
2011-08-11 11:54:31 +02:00
view_options_t : : margin_t & m = view_opts - > margin ;
2015-04-10 00:04:42 +02:00
switch ( sscanf ( arg , " %lf%*[ ,]%lf%*[ ,]%lf%*[ ,]%lf " , & m . t , & m . r , & m . b , & m . l ) ) {
2018-09-30 11:49:08 +02:00
case 1 : m . r = m . t ; HB_FALLTHROUGH ;
case 2 : m . b = m . t ; HB_FALLTHROUGH ;
case 3 : m . l = m . r ; HB_FALLTHROUGH ;
2012-06-06 02:35:40 +02:00
case 4 : return true ;
2011-08-11 11:54:31 +02:00
default :
g_set_error ( error , G_OPTION_ERROR , G_OPTION_ERROR_BAD_VALUE ,
" %s argument should be one to four space-separated numbers " ,
name ) ;
2012-06-06 02:35:40 +02:00
return false ;
2011-08-11 11:54:31 +02:00
}
}
static gboolean
parse_shapers ( const char * name G_GNUC_UNUSED ,
const char * arg ,
2011-09-08 23:08:32 +02:00
gpointer data ,
2018-04-19 22:41:37 +02:00
GError * * error )
2011-08-11 11:54:31 +02:00
{
2011-09-08 23:08:32 +02:00
shape_options_t * shape_opts = ( shape_options_t * ) data ;
2018-04-19 22:41:37 +02:00
char * * shapers = g_strsplit ( arg , " , " , 0 ) ;
for ( char * * shaper = shapers ; * shaper ; shaper + + ) {
bool found = false ;
for ( const char * * hb_shaper = hb_shape_list_shapers ( ) ; * hb_shaper ; hb_shaper + + ) {
if ( strcmp ( * shaper , * hb_shaper ) = = 0 ) {
found = true ;
break ;
}
}
if ( ! found ) {
g_set_error ( error , G_OPTION_ERROR , G_OPTION_ERROR_BAD_VALUE ,
" Unknown or unsupported shaper: %s " , * shaper ) ;
g_strfreev ( shapers ) ;
return false ;
}
}
2012-08-07 04:42:47 +02:00
g_strfreev ( shape_opts - > shapers ) ;
2018-04-19 22:41:37 +02:00
shape_opts - > shapers = shapers ;
2012-06-06 02:35:40 +02:00
return true ;
2011-08-11 11:54:31 +02:00
}
2011-10-12 21:03:58 +02:00
static G_GNUC_NORETURN gboolean
list_shapers ( const char * name G_GNUC_UNUSED ,
const char * arg G_GNUC_UNUSED ,
gpointer data G_GNUC_UNUSED ,
GError * * error G_GNUC_UNUSED )
{
for ( const char * * shaper = hb_shape_list_shapers ( ) ; * shaper ; shaper + + )
g_printf ( " %s \n " , * shaper ) ;
exit ( 0 ) ;
}
2011-08-11 11:54:31 +02:00
static gboolean
parse_features ( const char * name G_GNUC_UNUSED ,
const char * arg ,
2011-09-08 23:08:32 +02:00
gpointer data ,
2011-08-11 11:54:31 +02:00
GError * * error G_GNUC_UNUSED )
{
2011-09-08 23:08:32 +02:00
shape_options_t * shape_opts = ( shape_options_t * ) data ;
2011-08-11 11:54:31 +02:00
char * s = ( char * ) arg ;
char * p ;
shape_opts - > num_features = 0 ;
2012-05-25 20:30:24 +02:00
g_free ( shape_opts - > features ) ;
2017-10-15 12:11:08 +02:00
shape_opts - > features = nullptr ;
2011-08-11 11:54:31 +02:00
if ( ! * s )
2012-06-06 02:35:40 +02:00
return true ;
2011-08-11 11:54:31 +02:00
/* count the features first, so we can allocate memory */
p = s ;
do {
shape_opts - > num_features + + ;
p = strchr ( p , ' , ' ) ;
if ( p )
p + + ;
} while ( p ) ;
shape_opts - > features = ( hb_feature_t * ) calloc ( shape_opts - > num_features , sizeof ( * shape_opts - > features ) ) ;
2017-08-10 07:09:01 +02:00
if ( ! shape_opts - > features )
return false ;
2011-08-11 11:54:31 +02:00
/* now do the actual parsing */
p = s ;
shape_opts - > num_features = 0 ;
2012-09-07 04:09:06 +02:00
while ( p & & * p ) {
char * end = strchr ( p , ' , ' ) ;
if ( hb_feature_from_string ( p , end ? end - p : - 1 , & shape_opts - > features [ shape_opts - > num_features ] ) )
2011-08-11 11:54:31 +02:00
shape_opts - > num_features + + ;
2017-10-15 12:11:08 +02:00
p = end ? end + 1 : nullptr ;
2011-08-11 11:54:31 +02:00
}
2012-06-06 02:35:40 +02:00
return true ;
2011-08-11 11:54:31 +02:00
}
2017-01-22 02:51:41 +01:00
static gboolean
parse_variations ( 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 ;
char * s = ( char * ) arg ;
char * p ;
font_opts - > num_variations = 0 ;
g_free ( font_opts - > variations ) ;
2017-10-15 12:11:08 +02:00
font_opts - > variations = nullptr ;
2017-01-22 02:51:41 +01:00
if ( ! * s )
return true ;
/* count the variations first, so we can allocate memory */
p = s ;
do {
font_opts - > num_variations + + ;
p = strchr ( p , ' , ' ) ;
if ( p )
p + + ;
} while ( p ) ;
font_opts - > variations = ( hb_variation_t * ) calloc ( font_opts - > num_variations , sizeof ( * font_opts - > variations ) ) ;
2017-08-10 07:09:01 +02:00
if ( ! font_opts - > variations )
return false ;
2017-01-22 02:51:41 +01:00
/* now do the actual parsing */
p = s ;
font_opts - > num_variations = 0 ;
while ( p & & * p ) {
char * end = strchr ( p , ' , ' ) ;
if ( hb_variation_from_string ( p , end ? end - p : - 1 , & font_opts - > variations [ font_opts - > num_variations ] ) )
font_opts - > num_variations + + ;
2017-10-15 12:11:08 +02:00
p = end ? end + 1 : nullptr ;
2017-01-22 02:51:41 +01:00
}
return true ;
}
2017-09-02 04:09:54 +02:00
static gboolean
parse_text ( const char * name G_GNUC_UNUSED ,
const char * arg ,
gpointer data ,
GError * * error G_GNUC_UNUSED )
{
text_options_t * text_opts = ( text_options_t * ) data ;
if ( text_opts - > text )
{
g_set_error ( error , G_OPTION_ERROR , G_OPTION_ERROR_BAD_VALUE ,
" Either --text or --unicodes can be provided but not both " ) ;
return false ;
}
2018-11-06 16:49:19 +01:00
text_opts - > text_len = - 1 ;
2017-09-02 04:09:54 +02:00
text_opts - > text = g_strdup ( arg ) ;
return true ;
}
static gboolean
parse_unicodes ( const char * name G_GNUC_UNUSED ,
const char * arg ,
gpointer data ,
GError * * error G_GNUC_UNUSED )
{
text_options_t * text_opts = ( text_options_t * ) data ;
if ( text_opts - > text )
{
g_set_error ( error , G_OPTION_ERROR , G_OPTION_ERROR_BAD_VALUE ,
" Either --text or --unicodes can be provided but not both " ) ;
return false ;
}
2017-10-15 12:11:08 +02:00
GString * gs = g_string_new ( nullptr ) ;
2019-06-26 22:23:24 +02:00
if ( 0 = = strcmp ( arg , " * " ) )
2017-09-02 04:09:54 +02:00
{
2019-06-26 22:23:24 +02:00
g_string_append_c ( gs , ' * ' ) ;
}
else
{
char * s = ( char * ) arg ;
char * p ;
while ( s & & * s )
2017-09-02 04:09:54 +02:00
{
2019-06-26 22:23:24 +02:00
while ( * s & & strchr ( DELIMITERS , * s ) )
s + + ;
if ( ! * s )
break ;
errno = 0 ;
hb_codepoint_t u = strtoul ( s , & p , 16 ) ;
if ( errno | | s = = p )
{
g_set_error ( error , G_OPTION_ERROR , G_OPTION_ERROR_BAD_VALUE ,
" Failed parsing Unicode values at: '%s' " , s ) ;
return false ;
}
g_string_append_unichar ( gs , u ) ;
s = p ;
2017-09-02 04:09:54 +02:00
}
}
2018-11-06 16:49:19 +01:00
text_opts - > text_len = gs - > len ;
2017-09-02 04:09:54 +02:00
text_opts - > text = g_string_free ( gs , FALSE ) ;
return true ;
}
2011-08-11 11:54:31 +02:00
void
2011-09-13 19:30:39 +02:00
view_options_t : : add_options ( option_parser_t * parser )
2011-08-11 11:54:31 +02:00
{
GOptionEntry entries [ ] =
{
2017-10-15 12:11:08 +02:00
{ " annotate " , 0 , 0 , G_OPTION_ARG_NONE , & this - > annotate , " Annotate output rendering " , nullptr } ,
2013-12-12 19:21:57 +01:00
{ " 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 " } ,
2011-09-08 23:08:32 +02:00
{ " line-space " , 0 , 0 , G_OPTION_ARG_DOUBLE , & this - > line_space , " Set space between lines (default: 0) " , " units " } ,
2012-12-06 01:18:18 +01:00
{ " margin " , 0 , 0 , G_OPTION_ARG_CALLBACK , ( gpointer ) & parse_margin , " Margin around output (default: " G_STRINGIFY ( DEFAULT_MARGIN ) " ) " , " one to four numbers " } ,
2017-10-15 12:11:08 +02:00
{ nullptr }
2011-09-08 22:00:04 +02:00
} ;
2011-09-13 19:30:39 +02:00
parser - > add_group ( entries ,
" view " ,
" View options: " ,
2017-01-23 04:01:07 +01:00
" Options for output rendering " ,
2011-09-13 19:30:39 +02:00
this ) ;
2011-09-08 22:00:04 +02:00
}
2011-08-11 11:54:31 +02:00
2011-09-08 22:00:04 +02:00
void
2011-09-13 19:30:39 +02:00
shape_options_t : : add_options ( option_parser_t * parser )
2011-09-08 22:00:04 +02:00
{
GOptionEntry entries [ ] =
{
2011-10-12 21:03:58 +02:00
{ " list-shapers " , 0 , G_OPTION_FLAG_NO_ARG ,
2017-10-15 12:11:08 +02:00
G_OPTION_ARG_CALLBACK , ( gpointer ) & list_shapers , " List available shapers and quit " , nullptr } ,
2012-05-25 20:30:24 +02:00
{ " shaper " , 0 , G_OPTION_FLAG_HIDDEN ,
2017-10-15 12:11:08 +02:00
G_OPTION_ARG_CALLBACK , ( gpointer ) & parse_shapers , " Hidden duplicate of --shapers " , nullptr } ,
2014-07-05 21:50:18 +02:00
{ " shapers " , 0 , 0 , G_OPTION_ARG_CALLBACK , ( gpointer ) & parse_shapers , " Set comma-separated list of shapers to try " , " list " } ,
2011-09-08 23:08:32 +02:00
{ " direction " , 0 , 0 , G_OPTION_ARG_STRING , & this - > direction , " Set text direction (default: auto) " , " ltr/rtl/ttb/btt " } ,
{ " language " , 0 , 0 , G_OPTION_ARG_STRING , & this - > language , " Set text language (default: $LANG) " , " langstr " } ,
{ " script " , 0 , 0 , G_OPTION_ARG_STRING , & this - > script , " Set text script (default: auto) " , " ISO-15924 tag " } ,
2017-10-15 12:11:08 +02:00
{ " 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 } ,
{ " preserve-default-ignorables " , 0 , 0 , G_OPTION_ARG_NONE , & this - > preserve_default_ignorables , " Preserve Default-Ignorable characters " , nullptr } ,
2018-01-10 03:35:20 +01:00
{ " remove-default-ignorables " , 0 , 0 , G_OPTION_ARG_NONE , & this - > remove_default_ignorables , " Remove Default-Ignorable characters " , nullptr } ,
2018-10-08 02:46:11 +02:00
{ " invisible-glyph " , 0 , 0 , G_OPTION_ARG_INT , & this - > invisible_glyph , " Glyph value to replace Default-Ignorables with " , nullptr } ,
2017-10-15 12:11:08 +02:00
{ " utf8-clusters " , 0 , 0 , G_OPTION_ARG_NONE , & this - > utf8_clusters , " Use UTF8 byte indices, not char indices " , nullptr } ,
2015-07-22 17:51:12 +02:00
{ " cluster-level " , 0 , 0 , G_OPTION_ARG_INT , & this - > cluster_level , " Cluster merging level (default: 0) " , " 0/1/2 " } ,
2017-10-15 12:11:08 +02:00
{ " normalize-glyphs " , 0 , 0 , G_OPTION_ARG_NONE , & this - > normalize_glyphs , " Rearrange glyph clusters in nominal order " , nullptr } ,
{ " verify " , 0 , 0 , G_OPTION_ARG_NONE , & this - > verify , " Perform sanity checks on shaping results " , nullptr } ,
2018-09-11 14:11:10 +02:00
{ " num-iterations " , ' n ' , 0 , G_OPTION_ARG_INT , & this - > num_iterations , " Run shaper N times (default: 1) " , " N " } ,
2017-10-15 12:11:08 +02:00
{ nullptr }
2011-09-08 22:00:04 +02:00
} ;
2011-09-13 19:30:39 +02:00
parser - > add_group ( entries ,
" shape " ,
" Shape options: " ,
2017-01-23 04:01:07 +01:00
" Options for the shaping process " ,
2011-09-13 19:30:39 +02:00
this ) ;
2012-01-19 04:47:44 +01:00
2012-05-12 15:54:27 +02:00
const gchar * features_help = " Comma-separated list of font features \n "
2012-01-19 04:47:44 +01:00
" \n "
" Features can be enabled or disabled, either globally or limited to \n "
2014-07-25 18:35:03 +02:00
" specific character ranges. The format for specifying feature settings \n "
" follows. All valid CSS font-feature-settings values other than 'normal' \n "
2019-02-19 04:30:40 +01:00
" and the global values are also accepted, though not documented below. \n "
" CSS string escapes are not supported. "
2012-04-17 00:08:20 +02:00
" \n "
" The range indices refer to the positions between Unicode characters, \n "
" unless the --utf8-clusters is provided, in which case range indices \n "
" refer to UTF-8 byte indices. The position before the first character \n "
" is always 0. \n "
2012-01-22 01:07:22 +01:00
" \n "
" The format is Python-esque. Here is how it all works: \n "
2012-01-19 04:47:44 +01:00
" \n "
" Syntax: Value: Start: End: \n "
" \n "
" Setting value: \n "
" \" kern \" 1 0 ∞ # Turn feature on \n "
" \" +kern \" 1 0 ∞ # Turn feature on \n "
" \" -kern \" 0 0 ∞ # Turn feature off \n "
" \" kern=0 \" 0 0 ∞ # Turn feature off \n "
" \" kern=1 \" 1 0 ∞ # Turn feature on \n "
" \" aalt=2 \" 2 0 ∞ # Choose 2nd alternate \n "
" \n "
" Setting index: \n "
" \" kern[] \" 1 0 ∞ # Turn feature on \n "
" \" kern[:] \" 1 0 ∞ # Turn feature on \n "
" \" kern[5:] \" 1 5 ∞ # Turn feature on, partial \n "
" \" kern[:5] \" 1 0 5 # Turn feature on, partial \n "
" \" kern[3:5] \" 1 3 5 # Turn feature on, range \n "
" \" kern[3] \" 1 3 3+1 # Turn feature on, single char \n "
" \n "
" Mixing it all: \n "
" \n "
2012-11-12 19:07:28 +01:00
" \" aalt[3:5]=2 \" 2 3 5 # Turn 2nd alternate on for range " ;
2012-01-19 04:47:44 +01:00
GOptionEntry entries2 [ ] =
{
{ " features " , 0 , 0 , G_OPTION_ARG_CALLBACK , ( gpointer ) & parse_features , features_help , " list " } ,
2017-10-15 12:11:08 +02:00
{ nullptr }
2012-01-19 04:47:44 +01:00
} ;
parser - > add_group ( entries2 ,
" features " ,
" Features options: " ,
2017-01-23 04:01:07 +01:00
" Options for font features used " ,
2012-01-19 04:47:44 +01:00
this ) ;
2011-09-08 22:00:04 +02:00
}
2011-08-11 11:54:31 +02:00
2015-01-20 21:30:45 +01:00
static gboolean
parse_font_size ( 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 ;
if ( 0 = = strcmp ( arg , " upem " ) )
{
font_opts - > font_size_y = font_opts - > font_size_x = FONT_SIZE_UPEM ;
return true ;
}
2015-04-10 00:04:42 +02:00
switch ( sscanf ( arg , " %lf%*[ ,]%lf " , & font_opts - > font_size_x , & font_opts - > font_size_y ) ) {
2018-09-30 11:49:08 +02:00
case 1 : font_opts - > font_size_y = font_opts - > font_size_x ; HB_FALLTHROUGH ;
2015-01-20 21:30:45 +01:00
case 2 : return true ;
default :
g_set_error ( error , G_OPTION_ERROR , G_OPTION_ERROR_BAD_VALUE ,
2017-11-21 04:39:47 +01:00
" %s argument should be one or two space-separated numbers " ,
2015-01-20 21:30:45 +01:00
name ) ;
return false ;
}
}
2018-02-23 00:24:12 +01:00
static gboolean
parse_font_ppem ( 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 , " %d%*[ ,]%d " , & font_opts - > x_ppem , & font_opts - > y_ppem ) ) {
2018-09-30 11:49:08 +02:00
case 1 : font_opts - > y_ppem = font_opts - > x_ppem ; HB_FALLTHROUGH ;
2018-02-23 00:24:12 +01:00
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 ;
}
}
2011-09-08 22:00:04 +02:00
void
2011-09-13 19:30:39 +02:00
font_options_t : : add_options ( option_parser_t * parser )
2011-09-08 22:00:04 +02:00
{
2017-10-15 12:11:08 +02:00
char * text = nullptr ;
2014-07-05 21:50:18 +02:00
{
2018-09-16 19:33:48 +02:00
static_assert ( ( ARRAY_LENGTH_CONST ( supported_font_funcs ) > 0 ) ,
" No supported font-funcs found. " ) ;
2017-10-15 12:11:08 +02:00
GString * s = g_string_new ( nullptr ) ;
2014-07-05 21:50:18 +02:00
g_string_printf ( s , " Set font functions implementation to use (default: %s) \n \n Supported font function implementations are: %s " ,
supported_font_funcs [ 0 ] . name ,
supported_font_funcs [ 0 ] . name ) ;
for ( unsigned int i = 1 ; i < ARRAY_LENGTH ( supported_font_funcs ) ; i + + )
{
g_string_append_c ( s , ' / ' ) ;
g_string_append ( s , supported_font_funcs [ i ] . name ) ;
}
text = g_string_free ( s , FALSE ) ;
parser - > free_later ( text ) ;
}
2015-01-20 21:30:45 +01:00
char * font_size_text ;
if ( default_font_size = = FONT_SIZE_UPEM )
font_size_text = ( char * ) " Font size (default: upem) " ;
else
{
font_size_text = g_strdup_printf ( " Font size (default: %d) " , default_font_size ) ;
parser - > free_later ( font_size_text ) ;
}
2011-09-08 22:00:04 +02:00
GOptionEntry entries [ ] =
{
2018-02-23 00:24:12 +01:00
{ " 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 " } ,
2015-01-20 21:30:45 +01:00
{ " font-size " , 0 , default_font_size ? 0 : G_OPTION_FLAG_HIDDEN ,
2018-02-23 00:24:12 +01:00
G_OPTION_ARG_CALLBACK , ( gpointer ) & parse_font_size , font_size_text , " 1/2 integers or 'upem' " } ,
{ " font-ppem " , 0 , 0 , G_OPTION_ARG_CALLBACK , ( gpointer ) & parse_font_ppem , " Set x,y pixels per EM (default: 0; disabled) " , " 1/2 integers " } ,
{ " font-ptem " , 0 , 0 , G_OPTION_ARG_DOUBLE , & this - > ptem , " Set font point-size (default: 0; disabled) " , " point-size " } ,
{ " font-funcs " , 0 , 0 , G_OPTION_ARG_STRING , & this - > font_funcs , text , " impl " } ,
2018-09-11 14:21:15 +02:00
{ " ft-load-flags " , 0 , 0 , G_OPTION_ARG_INT , & this - > ft_load_flags , " Set FreeType load-flags (default: 2) " , " integer " } ,
2017-10-15 12:11:08 +02:00
{ nullptr }
2011-09-08 22:00:04 +02:00
} ;
2011-09-13 19:30:39 +02:00
parser - > add_group ( entries ,
" font " ,
" Font options: " ,
2017-01-23 04:01:07 +01:00
" Options for the font " ,
2011-09-13 19:30:39 +02:00
this ) ;
2017-01-22 02:51:41 +01:00
const gchar * variations_help = " Comma-separated list of font variations \n "
" \n "
2017-01-23 04:01:07 +01:00
" Variations are set globally. The format for specifying variation settings \n "
" follows. All valid CSS font-variation-settings values other than 'normal' \n "
2017-01-22 02:51:41 +01:00
" and 'inherited' are also accepted, though, not documented below. \n "
" \n "
2017-01-23 04:01:07 +01:00
" The format is a tag, optionally followed by an equals sign, followed by a \n "
" number. For example: \n "
2017-01-22 02:51:41 +01:00
" \n "
2017-01-23 04:01:07 +01:00
" \" wght=500 \" \n "
" \" slnt=-7.5 \" \n " ;
2017-01-22 02:51:41 +01:00
GOptionEntry entries2 [ ] =
{
{ " variations " , 0 , 0 , G_OPTION_ARG_CALLBACK , ( gpointer ) & parse_variations , variations_help , " list " } ,
2017-10-15 12:11:08 +02:00
{ nullptr }
2017-01-22 02:51:41 +01:00
} ;
parser - > add_group ( entries2 ,
" variations " ,
2018-01-17 18:47:50 +01:00
" Variations options: " ,
2017-01-23 04:01:07 +01:00
" Options for font variations used " ,
2017-01-22 02:51:41 +01:00
this ) ;
2011-09-08 22:00:04 +02:00
}
2011-08-11 11:54:31 +02:00
2011-09-08 22:00:04 +02:00
void
2011-09-13 19:30:39 +02:00
text_options_t : : add_options ( option_parser_t * parser )
2011-09-08 22:00:04 +02:00
{
GOptionEntry entries [ ] =
{
2017-09-02 04:09:54 +02:00
{ " text " , 0 , 0 , G_OPTION_ARG_CALLBACK , ( gpointer ) & parse_text , " Set input text " , " string " } ,
2012-11-14 00:15:09 +01:00
{ " text-file " , 0 , 0 , G_OPTION_ARG_STRING , & this - > text_file , " Set input text file-name \n \n If no text is provided, standard input is used for input. \n " , " filename " } ,
2017-09-09 20:21:07 +02:00
{ " unicodes " , ' u ' , 0 , G_OPTION_ARG_CALLBACK , ( gpointer ) & parse_unicodes , " Set input Unicode codepoints " , " list of hex numbers " } ,
2012-11-14 00:12:24 +01:00
{ " text-before " , 0 , 0 , G_OPTION_ARG_STRING , & this - > text_before , " Set text context before each line " , " string " } ,
{ " text-after " , 0 , 0 , G_OPTION_ARG_STRING , & this - > text_after , " Set text context after each line " , " string " } ,
2017-10-15 12:11:08 +02:00
{ nullptr }
2011-08-11 11:54:31 +02:00
} ;
2011-09-13 19:30:39 +02:00
parser - > add_group ( entries ,
" text " ,
" Text options: " ,
2017-01-23 04:01:07 +01:00
" Options for the input text " ,
2011-09-13 19:30:39 +02:00
this ) ;
}
void
output_options_t : : add_options ( option_parser_t * parser )
{
2012-12-21 22:46:53 +01:00
const char * text ;
2017-10-15 12:11:08 +02:00
if ( nullptr = = supported_formats )
2015-02-14 15:29:35 +01:00
text = " Set output serialization format " ;
2012-12-21 22:46:53 +01:00
else
2014-03-19 23:38:02 +01:00
{
char * items = g_strjoinv ( " / " , const_cast < char * * > ( supported_formats ) ) ;
2014-07-05 00:09:29 +02:00
text = g_strdup_printf ( " Set output format \n \n Supported output formats are: %s " , items ) ;
2014-03-19 23:38:02 +01:00
g_free ( items ) ;
2014-07-05 00:09:29 +02:00
parser - > free_later ( ( char * ) text ) ;
2014-03-19 23:38:02 +01:00
}
2012-12-21 22:46:53 +01:00
2011-09-13 19:30:39 +02:00
GOptionEntry entries [ ] =
{
2017-09-09 20:21:07 +02:00
{ " output-file " , ' o ' , 0 , G_OPTION_ARG_STRING , & this - > output_file , " Set output file-name (default: stdout) " , " filename " } ,
{ " output-format " , ' O ' , 0 , G_OPTION_ARG_STRING , & this - > output_format , text , " format " } ,
2017-10-15 12:11:08 +02:00
{ nullptr }
2011-09-13 19:30:39 +02:00
} ;
parser - > add_group ( entries ,
" output " ,
2015-02-14 15:59:44 +01:00
" Output destination & format options: " ,
2017-01-23 04:01:07 +01:00
" Options for the destination & form of the output " ,
2011-09-13 19:30:39 +02:00
this ) ;
}
2011-08-11 11:54:31 +02:00
2011-09-13 19:30:39 +02:00
hb_font_t *
2018-12-17 19:01:01 +01:00
font_options_t : : get_font ( ) const
2011-09-13 19:30:39 +02:00
{
if ( font )
return font ;
/* Create the blob */
2018-04-20 07:59:06 +02:00
if ( ! font_file )
fail ( true , " No font file set " ) ;
2018-06-24 20:39:16 +02:00
const char * font_path = font_file ;
if ( 0 = = strcmp ( font_path , " - " ) )
{
2013-02-12 21:35:32 +01:00
# if defined(_WIN32) || defined(__CYGWIN__)
2018-04-20 07:59:06 +02:00
setmode ( fileno ( stdin ) , O_BINARY ) ;
2018-06-24 20:39:16 +02:00
font_path = " STDIN " ;
# else
font_path = " /dev/stdin " ;
2011-09-16 06:38:19 +02:00
# endif
2011-09-13 19:30:39 +02:00
}
2018-06-24 20:39:16 +02:00
blob = hb_blob_create_from_file ( font_path ) ;
2018-06-18 17:29:33 +02:00
if ( blob = = hb_blob_get_empty ( ) )
2018-10-18 06:08:47 +02:00
fail ( false , " Couldn't read or find %s, or it was empty. " , font_path ) ;
2018-06-17 14:34:55 +02:00
2011-09-13 19:30:39 +02:00
/* Create the face */
hb_face_t * face = hb_face_create ( blob , face_index ) ;
hb_blob_destroy ( blob ) ;
font = hb_font_create ( face ) ;
2015-01-20 21:30:45 +01:00
if ( font_size_x = = FONT_SIZE_UPEM )
font_size_x = hb_face_get_upem ( face ) ;
if ( font_size_y = = FONT_SIZE_UPEM )
font_size_y = hb_face_get_upem ( face ) ;
2018-02-23 00:24:12 +01:00
hb_font_set_ppem ( font , x_ppem , y_ppem ) ;
hb_font_set_ptem ( font , ptem ) ;
2015-01-20 21:30:45 +01:00
int scale_x = ( int ) scalbnf ( font_size_x , subpixel_bits ) ;
int scale_y = ( int ) scalbnf ( font_size_y , subpixel_bits ) ;
hb_font_set_scale ( font , scale_x , scale_y ) ;
2011-09-13 19:30:39 +02:00
hb_face_destroy ( face ) ;
2017-01-22 02:51:41 +01:00
hb_font_set_variations ( font , variations , num_variations ) ;
2017-10-15 12:11:08 +02:00
void ( * set_font_funcs ) ( hb_font_t * ) = nullptr ;
2014-07-05 21:50:18 +02:00
if ( ! font_funcs )
{
set_font_funcs = supported_font_funcs [ 0 ] . func ;
}
else
{
for ( unsigned int i = 0 ; i < ARRAY_LENGTH ( supported_font_funcs ) ; i + + )
2015-11-02 09:55:29 +01:00
if ( 0 = = g_ascii_strcasecmp ( font_funcs , supported_font_funcs [ i ] . name ) )
2014-07-05 21:50:18 +02:00
{
set_font_funcs = supported_font_funcs [ i ] . func ;
break ;
}
if ( ! set_font_funcs )
{
2017-10-15 12:11:08 +02:00
GString * s = g_string_new ( nullptr ) ;
2014-07-05 21:50:18 +02:00
for ( unsigned int i = 0 ; i < ARRAY_LENGTH ( supported_font_funcs ) ; i + + )
{
if ( i )
g_string_append_c ( s , ' / ' ) ;
g_string_append ( s , supported_font_funcs [ i ] . name ) ;
}
char * p = g_string_free ( s , FALSE ) ;
fail ( false , " Unknown font function implementation `%s'; supported values are: %s; default is %s " ,
font_funcs ,
p ,
supported_font_funcs [ 0 ] . name ) ;
//free (p);
}
}
set_font_funcs ( font ) ;
2018-09-11 14:21:15 +02:00
# ifdef HAVE_FREETYPE
hb_ft_font_set_load_flags ( font , ft_load_flags ) ;
# endif
2011-09-13 19:30:39 +02:00
return font ;
}
const char *
text_options_t : : get_line ( unsigned int * len )
{
2011-09-16 08:08:36 +02:00
if ( text ) {
2018-11-06 17:03:34 +01:00
if ( ! line )
{
line = text ;
2018-11-06 16:49:19 +01:00
line_len = text_len ;
2018-11-06 17:03:34 +01:00
}
2015-11-03 20:34:47 +01:00
if ( line_len = = ( unsigned int ) - 1 )
line_len = strlen ( line ) ;
2011-09-16 08:08:36 +02:00
2015-11-03 20:34:47 +01:00
if ( ! line_len ) {
2011-09-16 08:08:36 +02:00
* len = 0 ;
2017-10-15 12:11:08 +02:00
return nullptr ;
2011-09-16 08:08:36 +02:00
}
2015-11-03 20:34:47 +01:00
const char * ret = line ;
const char * p = ( const char * ) memchr ( line , ' \n ' , line_len ) ;
2011-09-16 08:08:36 +02:00
unsigned int ret_len ;
if ( ! p ) {
2015-11-03 20:34:47 +01:00
ret_len = line_len ;
line + = ret_len ;
line_len = 0 ;
2011-09-16 08:08:36 +02:00
} else {
ret_len = p - ret ;
2015-11-03 20:34:47 +01:00
line + = ret_len + 1 ;
line_len - = ret_len + 1 ;
2011-09-16 08:08:36 +02:00
}
* len = ret_len ;
return ret ;
}
if ( ! fp ) {
2011-09-13 19:30:39 +02:00
if ( ! text_file )
2012-06-06 02:35:40 +02:00
fail ( true , " At least one of text or text-file must be set " ) ;
2011-09-13 19:30:39 +02:00
2011-09-16 08:08:36 +02:00
if ( 0 ! = strcmp ( text_file , " - " ) )
fp = fopen ( text_file , " r " ) ;
else
fp = stdin ;
2011-08-11 11:54:31 +02:00
2011-09-16 08:08:36 +02:00
if ( ! fp )
2012-06-06 02:35:40 +02:00
fail ( false , " Failed opening text file `%s': %s " ,
2011-09-16 08:08:36 +02:00
text_file , strerror ( errno ) ) ;
2011-09-13 19:30:39 +02:00
2017-10-15 12:11:08 +02:00
gs = g_string_new ( nullptr ) ;
2011-09-13 19:30:39 +02:00
}
2011-09-16 08:08:36 +02:00
g_string_set_size ( gs , 0 ) ;
char buf [ BUFSIZ ] ;
while ( fgets ( buf , sizeof ( buf ) , fp ) ) {
unsigned int bytes = strlen ( buf ) ;
2012-01-19 18:30:43 +01:00
if ( bytes & & buf [ bytes - 1 ] = = ' \n ' ) {
2011-09-16 08:08:36 +02:00
bytes - - ;
g_string_append_len ( gs , buf , bytes ) ;
break ;
}
g_string_append_len ( gs , buf , bytes ) ;
2011-08-11 11:54:31 +02:00
}
2011-09-16 08:08:36 +02:00
if ( ferror ( fp ) )
2012-06-06 02:35:40 +02:00
fail ( false , " Failed reading text: %s " ,
2011-09-16 08:08:36 +02:00
strerror ( errno ) ) ;
* len = gs - > len ;
2017-10-15 12:11:08 +02:00
return ! * len & & feof ( fp ) ? nullptr : gs - > str ;
2011-08-11 11:54:31 +02:00
}
2011-09-16 07:16:41 +02:00
FILE *
2018-12-17 19:01:01 +01:00
output_options_t : : get_file_handle ( )
2011-09-16 07:16:41 +02:00
{
if ( fp )
return fp ;
if ( output_file )
fp = fopen ( output_file , " wb " ) ;
else {
2013-02-12 21:35:32 +01:00
# if defined(_WIN32) || defined(__CYGWIN__)
2015-12-17 17:28:38 +01:00
setmode ( fileno ( stdout ) , O_BINARY ) ;
2011-09-16 07:16:41 +02:00
# endif
fp = stdout ;
}
if ( ! fp )
2012-06-06 02:35:40 +02:00
fail ( false , " Cannot open output file `%s': %s " ,
2011-09-16 07:16:41 +02:00
g_filename_display_name ( output_file ) , strerror ( errno ) ) ;
return fp ;
}
2011-09-19 22:41:17 +02:00
2012-06-04 14:56:00 +02:00
static gboolean
parse_verbose ( const char * name G_GNUC_UNUSED ,
const char * arg G_GNUC_UNUSED ,
gpointer data G_GNUC_UNUSED ,
GError * * error G_GNUC_UNUSED )
{
format_options_t * format_opts = ( format_options_t * ) data ;
2012-06-06 02:35:40 +02:00
format_opts - > show_text = format_opts - > show_unicode = format_opts - > show_line_num = true ;
return true ;
2012-06-04 14:56:00 +02:00
}
2011-09-19 22:41:17 +02:00
2018-01-10 02:48:04 +01:00
static gboolean
parse_ned ( const char * name G_GNUC_UNUSED ,
const char * arg G_GNUC_UNUSED ,
gpointer data G_GNUC_UNUSED ,
GError * * error G_GNUC_UNUSED )
{
format_options_t * format_opts = ( format_options_t * ) data ;
format_opts - > show_clusters = format_opts - > show_advances = false ;
return true ;
}
2011-09-19 22:41:17 +02:00
void
format_options_t : : add_options ( option_parser_t * parser )
{
GOptionEntry entries [ ] =
{
2017-10-15 12:11:08 +02:00
{ " show-text " , 0 , 0 , G_OPTION_ARG_NONE , & this - > show_text , " Prefix each line of output with its corresponding input text " , nullptr } ,
{ " show-unicode " , 0 , 0 , G_OPTION_ARG_NONE , & this - > show_unicode , " Prefix each line of output with its corresponding input codepoint(s) " , nullptr } ,
{ " show-line-num " , 0 , 0 , G_OPTION_ARG_NONE , & this - > show_line_num , " Prefix each line of output with its corresponding input line number " , nullptr } ,
2017-09-09 20:21:07 +02:00
{ " verbose " , ' v ' , G_OPTION_FLAG_NO_ARG ,
2017-10-15 12:11:08 +02:00
G_OPTION_ARG_CALLBACK , ( gpointer ) & parse_verbose , " Prefix each line of output with all of the above " , nullptr } ,
2015-04-14 08:51:45 +02:00
{ " no-glyph-names " , 0 , G_OPTION_FLAG_REVERSE ,
2017-10-15 12:11:08 +02:00
G_OPTION_ARG_NONE , & this - > show_glyph_names , " Output glyph indices instead of names " , nullptr } ,
2015-04-14 08:51:45 +02:00
{ " no-positions " , 0 , G_OPTION_FLAG_REVERSE ,
2017-10-15 12:11:08 +02:00
G_OPTION_ARG_NONE , & this - > show_positions , " Do not output glyph positions " , nullptr } ,
2018-01-10 02:20:14 +01:00
{ " no-advances " , 0 , G_OPTION_FLAG_REVERSE ,
G_OPTION_ARG_NONE , & this - > show_advances , " Do not output glyph advances " , nullptr } ,
2015-04-14 08:51:45 +02:00
{ " no-clusters " , 0 , G_OPTION_FLAG_REVERSE ,
2017-10-15 12:11:08 +02:00
G_OPTION_ARG_NONE , & this - > show_clusters , " Do not output cluster indices " , nullptr } ,
{ " show-extents " , 0 , 0 , G_OPTION_ARG_NONE , & this - > show_extents , " Output glyph extents " , nullptr } ,
{ " show-flags " , 0 , 0 , G_OPTION_ARG_NONE , & this - > show_flags , " Output glyph flags " , nullptr } ,
2018-01-10 02:48:04 +01:00
{ " ned " , ' v ' , G_OPTION_FLAG_NO_ARG ,
G_OPTION_ARG_CALLBACK , ( gpointer ) & parse_ned , " No Extra Data; Do not output clusters or advances " , nullptr } ,
2017-10-15 12:11:08 +02:00
{ " trace " , ' V ' , 0 , G_OPTION_ARG_NONE , & this - > trace , " Output interim shaping results " , nullptr } ,
{ nullptr }
2011-09-19 22:41:17 +02:00
} ;
parser - > add_group ( entries ,
2015-02-14 15:59:44 +01:00
" output-syntax " ,
" Output syntax: \n "
" text: [<glyph name or index>=<glyph cluster index within input>@<horizontal displacement>,<vertical displacement>+<horizontal advance>,<vertical advance>|...] \n "
" json: [{ \" g \" : <glyph name or index>, \" ax \" : <horizontal advance>, \" ay \" : <vertical advance>, \" dx \" : <horizontal displacement>, \" dy \" : <vertical displacement>, \" cl \" : <glyph cluster index within input>}, ...] \n "
" \n Output syntax options: " ,
2017-01-23 04:01:07 +01:00
" Options for the syntax of the output " ,
2011-09-19 22:41:17 +02:00
this ) ;
}
void
2012-01-19 18:32:20 +01:00
format_options_t : : serialize_unicode ( hb_buffer_t * buffer ,
GString * gs )
{
unsigned int num_glyphs = hb_buffer_get_length ( buffer ) ;
2017-10-15 12:11:08 +02:00
hb_glyph_info_t * info = hb_buffer_get_glyph_infos ( buffer , nullptr ) ;
2012-01-19 18:32:20 +01:00
g_string_append_c ( gs , ' < ' ) ;
for ( unsigned int i = 0 ; i < num_glyphs ; i + + )
{
if ( i )
g_string_append_c ( gs , ' , ' ) ;
g_string_append_printf ( gs , " U+%04X " , info - > codepoint ) ;
info + + ;
}
g_string_append_c ( gs , ' > ' ) ;
}
void
format_options_t : : serialize_glyphs ( hb_buffer_t * buffer ,
hb_font_t * font ,
2012-11-15 21:14:09 +01:00
hb_buffer_serialize_format_t output_format ,
hb_buffer_serialize_flags_t flags ,
2012-01-19 18:32:20 +01:00
GString * gs )
2011-09-19 22:41:17 +02:00
{
2012-01-19 23:51:57 +01:00
g_string_append_c ( gs , ' [ ' ) ;
2012-11-15 21:14:09 +01:00
unsigned int num_glyphs = hb_buffer_get_length ( buffer ) ;
unsigned int start = 0 ;
2017-07-19 04:14:19 +02:00
while ( start < num_glyphs )
{
2012-11-15 21:14:09 +01:00
char buf [ 1024 ] ;
unsigned int consumed ;
start + = hb_buffer_serialize_glyphs ( buffer , start , num_glyphs ,
buf , sizeof ( buf ) , & consumed ,
font , output_format , flags ) ;
if ( ! consumed )
break ;
g_string_append ( gs , buf ) ;
2011-09-19 22:41:17 +02:00
}
2012-01-19 23:51:57 +01:00
g_string_append_c ( gs , ' ] ' ) ;
2011-09-19 22:41:17 +02:00
}
2012-01-19 18:46:18 +01:00
void
format_options_t : : serialize_line_no ( unsigned int line_no ,
GString * gs )
{
if ( show_line_num )
g_string_append_printf ( gs , " %d: " , line_no ) ;
}
void
2012-06-02 18:13:08 +02:00
format_options_t : : serialize_buffer_of_text ( hb_buffer_t * buffer ,
unsigned int line_no ,
const char * text ,
unsigned int text_len ,
hb_font_t * font ,
GString * gs )
2012-01-19 18:46:18 +01:00
{
2017-07-19 04:14:19 +02:00
if ( show_text )
{
2012-01-19 18:46:18 +01:00
serialize_line_no ( line_no , gs ) ;
2012-01-20 23:18:59 +01:00
g_string_append_c ( gs , ' ( ' ) ;
2012-01-19 18:46:18 +01:00
g_string_append_len ( gs , text , text_len ) ;
2012-01-20 23:18:59 +01:00
g_string_append_c ( gs , ' ) ' ) ;
2012-01-19 18:46:18 +01:00
g_string_append_c ( gs , ' \n ' ) ;
}
2017-07-19 04:14:19 +02:00
if ( show_unicode )
{
2012-01-19 18:46:18 +01:00
serialize_line_no ( line_no , gs ) ;
2012-06-02 18:21:19 +02:00
serialize_unicode ( buffer , gs ) ;
2012-01-19 18:46:18 +01:00
g_string_append_c ( gs , ' \n ' ) ;
}
2012-06-02 18:13:08 +02:00
}
void
format_options_t : : serialize_message ( unsigned int line_no ,
2017-08-16 02:30:18 +02:00
const char * type ,
2012-06-02 18:13:08 +02:00
const char * msg ,
GString * gs )
{
serialize_line_no ( line_no , gs ) ;
2017-08-16 02:30:18 +02:00
g_string_append_printf ( gs , " %s: %s " , type , msg ) ;
2012-06-02 18:13:08 +02:00
g_string_append_c ( gs , ' \n ' ) ;
}
void
format_options_t : : serialize_buffer_of_glyphs ( hb_buffer_t * buffer ,
unsigned int line_no ,
const char * text ,
unsigned int text_len ,
hb_font_t * font ,
2012-11-15 21:14:09 +01:00
hb_buffer_serialize_format_t output_format ,
hb_buffer_serialize_flags_t format_flags ,
2012-06-02 18:13:08 +02:00
GString * gs )
{
2012-01-19 18:46:18 +01:00
serialize_line_no ( line_no , gs ) ;
2012-11-15 21:14:09 +01:00
serialize_glyphs ( buffer , font , output_format , format_flags , gs ) ;
2012-01-19 18:46:18 +01:00
g_string_append_c ( gs , ' \n ' ) ;
}