PageRenderTime 53ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/gfx/harfbuzz/src/hb-ot-layout.cc

https://bitbucket.org/soko/mozilla-central
C++ | 543 lines | 391 code | 90 blank | 62 comment | 67 complexity | 20d3f258ae81765f5b787fc16e31895a 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. /*
  2. * Copyright © 1998-2004 David Turner and Werner Lemberg
  3. * Copyright © 2006 Behdad Esfahbod
  4. * Copyright © 2007,2008,2009 Red Hat, Inc.
  5. *
  6. * This is part of HarfBuzz, a text shaping library.
  7. *
  8. * Permission is hereby granted, without written agreement and without
  9. * license or royalty fees, to use, copy, modify, and distribute this
  10. * software and its documentation for any purpose, provided that the
  11. * above copyright notice and the following two paragraphs appear in
  12. * all copies of this software.
  13. *
  14. * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
  15. * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
  16. * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
  17. * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
  18. * DAMAGE.
  19. *
  20. * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
  21. * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  22. * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
  23. * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  24. * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  25. *
  26. * Red Hat Author(s): Behdad Esfahbod
  27. */
  28. #include "hb-ot-layout-private.hh"
  29. #include "hb-ot-layout-gdef-table.hh"
  30. #include "hb-ot-layout-gsub-table.hh"
  31. #include "hb-ot-layout-gpos-table.hh"
  32. #include "hb-ot-maxp-table.hh"
  33. #include "hb-ot-shape-private.hh"
  34. #include <stdlib.h>
  35. #include <string.h>
  36. hb_ot_layout_t *
  37. _hb_ot_layout_create (hb_face_t *face)
  38. {
  39. /* TODO Remove this object altogether */
  40. hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
  41. layout->gdef_blob = Sanitizer<GDEF>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GDEF));
  42. layout->gdef = Sanitizer<GDEF>::lock_instance (layout->gdef_blob);
  43. layout->gsub_blob = Sanitizer<GSUB>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GSUB));
  44. layout->gsub = Sanitizer<GSUB>::lock_instance (layout->gsub_blob);
  45. layout->gpos_blob = Sanitizer<GPOS>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GPOS));
  46. layout->gpos = Sanitizer<GPOS>::lock_instance (layout->gpos_blob);
  47. return layout;
  48. }
  49. void
  50. _hb_ot_layout_destroy (hb_ot_layout_t *layout)
  51. {
  52. hb_blob_destroy (layout->gdef_blob);
  53. hb_blob_destroy (layout->gsub_blob);
  54. hb_blob_destroy (layout->gpos_blob);
  55. free (layout);
  56. }
  57. static inline const GDEF&
  58. _get_gdef (hb_face_t *face)
  59. {
  60. return likely (face->ot_layout && face->ot_layout->gdef) ? *face->ot_layout->gdef : Null(GDEF);
  61. }
  62. static inline const GSUB&
  63. _get_gsub (hb_face_t *face)
  64. {
  65. return likely (face->ot_layout && face->ot_layout->gsub) ? *face->ot_layout->gsub : Null(GSUB);
  66. }
  67. static inline const GPOS&
  68. _get_gpos (hb_face_t *face)
  69. {
  70. return likely (face->ot_layout && face->ot_layout->gpos) ? *face->ot_layout->gpos : Null(GPOS);
  71. }
  72. /*
  73. * GDEF
  74. */
  75. hb_bool_t
  76. hb_ot_layout_has_glyph_classes (hb_face_t *face)
  77. {
  78. return _get_gdef (face).has_glyph_classes ();
  79. }
  80. unsigned int
  81. _hb_ot_layout_get_glyph_property (hb_face_t *face,
  82. hb_glyph_info_t *info)
  83. {
  84. if (!info->props_cache())
  85. {
  86. const GDEF &gdef = _get_gdef (face);
  87. info->props_cache() = gdef.get_glyph_props (info->codepoint);
  88. }
  89. return info->props_cache();
  90. }
  91. static hb_bool_t
  92. _hb_ot_layout_match_properties (hb_face_t *face,
  93. hb_codepoint_t codepoint,
  94. unsigned int glyph_props,
  95. unsigned int lookup_props)
  96. {
  97. /* Not covered, if, for example, glyph class is ligature and
  98. * lookup_props includes LookupFlags::IgnoreLigatures
  99. */
  100. if (glyph_props & lookup_props & LookupFlag::IgnoreFlags)
  101. return false;
  102. if (glyph_props & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
  103. {
  104. /* If using mark filtering sets, the high short of
  105. * lookup_props has the set index.
  106. */
  107. if (lookup_props & LookupFlag::UseMarkFilteringSet)
  108. return _get_gdef (face).mark_set_covers (lookup_props >> 16, codepoint);
  109. /* The second byte of lookup_props has the meaning
  110. * "ignore marks of attachment type different than
  111. * the attachment type specified."
  112. */
  113. if (lookup_props & LookupFlag::MarkAttachmentType && glyph_props & LookupFlag::MarkAttachmentType)
  114. return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
  115. }
  116. return true;
  117. }
  118. hb_bool_t
  119. _hb_ot_layout_check_glyph_property (hb_face_t *face,
  120. hb_glyph_info_t *ginfo,
  121. unsigned int lookup_props,
  122. unsigned int *property_out)
  123. {
  124. unsigned int property;
  125. property = _hb_ot_layout_get_glyph_property (face, ginfo);
  126. (void) (property_out && (*property_out = property));
  127. return _hb_ot_layout_match_properties (face, ginfo->codepoint, property, lookup_props);
  128. }
  129. hb_bool_t
  130. _hb_ot_layout_skip_mark (hb_face_t *face,
  131. hb_glyph_info_t *ginfo,
  132. unsigned int lookup_props,
  133. unsigned int *property_out)
  134. {
  135. unsigned int property;
  136. property = _hb_ot_layout_get_glyph_property (face, ginfo);
  137. (void) (property_out && (*property_out = property));
  138. /* If it's a mark, skip it we don't accept it. */
  139. if (unlikely (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
  140. return !_hb_ot_layout_match_properties (face, ginfo->codepoint, property, lookup_props);
  141. /* If not a mark, don't skip. */
  142. return false;
  143. }
  144. unsigned int
  145. hb_ot_layout_get_attach_points (hb_face_t *face,
  146. hb_codepoint_t glyph,
  147. unsigned int start_offset,
  148. unsigned int *point_count /* IN/OUT */,
  149. unsigned int *point_array /* OUT */)
  150. {
  151. return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array);
  152. }
  153. unsigned int
  154. hb_ot_layout_get_ligature_carets (hb_font_t *font,
  155. hb_direction_t direction,
  156. hb_codepoint_t glyph,
  157. unsigned int start_offset,
  158. unsigned int *caret_count /* IN/OUT */,
  159. int *caret_array /* OUT */)
  160. {
  161. return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
  162. }
  163. /*
  164. * GSUB/GPOS
  165. */
  166. static const GSUBGPOS&
  167. get_gsubgpos_table (hb_face_t *face,
  168. hb_tag_t table_tag)
  169. {
  170. switch (table_tag) {
  171. case HB_OT_TAG_GSUB: return _get_gsub (face);
  172. case HB_OT_TAG_GPOS: return _get_gpos (face);
  173. default: return Null(GSUBGPOS);
  174. }
  175. }
  176. unsigned int
  177. hb_ot_layout_table_get_script_tags (hb_face_t *face,
  178. hb_tag_t table_tag,
  179. unsigned int start_offset,
  180. unsigned int *script_count /* IN/OUT */,
  181. hb_tag_t *script_tags /* OUT */)
  182. {
  183. const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  184. return g.get_script_tags (start_offset, script_count, script_tags);
  185. }
  186. hb_bool_t
  187. hb_ot_layout_table_find_script (hb_face_t *face,
  188. hb_tag_t table_tag,
  189. hb_tag_t script_tag,
  190. unsigned int *script_index)
  191. {
  192. ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
  193. const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  194. if (g.find_script_index (script_tag, script_index))
  195. return TRUE;
  196. /* try finding 'DFLT' */
  197. if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
  198. return FALSE;
  199. /* try with 'dflt'; MS site has had typos and many fonts use it now :(.
  200. * including many versions of DejaVu Sans Mono! */
  201. if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
  202. return FALSE;
  203. if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
  204. return FALSE;
  205. }
  206. hb_bool_t
  207. hb_ot_layout_table_choose_script (hb_face_t *face,
  208. hb_tag_t table_tag,
  209. const hb_tag_t *script_tags,
  210. unsigned int *script_index,
  211. hb_tag_t *chosen_script)
  212. {
  213. ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
  214. const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  215. while (*script_tags)
  216. {
  217. if (g.find_script_index (*script_tags, script_index)) {
  218. if (chosen_script)
  219. *chosen_script = *script_tags;
  220. return TRUE;
  221. }
  222. script_tags++;
  223. }
  224. /* try finding 'DFLT' */
  225. if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) {
  226. if (chosen_script)
  227. *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT;
  228. return FALSE;
  229. }
  230. /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
  231. if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) {
  232. if (chosen_script)
  233. *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE;
  234. return FALSE;
  235. }
  236. /* try with 'latn'; some old fonts put their features there even though
  237. they're really trying to support Thai, for example :( */
  238. #define HB_OT_TAG_LATIN_SCRIPT HB_TAG ('l', 'a', 't', 'n')
  239. if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) {
  240. if (chosen_script)
  241. *chosen_script = HB_OT_TAG_LATIN_SCRIPT;
  242. return FALSE;
  243. }
  244. if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
  245. if (chosen_script)
  246. *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
  247. return FALSE;
  248. }
  249. unsigned int
  250. hb_ot_layout_table_get_feature_tags (hb_face_t *face,
  251. hb_tag_t table_tag,
  252. unsigned int start_offset,
  253. unsigned int *feature_count /* IN/OUT */,
  254. hb_tag_t *feature_tags /* OUT */)
  255. {
  256. const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  257. return g.get_feature_tags (start_offset, feature_count, feature_tags);
  258. }
  259. unsigned int
  260. hb_ot_layout_script_get_language_tags (hb_face_t *face,
  261. hb_tag_t table_tag,
  262. unsigned int script_index,
  263. unsigned int start_offset,
  264. unsigned int *language_count /* IN/OUT */,
  265. hb_tag_t *language_tags /* OUT */)
  266. {
  267. const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
  268. return s.get_lang_sys_tags (start_offset, language_count, language_tags);
  269. }
  270. hb_bool_t
  271. hb_ot_layout_script_find_language (hb_face_t *face,
  272. hb_tag_t table_tag,
  273. unsigned int script_index,
  274. hb_tag_t language_tag,
  275. unsigned int *language_index)
  276. {
  277. ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
  278. const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
  279. if (s.find_lang_sys_index (language_tag, language_index))
  280. return TRUE;
  281. /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
  282. if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))
  283. return FALSE;
  284. if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
  285. return FALSE;
  286. }
  287. hb_bool_t
  288. hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
  289. hb_tag_t table_tag,
  290. unsigned int script_index,
  291. unsigned int language_index,
  292. unsigned int *feature_index)
  293. {
  294. const LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
  295. if (feature_index) *feature_index = l.get_required_feature_index ();
  296. return l.has_required_feature ();
  297. }
  298. unsigned int
  299. hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
  300. hb_tag_t table_tag,
  301. unsigned int script_index,
  302. unsigned int language_index,
  303. unsigned int start_offset,
  304. unsigned int *feature_count /* IN/OUT */,
  305. unsigned int *feature_indexes /* OUT */)
  306. {
  307. const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  308. const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
  309. return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
  310. }
  311. unsigned int
  312. hb_ot_layout_language_get_feature_tags (hb_face_t *face,
  313. hb_tag_t table_tag,
  314. unsigned int script_index,
  315. unsigned int language_index,
  316. unsigned int start_offset,
  317. unsigned int *feature_count /* IN/OUT */,
  318. hb_tag_t *feature_tags /* OUT */)
  319. {
  320. const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  321. const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
  322. ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t));
  323. unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
  324. if (feature_tags) {
  325. unsigned int count = *feature_count;
  326. for (unsigned int i = 0; i < count; i++)
  327. feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]);
  328. }
  329. return ret;
  330. }
  331. hb_bool_t
  332. hb_ot_layout_language_find_feature (hb_face_t *face,
  333. hb_tag_t table_tag,
  334. unsigned int script_index,
  335. unsigned int language_index,
  336. hb_tag_t feature_tag,
  337. unsigned int *feature_index)
  338. {
  339. ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
  340. const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  341. const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
  342. unsigned int num_features = l.get_feature_count ();
  343. for (unsigned int i = 0; i < num_features; i++) {
  344. unsigned int f_index = l.get_feature_index (i);
  345. if (feature_tag == g.get_feature_tag (f_index)) {
  346. if (feature_index) *feature_index = f_index;
  347. return TRUE;
  348. }
  349. }
  350. if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
  351. return FALSE;
  352. }
  353. unsigned int
  354. hb_ot_layout_feature_get_lookup_indexes (hb_face_t *face,
  355. hb_tag_t table_tag,
  356. unsigned int feature_index,
  357. unsigned int start_offset,
  358. unsigned int *lookup_count /* IN/OUT */,
  359. unsigned int *lookup_indexes /* OUT */)
  360. {
  361. const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  362. const Feature &f = g.get_feature (feature_index);
  363. return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
  364. }
  365. /*
  366. * GSUB
  367. */
  368. hb_bool_t
  369. hb_ot_layout_has_substitution (hb_face_t *face)
  370. {
  371. return &_get_gsub (face) != &Null(GSUB);
  372. }
  373. void
  374. hb_ot_layout_substitute_start (hb_buffer_t *buffer)
  375. {
  376. GSUB::substitute_start (buffer);
  377. }
  378. hb_bool_t
  379. hb_ot_layout_substitute_lookup (hb_face_t *face,
  380. hb_buffer_t *buffer,
  381. unsigned int lookup_index,
  382. hb_mask_t mask)
  383. {
  384. return _get_gsub (face).substitute_lookup (face, buffer, lookup_index, mask);
  385. }
  386. void
  387. hb_ot_layout_substitute_finish (hb_buffer_t *buffer HB_UNUSED)
  388. {
  389. GSUB::substitute_finish (buffer);
  390. }
  391. /*
  392. * GPOS
  393. */
  394. hb_bool_t
  395. hb_ot_layout_has_positioning (hb_face_t *face)
  396. {
  397. return &_get_gpos (face) != &Null(GPOS);
  398. }
  399. void
  400. hb_ot_layout_position_start (hb_buffer_t *buffer)
  401. {
  402. GPOS::position_start (buffer);
  403. }
  404. hb_bool_t
  405. hb_ot_layout_position_lookup (hb_font_t *font,
  406. hb_buffer_t *buffer,
  407. unsigned int lookup_index,
  408. hb_mask_t mask)
  409. {
  410. return _get_gpos (font->face).position_lookup (font, buffer, lookup_index, mask);
  411. }
  412. void
  413. hb_ot_layout_position_finish (hb_face_t *face, hb_buffer_t *buffer)
  414. {
  415. /* force diacritics to have zero width */
  416. unsigned int count = buffer->len;
  417. if (hb_ot_layout_has_glyph_classes (face)) {
  418. const GDEF& gdef = _get_gdef (face);
  419. if (buffer->props.direction == HB_DIRECTION_RTL) {
  420. for (unsigned int i = 1; i < count; i++) {
  421. if (gdef.get_glyph_class (buffer->info[i].codepoint) == GDEF::MarkGlyph) {
  422. buffer->pos[i].x_advance = 0;
  423. }
  424. }
  425. } else {
  426. for (unsigned int i = 1; i < count; i++) {
  427. if (gdef.get_glyph_class (buffer->info[i].codepoint) == GDEF::MarkGlyph) {
  428. hb_glyph_position_t& pos = buffer->pos[i];
  429. pos.x_offset -= pos.x_advance;
  430. pos.x_advance = 0;
  431. }
  432. }
  433. }
  434. } else {
  435. /* no GDEF classes available, so use General Category as a fallback */
  436. if (buffer->props.direction == HB_DIRECTION_RTL) {
  437. for (unsigned int i = 1; i < count; i++) {
  438. if (buffer->info[i].general_category() == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) {
  439. buffer->pos[i].x_advance = 0;
  440. }
  441. }
  442. } else {
  443. for (unsigned int i = 1; i < count; i++) {
  444. if (buffer->info[i].general_category() == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) {
  445. hb_glyph_position_t& pos = buffer->pos[i];
  446. pos.x_offset -= pos.x_advance;
  447. pos.x_advance = 0;
  448. }
  449. }
  450. }
  451. }
  452. GPOS::position_finish (buffer);
  453. }