• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 FONT_OPTIONS_HH
28 #define FONT_OPTIONS_HH
29 
30 #include "face-options.hh"
31 
32 #ifdef HAVE_FREETYPE
33 #include <hb-ft.h>
34 #endif
35 #include <hb-ot.h>
36 
37 #define FONT_SIZE_UPEM 0x7FFFFFFF
38 #define FONT_SIZE_NONE 0
39 
40 extern const unsigned DEFAULT_FONT_SIZE;
41 extern const unsigned SUBPIXEL_BITS;
42 
43 struct font_options_t : face_options_t
44 {
~font_options_tfont_options_t45   ~font_options_t ()
46   {
47 #ifndef HB_NO_VAR
48     free (variations);
49 #endif
50     g_free (font_funcs);
51     hb_font_destroy (font);
52   }
53 
54   void add_options (option_parser_t *parser);
55 
56   void post_parse (GError **error);
57 
58   hb_bool_t sub_font = false;
59 #ifndef HB_NO_VAR
60   hb_variation_t *variations = nullptr;
61   unsigned int num_variations = 0;
62 #endif
63   int x_ppem = 0;
64   int y_ppem = 0;
65   double ptem = 0.;
66   double slant = 0.;
67   unsigned int subpixel_bits = SUBPIXEL_BITS;
68   mutable double font_size_x = DEFAULT_FONT_SIZE;
69   mutable double font_size_y = DEFAULT_FONT_SIZE;
70   char *font_funcs = nullptr;
71   int ft_load_flags = 2;
72 
73   hb_font_t *font = nullptr;
74 };
75 
76 
77 static struct supported_font_funcs_t {
78 	char name[4];
79 	void (*func) (hb_font_t *);
80 } supported_font_funcs[] =
81 {
82   {"ot",	hb_ot_font_set_funcs},
83 #ifdef HAVE_FREETYPE
84   {"ft",	hb_ft_font_set_funcs},
85 #endif
86 };
87 
88 
89 void
post_parse(GError ** error)90 font_options_t::post_parse (GError **error)
91 {
92   assert (!font);
93   font = hb_font_create (face);
94 
95   if (font_size_x == FONT_SIZE_UPEM)
96     font_size_x = hb_face_get_upem (face);
97   if (font_size_y == FONT_SIZE_UPEM)
98     font_size_y = hb_face_get_upem (face);
99 
100   hb_font_set_ppem (font, x_ppem, y_ppem);
101   hb_font_set_ptem (font, ptem);
102 
103   hb_font_set_synthetic_slant (font, slant);
104 
105   int scale_x = (int) scalbnf (font_size_x, subpixel_bits);
106   int scale_y = (int) scalbnf (font_size_y, subpixel_bits);
107   hb_font_set_scale (font, scale_x, scale_y);
108 
109 #ifndef HB_NO_VAR
110   hb_font_set_variations (font, variations, num_variations);
111 #endif
112 
113   void (*set_font_funcs) (hb_font_t *) = nullptr;
114   if (!font_funcs)
115   {
116     set_font_funcs = supported_font_funcs[0].func;
117   }
118   else
119   {
120     for (unsigned int i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++)
121       if (0 == g_ascii_strcasecmp (font_funcs, supported_font_funcs[i].name))
122       {
123 	set_font_funcs = supported_font_funcs[i].func;
124 	break;
125       }
126     if (!set_font_funcs)
127     {
128       GString *s = g_string_new (nullptr);
129       for (unsigned int i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++)
130       {
131 	if (i)
132 	  g_string_append_c (s, '/');
133 	g_string_append (s, supported_font_funcs[i].name);
134       }
135       g_string_append_c (s, '\n');
136       char *p = g_string_free (s, FALSE);
137       g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
138 		   "Unknown font function implementation `%s'; supported values are: %s; default is %s",
139 		   font_funcs,
140 		   p,
141 		   supported_font_funcs[0].name);
142       free (p);
143       return;
144     }
145   }
146   set_font_funcs (font);
147 #ifdef HAVE_FREETYPE
148   hb_ft_font_set_load_flags (font, ft_load_flags);
149 #endif
150 
151   if (sub_font)
152   {
153     hb_font_t *old_font = font;
154     font = hb_font_create_sub_font (old_font);
155     hb_font_set_scale (old_font, scale_x * 2, scale_y * 2);
156     hb_font_destroy (old_font);
157   }
158 }
159 
160 
161 #ifndef HB_NO_VAR
162 static gboolean
parse_variations(const char * name G_GNUC_UNUSED,const char * arg,gpointer data,GError ** error G_GNUC_UNUSED)163 parse_variations (const char *name G_GNUC_UNUSED,
164 		  const char *arg,
165 		  gpointer    data,
166 		  GError    **error G_GNUC_UNUSED)
167 {
168   font_options_t *font_opts = (font_options_t *) data;
169   char *s = (char *) arg;
170   char *p;
171 
172   font_opts->num_variations = 0;
173   g_free (font_opts->variations);
174   font_opts->variations = nullptr;
175 
176   if (!*s)
177     return true;
178 
179   /* count the variations first, so we can allocate memory */
180   p = s;
181   do {
182     font_opts->num_variations++;
183     p = strpbrk (p, ", ");
184     if (p)
185       p++;
186   } while (p);
187 
188   font_opts->variations = (hb_variation_t *) calloc (font_opts->num_variations, sizeof (*font_opts->variations));
189   if (!font_opts->variations)
190     return false;
191 
192   /* now do the actual parsing */
193   p = s;
194   font_opts->num_variations = 0;
195   while (p && *p) {
196     char *end = strpbrk (p, ", ");
197     if (hb_variation_from_string (p, end ? end - p : -1, &font_opts->variations[font_opts->num_variations]))
198       font_opts->num_variations++;
199     p = end ? end + 1 : nullptr;
200   }
201 
202   return true;
203 }
204 #endif
205 
206 static gboolean
parse_font_size(const char * name G_GNUC_UNUSED,const char * arg,gpointer data,GError ** error G_GNUC_UNUSED)207 parse_font_size (const char *name G_GNUC_UNUSED,
208 		 const char *arg,
209 		 gpointer    data,
210 		 GError    **error G_GNUC_UNUSED)
211 {
212   font_options_t *font_opts = (font_options_t *) data;
213   if (0 == strcmp (arg, "upem"))
214   {
215     font_opts->font_size_y = font_opts->font_size_x = FONT_SIZE_UPEM;
216     return true;
217   }
218   switch (sscanf (arg, "%lf%*[ ,]%lf", &font_opts->font_size_x, &font_opts->font_size_y)) {
219     case 1: font_opts->font_size_y = font_opts->font_size_x; HB_FALLTHROUGH;
220     case 2: return true;
221     default:
222       g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
223 		   "%s argument should be one or two space-separated numbers",
224 		   name);
225       return false;
226   }
227 }
228 
229 static gboolean
parse_font_ppem(const char * name G_GNUC_UNUSED,const char * arg,gpointer data,GError ** error G_GNUC_UNUSED)230 parse_font_ppem (const char *name G_GNUC_UNUSED,
231 		 const char *arg,
232 		 gpointer    data,
233 		 GError    **error G_GNUC_UNUSED)
234 {
235   font_options_t *font_opts = (font_options_t *) data;
236   switch (sscanf (arg, "%d%*[ ,]%d", &font_opts->x_ppem, &font_opts->y_ppem)) {
237     case 1: font_opts->y_ppem = font_opts->x_ppem; HB_FALLTHROUGH;
238     case 2: return true;
239     default:
240       g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
241 		   "%s argument should be one or two space-separated numbers",
242 		   name);
243       return false;
244   }
245 }
246 
247 void
add_options(option_parser_t * parser)248 font_options_t::add_options (option_parser_t *parser)
249 {
250   face_options_t::add_options (parser);
251 
252   char *text = nullptr;
253 
254   {
255     static_assert ((ARRAY_LENGTH_CONST (supported_font_funcs) > 0),
256 		   "No supported font-funcs found.");
257     GString *s = g_string_new (nullptr);
258     g_string_printf (s, "Set font functions implementation to use (default: %s)\n\n    Supported font function implementations are: %s",
259 		     supported_font_funcs[0].name,
260 		     supported_font_funcs[0].name);
261     for (unsigned int i = 1; i < ARRAY_LENGTH (supported_font_funcs); i++)
262     {
263       g_string_append_c (s, '/');
264       g_string_append (s, supported_font_funcs[i].name);
265     }
266     text = g_string_free (s, FALSE);
267     parser->free_later (text);
268   }
269 
270   char *font_size_text;
271   if (DEFAULT_FONT_SIZE == FONT_SIZE_UPEM)
272     font_size_text = (char *) "Font size (default: upem)";
273   else
274   {
275     font_size_text = g_strdup_printf ("Font size (default: %d)", DEFAULT_FONT_SIZE);
276     parser->free_later (font_size_text);
277   }
278 
279   int font_size_flags = DEFAULT_FONT_SIZE == FONT_SIZE_NONE ? G_OPTION_FLAG_HIDDEN : 0;
280   GOptionEntry entries[] =
281   {
282     {"font-size",	0, font_size_flags,
283 			      G_OPTION_ARG_CALLBACK,	(gpointer) &parse_font_size,	font_size_text,					"1/2 integers or 'upem'"},
284     {"font-ppem",	0, font_size_flags,
285 			      G_OPTION_ARG_CALLBACK,	(gpointer) &parse_font_ppem,	"Set x,y pixels per EM (default: 0; disabled)",	"1/2 integers"},
286     {"font-ptem",	0, 0,
287 			      G_OPTION_ARG_DOUBLE,	&this->ptem,			"Set font point-size (default: 0; disabled)",	"point-size"},
288     {"font-slant",	0, 0,
289 			      G_OPTION_ARG_DOUBLE,	&this->slant,			"Set synthetic slant (default: 0)",		 "slant ratio; eg. 0.2"},
290     {"font-funcs",	0, 0, G_OPTION_ARG_STRING,	&this->font_funcs,		text,						"impl"},
291     {"sub-font",	0, G_OPTION_FLAG_HIDDEN,
292 			      G_OPTION_ARG_NONE,	&this->sub_font,		"Create a sub-font (default: false)",		"boolean"},
293     {"ft-load-flags",	0, 0, G_OPTION_ARG_INT,		&this->ft_load_flags,		"Set FreeType load-flags (default: 2)",		"integer"},
294     {nullptr}
295   };
296   parser->add_group (entries,
297 		     "font",
298 		     "Font-instance options:",
299 		     "Options for the font instance",
300 		     this,
301 		     false /* We add below. */);
302 
303 #ifndef HB_NO_VAR
304   const gchar *variations_help = "Comma-separated list of font variations\n"
305     "\n"
306     "    Variations are set globally. The format for specifying variation settings\n"
307     "    follows.  All valid CSS font-variation-settings values other than 'normal'\n"
308     "    and 'inherited' are also accepted, though, not documented below.\n"
309     "\n"
310     "    The format is a tag, optionally followed by an equals sign, followed by a\n"
311     "    number. For example:\n"
312     "\n"
313     "      \"wght=500\"\n"
314     "      \"slnt=-7.5\"";
315 
316   GOptionEntry entries2[] =
317   {
318     {"variations",	0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_variations,	variations_help,	"list"},
319     {nullptr}
320   };
321   parser->add_group (entries2,
322 		     "variations",
323 		     "Variations options:",
324 		     "Options for font variations used",
325 		     this);
326 #endif
327 }
328 
329 #endif
330