hb-cff2-interp-cs.hh 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /*
  2. * Copyright © 2018 Adobe 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. * Adobe Author(s): Michiharu Ariza
  25. */
  26. #ifndef HB_CFF2_INTERP_CS_HH
  27. #define HB_CFF2_INTERP_CS_HH
  28. #include "hb.hh"
  29. #include "hb-cff-interp-cs-common.hh"
  30. namespace CFF {
  31. using namespace OT;
  32. struct blend_arg_t : number_t
  33. {
  34. void set_int (int v) { reset_blends (); number_t::set_int (v); }
  35. void set_fixed (int32_t v) { reset_blends (); number_t::set_fixed (v); }
  36. void set_real (double v) { reset_blends (); number_t::set_real (v); }
  37. void set_blends (unsigned int numValues_, unsigned int valueIndex_,
  38. hb_array_t<const blend_arg_t> blends_)
  39. {
  40. numValues = numValues_;
  41. valueIndex = valueIndex_;
  42. unsigned numBlends = blends_.length;
  43. if (unlikely (!deltas.resize (numBlends)))
  44. return;
  45. for (unsigned int i = 0; i < numBlends; i++)
  46. deltas.arrayZ[i] = blends_.arrayZ[i];
  47. }
  48. bool blending () const { return deltas.length > 0; }
  49. void reset_blends ()
  50. {
  51. numValues = valueIndex = 0;
  52. deltas.resize (0);
  53. }
  54. unsigned int numValues;
  55. unsigned int valueIndex;
  56. hb_vector_t<number_t> deltas;
  57. };
  58. typedef biased_subrs_t<CFF2Subrs> cff2_biased_subrs_t;
  59. template <typename ELEM>
  60. struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
  61. {
  62. template <typename ACC>
  63. cff2_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd,
  64. const int *coords_=nullptr, unsigned int num_coords_=0)
  65. : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs)
  66. {
  67. coords = coords_;
  68. num_coords = num_coords_;
  69. varStore = acc.varStore;
  70. seen_blend = false;
  71. seen_vsindex_ = false;
  72. scalars.init ();
  73. do_blend = num_coords && coords && varStore->size;
  74. set_ivs (acc.privateDicts[fd].ivs);
  75. }
  76. void fini ()
  77. {
  78. scalars.fini ();
  79. SUPER::fini ();
  80. }
  81. op_code_t fetch_op ()
  82. {
  83. if (this->str_ref.avail ())
  84. return SUPER::fetch_op ();
  85. /* make up return or endchar op */
  86. if (this->callStack.is_empty ())
  87. return OpCode_endchar;
  88. else
  89. return OpCode_return;
  90. }
  91. const ELEM& eval_arg (unsigned int i)
  92. {
  93. return SUPER::argStack[i];
  94. }
  95. const ELEM& pop_arg ()
  96. {
  97. return SUPER::argStack.pop ();
  98. }
  99. void process_blend ()
  100. {
  101. if (!seen_blend)
  102. {
  103. region_count = varStore->varStore.get_region_index_count (get_ivs ());
  104. if (do_blend)
  105. {
  106. if (unlikely (!scalars.resize (region_count)))
  107. SUPER::set_error ();
  108. else
  109. varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
  110. &scalars[0], region_count);
  111. }
  112. seen_blend = true;
  113. }
  114. }
  115. void process_vsindex ()
  116. {
  117. unsigned int index = SUPER::argStack.pop_uint ();
  118. if (unlikely (seen_vsindex () || seen_blend))
  119. {
  120. SUPER::set_error ();
  121. }
  122. else
  123. {
  124. set_ivs (index);
  125. }
  126. seen_vsindex_ = true;
  127. }
  128. unsigned int get_region_count () const { return region_count; }
  129. void set_region_count (unsigned int region_count_) { region_count = region_count_; }
  130. unsigned int get_ivs () const { return ivs; }
  131. void set_ivs (unsigned int ivs_) { ivs = ivs_; }
  132. bool seen_vsindex () const { return seen_vsindex_; }
  133. double blend_deltas (hb_array_t<const ELEM> deltas) const
  134. {
  135. double v = 0;
  136. if (do_blend)
  137. {
  138. if (likely (scalars.length == deltas.length))
  139. {
  140. unsigned count = scalars.length;
  141. for (unsigned i = 0; i < count; i++)
  142. v += (double) scalars.arrayZ[i] * deltas.arrayZ[i].to_real ();
  143. }
  144. }
  145. return v;
  146. }
  147. protected:
  148. const int *coords;
  149. unsigned int num_coords;
  150. const CFF2VariationStore *varStore;
  151. unsigned int region_count;
  152. unsigned int ivs;
  153. hb_vector_t<float> scalars;
  154. bool do_blend;
  155. bool seen_vsindex_;
  156. bool seen_blend;
  157. typedef cs_interp_env_t<ELEM, CFF2Subrs> SUPER;
  158. };
  159. template <typename OPSET, typename PARAM, typename ELEM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t<ELEM>, PARAM>>
  160. struct cff2_cs_opset_t : cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PARAM, PATH>
  161. {
  162. static void process_op (op_code_t op, cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
  163. {
  164. switch (op) {
  165. case OpCode_callsubr:
  166. case OpCode_callgsubr:
  167. /* a subroutine number shouldn't be a blended value */
  168. #if 0
  169. if (unlikely (env.argStack.peek ().blending ()))
  170. {
  171. env.set_error ();
  172. break;
  173. }
  174. #endif
  175. SUPER::process_op (op, env, param);
  176. break;
  177. case OpCode_blendcs:
  178. OPSET::process_blend (env, param);
  179. break;
  180. case OpCode_vsindexcs:
  181. #if 0
  182. if (unlikely (env.argStack.peek ().blending ()))
  183. {
  184. env.set_error ();
  185. break;
  186. }
  187. #endif
  188. OPSET::process_vsindex (env, param);
  189. break;
  190. default:
  191. SUPER::process_op (op, env, param);
  192. }
  193. }
  194. template <typename T = ELEM,
  195. hb_enable_if (hb_is_same (T, blend_arg_t))>
  196. static void process_arg_blend (cff2_cs_interp_env_t<ELEM> &env,
  197. ELEM &arg,
  198. const hb_array_t<const ELEM> blends,
  199. unsigned n, unsigned i)
  200. {
  201. arg.set_blends (n, i, blends);
  202. }
  203. template <typename T = ELEM,
  204. hb_enable_if (!hb_is_same (T, blend_arg_t))>
  205. static void process_arg_blend (cff2_cs_interp_env_t<ELEM> &env,
  206. ELEM &arg,
  207. const hb_array_t<const ELEM> blends,
  208. unsigned n, unsigned i)
  209. {
  210. arg.set_real (arg.to_real () + env.blend_deltas (blends));
  211. }
  212. static void process_blend (cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
  213. {
  214. unsigned int n, k;
  215. env.process_blend ();
  216. k = env.get_region_count ();
  217. n = env.argStack.pop_uint ();
  218. /* copy the blend values into blend array of the default values */
  219. unsigned int start = env.argStack.get_count () - ((k+1) * n);
  220. /* let an obvious error case fail, but note CFF2 spec doesn't forbid n==0 */
  221. if (unlikely (start > env.argStack.get_count ()))
  222. {
  223. env.set_error ();
  224. return;
  225. }
  226. for (unsigned int i = 0; i < n; i++)
  227. {
  228. const hb_array_t<const ELEM> blends = env.argStack.sub_array (start + n + (i * k), k);
  229. process_arg_blend (env, env.argStack[start + i], blends, n, i);
  230. }
  231. /* pop off blend values leaving default values now adorned with blend values */
  232. env.argStack.pop (k * n);
  233. }
  234. static void process_vsindex (cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
  235. {
  236. env.process_vsindex ();
  237. env.clear_args ();
  238. }
  239. private:
  240. typedef cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PARAM, PATH> SUPER;
  241. };
  242. template <typename OPSET, typename PARAM, typename ELEM>
  243. using cff2_cs_interpreter_t = cs_interpreter_t<cff2_cs_interp_env_t<ELEM>, OPSET, PARAM>;
  244. } /* namespace CFF */
  245. #endif /* HB_CFF2_INTERP_CS_HH */