PageRenderTime 44ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/gfx/ots/src/gsub.cc

https://bitbucket.org/careytilden/mozilla-central
C++ | 673 lines | 512 code | 86 blank | 75 comment | 118 complexity | 52bb377b5d16159b53430f714f565f50 MD5 | raw file
Possible License(s): MIT, LGPL-2.1, GPL-2.0, Apache-2.0, LGPL-3.0, AGPL-1.0, MPL-2.0-no-copyleft-exception, BSD-3-Clause, JSON, 0BSD
  1. // Copyright (c) 2011 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "gsub.h"
  5. #include <limits>
  6. #include <vector>
  7. #include "gdef.h"
  8. #include "gpos.h"
  9. #include "layout.h"
  10. #include "maxp.h"
  11. // GSUB - The Glyph Substitution Table
  12. // http://www.microsoft.com/typography/otspec/gsub.htm
  13. namespace {
  14. // The GSUB header size
  15. const size_t kGsubHeaderSize = 8;
  16. enum GSUB_TYPE {
  17. GSUB_TYPE_SINGLE = 1,
  18. GSUB_TYPE_MULTIPLE = 2,
  19. GSUB_TYPE_ALTERNATE = 3,
  20. GSUB_TYPE_LIGATURE = 4,
  21. GSUB_TYPE_CONTEXT = 5,
  22. GSUB_TYPE_CHANGING_CONTEXT = 6,
  23. GSUB_TYPE_EXTENSION_SUBSTITUTION = 7,
  24. GSUB_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE = 8,
  25. GSUB_TYPE_RESERVED = 9
  26. };
  27. // Lookup type parsers.
  28. bool ParseSingleSubstitution(const ots::OpenTypeFile *file,
  29. const uint8_t *data, const size_t length);
  30. bool ParseMutipleSubstitution(const ots::OpenTypeFile *file,
  31. const uint8_t *data, const size_t length);
  32. bool ParseAlternateSubstitution(const ots::OpenTypeFile *file,
  33. const uint8_t *data, const size_t length);
  34. bool ParseLigatureSubstitution(const ots::OpenTypeFile *file,
  35. const uint8_t *data, const size_t length);
  36. bool ParseContextSubstitution(const ots::OpenTypeFile *file,
  37. const uint8_t *data, const size_t length);
  38. bool ParseChainingContextSubstitution(const ots::OpenTypeFile *file,
  39. const uint8_t *data,
  40. const size_t length);
  41. bool ParseExtensionSubstitution(const ots::OpenTypeFile *file,
  42. const uint8_t *data, const size_t length);
  43. bool ParseReverseChainingContextSingleSubstitution(
  44. const ots::OpenTypeFile *file, const uint8_t *data, const size_t length);
  45. const ots::LookupSubtableParser::TypeParser kGsubTypeParsers[] = {
  46. {GSUB_TYPE_SINGLE, ParseSingleSubstitution},
  47. {GSUB_TYPE_MULTIPLE, ParseMutipleSubstitution},
  48. {GSUB_TYPE_ALTERNATE, ParseAlternateSubstitution},
  49. {GSUB_TYPE_LIGATURE, ParseLigatureSubstitution},
  50. {GSUB_TYPE_CONTEXT, ParseContextSubstitution},
  51. {GSUB_TYPE_CHANGING_CONTEXT, ParseChainingContextSubstitution},
  52. {GSUB_TYPE_EXTENSION_SUBSTITUTION, ParseExtensionSubstitution},
  53. {GSUB_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE,
  54. ParseReverseChainingContextSingleSubstitution}
  55. };
  56. const ots::LookupSubtableParser kGsubLookupSubtableParser = {
  57. GSUB_TYPE_RESERVED, GSUB_TYPE_EXTENSION_SUBSTITUTION, kGsubTypeParsers
  58. };
  59. // Lookup Type 1:
  60. // Single Substitution Subtable
  61. bool ParseSingleSubstitution(const ots::OpenTypeFile *file,
  62. const uint8_t *data, const size_t length) {
  63. ots::Buffer subtable(data, length);
  64. uint16_t format = 0;
  65. uint16_t offset_coverage = 0;
  66. if (!subtable.ReadU16(&format) ||
  67. !subtable.ReadU16(&offset_coverage)) {
  68. return OTS_FAILURE();
  69. }
  70. const uint16_t num_glyphs = file->maxp->num_glyphs;
  71. if (format == 1) {
  72. // Parse SingleSubstFormat1
  73. int16_t delta_glyph_id = 0;
  74. if (!subtable.ReadS16(&delta_glyph_id)) {
  75. return OTS_FAILURE();
  76. }
  77. if (std::abs(delta_glyph_id) >= num_glyphs) {
  78. return OTS_FAILURE();
  79. }
  80. } else if (format == 2) {
  81. // Parse SingleSubstFormat2
  82. uint16_t glyph_count = 0;
  83. if (!subtable.ReadU16(&glyph_count)) {
  84. return OTS_FAILURE();
  85. }
  86. if (glyph_count > num_glyphs) {
  87. return OTS_FAILURE();
  88. }
  89. for (unsigned i = 0; i < glyph_count; ++i) {
  90. uint16_t substitute = 0;
  91. if (!subtable.ReadU16(&substitute)) {
  92. return OTS_FAILURE();
  93. }
  94. if (substitute >= num_glyphs) {
  95. OTS_WARNING("too large substitute: %u", substitute);
  96. return OTS_FAILURE();
  97. }
  98. }
  99. } else {
  100. return OTS_FAILURE();
  101. }
  102. if (offset_coverage < subtable.offset() || offset_coverage >= length) {
  103. return OTS_FAILURE();
  104. }
  105. if (!ots::ParseCoverageTable(data + offset_coverage,
  106. length - offset_coverage, num_glyphs)) {
  107. return OTS_FAILURE();
  108. }
  109. return true;
  110. }
  111. bool ParseSequenceTable(const uint8_t *data, const size_t length,
  112. const uint16_t num_glyphs) {
  113. ots::Buffer subtable(data, length);
  114. uint16_t glyph_count = 0;
  115. if (!subtable.ReadU16(&glyph_count)) {
  116. return OTS_FAILURE();
  117. }
  118. if (glyph_count > num_glyphs) {
  119. return OTS_FAILURE();
  120. }
  121. for (unsigned i = 0; i < glyph_count; ++i) {
  122. uint16_t substitute = 0;
  123. if (!subtable.ReadU16(&substitute)) {
  124. return OTS_FAILURE();
  125. }
  126. if (substitute >= num_glyphs) {
  127. return OTS_FAILURE();
  128. }
  129. }
  130. return true;
  131. }
  132. // Lookup Type 2:
  133. // Multiple Substitution Subtable
  134. bool ParseMutipleSubstitution(const ots::OpenTypeFile *file,
  135. const uint8_t *data, const size_t length) {
  136. ots::Buffer subtable(data, length);
  137. uint16_t format = 0;
  138. uint16_t offset_coverage = 0;
  139. uint16_t sequence_count = 0;
  140. if (!subtable.ReadU16(&format) ||
  141. !subtable.ReadU16(&offset_coverage) ||
  142. !subtable.ReadU16(&sequence_count)) {
  143. return OTS_FAILURE();
  144. }
  145. if (format != 1) {
  146. return OTS_FAILURE();
  147. }
  148. const uint16_t num_glyphs = file->maxp->num_glyphs;
  149. const unsigned sequence_end = static_cast<unsigned>(6) +
  150. sequence_count * 2;
  151. if (sequence_end > std::numeric_limits<uint16_t>::max()) {
  152. return OTS_FAILURE();
  153. }
  154. for (unsigned i = 0; i < sequence_count; ++i) {
  155. uint16_t offset_sequence = 0;
  156. if (!subtable.ReadU16(&offset_sequence)) {
  157. return OTS_FAILURE();
  158. }
  159. if (offset_sequence < sequence_end || offset_sequence >= length) {
  160. return OTS_FAILURE();
  161. }
  162. if (!ParseSequenceTable(data + offset_sequence, length - offset_sequence,
  163. num_glyphs)) {
  164. return OTS_FAILURE();
  165. }
  166. }
  167. if (offset_coverage < sequence_end || offset_coverage >= length) {
  168. return OTS_FAILURE();
  169. }
  170. if (!ots::ParseCoverageTable(data + offset_coverage,
  171. length - offset_coverage, num_glyphs)) {
  172. return OTS_FAILURE();
  173. }
  174. return true;
  175. }
  176. bool ParseAlternateSetTable(const uint8_t *data, const size_t length,
  177. const uint16_t num_glyphs) {
  178. ots::Buffer subtable(data, length);
  179. uint16_t glyph_count = 0;
  180. if (!subtable.ReadU16(&glyph_count)) {
  181. return OTS_FAILURE();
  182. }
  183. if (glyph_count > num_glyphs) {
  184. return OTS_FAILURE();
  185. }
  186. for (unsigned i = 0; i < glyph_count; ++i) {
  187. uint16_t alternate = 0;
  188. if (!subtable.ReadU16(&alternate)) {
  189. return OTS_FAILURE();
  190. }
  191. if (alternate >= num_glyphs) {
  192. OTS_WARNING("too arge alternate: %u", alternate);
  193. return OTS_FAILURE();
  194. }
  195. }
  196. return true;
  197. }
  198. // Lookup Type 3:
  199. // Alternate Substitution Subtable
  200. bool ParseAlternateSubstitution(const ots::OpenTypeFile *file,
  201. const uint8_t *data, const size_t length) {
  202. ots::Buffer subtable(data, length);
  203. uint16_t format = 0;
  204. uint16_t offset_coverage = 0;
  205. uint16_t alternate_set_count = 0;
  206. if (!subtable.ReadU16(&format) ||
  207. !subtable.ReadU16(&offset_coverage) ||
  208. !subtable.ReadU16(&alternate_set_count)) {
  209. return OTS_FAILURE();
  210. }
  211. if (format != 1) {
  212. return OTS_FAILURE();
  213. }
  214. const uint16_t num_glyphs = file->maxp->num_glyphs;
  215. const unsigned alternate_set_end = static_cast<unsigned>(6) +
  216. alternate_set_count * 2;
  217. if (alternate_set_end > std::numeric_limits<uint16_t>::max()) {
  218. return OTS_FAILURE();
  219. }
  220. for (unsigned i = 0; i < alternate_set_count; ++i) {
  221. uint16_t offset_alternate_set = 0;
  222. if (!subtable.ReadU16(&offset_alternate_set)) {
  223. return OTS_FAILURE();
  224. }
  225. if (offset_alternate_set < alternate_set_end ||
  226. offset_alternate_set >= length) {
  227. return OTS_FAILURE();
  228. }
  229. if (!ParseAlternateSetTable(data + offset_alternate_set,
  230. length - offset_alternate_set,
  231. num_glyphs)) {
  232. return OTS_FAILURE();
  233. }
  234. }
  235. if (offset_coverage < alternate_set_end || offset_coverage >= length) {
  236. return OTS_FAILURE();
  237. }
  238. if (!ots::ParseCoverageTable(data + offset_coverage,
  239. length - offset_coverage, num_glyphs)) {
  240. return OTS_FAILURE();
  241. }
  242. return true;
  243. }
  244. bool ParseLigatureTable(const uint8_t *data, const size_t length,
  245. const uint16_t num_glyphs) {
  246. ots::Buffer subtable(data, length);
  247. uint16_t lig_glyph = 0;
  248. uint16_t comp_count = 0;
  249. if (!subtable.ReadU16(&lig_glyph) ||
  250. !subtable.ReadU16(&comp_count)) {
  251. return OTS_FAILURE();
  252. }
  253. if (lig_glyph >= num_glyphs) {
  254. OTS_WARNING("too large lig_glyph: %u", lig_glyph);
  255. return OTS_FAILURE();
  256. }
  257. if (comp_count == 0 || comp_count > num_glyphs) {
  258. return OTS_FAILURE();
  259. }
  260. for (unsigned i = 0; i < comp_count - static_cast<unsigned>(1); ++i) {
  261. uint16_t component = 0;
  262. if (!subtable.ReadU16(&component)) {
  263. return OTS_FAILURE();
  264. }
  265. if (component >= num_glyphs) {
  266. return OTS_FAILURE();
  267. }
  268. }
  269. return true;
  270. }
  271. bool ParseLigatureSetTable(const uint8_t *data, const size_t length,
  272. const uint16_t num_glyphs) {
  273. ots::Buffer subtable(data, length);
  274. uint16_t ligature_count = 0;
  275. if (!subtable.ReadU16(&ligature_count)) {
  276. return OTS_FAILURE();
  277. }
  278. const unsigned ligature_end = static_cast<unsigned>(2) + ligature_count * 2;
  279. if (ligature_end > std::numeric_limits<uint16_t>::max()) {
  280. return OTS_FAILURE();
  281. }
  282. for (unsigned i = 0; i < ligature_count; ++i) {
  283. uint16_t offset_ligature = 0;
  284. if (!subtable.ReadU16(&offset_ligature)) {
  285. return OTS_FAILURE();
  286. }
  287. if (offset_ligature < ligature_end || offset_ligature >= length) {
  288. return OTS_FAILURE();
  289. }
  290. if (!ParseLigatureTable(data + offset_ligature, length - offset_ligature,
  291. num_glyphs)) {
  292. return OTS_FAILURE();
  293. }
  294. }
  295. return true;
  296. }
  297. // Lookup Type 4:
  298. // Ligature Substitution Subtable
  299. bool ParseLigatureSubstitution(const ots::OpenTypeFile *file,
  300. const uint8_t *data, const size_t length) {
  301. ots::Buffer subtable(data, length);
  302. uint16_t format = 0;
  303. uint16_t offset_coverage = 0;
  304. uint16_t lig_set_count = 0;
  305. if (!subtable.ReadU16(&format) ||
  306. !subtable.ReadU16(&offset_coverage) ||
  307. !subtable.ReadU16(&lig_set_count)) {
  308. return OTS_FAILURE();
  309. }
  310. if (format != 1) {
  311. return OTS_FAILURE();
  312. }
  313. const uint16_t num_glyphs = file->maxp->num_glyphs;
  314. const unsigned ligature_set_end = static_cast<unsigned>(6) +
  315. lig_set_count * 2;
  316. if (ligature_set_end > std::numeric_limits<uint16_t>::max()) {
  317. return OTS_FAILURE();
  318. }
  319. for (unsigned i = 0; i < lig_set_count; ++i) {
  320. uint16_t offset_ligature_set = 0;
  321. if (!subtable.ReadU16(&offset_ligature_set)) {
  322. return OTS_FAILURE();
  323. }
  324. if (offset_ligature_set < ligature_set_end ||
  325. offset_ligature_set >= length) {
  326. return OTS_FAILURE();
  327. }
  328. if (!ParseLigatureSetTable(data + offset_ligature_set,
  329. length - offset_ligature_set, num_glyphs)) {
  330. return OTS_FAILURE();
  331. }
  332. }
  333. if (offset_coverage < ligature_set_end || offset_coverage >= length) {
  334. return OTS_FAILURE();
  335. }
  336. if (!ots::ParseCoverageTable(data + offset_coverage,
  337. length - offset_coverage, num_glyphs)) {
  338. return OTS_FAILURE();
  339. }
  340. return true;
  341. }
  342. // Lookup Type 5:
  343. // Contextual Substitution Subtable
  344. bool ParseContextSubstitution(const ots::OpenTypeFile *file,
  345. const uint8_t *data, const size_t length) {
  346. return ots::ParseContextSubtable(data, length, file->maxp->num_glyphs,
  347. file->gsub->num_lookups);
  348. }
  349. // Lookup Type 6:
  350. // Chaining Contextual Substitution Subtable
  351. bool ParseChainingContextSubstitution(const ots::OpenTypeFile *file,
  352. const uint8_t *data,
  353. const size_t length) {
  354. return ots::ParseChainingContextSubtable(data, length,
  355. file->maxp->num_glyphs,
  356. file->gsub->num_lookups);
  357. }
  358. // Lookup Type 7:
  359. // Extension Substition
  360. bool ParseExtensionSubstitution(const ots::OpenTypeFile *file,
  361. const uint8_t *data, const size_t length) {
  362. return ots::ParseExtensionSubtable(file, data, length,
  363. &kGsubLookupSubtableParser);
  364. }
  365. // Lookup Type 8:
  366. // Reverse Chaining Contexual Single Substitution Subtable
  367. bool ParseReverseChainingContextSingleSubstitution(
  368. const ots::OpenTypeFile *file, const uint8_t *data, const size_t length) {
  369. ots::Buffer subtable(data, length);
  370. uint16_t format = 0;
  371. uint16_t offset_coverage = 0;
  372. if (!subtable.ReadU16(&format) ||
  373. !subtable.ReadU16(&offset_coverage)) {
  374. return OTS_FAILURE();
  375. }
  376. const uint16_t num_glyphs = file->maxp->num_glyphs;
  377. uint16_t backtrack_glyph_count = 0;
  378. if (!subtable.ReadU16(&backtrack_glyph_count)) {
  379. return OTS_FAILURE();
  380. }
  381. if (backtrack_glyph_count > num_glyphs) {
  382. return OTS_FAILURE();
  383. }
  384. std::vector<uint16_t> offsets_backtrack;
  385. offsets_backtrack.reserve(backtrack_glyph_count);
  386. for (unsigned i = 0; i < backtrack_glyph_count; ++i) {
  387. uint16_t offset = 0;
  388. if (!subtable.ReadU16(&offset)) {
  389. return OTS_FAILURE();
  390. }
  391. offsets_backtrack.push_back(offset);
  392. }
  393. uint16_t lookahead_glyph_count = 0;
  394. if (!subtable.ReadU16(&lookahead_glyph_count)) {
  395. return OTS_FAILURE();
  396. }
  397. if (lookahead_glyph_count > num_glyphs) {
  398. return OTS_FAILURE();
  399. }
  400. std::vector<uint16_t> offsets_lookahead;
  401. offsets_lookahead.reserve(lookahead_glyph_count);
  402. for (unsigned i = 0; i < lookahead_glyph_count; ++i) {
  403. uint16_t offset = 0;
  404. if (!subtable.ReadU16(&offset)) {
  405. return OTS_FAILURE();
  406. }
  407. offsets_lookahead.push_back(offset);
  408. }
  409. uint16_t glyph_count = 0;
  410. if (!subtable.ReadU16(&glyph_count)) {
  411. return OTS_FAILURE();
  412. }
  413. if (glyph_count > num_glyphs) {
  414. return OTS_FAILURE();
  415. }
  416. for (unsigned i = 0; i < glyph_count; ++i) {
  417. uint16_t substitute = 0;
  418. if (!subtable.ReadU16(&substitute)) {
  419. return OTS_FAILURE();
  420. }
  421. if (substitute >= num_glyphs) {
  422. return OTS_FAILURE();
  423. }
  424. }
  425. const unsigned substitute_end = static_cast<unsigned>(10) +
  426. (backtrack_glyph_count + lookahead_glyph_count + glyph_count) * 2;
  427. if (substitute_end > std::numeric_limits<uint16_t>::max()) {
  428. return OTS_FAILURE();
  429. }
  430. if (offset_coverage < substitute_end || offset_coverage >= length) {
  431. return OTS_FAILURE();
  432. }
  433. if (!ots::ParseCoverageTable(data + offset_coverage,
  434. length - offset_coverage, num_glyphs)) {
  435. return OTS_FAILURE();
  436. }
  437. for (unsigned i = 0; i < backtrack_glyph_count; ++i) {
  438. if (offsets_backtrack[i] < substitute_end ||
  439. offsets_backtrack[i] >= length) {
  440. return OTS_FAILURE();
  441. }
  442. if (!ots::ParseCoverageTable(data + offsets_backtrack[i],
  443. length - offsets_backtrack[i], num_glyphs)) {
  444. return OTS_FAILURE();
  445. }
  446. }
  447. for (unsigned i = 0; i < lookahead_glyph_count; ++i) {
  448. if (offsets_lookahead[i] < substitute_end ||
  449. offsets_lookahead[i] >= length) {
  450. return OTS_FAILURE();
  451. }
  452. if (!ots::ParseCoverageTable(data + offsets_lookahead[i],
  453. length - offsets_lookahead[i], num_glyphs)) {
  454. return OTS_FAILURE();
  455. }
  456. }
  457. return true;
  458. }
  459. } // namespace
  460. #define DROP_THIS_TABLE \
  461. do { file->gsub->data = 0; file->gsub->length = 0; } while (0)
  462. namespace ots {
  463. // As far as I checked, following fonts contain invalid values in GSUB table.
  464. // OTS will drop their GSUB table.
  465. //
  466. // # too large substitute (value is 0xFFFF)
  467. // kaiu.ttf
  468. // mingliub2.ttf
  469. // mingliub1.ttf
  470. // mingliub0.ttf
  471. // GraublauWeb.otf
  472. // GraublauWebBold.otf
  473. //
  474. // # too large alternate (value is 0xFFFF)
  475. // ManchuFont.ttf
  476. //
  477. // # bad offset to lang sys table (NULL offset)
  478. // DejaVuMonoSansBold.ttf
  479. // DejaVuMonoSansBoldOblique.ttf
  480. // DejaVuMonoSansOblique.ttf
  481. // DejaVuSansMono-BoldOblique.ttf
  482. // DejaVuSansMono-Oblique.ttf
  483. // DejaVuSansMono-Bold.ttf
  484. //
  485. // # bad start coverage index
  486. // GenBasBI.ttf
  487. // GenBasI.ttf
  488. // AndBasR.ttf
  489. // GenBkBasI.ttf
  490. // CharisSILR.ttf
  491. // CharisSILBI.ttf
  492. // CharisSILI.ttf
  493. // CharisSILB.ttf
  494. // DoulosSILR.ttf
  495. // CharisSILBI.ttf
  496. // GenBkBasB.ttf
  497. // GenBkBasR.ttf
  498. // GenBkBasBI.ttf
  499. // GenBasB.ttf
  500. // GenBasR.ttf
  501. //
  502. // # glyph range is overlapping
  503. // KacstTitleL.ttf
  504. // KacstDecorative.ttf
  505. // KacstTitle.ttf
  506. // KacstArt.ttf
  507. // KacstPoster.ttf
  508. // KacstQurn.ttf
  509. // KacstDigital.ttf
  510. // KacstBook.ttf
  511. // KacstFarsi.ttf
  512. bool ots_gsub_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
  513. // Parsing gsub table requires |file->maxp->num_glyphs|
  514. if (!file->maxp) {
  515. return OTS_FAILURE();
  516. }
  517. Buffer table(data, length);
  518. OpenTypeGSUB *gsub = new OpenTypeGSUB;
  519. file->gsub = gsub;
  520. uint32_t version = 0;
  521. uint16_t offset_script_list = 0;
  522. uint16_t offset_feature_list = 0;
  523. uint16_t offset_lookup_list = 0;
  524. if (!table.ReadU32(&version) ||
  525. !table.ReadU16(&offset_script_list) ||
  526. !table.ReadU16(&offset_feature_list) ||
  527. !table.ReadU16(&offset_lookup_list)) {
  528. return OTS_FAILURE();
  529. }
  530. if (version != 0x00010000) {
  531. OTS_WARNING("bad GSUB version");
  532. DROP_THIS_TABLE;
  533. return true;
  534. }
  535. if ((offset_script_list < kGsubHeaderSize ||
  536. offset_script_list >= length) ||
  537. (offset_feature_list < kGsubHeaderSize ||
  538. offset_feature_list >= length) ||
  539. (offset_lookup_list < kGsubHeaderSize ||
  540. offset_lookup_list >= length)) {
  541. OTS_WARNING("bad offset in GSUB header");
  542. DROP_THIS_TABLE;
  543. return true;
  544. }
  545. if (!ParseLookupListTable(file, data + offset_lookup_list,
  546. length - offset_lookup_list,
  547. &kGsubLookupSubtableParser,
  548. &gsub->num_lookups)) {
  549. OTS_WARNING("faild to parse lookup list table");
  550. DROP_THIS_TABLE;
  551. return true;
  552. }
  553. uint16_t num_features = 0;
  554. if (!ParseFeatureListTable(data + offset_feature_list,
  555. length - offset_feature_list, gsub->num_lookups,
  556. &num_features)) {
  557. OTS_WARNING("faild to parse feature list table");
  558. DROP_THIS_TABLE;
  559. return true;
  560. }
  561. if (!ParseScriptListTable(data + offset_script_list,
  562. length - offset_script_list, num_features)) {
  563. OTS_WARNING("faild to parse script list table");
  564. DROP_THIS_TABLE;
  565. return true;
  566. }
  567. gsub->data = data;
  568. gsub->length = length;
  569. return true;
  570. }
  571. bool ots_gsub_should_serialise(OpenTypeFile *file) {
  572. const bool needed_tables_dropped =
  573. (file->gdef && file->gdef->data == NULL) ||
  574. (file->gpos && file->gpos->data == NULL);
  575. return file->gsub != NULL && file->gsub->data != NULL
  576. && !needed_tables_dropped;
  577. }
  578. bool ots_gsub_serialise(OTSStream *out, OpenTypeFile *file) {
  579. if (!out->Write(file->gsub->data, file->gsub->length)) {
  580. return OTS_FAILURE();
  581. }
  582. return true;
  583. }
  584. void ots_gsub_free(OpenTypeFile *file) {
  585. delete file->gsub;
  586. }
  587. } // namespace ots