1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright © 2011 Google, Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * This is part of HarfBuzz, a text shaping library. 5cb93a386Sopenharmony_ci * 6cb93a386Sopenharmony_ci * Permission is hereby granted, without written agreement and without 7cb93a386Sopenharmony_ci * license or royalty fees, to use, copy, modify, and distribute this 8cb93a386Sopenharmony_ci * software and its documentation for any purpose, provided that the 9cb93a386Sopenharmony_ci * above copyright notice and the following two paragraphs appear in 10cb93a386Sopenharmony_ci * all copies of this software. 11cb93a386Sopenharmony_ci * 12cb93a386Sopenharmony_ci * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13cb93a386Sopenharmony_ci * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14cb93a386Sopenharmony_ci * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15cb93a386Sopenharmony_ci * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16cb93a386Sopenharmony_ci * DAMAGE. 17cb93a386Sopenharmony_ci * 18cb93a386Sopenharmony_ci * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19cb93a386Sopenharmony_ci * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20cb93a386Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21cb93a386Sopenharmony_ci * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22cb93a386Sopenharmony_ci * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23cb93a386Sopenharmony_ci * 24cb93a386Sopenharmony_ci * Google Author(s): Behdad Esfahbod 25cb93a386Sopenharmony_ci */ 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_ci#ifndef FONT_OPTIONS_HH 28cb93a386Sopenharmony_ci#define FONT_OPTIONS_HH 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ci#include "face-options.hh" 31cb93a386Sopenharmony_ci 32cb93a386Sopenharmony_ci#ifdef HAVE_FREETYPE 33cb93a386Sopenharmony_ci#include <hb-ft.h> 34cb93a386Sopenharmony_ci#endif 35cb93a386Sopenharmony_ci#include <hb-ot.h> 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_ci#define FONT_SIZE_UPEM 0x7FFFFFFF 38cb93a386Sopenharmony_ci#define FONT_SIZE_NONE 0 39cb93a386Sopenharmony_ci 40cb93a386Sopenharmony_ciextern const unsigned DEFAULT_FONT_SIZE; 41cb93a386Sopenharmony_ciextern const unsigned SUBPIXEL_BITS; 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_cistruct font_options_t : face_options_t 44cb93a386Sopenharmony_ci{ 45cb93a386Sopenharmony_ci ~font_options_t () 46cb93a386Sopenharmony_ci { 47cb93a386Sopenharmony_ci free (variations); 48cb93a386Sopenharmony_ci g_free (font_funcs); 49cb93a386Sopenharmony_ci hb_font_destroy (font); 50cb93a386Sopenharmony_ci } 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci void add_options (option_parser_t *parser); 53cb93a386Sopenharmony_ci 54cb93a386Sopenharmony_ci void post_parse (GError **error); 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ci hb_variation_t *variations = nullptr; 57cb93a386Sopenharmony_ci unsigned int num_variations = 0; 58cb93a386Sopenharmony_ci int x_ppem = 0; 59cb93a386Sopenharmony_ci int y_ppem = 0; 60cb93a386Sopenharmony_ci double ptem = 0.; 61cb93a386Sopenharmony_ci unsigned int subpixel_bits = SUBPIXEL_BITS; 62cb93a386Sopenharmony_ci mutable double font_size_x = DEFAULT_FONT_SIZE; 63cb93a386Sopenharmony_ci mutable double font_size_y = DEFAULT_FONT_SIZE; 64cb93a386Sopenharmony_ci char *font_funcs = nullptr; 65cb93a386Sopenharmony_ci int ft_load_flags = 2; 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_ci hb_font_t *font = nullptr; 68cb93a386Sopenharmony_ci}; 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_cistatic struct supported_font_funcs_t { 72cb93a386Sopenharmony_ci char name[4]; 73cb93a386Sopenharmony_ci void (*func) (hb_font_t *); 74cb93a386Sopenharmony_ci} supported_font_funcs[] = 75cb93a386Sopenharmony_ci{ 76cb93a386Sopenharmony_ci#ifdef HAVE_FREETYPE 77cb93a386Sopenharmony_ci {"ft", hb_ft_font_set_funcs}, 78cb93a386Sopenharmony_ci#endif 79cb93a386Sopenharmony_ci {"ot", hb_ot_font_set_funcs}, 80cb93a386Sopenharmony_ci}; 81cb93a386Sopenharmony_ci 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_civoid 84cb93a386Sopenharmony_cifont_options_t::post_parse (GError **error) 85cb93a386Sopenharmony_ci{ 86cb93a386Sopenharmony_ci assert (!font); 87cb93a386Sopenharmony_ci font = hb_font_create (face); 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_ci if (font_size_x == FONT_SIZE_UPEM) 90cb93a386Sopenharmony_ci font_size_x = hb_face_get_upem (face); 91cb93a386Sopenharmony_ci if (font_size_y == FONT_SIZE_UPEM) 92cb93a386Sopenharmony_ci font_size_y = hb_face_get_upem (face); 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ci hb_font_set_ppem (font, x_ppem, y_ppem); 95cb93a386Sopenharmony_ci hb_font_set_ptem (font, ptem); 96cb93a386Sopenharmony_ci 97cb93a386Sopenharmony_ci int scale_x = (int) scalbnf (font_size_x, subpixel_bits); 98cb93a386Sopenharmony_ci int scale_y = (int) scalbnf (font_size_y, subpixel_bits); 99cb93a386Sopenharmony_ci hb_font_set_scale (font, scale_x, scale_y); 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ci hb_font_set_variations (font, variations, num_variations); 102cb93a386Sopenharmony_ci 103cb93a386Sopenharmony_ci void (*set_font_funcs) (hb_font_t *) = nullptr; 104cb93a386Sopenharmony_ci if (!font_funcs) 105cb93a386Sopenharmony_ci { 106cb93a386Sopenharmony_ci set_font_funcs = supported_font_funcs[0].func; 107cb93a386Sopenharmony_ci } 108cb93a386Sopenharmony_ci else 109cb93a386Sopenharmony_ci { 110cb93a386Sopenharmony_ci for (unsigned int i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++) 111cb93a386Sopenharmony_ci if (0 == g_ascii_strcasecmp (font_funcs, supported_font_funcs[i].name)) 112cb93a386Sopenharmony_ci { 113cb93a386Sopenharmony_ci set_font_funcs = supported_font_funcs[i].func; 114cb93a386Sopenharmony_ci break; 115cb93a386Sopenharmony_ci } 116cb93a386Sopenharmony_ci if (!set_font_funcs) 117cb93a386Sopenharmony_ci { 118cb93a386Sopenharmony_ci GString *s = g_string_new (nullptr); 119cb93a386Sopenharmony_ci for (unsigned int i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++) 120cb93a386Sopenharmony_ci { 121cb93a386Sopenharmony_ci if (i) 122cb93a386Sopenharmony_ci g_string_append_c (s, '/'); 123cb93a386Sopenharmony_ci g_string_append (s, supported_font_funcs[i].name); 124cb93a386Sopenharmony_ci } 125cb93a386Sopenharmony_ci g_string_append_c (s, '\n'); 126cb93a386Sopenharmony_ci char *p = g_string_free (s, FALSE); 127cb93a386Sopenharmony_ci g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, 128cb93a386Sopenharmony_ci "Unknown font function implementation `%s'; supported values are: %s; default is %s", 129cb93a386Sopenharmony_ci font_funcs, 130cb93a386Sopenharmony_ci p, 131cb93a386Sopenharmony_ci supported_font_funcs[0].name); 132cb93a386Sopenharmony_ci free (p); 133cb93a386Sopenharmony_ci return; 134cb93a386Sopenharmony_ci } 135cb93a386Sopenharmony_ci } 136cb93a386Sopenharmony_ci set_font_funcs (font); 137cb93a386Sopenharmony_ci#ifdef HAVE_FREETYPE 138cb93a386Sopenharmony_ci hb_ft_font_set_load_flags (font, ft_load_flags); 139cb93a386Sopenharmony_ci#endif 140cb93a386Sopenharmony_ci} 141cb93a386Sopenharmony_ci 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_cistatic gboolean 144cb93a386Sopenharmony_ciparse_variations (const char *name G_GNUC_UNUSED, 145cb93a386Sopenharmony_ci const char *arg, 146cb93a386Sopenharmony_ci gpointer data, 147cb93a386Sopenharmony_ci GError **error G_GNUC_UNUSED) 148cb93a386Sopenharmony_ci{ 149cb93a386Sopenharmony_ci font_options_t *font_opts = (font_options_t *) data; 150cb93a386Sopenharmony_ci char *s = (char *) arg; 151cb93a386Sopenharmony_ci char *p; 152cb93a386Sopenharmony_ci 153cb93a386Sopenharmony_ci font_opts->num_variations = 0; 154cb93a386Sopenharmony_ci g_free (font_opts->variations); 155cb93a386Sopenharmony_ci font_opts->variations = nullptr; 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_ci if (!*s) 158cb93a386Sopenharmony_ci return true; 159cb93a386Sopenharmony_ci 160cb93a386Sopenharmony_ci /* count the variations first, so we can allocate memory */ 161cb93a386Sopenharmony_ci p = s; 162cb93a386Sopenharmony_ci do { 163cb93a386Sopenharmony_ci font_opts->num_variations++; 164cb93a386Sopenharmony_ci p = strchr (p, ','); 165cb93a386Sopenharmony_ci if (p) 166cb93a386Sopenharmony_ci p++; 167cb93a386Sopenharmony_ci } while (p); 168cb93a386Sopenharmony_ci 169cb93a386Sopenharmony_ci font_opts->variations = (hb_variation_t *) calloc (font_opts->num_variations, sizeof (*font_opts->variations)); 170cb93a386Sopenharmony_ci if (!font_opts->variations) 171cb93a386Sopenharmony_ci return false; 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_ci /* now do the actual parsing */ 174cb93a386Sopenharmony_ci p = s; 175cb93a386Sopenharmony_ci font_opts->num_variations = 0; 176cb93a386Sopenharmony_ci while (p && *p) { 177cb93a386Sopenharmony_ci char *end = strchr (p, ','); 178cb93a386Sopenharmony_ci if (hb_variation_from_string (p, end ? end - p : -1, &font_opts->variations[font_opts->num_variations])) 179cb93a386Sopenharmony_ci font_opts->num_variations++; 180cb93a386Sopenharmony_ci p = end ? end + 1 : nullptr; 181cb93a386Sopenharmony_ci } 182cb93a386Sopenharmony_ci 183cb93a386Sopenharmony_ci return true; 184cb93a386Sopenharmony_ci} 185cb93a386Sopenharmony_ci 186cb93a386Sopenharmony_cistatic gboolean 187cb93a386Sopenharmony_ciparse_font_size (const char *name G_GNUC_UNUSED, 188cb93a386Sopenharmony_ci const char *arg, 189cb93a386Sopenharmony_ci gpointer data, 190cb93a386Sopenharmony_ci GError **error G_GNUC_UNUSED) 191cb93a386Sopenharmony_ci{ 192cb93a386Sopenharmony_ci font_options_t *font_opts = (font_options_t *) data; 193cb93a386Sopenharmony_ci if (0 == strcmp (arg, "upem")) 194cb93a386Sopenharmony_ci { 195cb93a386Sopenharmony_ci font_opts->font_size_y = font_opts->font_size_x = FONT_SIZE_UPEM; 196cb93a386Sopenharmony_ci return true; 197cb93a386Sopenharmony_ci } 198cb93a386Sopenharmony_ci switch (sscanf (arg, "%lf%*[ ,]%lf", &font_opts->font_size_x, &font_opts->font_size_y)) { 199cb93a386Sopenharmony_ci case 1: font_opts->font_size_y = font_opts->font_size_x; HB_FALLTHROUGH; 200cb93a386Sopenharmony_ci case 2: return true; 201cb93a386Sopenharmony_ci default: 202cb93a386Sopenharmony_ci g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, 203cb93a386Sopenharmony_ci "%s argument should be one or two space-separated numbers", 204cb93a386Sopenharmony_ci name); 205cb93a386Sopenharmony_ci return false; 206cb93a386Sopenharmony_ci } 207cb93a386Sopenharmony_ci} 208cb93a386Sopenharmony_ci 209cb93a386Sopenharmony_cistatic gboolean 210cb93a386Sopenharmony_ciparse_font_ppem (const char *name G_GNUC_UNUSED, 211cb93a386Sopenharmony_ci const char *arg, 212cb93a386Sopenharmony_ci gpointer data, 213cb93a386Sopenharmony_ci GError **error G_GNUC_UNUSED) 214cb93a386Sopenharmony_ci{ 215cb93a386Sopenharmony_ci font_options_t *font_opts = (font_options_t *) data; 216cb93a386Sopenharmony_ci switch (sscanf (arg, "%d%*[ ,]%d", &font_opts->x_ppem, &font_opts->y_ppem)) { 217cb93a386Sopenharmony_ci case 1: font_opts->y_ppem = font_opts->x_ppem; HB_FALLTHROUGH; 218cb93a386Sopenharmony_ci case 2: return true; 219cb93a386Sopenharmony_ci default: 220cb93a386Sopenharmony_ci g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, 221cb93a386Sopenharmony_ci "%s argument should be one or two space-separated numbers", 222cb93a386Sopenharmony_ci name); 223cb93a386Sopenharmony_ci return false; 224cb93a386Sopenharmony_ci } 225cb93a386Sopenharmony_ci} 226cb93a386Sopenharmony_ci 227cb93a386Sopenharmony_civoid 228cb93a386Sopenharmony_cifont_options_t::add_options (option_parser_t *parser) 229cb93a386Sopenharmony_ci{ 230cb93a386Sopenharmony_ci face_options_t::add_options (parser); 231cb93a386Sopenharmony_ci 232cb93a386Sopenharmony_ci char *text = nullptr; 233cb93a386Sopenharmony_ci 234cb93a386Sopenharmony_ci { 235cb93a386Sopenharmony_ci static_assert ((ARRAY_LENGTH_CONST (supported_font_funcs) > 0), 236cb93a386Sopenharmony_ci "No supported font-funcs found."); 237cb93a386Sopenharmony_ci GString *s = g_string_new (nullptr); 238cb93a386Sopenharmony_ci g_string_printf (s, "Set font functions implementation to use (default: %s)\n\n Supported font function implementations are: %s", 239cb93a386Sopenharmony_ci supported_font_funcs[0].name, 240cb93a386Sopenharmony_ci supported_font_funcs[0].name); 241cb93a386Sopenharmony_ci for (unsigned int i = 1; i < ARRAY_LENGTH (supported_font_funcs); i++) 242cb93a386Sopenharmony_ci { 243cb93a386Sopenharmony_ci g_string_append_c (s, '/'); 244cb93a386Sopenharmony_ci g_string_append (s, supported_font_funcs[i].name); 245cb93a386Sopenharmony_ci } 246cb93a386Sopenharmony_ci text = g_string_free (s, FALSE); 247cb93a386Sopenharmony_ci parser->free_later (text); 248cb93a386Sopenharmony_ci } 249cb93a386Sopenharmony_ci 250cb93a386Sopenharmony_ci char *font_size_text; 251cb93a386Sopenharmony_ci if (DEFAULT_FONT_SIZE == FONT_SIZE_UPEM) 252cb93a386Sopenharmony_ci font_size_text = (char *) "Font size (default: upem)"; 253cb93a386Sopenharmony_ci else 254cb93a386Sopenharmony_ci { 255cb93a386Sopenharmony_ci font_size_text = g_strdup_printf ("Font size (default: %d)", DEFAULT_FONT_SIZE); 256cb93a386Sopenharmony_ci parser->free_later (font_size_text); 257cb93a386Sopenharmony_ci } 258cb93a386Sopenharmony_ci 259cb93a386Sopenharmony_ci int font_size_flags = DEFAULT_FONT_SIZE == FONT_SIZE_NONE ? G_OPTION_FLAG_HIDDEN : 0; 260cb93a386Sopenharmony_ci GOptionEntry entries[] = 261cb93a386Sopenharmony_ci { 262cb93a386Sopenharmony_ci {"font-size", 0, font_size_flags, 263cb93a386Sopenharmony_ci G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_size, font_size_text, "1/2 integers or 'upem'"}, 264cb93a386Sopenharmony_ci {"font-ppem", 0, font_size_flags, 265cb93a386Sopenharmony_ci G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_ppem, "Set x,y pixels per EM (default: 0; disabled)", "1/2 integers"}, 266cb93a386Sopenharmony_ci {"font-ptem", 0, 0, 267cb93a386Sopenharmony_ci G_OPTION_ARG_DOUBLE, &this->ptem, "Set font point-size (default: 0; disabled)", "point-size"}, 268cb93a386Sopenharmony_ci {"font-funcs", 0, 0, G_OPTION_ARG_STRING, &this->font_funcs, text, "impl"}, 269cb93a386Sopenharmony_ci {"ft-load-flags", 0, 0, G_OPTION_ARG_INT, &this->ft_load_flags, "Set FreeType load-flags (default: 2)", "integer"}, 270cb93a386Sopenharmony_ci {nullptr} 271cb93a386Sopenharmony_ci }; 272cb93a386Sopenharmony_ci parser->add_group (entries, 273cb93a386Sopenharmony_ci "font", 274cb93a386Sopenharmony_ci "Font-instance options:", 275cb93a386Sopenharmony_ci "Options for the font instance", 276cb93a386Sopenharmony_ci this, 277cb93a386Sopenharmony_ci false /* We add below. */); 278cb93a386Sopenharmony_ci 279cb93a386Sopenharmony_ci const gchar *variations_help = "Comma-separated list of font variations\n" 280cb93a386Sopenharmony_ci "\n" 281cb93a386Sopenharmony_ci " Variations are set globally. The format for specifying variation settings\n" 282cb93a386Sopenharmony_ci " follows. All valid CSS font-variation-settings values other than 'normal'\n" 283cb93a386Sopenharmony_ci " and 'inherited' are also accepted, though, not documented below.\n" 284cb93a386Sopenharmony_ci "\n" 285cb93a386Sopenharmony_ci " The format is a tag, optionally followed by an equals sign, followed by a\n" 286cb93a386Sopenharmony_ci " number. For example:\n" 287cb93a386Sopenharmony_ci "\n" 288cb93a386Sopenharmony_ci " \"wght=500\"\n" 289cb93a386Sopenharmony_ci " \"slnt=-7.5\""; 290cb93a386Sopenharmony_ci 291cb93a386Sopenharmony_ci GOptionEntry entries2[] = 292cb93a386Sopenharmony_ci { 293cb93a386Sopenharmony_ci {"variations", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_variations, variations_help, "list"}, 294cb93a386Sopenharmony_ci {nullptr} 295cb93a386Sopenharmony_ci }; 296cb93a386Sopenharmony_ci parser->add_group (entries2, 297cb93a386Sopenharmony_ci "variations", 298cb93a386Sopenharmony_ci "Variations options:", 299cb93a386Sopenharmony_ci "Options for font variations used", 300cb93a386Sopenharmony_ci this); 301cb93a386Sopenharmony_ci} 302cb93a386Sopenharmony_ci 303cb93a386Sopenharmony_ci#endif 304