helper-subset.hh 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /*
  2. * Copyright © 2023 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): Garret Rieger
  25. */
  26. #ifndef HELPER_SUBSET_HH
  27. #define HELPER_SUBSET_HH
  28. #include "glib.h"
  29. #include <errno.h>
  30. #include <math.h>
  31. #include <stdbool.h>
  32. #include "hb-subset.h"
  33. #ifndef HB_NO_VAR
  34. // Parses an axis position string and sets min, default, and max to
  35. // the requested values. If a value should be set to it's default value
  36. // then it will be set to NaN.
  37. static gboolean
  38. parse_axis_position(const char* s,
  39. float* min,
  40. float* def,
  41. float* max,
  42. gboolean* drop,
  43. GError **error)
  44. {
  45. const char* part = strpbrk(s, ":");
  46. *drop = false;
  47. if (!part) {
  48. // Single value.
  49. if (strcmp (s, "drop") == 0)
  50. {
  51. *min = NAN;
  52. *def = NAN;
  53. *max = NAN;
  54. *drop = true;
  55. return true;
  56. }
  57. errno = 0;
  58. char *p;
  59. float axis_value = strtof (s, &p);
  60. if (errno || s == p)
  61. {
  62. g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
  63. "Failed parsing axis value at: '%s'", s);
  64. return false;
  65. }
  66. *min = axis_value;
  67. *def = axis_value;
  68. *max = axis_value;
  69. return true;
  70. }
  71. float values[3];
  72. int count = 0;
  73. for (int i = 0; i < 3; i++) {
  74. errno = 0;
  75. count++;
  76. if (!*s || part == s) {
  77. values[i] = NAN;
  78. if (part == NULL) break;
  79. s = part + 1;
  80. part = strpbrk(s, ":");
  81. continue;
  82. }
  83. char *pend;
  84. values[i] = strtof (s, &pend);
  85. if (errno || s == pend || (part && pend != part))
  86. {
  87. g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
  88. "Failed parsing axis value at: '%s'", s);
  89. return false;
  90. }
  91. if (part == NULL) break;
  92. s = pend + 1;
  93. part = strpbrk(s, ":");
  94. }
  95. if (count == 2) {
  96. *min = values[0];
  97. *def = NAN;
  98. *max = values[1];
  99. return true;
  100. } else if (count == 3) {
  101. *min = values[0];
  102. *def = values[1];
  103. *max = values[2];
  104. return true;
  105. }
  106. g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
  107. "Failed parsing axis value at: '%s'", s);
  108. return false;
  109. }
  110. static gboolean
  111. parse_instancing_spec (const char *arg,
  112. hb_face_t* face,
  113. hb_subset_input_t* input,
  114. GError **error)
  115. {
  116. char* s;
  117. while ((s = strtok((char *) arg, "=")))
  118. {
  119. arg = NULL;
  120. unsigned len = strlen (s);
  121. if (len > 4) //Axis tags are 4 bytes.
  122. {
  123. g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
  124. "Failed parsing axis tag at: '%s'", s);
  125. return false;
  126. }
  127. /* support *=drop */
  128. if (0 == strcmp (s, "*"))
  129. {
  130. s = strtok(NULL, ", ");
  131. if (0 != strcmp (s, "drop"))
  132. {
  133. g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
  134. "Failed parsing axis position at: '%s'", s);
  135. return false;
  136. }
  137. if (!hb_subset_input_pin_all_axes_to_default (input, face))
  138. {
  139. g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
  140. "Failed pinning all axes to default.");
  141. return false;
  142. }
  143. continue;
  144. }
  145. hb_tag_t axis_tag = hb_tag_from_string (s, len);
  146. s = strtok(NULL, ", ");
  147. if (!s)
  148. {
  149. g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
  150. "Value not specified for axis: %c%c%c%c", HB_UNTAG (axis_tag));
  151. return false;
  152. }
  153. gboolean drop;
  154. float min, def, max;
  155. if (!parse_axis_position(s, &min, &def, &max, &drop, error))
  156. return false;
  157. if (drop)
  158. {
  159. if (!hb_subset_input_pin_axis_to_default (input,
  160. face,
  161. axis_tag))
  162. {
  163. g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
  164. "Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag));
  165. return false;
  166. }
  167. continue;
  168. }
  169. if (min == def && def == max) {
  170. if (!hb_subset_input_pin_axis_location (input,
  171. face, axis_tag,
  172. def))
  173. {
  174. g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
  175. "Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag));
  176. return false;
  177. }
  178. continue;
  179. }
  180. if (!hb_subset_input_set_axis_range (input,
  181. face, axis_tag,
  182. min, max, def))
  183. {
  184. g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
  185. "Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag));
  186. return false;
  187. }
  188. continue;
  189. g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
  190. "Partial instancing is not supported.");
  191. return false;
  192. }
  193. return true;
  194. }
  195. #endif
  196. #endif