PageRenderTime 84ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/fontforge/lookups.c

https://bitbucket.org/sortsmill/sortsmill-tools
C | 6035 lines | 5333 code | 377 blank | 325 comment | 1970 complexity | 3b2070083e03feecf1d4562cdfff3c02 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.0
  1. #include <config.h> /* -*- coding: utf-8 -*- */
  2. // This file is part of the Sorts Mill Tools.
  3. //
  4. // Sorts Mill Tools is free software; you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation; either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // Sorts Mill Tools is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program; if not, see <http://www.gnu.org/licenses/>.
  16. /* Copyright (C) 2007-2012 by George Williams */
  17. /*
  18. * Redistribution and use in source and binary forms, with or without
  19. * modification, are permitted provided that the following conditions are met:
  20. * Redistributions of source code must retain the above copyright notice, this
  21. * list of conditions and the following disclaimer.
  22. * Redistributions in binary form must reproduce the above copyright notice,
  23. * this list of conditions and the following disclaimer in the documentation
  24. * and/or other materials provided with the distribution.
  25. * The name of the author may not be used to endorse or promote products
  26. * derived from this software without specific prior written permission.
  27. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
  28. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  29. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
  30. * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  31. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  32. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  33. * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  34. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  35. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  36. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  37. */
  38. #include "fontforgevw.h"
  39. #include <chardata.h>
  40. #include <utype.h>
  41. #include <ustring.h>
  42. #include <math.h>
  43. #include <locale.h>
  44. #include <stdlib.h>
  45. #include <stdarg.h>
  46. #include "ttf.h"
  47. #include "lookups.h"
  48. VISIBLE struct opentype_feature_friendlynames friendlies[] = {
  49. #if 0 /* They get stuffed into the 'MATH' table now */
  50. /* I added these first three features to allow round-trip conversion of tfm files */
  51. {CHR ('I', 'T', 'L', 'C'), "ITLC", N_("Italic Correction"), gpos_single_mask},
  52. {CHR ('T', 'C', 'H', 'L'), "TCHL", N_("TeX Glyphlist"), gsub_alternate_mask},
  53. {CHR ('T', 'E', 'X', 'L'), "TEXL", N_("TeX Extension List"),
  54. gsub_multiple_mask},
  55. #endif
  56. /* Normal OpenType features follow */
  57. {CHR ('a', 'a', 'l', 't'), "aalt", N_("Access All Alternates"),
  58. gsub_single_mask | gsub_alternate_mask},
  59. {CHR ('a', 'b', 'v', 'f'), "abvf", N_("Above Base Forms"), gsub_single_mask},
  60. {CHR ('a', 'b', 'v', 'm'), "abvm", N_("Above Base Mark"),
  61. gpos_mark2base_mask | gpos_mark2ligature_mask},
  62. {CHR ('a', 'b', 'v', 's'), "abvs", N_("Above Base Substitutions"),
  63. gsub_ligature_mask},
  64. {CHR ('a', 'f', 'r', 'c'), "afrc", N_("Vertical Fractions"),
  65. gsub_ligature_mask},
  66. {CHR ('a', 'k', 'h', 'n'), "akhn", N_("Akhand"), gsub_ligature_mask},
  67. {CHR ('a', 'l', 'i', 'g'), "alig", N_("Ancient Ligatures"),
  68. gsub_ligature_mask},
  69. {CHR ('b', 'l', 'w', 'f'), "blwf", N_("Below Base Forms"),
  70. gsub_ligature_mask},
  71. {CHR ('b', 'l', 'w', 'm'), "blwm", N_("Below Base Mark"),
  72. gpos_mark2base_mask | gpos_mark2ligature_mask},
  73. {CHR ('b', 'l', 'w', 's'), "blws", N_("Below Base Substitutions"),
  74. gsub_ligature_mask},
  75. {CHR ('c', '2', 'p', 'c'), "c2pc", N_("Capitals to Petite Capitals"),
  76. gsub_single_mask},
  77. {CHR ('c', '2', 's', 'c'), "c2sc", N_("Capitals to Small Capitals"),
  78. gsub_single_mask},
  79. {CHR ('c', 'a', 'l', 't'), "calt", N_("Contextual Alternates"),
  80. gsub_context_mask | gsub_contextchain_mask},
  81. {CHR ('c', 'a', 's', 'e'), "case", N_("Case-Sensitive Forms"),
  82. gsub_single_mask | gpos_single_mask},
  83. {CHR ('c', 'c', 'm', 'p'), "ccmp", N_("Glyph Composition/Decomposition"),
  84. gsub_multiple_mask | gsub_ligature_mask},
  85. {CHR ('c', 'f', 'a', 'r'), "cfar", N_("Conjunct Form After Ro"),
  86. gsub_single_mask},
  87. {CHR ('c', 'j', 'c', 't'), "cjct", N_("Conjunct Forms"), gsub_ligature_mask},
  88. {CHR ('c', 'l', 'i', 'g'), "clig", N_("Contextual Ligatures"),
  89. gsub_reversecchain_mask},
  90. {CHR ('c', 'p', 'c', 't'), "cpct", N_("Centered CJK Punctuation"),
  91. gpos_single_mask},
  92. {CHR ('c', 'p', 's', 'p'), "cpsp", N_("Capital Spacing"), gpos_single_mask},
  93. {CHR ('c', 's', 'w', 'h'), "cswh", N_("Contextual Swash"),
  94. gsub_reversecchain_mask},
  95. {CHR ('c', 'u', 'r', 's'), "curs", N_("Cursive Attachment"),
  96. gpos_cursive_mask},
  97. {CHR ('c', 'v', '0', '1'), "cv01", N_("Character Variants 01"),
  98. gsub_single_mask},
  99. {CHR ('c', 'v', '0', '2'), "cv02", N_("Character Variants 02"),
  100. gsub_single_mask},
  101. {CHR ('c', 'v', '0', '3'), "cv03", N_("Character Variants 03"),
  102. gsub_single_mask},
  103. {CHR ('c', 'v', '0', '4'), "cv04", N_("Character Variants 04"),
  104. gsub_single_mask},
  105. {CHR ('c', 'v', '0', '5'), "cv05", N_("Character Variants 05"),
  106. gsub_single_mask},
  107. {CHR ('c', 'v', '0', '6'), "cv06", N_("Character Variants 06"),
  108. gsub_single_mask},
  109. {CHR ('c', 'v', '0', '7'), "cv07", N_("Character Variants 07"),
  110. gsub_single_mask},
  111. {CHR ('c', 'v', '0', '8'), "cv08", N_("Character Variants 08"),
  112. gsub_single_mask},
  113. {CHR ('c', 'v', '0', '9'), "cv09", N_("Character Variants 09"),
  114. gsub_single_mask},
  115. {CHR ('c', 'v', '1', '0'), "cv10", N_("Character Variants 10"),
  116. gsub_single_mask},
  117. {CHR ('c', 'v', '9', '9'), "cv99", N_("Character Variants 99"),
  118. gsub_single_mask},
  119. {CHR ('d', 'c', 'a', 'p'), "dcap", N_("Drop Caps"), gsub_single_mask},
  120. {CHR ('d', 'i', 's', 't'), "dist", N_("Distance"), gpos_pair_mask},
  121. {CHR ('d', 'l', 'i', 'g'), "dlig", N_("Discretionary Ligatures"),
  122. gsub_ligature_mask},
  123. {CHR ('d', 'n', 'o', 'm'), "dnom", N_("Denominators"), gsub_single_mask},
  124. {CHR ('d', 'p', 'n', 'g'), "dpng", N_("Dipthongs (Obsolete)"),
  125. gsub_ligature_mask},
  126. {CHR ('d', 't', 'l', 's'), "dtls", N_("Dotless Forms"), gsub_single_mask},
  127. {CHR ('e', 'x', 'p', 't'), "expt", N_("Expert Forms"), gsub_single_mask},
  128. {CHR ('f', 'a', 'l', 't'), "falt", N_("Final Glyph On Line"),
  129. gsub_alternate_mask},
  130. {CHR ('f', 'i', 'n', '2'), "fin2", N_("Terminal Forms #2"),
  131. gsub_context_mask | gsub_contextchain_mask},
  132. {CHR ('f', 'i', 'n', '3'), "fin3", N_("Terminal Forms #3"),
  133. gsub_context_mask | gsub_contextchain_mask},
  134. {CHR ('f', 'i', 'n', 'a'), "fina", N_("Terminal Forms"), gsub_single_mask},
  135. {CHR ('f', 'l', 'a', 'c'), "flac", N_("Flattened Accents over Capitals"),
  136. gsub_single_mask | gsub_ligature_mask},
  137. {CHR ('f', 'r', 'a', 'c'), "frac", N_("Diagonal Fractions"),
  138. gsub_single_mask | gsub_ligature_mask},
  139. {CHR ('f', 'w', 'i', 'd'), "fwid", N_("Full Widths"),
  140. gsub_single_mask | gpos_single_mask},
  141. {CHR ('h', 'a', 'l', 'f'), "half", N_("Half Forms"), gsub_ligature_mask},
  142. {CHR ('h', 'a', 'l', 'n'), "haln", N_("Halant Forms"), gsub_ligature_mask},
  143. {CHR ('h', 'a', 'l', 't'), "halt", N_("Alternative Half Widths"),
  144. gpos_single_mask},
  145. {CHR ('h', 'i', 's', 't'), "hist", N_("Historical Forms"), gsub_single_mask},
  146. {CHR ('h', 'k', 'n', 'a'), "hkna", N_("Horizontal Kana Alternatives"),
  147. gsub_single_mask},
  148. {CHR ('h', 'l', 'i', 'g'), "hlig", N_("Historic Ligatures"),
  149. gsub_ligature_mask},
  150. {CHR ('h', 'n', 'g', 'l'), "hngl", N_("Hanja to Hangul"),
  151. gsub_single_mask | gsub_alternate_mask},
  152. {CHR ('h', 'o', 'j', 'o'), "hojo", N_("Hojo (JIS X 0212-1990) Kanji Forms"),
  153. gsub_single_mask},
  154. {CHR ('h', 'w', 'i', 'd'), "hwid", N_("Half Widths"),
  155. gsub_single_mask | gpos_single_mask},
  156. {CHR ('i', 'n', 'i', 't'), "init", N_("Initial Forms"), gsub_single_mask},
  157. {CHR ('i', 's', 'o', 'l'), "isol", N_("Isolated Forms"), gsub_single_mask},
  158. {CHR ('i', 't', 'a', 'l'), "ital", N_("Italics"), gsub_single_mask},
  159. {CHR ('j', 'a', 'l', 't'), "jalt", N_("Justification Alternatives"),
  160. gsub_alternate_mask},
  161. {CHR ('j', 'a', 'j', 'p'), "jajp", N_("Japanese Forms (Obsolete)"),
  162. gsub_single_mask | gsub_alternate_mask},
  163. {CHR ('j', 'p', '0', '4'), "jp04", N_("JIS2004 Forms"), gsub_single_mask},
  164. {CHR ('j', 'p', '7', '8'), "jp78", N_("JIS78 Forms"),
  165. gsub_single_mask | gsub_alternate_mask},
  166. {CHR ('j', 'p', '8', '3'), "jp83", N_("JIS83 Forms"), gsub_single_mask},
  167. {CHR ('j', 'p', '9', '0'), "jp90", N_("JIS90 Forms"), gsub_single_mask},
  168. {CHR ('k', 'e', 'r', 'n'), "kern", N_("Horizontal Kerning"),
  169. gpos_pair_mask | gpos_context_mask | gpos_contextchain_mask},
  170. {CHR ('l', 'f', 'b', 'd'), "lfbd", N_("Left Bounds"), gpos_single_mask},
  171. {CHR ('l', 'i', 'g', 'a'), "liga", N_("Standard Ligatures"),
  172. gsub_ligature_mask},
  173. {CHR ('l', 'j', 'm', 'o'), "ljmo", N_("Leading Jamo Forms"),
  174. gsub_ligature_mask},
  175. {CHR ('l', 'n', 'u', 'm'), "lnum", N_("Lining Figures"), gsub_single_mask},
  176. {CHR ('l', 'o', 'c', 'l'), "locl", N_("Localized Forms"), gsub_single_mask},
  177. {CHR ('m', 'a', 'r', 'k'), "mark", N_("Mark Positioning"),
  178. gpos_mark2base_mask | gpos_mark2ligature_mask},
  179. {CHR ('m', 'e', 'd', '2'), "med2", N_("Medial Forms 2"),
  180. gsub_context_mask | gsub_contextchain_mask},
  181. {CHR ('m', 'e', 'd', 'i'), "medi", N_("Medial Forms"), gsub_single_mask},
  182. {CHR ('m', 'g', 'r', 'k'), "mgrk", N_("Mathematical Greek"),
  183. gsub_single_mask},
  184. {CHR ('m', 'k', 'm', 'k'), "mkmk", N_("Mark to Mark"), gpos_mark2mark_mask},
  185. {CHR ('m', 's', 'e', 't'), "mset", N_("Mark Positioning via Substitution"),
  186. gsub_context_mask | gsub_contextchain_mask},
  187. {CHR ('n', 'a', 'l', 't'), "nalt", N_("Alternate Annotation Forms"),
  188. gsub_single_mask | gsub_alternate_mask},
  189. {CHR ('n', 'l', 'c', 'k'), "nlck", N_("NLC Kanji Forms"), gsub_single_mask},
  190. {CHR ('n', 'u', 'k', 't'), "nukt", N_("Nukta Forms"), gsub_ligature_mask},
  191. {CHR ('n', 'u', 'm', 'r'), "numr", N_("Numerators"), gsub_single_mask},
  192. {CHR ('o', 'n', 'u', 'm'), "onum", N_("Oldstyle Figures"), gsub_single_mask},
  193. {CHR ('o', 'p', 'b', 'd'), "opbd", N_("Optical Bounds"), gpos_single_mask},
  194. {CHR ('o', 'r', 'd', 'n'), "ordn", N_("Ordinals"),
  195. gsub_ligature_mask | gsub_context_mask | gsub_contextchain_mask},
  196. {CHR ('o', 'r', 'n', 'm'), "ornm", N_("Ornaments"),
  197. gsub_single_mask | gsub_alternate_mask},
  198. {CHR ('p', 'a', 'l', 't'), "palt", N_("Proportional Alternate Metrics"),
  199. gpos_single_mask},
  200. {CHR ('p', 'c', 'a', 'p'), "pcap", N_("Lowercase to Petite Capitals"),
  201. gsub_single_mask},
  202. {CHR ('p', 'k', 'n', 'a'), "pkna", N_("Proportional Kana"), gpos_single_mask},
  203. {CHR ('p', 'n', 'u', 'm'), "pnum", N_("Proportional Numbers"),
  204. gsub_single_mask},
  205. {CHR ('p', 'r', 'e', 'f'), "pref", N_("Pre Base Forms"), gsub_ligature_mask},
  206. {CHR ('p', 'r', 'e', 's'), "pres", N_("Pre Base Substitutions"),
  207. gsub_ligature_mask | gsub_context_mask | gsub_contextchain_mask},
  208. {CHR ('p', 's', 't', 'f'), "pstf", N_("Post Base Forms"), gsub_ligature_mask},
  209. {CHR ('p', 's', 't', 's'), "psts", N_("Post Base Substitutions"),
  210. gsub_ligature_mask},
  211. {CHR ('p', 'w', 'i', 'd'), "pwid", N_("Proportional Width"),
  212. gsub_single_mask},
  213. {CHR ('q', 'w', 'i', 'd'), "qwid", N_("Quarter Widths"),
  214. gsub_single_mask | gpos_single_mask},
  215. {CHR ('r', 'a', 'n', 'd'), "rand", N_("Randomize"), gsub_alternate_mask},
  216. {CHR ('r', 'k', 'r', 'f'), "rkrf", N_("Rakar Forms"), gsub_ligature_mask},
  217. {CHR ('r', 'l', 'i', 'g'), "rlig", N_("Required Ligatures"),
  218. gsub_ligature_mask},
  219. {CHR ('r', 'p', 'h', 'f'), "rphf", N_("Reph Form"), gsub_ligature_mask},
  220. {CHR ('r', 't', 'b', 'd'), "rtbd", N_("Right Bounds"), gpos_single_mask},
  221. {CHR ('r', 't', 'l', 'a'), "rtla", N_("Right to Left Alternates"),
  222. gsub_single_mask},
  223. {CHR ('r', 't', 'l', 'm'), "rtlm", N_("Right to Left mirrored forms"),
  224. gsub_single_mask},
  225. {CHR ('r', 'u', 'b', 'y'), "ruby", N_("Ruby Notational Forms"),
  226. gsub_single_mask},
  227. {CHR ('s', 'a', 'l', 't'), "salt", N_("Stylistic Alternatives"),
  228. gsub_single_mask | gsub_alternate_mask},
  229. {CHR ('s', 'i', 'n', 'f'), "sinf", N_("Scientific Inferiors"),
  230. gsub_single_mask},
  231. {CHR ('s', 'm', 'c', 'p'), "smcp", N_("Lowercase to Small Capitals"),
  232. gsub_single_mask},
  233. {CHR ('s', 'm', 'p', 'l'), "smpl", N_("Simplified Forms"), gsub_single_mask},
  234. {CHR ('s', 's', '0', '1'), "ss01", N_("Style Set 1"), gsub_single_mask},
  235. {CHR ('s', 's', '0', '2'), "ss02", N_("Style Set 2"), gsub_single_mask},
  236. {CHR ('s', 's', '0', '3'), "ss03", N_("Style Set 3"), gsub_single_mask},
  237. {CHR ('s', 's', '0', '4'), "ss04", N_("Style Set 4"), gsub_single_mask},
  238. {CHR ('s', 's', '0', '5'), "ss05", N_("Style Set 5"), gsub_single_mask},
  239. {CHR ('s', 's', '0', '6'), "ss06", N_("Style Set 6"), gsub_single_mask},
  240. {CHR ('s', 's', '0', '7'), "ss07", N_("Style Set 7"), gsub_single_mask},
  241. {CHR ('s', 's', '0', '8'), "ss08", N_("Style Set 8"), gsub_single_mask},
  242. {CHR ('s', 's', '0', '9'), "ss09", N_("Style Set 9"), gsub_single_mask},
  243. {CHR ('s', 's', '1', '0'), "ss10", N_("Style Set 10"), gsub_single_mask},
  244. {CHR ('s', 's', '1', '1'), "ss11", N_("Style Set 11"), gsub_single_mask},
  245. {CHR ('s', 's', '1', '2'), "ss12", N_("Style Set 12"), gsub_single_mask},
  246. {CHR ('s', 's', '1', '3'), "ss13", N_("Style Set 13"), gsub_single_mask},
  247. {CHR ('s', 's', '1', '4'), "ss14", N_("Style Set 14"), gsub_single_mask},
  248. {CHR ('s', 's', '1', '5'), "ss15", N_("Style Set 15"), gsub_single_mask},
  249. {CHR ('s', 's', '1', '6'), "ss16", N_("Style Set 16"), gsub_single_mask},
  250. {CHR ('s', 's', '1', '7'), "ss17", N_("Style Set 17"), gsub_single_mask},
  251. {CHR ('s', 's', '1', '8'), "ss18", N_("Style Set 18"), gsub_single_mask},
  252. {CHR ('s', 's', '1', '9'), "ss19", N_("Style Set 19"), gsub_single_mask},
  253. {CHR ('s', 's', '2', '0'), "ss20", N_("Style Set 20"), gsub_single_mask},
  254. {CHR ('s', 's', 't', 'y'), "ssty", N_("Script Style"),
  255. gsub_single_mask | gsub_alternate_mask},
  256. {CHR ('s', 'u', 'b', 's'), "subs", N_("Subscript"), gsub_single_mask},
  257. {CHR ('s', 'u', 'p', 's'), "sups", N_("Superscript"), gsub_single_mask},
  258. {CHR ('s', 'w', 's', 'h'), "swsh", N_("Swash"),
  259. gsub_single_mask | gsub_alternate_mask},
  260. {CHR ('t', 'i', 't', 'l'), "titl", N_("Titling"), gsub_single_mask},
  261. {CHR ('t', 'j', 'm', 'o'), "tjmo", N_("Trailing Jamo Forms"),
  262. gsub_ligature_mask},
  263. {CHR ('t', 'n', 'a', 'm'), "tnam", N_("Traditional Name Forms"),
  264. gsub_single_mask},
  265. {CHR ('t', 'n', 'u', 'm'), "tnum", N_("Tabular Numbers"), gsub_single_mask},
  266. {CHR ('t', 'r', 'a', 'd'), "trad", N_("Traditional Forms"),
  267. gsub_single_mask | gsub_alternate_mask},
  268. {CHR ('t', 'w', 'i', 'd'), "twid", N_("Third Widths"),
  269. gsub_single_mask | gpos_single_mask},
  270. {CHR ('u', 'n', 'i', 'c'), "unic", N_("Unicase"), gsub_single_mask},
  271. {CHR ('v', 'a', 'l', 't'), "valt", N_("Alternate Vertical Metrics"),
  272. gpos_single_mask},
  273. {CHR ('v', 'a', 't', 'u'), "vatu", N_("Vattu Variants"), gsub_ligature_mask},
  274. {CHR ('v', 'e', 'r', 't'), "vert", N_("Vertical Alternates (obs)"),
  275. gsub_single_mask},
  276. {CHR ('v', 'h', 'a', 'l'), "vhal", N_("Alternate Vertical Half Metrics"),
  277. gpos_single_mask},
  278. {CHR ('v', 'j', 'm', 'o'), "vjmo", N_("Vowel Jamo Forms"),
  279. gsub_ligature_mask},
  280. {CHR ('v', 'k', 'n', 'a'), "vkna", N_("Vertical Kana Alternates"),
  281. gsub_single_mask},
  282. {CHR ('v', 'k', 'r', 'n'), "vkrn", N_("Vertical Kerning"),
  283. gpos_pair_mask | gpos_context_mask | gpos_contextchain_mask},
  284. {CHR ('v', 'p', 'a', 'l'), "vpal",
  285. N_("Proportional Alternate Vertical Metrics"), gpos_single_mask},
  286. {CHR ('v', 'r', 't', '2'), "vrt2", N_("Vertical Rotation & Alternates"),
  287. gsub_single_mask},
  288. {CHR ('z', 'e', 'r', 'o'), "zero", N_("Slashed Zero"), gsub_single_mask},
  289. /* This is my hack for setting the "Required feature" field of a script */
  290. {CHR (' ', 'R', 'Q', 'D'), " RQD", N_("Required feature"),
  291. gsub_single_mask | gsub_multiple_mask | gsub_alternate_mask |
  292. gsub_ligature_mask | gsub_context_mask | gsub_contextchain_mask |
  293. gsub_reversecchain_mask | gpos_single_mask | gpos_pair_mask |
  294. gpos_cursive_mask | gpos_mark2base_mask | gpos_mark2ligature_mask |
  295. gpos_mark2mark_mask | gpos_context_mask | gpos_contextchain_mask},
  296. OPENTYPE_FEATURE_FRIENDLYNAMES_EMPTY
  297. };
  298. static int
  299. uint32_cmp (const void *_ui1, const void *_ui2)
  300. {
  301. if (*(uint32_t *) _ui1 > *(uint32_t *) _ui2)
  302. return 1;
  303. if (*(uint32_t *) _ui1 < *(uint32_t *) _ui2)
  304. return -1;
  305. return 0;
  306. }
  307. static int
  308. lang_cmp (const void *_ui1, const void *_ui2)
  309. {
  310. /* The default language is magic, and should come first in the list even */
  311. /* if that is not true alphabetical order */
  312. if (*(uint32_t *) _ui1 == DEFAULT_LANG)
  313. return -1;
  314. if (*(uint32_t *) _ui2 == DEFAULT_LANG)
  315. return 1;
  316. if (*(uint32_t *) _ui1 > *(uint32_t *) _ui2)
  317. return 1;
  318. if (*(uint32_t *) _ui1 < *(uint32_t *) _ui2)
  319. return -1;
  320. return 0;
  321. }
  322. FeatureScriptLangList *
  323. FindFeatureTagInFeatureScriptList (uint32_t tag, FeatureScriptLangList *fl)
  324. {
  325. while (fl != NULL)
  326. {
  327. if (fl->featuretag == tag)
  328. return fl;
  329. fl = fl->next;
  330. }
  331. return NULL;
  332. }
  333. int
  334. FeatureTagInFeatureScriptList (uint32_t tag, FeatureScriptLangList *fl)
  335. {
  336. while (fl != NULL)
  337. {
  338. if (fl->featuretag == tag)
  339. return true;
  340. fl = fl->next;
  341. }
  342. return false;
  343. }
  344. int
  345. ScriptInFeatureScriptList (uint32_t script, FeatureScriptLangList *fl)
  346. {
  347. struct scriptlanglist *sl;
  348. if (fl == NULL) /* No features bound to lookup? (nested?) don't restrict by script */
  349. return true;
  350. while (fl != NULL)
  351. {
  352. for (sl = fl->scripts; sl != NULL; sl = sl->next)
  353. {
  354. if (sl->script == script)
  355. return true;
  356. }
  357. fl = fl->next;
  358. }
  359. return false;
  360. }
  361. int
  362. FeatureScriptTagInFeatureScriptList (uint32_t feature, uint32_t script,
  363. FeatureScriptLangList *fl)
  364. {
  365. struct scriptlanglist *sl;
  366. while (fl != NULL)
  367. {
  368. if (fl->featuretag == feature)
  369. {
  370. for (sl = fl->scripts; sl != NULL; sl = sl->next)
  371. {
  372. if (sl->script == script)
  373. return true;
  374. }
  375. }
  376. fl = fl->next;
  377. }
  378. return false;
  379. }
  380. int
  381. DefaultLangTagInOneScriptList (struct scriptlanglist *sl)
  382. {
  383. int l;
  384. for (l = 0; l < sl->lang_cnt; ++l)
  385. {
  386. uint32_t lang = l < MAX_LANG ? sl->langs[l] : sl->morelangs[l - MAX_LANG];
  387. if (lang == DEFAULT_LANG)
  388. return true;
  389. }
  390. return false;
  391. }
  392. struct scriptlanglist *
  393. DefaultLangTagInScriptList (struct scriptlanglist *sl, int DFLT_ok)
  394. {
  395. while (sl != NULL)
  396. {
  397. if (DFLT_ok || sl->script != DEFAULT_SCRIPT)
  398. {
  399. if (DefaultLangTagInOneScriptList (sl))
  400. return sl;
  401. }
  402. sl = sl->next;
  403. }
  404. return NULL;
  405. }
  406. uint32_t *
  407. SFScriptsInLookups (SplineFont *sf, int gpos)
  408. {
  409. /* Presumes that either SFFindUnusedLookups or SFFindClearUnusedLookupBits */
  410. /* has been called first */
  411. /* Since MS will sometimes ignore a script if it isn't found in both */
  412. /* GPOS and GSUB we want to return the same script list no matter */
  413. /* what the setting of gpos ... so we totally ignore that argument */
  414. /* and always look at both sets of lookups */
  415. /* Sergey Malkin from MicroSoft tells me:
  416. Each shaping engine in Uniscribe can decide on its requirements for
  417. layout tables - some of them require both GSUB and GPOS, in some cases
  418. any table present is enough, or it can work without any table.
  419. Sometimes, purpose of the check is to determine if font is supporting
  420. particular script - if required tables are not there font is just
  421. rejected by this shaping engine. Sometimes, shaping engine can not just
  422. reject the font because there are fonts using older shaping technologies
  423. we still have to support, so it uses some logic when to fallback to
  424. legacy layout code.
  425. In your case this is Hebrew, where both tables are required to use
  426. OpenType processing. Arabic requires both tables too, Latin requires
  427. GSUB to execute GPOS. But in general, if you have both tables you should
  428. be safe with any script to get fully featured OpenType shaping.
  429. In other words, if we have a Hebrew font with just GPOS features they won't work,
  430. and MS will not use the font at all. We must add a GSUB table. In the unlikely
  431. event that we had a hebrew font with only GSUB it would not work either.
  432. So if we want our lookups to have a chance of executing under Uniscribe we
  433. better make sure that both tables have the same script set.
  434. (Sergey says we could optimize a little: A Latin GSUB table will run without
  435. a GPOS, but he says the GPOS won't work without a GSUB.)
  436. */
  437. int cnt = 0, tot = 0, i;
  438. uint32_t *scripts = NULL;
  439. OTLookup *test;
  440. FeatureScriptLangList *fl;
  441. struct scriptlanglist *sl;
  442. /* So here always give scripts for both (see comment above) no */
  443. /* matter what they asked for */
  444. for (gpos = 0; gpos < 2; ++gpos)
  445. {
  446. for (test = gpos ? sf->gpos_lookups : sf->gsub_lookups; test != NULL;
  447. test = test->next)
  448. {
  449. if (test->unused)
  450. continue;
  451. for (fl = test->features; fl != NULL; fl = fl->next)
  452. {
  453. for (sl = fl->scripts; sl != NULL; sl = sl->next)
  454. {
  455. for (i = 0; i < cnt; ++i)
  456. {
  457. if (sl->script == scripts[i])
  458. break;
  459. }
  460. if (i == cnt)
  461. {
  462. if (cnt >= tot)
  463. scripts =
  464. xrealloc (scripts, (tot += 10) * sizeof (uint32_t));
  465. scripts[cnt++] = sl->script;
  466. }
  467. }
  468. }
  469. }
  470. }
  471. if (cnt == 0)
  472. return NULL;
  473. /* We want our scripts in alphabetic order */
  474. qsort (scripts, cnt, sizeof (uint32_t), uint32_cmp);
  475. /* add a 0 entry to mark the end of the list */
  476. if (cnt >= tot)
  477. scripts = xrealloc (scripts, (tot + 1) * sizeof (uint32_t));
  478. scripts[cnt] = 0;
  479. return scripts;
  480. }
  481. uint32_t *
  482. SFLangsInScript (SplineFont *sf, int gpos, uint32_t script)
  483. {
  484. /* However, the language lists (I think) are distinct */
  485. /* But giving a value of -1 for gpos will give us the set of languages in */
  486. /* both tables (for this script) */
  487. int cnt = 0, tot = 0, i, g, l;
  488. uint32_t *langs = NULL;
  489. OTLookup *test;
  490. FeatureScriptLangList *fl;
  491. struct scriptlanglist *sl;
  492. for (g = 0; g < 2; ++g)
  493. {
  494. if ((gpos == 0 && g == 1) || (gpos == 1 && g == 0))
  495. continue;
  496. for (test = g ? sf->gpos_lookups : sf->gsub_lookups; test != NULL;
  497. test = test->next)
  498. {
  499. if (test->unused)
  500. continue;
  501. for (fl = test->features; fl != NULL; fl = fl->next)
  502. {
  503. for (sl = fl->scripts; sl != NULL; sl = sl->next)
  504. {
  505. if (sl->script == script)
  506. {
  507. for (l = 0; l < sl->lang_cnt; ++l)
  508. {
  509. int lang;
  510. if (l < MAX_LANG)
  511. lang = sl->langs[l];
  512. else
  513. lang = sl->morelangs[l - MAX_LANG];
  514. for (i = 0; i < cnt; ++i)
  515. {
  516. if (lang == langs[i])
  517. break;
  518. }
  519. if (i == cnt)
  520. {
  521. if (cnt >= tot)
  522. langs =
  523. xrealloc (langs,
  524. (tot += 10) * sizeof (uint32_t));
  525. langs[cnt++] = lang;
  526. }
  527. }
  528. }
  529. }
  530. }
  531. }
  532. }
  533. if (cnt == 0)
  534. {
  535. /* We add dummy script entries. Because Uniscribe will refuse to */
  536. /* process some scripts if they don't have an entry in both GPOS */
  537. /* an GSUB. So if a script appears in either table, force it to */
  538. /* appear in both. That means we can get scripts with no lookups */
  539. /* and hence no languages. It seems that Uniscribe doesn't like */
  540. /* that either. So give each such script a dummy default language */
  541. /* entry. This is what VOLT does */
  542. langs = xcalloc (2, sizeof (uint32_t));
  543. langs[0] = DEFAULT_LANG;
  544. return langs;
  545. }
  546. /* We want our languages in alphabetic order */
  547. qsort (langs, cnt, sizeof (uint32_t), lang_cmp);
  548. /* add a 0 entry to mark the end of the list */
  549. if (cnt >= tot)
  550. langs = xrealloc (langs, (tot + 1) * sizeof (uint32_t));
  551. langs[cnt] = 0;
  552. return langs;
  553. }
  554. uint32_t *
  555. SFFeaturesInScriptLang (SplineFont *sf, int gpos, uint32_t script,
  556. uint32_t lang)
  557. {
  558. int cnt = 0, tot = 0, i, l, isg;
  559. uint32_t *features = NULL;
  560. OTLookup *test;
  561. FeatureScriptLangList *fl;
  562. struct scriptlanglist *sl;
  563. /* gpos==0 => GSUB, gpos==1 => GPOS, gpos==-1 => both, gpos==-2 => Both & morx & kern */
  564. if (sf->cidmaster)
  565. sf = sf->cidmaster;
  566. for (isg = 0; isg < 2; ++isg)
  567. {
  568. if (gpos >= 0 && isg != gpos)
  569. continue;
  570. for (test = isg ? sf->gpos_lookups : sf->gsub_lookups; test != NULL;
  571. test = test->next)
  572. {
  573. if (test->unused)
  574. continue;
  575. for (fl = test->features; fl != NULL; fl = fl->next)
  576. {
  577. if (script == 0xffffffff)
  578. {
  579. for (i = 0; i < cnt; ++i)
  580. {
  581. if (fl->featuretag == features[i])
  582. break;
  583. }
  584. if (i == cnt)
  585. {
  586. if (cnt >= tot)
  587. features =
  588. xrealloc (features, (tot += 10) * sizeof (uint32_t));
  589. features[cnt++] = fl->featuretag;
  590. }
  591. }
  592. else
  593. for (sl = fl->scripts; sl != NULL; sl = sl->next)
  594. {
  595. if (sl->script == script)
  596. {
  597. int matched = false;
  598. for (l = 0; l < sl->lang_cnt; ++l)
  599. {
  600. int testlang;
  601. if (l < MAX_LANG)
  602. testlang = sl->langs[l];
  603. else
  604. testlang = sl->morelangs[l - MAX_LANG];
  605. if (testlang == lang)
  606. {
  607. matched = true;
  608. break;
  609. }
  610. }
  611. if (matched)
  612. {
  613. for (i = 0; i < cnt; ++i)
  614. {
  615. if (fl->featuretag == features[i])
  616. break;
  617. }
  618. if (i == cnt)
  619. {
  620. if (cnt >= tot)
  621. features =
  622. xrealloc (features,
  623. (tot += 10) * sizeof (uint32_t));
  624. features[cnt++] = fl->featuretag;
  625. }
  626. }
  627. }
  628. }
  629. }
  630. }
  631. }
  632. if (sf->design_size != 0 && gpos)
  633. {
  634. /* The 'size' feature is like no other. It has no lookups and so */
  635. /* we will never find it in the normal course of events. If the */
  636. /* user has specified a design size, then every script/lang combo */
  637. /* gets a 'size' feature which contains no lookups but feature */
  638. /* params */
  639. if (cnt >= tot)
  640. features = xrealloc (features, (tot += 2) * sizeof (uint32_t));
  641. features[cnt++] = CHR ('s', 'i', 'z', 'e');
  642. }
  643. if (cnt == 0)
  644. return xcalloc (1, sizeof (uint32_t));
  645. /* We don't care if our features are in alphabetical order here */
  646. /* all that matters is whether the complete list of features is */
  647. /* ordering here would be irrelevant */
  648. /* qsort(features,cnt,sizeof(uint32_t),uint32_cmp); */
  649. /* add a 0 entry to mark the end of the list */
  650. if (cnt >= tot)
  651. features = xrealloc (features, (tot + 1) * sizeof (uint32_t));
  652. features[cnt] = 0;
  653. return features;
  654. }
  655. OTLookup **
  656. SFLookupsInScriptLangFeature (SplineFont *sf, int gpos, uint32_t script,
  657. uint32_t lang, uint32_t feature)
  658. {
  659. int cnt = 0, tot = 0, l;
  660. OTLookup **lookups = NULL;
  661. OTLookup *test;
  662. FeatureScriptLangList *fl;
  663. struct scriptlanglist *sl;
  664. for (test = gpos ? sf->gpos_lookups : sf->gsub_lookups; test != NULL;
  665. test = test->next)
  666. {
  667. if (test->unused)
  668. continue;
  669. for (fl = test->features; fl != NULL; fl = fl->next)
  670. {
  671. if (fl->featuretag == feature)
  672. {
  673. for (sl = fl->scripts; sl != NULL; sl = sl->next)
  674. {
  675. if (sl->script == script)
  676. {
  677. for (l = 0; l < sl->lang_cnt; ++l)
  678. {
  679. int testlang;
  680. if (l < MAX_LANG)
  681. testlang = sl->langs[l];
  682. else
  683. testlang = sl->morelangs[l - MAX_LANG];
  684. if (testlang == lang)
  685. {
  686. if (cnt >= tot)
  687. lookups =
  688. xrealloc (lookups,
  689. (tot += 10) * sizeof (OTLookup *));
  690. lookups[cnt++] = test;
  691. goto found;
  692. }
  693. }
  694. }
  695. }
  696. }
  697. }
  698. found:;
  699. }
  700. if (cnt == 0)
  701. return NULL;
  702. /* lookup order is irrelevant here. might as well leave it in invocation order */
  703. /* add a 0 entry to mark the end of the list */
  704. if (cnt >= tot)
  705. lookups = xrealloc (lookups, (tot + 1) * sizeof (OTLookup *));
  706. lookups[cnt] = 0;
  707. return lookups;
  708. }
  709. static int
  710. LigaturesFirstComponentGID (SplineFont *sf, char *components)
  711. {
  712. int gid, ch;
  713. char *pt;
  714. for (pt = components; *pt != '\0' && *pt != ' '; ++pt);
  715. ch = *pt;
  716. *pt = '\0';
  717. gid = SFFindExistingSlot (sf, -1, components);
  718. *pt = ch;
  719. return gid;
  720. }
  721. static int
  722. PSTValid (SplineFont *sf, PST *pst)
  723. {
  724. char *start, *pt, ch;
  725. int ret;
  726. switch (pst->type)
  727. {
  728. case pst_position:
  729. return true;
  730. case pst_pair:
  731. return SCWorthOutputting (SFGetChar (sf, -1, pst->u.pair.paired));
  732. case pst_substitution:
  733. case pst_alternate:
  734. case pst_multiple:
  735. case pst_ligature:
  736. for (start = pst->u.mult.components; *start;)
  737. {
  738. for (pt = start; *pt && *pt != ' '; ++pt);
  739. ch = *pt;
  740. *pt = '\0';
  741. ret = SCWorthOutputting (SFGetChar (sf, -1, start));
  742. *pt = ch;
  743. if (!ret)
  744. return false;
  745. if (ch == 0)
  746. start = pt;
  747. else
  748. start = pt + 1;
  749. }
  750. }
  751. return true;
  752. }
  753. SplineChar **
  754. SFGlyphsWithPSTinSubtable (SplineFont *sf, struct lookup_subtable *subtable)
  755. {
  756. uint8_t *used = xcalloc (sf->glyphcnt, sizeof (uint8_t));
  757. SplineChar **glyphs, *sc;
  758. int i, k, gid, cnt;
  759. KernPair *kp;
  760. PST *pst;
  761. int ispair = subtable->lookup->lookup_type == gpos_pair;
  762. int isliga = subtable->lookup->lookup_type == gsub_ligature;
  763. for (i = 0; i < sf->glyphcnt; ++i)
  764. if (SCWorthOutputting (sc = sf->glyphs[i]))
  765. {
  766. if (ispair)
  767. {
  768. for (k = 0; k < 2; ++k)
  769. {
  770. for (kp = k ? sc->kerns : sc->vkerns; kp != NULL; kp = kp->next)
  771. {
  772. if (!SCWorthOutputting (kp->sc))
  773. continue;
  774. if (kp->subtable == subtable)
  775. {
  776. used[i] = true;
  777. goto continue_;
  778. }
  779. }
  780. }
  781. }
  782. for (pst = sc->possub; pst != NULL; pst = pst->next)
  783. {
  784. if (pst->subtable == subtable && PSTValid (sf, pst))
  785. {
  786. if (!isliga)
  787. {
  788. used[i] = true;
  789. goto continue_;
  790. }
  791. else
  792. {
  793. gid =
  794. LigaturesFirstComponentGID (sf, pst->u.lig.components);
  795. pst->u.lig.lig = sc;
  796. if (gid != -1)
  797. used[gid] = true;
  798. /* can't continue here. ffi might be "f+f+i" and "ff+i" */
  799. /* and we need to mark both "f" and "ff" as used */
  800. }
  801. }
  802. }
  803. continue_:;
  804. }
  805. for (i = cnt = 0; i < sf->glyphcnt; ++i)
  806. if (used[i])
  807. ++cnt;
  808. if (cnt == 0)
  809. {
  810. free (used);
  811. return NULL;
  812. }
  813. glyphs = xmalloc ((cnt + 1) * sizeof (SplineChar *));
  814. for (i = cnt = 0; i < sf->glyphcnt; ++i)
  815. {
  816. if (used[i])
  817. glyphs[cnt++] = sf->glyphs[i];
  818. }
  819. glyphs[cnt] = NULL;
  820. free (used);
  821. return glyphs;
  822. }
  823. SplineChar **
  824. SFGlyphsWithLigatureinLookup (SplineFont *sf, struct lookup_subtable *subtable)
  825. {
  826. uint8_t *used = xcalloc (sf->glyphcnt, sizeof (uint8_t));
  827. SplineChar **glyphs, *sc;
  828. int i, cnt;
  829. PST *pst;
  830. for (i = 0; i < sf->glyphcnt; ++i)
  831. if (SCWorthOutputting (sc = sf->glyphs[i]))
  832. {
  833. for (pst = sc->possub; pst != NULL; pst = pst->next)
  834. {
  835. if (pst->subtable == subtable)
  836. {
  837. used[i] = true;
  838. goto continue_;
  839. }
  840. }
  841. continue_:;
  842. }
  843. for (i = cnt = 0; i < sf->glyphcnt; ++i)
  844. if (used[i])
  845. ++cnt;
  846. if (cnt == 0)
  847. {
  848. free (used);
  849. return NULL;
  850. }
  851. glyphs = xmalloc ((cnt + 1) * sizeof (SplineChar *));
  852. for (i = cnt = 0; i < sf->glyphcnt; ++i)
  853. {
  854. if (used[i])
  855. glyphs[cnt++] = sf->glyphs[i];
  856. }
  857. glyphs[cnt] = NULL;
  858. free (used);
  859. return glyphs;
  860. }
  861. static void
  862. TickLookupKids (OTLookup *otl)
  863. {
  864. struct lookup_subtable *sub;
  865. int i, j;
  866. for (sub = otl->subtables; sub != NULL; sub = sub->next)
  867. {
  868. if (sub->fpst != NULL)
  869. {
  870. for (i = 0; i < sub->fpst->rule_cnt; ++i)
  871. {
  872. struct fpst_rule *rule = &sub->fpst->rules[i];
  873. for (j = 0; j < rule->lookup_cnt; ++j)
  874. {
  875. if (rule->lookups[j].lookup != NULL)
  876. rule->lookups[j].lookup->in_gpos = true;
  877. }
  878. }
  879. }
  880. }
  881. }
  882. void
  883. SFFindUnusedLookups (SplineFont *sf)
  884. {
  885. OTLookup *test;
  886. struct lookup_subtable *sub;
  887. int gpos;
  888. AnchorClass *ac;
  889. AnchorPoint *ap;
  890. SplineChar *sc;
  891. KernPair *kp;
  892. PST *pst;
  893. int i, k, gid, isv;
  894. SplineFont *_sf = sf;
  895. Justify *jscripts;
  896. struct jstf_lang *jlangs;
  897. if (_sf->cidmaster)
  898. _sf = _sf->cidmaster;
  899. /* Some things are obvious. If a subtable consists of a kernclass or some */
  900. /* such, then obviously it is used. But more distributed info takes more */
  901. /* work. So mark anything easy as used, and anything difficult as unused */
  902. /* We'll work on the difficult things later */
  903. for (gpos = 0; gpos < 2; ++gpos)
  904. {
  905. for (test = gpos ? _sf->gpos_lookups : _sf->gsub_lookups; test != NULL;
  906. test = test->next)
  907. {
  908. for (sub = test->subtables; sub != NULL; sub = sub->next)
  909. {
  910. if (sub->kc != NULL || sub->fpst != NULL)
  911. {
  912. sub->unused = false;
  913. continue;
  914. }
  915. sub->unused = true;
  916. /* We'll turn the following bit back on if there turns out */
  917. /* to be an anchor class attached to it -- that is subtly */
  918. /* different than being unused -- unused will be set if all */
  919. /* acs are unused, this bit will be on if there are unused */
  920. /* classes that still refer to us. */
  921. sub->anchor_classes = false;
  922. }
  923. }
  924. }
  925. /* To be useful an anchor class must have both at least one base and one mark */
  926. /* (for cursive anchors that means at least one entry and at least one exit) */
  927. /* Start by assuming the worst */
  928. for (ac = _sf->anchor; ac != NULL; ac = ac->next)
  929. ac->has_mark = ac->has_base = false;
  930. /* Ok, for each glyph, look at all lookups (or anchor classes) it affects */
  931. /* and mark the appropriate parts of them as used */
  932. k = 0;
  933. do
  934. {
  935. sf = _sf->subfontcnt == 0 ? _sf : _sf->subfonts[k];
  936. for (gid = 0; gid < sf->glyphcnt; ++gid)
  937. if (SCWorthOutputting (sc = sf->glyphs[gid]))
  938. {
  939. for (ap = sc->anchor; ap != NULL; ap = ap->next)
  940. {
  941. switch (ap->type)
  942. {
  943. case at_mark:
  944. case at_centry:
  945. ap->anchor->has_mark = true;
  946. break;
  947. case at_basechar:
  948. case at_baselig:
  949. case at_basemark:
  950. case at_cexit:
  951. ap->anchor->has_base = true;
  952. break;
  953. }
  954. }
  955. for (isv = 0; isv < 2; ++isv)
  956. {
  957. for (kp = isv ? sc->kerns : sc->vkerns; kp != NULL;
  958. kp = kp->next)
  959. {
  960. if (SCWorthOutputting (kp->sc))
  961. kp->subtable->unused = false;
  962. }
  963. }
  964. for (pst = sc->possub; pst != NULL; pst = pst->next)
  965. {
  966. if (pst->subtable == NULL)
  967. continue;
  968. if (!PSTValid (sf, pst))
  969. continue;
  970. pst->subtable->unused = false;
  971. }
  972. }
  973. ++k;
  974. }
  975. while (k < _sf->subfontcnt);
  976. /* Finally for any anchor class that has both a mark and a base then it is */
  977. /* used, and its lookup is also used */
  978. /* Also, even if unused, as long as the anchor class exists we must keep */
  979. /* the subtable around */
  980. for (ac = _sf->anchor; ac != NULL; ac = ac->next)
  981. {
  982. ac->subtable->anchor_classes = true;
  983. if (ac->has_mark && ac->has_base)
  984. ac->subtable->unused = false;
  985. }
  986. /* Now for each lookup, a lookup is unused if ALL subtables are unused */
  987. for (gpos = 0; gpos < 2; ++gpos)
  988. {
  989. for (test = gpos ? _sf->gpos_lookups : _sf->gsub_lookups; test != NULL;
  990. test = test->next)
  991. {
  992. test->unused = test->empty = true;
  993. for (sub = test->subtables; sub != NULL; sub = sub->next)
  994. {
  995. if (!sub->unused)
  996. test->unused = false;
  997. if (!sub->unused && !sub->anchor_classes)
  998. {
  999. test->empty = false;
  1000. break;
  1001. }
  1002. }
  1003. }
  1004. }
  1005. /* I store JSTF max lookups in the gpos list because they have the same */
  1006. /* format. But now I need to tease them out and learn which lookups are */
  1007. /* used in GPOS and which in JSTF (and conceivably which get duplicated */
  1008. /* and placed in both) */
  1009. for (test = sf->gpos_lookups; test != NULL; test = test->next)
  1010. {
  1011. test->only_jstf = test->in_jstf = test->in_gpos = false;
  1012. if (test->features != NULL)
  1013. test->in_gpos = true;
  1014. }
  1015. for (jscripts = sf->justify; jscripts != NULL; jscripts = jscripts->next)
  1016. {
  1017. for (jlangs = jscripts->langs; jlangs != NULL; jlangs = jlangs->next)
  1018. {
  1019. for (i = 0; i < jlangs->cnt; ++i)
  1020. {
  1021. struct jstf_prio *prio = &jlangs->prios[i];
  1022. if (prio->enableShrink != NULL)
  1023. for (k = 0; prio->enableShrink[k] != NULL; ++k)
  1024. prio->enableShrink[k]->in_gpos = true;
  1025. if (prio->disableShrink != NULL)
  1026. for (k = 0; prio->disableShrink[k] != NULL; ++k)
  1027. prio->disableShrink[k]->in_gpos = true;
  1028. if (prio->enableExtend != NULL)
  1029. for (k = 0; prio->enableExtend[k] != NULL; ++k)
  1030. prio->enableExtend[k]->in_gpos = true;
  1031. if (prio->disableExtend != NULL)
  1032. for (k = 0; prio->disableExtend[k] != NULL; ++k)
  1033. prio->disableExtend[k]->in_gpos = true;
  1034. if (prio->maxShrink != NULL)
  1035. for (k = 0; prio->maxShrink[k] != NULL; ++k)
  1036. prio->maxShrink[k]->in_jstf = true;
  1037. if (prio->maxExtend != NULL)
  1038. for (k = 0; prio->maxExtend[k] != NULL; ++k)
  1039. prio->maxExtend[k]->in_jstf = true;
  1040. }
  1041. }
  1042. }
  1043. for (test = sf->gpos_lookups; test != NULL; test = test->next)
  1044. {
  1045. if (test->in_gpos
  1046. && (test->lookup_type == gpos_context
  1047. || test->lookup_type == gpos_contextchain))
  1048. TickLookupKids (test);
  1049. }
  1050. for (test = sf->gpos_lookups; test != NULL; test = test->next)
  1051. test->only_jstf = test->in_jstf && !test->in_gpos;
  1052. }
  1053. void
  1054. SFFindClearUnusedLookupBits (SplineFont *sf)
  1055. {
  1056. OTLookup *test;
  1057. int gpos;
  1058. for (gpos = 0; gpos < 2; ++gpos)
  1059. {
  1060. for (test = gpos ? sf->gpos_lookups : sf->gsub_lookups; test != NULL;
  1061. test = test->next)
  1062. {
  1063. test->unused = false;
  1064. test->empty = false;
  1065. test->def_lang_checked = false;
  1066. }
  1067. }
  1068. }
  1069. static void
  1070. SFRemoveAnchorPointsOfAC (SplineFont *sf, AnchorClass * ac)
  1071. {
  1072. int gid;
  1073. SplineChar *sc;
  1074. AnchorPoint *ap, *prev, *next;
  1075. for (gid = 0; gid < sf->glyphcnt; ++gid)
  1076. if ((sc = sf->glyphs[gid]) != NULL)
  1077. {
  1078. for (prev = NULL, ap = sc->anchor; ap != NULL; ap = next)
  1079. {
  1080. next = ap->next;
  1081. if (ap->anchor != ac)
  1082. prev = ap;
  1083. else
  1084. {
  1085. if (prev == NULL)
  1086. sc->anchor = next;
  1087. else
  1088. prev->next = next;
  1089. ap->next = NULL;
  1090. AnchorPointsFree (ap);
  1091. }
  1092. }
  1093. }
  1094. }
  1095. static OTLookup **
  1096. RemoveFromList (OTLookup **list, OTLookup *dying)
  1097. {
  1098. int i, j;
  1099. if (list == NULL)
  1100. return NULL;
  1101. for (i = 0; list[i] != NULL; ++i)
  1102. {
  1103. if (list[i] == dying)
  1104. {
  1105. for (j = i + 1;; ++j)
  1106. {
  1107. list[j - 1] = list[j];
  1108. if (list[j] == NULL)
  1109. break;
  1110. }
  1111. }
  1112. }
  1113. if (list[0] == NULL)
  1114. {
  1115. free (list);
  1116. return NULL;
  1117. }
  1118. return list;
  1119. }
  1120. static void
  1121. RemoveJSTFReferences (SplineFont *sf, OTLookup *dying)
  1122. {
  1123. Justify *jscript;
  1124. struct jstf_lang *jlang;
  1125. int i;
  1126. for (jscript = sf->justify; jscript != NULL; jscript = jscript->next)
  1127. {
  1128. for (jlang = jscript->langs; jlang != NULL; jlang = jlang->next)
  1129. {
  1130. for (i = 0; i < jlang->cnt; ++i)
  1131. {
  1132. struct jstf_prio *prio = &jlang->prios[i];
  1133. prio->enableShrink = RemoveFromList (prio->enableShrink, dying);
  1134. prio->disableShrink = RemoveFromList (prio->disableShrink, dying);
  1135. prio->enableExtend = RemoveFromList (prio->enableExtend, dying);
  1136. prio->disableExtend = RemoveFromList (prio->disableExtend, dying);
  1137. prio->maxShrink = RemoveFromList (prio->maxShrink, dying);
  1138. prio->maxExtend = RemoveFromList (prio->maxExtend, dying);
  1139. }
  1140. }
  1141. }
  1142. }
  1143. static void
  1144. RemoveNestedReferences (SplineFont *sf, int isgpos, OTLookup *dying)
  1145. {
  1146. OTLookup *otl;
  1147. struct lookup_subtable *sub;
  1148. int i, j, k;
  1149. for (otl = isgpos ? sf->gpos_lookups : sf->gsub_lookups; otl != NULL;
  1150. otl = otl->next)
  1151. {
  1152. /* Reverse chaining tables do not reference lookups. The match pattern */
  1153. /* is a (exactly one) coverage table, and each glyph in that table */
  1154. /* as an inline replacement. There is no lookup to do the replacement */
  1155. /* (so we ignore it here) */
  1156. if (otl->lookup_type == gsub_context
  1157. || otl->lookup_type == gsub_contextchain
  1158. || otl->lookup_type == gpos_context
  1159. || otl->lookup_type == gpos_contextchain)
  1160. {
  1161. for (sub = otl->subtables; sub != NULL; sub = sub->next)
  1162. {
  1163. FPST *fpst = sub->fpst;
  1164. for (i = 0; i < fpst->rule_cnt; ++i)
  1165. {
  1166. for (j = 0; j < fpst->rules[i].lookup_cnt; ++j)
  1167. {
  1168. if (fpst->rules[i].lookups[j].lookup == otl)
  1169. {
  1170. for (k = j + 1; k < fpst->rules[i].lookup_cnt; ++k)
  1171. fpst->rules[i].lookups[k - 1] =
  1172. fpst->rules[i].lookups[k];
  1173. --fpst->rules[i].lookup_cnt;
  1174. --j;
  1175. }
  1176. }
  1177. }
  1178. }
  1179. }
  1180. }
  1181. }
  1182. void
  1183. SFRemoveUnusedLookupSubTables (SplineFont *sf,
  1184. int remove_incomplete_anchorclasses,
  1185. int remove_unused_lookups)
  1186. {
  1187. int gpos;
  1188. struct lookup_subtable *sub, *subnext, *prev;
  1189. AnchorClass *ac, *acprev, *acnext;
  1190. OTLookup *otl, *otlprev, *otlnext;
  1191. /* Presumes someone has called SFFindUnusedLookups first */
  1192. if (remove_incomplete_anchorclasses)
  1193. {
  1194. for (acprev = NULL, ac = sf->anchor; ac != NULL; ac = acnext)
  1195. {
  1196. acnext = ac->next;
  1197. if (ac->has_mark && ac->has_base)
  1198. acprev = ac;
  1199. else
  1200. {
  1201. SFRemoveAnchorPointsOfAC (sf, ac);
  1202. ac->next = NULL;
  1203. AnchorClassesFree (ac);
  1204. if (acprev == NULL)
  1205. sf->anchor = acnext;
  1206. else
  1207. acprev = acnext;
  1208. }
  1209. }
  1210. }
  1211. for (gpos = 0; gpos < 2; ++gpos)
  1212. {
  1213. for (otl = gpos ? sf->gpos_lookups : sf->gsub_lookups; otl != NULL;
  1214. otl = otlnext)
  1215. {
  1216. otlnext = otl->next;
  1217. if (remove_unused_lookups && (otl->empty ||
  1218. (otl->unused
  1219. && remove_incomplete_anchorclasses)))
  1220. {
  1221. if (otlprev != NULL)
  1222. otlprev->next = otlnext;
  1223. else if (gpos)
  1224. sf->gpos_lookups = otlnext;
  1225. else
  1226. sf->gsub_lookups = otlnext;
  1227. RemoveNestedReferences (sf, gpos, otl);
  1228. OTLookupFree (otl);
  1229. }
  1230. else
  1231. {
  1232. for (prev = NULL, sub = otl->subtables; sub != NULL;
  1233. sub = subnext)
  1234. {
  1235. subnext = sub->next;
  1236. if (sub->unused &&
  1237. (!sub->anchor_classes || remove_incomplete_anchorclasses))
  1238. {
  1239. if (prev == NULL)
  1240. otl->subtables = subnext;
  1241. else
  1242. prev->next = subnext;
  1243. free (sub->subtable_name);
  1244. free (sub);
  1245. }
  1246. else
  1247. prev = sub;
  1248. }
  1249. }
  1250. }
  1251. }
  1252. }
  1253. void
  1254. SFRemoveLookupSubTable (SplineFont *sf, struct lookup_subtable *sub)
  1255. {
  1256. OTLookup *otl = sub->lookup;
  1257. struct lookup_subtable *subprev, *subtest;
  1258. if (sf->cidmaster != NULL)
  1259. sf = sf->cidmaster;
  1260. if (sub->fpst != NULL)
  1261. {
  1262. FPST *prev = NULL, *test;
  1263. for (test = sf->possub; test != NULL && test != sub->fpst;
  1264. prev = test, test = test->next);
  1265. if (prev == NULL)
  1266. sf->possub = sub->fpst->next;
  1267. else
  1268. prev->next = sub->fpst->next;
  1269. sub->fpst->next = NULL;
  1270. FPSTFree (sub->fpst);
  1271. sub->fpst = NULL;
  1272. }
  1273. else if (sub->kc != NULL)
  1274. {
  1275. KernClass *prev = NULL, *test;
  1276. for (test = sf->kerns; test != NULL && test != sub->kc;
  1277. prev = test, test = test->next);
  1278. if (test != NULL)
  1279. {
  1280. if (prev == NULL)
  1281. sf->kerns = sub->kc->next;
  1282. else
  1283. prev->next = sub->kc->next;
  1284. }
  1285. else
  1286. {
  1287. for (prev = NULL, test = sf->vkerns; test != NULL && test != sub->kc;
  1288. prev = test, test = test->next);
  1289. if (prev == NULL)
  1290. sf->vkerns = sub->kc->next;
  1291. else
  1292. prev->next = sub->kc->next;
  1293. }
  1294. sub->kc->next = NULL;
  1295. KernClassListFree (sub->kc);
  1296. sub->kc = NULL;
  1297. }
  1298. else if (otl->lookup_type == gpos_cursive
  1299. || otl->lookup_type == gpos_mark2base
  1300. || otl->lookup_type == gpos_mark2ligature
  1301. || otl->lookup_type == gpos_mark2mark)
  1302. {
  1303. AnchorClass *ac, *acnext;
  1304. for (ac = sf->anchor; ac != NULL; ac = acnext)
  1305. {
  1306. acnext = ac->next;
  1307. if (ac->subtable == sub)
  1308. SFRemoveAnchorClass (sf, ac);
  1309. }
  1310. }
  1311. else
  1312. {
  1313. int i, k, v;
  1314. SplineChar *sc;
  1315. SplineFont *_sf;
  1316. PST *pst, *prev, *next;
  1317. KernPair *kp, *kpprev, *kpnext;
  1318. k = 0;
  1319. do
  1320. {
  1321. _sf = sf->subfontcnt == 0 ? sf : sf->subfonts[i];
  1322. for (i = 0; i < _sf->glyphcnt; ++i)
  1323. if ((sc = _sf->glyphs[i]) != NULL)
  1324. {
  1325. for (pst = sc->possub, prev = NULL; pst != NULL; pst = next)
  1326. {
  1327. next = pst->next;
  1328. if (pst->subtable == sub)
  1329. {
  1330. if (prev == NULL)
  1331. sc->possub = next;
  1332. else
  1333. prev->next = next;
  1334. pst->next = NULL;
  1335. PSTFree (pst);
  1336. }
  1337. else
  1338. prev = pst;
  1339. }
  1340. for (v = 0; v < 2; ++v)
  1341. {
  1342. for (kp = v ? sc->vkerns : sc->kerns, kpprev = NULL;
  1343. kp != NULL; kp = kpnext)
  1344. {
  1345. kpnext = kp->next;
  1346. if (kp->subtable == sub)
  1347. {
  1348. if (kpprev != NULL)
  1349. kpprev->next = kpnext;
  1350. else if (v)
  1351. sc->vkerns = kpnext;
  1352. else
  1353. sc->kerns = kpnext;
  1354. kp->next = NULL;
  1355. KernPairsFree (kp);
  1356. }
  1357. else
  1358. kpprev = kp;
  1359. }
  1360. }
  1361. }
  1362. ++k;
  1363. }
  1364. while (k < sf->subfontcnt);
  1365. }
  1366. subprev = NULL;
  1367. for (subtest = otl->subtables; subtest != NULL && subtest != sub;
  1368. subprev = subtest, subtest = subtest->next);
  1369. if (subprev == NULL)
  1370. otl->subtables = sub->next;
  1371. else
  1372. subprev->next = sub->next;
  1373. free (sub->subtable_name);
  1374. free (sub->suffix);
  1375. free (sub);
  1376. }
  1377. void
  1378. SFRemoveLookup (SplineFont *sf, OTLookup *otl)
  1379. {
  1380. OTLookup *test, *prev;
  1381. int isgpos;
  1382. struct lookup_subtable *sub, *subnext;
  1383. if (sf->cidmaster)
  1384. sf = sf->cidmaster;
  1385. for (sub = otl->subtables; sub != NULL; sub = subnext)
  1386. {
  1387. subnext = sub->next;
  1388. SFRemoveLookupSubTable (sf, sub);
  1389. }
  1390. for (prev = NULL, test = sf->gpos_lookups; test != NULL && test != otl;
  1391. prev = test, test = test->next);
  1392. if (test == NULL)
  1393. {
  1394. isgpos = false;
  1395. for (prev = NULL, test = sf->gsub_lookups; test != NULL && test != otl;
  1396. prev = test, test = test->next);
  1397. }
  1398. else
  1399. isgpos = true;
  1400. if (prev != NULL)
  1401. prev->next = otl->next;
  1402. else if (isgpos)
  1403. sf->gpos_lookups = otl->next;
  1404. else
  1405. sf->gsub_lookups = otl->next;
  1406. RemoveNestedReferences (sf, isgpos, otl);
  1407. RemoveJSTFReferences (sf, otl);
  1408. otl->next = NULL;
  1409. OTLookupFree (otl);
  1410. }
  1411. struct lookup_subtable *
  1412. SFFindLookupSubtable (SplineFont *sf, char *name)
  1413. {
  1414. int isgpos;
  1415. OTLookup *otl;
  1416. struct lookup_subtable *sub;
  1417. if (sf->cidmaster)
  1418. sf = sf->cidmaster;
  1419. if (name == NULL)
  1420. return NULL;
  1421. for (isgpos = 0; isgpos < 2; ++isgpos)
  1422. {
  1423. for (otl = isgpos ? sf->gpos_lookups : sf->gsub_lookups; otl != NULL;
  1424. otl = otl->next)
  1425. {
  1426. for (sub = otl->subtables; sub != NULL; sub = sub->next)
  1427. {
  1428. if (strcmp (name, sub->subtable_name) == 0)
  1429. return sub;
  1430. }
  1431. }
  1432. }
  1433. return NULL;
  1434. }
  1435. struct lookup_subtable *
  1436. SFFindLookupSubtableAndFreeName (SplineFont *sf, char *name)
  1437. {
  1438. struct lookup_subtable *sub = SFFindLookupSubtable (sf, name);
  1439. free (name);
  1440. return sub;
  1441. }
  1442. OTLookup *
  1443. SFFindLookup (SplineFont *sf, char *name)
  1444. {
  1445. int isgpos;
  1446. OTLookup *otl;
  1447. if (sf->cidmaster)
  1448. sf = sf->cidmaster;
  1449. if (name == NULL)
  1450. return NULL;
  1451. for (isgpos = 0; isgpos < 2; ++isgpos)
  1452. {
  1453. for (otl = isgpos ? sf->gpos_lookups : sf->gsub_lookups; otl != NULL;
  1454. otl = otl->next)
  1455. {
  1456. if (strcmp (name, otl->lookup_name) == 0)
  1457. return otl;
  1458. }
  1459. }
  1460. return NULL;
  1461. }
  1462. void
  1463. FListAppendScriptLang (FeatureScriptLangList *fl, uint32_t script_tag,
  1464. uint32_t lang_tag)
  1465. {
  1466. struct scriptlanglist *sl;
  1467. int l;
  1468. for (sl = fl->scripts; sl != NULL && sl->script != script_tag; sl = sl->next);
  1469. if (sl == NULL)
  1470. {
  1471. sl = xzalloc (sizeof (struct scriptlanglist));
  1472. sl->script = script_tag;
  1473. sl->next = fl->scripts;
  1474. fl->scripts = sl;
  1475. }
  1476. for (l = 0; l < MAX_LANG && l < sl->lang_cnt && sl->langs[l] != lang_tag;
  1477. ++l);
  1478. if (l >= MAX_LANG && l < sl->lang_cnt)
  1479. {
  1480. while (l < sl->lang_cnt && sl->morelangs[l - MAX_LANG] != lang_tag)
  1481. ++l;
  1482. }
  1483. if (l >= sl->lang_cnt)
  1484. {
  1485. if (l < MAX_LANG)
  1486. sl->langs[l] = lang_tag;
  1487. else
  1488. {
  1489. if (l % MAX_LANG == 0)
  1490. sl->morelangs = xrealloc (sl->morelangs, l * sizeof (uint32_t));
  1491. /* We've just allocated MAX_LANG-1 more than we need */
  1492. /* so we don't do quite some many allocations */
  1493. sl->morelangs[l - MAX_LANG] = lang_tag;
  1494. }
  1495. ++sl->lang_cnt;
  1496. }
  1497. }
  1498. void
  1499. FListsAppendScriptLang (FeatureScriptLangList *fl, uint32_t script_tag,
  1500. uint32_t lang_tag)
  1501. {
  1502. while (fl != NULL)
  1503. {
  1504. FListAppendScriptLang (fl, script_tag, lang_tag);
  1505. fl = fl->next;
  1506. }
  1507. }
  1508. char *
  1509. SuffixFromTags (FeatureScriptLangList *fl)
  1510. {
  1511. static struct
  1512. {
  1513. uint32_t tag;
  1514. char *suffix;
  1515. } tags2suffix[] =
  1516. {
  1517. {
  1518. CHR ('v', 'r', 't', '2'), "vert"}, /* Will check for vrt2 later */
  1519. {
  1520. CHR ('o', 'n', 'u', 'm'), "oldstyle"},
  1521. {
  1522. CHR ('s', 'u', 'p', 's'), "superior"},
  1523. {
  1524. CHR ('s', 'u', 'b', 's'), "inferior"},
  1525. {
  1526. CHR ('s', 'w', 's', 'h'), "swash"},
  1527. {
  1528. CHR ('f', 'w', 'i', 'd'), "full"},
  1529. {
  1530. CHR ('h', 'w', 'i', 'd'), "hw"},
  1531. {
  1532. 0, NULL}
  1533. };
  1534. int i;
  1535. while (fl != NULL)
  1536. {
  1537. for (i = 0; tags2suffix[i].tag != 0; ++i)
  1538. if (tags2suffix[i].tag == fl->featuretag)
  1539. return xstrdup_or_null (tags2suffix[i].suffix);
  1540. fl = fl->next;
  1541. }
  1542. return NULL;
  1543. }
  1544. char *lookup_type_names[2][10] = {
  1545. {N_("Undefined substitution"), N_("Single Substitution"),
  1546. N_("Multiple Substitution"),
  1547. N_("Alternate Substitution"), N_("Ligature Substitution"),
  1548. N_("Contextual Substitution"),
  1549. N_("Contextual Chaining Substitution"), N_("Extension"),
  1550. N_("Reverse Contextual Chaining Substitution")},
  1551. {N_("Undefined positioning"), N_("Single Positioning"),
  1552. N_("Pairwise Positioning (kerning)"),
  1553. N_("Cursive attachment"), N_("Mark to base attachment"),
  1554. N_("Mark to Ligature attachment"), N_("Mark to Mark attachment"),
  1555. N_("Contextual Positioning"), N_("Contextual Chaining Positioning"),
  1556. N_("Extension")}
  1557. };
  1558. /* This is a non-ui based copy of a similar list in lookupui.c */
  1559. static struct
  1560. {
  1561. char *text;
  1562. uint32_t tag;
  1563. } localscripts[] =
  1564. {
  1565. {
  1566. NC_ ("Script", "Arabic"), CHR ('a', 'r', 'a', 'b')},
  1567. {
  1568. NC_ ("Script", "Aramaic"), CHR ('a', 'r', 'a', 'm')},
  1569. {
  1570. NC_ ("Script", "Armenian"), CHR ('a', 'r', 'm', 'n')},
  1571. {
  1572. NC_ ("Script", "Avestan"), CHR ('a', 'v', 'e', 's')},
  1573. {
  1574. NC_ ("Script", "Balinese"), CHR ('b', 'a', 'l', 'i')},
  1575. {
  1576. NC_ ("Script", "Batak"), CHR ('b', 'a', 't', 'k')},
  1577. {
  1578. NC_ ("Script", "Bengali"), CHR ('b', 'e', 'n', 'g')},
  1579. {
  1580. NC_ ("Script", "Bengali2"), CHR ('b', 'n', 'g', '2')},
  1581. {
  1582. NC_ ("Script", "Bliss Symbolics"), CHR ('b', 'l', 'i', 's')},
  1583. {
  1584. NC_ ("Script", "Bopomofo"), CHR ('b', 'o', 'p', 'o')},
  1585. {
  1586. NC_ ("Script", "Brāhmī"), CHR ('b', 'r', 'a', 'h')},
  1587. {
  1588. NC_ ("Script", "Braille"), CHR ('b', 'r', 'a', 'i')},
  1589. {
  1590. NC_ ("Script", "Buginese"), CHR ('b', 'u', 'g', 'i')},
  1591. {
  1592. NC_ ("Script", "Buhid"), CHR ('b', 'u', 'h', 'd')},
  1593. {
  1594. NC_ ("Script", "Byzantine Music"), CHR ('b', 'y', 'z', 'm')},
  1595. {
  1596. NC_ ("Script", "Canadian Syllabics"), CHR ('c', 'a', 'n', 's')},
  1597. {
  1598. NC_ ("Script", "Carian"), CHR ('c', 'a', 'r', 'i')},
  1599. {
  1600. NC_ ("Script", "Cherokee"), CHR ('c', 'h', 'a', 'm')},
  1601. {
  1602. NC_ ("Script", "Cham"), CHR ('c', 'h', 'a', 'm')},
  1603. {
  1604. NC_ ("Script", "Cherokee"), CHR ('c', 'h', 'e', 'r')},
  1605. {
  1606. NC_ ("Script", "Cirth"), CHR ('c', 'i', 'r', 't')},
  1607. {
  1608. NC_ ("Script", "CJK Ideographic"), CHR ('h', 'a', 'n', 'i')},
  1609. {
  1610. NC_ ("Script", "Coptic"), CHR ('c', 'o', 'p', 't')},
  1611. {
  1612. NC_ ("Script", "Cypro-Minoan"), CHR ('c', 'p', 'r', 't')},
  1613. {
  1614. NC_ ("Script", "Cypriot syllabary"), CHR ('c', 'p', 'm', 'n')},
  1615. {
  1616. NC_ ("Script", "Cyrillic"), CHR ('c', 'y', 'r', 'l')},
  1617. {
  1618. NC_ ("Script", "Default"), CHR ('D', 'F', 'L', 'T')},
  1619. {
  1620. NC_ ("Script", "Deseret (Mormon)"), CHR ('d', 's', 'r', 't')},
  1621. {
  1622. NC_ ("Script", "Devanagari"), CHR ('d', 'e', 'v', 'a')},
  1623. {
  1624. NC_ ("Script", "Devanagari2"), CHR ('d', 'e', 'v', '2')},
  1625. /* { NC_("Script", "Egyptian demotic"), CHR('e','g','y','d') }, */
  1626. /* { NC_("Script", "Egyptian hieratic"), CHR('e','g','y','h') }, */
  1627. /* TRANSLATORS:
  1628. * Someone asked if FontForge actually was prepared generate hieroglyph output
  1629. * because of this string. No. But OpenType and Unicode have placeholders for
  1630. * dealing with these scripts against the day someone wants to use them. So
  1631. * FontForge must be prepared to deal with those placeholders if nothing else.
  1632. */
  1633. /* { NC_("Script", "Egyptian hieroglyphs"), CHR('e','g','y','p') }, */
  1634. {
  1635. NC_ ("Script", "Ethiopic"), CHR ('e', 't', 'h', 'i')},
  1636. {
  1637. NC_ ("Script", "Georgian"), CHR ('g', 'e', 'o', 'r')},
  1638. {
  1639. NC_ ("Script", "Glagolitic"), CHR ('g', 'l', 'a', 'g')},
  1640. {
  1641. NC_ ("Script", "Gothic"), CHR ('g', 'o', 't', 'h')},
  1642. {
  1643. NC_ ("Script", "Greek"), CHR ('g', 'r', 'e', 'k')},
  1644. {
  1645. NC_ ("Script", "Gujarati"), CHR ('g', 'u', 'j', 'r')},
  1646. {
  1647. NC_ ("Script", "Gujarati2"), CHR ('g', 'j', 'r', '2')},
  1648. {
  1649. NC_ ("Script", "Gurmukhi"), CHR ('g', 'u', 'r', 'u')},
  1650. {
  1651. NC_ ("Script", "Gurmukhi2"), CHR ('g', 'u', 'r', '2')},
  1652. {
  1653. NC_ ("Script", "Hangul Jamo"), CHR ('j', 'a', 'm', 'o')},
  1654. {
  1655. NC_ ("Script", "Hangul"), CHR ('h', 'a', 'n', 'g')},
  1656. {
  1657. NC_ ("Script", "Hanunóo"), CHR ('h', 'a', 'n', 'o')},
  1658. {
  1659. NC_ ("Script", "Hebrew"), CHR ('h', 'e', 'b', 'r')},
  1660. /* { NC_("Script", "Pahawh Hmong"), CHR('h','m','n','g') },*/
  1661. /* { NC_("Script", "Indus (Harappan)"), CHR('i','n','d','s') },*/
  1662. {
  1663. NC_ ("Script", "Javanese"), CHR ('j', 'a', 'v', 'a')},
  1664. {
  1665. NC_ ("Script", "Kayah Li"), CHR ('k', 'a', 'l', 'i')},
  1666. {
  1667. NC_ ("Script", "Hiragana & Katakana"), CHR ('k', 'a', 'n', 'a')},
  1668. {
  1669. NC_ ("Script", "Kharoṣṭhī"), CHR ('k', 'h', 'a', 'r')},
  1670. {
  1671. NC_ ("Script", "Kannada"), CHR ('k', 'n', 'd', 'a')},
  1672. {
  1673. NC_ ("Script", "Kannada2"), CHR ('k', 'n', 'd', '2')},
  1674. {
  1675. NC_ ("Script", "Khmer"), CHR ('k', 'h', 'm', 'r')},
  1676. {
  1677. NC_ ("Script", "Kharosthi"), CHR ('k', 'h', 'a', 'r')},
  1678. {
  1679. NC_ ("Script", "Lao"), CHR ('l', 'a', 'o', ' ')},
  1680. {
  1681. NC_ ("Script", "Latin"), CHR ('l', 'a', 't', 'n')},
  1682. {
  1683. NC_ ("Script", "Lepcha (Róng)"), CHR ('l', 'e', 'p', 'c')},
  1684. {
  1685. NC_ ("Script", "Limbu"), CHR ('l', 'i', 'm', 'b')}, /* Not in ISO 15924 !!!!!, just guessing */
  1686. {
  1687. NC_ ("Script", "Linear A"), CHR ('l', 'i', 'n', 'a')},
  1688. {
  1689. NC_ ("Script", "Linear B"), CHR ('l', 'i', 'n', 'b')},
  1690. {
  1691. NC_ ("Script", "Lycian"), CHR ('l', 'y', 'c', 'i')},
  1692. {
  1693. NC_ ("Script", "Lydian"), CHR ('l', 'y', 'd', 'i')},
  1694. {
  1695. NC_ ("Script", "Mandaean"), CHR ('m', 'a', 'n', 'd')},
  1696. /* { NC_("Script", "Mayan hieroglyphs"), CHR('m','a','y','a') },*/
  1697. {
  1698. NC_ ("Script", "Malayālam"), CHR ('m', 'l', 'y', 'm')},
  1699. {
  1700. NC_ ("Script", "Malayālam2"), CHR ('m', 'l', 'm', '2')},
  1701. {
  1702. NC_ ("Script", "Mathematical Alphanumeric Symbols"), CHR ('m', 'a', 't',
  1703. 'h')},
  1704. {
  1705. NC_ ("Script", "Mongolian"), CHR ('m', 'o', 'n', 'g')},
  1706. {
  1707. NC_ ("Script", "Musical"), CHR ('m', 'u', 's', 'c')},
  1708. {
  1709. NC_ ("Script", "Myanmar"), CHR ('m', 'y', 'm', 'r')},
  1710. {
  1711. NC_ ("Script", "New Tai Lue"), CHR ('t', 'a', 'l', 'u')},
  1712. {
  1713. NC_ ("Script", "N'Ko"), CHR ('n', 'k', 'o', ' ')},
  1714. {
  1715. NC_ ("Script", "Ogham"), CHR ('o', 'g', 'a', 'm')},
  1716. {
  1717. NC_ ("Script", "Ol Chiki"), CHR ('o', 'l', 'c', 'k')},
  1718. {
  1719. NC_ ("Script", "Old Italic (Etruscan, Oscan, etc.)"), CHR ('i', 't', 'a',
  1720. 'l')},
  1721. {
  1722. NC_ ("Script", "Old Permic"), CHR ('p', 'e', 'r', 'm')},
  1723. {
  1724. NC_ ("Script", "Old Persian cuneiform"), CHR ('x', 'p', 'e', 'o')},
  1725. {
  1726. NC_ ("Script", "Oriya"), CHR ('o', 'r', 'y', 'a')},
  1727. {
  1728. NC_ ("Script", "Oriya2"), CHR ('o', 'r', 'y', '2')},
  1729. {
  1730. NC_ ("Script", "Osmanya"), CHR ('o', 's', 'm', 'a')},
  1731. {
  1732. NC_ ("Script", "Pahlavi"), CHR ('p', 'a', 'l', 'v')},
  1733. {
  1734. NC_ ("Script", "Phags-pa"), CHR ('p', 'h', 'a', 'g')},
  1735. {
  1736. NC_ ("Script", "Phoenician"), CHR ('p', 'h', 'n', 'x')},
  1737. {
  1738. NC_ ("Script", "Phaistos"), CHR ('p', 'h', 's', 't')},
  1739. {
  1740. NC_ ("Script", "Pollard Phonetic"), CHR ('p', 'l', 'r', 'd')},
  1741. {
  1742. NC_ ("Script", "Rejang"), CHR ('r', 'j', 'n', 'g')},
  1743. {
  1744. NC_ ("Script", "Rongorongo"), CHR ('r', 'o', 'r', 'o')},
  1745. {
  1746. NC_ ("Script", "Runic"), CHR ('r', 'u', 'n', 'r')},
  1747. {
  1748. NC_ ("Script", "Saurashtra"), CHR ('s', 'a', 'u', 'r')},
  1749. {
  1750. NC_ ("Script", "Shavian"), CHR ('s', 'h', 'a', 'w')},
  1751. {
  1752. NC_ ("Script", "Sinhala"), CHR ('s', 'i', 'n', 'h')},
  1753. {
  1754. NC_ ("Script", "Sumero-Akkadian Cuneiform"), CHR ('x', 's', 'u', 'x')},
  1755. {
  1756. NC_ ("Script", "Sundanese"), CHR ('s', 'u', 'n', 'd')},
  1757. {
  1758. NC_ ("Script", "Syloti Nagri"), CHR ('s', 'y', 'l', 'o')},
  1759. {
  1760. NC_ ("Script", "Syriac"), CHR ('s', 'y', 'r', 'c')},
  1761. {
  1762. NC_ ("Script", "Tagalog"), CHR ('t', 'g', 'l', 'g')},
  1763. {
  1764. NC_ ("Script", "Tagbanwa"), CHR ('t', 'a', 'g', 'b')},
  1765. {
  1766. NC_ ("Script", "Tai Le"), CHR ('t', 'a', 'l', 'e')}, /* Not in ISO 15924 !!!!!, just guessing */
  1767. {
  1768. NC_ ("Script", "Tai Lu"), CHR ('t', 'a', 'l', 'a')}, /* Not in ISO 15924 !!!!!, just guessing */
  1769. {
  1770. NC_ ("Script", "Tamil"), CHR ('t', 'a', 'm', 'l')},
  1771. {
  1772. NC_ ("Script", "Tamil2"), CHR ('t', 'm', 'l', '2')},
  1773. {
  1774. NC_ ("Script", "Telugu"), CHR ('t', 'e', 'l', 'u')},
  1775. {
  1776. NC_ ("Script", "Telugu2"), CHR ('t', 'e', 'l', '2')},
  1777. {
  1778. NC_ ("Script", "Tengwar"), CHR ('t', 'e', 'n', 'g')},
  1779. {
  1780. NC_ ("Script", "Thaana"), CHR ('t', 'h', 'a', 'a')},
  1781. {
  1782. NC_ ("Script", "Thai"), CHR ('t', 'h', 'a', 'i')},
  1783. {
  1784. NC_ ("Script", "Tibetan"), CHR ('t', 'i', 'b', 't')},
  1785. {
  1786. NC_ ("Script", "Tifinagh (Berber)"), CHR ('t', 'f', 'n', 'g')},
  1787. {
  1788. NC_ ("Script", "Ugaritic"), CHR ('u', 'g', 'r', 't')}, /* Not in ISO 15924 !!!!!, just guessing */
  1789. {
  1790. NC_ ("Script", "Vai"), CHR ('v', 'a', 'i', ' ')},
  1791. /* { NC_("Script", "Visible Speech"), CHR('v','i','s','p') },*/
  1792. {
  1793. NC_ ("Script", "Cuneiform, Ugaritic"), CHR ('x', 'u', 'g', 'a')},
  1794. {
  1795. NC_ ("Script", "Yi"), CHR ('y', 'i', ' ', ' ')},
  1796. /* { NC_("Script", "Private Use Script 1"), CHR('q','a','a','a') },*/
  1797. /* { NC_("Script", "Private Use Script 2"), CHR('q','a','a','b') },*/
  1798. /* { NC_("Script", "Undetermined Script"), CHR('z','y','y','y') },*/
  1799. /* { NC_("Script", "Uncoded Script"), CHR('z','z','z','z') },*/
  1800. {
  1801. NULL, 0}
  1802. };
  1803. void
  1804. LookupInit (void)
  1805. {
  1806. static int done = false;
  1807. int i, j;
  1808. if (done)
  1809. return;
  1810. done = true;
  1811. for (j = 0; j < 2; ++j)
  1812. {
  1813. for (i = 0; i < 10; ++i)
  1814. if (lookup_type_names[j][i] != NULL)
  1815. lookup_type_names[j][i] = _(lookup_type_names[j][i]);
  1816. }
  1817. for (i = 0; localscripts[i].text != NULL; ++i)
  1818. localscripts[i].text =
  1819. (char *) g_dpgettext2 (NULL, "Script", localscripts[i].text);
  1820. for (i = 0; friendlies[i].friendlyname != NULL; ++i)
  1821. friendlies[i].friendlyname = _(friendlies[i].friendlyname);
  1822. }
  1823. char *
  1824. TagFullName (SplineFont *sf, uint32_t tag, int onlyifknown)
  1825. {
  1826. char ubuf[200], *end = ubuf + sizeof (ubuf);
  1827. int k;
  1828. int stag = tag;
  1829. if (tag == CHR ('n', 'u', 't', 'f')) /* early name that was standardize later as... */
  1830. stag = CHR ('a', 'f', 'r', 'c'); /* Stood for nut fractions. "nut" meaning "fits in an en" in old typography-speak => vertical fractions rather than diagonal ones */
  1831. if (tag == REQUIRED_FEATURE)
  1832. {
  1833. strcpy (ubuf, _("Required Feature"));
  1834. }
  1835. else
  1836. {
  1837. LookupInit ();
  1838. for (k = 0; friendlies[k].tag != 0; ++k)
  1839. {
  1840. if (friendlies[k].tag == stag)
  1841. break;
  1842. }
  1843. ubuf[0] = '\'';
  1844. ubuf[1] = tag >> 24;
  1845. ubuf[2] = (tag >> 16) & 0xff;
  1846. ubuf[3] = (tag >> 8) & 0xff;
  1847. ubuf[4] = tag & 0xff;
  1848. ubuf[5] = '\'';
  1849. ubuf[6] = ' ';
  1850. if (friendlies[k].tag != 0)
  1851. strncpy (ubuf + 7, (char *) friendlies[k].friendlyname, end - ubuf - 7);
  1852. else if (onlyifknown)
  1853. return NULL;
  1854. else
  1855. ubuf[7] = '\0';
  1856. }
  1857. return xstrdup_or_null (ubuf);
  1858. }
  1859. void
  1860. NameOTLookup (OTLookup *otl, SplineFont *sf)
  1861. {
  1862. char *userfriendly = NULL, *script;
  1863. FeatureScriptLangList *fl;
  1864. const char *lookuptype;
  1865. char *format;
  1866. struct lookup_subtable *subtable;
  1867. int k;
  1868. LookupInit ();
  1869. if (otl->lookup_name == NULL)
  1870. {
  1871. for (k = 0; k < 2; ++k)
  1872. {
  1873. for (fl = otl->features; fl != NULL; fl = fl->next)
  1874. {
  1875. /* look first for a feature attached to a default language */
  1876. if (k == 1
  1877. || DefaultLangTagInScriptList (fl->scripts, false) != NULL)
  1878. {
  1879. userfriendly = TagFullName (sf, fl->featuretag, true);
  1880. if (userfriendly != NULL)
  1881. break;
  1882. }
  1883. }
  1884. if (userfriendly != NULL)
  1885. break;
  1886. }
  1887. if (userfriendly == NULL)
  1888. {
  1889. if ((otl->lookup_type >> 8) < 2 && (otl->lookup_type & 0xff) < 10)
  1890. lookuptype =
  1891. _(lookup_type_names[otl->lookup_type >> 8]
  1892. [otl->lookup_type & 0xff]);
  1893. else
  1894. lookuptype = C_ ("LookupType", "Unknown");
  1895. for (fl = otl->features; fl != NULL; fl = fl->next);
  1896. if (fl == NULL)
  1897. userfriendly = xstrdup_or_null (lookuptype);
  1898. else
  1899. {
  1900. userfriendly = xmalloc (strlen (lookuptype) + 10);
  1901. sprintf (userfriendly, "%s '%c%c%c%c'", lookuptype,
  1902. fl->featuretag >> 24,
  1903. fl->featuretag >> 16,
  1904. fl->featuretag >> 8, fl->featuretag);
  1905. }
  1906. }
  1907. script = NULL;
  1908. if (fl == NULL)
  1909. fl = otl->features;
  1910. if (fl != NULL && fl->scripts != NULL)
  1911. {
  1912. char buf[8];
  1913. int j;
  1914. struct scriptlanglist *sl, *found, *found2;
  1915. uint32_t script_tag = fl->scripts->script;
  1916. found = found2 = NULL;
  1917. for (sl = fl->scripts; sl != NULL; sl = sl->next)
  1918. {
  1919. if (sl->script == DEFAULT_SCRIPT)
  1920. /* Ignore it */ ;
  1921. else if (DefaultLangTagInOneScriptList (sl))
  1922. {
  1923. if (found == NULL)
  1924. found = sl;
  1925. else
  1926. {
  1927. found = found2 = NULL;
  1928. break;
  1929. }
  1930. }
  1931. else if (found2 == NULL)
  1932. found2 = sl;
  1933. else
  1934. found2 = (struct scriptlanglist *) -1;
  1935. }
  1936. if (found == NULL && found2 != NULL
  1937. && found2 != (struct scriptlanglist *) -1)
  1938. found = found2;
  1939. if (found != NULL)
  1940. {
  1941. script_tag = found->script;
  1942. for (j = 0;
  1943. localscripts[j].text != NULL
  1944. && script_tag != localscripts[j].tag; ++j);
  1945. if (localscripts[j].text != NULL)
  1946. script =
  1947. xstrdup_or_null (g_dpgettext2
  1948. (NULL, "Script",
  1949. (char *) localscripts[j].text));
  1950. else
  1951. {
  1952. buf[0] = '\'';
  1953. buf[1] = fl->scripts->script >> 24;
  1954. buf[2] = (fl->scripts->script >> 16) & 0xff;
  1955. buf[3] = (fl->scripts->script >> 8) & 0xff;
  1956. buf[4] = fl->scripts->script & 0xff;
  1957. buf[5] = '\'';
  1958. buf[6] = 0;
  1959. script = xstrdup_or_null (buf);
  1960. }
  1961. }
  1962. }
  1963. if (script != NULL)
  1964. {
  1965. /* TRANSLATORS: This string is used to generate a name for each OpenType lookup. */
  1966. /* The %s will be filled with the user friendly name of the feature used to invoke the lookup */
  1967. /* The second %s (if present) is the script */
  1968. /* While the %d is the index into the lookup list and is used to disambiguate it */
  1969. /* In case that is needed */
  1970. format = _("%s in %s lookup %d");
  1971. otl->lookup_name =
  1972. xmalloc (strlen (userfriendly) + strlen (format) + strlen (script) +
  1973. 10);
  1974. sprintf (otl->lookup_name, format, userfriendly, script,
  1975. otl->lookup_index);
  1976. }
  1977. else
  1978. {
  1979. format = _("%s lookup %d");
  1980. otl->lookup_name =
  1981. xmalloc (strlen (userfriendly) + strlen (format) + 10);
  1982. sprintf (otl->lookup_name, format, userfriendly, otl->lookup_index);
  1983. }
  1984. free (script);
  1985. free (userfriendly);
  1986. }
  1987. if (otl->subtables == NULL)
  1988. /* IError( _("Lookup with no subtables")) */ ;
  1989. else
  1990. {
  1991. int cnt = 0;
  1992. for (subtable = otl->subtables; subtable != NULL;
  1993. subtable = subtable->next, ++cnt)
  1994. if (subtable->subtable_name == NULL)
  1995. {
  1996. if (subtable == otl->subtables && subtable->next == NULL)
  1997. /* TRANSLATORS: This string is used to generate a name for an OpenType lookup subtable. */
  1998. /* %s is the lookup name */
  1999. format = _("%s subtable");
  2000. else if (subtable->per_glyph_pst_or_kern)
  2001. /* TRANSLATORS: This string is used to generate a name for an OpenType lookup subtable. */
  2002. /* %s is the lookup name, %d is the index of the subtable in the lookup */
  2003. format = _("%s per glyph data %d");
  2004. else if (subtable->kc != NULL)
  2005. format = _("%s kerning class %d");
  2006. else if (subtable->fpst != NULL)
  2007. format = _("%s contextual %d");
  2008. else if (subtable->anchor_classes)
  2009. format = _("%s anchor %d");
  2010. else
  2011. {
  2012. IError ("Subtable status not filled in for %dth subtable of %s",
  2013. cnt, otl->lookup_name);
  2014. format = "%s !!!!!!!! %d";
  2015. }
  2016. subtable->subtable_name =
  2017. xmalloc (strlen (otl->lookup_name) + strlen (format) + 10);
  2018. sprintf (subtable->subtable_name, format, otl->lookup_name, cnt);
  2019. }
  2020. }
  2021. if (otl->lookup_type == gsub_ligature)
  2022. {
  2023. for (fl = otl->features; fl != NULL; fl = fl->next)
  2024. if (fl->featuretag == CHR ('l', 'i', 'g', 'a')
  2025. || fl->featuretag == CHR ('r', 'l', 'i', 'g'))
  2026. otl->store_in_afm = true;
  2027. }
  2028. if (otl->lookup_type == gsub_single)
  2029. for (subtable = otl->subtables; subtable != NULL; subtable = subtable->next)
  2030. subtable->suffix = SuffixFromTags (otl->features);
  2031. }
  2032. static void
  2033. LangOrder (struct scriptlanglist *sl)
  2034. {
  2035. int i, j;
  2036. uint32_t lang, lang2;
  2037. for (i = 0; i < sl->lang_cnt; ++i)
  2038. {
  2039. lang = i < MAX_LANG ? sl->langs[i] : sl->morelangs[i - MAX_LANG];
  2040. for (j = i + 1; j < sl->lang_cnt; ++j)
  2041. {
  2042. lang2 = j < MAX_LANG ? sl->langs[j] : sl->morelangs[j - MAX_LANG];
  2043. if (lang > lang2)
  2044. {
  2045. if (i < MAX_LANG)
  2046. sl->langs[i] = lang2;
  2047. else
  2048. sl->morelangs[i - MAX_LANG] = lang2;
  2049. if (j < MAX_LANG)
  2050. sl->langs[j] = lang;
  2051. else
  2052. sl->morelangs[j - MAX_LANG] = lang;
  2053. lang = lang2;
  2054. }
  2055. }
  2056. }
  2057. }
  2058. static struct scriptlanglist *
  2059. SLOrder (struct scriptlanglist *sl)
  2060. {
  2061. int i, j, cnt;
  2062. struct scriptlanglist *sl2, *space[30], **allocked = NULL, **test = space;
  2063. for (sl2 = sl, cnt = 0; sl2 != NULL; sl2 = sl2->next, ++cnt)
  2064. LangOrder (sl2);
  2065. if (cnt <= 1)
  2066. return sl;
  2067. if (cnt > 30)
  2068. test = allocked = xmalloc (cnt * sizeof (struct scriptlanglist *));
  2069. for (sl2 = sl, cnt = 0; sl2 != NULL; sl2 = sl2->next, ++cnt)
  2070. test[cnt] = sl2;
  2071. for (i = 0; i < cnt; ++i)
  2072. for (j = i + 1; j < cnt; ++j)
  2073. {
  2074. if (test[i]->script > test[j]->script)
  2075. {
  2076. struct scriptlanglist *temp;
  2077. temp = test[i];
  2078. test[i] = test[j];
  2079. test[j] = temp;
  2080. }
  2081. }
  2082. sl = test[0];
  2083. for (i = 1; i < cnt; ++i)
  2084. test[i - 1]->next = test[i];
  2085. test[i - 1]->next = NULL;
  2086. free (allocked);
  2087. return sl;
  2088. }
  2089. FeatureScriptLangList *
  2090. FLOrder (FeatureScriptLangList *fl)
  2091. {
  2092. int i, j, cnt;
  2093. FeatureScriptLangList *fl2, *space[30], **allocked = NULL, **test = space;
  2094. for (fl2 = fl, cnt = 0; fl2 != NULL; fl2 = fl2->next, ++cnt)
  2095. fl2->scripts = SLOrder (fl2->scripts);
  2096. if (cnt <= 1)
  2097. return fl;
  2098. if (cnt > 30)
  2099. test = allocked = xmalloc (cnt * sizeof (FeatureScriptLangList *));
  2100. for (fl2 = fl, cnt = 0; fl2 != NULL; fl2 = fl2->next, ++cnt)
  2101. test[cnt] = fl2;
  2102. for (i = 0; i < cnt; ++i)
  2103. for (j = i + 1; j < cnt; ++j)
  2104. {
  2105. if (test[i]->featuretag > test[j]->featuretag)
  2106. {
  2107. FeatureScriptLangList *temp;
  2108. temp = test[i];
  2109. test[i] = test[j];
  2110. test[j] = temp;
  2111. }
  2112. }
  2113. fl = test[0];
  2114. for (i = 1; i < cnt; ++i)
  2115. test[i - 1]->next = test[i];
  2116. test[i - 1]->next = NULL;
  2117. free (allocked);
  2118. return fl;
  2119. }
  2120. struct scriptlanglist *
  2121. SLCopy (struct scriptlanglist *sl)
  2122. {
  2123. struct scriptlanglist *newsl;
  2124. newsl = xzalloc (sizeof (struct scriptlanglist));
  2125. *newsl = *sl;
  2126. newsl->next = NULL;
  2127. if (sl->lang_cnt > MAX_LANG)
  2128. {
  2129. newsl->morelangs =
  2130. xmalloc ((newsl->lang_cnt - MAX_LANG) * sizeof (uint32_t));
  2131. memcpy (newsl->morelangs, sl->morelangs,
  2132. (newsl->lang_cnt - MAX_LANG) * sizeof (uint32_t));
  2133. }
  2134. return newsl;
  2135. }
  2136. struct scriptlanglist *
  2137. SListCopy (struct scriptlanglist *sl)
  2138. {
  2139. struct scriptlanglist *head = NULL, *last = NULL, *cur;
  2140. for (; sl != NULL; sl = sl->next)
  2141. {
  2142. cur = SLCopy (sl);
  2143. if (head == NULL)
  2144. head = cur;
  2145. else
  2146. last->next = cur;
  2147. last = cur;
  2148. }
  2149. return head;
  2150. }
  2151. FeatureScriptLangList *
  2152. FeatureListCopy (FeatureScriptLangList *fl)
  2153. {
  2154. FeatureScriptLangList *newfl;
  2155. if (fl == NULL)
  2156. return NULL;
  2157. newfl = xzalloc (sizeof (FeatureScriptLangList));
  2158. *newfl = *fl;
  2159. newfl->next = NULL;
  2160. newfl->scripts = SListCopy (fl->scripts);
  2161. return newfl;
  2162. }
  2163. static void
  2164. LangMerge (struct scriptlanglist *into, struct scriptlanglist *from)
  2165. {
  2166. int i, j;
  2167. uint32_t flang, tlang;
  2168. for (i = 0; i < from->lang_cnt; ++i)
  2169. {
  2170. flang = i < MAX_LANG ? from->langs[i] : from->morelangs[i - MAX_LANG];
  2171. for (j = 0; j < into->lang_cnt; ++j)
  2172. {
  2173. tlang = j < MAX_LANG ? into->langs[j] : into->morelangs[j - MAX_LANG];
  2174. if (tlang == flang)
  2175. break;
  2176. }
  2177. if (j == into->lang_cnt)
  2178. {
  2179. if (into->lang_cnt < MAX_LANG)
  2180. into->langs[into->lang_cnt++] = flang;
  2181. else
  2182. {
  2183. into->morelangs =
  2184. xrealloc (into->morelangs,
  2185. (into->lang_cnt + 1 - MAX_LANG) * sizeof (uint32_t));
  2186. into->morelangs[into->lang_cnt++ - MAX_LANG] = flang;
  2187. }
  2188. }
  2189. }
  2190. }
  2191. void
  2192. SLMerge (FeatureScriptLangList *into, struct scriptlanglist *fsl)
  2193. {
  2194. struct scriptlanglist *isl;
  2195. for (; fsl != NULL; fsl = fsl->next)
  2196. {
  2197. for (isl = into->scripts; isl != NULL; isl = isl->next)
  2198. {
  2199. if (fsl->script == isl->script)
  2200. break;
  2201. }
  2202. if (isl != NULL)
  2203. LangMerge (isl, fsl);
  2204. else
  2205. {
  2206. isl = SLCopy (fsl);
  2207. isl->next = into->scripts;
  2208. into->scripts = isl;
  2209. }
  2210. }
  2211. }
  2212. void
  2213. FLMerge (OTLookup *into, OTLookup *from)
  2214. {
  2215. /* Merge the feature list from "from" into "into" */
  2216. FeatureScriptLangList *ifl, *ffl;
  2217. /* first check for common featuretags and merge the scripts of each */
  2218. for (ffl = from->features; ffl != NULL; ffl = ffl->next)
  2219. {
  2220. for (ifl = into->features; ifl != NULL; ifl = ifl->next)
  2221. {
  2222. if (ffl->featuretag == ifl->featuretag)
  2223. break;
  2224. }
  2225. if (ifl != NULL)
  2226. SLMerge (ffl, ifl->scripts);
  2227. else
  2228. {
  2229. ifl = FeatureListCopy (ffl);
  2230. ifl->next = into->features;
  2231. into->features = ifl;
  2232. }
  2233. }
  2234. into->features = FLOrder (into->features);
  2235. }
  2236. void
  2237. SFSubTablesMerge (SplineFont *_sf, struct lookup_subtable *subfirst,
  2238. struct lookup_subtable *subsecond)
  2239. {
  2240. int lookup_type = subfirst->lookup->lookup_type;
  2241. int gid, k, isv;
  2242. SplineChar *sc;
  2243. SplineFont *sf = _sf;
  2244. PST *pst, *fpst, *spst, *pstprev, *pstnext;
  2245. KernPair *fkp, *skp, *kpprev, *kpnext;
  2246. AnchorClass *ac;
  2247. if (lookup_type != subsecond->lookup->lookup_type)
  2248. {
  2249. IError ("Attempt to merge lookup subtables with mismatch types");
  2250. return;
  2251. }
  2252. if (lookup_type != gsub_single &&
  2253. lookup_type != gsub_multiple &&
  2254. lookup_type != gsub_alternate &&
  2255. lookup_type != gsub_ligature &&
  2256. lookup_type != gpos_single &&
  2257. lookup_type != gpos_pair &&
  2258. lookup_type != gpos_cursive &&
  2259. lookup_type != gpos_mark2base &&
  2260. lookup_type != gpos_mark2ligature && lookup_type != gpos_mark2mark)
  2261. {
  2262. IError ("Attempt to merge lookup subtables with bad types");
  2263. return;
  2264. }
  2265. else if (subfirst->kc != NULL || subsecond->kc != NULL)
  2266. {
  2267. IError ("Attempt to merge lookup subtables with kerning classes");
  2268. return;
  2269. }
  2270. if (lookup_type == gpos_cursive || lookup_type == gpos_mark2base ||
  2271. lookup_type == gpos_mark2ligature || lookup_type == gpos_mark2mark)
  2272. {
  2273. for (ac = sf->anchor; ac != NULL; ac = ac->next)
  2274. if (ac->subtable == subsecond)
  2275. ac->subtable = subfirst;
  2276. }
  2277. else
  2278. {
  2279. k = 0;
  2280. do
  2281. {
  2282. sf = _sf->subfontcnt == 0 ? _sf : _sf->subfonts[k];
  2283. for (gid = 0; gid < sf->glyphcnt; ++gid)
  2284. if ((sc = sf->glyphs[gid]) != NULL)
  2285. {
  2286. if (lookup_type == gsub_single || lookup_type == gsub_multiple
  2287. || lookup_type == gsub_alternate
  2288. || lookup_type == gpos_single)
  2289. {
  2290. fpst = spst = NULL;
  2291. for (pst = sc->possub; pst != NULL; pst = pst->next)
  2292. {
  2293. if (pst->subtable == subfirst)
  2294. {
  2295. fpst = pst;
  2296. if (spst != NULL)
  2297. break;
  2298. }
  2299. else if (pst->subtable == subsecond)
  2300. {
  2301. spst = pst;
  2302. if (fpst != NULL)
  2303. break;
  2304. }
  2305. }
  2306. if (fpst == NULL && spst != NULL)
  2307. spst->subtable = subfirst;
  2308. else if (spst != NULL)
  2309. {
  2310. LogError (_
  2311. ("The glyph, %s, contains a %s from %s and one from %s.\nThe one from %s will be removed.\n"),
  2312. sc->name,
  2313. lookup_type ==
  2314. gpos_single ? _("positioning") :
  2315. _("substitution"), subfirst->subtable_name,
  2316. subsecond->subtable_name,
  2317. subsecond->subtable_name);
  2318. pstprev = NULL;
  2319. for (pst = sc->possub; pst != NULL && pst != spst;
  2320. pstprev = pst, pst = pst->next);
  2321. if (pstprev == NULL)
  2322. sc->possub = spst->next;
  2323. else
  2324. pstprev = spst->next;
  2325. spst->next = NULL;
  2326. PSTFree (spst);
  2327. }
  2328. }
  2329. else if (lookup_type == gsub_ligature
  2330. || lookup_type == gpos_pair)
  2331. {
  2332. pstprev = NULL;
  2333. for (spst = sc->possub; spst != NULL; spst = pstnext)
  2334. {
  2335. pstnext = spst->next;
  2336. if (spst->subtable == subsecond)
  2337. {
  2338. for (fpst = sc->possub; fpst != NULL;
  2339. fpst = fpst->next)
  2340. {
  2341. if (fpst->subtable == subfirst &&
  2342. strcmp (fpst->u.lig.components,
  2343. spst->u.lig.components) == 0)
  2344. break;
  2345. }
  2346. if (fpst == NULL)
  2347. spst->subtable = subfirst;
  2348. else
  2349. {
  2350. LogError (_
  2351. ("The glyph, %s, contains the same %s from %s and from %s.\nThe one from %s will be removed.\n"),
  2352. sc->name,
  2353. lookup_type ==
  2354. gsub_ligature ? _("ligature") :
  2355. _("kern pair"),
  2356. subfirst->subtable_name,
  2357. subsecond->subtable_name,
  2358. subsecond->subtable_name);
  2359. if (pstprev == NULL)
  2360. sc->possub = pstnext;
  2361. else
  2362. pstprev->next = pstnext;
  2363. spst->next = NULL;
  2364. PSTFree (spst);
  2365. spst = pstprev;
  2366. }
  2367. }
  2368. pstprev = spst;
  2369. }
  2370. for (isv = 0; isv < 2; ++isv)
  2371. {
  2372. kpprev = NULL;
  2373. for (skp = isv ? sc->vkerns : sc->kerns; skp != NULL;
  2374. skp = kpnext)
  2375. {
  2376. kpnext = skp->next;
  2377. if (skp->subtable == subsecond)
  2378. {
  2379. for (fkp = isv ? sc->vkerns : sc->kerns;
  2380. fkp != NULL; fkp = fkp->next)
  2381. {
  2382. if (fkp->subtable == subfirst
  2383. && fkp->sc == skp->sc)
  2384. break;
  2385. }
  2386. if (fkp == NULL)
  2387. skp->subtable = subfirst;
  2388. else
  2389. {
  2390. LogError (_
  2391. ("The glyph, %s, contains the same kern pair from %s and from %s.\nThe one from %s will be removed.\n"),
  2392. sc->name, subfirst->subtable_name,
  2393. subsecond->subtable_name,
  2394. subsecond->subtable_name);
  2395. if (kpprev != NULL)
  2396. kpprev->next = kpnext;
  2397. else if (isv)
  2398. sc->vkerns = kpnext;
  2399. else
  2400. sc->kerns = kpnext;
  2401. skp->next = NULL;
  2402. KernPairsFree (skp);
  2403. skp = kpprev;
  2404. }
  2405. }
  2406. kpprev = skp;
  2407. }
  2408. }
  2409. }
  2410. }
  2411. ++k;
  2412. }
  2413. while (k < _sf->subfontcnt);
  2414. }
  2415. }
  2416. /* ************************************************************************** */
  2417. /* ******************************* copy lookup ****************************** */
  2418. /* ************************************************************************** */
  2419. static char **
  2420. ClassCopy (int class_cnt, char **classes)
  2421. {
  2422. char **newclasses;
  2423. int i;
  2424. if (classes == NULL || class_cnt == 0)
  2425. return NULL;
  2426. newclasses = xmalloc (class_cnt * sizeof (char *));
  2427. for (i = 0; i < class_cnt; ++i)
  2428. newclasses[i] = xstrdup_or_null (classes[i]);
  2429. return newclasses;
  2430. }
  2431. static OTLookup *_OTLookupCopyInto (struct sfmergecontext *mc,
  2432. OTLookup *from_otl, OTLookup *before,
  2433. int do_contents);
  2434. static OTLookup *
  2435. OTLookupCopyNested (struct sfmergecontext *mc, OTLookup *from_otl)
  2436. {
  2437. char *newname;
  2438. OTLookup *to_nested_otl;
  2439. int l;
  2440. if (from_otl == NULL)
  2441. return NULL;
  2442. for (l = 0; l < mc->lcnt; ++l)
  2443. {
  2444. if (mc->lks[l].from == from_otl)
  2445. return mc->lks[l].to;
  2446. }
  2447. newname = x_gc_strjoin (mc->prefix, from_otl->lookup_name, NULL);
  2448. to_nested_otl = SFFindLookup (mc->sf_to, newname);
  2449. if (to_nested_otl == NULL)
  2450. to_nested_otl = _OTLookupCopyInto (mc, from_otl, (OTLookup *) -1, true);
  2451. return to_nested_otl;
  2452. }
  2453. static KernClass *
  2454. SF_AddKernClass (struct sfmergecontext *mc, KernClass *kc,
  2455. struct lookup_subtable *sub)
  2456. {
  2457. KernClass *newkc;
  2458. newkc = xzalloc (sizeof (KernClass));
  2459. *newkc = *kc;
  2460. newkc->subtable = sub;
  2461. if (sub->vertical_kerning)
  2462. {
  2463. newkc->next = mc->sf_to->vkerns;
  2464. mc->sf_to->vkerns = newkc;
  2465. }
  2466. else
  2467. {
  2468. newkc->next = mc->sf_to->kerns;
  2469. mc->sf_to->kerns = newkc;
  2470. }
  2471. newkc->firsts = ClassCopy (newkc->first_cnt, newkc->firsts);
  2472. newkc->seconds = ClassCopy (newkc->second_cnt, newkc->seconds);
  2473. newkc->offsets =
  2474. xmalloc (newkc->first_cnt * newkc->second_cnt * sizeof (int16_t));
  2475. memcpy (newkc->offsets, kc->offsets,
  2476. newkc->first_cnt * newkc->second_cnt * sizeof (int16_t));
  2477. return newkc;
  2478. }
  2479. static FPST *
  2480. SF_AddFPST (struct sfmergecontext *mc, FPST *fpst, struct lookup_subtable *sub)
  2481. {
  2482. FPST *newfpst;
  2483. int i, k, cur;
  2484. newfpst = xzalloc (sizeof (FPST));
  2485. *newfpst = *fpst;
  2486. newfpst->subtable = sub;
  2487. newfpst->next = mc->sf_to->possub;
  2488. mc->sf_to->possub = newfpst;
  2489. newfpst->nclass = ClassCopy (newfpst->nccnt, newfpst->nclass);
  2490. newfpst->bclass = ClassCopy (newfpst->bccnt, newfpst->bclass);
  2491. newfpst->fclass = ClassCopy (newfpst->fccnt, newfpst->fclass);
  2492. newfpst->nclassnames = ClassCopy (newfpst->nccnt, newfpst->nclassnames);
  2493. newfpst->bclassnames = ClassCopy (newfpst->bccnt, newfpst->bclassnames);
  2494. newfpst->fclassnames = ClassCopy (newfpst->fccnt, newfpst->fclassnames);
  2495. newfpst->rules = xmalloc (newfpst->rule_cnt * sizeof (struct fpst_rule));
  2496. memcpy (newfpst->rules, fpst->rules,
  2497. newfpst->rule_cnt * sizeof (struct fpst_rule));
  2498. cur = 0;
  2499. for (i = 0; i < newfpst->rule_cnt; ++i)
  2500. {
  2501. struct fpst_rule *r = &newfpst->rules[i], *oldr = &fpst->rules[i];
  2502. r->lookups = xmalloc (r->lookup_cnt * sizeof (struct seqlookup));
  2503. memcpy (r->lookups, oldr->lookups,
  2504. r->lookup_cnt * sizeof (struct seqlookup));
  2505. for (k = 0; k < r->lookup_cnt; ++k)
  2506. {
  2507. r->lookups[k].lookup = OTLookupCopyNested (mc, r->lookups[k].lookup);
  2508. }
  2509. switch (newfpst->format)
  2510. {
  2511. case pst_glyphs:
  2512. r->u.glyph.names = xstrdup_or_null (r->u.glyph.names);
  2513. r->u.glyph.back = xstrdup_or_null (r->u.glyph.back);
  2514. r->u.glyph.fore = xstrdup_or_null (r->u.glyph.fore);
  2515. break;
  2516. case pst_class:
  2517. r->u.class.nclasses = xmalloc (r->u.class.ncnt * sizeof (uint16_t));
  2518. memcpy (r->u.class.nclasses, oldr->u.class.nclasses,
  2519. r->u.class.ncnt * sizeof (uint16_t));
  2520. r->u.class.bclasses = xmalloc (r->u.class.bcnt * sizeof (uint16_t));
  2521. memcpy (r->u.class.bclasses, oldr->u.class.bclasses,
  2522. r->u.class.bcnt * sizeof (uint16_t));
  2523. r->u.class.fclasses = xmalloc (r->u.class.fcnt * sizeof (uint16_t));
  2524. memcpy (r->u.class.fclasses, oldr->u.class.fclasses,
  2525. r->u.class.fcnt * sizeof (uint16_t));
  2526. break;
  2527. case pst_coverage:
  2528. r->u.coverage.ncovers =
  2529. ClassCopy (r->u.coverage.ncnt, r->u.coverage.ncovers);
  2530. r->u.coverage.bcovers =
  2531. ClassCopy (r->u.coverage.bcnt, r->u.coverage.bcovers);
  2532. r->u.coverage.fcovers =
  2533. ClassCopy (r->u.coverage.fcnt, r->u.coverage.fcovers);
  2534. break;
  2535. case pst_reversecoverage:
  2536. r->u.rcoverage.ncovers =
  2537. ClassCopy (r->u.rcoverage.always1, r->u.rcoverage.ncovers);
  2538. r->u.rcoverage.bcovers =
  2539. ClassCopy (r->u.rcoverage.bcnt, r->u.rcoverage.bcovers);
  2540. r->u.rcoverage.fcovers =
  2541. ClassCopy (r->u.rcoverage.fcnt, r->u.rcoverage.fcovers);
  2542. r->u.rcoverage.replacements =
  2543. xstrdup_or_null (r->u.rcoverage.replacements);
  2544. break;
  2545. }
  2546. }
  2547. return newfpst;
  2548. }
  2549. static SplineChar *
  2550. SCFindOrMake (SplineFont *into, SplineChar *fromsc)
  2551. {
  2552. int to_index;
  2553. if (into->cidmaster == NULL && into->fv != NULL)
  2554. {
  2555. to_index =
  2556. SFFindSlot (into, into->fv->map, fromsc->unicodeenc, fromsc->name);
  2557. if (to_index == -1)
  2558. return NULL;
  2559. return SFMakeChar (into, into->fv->map, to_index);
  2560. }
  2561. return SFGetChar (into, fromsc->unicodeenc, fromsc->name);
  2562. }
  2563. static void
  2564. SF_SCAddAP (SplineChar *tosc, AnchorPoint *ap, AnchorClass * newac)
  2565. {
  2566. AnchorPoint *newap;
  2567. newap = xzalloc (sizeof (AnchorPoint));
  2568. *newap = *ap;
  2569. newap->anchor = newac;
  2570. newap->next = tosc->anchor;
  2571. tosc->anchor = newap;
  2572. }
  2573. static void
  2574. SF_AddAnchorClasses (struct sfmergecontext *mc,
  2575. struct lookup_subtable *from_sub,
  2576. struct lookup_subtable *sub)
  2577. {
  2578. AnchorClass *ac, *nac;
  2579. int k, gid;
  2580. SplineFont *fsf;
  2581. AnchorPoint *ap;
  2582. SplineChar *fsc, *tsc;
  2583. for (ac = mc->sf_from->anchor; ac != NULL; ac = ac->next)
  2584. if (ac->subtable == from_sub)
  2585. {
  2586. nac = xzalloc (sizeof (AnchorClass));
  2587. *nac = *ac;
  2588. nac->subtable = sub;
  2589. nac->name = xstrdup (x_gc_strjoin (mc->prefix, nac->name, NULL));
  2590. nac->next = mc->sf_to->anchor;
  2591. mc->sf_to->anchor = nac;
  2592. k = 0;
  2593. do
  2594. {
  2595. fsf =
  2596. mc->sf_from->subfontcnt ==
  2597. 0 ? mc->sf_from : mc->sf_from->subfonts[k];
  2598. for (gid = 0; gid < fsf->glyphcnt; ++gid)
  2599. if ((fsc = fsf->glyphs[gid]) != NULL)
  2600. {
  2601. for (ap = fsc->anchor; ap != NULL; ap = ap->next)
  2602. {
  2603. if (ap->anchor == ac)
  2604. {
  2605. tsc = SCFindOrMake (mc->sf_to, fsc);
  2606. if (tsc == NULL)
  2607. break;
  2608. SF_SCAddAP (tsc, ap, nac);
  2609. }
  2610. }
  2611. }
  2612. ++k;
  2613. }
  2614. while (k < mc->sf_from->subfontcnt);
  2615. }
  2616. }
  2617. static int
  2618. SF_SCAddPST (SplineChar *tosc, PST *pst, struct lookup_subtable *sub)
  2619. {
  2620. PST *newpst;
  2621. newpst = xzalloc (sizeof (PST));
  2622. *newpst = *pst;
  2623. newpst->subtable = sub;
  2624. newpst->next = tosc->possub;
  2625. tosc->possub = newpst;
  2626. switch (newpst->type)
  2627. {
  2628. case pst_pair:
  2629. newpst->u.pair.paired = xstrdup_or_null (pst->u.pair.paired);
  2630. newpst->u.pair.vr = xzalloc (sizeof (ValueRecord[2]));
  2631. memcpy (newpst->u.pair.vr, pst->u.pair.vr, sizeof (ValueRecord[2]));
  2632. break;
  2633. case pst_ligature:
  2634. newpst->u.lig.lig = tosc;
  2635. /* Fall through */
  2636. case pst_substitution:
  2637. case pst_alternate:
  2638. case pst_multiple:
  2639. newpst->u.subs.variant = xstrdup_or_null (pst->u.subs.variant);
  2640. break;
  2641. }
  2642. return true;
  2643. }
  2644. static int
  2645. SF_SCAddKP (SplineChar *tosc, KernPair *kp, struct lookup_subtable *sub,
  2646. int isvkern, SplineFont *to_sf)
  2647. {
  2648. SplineChar *tosecond;
  2649. KernPair *newkp;
  2650. tosecond = SFGetChar (to_sf, kp->sc->unicodeenc, kp->sc->name);
  2651. if (tosecond == NULL)
  2652. return false;
  2653. newkp = xzalloc (sizeof (KernPair));
  2654. *newkp = *kp;
  2655. newkp->subtable = sub;
  2656. newkp->sc = tosecond;
  2657. if (isvkern)
  2658. {
  2659. newkp->next = tosc->vkerns;
  2660. tosc->vkerns = newkp;
  2661. }
  2662. else
  2663. {
  2664. newkp->next = tosc->kerns;
  2665. tosc->kerns = newkp;
  2666. }
  2667. return true;
  2668. }
  2669. static void
  2670. SF_AddPSTKern (struct sfmergecontext *mc, struct lookup_subtable *from_sub,
  2671. struct lookup_subtable *sub)
  2672. {
  2673. int k, gid, isv;
  2674. SplineFont *fsf;
  2675. SplineChar *fsc, *tsc;
  2676. PST *pst;
  2677. KernPair *kp;
  2678. int iskern = sub->lookup->lookup_type == gpos_pair;
  2679. k = 0;
  2680. do
  2681. {
  2682. fsf =
  2683. mc->sf_from->subfontcnt == 0 ? mc->sf_from : mc->sf_from->subfonts[k];
  2684. for (gid = 0; gid < fsf->glyphcnt; ++gid)
  2685. if ((fsc = fsf->glyphs[gid]) != NULL)
  2686. {
  2687. tsc = (SplineChar *) -1;
  2688. for (pst = fsc->possub; pst != NULL; pst = pst->next)
  2689. {
  2690. if (pst->subtable == from_sub)
  2691. {
  2692. if (tsc == (SplineChar *) -1)
  2693. {
  2694. tsc = SCFindOrMake (mc->sf_to, fsc);
  2695. if (tsc == NULL)
  2696. break;
  2697. }
  2698. SF_SCAddPST (tsc, pst, sub);
  2699. }
  2700. }
  2701. if (tsc != NULL && iskern)
  2702. {
  2703. for (isv = 0; isv < 2 && tsc != NULL; ++isv)
  2704. {
  2705. for (kp = isv ? fsc->vkerns : fsc->kerns; kp != NULL;
  2706. kp = kp->next)
  2707. {
  2708. if (kp->subtable == sub)
  2709. {
  2710. /* Kerning data tend to be individualistic. Only copy if */
  2711. /* glyphs exist */
  2712. if (tsc == (SplineChar *) -1)
  2713. {
  2714. tsc =
  2715. SFGetChar (mc->sf_to, fsc->unicodeenc,
  2716. fsc->name);
  2717. if (tsc == NULL)
  2718. break;
  2719. }
  2720. SF_SCAddKP (tsc, kp, sub, isv, mc->sf_to);
  2721. }
  2722. }
  2723. }
  2724. }
  2725. }
  2726. ++k;
  2727. }
  2728. while (k < mc->sf_from->subfontcnt);
  2729. }
  2730. int
  2731. _FeatureOrderId (int isgpos, uint32_t tag)
  2732. {
  2733. /* This is the order in which features should be executed */
  2734. if (!isgpos)
  2735. switch (tag)
  2736. {
  2737. /* GSUB ordering */
  2738. case CHR ('c', 'c', 'm', 'p'): /* Must be first? */
  2739. return -2;
  2740. case CHR ('l', 'o', 'c', 'l'): /* Language dependent letter forms (serbian uses some different glyphs than russian) */
  2741. return -1;
  2742. case CHR ('i', 's', 'o', 'l'):
  2743. return 0;
  2744. case CHR ('j', 'a', 'l', 't'): /* must come after 'isol' */
  2745. return 1;
  2746. case CHR ('f', 'i', 'n', 'a'):
  2747. return 2;
  2748. case CHR ('f', 'i', 'n', '2'):
  2749. case CHR ('f', 'a', 'l', 't'): /* must come after 'fina' */
  2750. return 3;
  2751. case CHR ('f', 'i', 'n', '3'):
  2752. return 4;
  2753. case CHR ('m', 'e', 'd', 'i'):
  2754. return 5;
  2755. case CHR ('m', 'e', 'd', '2'):
  2756. return 6;
  2757. case CHR ('i', 'n', 'i', 't'):
  2758. return 7;
  2759. case CHR ('r', 't', 'l', 'a'):
  2760. return 100;
  2761. case CHR ('s', 'm', 'c', 'p'):
  2762. case CHR ('c', '2', 's', 'c'):
  2763. return 200;
  2764. case CHR ('r', 'l', 'i', 'g'):
  2765. return 300;
  2766. case CHR ('c', 'a', 'l', 't'):
  2767. return 301;
  2768. case CHR ('l', 'i', 'g', 'a'):
  2769. return 302;
  2770. case CHR ('d', 'l', 'i', 'g'):
  2771. case CHR ('h', 'l', 'i', 'g'):
  2772. return 303;
  2773. case CHR ('c', 's', 'w', 'h'):
  2774. return 304;
  2775. case CHR ('m', 's', 'e', 't'):
  2776. return 305;
  2777. case CHR ('f', 'r', 'a', 'c'):
  2778. return 306;
  2779. /* Indic processing */
  2780. case CHR ('n', 'u', 'k', 't'):
  2781. case CHR ('p', 'r', 'e', 'f'):
  2782. return 301;
  2783. case CHR ('a', 'k', 'h', 'n'):
  2784. return 302;
  2785. case CHR ('r', 'p', 'h', 'f'):
  2786. return 303;
  2787. case CHR ('b', 'l', 'w', 'f'):
  2788. return 304;
  2789. case CHR ('h', 'a', 'l', 'f'):
  2790. case CHR ('a', 'b', 'v', 'f'):
  2791. return 305;
  2792. case CHR ('p', 's', 't', 'f'):
  2793. return 306;
  2794. case CHR ('v', 'a', 't', 'u'):
  2795. return 307;
  2796. case CHR ('p', 'r', 'e', 's'):
  2797. return 310;
  2798. case CHR ('b', 'l', 'w', 's'):
  2799. return 311;
  2800. case CHR ('a', 'b', 'v', 's'):
  2801. return 312;
  2802. case CHR ('p', 's', 't', 's'):
  2803. return 313;
  2804. case CHR ('c', 'l', 'i', 'g'):
  2805. return 314;
  2806. case CHR ('h', 'a', 'l', 'n'):
  2807. return 320;
  2808. /* end indic ordering */
  2809. case CHR ('a', 'f', 'r', 'c'):
  2810. case CHR ('l', 'j', 'm', 'o'):
  2811. case CHR ('v', 'j', 'm', 'o'):
  2812. return 350;
  2813. case CHR ('v', 'r', 't', '2'):
  2814. case CHR ('v', 'e', 'r', 't'):
  2815. return 1010; /* Documented to come last */
  2816. /* Unknown things come after everything but vert/vrt2 */
  2817. default:
  2818. return 1000;
  2819. }
  2820. else
  2821. switch (tag)
  2822. {
  2823. /* GPOS ordering */
  2824. case CHR ('c', 'u', 'r', 's'):
  2825. return 0;
  2826. case CHR ('d', 'i', 's', 't'):
  2827. return 100;
  2828. case CHR ('b', 'l', 'w', 'm'):
  2829. return 201;
  2830. case CHR ('a', 'b', 'v', 'm'):
  2831. return 202;
  2832. case CHR ('k', 'e', 'r', 'n'):
  2833. return 300;
  2834. case CHR ('m', 'a', 'r', 'k'):
  2835. return 400;
  2836. case CHR ('m', 'k', 'm', 'k'):
  2837. return 500;
  2838. /* Unknown things come after everything */
  2839. default:
  2840. return 1000;
  2841. }
  2842. }
  2843. int
  2844. FeatureOrderId (int isgpos, FeatureScriptLangList *fl)
  2845. {
  2846. int pos = 9999, temp;
  2847. if (fl == NULL)
  2848. return 0;
  2849. while (fl != NULL)
  2850. {
  2851. temp = _FeatureOrderId (isgpos, fl->featuretag);
  2852. if (temp < pos)
  2853. pos = temp;
  2854. fl = fl->next;
  2855. }
  2856. return pos;
  2857. }
  2858. void
  2859. SortInsertLookup (SplineFont *sf, OTLookup *newotl)
  2860. {
  2861. int isgpos = newotl->lookup_type >= gpos_start;
  2862. int pos;
  2863. OTLookup *prev, *otl;
  2864. pos = FeatureOrderId (isgpos, newotl->features);
  2865. for (prev = NULL, otl = isgpos ? sf->gpos_lookups : sf->gsub_lookups;
  2866. otl != NULL && FeatureOrderId (isgpos, newotl->features) < pos;
  2867. prev = otl, otl = otl->next);
  2868. newotl->next = otl;
  2869. if (prev != NULL)
  2870. prev->next = newotl;
  2871. else if (isgpos)
  2872. sf->gpos_lookups = newotl;
  2873. else
  2874. sf->gsub_lookups = newotl;
  2875. }
  2876. /* Before may be:
  2877. * A lookup in into_sf, in which case insert new lookup before it
  2878. * NULL , in which case insert new lookup at end
  2879. * -1 , in which case insert new lookup at start
  2880. * -2 , try to guess a good position
  2881. */
  2882. static void
  2883. OrderNewLookup (SplineFont *into_sf, OTLookup *otl, OTLookup *before)
  2884. {
  2885. int isgpos = otl->lookup_type >= gpos_start;
  2886. OTLookup **head = isgpos ? &into_sf->gpos_lookups : &into_sf->gsub_lookups;
  2887. OTLookup *prev;
  2888. if (before == (OTLookup *) -2)
  2889. SortInsertLookup (into_sf, otl);
  2890. else if (before == (OTLookup *) -1 || *head == NULL || *head == before)
  2891. {
  2892. otl->next = *head;
  2893. *head = otl;
  2894. }
  2895. else
  2896. {
  2897. for (prev = *head; prev->next != NULL && prev->next != before;
  2898. prev = prev->next);
  2899. otl->next = prev->next;
  2900. prev->next = otl;
  2901. }
  2902. }
  2903. static OTLookup *
  2904. _OTLookupCopyInto (struct sfmergecontext *mc,
  2905. OTLookup *from_otl, OTLookup *before, int do_contents)
  2906. {
  2907. OTLookup *otl;
  2908. struct lookup_subtable *sub, *last, *from_sub;
  2909. int scnt, l;
  2910. for (l = 0; l < mc->lcnt; ++l)
  2911. {
  2912. if (mc->lks[l].from == from_otl)
  2913. {
  2914. if (mc->lks[l].old)
  2915. return mc->lks[l].to;
  2916. else
  2917. break;
  2918. }
  2919. }
  2920. if (l >= mc->lmax)
  2921. mc->lks = xrealloc (mc->lks, (mc->lmax += 20) * sizeof (struct lookup_cvt));
  2922. mc->sf_to->changed = true;
  2923. if (l >= mc->lcnt)
  2924. {
  2925. otl = xzalloc (sizeof (OTLookup));
  2926. *otl = *from_otl;
  2927. memset (&mc->lks[l], 0, sizeof (mc->lks[l]));
  2928. mc->lks[l].from = from_otl;
  2929. mc->lks[l].to = otl;
  2930. ++mc->lcnt;
  2931. otl->lookup_name = xstrdup (x_gc_strjoin (mc->prefix, from_otl->lookup_name, NULL));
  2932. otl->features = FeatureListCopy (from_otl->features);
  2933. otl->next = NULL;
  2934. otl->subtables = NULL;
  2935. OrderNewLookup (mc->sf_to, otl, before);
  2936. if (!do_contents)
  2937. FIOTLookupCopyInto (mc->sf_to, mc->sf_from, from_otl, otl, 0, before);
  2938. }
  2939. else
  2940. otl = mc->lks[l].to;
  2941. if (!do_contents)
  2942. return otl;
  2943. last = NULL;
  2944. scnt = 0;
  2945. for (from_sub = from_otl->subtables; from_sub != NULL;
  2946. from_sub = from_sub->next)
  2947. {
  2948. sub =
  2949. xzalloc (sizeof (struct lookup_subtable));
  2950. *sub = *from_sub;
  2951. sub->lookup = otl;
  2952. sub->subtable_name = xstrdup (x_gc_strjoin (mc->prefix, from_sub->subtable_name, NULL));
  2953. sub->suffix = xstrdup_or_null (sub->suffix);
  2954. if (last == NULL)
  2955. otl->subtables = sub;
  2956. else
  2957. last->next = sub;
  2958. last = sub;
  2959. if (from_sub->kc != NULL)
  2960. sub->kc = SF_AddKernClass (mc, from_sub->kc, sub);
  2961. else if (from_sub->fpst != NULL)
  2962. sub->fpst = SF_AddFPST (mc, from_sub->fpst, sub);
  2963. else if (from_sub->anchor_classes)
  2964. SF_AddAnchorClasses (mc, from_sub, sub);
  2965. else
  2966. SF_AddPSTKern (mc, from_sub, sub);
  2967. ++scnt;
  2968. }
  2969. FIOTLookupCopyInto (mc->sf_to, mc->sf_from, from_otl, otl, scnt, before);
  2970. return otl;
  2971. }
  2972. static int
  2973. NeedsPrefix (SplineFont *into_sf, SplineFont *from_sf, OTLookup **list)
  2974. {
  2975. struct lookup_subtable *from_sub;
  2976. int i, j, k;
  2977. OTLookup *sublist[2];
  2978. sublist[1] = NULL;
  2979. if (list == NULL || list[0] == NULL)
  2980. return false;
  2981. for (k = 0; list[k] != NULL; ++k)
  2982. {
  2983. OTLookup *from_otl = list[k];
  2984. if (SFFindLookup (into_sf, from_otl->lookup_name) != NULL)
  2985. return true;
  2986. for (from_sub = from_otl->subtables; from_sub != NULL;
  2987. from_sub = from_sub->next)
  2988. {
  2989. if (from_sub->fpst != NULL)
  2990. {
  2991. for (i = 0; i < from_sub->fpst->rule_cnt; ++i)
  2992. {
  2993. struct fpst_rule *r = &from_sub->fpst->rules[i];
  2994. for (j = 0; j < r->lookup_cnt; ++j)
  2995. {
  2996. sublist[0] = r->lookups[j].lookup;
  2997. if (NeedsPrefix (into_sf, from_sf, sublist))
  2998. return true;
  2999. }
  3000. }
  3001. }
  3002. }
  3003. }
  3004. return false;
  3005. }
  3006. OTLookup *
  3007. OTLookupCopyInto (SplineFont *into_sf, SplineFont *from_sf, OTLookup *from_otl)
  3008. {
  3009. OTLookup *newotl, *list[2];
  3010. struct sfmergecontext mc;
  3011. memset (&mc, 0, sizeof (mc));
  3012. mc.sf_from = from_sf;
  3013. mc.sf_to = into_sf;
  3014. list[0] = from_otl;
  3015. list[1] = NULL;
  3016. mc.prefix = NeedsPrefix (into_sf, from_sf, list)
  3017. ? x_gc_strjoin (from_sf->fontname, "-", NULL) : x_gc_strdup ("");
  3018. newotl = _OTLookupCopyInto (&mc, from_otl, (OTLookup *) -2, true);
  3019. free (mc.lks);
  3020. return newotl;
  3021. }
  3022. void
  3023. OTLookupsCopyInto (SplineFont *into_sf, SplineFont *from_sf,
  3024. OTLookup **list, OTLookup *before)
  3025. {
  3026. int i, do_contents;
  3027. struct sfmergecontext mc;
  3028. memset (&mc, 0, sizeof (mc));
  3029. mc.sf_from = from_sf;
  3030. mc.sf_to = into_sf;
  3031. mc.prefix = NeedsPrefix (into_sf, from_sf, list)
  3032. ? x_gc_strjoin (from_sf->fontname, "-", NULL) : x_gc_strdup ("");
  3033. for (i = 0; list[i] != NULL; ++i);
  3034. mc.lks = xmalloc ((mc.lmax = i + 5) * sizeof (struct lookup_cvt));
  3035. /* First create all the lookups and position them in the right order */
  3036. /* then create subtables (which may in turn create some new lookups */
  3037. /* for contextual lookups which invoke other lookups, don't care how */
  3038. /* those nested lookups are ordered) */
  3039. for (do_contents = 0; do_contents < 2; ++do_contents)
  3040. for (i = 0; list[i] != NULL; ++i)
  3041. (void) _OTLookupCopyInto (&mc, list[i], before, do_contents);
  3042. free (mc.lks);
  3043. }
  3044. /* ************************************************************************** */
  3045. /* ****************************** Apply lookups ***************************** */
  3046. /* ************************************************************************** */
  3047. struct lookup_data
  3048. {
  3049. struct opentype_str *str;
  3050. int cnt, max;
  3051. uint32_t script;
  3052. SplineFont *sf;
  3053. struct lookup_subtable *lig_owner;
  3054. int lcnt, lmax;
  3055. SplineChar ***ligs; /* For each ligature we have an array of SplineChars that are its components preceded by the ligature glyph itself */
  3056. /* NULL terminated */
  3057. int pixelsize;
  3058. double scale;
  3059. };
  3060. static int ApplyLookupAtPos (uint32_t tag, OTLookup *otl,
  3061. struct lookup_data *data, int pos);
  3062. static int
  3063. GlyphNameInClass (char *name, char *class)
  3064. {
  3065. char *pt;
  3066. int len = strlen (name);
  3067. if (class == NULL)
  3068. return false;
  3069. pt = class;
  3070. while ((pt = strstr (pt, name)) != NULL)
  3071. {
  3072. if (pt == NULL)
  3073. return false;
  3074. if ((pt == class || pt[-1] == ' ') && (pt[len] == '\0' || pt[len] == ' '))
  3075. return true;
  3076. pt += len;
  3077. }
  3078. return false;
  3079. }
  3080. /* ************************************************************************** */
  3081. /* ************************* Apply OpenType Lookups ************************* */
  3082. /* ************************************************************************** */
  3083. static void
  3084. LigatureFree (struct lookup_data *data)
  3085. {
  3086. int i;
  3087. if (data->ligs == NULL)
  3088. return;
  3089. for (i = 0; data->ligs[i] != NULL; ++i)
  3090. free (data->ligs[i]);
  3091. }
  3092. static void
  3093. LigatureSearch (struct lookup_subtable *sub, struct lookup_data *data)
  3094. {
  3095. SplineFont *sf = data->sf;
  3096. int gid, ccnt, cnt, ch, err;
  3097. SplineChar *sc;
  3098. PST *pst;
  3099. char *pt, *start;
  3100. LigatureFree (data);
  3101. cnt = 0;
  3102. for (gid = 0; gid < sf->glyphcnt; ++gid)
  3103. if ((sc = sf->glyphs[gid]) != NULL)
  3104. {
  3105. for (pst = sc->possub; pst != NULL; pst = pst->next)
  3106. if (pst->subtable == sub)
  3107. {
  3108. for (pt = pst->u.lig.components, ccnt = 0; *pt; ++pt)
  3109. if (*pt == ' ')
  3110. ++ccnt;
  3111. if (cnt >= data->lmax)
  3112. data->ligs =
  3113. xrealloc (data->ligs,
  3114. (data->lmax += 100) * sizeof (SplineChar **));
  3115. data->ligs[cnt] = xmalloc ((ccnt + 3) * sizeof (SplineChar *));
  3116. data->ligs[cnt][0] = sc;
  3117. ccnt = 1;
  3118. err = 0;
  3119. for (pt = pst->u.lig.components; *pt;)
  3120. {
  3121. while (*pt == ' ')
  3122. ++pt;
  3123. if (*pt == '\0')
  3124. break;
  3125. for (start = pt; *pt != '\0' && *pt != ' '; ++pt);
  3126. ch = *pt;
  3127. *pt = '\0';
  3128. data->ligs[cnt][ccnt++] = SFGetChar (sf, -1, start);
  3129. *pt = ch;
  3130. if (data->ligs[cnt][ccnt - 1] == NULL)
  3131. err = 1;
  3132. }
  3133. if (!err)
  3134. data->ligs[cnt++][ccnt] = NULL;
  3135. }
  3136. }
  3137. if (cnt >= data->lmax)
  3138. data->ligs =
  3139. xrealloc (data->ligs, (data->lmax += 1) * sizeof (SplineChar **));
  3140. data->ligs[cnt] = NULL;
  3141. data->lcnt = cnt;
  3142. }
  3143. static int
  3144. skipglyphs (int lookup_flags, struct lookup_data *data, int pos)
  3145. {
  3146. int mc, glyph_class, ms;
  3147. /* The lookup flags tell us what glyphs to ignore. Skip over anything we */
  3148. /* should ignore */
  3149. if (lookup_flags == 0)
  3150. return pos;
  3151. mc = (lookup_flags >> 8);
  3152. if (mc < 0 || mc >= data->sf->mark_class_cnt)
  3153. mc = 0;
  3154. ms = lookup_flags >> 16;
  3155. if (!(lookup_flags & pst_usemarkfilteringset) || ms >= data->sf->mark_set_cnt)
  3156. ms = -1;
  3157. while (pos < data->cnt)
  3158. {
  3159. glyph_class = gdefclass (data->str[pos].sc);
  3160. /* 1=>base, 2=>ligature, 3=>mark, 4=>component?, 0=>.notdef */
  3161. if ((glyph_class == 1 && (lookup_flags & pst_ignorebaseglyphs)) ||
  3162. (glyph_class == 2 && (lookup_flags & pst_ignoreligatures)) ||
  3163. (glyph_class == 3 && (lookup_flags & pst_ignorecombiningmarks)) ||
  3164. (glyph_class == 3 && mc != 0 &&
  3165. !GlyphNameInClass (data->str[pos].sc->name,
  3166. data->sf->mark_classes[mc])) || (ms >= 0
  3167. &&
  3168. !GlyphNameInClass
  3169. (data->str[pos].
  3170. sc->name,
  3171. data->sf->
  3172. mark_sets[ms])))
  3173. {
  3174. ++pos;
  3175. }
  3176. else
  3177. break;
  3178. }
  3179. return pos;
  3180. }
  3181. static int
  3182. bskipmarkglyphs (int lookup_flags, struct lookup_data *data, int pos)
  3183. {
  3184. int mc, glyph_class, ms;
  3185. /* The lookup flags tell us what glyphs to ignore. Skip over anything we */
  3186. /* should ignore. Here we skip backward */
  3187. mc = (lookup_flags >> 8);
  3188. if (mc < 0 || mc >= data->sf->mark_class_cnt)
  3189. mc = 0;
  3190. ms = lookup_flags >> 16;
  3191. if (!(lookup_flags & pst_usemarkfilteringset) || ms >= data->sf->mark_set_cnt)
  3192. ms = -1;
  3193. while (pos >= 0)
  3194. {
  3195. glyph_class = gdefclass (data->str[pos].sc);
  3196. /* 1=>base, 2=>ligature, 3=>mark, 4=>component?, 0=>.notdef */
  3197. if (glyph_class == 3)
  3198. --pos;
  3199. else if ((glyph_class == 1 && (lookup_flags & pst_ignorebaseglyphs)) ||
  3200. (glyph_class == 2 && (lookup_flags & pst_ignoreligatures)) ||
  3201. (glyph_class == 3 && (lookup_flags & pst_ignorecombiningmarks))
  3202. || (glyph_class == 3 && mc != 0
  3203. && !GlyphNameInClass (data->str[pos].sc->name,
  3204. data->sf->mark_classes[mc]))
  3205. || (ms >= 0
  3206. && !GlyphNameInClass (data->str[pos].sc->name,
  3207. data->sf->mark_sets[ms])))
  3208. {
  3209. --pos;
  3210. }
  3211. else
  3212. break;
  3213. }
  3214. return pos;
  3215. }
  3216. static int
  3217. bskipglyphs (int lookup_flags, struct lookup_data *data, int pos)
  3218. {
  3219. int mc, glyph_class, ms;
  3220. /* The lookup flags tell us what glyphs to ignore. Skip over anything we */
  3221. /* should ignore. Here we skip backward */
  3222. if (lookup_flags == 0)
  3223. return pos;
  3224. mc = (lookup_flags >> 8);
  3225. if (mc < 0 || mc >= data->sf->mark_class_cnt)
  3226. mc = 0;
  3227. ms = lookup_flags >> 16;
  3228. if (!(lookup_flags & pst_usemarkfilteringset) || ms >= data->sf->mark_set_cnt)
  3229. ms = -1;
  3230. while (pos >= 0)
  3231. {
  3232. glyph_class = gdefclass (data->str[pos].sc);
  3233. /* 1=>base, 2=>ligature, 3=>mark, 4=>component?, 0=>.notdef */
  3234. if ((glyph_class == 1 && (lookup_flags & pst_ignorebaseglyphs)) ||
  3235. (glyph_class == 2 && (lookup_flags & pst_ignoreligatures)) ||
  3236. (glyph_class == 3 && (lookup_flags & pst_ignorecombiningmarks)) ||
  3237. (glyph_class == 3 && mc != 0 &&
  3238. !GlyphNameInClass (data->str[pos].sc->name,
  3239. data->sf->mark_classes[mc])) || (ms >= 0
  3240. &&
  3241. !GlyphNameInClass
  3242. (data->str[pos].
  3243. sc->name,
  3244. data->sf->
  3245. mark_sets[ms])))
  3246. {
  3247. --pos;
  3248. }
  3249. else
  3250. break;
  3251. }
  3252. return pos;
  3253. }
  3254. static int
  3255. ContextualMatch (struct lookup_subtable *sub, struct lookup_data *data,
  3256. int pos, struct fpst_rule **_rule)
  3257. {
  3258. int i, cpos, retpos, r;
  3259. FPST *fpst = sub->fpst;
  3260. int lookup_flags = sub->lookup->lookup_flags;
  3261. char *pt;
  3262. /* If we should skip the current glyph then don't try for a match here */
  3263. cpos = skipglyphs (lookup_flags, data, pos);
  3264. if (cpos != pos)
  3265. return 0;
  3266. for (r = 0; r < fpst->rule_cnt; ++r)
  3267. {
  3268. struct fpst_rule *rule = &fpst->rules[r];
  3269. for (i = pos; i < data->cnt; ++i)
  3270. data->str[i].context_pos = -1;
  3271. /* Handle backtrack (backtrace in the rule is stored in reverse textual order) */
  3272. if (fpst->type == pst_chainpos || fpst->type == pst_chainsub)
  3273. {
  3274. if (fpst->format == pst_glyphs)
  3275. {
  3276. pt = rule->u.glyph.back;
  3277. for (i = bskipglyphs (lookup_flags, data, pos - 1), cpos = 0;
  3278. i >= 0; i = bskipglyphs (lookup_flags, data, i - 1))
  3279. {
  3280. char *name = data->str[i].sc->name;
  3281. int len = strlen (name);
  3282. if (strncmp (name, pt, len) != 0
  3283. || (pt[len] != '\0' && pt[len] != ' '))
  3284. break;
  3285. pt += len;
  3286. while (*pt == ' ')
  3287. ++pt;
  3288. }
  3289. if (*pt != '\0')
  3290. continue; /* didn't match */
  3291. }
  3292. else if (fpst->format == pst_class)
  3293. {
  3294. for (i = bskipglyphs (lookup_flags, data, pos - 1), cpos = 0;
  3295. i >= 0 && cpos < rule->u.class.bcnt;
  3296. i = bskipglyphs (lookup_flags, data, i - 1))
  3297. {
  3298. if (!GlyphNameInClass
  3299. (data->str[i].sc->name,
  3300. fpst->bclass[rule->u.class.bclasses[cpos]]))
  3301. break;
  3302. ++cpos;
  3303. }
  3304. if (cpos != rule->u.class.bcnt)
  3305. continue; /* didn't match */
  3306. }
  3307. else if (fpst->format == pst_coverage)
  3308. {
  3309. for (i = bskipglyphs (lookup_flags, data, pos - 1), cpos = 0;
  3310. i >= 0 && cpos < rule->u.coverage.bcnt;
  3311. i = bskipglyphs (lookup_flags, data, i - 1))
  3312. {
  3313. if (!GlyphNameInClass
  3314. (data->str[i].sc->name, rule->u.coverage.bcovers[cpos]))
  3315. break;
  3316. ++cpos;
  3317. }
  3318. if (cpos < rule->u.coverage.bcnt)
  3319. continue; /* didn't match */
  3320. }
  3321. }
  3322. /* Handle Match */
  3323. if (fpst->format == pst_glyphs)
  3324. {
  3325. pt = rule->u.glyph.names;
  3326. for (i = pos, cpos = 0; i < data->cnt && *pt != '\0';
  3327. i = skipglyphs (lookup_flags, data, i + 1))
  3328. {
  3329. char *name = data->str[i].sc->name;
  3330. int len = strlen (name);
  3331. if (strncmp (name, pt, len) != 0
  3332. || (pt[len] != '\0' && pt[len] != ' '))
  3333. break;
  3334. data->str[i].context_pos = cpos++;
  3335. pt += len;
  3336. while (*pt == ' ')
  3337. ++pt;
  3338. }
  3339. if (*pt != '\0')
  3340. continue; /* didn't match */
  3341. }
  3342. else if (fpst->format == pst_class)
  3343. {
  3344. for (i = pos, cpos = 0; i < data->cnt && cpos < rule->u.class.ncnt;
  3345. i = skipglyphs (lookup_flags, data, i + 1))
  3346. {
  3347. int class = rule->u.class.nclasses[cpos];
  3348. if (class != 0)
  3349. {
  3350. if (!GlyphNameInClass
  3351. (data->str[i].sc->name, fpst->nclass[class]))
  3352. break;
  3353. }
  3354. else
  3355. {
  3356. int c;
  3357. /* Ok, to match class 0 we must fail to match all other classes */
  3358. for (c = 1; c < fpst->nccnt; ++c)
  3359. if (!GlyphNameInClass
  3360. (data->str[i].sc->name, fpst->nclass[c]))
  3361. break;
  3362. if (c != fpst->nccnt)
  3363. break; /* It matched another class => not in class 0 */
  3364. }
  3365. data->str[i].context_pos = cpos++;
  3366. }
  3367. if (cpos < rule->u.class.ncnt)
  3368. continue; /* didn't match */
  3369. }
  3370. else if (fpst->format == pst_coverage)
  3371. {
  3372. for (i = pos, cpos = 0; i < data->cnt && cpos < rule->u.coverage.ncnt;
  3373. i = skipglyphs (lookup_flags, data, i + 1))
  3374. {
  3375. if (!GlyphNameInClass
  3376. (data->str[i].sc->name, rule->u.coverage.ncovers[cpos]))
  3377. break;
  3378. data->str[i].context_pos = cpos++;
  3379. }
  3380. if (cpos < rule->u.coverage.ncnt)
  3381. continue; /* didn't match */
  3382. }
  3383. else
  3384. return 0; /* Not ready to deal with reverse chainging */
  3385. retpos = i;
  3386. /* Handle lookahead */
  3387. if (fpst->type == pst_chainpos || fpst->type == pst_chainsub)
  3388. {
  3389. if (fpst->format == pst_glyphs)
  3390. {
  3391. pt = rule->u.glyph.fore;
  3392. for (i = retpos; i < data->cnt && *pt != '\0';
  3393. i = skipglyphs (lookup_flags, data, i + 1))
  3394. {
  3395. char *name = data->str[i].sc->name;
  3396. int len = strlen (name);
  3397. if (strncmp (name, pt, len) != 0
  3398. || (pt[len] != '\0' && pt[len] != ' '))
  3399. break;
  3400. pt += len;
  3401. while (*pt == ' ')
  3402. ++pt;
  3403. }
  3404. if (*pt != '\0')
  3405. continue; /* didn't match */
  3406. }
  3407. else if (fpst->format == pst_class)
  3408. {
  3409. for (i = retpos, cpos = 0;
  3410. i < data->cnt && cpos < rule->u.class.fcnt;
  3411. i = skipglyphs (lookup_flags, data, i + 1))
  3412. {
  3413. if (!GlyphNameInClass
  3414. (data->str[i].sc->name,
  3415. fpst->fclass[rule->u.class.fclasses[cpos]]))
  3416. break;
  3417. cpos++;
  3418. }
  3419. if (cpos < rule->u.class.fcnt)
  3420. continue; /* didn't match */
  3421. }
  3422. else if (fpst->format == pst_coverage)
  3423. {
  3424. for (i = retpos, cpos = 0;
  3425. i < data->cnt && cpos < rule->u.coverage.fcnt;
  3426. i = skipglyphs (lookup_flags, data, i + 1))
  3427. {
  3428. if (!GlyphNameInClass
  3429. (data->str[i].sc->name, rule->u.coverage.fcovers[cpos]))
  3430. break;
  3431. cpos++;
  3432. }
  3433. if (cpos < rule->u.coverage.fcnt)
  3434. continue; /* didn't match */
  3435. }
  3436. }
  3437. *_rule = rule;
  3438. return retpos;
  3439. }
  3440. return 0;
  3441. }
  3442. static int
  3443. ApplySingleSubsAtPos (struct lookup_subtable *sub, struct lookup_data *data,
  3444. int pos)
  3445. {
  3446. PST *pst;
  3447. SplineChar *sc;
  3448. for (pst = data->str[pos].sc->possub; pst != NULL && pst->subtable != sub;
  3449. pst = pst->next);
  3450. if (pst == NULL)
  3451. return 0;
  3452. sc = SFGetChar (data->sf, -1, pst->u.subs.variant);
  3453. if (sc != NULL)
  3454. {
  3455. data->str[pos].sc = sc;
  3456. return pos + 1;
  3457. }
  3458. else if (strcmp (pst->u.subs.variant, MAC_DELETED_GLYPH_NAME) == 0)
  3459. {
  3460. /* Under AAT we delete the glyph. But OpenType doesn't have that concept */
  3461. int i;
  3462. for (i = pos + 1; i < data->cnt; ++i)
  3463. data->str[pos - 1] = data->str[pos];
  3464. --data->cnt;
  3465. return pos;
  3466. }
  3467. else
  3468. {
  3469. return 0;
  3470. }
  3471. }
  3472. static int
  3473. ApplyMultSubsAtPos (struct lookup_subtable *sub, struct lookup_data *data,
  3474. int pos)
  3475. {
  3476. PST *pst;
  3477. SplineChar *sc;
  3478. char *start, *pt;
  3479. int mcnt, ch, i;
  3480. SplineChar *mults[20];
  3481. for (pst = data->str[pos].sc->possub; pst != NULL && pst->subtable != sub;
  3482. pst = pst->next);
  3483. if (pst == NULL)
  3484. return 0;
  3485. mcnt = 0;
  3486. for (start = pst->u.alt.components; *start == ' '; ++start);
  3487. for (; *start;)
  3488. {
  3489. for (pt = start; *pt != '\0' && *pt != ' '; ++pt);
  3490. ch = *pt;
  3491. *pt = '\0';
  3492. sc = SFGetChar (data->sf, -1, start);
  3493. *pt = ch;
  3494. if (sc == NULL)
  3495. return 0;
  3496. if (mcnt < 20)
  3497. mults[mcnt++] = sc;
  3498. while (*pt == ' ')
  3499. ++pt;
  3500. start = pt;
  3501. }
  3502. if (mcnt == 0)
  3503. {
  3504. /* Is this legal? that is can we remove a glyph with an empty multiple? */
  3505. for (i = pos + 1; i < data->cnt; ++i)
  3506. data->str[i - 1] = data->str[i];
  3507. --data->cnt;
  3508. return pos;
  3509. }
  3510. else if (mcnt == 1)
  3511. {
  3512. data->str[pos].sc = mults[0];
  3513. return pos + 1;
  3514. }
  3515. else
  3516. {
  3517. if (data->cnt + mcnt - 1 >= data->max)
  3518. data->str =
  3519. xrealloc (data->str,
  3520. (data->max += mcnt) * sizeof (struct opentype_str));
  3521. for (i = data->cnt - 1; i > pos; --i)
  3522. data->str[i + mcnt - 1] = data->str[i];
  3523. memset (data->str + pos, 0, mcnt * sizeof (struct opentype_str));
  3524. for (i = 0; i < mcnt; ++i)
  3525. {
  3526. data->str[pos + i].sc = mults[i];
  3527. data->str[pos + i].orig_index = data->str[pos].orig_index;
  3528. }
  3529. data->cnt += (mcnt - 1);
  3530. return pos + mcnt;
  3531. }
  3532. }
  3533. static int
  3534. ApplyAltSubsAtPos (struct lookup_subtable *sub, struct lookup_data *data,
  3535. int pos)
  3536. {
  3537. PST *pst;
  3538. SplineChar *sc;
  3539. char *start, *pt, ch;
  3540. for (pst = data->str[pos].sc->possub; pst != NULL && pst->subtable != sub;
  3541. pst = pst->next);
  3542. if (pst == NULL)
  3543. return 0;
  3544. for (start = pst->u.alt.components; *start == ' '; ++start);
  3545. for (; *start;)
  3546. {
  3547. for (pt = start; *pt != '\0' && *pt != ' '; ++pt);
  3548. ch = *pt;
  3549. *pt = '\0';
  3550. sc = SFGetChar (data->sf, -1, start);
  3551. *pt = ch;
  3552. if (sc != NULL)
  3553. {
  3554. data->str[pos].sc = sc;
  3555. return pos + 1;
  3556. }
  3557. while (*pt == ' ')
  3558. ++pt;
  3559. start = pt;
  3560. }
  3561. return 0;
  3562. }
  3563. static int
  3564. ApplyLigatureSubsAtPos (struct lookup_subtable *sub, struct lookup_data *data,
  3565. int pos)
  3566. {
  3567. int i, k, lpos, npos;
  3568. int lookup_flags = sub->lookup->lookup_flags;
  3569. int match_found = -1, match_len = 0;
  3570. if (data->lig_owner != sub)
  3571. LigatureSearch (sub, data);
  3572. for (i = 0; i < data->lcnt; ++i)
  3573. {
  3574. if (data->ligs[i][1] == data->str[pos].sc)
  3575. {
  3576. lpos = 0;
  3577. npos = pos + 1;
  3578. for (k = 2; data->ligs[i][k] != NULL; ++k)
  3579. {
  3580. npos = skipglyphs (lookup_flags, data, npos);
  3581. if (npos >= data->cnt || data->str[npos].sc != data->ligs[i][k])
  3582. break;
  3583. ++npos;
  3584. }
  3585. if (data->ligs[i][k] == NULL)
  3586. {
  3587. if (match_found == -1 || k > match_len)
  3588. {
  3589. match_found = i;
  3590. match_len = k;
  3591. }
  3592. }
  3593. }
  3594. }
  3595. if (match_found != -1)
  3596. {
  3597. /* Matched. Remove the component glyphs, and note which component */
  3598. /* any intervening marks should be attached to */
  3599. data->str[pos].sc = data->ligs[match_found][0];
  3600. npos = pos + 1;
  3601. for (k = 2; data->ligs[match_found][k] != NULL; ++k)
  3602. {
  3603. lpos = skipglyphs (lookup_flags, data, npos);
  3604. for (; npos < lpos; ++npos)
  3605. data->str[npos].lig_pos = k - 2;
  3606. /* Remove this glyph (copy the final NUL too) */
  3607. for (++lpos; lpos <= data->cnt; ++lpos)
  3608. data->str[lpos - 1] = data->str[lpos];
  3609. --data->cnt;
  3610. }
  3611. /* Any marks after the last component (which should be attached */
  3612. /* to it) will not have been tagged, so do that now */
  3613. lpos = skipglyphs (lookup_flags, data, npos);
  3614. for (; npos < lpos; ++npos)
  3615. data->str[npos].lig_pos = k - 2;
  3616. return pos + 1;
  3617. }
  3618. return 0;
  3619. }
  3620. static int
  3621. ApplyContextual (struct lookup_subtable *sub, struct lookup_data *data, int pos)
  3622. {
  3623. /* On this level there is no difference between GPOS/GSUB contextuals */
  3624. /* If the contextual matches, then we apply the lookups, otherwise we */
  3625. /* don't. Now the lookups will be different, but we don't care here */
  3626. struct fpst_rule *rule;
  3627. int retpos, i, j;
  3628. retpos = ContextualMatch (sub, data, pos, &rule);
  3629. if (retpos == 0)
  3630. return 0;
  3631. for (i = 0; i < rule->lookup_cnt; ++i)
  3632. {
  3633. for (j = pos; j < data->cnt; ++j)
  3634. {
  3635. if (data->str[j].context_pos == rule->lookups[i].seq)
  3636. {
  3637. ApplyLookupAtPos (0, rule->lookups[i].lookup, data, j);
  3638. break;
  3639. }
  3640. }
  3641. }
  3642. return retpos;
  3643. }
  3644. static int
  3645. FigureDeviceTable (DeviceTable *dt, int pixelsize)
  3646. {
  3647. if (dt == NULL || dt->corrections == NULL || pixelsize < dt->first_pixel_size
  3648. || pixelsize > dt->last_pixel_size)
  3649. return 0;
  3650. return dt->corrections[pixelsize - dt->last_pixel_size];
  3651. }
  3652. static int
  3653. ApplySinglePosAtPos (struct lookup_subtable *sub, struct lookup_data *data,
  3654. int pos)
  3655. {
  3656. PST *pst;
  3657. for (pst = data->str[pos].sc->possub; pst != NULL && pst->subtable != sub;
  3658. pst = pst->next);
  3659. if (pst == NULL)
  3660. return 0;
  3661. data->str[pos].vr.xoff += rint (pst->u.pos.xoff * data->scale);
  3662. data->str[pos].vr.yoff += rint (pst->u.pos.yoff * data->scale);
  3663. data->str[pos].vr.h_adv_off += rint (pst->u.pos.h_adv_off * data->scale);
  3664. data->str[pos].vr.v_adv_off += rint (pst->u.pos.v_adv_off * data->scale);
  3665. if (pst->u.pos.adjust != NULL)
  3666. {
  3667. data->str[pos].vr.xoff +=
  3668. FigureDeviceTable (&pst->u.pos.adjust->xadjust, data->pixelsize);
  3669. data->str[pos].vr.yoff +=
  3670. FigureDeviceTable (&pst->u.pos.adjust->yadjust, data->pixelsize);
  3671. data->str[pos].vr.h_adv_off +=
  3672. FigureDeviceTable (&pst->u.pos.adjust->xadv, data->pixelsize);
  3673. data->str[pos].vr.v_adv_off +=
  3674. FigureDeviceTable (&pst->u.pos.adjust->yadv, data->pixelsize);
  3675. }
  3676. return pos + 1;
  3677. }
  3678. static int
  3679. ApplyPairPosAtPos (struct lookup_subtable *sub, struct lookup_data *data,
  3680. int pos, int allow_class0)
  3681. {
  3682. PST *pst;
  3683. int npos, isv, within, f, l, kcspecd;
  3684. KernPair *kp;
  3685. npos = skipglyphs (sub->lookup->lookup_flags, data, pos + 1);
  3686. if (npos >= data->cnt)
  3687. return 0;
  3688. if (sub->kc != NULL)
  3689. {
  3690. kcspecd = sub->kc->firsts[0] != NULL;
  3691. f =
  3692. KCFindName (data->str[pos].sc->name, sub->kc->firsts,
  3693. sub->kc->first_cnt, allow_class0);
  3694. l =
  3695. KCFindName (data->str[npos].sc->name, sub->kc->seconds,
  3696. sub->kc->second_cnt, allow_class0);
  3697. if (f == -1 || l == -1 || (!kcspecd && f == 0 && l == 0))
  3698. return 0;
  3699. data->str[pos].kc_index = within = f * sub->kc->second_cnt + l;
  3700. data->str[pos].kc = sub->kc;
  3701. data->str[pos].prev_kc0 = (!kcspecd && f == 0);
  3702. data->str[pos].next_kc0 = (l == 0);
  3703. if (sub->vertical_kerning)
  3704. {
  3705. data->str[pos].vr.v_adv_off +=
  3706. rint (sub->kc->offsets[within] * data->scale);
  3707. data->str[pos].vr.v_adv_off +=
  3708. FigureDeviceTable (&sub->kc->adjusts[within], data->pixelsize);
  3709. }
  3710. else
  3711. {
  3712. data->str[pos].vr.h_adv_off +=
  3713. rint (sub->kc->offsets[within] * data->scale);
  3714. data->str[pos].vr.h_adv_off +=
  3715. FigureDeviceTable (&sub->kc->adjusts[within], data->pixelsize);
  3716. }
  3717. /* Return 1 if the result we have got comes from a combination with an {Everything Else} class */
  3718. /* This is acceptable, but we should continue looking for a better match */
  3719. return pos + 1;
  3720. }
  3721. else
  3722. {
  3723. for (pst = data->str[pos].sc->possub; pst != NULL; pst = pst->next)
  3724. {
  3725. if (pst->subtable == sub
  3726. && strcmp (pst->u.pair.paired, data->str[npos].sc->name) == 0)
  3727. {
  3728. data->str[pos].vr.xoff +=
  3729. rint (pst->u.pair.vr[0].xoff * data->scale);
  3730. data->str[pos].vr.yoff +=
  3731. rint (pst->u.pair.vr[0].yoff * data->scale);
  3732. data->str[pos].vr.h_adv_off +=
  3733. rint (pst->u.pair.vr[0].h_adv_off * data->scale);
  3734. data->str[pos].vr.v_adv_off +=
  3735. rint (pst->u.pair.vr[0].v_adv_off * data->scale);
  3736. data->str[npos].vr.xoff +=
  3737. rint (pst->u.pair.vr[1].xoff * data->scale);
  3738. data->str[npos].vr.yoff +=
  3739. rint (pst->u.pair.vr[1].yoff * data->scale);
  3740. data->str[npos].vr.h_adv_off +=
  3741. rint (pst->u.pair.vr[1].h_adv_off * data->scale);
  3742. data->str[npos].vr.v_adv_off +=
  3743. rint (pst->u.pair.vr[1].v_adv_off * data->scale);
  3744. /* I got bored. I should do all of them */
  3745. if (pst->u.pair.vr[0].adjust != NULL)
  3746. {
  3747. data->str[pos].vr.h_adv_off +=
  3748. FigureDeviceTable (&pst->u.pair.vr[0].adjust->xadv,
  3749. data->pixelsize);
  3750. }
  3751. return pos + 1; /* We do NOT want to return npos+1 */
  3752. }
  3753. }
  3754. for (isv = 0; isv < 2; ++isv)
  3755. {
  3756. for (kp = isv ? data->str[pos].sc->vkerns : data->str[pos].sc->kerns;
  3757. kp != NULL; kp = kp->next)
  3758. {
  3759. if (kp->subtable == sub && kp->sc == data->str[npos].sc)
  3760. {
  3761. data->str[pos].kp = kp;
  3762. if (isv)
  3763. {
  3764. data->str[pos].vr.v_adv_off +=
  3765. rint (kp->off * data->scale);
  3766. data->str[pos].vr.v_adv_off +=
  3767. FigureDeviceTable (kp->adjust, data->pixelsize);
  3768. }
  3769. else
  3770. {
  3771. data->str[pos].vr.h_adv_off +=
  3772. rint (kp->off * data->scale);
  3773. data->str[pos].vr.h_adv_off +=
  3774. FigureDeviceTable (kp->adjust, data->pixelsize);
  3775. }
  3776. return pos + 1;
  3777. }
  3778. }
  3779. }
  3780. }
  3781. return 0;
  3782. }
  3783. static int
  3784. ApplyAnchorPosAtPos (struct lookup_subtable *sub, struct lookup_data *data,
  3785. int pos)
  3786. {
  3787. AnchorPoint *ap1, *ap2;
  3788. int bpos;
  3789. /* Anchors do not position the base glyph, but the mark (or second glyph */
  3790. /* of a cursive attachment). This means we don't apply the attachment when */
  3791. /* we meet the first glyph, but wait until we meet the second, and then */
  3792. /* walk backwards */
  3793. /* The backwards walk is different depending on the lookup type (I think) */
  3794. /* mark to base and mark to ligature lookups will skip all marks even if */
  3795. /* lookup flags don't specify that */
  3796. /* mark to mark, and cursive attachment only skip what the lookup flags */
  3797. /* tell them to skip. */
  3798. for (ap2 = data->str[pos].sc->anchor; ap2 != NULL; ap2 = ap2->next)
  3799. {
  3800. if (ap2->anchor->subtable == sub
  3801. && (ap2->type == at_mark || ap2->type == at_centry))
  3802. break;
  3803. }
  3804. if (ap2 == NULL)
  3805. {
  3806. /* This subtable is not used by this glyph ... at least this glyph is */
  3807. /* neither a mark nor an entry point for this subtable */
  3808. return 0;
  3809. }
  3810. /* There's only going to be one mark anchor on a glyph in a given subtable */
  3811. /* And cursive attachments only allow one anchor class per subtable */
  3812. /* in either case we have already found the only attachment site possible */
  3813. /* in the current glyph */
  3814. if (sub->lookup->lookup_type == gpos_mark2base ||
  3815. sub->lookup->lookup_type == gpos_mark2ligature)
  3816. bpos = bskipmarkglyphs (sub->lookup->lookup_flags, data, pos - 1);
  3817. else
  3818. bpos = bskipglyphs (sub->lookup->lookup_flags, data, pos - 1);
  3819. if (bpos == -1)
  3820. return 0; /* No match */
  3821. if (sub->lookup->lookup_type == gpos_cursive)
  3822. {
  3823. for (ap1 = data->str[bpos].sc->anchor; ap1 != NULL; ap1 = ap1->next)
  3824. {
  3825. if (ap1->anchor == ap2->anchor && ap1->type == at_cexit)
  3826. break;
  3827. }
  3828. }
  3829. else if (sub->lookup->lookup_type == gpos_mark2ligature)
  3830. {
  3831. for (ap1 = data->str[bpos].sc->anchor; ap1 != NULL; ap1 = ap1->next)
  3832. {
  3833. if (ap1->anchor == ap2->anchor && ap1->type == at_baselig &&
  3834. ap1->lig_index == data->str[pos].lig_pos)
  3835. break;
  3836. }
  3837. }
  3838. else
  3839. {
  3840. for (ap1 = data->str[bpos].sc->anchor; ap1 != NULL; ap1 = ap1->next)
  3841. {
  3842. if (ap1->anchor == ap2->anchor &&
  3843. (ap1->type == at_basechar || ap1->type == at_basemark))
  3844. break;
  3845. }
  3846. }
  3847. if (ap1 == NULL)
  3848. return 0; /* No match */
  3849. /* This probably doesn't work for vertical text */
  3850. data->str[pos].vr.yoff = data->str[bpos].vr.yoff +
  3851. rint ((ap1->me.y - ap2->me.y) * data->scale);
  3852. data->str[pos].vr.yoff += FigureDeviceTable (&ap1->yadjust, data->pixelsize) -
  3853. FigureDeviceTable (&ap2->yadjust, data->pixelsize);
  3854. data->str[pos].vr.xoff = data->str[bpos].vr.xoff +
  3855. rint ((ap1->me.x - ap2->me.x -
  3856. data->str[bpos].sc->width) * data->scale -
  3857. data->str[bpos].vr.h_adv_off);
  3858. data->str[pos].vr.xoff +=
  3859. FigureDeviceTable (&ap1->xadjust,
  3860. data->pixelsize) - FigureDeviceTable (&ap2->xadjust,
  3861. data->
  3862. pixelsize);
  3863. return pos + 1;
  3864. }
  3865. static int
  3866. ConditionalTagOk (uint32_t tag, OTLookup *otl, struct lookup_data *data,
  3867. int pos)
  3868. {
  3869. int npos, bpos;
  3870. uint32_t script;
  3871. int before_in_script, after_in_script;
  3872. if (tag == CHR ('i', 'n', 'i', 't') || tag == CHR ('i', 's', 'o', 'l') ||
  3873. tag == CHR ('f', 'i', 'n', 'a') || tag == CHR ('m', 'e', 'd', 'i'))
  3874. {
  3875. npos = skipglyphs (otl->lookup_flags, data, pos + 1);
  3876. bpos = bskipglyphs (otl->lookup_flags, data, pos - 1);
  3877. script = SCScriptFromUnicode (data->str[pos].sc);
  3878. before_in_script = (bpos >= 0
  3879. && SCScriptFromUnicode (data->str[bpos].sc) ==
  3880. script);
  3881. after_in_script = (npos < data->cnt
  3882. && SCScriptFromUnicode (data->str[npos].sc) == script);
  3883. if (tag == CHR ('i', 'n', 'i', 't'))
  3884. return !before_in_script && after_in_script;
  3885. else if (tag == CHR ('i', 's', 'o', 'l'))
  3886. return !before_in_script && !after_in_script;
  3887. else if (tag == CHR ('f', 'i', 'n', 'a'))
  3888. return before_in_script && !after_in_script;
  3889. else
  3890. return before_in_script && after_in_script;
  3891. }
  3892. return true;
  3893. }
  3894. static int
  3895. ApplyLookupAtPos (uint32_t tag, OTLookup *otl, struct lookup_data *data,
  3896. int pos)
  3897. {
  3898. struct lookup_subtable *sub;
  3899. int newpos;
  3900. /* Need two passes for pair kerning lookups. At the second pass we accept */
  3901. /* also combinations with the {Everything Else} class */
  3902. int i, pcnt = otl->lookup_type == gpos_pair ? 2 : 1;
  3903. /* Some tags imply a conditional check. Do that now */
  3904. if (!ConditionalTagOk (tag, otl, data, pos))
  3905. return 0;
  3906. for (i = 0; i < pcnt; i++)
  3907. {
  3908. for (sub = otl->subtables; sub != NULL; sub = sub->next)
  3909. {
  3910. switch (otl->lookup_type)
  3911. {
  3912. case gsub_single:
  3913. newpos = ApplySingleSubsAtPos (sub, data, pos);
  3914. break;
  3915. case gsub_multiple:
  3916. newpos = ApplyMultSubsAtPos (sub, data, pos);
  3917. break;
  3918. case gsub_alternate:
  3919. newpos = ApplyAltSubsAtPos (sub, data, pos);
  3920. break;
  3921. case gsub_ligature:
  3922. newpos = ApplyLigatureSubsAtPos (sub, data, pos);
  3923. break;
  3924. case gsub_context:
  3925. newpos = ApplyContextual (sub, data, pos);
  3926. break;
  3927. case gsub_contextchain:
  3928. newpos = ApplyContextual (sub, data, pos);
  3929. break;
  3930. case gsub_reversecchain:
  3931. newpos = ApplySingleSubsAtPos (sub, data, pos);
  3932. break;
  3933. case gpos_single:
  3934. newpos = ApplySinglePosAtPos (sub, data, pos);
  3935. break;
  3936. case gpos_pair:
  3937. newpos = ApplyPairPosAtPos (sub, data, pos, i > 0);
  3938. break;
  3939. case gpos_cursive:
  3940. newpos = ApplyAnchorPosAtPos (sub, data, pos);
  3941. break;
  3942. case gpos_mark2base:
  3943. newpos = ApplyAnchorPosAtPos (sub, data, pos);
  3944. break;
  3945. case gpos_mark2ligature:
  3946. newpos = ApplyAnchorPosAtPos (sub, data, pos);
  3947. break;
  3948. case gpos_mark2mark:
  3949. newpos = ApplyAnchorPosAtPos (sub, data, pos);
  3950. break;
  3951. case gpos_context:
  3952. newpos = ApplyContextual (sub, data, pos);
  3953. break;
  3954. case gpos_contextchain:
  3955. newpos = ApplyContextual (sub, data, pos);
  3956. break;
  3957. default:
  3958. newpos = 0;
  3959. break;
  3960. }
  3961. /* if a subtable worked, we don't try to apply the next one */
  3962. if (newpos != 0)
  3963. return newpos;
  3964. }
  3965. }
  3966. return 0;
  3967. }
  3968. static void
  3969. ApplyLookup (uint32_t tag, OTLookup *otl, struct lookup_data *data)
  3970. {
  3971. int pos, npos;
  3972. /* OpenType */
  3973. for (pos = 0; pos < data->cnt;)
  3974. {
  3975. npos = ApplyLookupAtPos (tag, otl, data, pos);
  3976. if (npos <= pos) /* !!!!! */
  3977. npos = pos + 1;
  3978. pos = npos;
  3979. }
  3980. }
  3981. static uint32_t
  3982. FSLLMatches (FeatureScriptLangList *fl, uint32_t *flist, uint32_t script,
  3983. uint32_t lang)
  3984. {
  3985. int i, l;
  3986. struct scriptlanglist *sl;
  3987. if (flist == NULL)
  3988. return 0;
  3989. while (fl != NULL)
  3990. {
  3991. for (i = 0; flist[i] != 0; ++i)
  3992. {
  3993. if (fl->featuretag == flist[i])
  3994. break;
  3995. }
  3996. if (flist[i] != 0)
  3997. {
  3998. for (sl = fl->scripts; sl != NULL; sl = sl->next)
  3999. {
  4000. if (sl->script == script)
  4001. {
  4002. for (l = 0; l < sl->lang_cnt; ++l)
  4003. if ((l < MAX_LANG && sl->langs[l] == lang) ||
  4004. (l >= MAX_LANG && sl->morelangs[l - MAX_LANG] == lang))
  4005. return fl->featuretag;
  4006. }
  4007. }
  4008. }
  4009. fl = fl->next;
  4010. }
  4011. return 0;
  4012. }
  4013. /* This routine takes a string of glyphs and applies the opentype transformations */
  4014. /* indicated by the features (and script and language) we are passed, it returns */
  4015. /* a transformed string with substitutions applied and containing positioning */
  4016. /* info */
  4017. struct opentype_str *
  4018. ApplyTickedFeatures (SplineFont *sf, uint32_t *flist, uint32_t script,
  4019. uint32_t lang, int pixelsize, SplineChar **glyphs)
  4020. {
  4021. int isgpos, cnt;
  4022. OTLookup *otl;
  4023. struct lookup_data data;
  4024. uint32_t *langs, templang;
  4025. int i;
  4026. memset (&data, 0, sizeof (data));
  4027. for (cnt = 0; glyphs[cnt] != NULL; ++cnt);
  4028. data.str = xcalloc (cnt + 1, sizeof (struct opentype_str));
  4029. data.cnt = data.max = cnt;
  4030. for (cnt = 0; glyphs[cnt] != NULL; ++cnt)
  4031. {
  4032. data.str[cnt].sc = glyphs[cnt];
  4033. data.str[cnt].orig_index = cnt;
  4034. data.str[cnt].lig_pos = data.str[cnt].context_pos = -1;
  4035. }
  4036. if (sf->cidmaster != NULL)
  4037. sf = sf->cidmaster;
  4038. data.sf = sf;
  4039. data.pixelsize = pixelsize;
  4040. data.scale = pixelsize / (double) (sf->ascent + sf->descent);
  4041. /* Indic glyph reordering???? */
  4042. for (isgpos = 0; isgpos < 2; ++isgpos)
  4043. {
  4044. /* Check that this table has an entry for this language */
  4045. /* if it doesn't use the default language */
  4046. /* GPOS/GSUB may have different language sets, so we must be prepared */
  4047. templang = lang;
  4048. langs = SFLangsInScript (sf, isgpos, script);
  4049. for (i = 0; langs[i] != 0 && langs[i] != lang; ++i);
  4050. if (langs[i] == 0)
  4051. templang = DEFAULT_LANG;
  4052. free (langs);
  4053. for (otl = isgpos ? sf->gpos_lookups : sf->gsub_lookups; otl != NULL;
  4054. otl = otl->next)
  4055. {
  4056. uint32_t tag;
  4057. if ((tag = FSLLMatches (otl->features, flist, script, templang)) != 0)
  4058. ApplyLookup (tag, otl, &data);
  4059. }
  4060. }
  4061. LigatureFree (&data);
  4062. free (data.ligs);
  4063. data.str = xrealloc (data.str, (data.cnt + 1) * sizeof (struct opentype_str));
  4064. memset (&data.str[data.cnt], 0, sizeof (struct opentype_str));
  4065. return data.str;
  4066. }
  4067. static void
  4068. doreplace (char **haystack, char *start, char *search, char *rpl, int slen)
  4069. {
  4070. int rlen;
  4071. char *pt = start + slen;
  4072. rlen = strlen (rpl);
  4073. if (slen >= rlen)
  4074. {
  4075. memcpy (start, rpl, rlen);
  4076. if (slen > rlen)
  4077. {
  4078. int diff = slen - rlen;
  4079. for (; *pt; ++pt)
  4080. pt[-diff] = *pt;
  4081. pt[-diff] = '\0';
  4082. }
  4083. }
  4084. else
  4085. {
  4086. char *base = *haystack;
  4087. char *new = xmalloc (pt - base + strlen (pt) + rlen - slen + 1);
  4088. memcpy (new, base, start - base);
  4089. memcpy (new + (start - base), rpl, rlen);
  4090. strcpy (new + (start - base) + rlen, pt);
  4091. free (base);
  4092. *haystack = new;
  4093. }
  4094. }
  4095. static int
  4096. rplstr (char **haystack, char *search, char *rpl, int multipleoccurances)
  4097. {
  4098. char *start, *pt, *base = *haystack;
  4099. int ch, match, slen = strlen (search);
  4100. int any = 0;
  4101. if (base == NULL)
  4102. return false;
  4103. for (pt = base;;)
  4104. {
  4105. while (*pt == ' ')
  4106. ++pt;
  4107. if (*pt == '\0')
  4108. return any;
  4109. start = pt;
  4110. while (*pt != ' ' && *pt != '\0')
  4111. ++pt;
  4112. if (pt - start != slen)
  4113. match = -1;
  4114. else
  4115. {
  4116. ch = *pt;
  4117. *pt = '\0';
  4118. match = strcmp (start, search);
  4119. *pt = ch;
  4120. }
  4121. if (match == 0)
  4122. {
  4123. doreplace (haystack, start, search, rpl, slen);
  4124. if (!multipleoccurances)
  4125. return true;
  4126. any = true;
  4127. if (base != *haystack)
  4128. {
  4129. pt = *haystack + (start - base) + strlen (rpl);
  4130. base = *haystack;
  4131. }
  4132. else
  4133. pt = start + strlen (rpl);
  4134. }
  4135. }
  4136. }
  4137. static int
  4138. rplglyphname (char **haystack, char *search, char *rpl)
  4139. {
  4140. /* If we change "f" to "uni0066" then we should also change "f.sc" to */
  4141. /* "uni0066.sc" and "f_f_l" to "uni0066_uni0066_l" */
  4142. char *start, *pt, *base = *haystack;
  4143. int ch, match, slen = strlen (search);
  4144. int any = 0;
  4145. if (slen >= strlen (base))
  4146. return false;
  4147. for (pt = base;;)
  4148. {
  4149. while (*pt == '_')
  4150. ++pt;
  4151. if (*pt == '\0' || *pt == '.')
  4152. return any;
  4153. start = pt;
  4154. while (*pt != '_' && *pt != '\0' && *pt != '.')
  4155. ++pt;
  4156. if (*pt == '\0' && start == base) /* Don't change any unsegmented names */
  4157. return false; /* In particular don't rename ourselves */
  4158. if (pt - start != slen)
  4159. match = -1;
  4160. else
  4161. {
  4162. ch = *pt;
  4163. *pt = '\0';
  4164. match = strcmp (start, search);
  4165. *pt = ch;
  4166. }
  4167. if (match == 0)
  4168. {
  4169. doreplace (haystack, start, search, rpl, slen);
  4170. any = true;
  4171. if (base != *haystack)
  4172. {
  4173. pt = *haystack + (start - base) + strlen (rpl);
  4174. base = *haystack;
  4175. }
  4176. else
  4177. pt = start + strlen (rpl);
  4178. }
  4179. }
  4180. }
  4181. static int
  4182. glyphnameIsComponent (char *haystack, char *search)
  4183. {
  4184. /* Check for a glyph name in ligature names and dotted names */
  4185. char *start, *pt;
  4186. int slen = strlen (search);
  4187. if (slen >= strlen (haystack))
  4188. return false;
  4189. for (pt = haystack;;)
  4190. {
  4191. while (*pt == '_')
  4192. ++pt;
  4193. if (*pt == '\0' || *pt == '.')
  4194. return false;
  4195. start = pt;
  4196. while (*pt != '_' && *pt != '\0' && *pt != '.')
  4197. ++pt;
  4198. if (*pt == '\0' && start == haystack) /* Don't change any unsegmented names */
  4199. return false; /* In particular don't rename ourselves */
  4200. if (pt - start == slen && strncmp (start, search, slen) == 0)
  4201. return true;
  4202. }
  4203. }
  4204. static int
  4205. gvfixup (struct glyphvariants *gv, char *old, char *new)
  4206. {
  4207. int i;
  4208. int ret = 0;
  4209. if (gv == NULL)
  4210. return false;
  4211. ret = rplstr (&gv->variants, old, new, false);
  4212. for (i = 0; i < gv->part_cnt; ++i)
  4213. {
  4214. if (strcmp (gv->parts[i].component, old) == 0)
  4215. {
  4216. free (gv->parts[i].component);
  4217. gv->parts[i].component = xstrdup_or_null (new);
  4218. ret = true;
  4219. }
  4220. }
  4221. return ret;
  4222. }
  4223. void
  4224. SFGlyphRenameFixup (SplineFont *sf, char *old, char *new,
  4225. bool rename_related_glyphs)
  4226. {
  4227. SplineFont *master = sf;
  4228. CVGlyphRenameFixup (sf, old, new);
  4229. if (sf->cidmaster != NULL)
  4230. master = sf->cidmaster;
  4231. for (int k = 0; k <= master->subfontcnt; k++)
  4232. {
  4233. SplineFont *font = k < master->subfontcnt ? master->subfonts[k] : master;
  4234. for (int gid = 0; gid < font->glyphcnt; ++gid)
  4235. {
  4236. SplineChar *sc = font->glyphs[gid];
  4237. if (sc != NULL)
  4238. {
  4239. /* If the name is "f" then look for glyph names like "f.sc" or
  4240. * "f_f_l" and be ready to change them too */
  4241. if (rename_related_glyphs && glyphnameIsComponent (sc->name, old))
  4242. {
  4243. char *newer = xstrdup_or_null (sc->name);
  4244. rplglyphname (&newer, old, new);
  4245. SFGlyphRenameFixup (master, sc->name, newer, true);
  4246. free (sc->name);
  4247. sc->name = newer;
  4248. sc->namechanged = sc->changed = true;
  4249. }
  4250. /* Look through all substitutions (and pairwise psts) stored on
  4251. * the glyphs and change any occurances of the name (KernPairs
  4252. * have a reference to the SC rather than the name, and need no
  4253. * fixup) */
  4254. for (PST *pst = sc->possub; pst != NULL; pst = pst->next)
  4255. {
  4256. if (pst->type == pst_substitution
  4257. || pst->type == pst_alternate
  4258. || pst->type == pst_multiple
  4259. || pst->type == pst_pair
  4260. || pst->type == pst_ligature)
  4261. {
  4262. bool ligature = pst->type == pst_ligature;
  4263. if (rplstr (&pst->u.mult.components, old, new, ligature))
  4264. sc->changed = true;
  4265. }
  4266. }
  4267. /* For once I don't want a short circuit eval of "or", so I use
  4268. * bitwise rather than boolean intentionally */
  4269. if (gvfixup (sc->vert_variants, old, new) |
  4270. gvfixup (sc->horiz_variants, old, new))
  4271. sc->changed = true;
  4272. }
  4273. }
  4274. }
  4275. /* Now look for contextual fpsts which might use the name */
  4276. for (FPST *fpst = master->possub; fpst != NULL; fpst = fpst->next)
  4277. {
  4278. if (fpst->format == pst_class)
  4279. {
  4280. for (int i = 0; i < fpst->nccnt; ++i)
  4281. if (fpst->nclass[i] != NULL)
  4282. {
  4283. if (rplstr (&fpst->nclass[i], old, new, false))
  4284. break;
  4285. }
  4286. for (int i = 0; i < fpst->bccnt; ++i)
  4287. if (fpst->bclass[i] != NULL)
  4288. {
  4289. if (rplstr (&fpst->bclass[i], old, new, false))
  4290. break;
  4291. }
  4292. for (int i = 0; i < fpst->fccnt; ++i)
  4293. if (fpst->fclass[i] != NULL)
  4294. {
  4295. if (rplstr (&fpst->fclass[i], old, new, false))
  4296. break;
  4297. }
  4298. }
  4299. for (int r = 0; r < fpst->rule_cnt; ++r)
  4300. {
  4301. struct fpst_rule *rule = &fpst->rules[r];
  4302. if (fpst->format == pst_glyphs)
  4303. {
  4304. rplstr (&rule->u.glyph.names, old, new, true);
  4305. rplstr (&rule->u.glyph.back, old, new, true);
  4306. rplstr (&rule->u.glyph.fore, old, new, true);
  4307. }
  4308. else if (fpst->format == pst_coverage ||
  4309. fpst->format == pst_reversecoverage)
  4310. {
  4311. for (int i = 0; i < rule->u.coverage.ncnt; ++i)
  4312. rplstr (&rule->u.coverage.ncovers[i], old, new, false);
  4313. for (int i = 0; i < rule->u.coverage.bcnt; ++i)
  4314. rplstr (&rule->u.coverage.bcovers[i], old, new, false);
  4315. for (int i = 0; i < rule->u.coverage.fcnt; ++i)
  4316. rplstr (&rule->u.coverage.fcovers[i], old, new, false);
  4317. if (fpst->format == pst_reversecoverage)
  4318. rplstr (&rule->u.rcoverage.replacements, old, new, true);
  4319. }
  4320. }
  4321. }
  4322. /* Now look for contextual kerning classes which might use the name */
  4323. for (int isv = 0; isv < 2; ++isv)
  4324. {
  4325. for (KernClass *kc = isv ? master->vkerns : master->kerns; kc != NULL;
  4326. kc = kc->next)
  4327. {
  4328. for (int i = 0; i < kc->first_cnt; ++i)
  4329. if (kc->firsts[i] != NULL)
  4330. {
  4331. if (rplstr (&kc->firsts[i], old, new, false))
  4332. break;
  4333. }
  4334. for (int i = 0; i < kc->second_cnt; ++i)
  4335. if (kc->seconds[i] != NULL)
  4336. {
  4337. if (rplstr (&kc->seconds[i], old, new, false))
  4338. break;
  4339. }
  4340. }
  4341. }
  4342. }
  4343. struct lookup_subtable *
  4344. SFSubTableFindOrMake (SplineFont *sf, uint32_t tag, uint32_t script,
  4345. int lookup_type)
  4346. {
  4347. OTLookup **base;
  4348. OTLookup *otl, *found = NULL;
  4349. int isgpos = lookup_type >= gpos_start;
  4350. struct lookup_subtable *sub;
  4351. int isnew = false;
  4352. if (sf->cidmaster)
  4353. sf = sf->cidmaster;
  4354. base = isgpos ? &sf->gpos_lookups : &sf->gsub_lookups;
  4355. for (otl = *base; otl != NULL; otl = otl->next)
  4356. {
  4357. if (otl->lookup_type == lookup_type &&
  4358. FeatureScriptTagInFeatureScriptList (tag, script, otl->features))
  4359. {
  4360. for (sub = otl->subtables; sub != NULL; sub = sub->next)
  4361. if (sub->kc == NULL)
  4362. return sub;
  4363. found = otl;
  4364. }
  4365. }
  4366. if (found == NULL)
  4367. {
  4368. found = xzalloc (sizeof (OTLookup));
  4369. found->lookup_type = lookup_type;
  4370. found->features =
  4371. xzalloc (sizeof (FeatureScriptLangList));
  4372. found->features->featuretag = tag;
  4373. found->features->scripts =
  4374. xzalloc (sizeof (struct scriptlanglist));
  4375. found->features->scripts->script = script;
  4376. found->features->scripts->langs[0] = DEFAULT_LANG;
  4377. found->features->scripts->lang_cnt = 1;
  4378. SortInsertLookup (sf, found);
  4379. isnew = true;
  4380. }
  4381. sub = xzalloc (sizeof (struct lookup_subtable));
  4382. sub->next = found->subtables;
  4383. found->subtables = sub;
  4384. sub->lookup = found;
  4385. sub->per_glyph_pst_or_kern = true;
  4386. NameOTLookup (found, sf);
  4387. return sub;
  4388. }
  4389. struct lookup_subtable *
  4390. SFSubTableMake (SplineFont *sf, uint32_t tag, uint32_t script, int lookup_type)
  4391. {
  4392. OTLookup **base;
  4393. OTLookup *otl, *found = NULL;
  4394. int isgpos = lookup_type >= gpos_start;
  4395. struct lookup_subtable *sub;
  4396. int isnew = false;
  4397. if (sf->cidmaster)
  4398. sf = sf->cidmaster;
  4399. base = isgpos ? &sf->gpos_lookups : &sf->gsub_lookups;
  4400. for (otl = *base; otl != NULL; otl = otl->next)
  4401. {
  4402. if (otl->lookup_type == lookup_type &&
  4403. FeatureScriptTagInFeatureScriptList (tag, script, otl->features))
  4404. {
  4405. found = otl;
  4406. }
  4407. }
  4408. if (found == NULL)
  4409. {
  4410. found = xzalloc (sizeof (OTLookup));
  4411. found->lookup_type = lookup_type;
  4412. found->features =
  4413. xzalloc (sizeof (FeatureScriptLangList));
  4414. found->features->featuretag = tag;
  4415. found->features->scripts =
  4416. xzalloc (sizeof (struct scriptlanglist));
  4417. found->features->scripts->script = script;
  4418. found->features->scripts->langs[0] = DEFAULT_LANG;
  4419. found->features->scripts->lang_cnt = 1;
  4420. SortInsertLookup (sf, found);
  4421. isnew = true;
  4422. }
  4423. sub = xzalloc (sizeof (struct lookup_subtable));
  4424. sub->next = found->subtables;
  4425. found->subtables = sub;
  4426. sub->lookup = found;
  4427. if (isnew)
  4428. NameOTLookup (found, sf);
  4429. return sub;
  4430. }
  4431. int
  4432. LookupUsedNested (SplineFont *sf, OTLookup *checkme)
  4433. {
  4434. OTLookup *otl;
  4435. struct lookup_subtable *sub;
  4436. int r, c;
  4437. if (checkme->lookup_type >= gpos_start)
  4438. otl = sf->gpos_lookups;
  4439. else
  4440. otl = sf->gsub_lookups;
  4441. while (otl != NULL)
  4442. {
  4443. for (sub = otl->subtables; sub != NULL; sub = sub->next)
  4444. {
  4445. if (sub->fpst != NULL)
  4446. {
  4447. for (r = 0; r < sub->fpst->rule_cnt; ++r)
  4448. {
  4449. struct fpst_rule *rule = &sub->fpst->rules[r];
  4450. for (c = 0; c < rule->lookup_cnt; ++c)
  4451. {
  4452. if (rule->lookups[c].lookup == checkme)
  4453. return true;
  4454. }
  4455. }
  4456. }
  4457. }
  4458. otl = otl->next;
  4459. }
  4460. return false;
  4461. }
  4462. static void
  4463. AALTRemoveOld (SplineFont *sf)
  4464. {
  4465. FeatureScriptLangList *fl, *prev;
  4466. OTLookup *otl, *otlnext;
  4467. for (otl = sf->gsub_lookups; otl != NULL; otl = otlnext)
  4468. {
  4469. otlnext = otl->next;
  4470. prev = NULL;
  4471. for (fl = otl->features; fl != NULL; prev = fl, fl = fl->next)
  4472. {
  4473. if (fl->featuretag == CHR ('a', 'a', 'l', 't'))
  4474. {
  4475. if (fl == otl->features && fl->next == NULL
  4476. && !LookupUsedNested (sf, otl))
  4477. SFRemoveLookup (sf, otl);
  4478. else
  4479. {
  4480. if (prev == NULL)
  4481. otl->features = fl->next;
  4482. else
  4483. prev->next = fl->next;
  4484. fl->next = NULL;
  4485. FeatureScriptLangListFree (fl);
  4486. }
  4487. break;
  4488. }
  4489. }
  4490. }
  4491. }
  4492. void
  4493. SllkFree (struct sllk *sllk, int sllk_cnt)
  4494. {
  4495. int i;
  4496. for (i = 0; i < sllk_cnt; ++i)
  4497. {
  4498. free (sllk[i].langs);
  4499. free (sllk[i].lookups);
  4500. }
  4501. free (sllk);
  4502. }
  4503. static void
  4504. AddOTLToSllk (struct sllk *sllk, OTLookup *otl, struct scriptlanglist *sl)
  4505. {
  4506. int i, j, k, l;
  4507. if (otl->lookup_type == gsub_single || otl->lookup_type == gsub_alternate)
  4508. {
  4509. for (i = 0; i < sllk->cnt; ++i)
  4510. if (sllk->lookups[i] == otl)
  4511. break;
  4512. if (i == sllk->cnt)
  4513. {
  4514. if (sllk->cnt >= sllk->max)
  4515. sllk->lookups =
  4516. xrealloc (sllk->lookups, (sllk->max += 5) * sizeof (OTLookup *));
  4517. sllk->lookups[sllk->cnt++] = otl;
  4518. for (l = 0; l < sl->lang_cnt; ++l)
  4519. {
  4520. uint32_t lang =
  4521. l < MAX_LANG ? sl->langs[l] : sl->morelangs[l - MAX_LANG];
  4522. for (j = 0; j < sllk->lcnt; ++j)
  4523. if (sllk->langs[j] == lang)
  4524. break;
  4525. if (j == sllk->lcnt)
  4526. {
  4527. if (sllk->lcnt >= sllk->lmax)
  4528. sllk->langs =
  4529. xrealloc (sllk->langs,
  4530. (sllk->lmax +=
  4531. sl->lang_cnt + MAX_LANG) * sizeof (uint32_t));
  4532. sllk->langs[sllk->lcnt++] = lang;
  4533. }
  4534. }
  4535. }
  4536. }
  4537. else if (otl->lookup_type == gsub_context
  4538. || otl->lookup_type == gsub_contextchain)
  4539. {
  4540. struct lookup_subtable *sub;
  4541. for (sub = otl->subtables; sub != NULL; sub = sub->next)
  4542. {
  4543. FPST *fpst = sub->fpst;
  4544. for (j = 0; j < fpst->rule_cnt; ++j)
  4545. {
  4546. struct fpst_rule *r = &fpst->rules[j];
  4547. for (k = 0; k < r->lookup_cnt; ++k)
  4548. AddOTLToSllk (sllk, r->lookups[k].lookup, sl);
  4549. }
  4550. }
  4551. }
  4552. /* reverse contextual chaining is weird and I shall ignore it. Adobe does too */
  4553. }
  4554. static char *
  4555. ComponentsFromPSTs (PST **psts, int pcnt)
  4556. {
  4557. char **names = NULL;
  4558. int ncnt = 0, nmax = 0;
  4559. int i, j, len;
  4560. char *ret;
  4561. /* First find all the names */
  4562. for (i = 0; i < pcnt; ++i)
  4563. {
  4564. char *nlist = psts[i]->u.alt.components;
  4565. char *start, *pt, ch;
  4566. for (start = nlist;;)
  4567. {
  4568. while (*start == ' ')
  4569. ++start;
  4570. if (*start == '\0')
  4571. break;
  4572. for (pt = start; *pt != ' ' && *pt != '\0'; ++pt);
  4573. ch = *pt;
  4574. *pt = '\0';
  4575. for (j = 0; j < ncnt; ++j)
  4576. if (strcmp (start, names[j]) == 0)
  4577. break;
  4578. if (j == ncnt)
  4579. {
  4580. if (ncnt >= nmax)
  4581. names = xrealloc (names, (nmax += 10) * sizeof (char *));
  4582. names[ncnt++] = xstrdup_or_null (start);
  4583. }
  4584. *pt = ch;
  4585. start = pt;
  4586. }
  4587. }
  4588. len = 0;
  4589. for (i = 0; i < ncnt; ++i)
  4590. len += strlen (names[i]) + 1;
  4591. if (len == 0)
  4592. len = 1;
  4593. ret = xmalloc (len);
  4594. len = 0;
  4595. for (i = 0; i < ncnt; ++i)
  4596. {
  4597. strcpy (ret + len, names[i]);
  4598. len += strlen (names[i]);
  4599. ret[len++] = ' ';
  4600. }
  4601. if (len == 0)
  4602. *ret = '\0';
  4603. else
  4604. ret[len - 1] = '\0';
  4605. for (i = 0; i < ncnt; ++i)
  4606. free (names[i]);
  4607. free (names);
  4608. return ret;
  4609. }
  4610. static int
  4611. SllkMatch (struct sllk *sllk, int s1, int s2)
  4612. {
  4613. int i;
  4614. if (sllk[s1].cnt != sllk[s2].cnt)
  4615. return false;
  4616. for (i = 0; i < sllk[s1].cnt; ++i)
  4617. {
  4618. if (sllk[s1].lookups[i] != sllk[s2].lookups[i])
  4619. return false;
  4620. }
  4621. return true;
  4622. }
  4623. struct sllk *
  4624. AddOTLToSllks (OTLookup *otl, struct sllk *sllk, int *_sllk_cnt, int *_sllk_max)
  4625. {
  4626. FeatureScriptLangList *fl;
  4627. struct scriptlanglist *sl;
  4628. int s;
  4629. for (fl = otl->features; fl != NULL; fl = fl->next)
  4630. {
  4631. for (sl = fl->scripts; sl != NULL; sl = sl->next)
  4632. {
  4633. for (s = 0; s < *_sllk_cnt; ++s)
  4634. if (sl->script == sllk[s].script)
  4635. break;
  4636. if (s == *_sllk_cnt)
  4637. {
  4638. if (*_sllk_cnt >= *_sllk_max)
  4639. sllk =
  4640. xrealloc (sllk, ((*_sllk_max) += 10) * sizeof (struct sllk));
  4641. memset (&sllk[*_sllk_cnt], 0, sizeof (struct sllk));
  4642. sllk[(*_sllk_cnt)++].script = sl->script;
  4643. }
  4644. AddOTLToSllk (&sllk[s], otl, sl);
  4645. }
  4646. }
  4647. return sllk;
  4648. }
  4649. OTLookup *
  4650. NewAALTLookup (SplineFont *sf, struct sllk *sllk, int sllk_cnt, int i)
  4651. {
  4652. OTLookup *otl;
  4653. struct lookup_subtable *sub;
  4654. FeatureScriptLangList *fl;
  4655. struct scriptlanglist *sl;
  4656. PST **psts, *pst;
  4657. int j, k, l;
  4658. int gid, pcnt;
  4659. SplineFont *_sf;
  4660. SplineChar *sc;
  4661. /* Make the new lookup (and all its supporting data structures) */
  4662. otl = xzalloc (sizeof (OTLookup));
  4663. otl->lookup_type = gsub_alternate;
  4664. otl->lookup_flags = sllk[i].lookups[0]->lookup_flags & pst_r2l;
  4665. otl->features = fl =
  4666. xzalloc (sizeof (FeatureScriptLangList));
  4667. fl->featuretag = CHR ('a', 'a', 'l', 't');
  4668. /* Any other scripts with the same lookup set? */
  4669. for (j = i; j < sllk_cnt; ++j)
  4670. {
  4671. if (i == j || SllkMatch (sllk, i, j))
  4672. {
  4673. sl =
  4674. xzalloc (sizeof (struct scriptlanglist));
  4675. sl->next = fl->scripts;
  4676. fl->scripts = sl;
  4677. sl->script = sllk[j].script;
  4678. sl->lang_cnt = sllk[j].lcnt;
  4679. if (sl->lang_cnt > MAX_LANG)
  4680. sl->morelangs =
  4681. xmalloc ((sl->lang_cnt - MAX_LANG) * sizeof (uint32_t));
  4682. for (l = 0; l < sl->lang_cnt; ++l)
  4683. if (l < MAX_LANG)
  4684. sl->langs[l] = sllk[j].langs[l];
  4685. else
  4686. sl->morelangs[l - MAX_LANG] = sllk[j].langs[l];
  4687. if (i != j)
  4688. sllk[j].cnt = 0; /* Mark as processed */
  4689. }
  4690. }
  4691. otl->subtables = sub =
  4692. xzalloc (sizeof (struct lookup_subtable));
  4693. sub->lookup = otl;
  4694. sub->per_glyph_pst_or_kern = true;
  4695. /* Add it to the various lists it needs to be in */
  4696. otl->next = sf->gsub_lookups;
  4697. sf->gsub_lookups = otl;
  4698. /* Now look at every glyph in the font, and see if it has any of the */
  4699. /* lookups we are interested in, and if it does, build a new pst */
  4700. /* containing all posibilities listed on any of them */
  4701. if (sf->cidmaster)
  4702. sf = sf->cidmaster;
  4703. psts = xmalloc (sllk[i].cnt * sizeof (PST *));
  4704. k = 0;
  4705. do
  4706. {
  4707. _sf = k < sf->subfontcnt ? sf->subfonts[k] : sf;
  4708. for (gid = 0; gid < _sf->glyphcnt; ++gid)
  4709. if ((sc = _sf->glyphs[gid]) != NULL)
  4710. {
  4711. pcnt = 0;
  4712. for (pst = sc->possub; pst != NULL; pst = pst->next)
  4713. {
  4714. if (pst->subtable == NULL)
  4715. continue;
  4716. for (j = 0; j < sllk[i].cnt; ++j)
  4717. if (pst->subtable->lookup == sllk[i].lookups[j])
  4718. break;
  4719. if (j < sllk[i].cnt)
  4720. psts[pcnt++] = pst;
  4721. }
  4722. if (pcnt == 0)
  4723. continue;
  4724. pst = xzalloc (sizeof (PST));
  4725. pst->subtable = sub;
  4726. pst->type = pst_alternate;
  4727. pst->next = sc->possub;
  4728. sc->possub = pst;
  4729. pst->u.alt.components = ComponentsFromPSTs (psts, pcnt);
  4730. }
  4731. ++k;
  4732. }
  4733. while (k < sf->subfontcnt);
  4734. free (psts);
  4735. NameOTLookup (otl, sf);
  4736. return otl;
  4737. }
  4738. void
  4739. AddNewAALTFeatures (SplineFont *sf)
  4740. {
  4741. /* different script/lang combinations may need different 'aalt' lookups */
  4742. /* well, let's just say different script combinations */
  4743. /* for each script/lang combo find all single/alternate subs for each */
  4744. /* glyph. Merge those choices and create new lookup with that info */
  4745. struct sllk *sllk = NULL;
  4746. int sllk_cnt = 0, sllk_max = 0;
  4747. int i;
  4748. OTLookup *otl;
  4749. AALTRemoveOld (sf);
  4750. /* Find all scripts, and all the single/alternate lookups for each */
  4751. /* and all the languages used for these in each script */
  4752. for (otl = sf->gsub_lookups; otl != NULL; otl = otl->next)
  4753. {
  4754. sllk = AddOTLToSllks (otl, sllk, &sllk_cnt, &sllk_max);
  4755. }
  4756. /* Each of these gets its own gsub_alternate lookup which gets inserted */
  4757. /* at the head of the lookup list. Each lookup has one subtable */
  4758. for (i = 0; i < sllk_cnt; ++i)
  4759. {
  4760. if (sllk[i].cnt == 0) /* Script used, but provides no alternates */
  4761. continue;
  4762. NewAALTLookup (sf, sllk, sllk_cnt, i);
  4763. }
  4764. SllkFree (sllk, sllk_cnt);
  4765. }
  4766. int
  4767. VerticalKernFeature (SplineFont *sf, OTLookup *otl, int ask)
  4768. {
  4769. FeatureScriptLangList *fl;
  4770. struct lookup_subtable *sub;
  4771. KernClass *kc;
  4772. char *buts[3];
  4773. for (fl = otl->features; fl != NULL; fl = fl->next)
  4774. {
  4775. if (fl->featuretag == CHR ('k', 'e', 'r', 'n'))
  4776. return false;
  4777. else if (fl->featuretag == CHR ('v', 'k', 'r', 'n'))
  4778. return true;
  4779. }
  4780. for (sub = otl->subtables; sub != NULL; sub = sub->next)
  4781. {
  4782. if (sub->kc != NULL)
  4783. {
  4784. for (kc = sf->kerns; kc != NULL; kc = kc->next)
  4785. if (kc == sub->kc)
  4786. return false;
  4787. for (kc = sf->vkerns; kc != NULL; kc = kc->next)
  4788. if (kc == sub->kc)
  4789. return true;
  4790. }
  4791. }
  4792. if (!ask)
  4793. return -1;
  4794. buts[0] = _("_Horizontal");
  4795. buts[1] = _("_Vertical");
  4796. buts[2] = NULL;
  4797. return (ff_ask
  4798. (_("Kerning direction"), (const char **) buts, 0, 1,
  4799. _("Is this horizontal or vertical kerning data?")));
  4800. }
  4801. int
  4802. IsAnchorClassUsed (SplineChar *sc, AnchorClass * an)
  4803. {
  4804. AnchorPoint *ap;
  4805. int waslig = 0, sawentry = 0, sawexit = 0;
  4806. for (ap = sc->anchor; ap != NULL; ap = ap->next)
  4807. {
  4808. if (ap->anchor == an)
  4809. {
  4810. if (ap->type == at_centry)
  4811. sawentry = true;
  4812. else if (ap->type == at_cexit)
  4813. sawexit = true;
  4814. else if (AnchorClass_lookup_type (an) == gpos_mark2mark)
  4815. {
  4816. if (ap->type == at_basemark)
  4817. sawexit = true;
  4818. else
  4819. sawentry = true;
  4820. }
  4821. else if (ap->type != at_baselig)
  4822. return -1;
  4823. else if (waslig < ap->lig_index + 1)
  4824. waslig = ap->lig_index + 1;
  4825. }
  4826. }
  4827. if (sawentry && sawexit)
  4828. return -1;
  4829. else if (sawentry)
  4830. return -2;
  4831. else if (sawexit)
  4832. return -3;
  4833. return waslig;
  4834. }
  4835. int
  4836. PSTContains (const char *components, const char *name)
  4837. {
  4838. const char *pt;
  4839. int len = strlen (name);
  4840. for (pt = strstr (components, name); pt != NULL; pt = strstr (pt + len, name))
  4841. {
  4842. if ((pt == components || pt[-1] == ' ')
  4843. && (pt[len] == ' ' || pt[len] == '\0'))
  4844. return true;
  4845. }
  4846. return false;
  4847. }
  4848. int
  4849. KernClassContains (KernClass *kc, char *name1, char *name2, int ordered)
  4850. {
  4851. int infirst = 0, insecond = 0, scpos1, kwpos1, scpos2, kwpos2;
  4852. int i;
  4853. for (i = 1; i < kc->first_cnt; ++i)
  4854. {
  4855. if (PSTContains (kc->firsts[i], name1))
  4856. {
  4857. scpos1 = i;
  4858. if (++infirst >= 3) /* The name occurs twice??? */
  4859. break;
  4860. }
  4861. else if (PSTContains (kc->firsts[i], name2))
  4862. {
  4863. kwpos1 = i;
  4864. if ((infirst += 2) >= 3)
  4865. break;
  4866. }
  4867. }
  4868. if (infirst == 0 || infirst > 3)
  4869. return 0;
  4870. for (i = 1; i < kc->second_cnt; ++i)
  4871. {
  4872. if (PSTContains (kc->seconds[i], name1))
  4873. {
  4874. scpos2 = i;
  4875. if (++insecond >= 3)
  4876. break;
  4877. }
  4878. else if (PSTContains (kc->seconds[i], name2))
  4879. {
  4880. kwpos2 = i;
  4881. if ((insecond += 2) >= 3)
  4882. break;
  4883. }
  4884. }
  4885. if (insecond == 0 || insecond > 3)
  4886. return 0;
  4887. if ((infirst & 1) && (insecond & 2))
  4888. {
  4889. if (kc->offsets[scpos1 * kc->second_cnt + kwpos2] != 0)
  4890. return kc->offsets[scpos1 * kc->second_cnt + kwpos2];
  4891. }
  4892. if (!ordered)
  4893. {
  4894. if ((infirst & 2) && (insecond & 1))
  4895. {
  4896. if (kc->offsets[kwpos1 * kc->second_cnt + scpos2] != 0)
  4897. return kc->offsets[kwpos1 * kc->second_cnt + scpos2];
  4898. }
  4899. }
  4900. return 0;
  4901. }
  4902. int
  4903. KCFindName (char *name, char **classnames, int cnt, int allow_class0)
  4904. {
  4905. int i;
  4906. char *pt, *end, ch;
  4907. for (i = 0; i < cnt; ++i)
  4908. {
  4909. if (classnames[i] == NULL)
  4910. continue;
  4911. for (pt = classnames[i]; *pt; pt = end + 1)
  4912. {
  4913. end = strchr (pt, ' ');
  4914. if (end == NULL)
  4915. end = pt + strlen (pt);
  4916. ch = *end;
  4917. *end = '\0';
  4918. if (strcmp (pt, name) == 0)
  4919. {
  4920. *end = ch;
  4921. return i;
  4922. }
  4923. *end = ch;
  4924. if (ch == '\0')
  4925. break;
  4926. }
  4927. }
  4928. /* If class 0 is specified, then we didn't find anything. If class 0 is */
  4929. /* unspecified then it means "anything" so we found something */
  4930. return classnames[0] != NULL || !allow_class0 ? -1 : 0;
  4931. }
  4932. /* Routines to generate human readable forms of FPST rules */
  4933. static void
  4934. GrowBufferAddLookup (GrowBuf * gb, struct fpst_rule *rule, int seq)
  4935. {
  4936. int i;
  4937. for (i = 0; i < rule->lookup_cnt; ++i)
  4938. {
  4939. if (seq == rule->lookups[i].seq)
  4940. {
  4941. GrowBufferAddStr (gb, "@<");
  4942. GrowBufferAddStr (gb, rule->lookups[i].lookup->lookup_name);
  4943. GrowBufferAddStr (gb, "> ");
  4944. }
  4945. }
  4946. }
  4947. static void
  4948. GrowBufferAddClass (GrowBuf * gb, int class_n, char **classnames, int class_cnt)
  4949. {
  4950. char buffer[20], *str;
  4951. if (class_n < 0 || class_n >= class_cnt)
  4952. {
  4953. IError ("Bad class in FPST");
  4954. class_n = 0;
  4955. }
  4956. if (classnames == NULL || (str = classnames[class_n]) == NULL)
  4957. {
  4958. sprintf (buffer, "%d", class_n);
  4959. str = buffer;
  4960. }
  4961. GrowBufferAddStr (gb, str);
  4962. GrowBufferAdd (gb, ' ');
  4963. }
  4964. int
  4965. GlyphNameCnt (const char *pt)
  4966. {
  4967. int cnt = 0;
  4968. while (*pt)
  4969. {
  4970. while (isspace (*pt))
  4971. ++pt;
  4972. if (*pt == '\0')
  4973. return cnt;
  4974. ++cnt;
  4975. while (!isspace (*pt) && *pt != '\0')
  4976. ++pt;
  4977. }
  4978. return cnt;
  4979. }
  4980. char *
  4981. reverseGlyphNames (char *str)
  4982. {
  4983. char *ret;
  4984. char *rpt, *pt, *start, *spt;
  4985. if (str == NULL)
  4986. return NULL;
  4987. rpt = ret = xmalloc (strlen (str) + 1);
  4988. *ret = '\0';
  4989. for (pt = str + strlen (str); pt > str; pt = start)
  4990. {
  4991. for (start = pt - 1; start >= str && *start != ' '; --start);
  4992. for (spt = start + 1; spt < pt;)
  4993. *rpt++ = *spt++;
  4994. *rpt++ = ' ';
  4995. }
  4996. if (rpt > ret)
  4997. rpt[-1] = '\0';
  4998. return ret;
  4999. }
  5000. /* Note: My string format cannot represent contextual rules were the order */
  5001. /* of application of lookups is not the same as textual order. This rarely */
  5002. /* happens. Adobe's feature files have the same drawback. And there are */
  5003. /* rarely two or more lookups applied by one rule. But it could, so be aware!*/
  5004. char *
  5005. FPSTRule_To_Str (SplineFont *sf, FPST *fpst, struct fpst_rule *rule)
  5006. {
  5007. int i, max = 0;
  5008. char *ret, *npt;
  5009. int seq = 0;
  5010. GrowBuf gb;
  5011. /* Note that nothing in the output distinquishes between back, match and forward */
  5012. /* the thought being that to all intents and purposes, match starts at */
  5013. /* the first lookup and ends at the last. Anything before is back, */
  5014. /* anything after is for *//* Adobe uses this convention in feature files */
  5015. /* Drat. That doesn't work for classes if the back/fore classes differ */
  5016. /* from match classes *//* Adobe doesn't support classes in feature files */
  5017. /* Nor does it work when the lookup needs more than one input characters */
  5018. /* ligature lookups */
  5019. memset (&gb, 0, sizeof (gb));
  5020. switch (fpst->format)
  5021. {
  5022. case pst_glyphs:
  5023. max = (rule->u.glyph.names ? strlen (rule->u.glyph.names) : 0) +
  5024. (rule->u.glyph.back ? strlen (rule->u.glyph.back) : 0) +
  5025. (rule->u.glyph.fore ? strlen (rule->u.glyph.fore) : 0) + 200;
  5026. gb.base = gb.pt = xmalloc (max + 1);
  5027. gb.end = gb.base + max;
  5028. if (rule->u.glyph.back != NULL)
  5029. {
  5030. char *temp;
  5031. GrowBufferAddStr (&gb,
  5032. (temp = reverseGlyphNames (rule->u.glyph.back)));
  5033. free (temp);
  5034. GrowBufferAdd (&gb, ' ');
  5035. }
  5036. if (fpst->type != pst_contextpos && fpst->type != pst_contextsub)
  5037. GrowBufferAddStr (&gb, "| ");
  5038. for (npt = rule->u.glyph.names; isspace (*npt); ++npt)
  5039. /* Skip over leading spaces, if any */ ;
  5040. for (npt = rule->u.glyph.names, seq = 0; *npt; ++seq)
  5041. {
  5042. while (isspace (*npt))
  5043. ++npt;
  5044. while (*npt != '\0' && !isspace (*npt))
  5045. {
  5046. GrowBufferAdd (&gb, *npt++);
  5047. }
  5048. GrowBufferAdd (&gb, ' ');
  5049. GrowBufferAddLookup (&gb, rule, seq);
  5050. }
  5051. if (fpst->type != pst_contextpos && fpst->type != pst_contextsub)
  5052. GrowBufferAddStr (&gb, "| ");
  5053. if (rule->u.glyph.fore != NULL)
  5054. {
  5055. GrowBufferAddStr (&gb, rule->u.glyph.fore);
  5056. }
  5057. break;
  5058. case pst_class:
  5059. /* Reverse the backtrack classes */
  5060. for (i = rule->u.class.bcnt - 1; i >= 0; --i)
  5061. GrowBufferAddClass (&gb, rule->u.class.bclasses[i], fpst->bclassnames,
  5062. fpst->bccnt);
  5063. if (fpst->type != pst_contextpos && fpst->type != pst_contextsub)
  5064. GrowBufferAddStr (&gb, "| ");
  5065. for (i = 0; i < rule->u.class.ncnt; ++i)
  5066. {
  5067. GrowBufferAddClass (&gb, rule->u.class.nclasses[i], fpst->nclassnames,
  5068. fpst->nccnt);
  5069. GrowBufferAddLookup (&gb, rule, i);
  5070. }
  5071. if (fpst->type != pst_contextpos && fpst->type != pst_contextsub)
  5072. GrowBufferAddStr (&gb, "| ");
  5073. for (i = 0; i < rule->u.class.fcnt; ++i)
  5074. GrowBufferAddClass (&gb, rule->u.class.fclasses[i], fpst->fclassnames,
  5075. fpst->fccnt);
  5076. break;
  5077. case pst_coverage:
  5078. case pst_reversecoverage:
  5079. /* Reverse the backtrack tables */
  5080. for (i = rule->u.coverage.bcnt - 1; i >= 0; --i)
  5081. {
  5082. GrowBufferAdd (&gb, '[');
  5083. GrowBufferAddStr (&gb, rule->u.coverage.bcovers[i]);
  5084. GrowBufferAddStr (&gb, "] ");
  5085. }
  5086. if (fpst->type != pst_contextpos && fpst->type != pst_contextsub)
  5087. GrowBufferAddStr (&gb, "| ");
  5088. for (i = 0; i < rule->u.coverage.ncnt; ++i)
  5089. {
  5090. GrowBufferAdd (&gb, '[');
  5091. GrowBufferAddStr (&gb, rule->u.coverage.ncovers[i]);
  5092. GrowBufferAddStr (&gb, "] ");
  5093. if (fpst->format == pst_reversecoverage)
  5094. {
  5095. GrowBufferAddStr (&gb, "=> [");
  5096. GrowBufferAddStr (&gb, rule->u.rcoverage.replacements);
  5097. GrowBufferAddStr (&gb, "] ");
  5098. }
  5099. else
  5100. {
  5101. GrowBufferAddLookup (&gb, rule, i);
  5102. }
  5103. }
  5104. if (fpst->type != pst_contextpos && fpst->type != pst_contextsub)
  5105. GrowBufferAddStr (&gb, "| ");
  5106. for (i = 0; i < rule->u.coverage.fcnt; ++i)
  5107. {
  5108. GrowBufferAdd (&gb, '[');
  5109. GrowBufferAddStr (&gb, rule->u.coverage.fcovers[i]);
  5110. GrowBufferAddStr (&gb, "] ");
  5111. }
  5112. break;
  5113. default:
  5114. IError ("Bad FPST format");
  5115. return NULL;
  5116. }
  5117. if (gb.pt > gb.base && gb.pt[-1] == ' ')
  5118. gb.pt[-1] = '\0';
  5119. ret = xstrdup_or_null ((const char *) gb.base);
  5120. free (gb.base);
  5121. return ret;
  5122. }
  5123. static char *
  5124. my_asprintf (const char *format, ...)
  5125. {
  5126. va_list ap;
  5127. char buffer[400];
  5128. va_start (ap, format);
  5129. vsnprintf (buffer, sizeof (buffer), format, ap);
  5130. va_end (ap);
  5131. return xstrdup_or_null (buffer);
  5132. }
  5133. typedef struct lookuplist
  5134. {
  5135. OTLookup *lookup;
  5136. struct lookuplist *next;
  5137. } LookupList;
  5138. typedef struct matchstr
  5139. {
  5140. char *entity;
  5141. char *replacements; /* For reverse contextual chaining */
  5142. LookupList *lookups;
  5143. } MatchStr;
  5144. /* Returns an error message, a warning, or NULL if parsing were successful */
  5145. /* if successful rule will be filled in. Error msg must be freed */
  5146. char *
  5147. FPSTRule_From_Str (SplineFont *sf, FPST *fpst, struct fpst_rule *rule,
  5148. char *line, int *return_is_warning)
  5149. {
  5150. char *lpt, *start, *end;
  5151. int ch;
  5152. int do_replacements = 0, anylookup = 0;
  5153. int cnt = 0, max = 0;
  5154. MatchStr *parsed = NULL;
  5155. LookupList *ll, *llp;
  5156. int i, j, first, last;
  5157. char *ret;
  5158. int isgpos = fpst->type == pst_contextpos || fpst->type == pst_chainpos;
  5159. OTLookup *lookup;
  5160. /* Parse the string into meaningful chunks. These could be:
  5161. A coverage table (a list of glyph names enclosed in []
  5162. A glyph name (I'll accept this as a degenerate coverage table containing one glyph)
  5163. A class name
  5164. A lookup invocation
  5165. A list of replacement glyphs for a reverse contextual chaining lookup
  5166. (This is a two step process. First parse the replacement marker "=>"
  5167. then parse the coverage table)
  5168. We can also have a mark that we've switched from the backtracking list
  5169. to the match list to the forward list. Might be needed for classes
  5170. */
  5171. first = last = -1;
  5172. *return_is_warning = false;
  5173. for (lpt = line; *lpt;)
  5174. {
  5175. while (isspace (*lpt))
  5176. ++lpt;
  5177. if (*lpt == '\0')
  5178. break;
  5179. start = lpt;
  5180. if (*start == '|')
  5181. {
  5182. if (fpst->type == pst_contextpos || fpst->type == pst_contextsub)
  5183. return (my_asprintf
  5184. (_
  5185. ("Separation marks only meaningful in contextual chaining lookups, starting at: %.20s..."),
  5186. lpt));
  5187. if (first == -1)
  5188. first = cnt;
  5189. else if (last == -1)
  5190. last = cnt - 1;
  5191. else
  5192. return (my_asprintf
  5193. (_("Too many separation marks, starting at: %.20s..."),
  5194. lpt));
  5195. ++lpt;
  5196. continue;
  5197. }
  5198. else if (*start == '[')
  5199. {
  5200. /* A coverage table */
  5201. if (fpst->format != pst_coverage
  5202. && fpst->format != pst_reversecoverage)
  5203. return (my_asprintf
  5204. (_
  5205. ("A coverage table was found in a glyph or class based contextual lookup, starting at: %.20s..."),
  5206. lpt));
  5207. ++start;
  5208. for (lpt = start; *lpt != '\0' && *lpt != ']'; ++lpt);
  5209. if (*lpt != ']')
  5210. return (my_asprintf
  5211. (_("Unterminated coverage table, starting at: %.20s..."),
  5212. start - 1));
  5213. end = lpt++;
  5214. if (do_replacements == 1)
  5215. {
  5216. int rcnt, ecnt;
  5217. do_replacements = 2;
  5218. if (cnt == 0)
  5219. return (my_asprintf
  5220. (_
  5221. ("Replacements must follow the coverage table to which they apply: %s"),
  5222. start - 4));
  5223. ch = *end;
  5224. *end = '\0';
  5225. parsed[cnt].replacements = xstrdup_or_null (start);
  5226. *end = ch;
  5227. rcnt = GlyphNameCnt (parsed[cnt].replacements);
  5228. ecnt = GlyphNameCnt (parsed[cnt].entity);
  5229. if (ecnt == rcnt)
  5230. /* Good */ ;
  5231. else if (rcnt == 1 && ecnt > 1)
  5232. {
  5233. char *newr;
  5234. newr =
  5235. xmalloc (ecnt * (strlen (parsed[cnt].replacements) + 1) +
  5236. 1);
  5237. *newr = '\0';
  5238. for (i = 0; i < ecnt; ++i)
  5239. {
  5240. strcat (newr, parsed[cnt].replacements);
  5241. if (i != ecnt - 1)
  5242. strcat (newr, " ");
  5243. }
  5244. free (parsed[cnt].replacements);
  5245. parsed[cnt].replacements = newr;
  5246. }
  5247. else
  5248. return (my_asprintf
  5249. (_
  5250. ("There must be as many replacement glyphs as there are match glyphs: %s => %s"),
  5251. parsed[cnt].entity, parsed[cnt].replacements));
  5252. continue;
  5253. }
  5254. }
  5255. else if (*start != '@' && *start != '<'
  5256. && !(*start == '=' && start[1] == '>'))
  5257. {
  5258. /* Just a normal glyph or class name. (If we expect a coverage table we'll treat it as a table with one glyph) */
  5259. while (*lpt != '\0' && !isspace (*lpt) && *lpt != '@' && *lpt != '<'
  5260. && *lpt != '[')
  5261. ++lpt;
  5262. end = lpt;
  5263. }
  5264. else if (*start == '=' && start[1] == '>')
  5265. {
  5266. /* A reverse contextual chaining */
  5267. if (fpst->format != pst_reversecoverage)
  5268. return (my_asprintf
  5269. (_
  5270. ("No replacement lists may be specified in this contextual lookup, use a nested lookup instead, starting at: %.20s..."),
  5271. lpt));
  5272. if (do_replacements)
  5273. return (my_asprintf
  5274. (_
  5275. ("Only one replacement list may be specified in a reverse contextual chaining lookup, starting at: %.20s..."),
  5276. lpt));
  5277. do_replacements = true;
  5278. lpt += 2;
  5279. }
  5280. else
  5281. {
  5282. /* A lookup invocation */
  5283. if (fpst->format == pst_reversecoverage)
  5284. return (my_asprintf
  5285. (_
  5286. ("No lookups may be specified in a reverse contextual lookup (use a replacement list instead), starting at: %.20s..."),
  5287. lpt));
  5288. if (*start == '@')
  5289. {
  5290. for (lpt = start + 1; isspace (*lpt); ++lpt);
  5291. if (*lpt != '<')
  5292. return (my_asprintf
  5293. (_
  5294. ("A lookup invocation must be started by the sequence '@<' and ended with '>', starting at: %.20s..."),
  5295. start));
  5296. }
  5297. start = ++lpt;
  5298. for (lpt = start; *lpt != '\0' && *lpt != '>'; ++lpt);
  5299. if (*lpt != '>')
  5300. return (my_asprintf
  5301. (_("Unterminated lookup invocation, starting at: %.20s..."),
  5302. start - 1));
  5303. *lpt = '\0';
  5304. lookup = SFFindLookup (sf, start);
  5305. if (lookup == NULL)
  5306. {
  5307. ret = my_asprintf (_("Unknown lookup: %s"), start);
  5308. *lpt = '>';
  5309. return ret;
  5310. }
  5311. else if ((isgpos && lookup->lookup_type < gpos_start)
  5312. || (!isgpos && lookup->lookup_type > gpos_start))
  5313. {
  5314. ret =
  5315. my_asprintf (isgpos ?
  5316. _
  5317. ("GSUB lookup refered to in this GPOS contextual lookup: %s")
  5318. :
  5319. _
  5320. ("GPOS lookup refered to in this GSUB contextual lookup: %s"),
  5321. start);
  5322. *lpt = '>';
  5323. return ret;
  5324. }
  5325. else if (cnt == 0)
  5326. {
  5327. ret =
  5328. my_asprintf (_
  5329. ("Lookups must follow the glyph, class or coverage table to which they apply: %s"),
  5330. start);
  5331. *lpt = '>';
  5332. return ret;
  5333. }
  5334. *lpt++ = '>';
  5335. ll = xzalloc (sizeof (LookupList));
  5336. ll->lookup = lookup;
  5337. /* Lookup order is important */
  5338. if (parsed[cnt - 1].lookups == NULL)
  5339. parsed[cnt - 1].lookups = ll;
  5340. else
  5341. {
  5342. for (llp = parsed[cnt - 1].lookups; llp->next != NULL;
  5343. llp = llp->next);
  5344. llp->next = ll;
  5345. }
  5346. anylookup = true;
  5347. if (first == -1)
  5348. first = cnt - 1;
  5349. continue;
  5350. }
  5351. /* We get here on glyph/class names and coverage tables */
  5352. /* not on lookup invocations */
  5353. ch = *end;
  5354. *end = '\0';
  5355. if (cnt >= max)
  5356. parsed = xrealloc (parsed, (max += 200) * sizeof (MatchStr));
  5357. memset (&parsed[cnt], '\0', sizeof (MatchStr));
  5358. parsed[cnt++].entity = xstrdup_or_null (start);
  5359. *end = ch;
  5360. }
  5361. if (cnt == 0)
  5362. return xstrdup_or_null (_("Empty rule"));
  5363. ret = NULL;
  5364. if (!do_replacements && !anylookup)
  5365. {
  5366. if (fpst->format == pst_reversecoverage)
  5367. return (xstrdup_or_null
  5368. (_
  5369. ("A reverse contextual chaining lookup must have a set of replacement glyphs somewhere")));
  5370. else
  5371. {
  5372. *return_is_warning = true;
  5373. /* If there are no lookups then this rule matches and does nothing */
  5374. /* which can make it easier to write subsequent rules */
  5375. ret = xstrdup_or_null (_("This contextual rule applies no lookups."));
  5376. }
  5377. }
  5378. /* Figure out the boundaries between backtrack, match and forward */
  5379. for (i = 0; i < cnt; ++i)
  5380. {
  5381. if (parsed[i].lookups != NULL)
  5382. {
  5383. if (i > last)
  5384. last = i;
  5385. if (first == -1)
  5386. first = i;
  5387. }
  5388. if (parsed[i].replacements != NULL)
  5389. {
  5390. if ((first != -1 && first != i) || (last != -1 && last != i))
  5391. return (xstrdup_or_null
  5392. (_
  5393. ("A reverse contextual chaining lookup can only match one coverage table directly")));
  5394. first = last = i;
  5395. }
  5396. }
  5397. if (fpst->type == pst_contextpos || fpst->type == pst_contextsub)
  5398. {
  5399. first = 0;
  5400. last = cnt - 1;
  5401. }
  5402. switch (fpst->format)
  5403. {
  5404. case pst_glyphs:
  5405. {
  5406. int blen = 0, mlen = 0, flen = 0;
  5407. for (i = 0; i < cnt; ++i)
  5408. {
  5409. if (SFGetChar (sf, -1, parsed[i].entity) == NULL)
  5410. {
  5411. if (ret == NULL)
  5412. {
  5413. ret =
  5414. my_asprintf (_
  5415. ("There is no glyph named \"%s\" in the font."),
  5416. parsed[i].entity);
  5417. *return_is_warning = true;
  5418. }
  5419. }
  5420. if (i < first)
  5421. blen += strlen (parsed[i].entity) + 1;
  5422. else if (i <= last)
  5423. mlen += strlen (parsed[i].entity) + 1;
  5424. else
  5425. flen += strlen (parsed[i].entity) + 1;
  5426. }
  5427. rule->u.glyph.names = xcalloc (mlen + 1, 1);
  5428. if (blen != 0)
  5429. rule->u.glyph.back = xcalloc (blen + 1, 1);
  5430. if (flen != 0)
  5431. rule->u.glyph.fore = xcalloc (flen + 1, 1);
  5432. for (i = 0; i < cnt; ++i)
  5433. {
  5434. if (i < first)
  5435. {
  5436. strcat (rule->u.glyph.back, parsed[i].entity);
  5437. if (i != first - 1)
  5438. strcat (rule->u.glyph.back, " ");
  5439. }
  5440. else if (i <= last)
  5441. {
  5442. strcat (rule->u.glyph.names, parsed[i].entity);
  5443. if (i != last)
  5444. strcat (rule->u.glyph.names, " ");
  5445. }
  5446. else
  5447. {
  5448. strcat (rule->u.glyph.fore, parsed[i].entity);
  5449. if (i != cnt - 1)
  5450. strcat (rule->u.glyph.fore, " ");
  5451. }
  5452. }
  5453. if (blen != 0)
  5454. {
  5455. char *temp = reverseGlyphNames (rule->u.glyph.back);
  5456. free (rule->u.glyph.back);
  5457. rule->u.glyph.back = temp;
  5458. }
  5459. } break;
  5460. case pst_class:
  5461. rule->u.class.ncnt = last + 1 - first;
  5462. rule->u.class.nclasses = xmalloc (rule->u.class.ncnt * sizeof (uint16_t));
  5463. rule->u.class.bcnt = first;
  5464. if (first != 0)
  5465. rule->u.class.bclasses = xmalloc (first * sizeof (uint16_t));
  5466. rule->u.class.fcnt = cnt == last ? 0 : cnt - last - 1;
  5467. if (rule->u.class.fcnt != 0)
  5468. rule->u.class.fclasses =
  5469. xmalloc (rule->u.class.fcnt * sizeof (uint16_t));
  5470. for (i = 0; i < cnt; ++i)
  5471. {
  5472. char **classnames, *pend;
  5473. int class_cnt, val;
  5474. if (i < first)
  5475. {
  5476. classnames = fpst->bclassnames;
  5477. class_cnt = fpst->bccnt;
  5478. }
  5479. else if (i <= last)
  5480. {
  5481. classnames = fpst->nclassnames;
  5482. class_cnt = fpst->nccnt;
  5483. }
  5484. else
  5485. {
  5486. classnames = fpst->fclassnames;
  5487. class_cnt = fpst->fccnt;
  5488. }
  5489. val = strtol (parsed[i].entity, &pend, 10);
  5490. if (*pend != '\0')
  5491. val = -1;
  5492. for (j = 0; j < class_cnt; ++j)
  5493. {
  5494. if (classnames[j] != NULL)
  5495. {
  5496. if (strcmp (parsed[i].entity, classnames[j]) == 0)
  5497. break;
  5498. }
  5499. else
  5500. {
  5501. if (val == j)
  5502. break;
  5503. }
  5504. }
  5505. if (j == class_cnt)
  5506. {
  5507. free (rule->u.class.nclasses);
  5508. rule->u.class.nclasses = NULL;
  5509. free (rule->u.class.bclasses);
  5510. rule->u.class.bclasses = NULL;
  5511. free (rule->u.class.fclasses);
  5512. rule->u.class.fclasses = NULL;
  5513. rule->u.class.bcnt = rule->u.class.fcnt = rule->u.class.ncnt = 0;
  5514. if (i < first)
  5515. return (my_asprintf
  5516. (_
  5517. ("%s is not a class name for the backtracking classes."),
  5518. parsed[i].entity));
  5519. else if (i <= last)
  5520. return (my_asprintf
  5521. (_("%s is not a class name for the matching classes."),
  5522. parsed[i].entity));
  5523. else
  5524. return (my_asprintf
  5525. (_("%s is not a class name for the forward classes."),
  5526. parsed[i].entity));
  5527. }
  5528. if (i < first)
  5529. rule->u.class.bclasses[first - 1 - i] = j; /* Reverse the backtrack classes */
  5530. else if (i <= last)
  5531. rule->u.class.nclasses[i - first] = j;
  5532. else
  5533. rule->u.class.fclasses[i - last - 1] = j;
  5534. }
  5535. break;
  5536. case pst_coverage:
  5537. case pst_reversecoverage:
  5538. for (i = 0; i < cnt; ++i)
  5539. {
  5540. for (lpt = parsed[i].entity; *lpt;)
  5541. {
  5542. while (isspace (*lpt))
  5543. ++lpt;
  5544. if (*lpt == '\0')
  5545. break;
  5546. start = lpt;
  5547. while (!isspace (*lpt) && *lpt != '\0')
  5548. ++lpt;
  5549. ch = *lpt;
  5550. *lpt = '\0';
  5551. if (SFGetChar (sf, -1, start) == NULL)
  5552. {
  5553. if (ret == NULL)
  5554. {
  5555. ret =
  5556. my_asprintf (_
  5557. ("There is no glyph named \"%s\" in the font."),
  5558. start);
  5559. *return_is_warning = true;
  5560. }
  5561. }
  5562. *lpt = ch;
  5563. }
  5564. }
  5565. rule->u.coverage.ncnt = last + 1 - first;
  5566. rule->u.coverage.ncovers =
  5567. xmalloc (rule->u.coverage.ncnt * sizeof (char *));
  5568. rule->u.coverage.bcnt = first;
  5569. if (first != 0)
  5570. rule->u.coverage.bcovers = xmalloc (first * sizeof (char *));
  5571. rule->u.coverage.fcnt = cnt - last - 1;
  5572. if (rule->u.coverage.fcnt != 0)
  5573. rule->u.coverage.fcovers =
  5574. xmalloc (rule->u.coverage.fcnt * sizeof (char *));
  5575. for (i = 0; i < cnt; ++i)
  5576. {
  5577. if (i < first)
  5578. rule->u.coverage.bcovers[first - 1 - i] = parsed[i].entity; /* Reverse the order of backtrack coverage tables */
  5579. else if (i <= last)
  5580. {
  5581. rule->u.coverage.ncovers[i - first] = parsed[i].entity;
  5582. if (fpst->format == pst_reversecoverage)
  5583. {
  5584. rule->u.rcoverage.replacements = parsed[i].replacements;
  5585. parsed[i].replacements = NULL;
  5586. }
  5587. }
  5588. else
  5589. rule->u.coverage.ncovers[i - last - 1] = parsed[i].entity;
  5590. parsed[i].entity = NULL;
  5591. }
  5592. break;
  5593. default:
  5594. return xstrdup_or_null (_("Bad FPST format"));
  5595. }
  5596. if (fpst->format != pst_reversecoverage)
  5597. {
  5598. int tot = 0;
  5599. for (i = first; i <= last; ++i)
  5600. {
  5601. for (ll = parsed[i].lookups; ll != NULL; ll = ll->next)
  5602. ++tot;
  5603. }
  5604. rule->lookups = xcalloc (tot, sizeof (struct seqlookup));
  5605. rule->lookup_cnt = tot;
  5606. tot = 0;
  5607. for (i = first; i <= last; ++i)
  5608. {
  5609. for (ll = parsed[i].lookups; ll != NULL; ll = llp)
  5610. {
  5611. llp = ll->next;
  5612. rule->lookups[tot].seq = i - first;
  5613. rule->lookups[tot].lookup = ll->lookup;
  5614. ++tot;
  5615. free (ll);
  5616. }
  5617. }
  5618. }
  5619. for (i = 0; i < cnt; ++i)
  5620. free (parsed[i].entity);
  5621. free (parsed);
  5622. return ret;
  5623. }
  5624. /* User interface functionality when we have no UI */
  5625. static void
  5626. NOFI_SortInsertLookup (SplineFont *sf, OTLookup *newotl)
  5627. {
  5628. }
  5629. static void
  5630. NOFI_OTLookupCopyInto (SplineFont *into_sf, SplineFont *from_sf,
  5631. OTLookup *from_otl, OTLookup *to_otl, int scnt,
  5632. OTLookup *before)
  5633. {
  5634. }
  5635. static void
  5636. NOFI_Destroy (SplineFont *sf)
  5637. {
  5638. }
  5639. struct fi_interface noui_fi = {
  5640. NOFI_SortInsertLookup,
  5641. NOFI_OTLookupCopyInto,
  5642. NOFI_Destroy
  5643. };
  5644. struct fi_interface *fi_interface = &noui_fi;
  5645. void
  5646. FF_SetFIInterface (struct fi_interface *fii)
  5647. {
  5648. fi_interface = fii;
  5649. }