/* * Copyright © 2011 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 FACE_OPTIONS_HH #define FACE_OPTIONS_HH #include "options.hh" #ifdef HAVE_FREETYPE #include #endif #ifdef HAVE_CORETEXT #include #endif struct face_options_t { ~face_options_t () { g_free (face_loader); g_free (font_file); } void set_face (hb_face_t *face_) { face = face_; } void add_options (option_parser_t *parser); void post_parse (GError **error); static struct cache_t { ~cache_t () { g_free (font_path); hb_face_destroy (face); } char *font_path = 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_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) { if (!font_file) { g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "No font file set"); return; } assert (font_file); const char *font_path = font_file; if (0 == strcmp (font_path, "-")) { #if defined(_WIN32) || defined(__CYGWIN__) setmode (fileno (stdin), O_BINARY); font_path = "STDIN"; #else font_path = "/dev/stdin"; #endif } hb_face_t * (*face_load) (const char *file_name, unsigned face_index) = nullptr; if (!face_loader) { 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.face) { g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "%s: Failed loading font face", font_path); return; } } 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", '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, "face", "Font-face options:", "Options for the font face", this); } #endif