PageRenderTime 54ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/gfx/ots/src/gsub.cc

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