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

/gfx/ots/src/gdef.cc

https://bitbucket.org/MeeGoAdmin/mozilla-central/
C++ | 393 lines | 326 code | 42 blank | 25 comment | 89 complexity | 349a8e6e182a9d526ee64236f4641be9 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 "gdef.h"
  5. #include <limits>
  6. #include <vector>
  7. #include "gpos.h"
  8. #include "gsub.h"
  9. #include "layout.h"
  10. #include "maxp.h"
  11. // GDEF - The Glyph Definition Table
  12. // http://www.microsoft.com/typography/otspec/gdef.htm
  13. namespace {
  14. // The maximum class value in class definition tables.
  15. const uint16_t kMaxClassDefValue = 0xFFFF;
  16. // The maximum class value in the glyph class definision table.
  17. const uint16_t kMaxGlyphClassDefValue = 4;
  18. // The maximum format number of caret value tables.
  19. // We don't support format 3 for now. See the comment in
  20. // ParseLigCaretListTable() for the reason.
  21. const uint16_t kMaxCaretValueFormat = 2;
  22. bool ParseGlyphClassDefTable(ots::OpenTypeFile *file, const uint8_t *data,
  23. size_t length, const uint16_t num_glyphs) {
  24. return ots::ParseClassDefTable(data, length, num_glyphs,
  25. kMaxGlyphClassDefValue);
  26. }
  27. bool ParseAttachListTable(ots::OpenTypeFile *file, const uint8_t *data,
  28. size_t length, const uint16_t num_glyphs) {
  29. ots::Buffer subtable(data, length);
  30. uint16_t offset_coverage = 0;
  31. uint16_t glyph_count = 0;
  32. if (!subtable.ReadU16(&offset_coverage) ||
  33. !subtable.ReadU16(&glyph_count)) {
  34. return OTS_FAILURE();
  35. }
  36. const unsigned attach_points_end = static_cast<unsigned>(4) + 2*glyph_count;
  37. if (attach_points_end > std::numeric_limits<uint16_t>::max()) {
  38. return OTS_FAILURE();
  39. }
  40. if (offset_coverage == 0 || offset_coverage >= length ||
  41. offset_coverage < attach_points_end) {
  42. return OTS_FAILURE();
  43. }
  44. if (glyph_count > num_glyphs) {
  45. OTS_WARNING("bad glyph count: %u", glyph_count);
  46. return OTS_FAILURE();
  47. }
  48. std::vector<uint16_t> attach_points;
  49. attach_points.resize(glyph_count);
  50. for (unsigned i = 0; i < glyph_count; ++i) {
  51. if (!subtable.ReadU16(&attach_points[i])) {
  52. return OTS_FAILURE();
  53. }
  54. if (attach_points[i] >= length ||
  55. attach_points[i] < attach_points_end) {
  56. return OTS_FAILURE();
  57. }
  58. }
  59. // Parse coverage table
  60. if (!ots::ParseCoverageTable(data + offset_coverage,
  61. length - offset_coverage, num_glyphs)) {
  62. return OTS_FAILURE();
  63. }
  64. // Parse attach point table
  65. for (unsigned i = 0; i < attach_points.size(); ++i) {
  66. subtable.set_offset(attach_points[i]);
  67. uint16_t point_count = 0;
  68. if (!subtable.ReadU16(&point_count)) {
  69. return OTS_FAILURE();
  70. }
  71. if (point_count == 0) {
  72. return OTS_FAILURE();
  73. }
  74. uint16_t last_point_index = 0;
  75. uint16_t point_index = 0;
  76. for (unsigned j = 0; j < point_count; ++j) {
  77. if (!subtable.ReadU16(&point_index)) {
  78. return OTS_FAILURE();
  79. }
  80. // Contour point indeces are in increasing numerical order
  81. if (last_point_index != 0 && last_point_index >= point_index) {
  82. OTS_WARNING("bad contour indeces: %u >= %u",
  83. last_point_index, point_index);
  84. return OTS_FAILURE();
  85. }
  86. last_point_index = point_index;
  87. }
  88. }
  89. return true;
  90. }
  91. bool ParseLigCaretListTable(ots::OpenTypeFile *file, const uint8_t *data,
  92. size_t length, const uint16_t num_glyphs) {
  93. ots::Buffer subtable(data, length);
  94. uint16_t offset_coverage = 0;
  95. uint16_t lig_glyph_count = 0;
  96. if (!subtable.ReadU16(&offset_coverage) ||
  97. !subtable.ReadU16(&lig_glyph_count)) {
  98. return OTS_FAILURE();
  99. }
  100. const unsigned lig_glyphs_end = static_cast<unsigned>(4) + 2*lig_glyph_count;
  101. if (lig_glyphs_end > std::numeric_limits<uint16_t>::max()) {
  102. return OTS_FAILURE();
  103. }
  104. if (offset_coverage == 0 || offset_coverage >= length ||
  105. offset_coverage < lig_glyphs_end) {
  106. return OTS_FAILURE();
  107. }
  108. if (lig_glyph_count > num_glyphs) {
  109. OTS_WARNING("bad ligature glyph count: %u", lig_glyph_count);
  110. return OTS_FAILURE();
  111. }
  112. std::vector<uint16_t> lig_glyphs;
  113. lig_glyphs.resize(lig_glyph_count);
  114. for (unsigned i = 0; i < lig_glyph_count; ++i) {
  115. if (!subtable.ReadU16(&lig_glyphs[i])) {
  116. return OTS_FAILURE();
  117. }
  118. if (lig_glyphs[i] >= length || lig_glyphs[i] < lig_glyphs_end) {
  119. return OTS_FAILURE();
  120. }
  121. }
  122. // Parse coverage table
  123. if (!ots::ParseCoverageTable(data + offset_coverage,
  124. length - offset_coverage, num_glyphs)) {
  125. return OTS_FAILURE();
  126. }
  127. // Parse ligature glyph table
  128. for (unsigned i = 0; i < lig_glyphs.size(); ++i) {
  129. subtable.set_offset(lig_glyphs[i]);
  130. uint16_t caret_count = 0;
  131. if (!subtable.ReadU16(&caret_count)) {
  132. return OTS_FAILURE();
  133. }
  134. if (caret_count == 0) {
  135. OTS_WARNING("bad caret value count: %u", caret_count);
  136. return OTS_FAILURE();
  137. }
  138. std::vector<uint16_t> caret_values;
  139. caret_values.resize(caret_count);
  140. uint16_t last_offset_caret = 0;
  141. unsigned caret_values_end = static_cast<unsigned>(2) + 2*caret_count;
  142. for (unsigned j = 0; j < caret_count; ++j) {
  143. if (!subtable.ReadU16(&caret_values[j])) {
  144. return OTS_FAILURE();
  145. }
  146. if (caret_values[j] >= length || caret_values[j] < caret_values_end) {
  147. return OTS_FAILURE();
  148. }
  149. // Caret offsets are in increasing coordinate order
  150. if (last_offset_caret != 0 && last_offset_caret >= caret_values[j]) {
  151. OTS_WARNING("offset isn't in increasing coordinate order: %u >= %u",
  152. last_offset_caret, caret_values[j]);
  153. return OTS_FAILURE();
  154. }
  155. last_offset_caret = caret_values[j];
  156. }
  157. // Parse caret values table
  158. for (unsigned j = 0; j < caret_count; ++j) {
  159. subtable.set_offset(lig_glyphs[i] + caret_values[j]);
  160. uint16_t caret_format = 0;
  161. if (!subtable.ReadU16(&caret_format)) {
  162. return OTS_FAILURE();
  163. }
  164. // TODO(bashi): We only support caret value format 1 and 2 for now
  165. // because there are no fonts which contain caret value format 3
  166. // as far as we investigated.
  167. if (caret_format == 0 || caret_format > kMaxCaretValueFormat) {
  168. OTS_WARNING("bad caret value format: %u", caret_format);
  169. return OTS_FAILURE();
  170. }
  171. // CaretValueFormats contain a 2-byte field which could be
  172. // arbitrary value.
  173. if (!subtable.Skip(2)) {
  174. return OTS_FAILURE();
  175. }
  176. }
  177. }
  178. return true;
  179. }
  180. bool ParseMarkAttachClassDefTable(ots::OpenTypeFile *file, const uint8_t *data,
  181. size_t length, const uint16_t num_glyphs) {
  182. return ots::ParseClassDefTable(data, length, num_glyphs, kMaxClassDefValue);
  183. }
  184. bool ParseMarkGlyphSetsDefTable(ots::OpenTypeFile *file, const uint8_t *data,
  185. size_t length, const uint16_t num_glyphs) {
  186. ots::Buffer subtable(data, length);
  187. uint16_t format = 0;
  188. uint16_t mark_set_count = 0;
  189. if (!subtable.ReadU16(&format) ||
  190. !subtable.ReadU16(&mark_set_count)) {
  191. return OTS_FAILURE();
  192. }
  193. if (format != 1) {
  194. OTS_WARNING("bad mark glyph set table format: %u", format);
  195. return OTS_FAILURE();
  196. }
  197. const unsigned mark_sets_end = static_cast<unsigned>(4) + 2*mark_set_count;
  198. if (mark_sets_end > std::numeric_limits<uint16_t>::max()) {
  199. return OTS_FAILURE();
  200. }
  201. for (unsigned i = 0; i < mark_set_count; ++i) {
  202. uint32_t offset_coverage = 0;
  203. if (!subtable.ReadU32(&offset_coverage)) {
  204. return OTS_FAILURE();
  205. }
  206. if (offset_coverage >= length ||
  207. offset_coverage < mark_sets_end) {
  208. return OTS_FAILURE();
  209. }
  210. if (!ots::ParseCoverageTable(data + offset_coverage,
  211. length - offset_coverage, num_glyphs)) {
  212. return OTS_FAILURE();
  213. }
  214. }
  215. file->gdef->num_mark_glyph_sets = mark_set_count;
  216. return true;
  217. }
  218. } // namespace
  219. #define DROP_THIS_TABLE \
  220. do { file->gdef->data = 0; file->gdef->length = 0; } while (0)
  221. namespace ots {
  222. bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
  223. // Grab the number of glyphs in the file from the maxp table to check
  224. // GlyphIDs in GDEF table.
  225. if (!file->maxp) {
  226. return OTS_FAILURE();
  227. }
  228. const uint16_t num_glyphs = file->maxp->num_glyphs;
  229. Buffer table(data, length);
  230. OpenTypeGDEF *gdef = new OpenTypeGDEF;
  231. file->gdef = gdef;
  232. uint32_t version = 0;
  233. if (!table.ReadU32(&version)) {
  234. return OTS_FAILURE();
  235. }
  236. if (version < 0x00010000 || version == 0x00010001) {
  237. OTS_WARNING("bad GDEF version");
  238. DROP_THIS_TABLE;
  239. return true;
  240. }
  241. if (version >= 0x00010002) {
  242. gdef->version_2 = true;
  243. }
  244. uint16_t offset_glyph_class_def = 0;
  245. uint16_t offset_attach_list = 0;
  246. uint16_t offset_lig_caret_list = 0;
  247. uint16_t offset_mark_attach_class_def = 0;
  248. if (!table.ReadU16(&offset_glyph_class_def) ||
  249. !table.ReadU16(&offset_attach_list) ||
  250. !table.ReadU16(&offset_lig_caret_list) ||
  251. !table.ReadU16(&offset_mark_attach_class_def)) {
  252. return OTS_FAILURE();
  253. }
  254. uint16_t offset_mark_glyph_sets_def = 0;
  255. if (gdef->version_2) {
  256. if (!table.ReadU16(&offset_mark_glyph_sets_def)) {
  257. return OTS_FAILURE();
  258. }
  259. }
  260. const unsigned gdef_header_end = static_cast<unsigned>(8) +
  261. gdef->version_2 ? static_cast<unsigned>(2) : static_cast<unsigned>(0);
  262. if (gdef_header_end > std::numeric_limits<uint16_t>::max()) {
  263. return OTS_FAILURE();
  264. }
  265. // Parse subtables
  266. if (offset_glyph_class_def) {
  267. if (offset_glyph_class_def >= length ||
  268. offset_glyph_class_def < gdef_header_end) {
  269. return OTS_FAILURE();
  270. }
  271. if (!ParseGlyphClassDefTable(file, data + offset_glyph_class_def,
  272. length - offset_glyph_class_def,
  273. num_glyphs)) {
  274. DROP_THIS_TABLE;
  275. return true;
  276. }
  277. gdef->has_glyph_class_def = true;
  278. }
  279. if (offset_attach_list) {
  280. if (offset_attach_list >= length ||
  281. offset_attach_list < gdef_header_end) {
  282. return OTS_FAILURE();
  283. }
  284. if (!ParseAttachListTable(file, data + offset_attach_list,
  285. length - offset_attach_list,
  286. num_glyphs)) {
  287. DROP_THIS_TABLE;
  288. return true;
  289. }
  290. }
  291. if (offset_lig_caret_list) {
  292. if (offset_lig_caret_list >= length ||
  293. offset_lig_caret_list < gdef_header_end) {
  294. return OTS_FAILURE();
  295. }
  296. if (!ParseLigCaretListTable(file, data + offset_lig_caret_list,
  297. length - offset_lig_caret_list,
  298. num_glyphs)) {
  299. DROP_THIS_TABLE;
  300. return true;
  301. }
  302. }
  303. if (offset_mark_attach_class_def) {
  304. if (offset_mark_attach_class_def >= length ||
  305. offset_mark_attach_class_def < gdef_header_end) {
  306. return OTS_FAILURE();
  307. }
  308. if (!ParseMarkAttachClassDefTable(file,
  309. data + offset_mark_attach_class_def,
  310. length - offset_mark_attach_class_def,
  311. num_glyphs)) {
  312. DROP_THIS_TABLE;
  313. return true;
  314. }
  315. gdef->has_mark_attachment_class_def = true;
  316. }
  317. if (offset_mark_glyph_sets_def) {
  318. if (offset_mark_glyph_sets_def >= length ||
  319. offset_mark_glyph_sets_def < gdef_header_end) {
  320. return OTS_FAILURE();
  321. }
  322. if (!ParseMarkGlyphSetsDefTable(file,
  323. data + offset_mark_glyph_sets_def,
  324. length - offset_mark_glyph_sets_def,
  325. num_glyphs)) {
  326. DROP_THIS_TABLE;
  327. return true;
  328. }
  329. gdef->has_mark_glyph_sets_def = true;
  330. }
  331. gdef->data = data;
  332. gdef->length = length;
  333. return true;
  334. }
  335. bool ots_gdef_should_serialise(OpenTypeFile *file) {
  336. const bool needed_tables_dropped =
  337. (file->gsub && file->gsub->data == NULL) ||
  338. (file->gpos && file->gpos->data == NULL);
  339. return file->gdef != NULL && file->gdef->data != NULL &&
  340. !needed_tables_dropped;
  341. }
  342. bool ots_gdef_serialise(OTSStream *out, OpenTypeFile *file) {
  343. if (!out->Write(file->gdef->data, file->gdef->length)) {
  344. return OTS_FAILURE();
  345. }
  346. return true;
  347. }
  348. void ots_gdef_free(OpenTypeFile *file) {
  349. delete file->gdef;
  350. }
  351. } // namespace ots