PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/gfx/ots/src/gsub.cc

https://bitbucket.org/MeeGoAdmin/mozilla-central/
C++ | 691 lines | 528 code | 88 blank | 75 comment | 121 complexity | 13ee9bc992b478a2561b0389e8e40bbc MD5 | raw file
Possible License(s): AGPL-1.0, MIT, BSD-3-Clause, Apache-2.0, LGPL-2.1, 0BSD, LGPL-3.0, MPL-2.0-no-copyleft-exception, GPL-2.0, JSON
  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. bool ParseSubstLookupRecord(ots::Buffer *subtable, const uint16_t num_glyphs,
  343. const uint16_t num_lookups) {
  344. uint16_t sequence_index = 0;
  345. uint16_t lookup_list_index = 0;
  346. if (!subtable->ReadU16(&sequence_index) ||
  347. !subtable->ReadU16(&lookup_list_index)) {
  348. return OTS_FAILURE();
  349. }
  350. if (sequence_index >= num_glyphs) {
  351. return OTS_FAILURE();
  352. }
  353. if (lookup_list_index >= num_lookups) {
  354. return OTS_FAILURE();
  355. }
  356. return true;
  357. }
  358. // Lookup Type 5:
  359. // Contextual Substitution Subtable
  360. bool ParseContextSubstitution(const ots::OpenTypeFile *file,
  361. const uint8_t *data, const size_t length) {
  362. return ots::ParseContextSubtable(data, length, file->maxp->num_glyphs,
  363. file->gsub->num_lookups);
  364. }
  365. // Lookup Type 6:
  366. // Chaining Contextual Substitution Subtable
  367. bool ParseChainingContextSubstitution(const ots::OpenTypeFile *file,
  368. const uint8_t *data,
  369. const size_t length) {
  370. return ots::ParseChainingContextSubtable(data, length,
  371. file->maxp->num_glyphs,
  372. file->gsub->num_lookups);
  373. }
  374. // Lookup Type 7:
  375. // Extension Substition
  376. bool ParseExtensionSubstitution(const ots::OpenTypeFile *file,
  377. const uint8_t *data, const size_t length) {
  378. return ots::ParseExtensionSubtable(file, data, length,
  379. &kGsubLookupSubtableParser);
  380. }
  381. // Lookup Type 8:
  382. // Reverse Chaining Contexual Single Substitution Subtable
  383. bool ParseReverseChainingContextSingleSubstitution(
  384. const ots::OpenTypeFile *file, const uint8_t *data, const size_t length) {
  385. ots::Buffer subtable(data, length);
  386. uint16_t format = 0;
  387. uint16_t offset_coverage = 0;
  388. if (!subtable.ReadU16(&format) ||
  389. !subtable.ReadU16(&offset_coverage)) {
  390. return OTS_FAILURE();
  391. }
  392. const uint16_t num_glyphs = file->maxp->num_glyphs;
  393. uint16_t backtrack_glyph_count = 0;
  394. if (!subtable.ReadU16(&backtrack_glyph_count)) {
  395. return OTS_FAILURE();
  396. }
  397. if (backtrack_glyph_count > num_glyphs) {
  398. return OTS_FAILURE();
  399. }
  400. std::vector<uint16_t> offsets_backtrack;
  401. offsets_backtrack.reserve(backtrack_glyph_count);
  402. for (unsigned i = 0; i < backtrack_glyph_count; ++i) {
  403. uint16_t offset = 0;
  404. if (!subtable.ReadU16(&offset)) {
  405. return OTS_FAILURE();
  406. }
  407. offsets_backtrack.push_back(offset);
  408. }
  409. uint16_t lookahead_glyph_count = 0;
  410. if (!subtable.ReadU16(&lookahead_glyph_count)) {
  411. return OTS_FAILURE();
  412. }
  413. if (lookahead_glyph_count > num_glyphs) {
  414. return OTS_FAILURE();
  415. }
  416. std::vector<uint16_t> offsets_lookahead;
  417. offsets_lookahead.reserve(lookahead_glyph_count);
  418. for (unsigned i = 0; i < lookahead_glyph_count; ++i) {
  419. uint16_t offset = 0;
  420. if (!subtable.ReadU16(&offset)) {
  421. return OTS_FAILURE();
  422. }
  423. offsets_lookahead.push_back(offset);
  424. }
  425. uint16_t glyph_count = 0;
  426. if (!subtable.ReadU16(&glyph_count)) {
  427. return OTS_FAILURE();
  428. }
  429. if (glyph_count > num_glyphs) {
  430. return OTS_FAILURE();
  431. }
  432. for (unsigned i = 0; i < glyph_count; ++i) {
  433. uint16_t substitute = 0;
  434. if (!subtable.ReadU16(&substitute)) {
  435. return OTS_FAILURE();
  436. }
  437. if (substitute >= num_glyphs) {
  438. return OTS_FAILURE();
  439. }
  440. }
  441. const unsigned substitute_end = static_cast<unsigned>(10) +
  442. (backtrack_glyph_count + lookahead_glyph_count + glyph_count) * 2;
  443. if (substitute_end > std::numeric_limits<uint16_t>::max()) {
  444. return OTS_FAILURE();
  445. }
  446. if (offset_coverage < substitute_end || offset_coverage >= length) {
  447. return OTS_FAILURE();
  448. }
  449. if (!ots::ParseCoverageTable(data + offset_coverage,
  450. length - offset_coverage, num_glyphs)) {
  451. return OTS_FAILURE();
  452. }
  453. for (unsigned i = 0; i < backtrack_glyph_count; ++i) {
  454. if (offsets_backtrack[i] < substitute_end ||
  455. offsets_backtrack[i] >= length) {
  456. return OTS_FAILURE();
  457. }
  458. if (!ots::ParseCoverageTable(data + offsets_backtrack[i],
  459. length - offsets_backtrack[i], num_glyphs)) {
  460. return OTS_FAILURE();
  461. }
  462. }
  463. for (unsigned i = 0; i < lookahead_glyph_count; ++i) {
  464. if (offsets_lookahead[i] < substitute_end ||
  465. offsets_lookahead[i] >= length) {
  466. return OTS_FAILURE();
  467. }
  468. if (!ots::ParseCoverageTable(data + offsets_lookahead[i],
  469. length - offsets_lookahead[i], num_glyphs)) {
  470. return OTS_FAILURE();
  471. }
  472. }
  473. return true;
  474. }
  475. } // namespace
  476. #define DROP_THIS_TABLE \
  477. do { file->gsub->data = 0; file->gsub->length = 0; } while (0)
  478. namespace ots {
  479. // As far as I checked, following fonts contain invalid values in GSUB table.
  480. // OTS will drop their GSUB table.
  481. //
  482. // # too large substitute (value is 0xFFFF)
  483. // kaiu.ttf
  484. // mingliub2.ttf
  485. // mingliub1.ttf
  486. // mingliub0.ttf
  487. // GraublauWeb.otf
  488. // GraublauWebBold.otf
  489. //
  490. // # too large alternate (value is 0xFFFF)
  491. // ManchuFont.ttf
  492. //
  493. // # bad offset to lang sys table (NULL offset)
  494. // DejaVuMonoSansBold.ttf
  495. // DejaVuMonoSansBoldOblique.ttf
  496. // DejaVuMonoSansOblique.ttf
  497. // DejaVuSansMono-BoldOblique.ttf
  498. // DejaVuSansMono-Oblique.ttf
  499. // DejaVuSansMono-Bold.ttf
  500. //
  501. // # bad start coverage index
  502. // GenBasBI.ttf
  503. // GenBasI.ttf
  504. // AndBasR.ttf
  505. // GenBkBasI.ttf
  506. // CharisSILR.ttf
  507. // CharisSILBI.ttf
  508. // CharisSILI.ttf
  509. // CharisSILB.ttf
  510. // DoulosSILR.ttf
  511. // CharisSILBI.ttf
  512. // GenBkBasB.ttf
  513. // GenBkBasR.ttf
  514. // GenBkBasBI.ttf
  515. // GenBasB.ttf
  516. // GenBasR.ttf
  517. //
  518. // # glyph range is overlapping
  519. // KacstTitleL.ttf
  520. // KacstDecorative.ttf
  521. // KacstTitle.ttf
  522. // KacstArt.ttf
  523. // KacstPoster.ttf
  524. // KacstQurn.ttf
  525. // KacstDigital.ttf
  526. // KacstBook.ttf
  527. // KacstFarsi.ttf
  528. bool ots_gsub_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
  529. // Parsing gsub table requires |file->maxp->num_glyphs|
  530. if (!file->maxp) {
  531. return OTS_FAILURE();
  532. }
  533. Buffer table(data, length);
  534. OpenTypeGSUB *gsub = new OpenTypeGSUB;
  535. file->gsub = gsub;
  536. uint32_t version = 0;
  537. uint16_t offset_script_list = 0;
  538. uint16_t offset_feature_list = 0;
  539. uint16_t offset_lookup_list = 0;
  540. if (!table.ReadU32(&version) ||
  541. !table.ReadU16(&offset_script_list) ||
  542. !table.ReadU16(&offset_feature_list) ||
  543. !table.ReadU16(&offset_lookup_list)) {
  544. return OTS_FAILURE();
  545. }
  546. if (version != 0x00010000) {
  547. OTS_WARNING("bad GSUB version");
  548. DROP_THIS_TABLE;
  549. return true;
  550. }
  551. if ((offset_script_list < kGsubHeaderSize ||
  552. offset_script_list >= length) ||
  553. (offset_feature_list < kGsubHeaderSize ||
  554. offset_feature_list >= length) ||
  555. (offset_lookup_list < kGsubHeaderSize ||
  556. offset_lookup_list >= length)) {
  557. OTS_WARNING("bad offset in GSUB header");
  558. DROP_THIS_TABLE;
  559. return true;
  560. }
  561. if (!ParseLookupListTable(file, data + offset_lookup_list,
  562. length - offset_lookup_list,
  563. &kGsubLookupSubtableParser,
  564. &gsub->num_lookups)) {
  565. OTS_WARNING("faild to parse lookup list table");
  566. DROP_THIS_TABLE;
  567. return true;
  568. }
  569. uint16_t num_features = 0;
  570. if (!ParseFeatureListTable(data + offset_feature_list,
  571. length - offset_feature_list, gsub->num_lookups,
  572. &num_features)) {
  573. OTS_WARNING("faild to parse feature list table");
  574. DROP_THIS_TABLE;
  575. return true;
  576. }
  577. if (!ParseScriptListTable(data + offset_script_list,
  578. length - offset_script_list, num_features)) {
  579. OTS_WARNING("faild to parse script list table");
  580. DROP_THIS_TABLE;
  581. return true;
  582. }
  583. gsub->data = data;
  584. gsub->length = length;
  585. return true;
  586. }
  587. bool ots_gsub_should_serialise(OpenTypeFile *file) {
  588. const bool needed_tables_dropped =
  589. (file->gdef && file->gdef->data == NULL) ||
  590. (file->gpos && file->gpos->data == NULL);
  591. return file->gsub != NULL && file->gsub->data != NULL
  592. && !needed_tables_dropped;
  593. }
  594. bool ots_gsub_serialise(OTSStream *out, OpenTypeFile *file) {
  595. if (!out->Write(file->gsub->data, file->gsub->length)) {
  596. return OTS_FAILURE();
  597. }
  598. return true;
  599. }
  600. void ots_gsub_free(OpenTypeFile *file) {
  601. delete file->gsub;
  602. }
  603. } // namespace ots