xref: /aosp_15_r20/external/harfbuzz_ng/util/face-options.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1 /*
2  * Copyright © 2011  Google, Inc.
3  *
4  *  This is part of HarfBuzz, a text shaping library.
5  *
6  * Permission is hereby granted, without written agreement and without
7  * license or royalty fees, to use, copy, modify, and distribute this
8  * software and its documentation for any purpose, provided that the
9  * above copyright notice and the following two paragraphs appear in
10  * all copies of this software.
11  *
12  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16  * DAMAGE.
17  *
18  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23  *
24  * Google Author(s): Behdad Esfahbod
25  */
26 
27 #ifndef FACE_OPTIONS_HH
28 #define FACE_OPTIONS_HH
29 
30 #include "options.hh"
31 
32 #ifdef HAVE_FREETYPE
33 #include <hb-ft.h>
34 #endif
35 #ifdef HAVE_CORETEXT
36 #include <hb-coretext.h>
37 #endif
38 
39 struct face_options_t
40 {
~face_options_tface_options_t41   ~face_options_t ()
42   {
43     g_free (face_loader);
44     g_free (font_file);
45   }
46 
set_faceface_options_t47   void set_face (hb_face_t *face_)
48   { face = face_; }
49 
50   void add_options (option_parser_t *parser);
51 
52   void post_parse (GError **error);
53 
54   static struct cache_t
55   {
~cache_tface_options_t::cache_t56     ~cache_t ()
57     {
58       g_free (font_path);
59       hb_face_destroy (face);
60     }
61 
62     char *font_path = nullptr;
63     unsigned face_index = (unsigned) -1;
64     hb_face_t *face = nullptr;
65   } cache;
66 
67   char *font_file = nullptr;
68   unsigned face_index = 0;
69   char *face_loader = nullptr;
70 
71   hb_face_t *face = nullptr;
72 };
73 
74 
75 face_options_t::cache_t face_options_t::cache {};
76 
77 static struct supported_face_loaders_t {
78 	char name[9];
79 	hb_face_t * (*func) (const char *font_file, unsigned face_index);
80 } supported_face_loaders[] =
81 {
82   {"ot",	hb_face_create_from_file_or_fail},
83 #ifdef HAVE_FREETYPE
84   {"ft",	hb_ft_face_create_from_file_or_fail},
85 #endif
86 #ifdef HAVE_CORETEXT
87   {"coretext",	hb_coretext_face_create_from_file_or_fail},
88 #endif
89 };
90 
91 void
post_parse(GError ** error)92 face_options_t::post_parse (GError **error)
93 {
94   if (!font_file)
95   {
96     g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
97 		 "No font file set");
98     return;
99   }
100 
101   assert (font_file);
102 
103   const char *font_path = font_file;
104 
105   if (0 == strcmp (font_path, "-"))
106   {
107 #if defined(_WIN32) || defined(__CYGWIN__)
108     setmode (fileno (stdin), O_BINARY);
109     font_path = "STDIN";
110 #else
111     font_path = "/dev/stdin";
112 #endif
113   }
114 
115   hb_face_t * (*face_load) (const char *file_name, unsigned face_index) = nullptr;
116   if (!face_loader)
117   {
118     face_load = supported_face_loaders[0].func;
119   }
120   else
121   {
122     for (unsigned int i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
123       if (0 == g_ascii_strcasecmp (face_loader, supported_face_loaders[i].name))
124       {
125 	face_load = supported_face_loaders[i].func;
126 	break;
127       }
128     if (!face_load)
129     {
130       GString *s = g_string_new (nullptr);
131       for (unsigned int i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
132       {
133 	if (i)
134 	  g_string_append_c (s, '/');
135 	g_string_append (s, supported_face_loaders[i].name);
136       }
137       g_string_append_c (s, '\n');
138       char *p = g_string_free (s, FALSE);
139       g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
140 		   "Unknown face loader `%s'; supported values are: %s; default is %s",
141 		   face_loader,
142 		   p,
143 		   supported_face_loaders[0].name);
144       free (p);
145       return;
146     }
147   }
148 
149   if (!cache.font_path ||
150       0 != strcmp (cache.font_path, font_path) ||
151       cache.face_index != face_index)
152   {
153     hb_face_destroy (cache.face);
154     cache.face = face_load (font_path, face_index);
155     cache.face_index = face_index;
156 
157     free ((char *) cache.font_path);
158     cache.font_path = g_strdup (font_path);
159 
160     if (!cache.face)
161     {
162       g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
163 		   "%s: Failed loading font face", font_path);
164       return;
165     }
166   }
167 
168   face = cache.face;
169 }
170 
171 void
add_options(option_parser_t * parser)172 face_options_t::add_options (option_parser_t *parser)
173 {
174   char *face_loaders_text = nullptr;
175   {
176     static_assert ((ARRAY_LENGTH_CONST (supported_face_loaders) > 0),
177 		   "No supported face-loaders found.");
178     GString *s = g_string_new (nullptr);
179     g_string_printf (s, "Set face loader to use (default: %s)\n\n    Supported face loaders are: %s",
180 		     supported_face_loaders[0].name,
181 		     supported_face_loaders[0].name);
182     for (unsigned int i = 1; i < ARRAY_LENGTH (supported_face_loaders); i++)
183     {
184       g_string_append_c (s, '/');
185       g_string_append (s, supported_face_loaders[i].name);
186     }
187     face_loaders_text = g_string_free (s, FALSE);
188     parser->free_later (face_loaders_text);
189   }
190 
191   GOptionEntry entries[] =
192   {
193     {"font-file",	0, 0, G_OPTION_ARG_STRING,	&this->font_file,		"Set font file-name",				"filename"},
194     {"face-index",	'y', 0, G_OPTION_ARG_INT,	&this->face_index,		"Set face index (default: 0)",			"index"},
195     {"face-loader",	0, 0, G_OPTION_ARG_STRING,	&this->face_loader,		face_loaders_text,				"loader"},
196     {nullptr}
197   };
198   parser->add_group (entries,
199 		     "face",
200 		     "Font-face options:",
201 		     "Options for the font face",
202 		     this);
203 }
204 
205 #endif
206