PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

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

https://bitbucket.org/MeeGoAdmin/mozilla-central/
C++ | 504 lines | 354 code | 90 blank | 60 comment | 49 complexity | 3d089a1505c468007bd34c7cf29dc4a6 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. /*
  2. * Copyright (C) 1998-2004 David Turner and Werner Lemberg
  3. * Copyright (C) 2006 Behdad Esfahbod
  4. * Copyright (C) 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. #define HB_OT_LAYOUT_CC
  29. #include "hb-ot-layout-private.hh"
  30. #include "hb-ot-layout-gdef-private.hh"
  31. #include "hb-ot-layout-gsub-private.hh"
  32. #include "hb-ot-layout-gpos-private.hh"
  33. #include "hb-ot-shape-private.hh"
  34. #include <stdlib.h>
  35. #include <string.h>
  36. HB_BEGIN_DECLS
  37. hb_ot_layout_t *
  38. _hb_ot_layout_new (hb_face_t *face)
  39. {
  40. /* Remove this object altogether */
  41. hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
  42. layout->gdef_blob = Sanitizer<GDEF>::sanitize (hb_face_get_table (face, HB_OT_TAG_GDEF));
  43. layout->gdef = Sanitizer<GDEF>::lock_instance (layout->gdef_blob);
  44. layout->gsub_blob = Sanitizer<GSUB>::sanitize (hb_face_get_table (face, HB_OT_TAG_GSUB));
  45. layout->gsub = Sanitizer<GSUB>::lock_instance (layout->gsub_blob);
  46. layout->gpos_blob = Sanitizer<GPOS>::sanitize (hb_face_get_table (face, HB_OT_TAG_GPOS));
  47. layout->gpos = Sanitizer<GPOS>::lock_instance (layout->gpos_blob);
  48. return layout;
  49. }
  50. void
  51. _hb_ot_layout_free (hb_ot_layout_t *layout)
  52. {
  53. hb_blob_unlock (layout->gdef_blob);
  54. hb_blob_unlock (layout->gsub_blob);
  55. hb_blob_unlock (layout->gpos_blob);
  56. hb_blob_destroy (layout->gdef_blob);
  57. hb_blob_destroy (layout->gsub_blob);
  58. hb_blob_destroy (layout->gpos_blob);
  59. free (layout);
  60. }
  61. static inline const GDEF&
  62. _get_gdef (hb_face_t *face)
  63. {
  64. return likely (face->ot_layout && face->ot_layout->gdef) ? *face->ot_layout->gdef : Null(GDEF);
  65. }
  66. static inline const GSUB&
  67. _get_gsub (hb_face_t *face)
  68. {
  69. return likely (face->ot_layout && face->ot_layout->gsub) ? *face->ot_layout->gsub : Null(GSUB);
  70. }
  71. static inline const GPOS&
  72. _get_gpos (hb_face_t *face)
  73. {
  74. return likely (face->ot_layout && face->ot_layout->gpos) ? *face->ot_layout->gpos : Null(GPOS);
  75. }
  76. /*
  77. * GDEF
  78. */
  79. hb_bool_t
  80. hb_ot_layout_has_glyph_classes (hb_face_t *face)
  81. {
  82. return _get_gdef (face).has_glyph_classes ();
  83. }
  84. unsigned int
  85. _hb_ot_layout_get_glyph_property (hb_face_t *face,
  86. hb_glyph_info_t *info)
  87. {
  88. if (!info->props_cache())
  89. {
  90. const GDEF &gdef = _get_gdef (face);
  91. info->props_cache() = gdef.get_glyph_props (info->codepoint);
  92. }
  93. return info->props_cache();
  94. }
  95. static hb_bool_t
  96. _hb_ot_layout_match_properties (hb_face_t *face,
  97. hb_codepoint_t codepoint,
  98. unsigned int glyph_props,
  99. unsigned int lookup_props)
  100. {
  101. /* Not covered, if, for example, glyph class is ligature and
  102. * lookup_props includes LookupFlags::IgnoreLigatures
  103. */
  104. if (glyph_props & lookup_props & LookupFlag::IgnoreFlags)
  105. return false;
  106. if (glyph_props & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
  107. {
  108. /* If using mark filtering sets, the high short of
  109. * lookup_props has the set index.
  110. */
  111. if (lookup_props & LookupFlag::UseMarkFilteringSet)
  112. return _get_gdef (face).mark_set_covers (lookup_props >> 16, codepoint);
  113. /* The second byte of lookup_props has the meaning
  114. * "ignore marks of attachment type different than
  115. * the attachment type specified."
  116. */
  117. if (lookup_props & LookupFlag::MarkAttachmentType && glyph_props & LookupFlag::MarkAttachmentType)
  118. return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
  119. }
  120. return true;
  121. }
  122. hb_bool_t
  123. _hb_ot_layout_check_glyph_property (hb_face_t *face,
  124. hb_glyph_info_t *ginfo,
  125. unsigned int lookup_props,
  126. unsigned int *property_out)
  127. {
  128. unsigned int property;
  129. property = _hb_ot_layout_get_glyph_property (face, ginfo);
  130. (void) (property_out && (*property_out = property));
  131. return _hb_ot_layout_match_properties (face, ginfo->codepoint, property, lookup_props);
  132. }
  133. hb_bool_t
  134. _hb_ot_layout_skip_mark (hb_face_t *face,
  135. hb_glyph_info_t *ginfo,
  136. unsigned int lookup_props,
  137. unsigned int *property_out)
  138. {
  139. unsigned int property;
  140. property = _hb_ot_layout_get_glyph_property (face, ginfo);
  141. (void) (property_out && (*property_out = property));
  142. /* If it's a mark, skip it we don't accept it. */
  143. if (unlikely (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
  144. return !_hb_ot_layout_match_properties (face, ginfo->codepoint, property, lookup_props);
  145. /* If not a mark, don't skip. */
  146. return false;
  147. }
  148. unsigned int
  149. hb_ot_layout_get_attach_points (hb_face_t *face,
  150. hb_codepoint_t glyph,
  151. unsigned int start_offset,
  152. unsigned int *point_count /* IN/OUT */,
  153. unsigned int *point_array /* OUT */)
  154. {
  155. return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array);
  156. }
  157. unsigned int
  158. hb_ot_layout_get_ligature_carets (hb_font_t *font,
  159. hb_face_t *face,
  160. hb_direction_t direction,
  161. hb_codepoint_t glyph,
  162. unsigned int start_offset,
  163. unsigned int *caret_count /* IN/OUT */,
  164. int *caret_array /* OUT */)
  165. {
  166. hb_ot_layout_context_t c;
  167. c.font = font;
  168. c.face = face;
  169. return _get_gdef (face).get_lig_carets (&c, direction, glyph, start_offset, caret_count, caret_array);
  170. }
  171. /*
  172. * GSUB/GPOS
  173. */
  174. static const GSUBGPOS&
  175. get_gsubgpos_table (hb_face_t *face,
  176. hb_tag_t table_tag)
  177. {
  178. switch (table_tag) {
  179. case HB_OT_TAG_GSUB: return _get_gsub (face);
  180. case HB_OT_TAG_GPOS: return _get_gpos (face);
  181. default: return Null(GSUBGPOS);
  182. }
  183. }
  184. unsigned int
  185. hb_ot_layout_table_get_script_tags (hb_face_t *face,
  186. hb_tag_t table_tag,
  187. unsigned int start_offset,
  188. unsigned int *script_count /* IN/OUT */,
  189. hb_tag_t *script_tags /* OUT */)
  190. {
  191. const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  192. return g.get_script_tags (start_offset, script_count, script_tags);
  193. }
  194. hb_bool_t
  195. hb_ot_layout_table_find_script (hb_face_t *face,
  196. hb_tag_t table_tag,
  197. hb_tag_t script_tag,
  198. unsigned int *script_index)
  199. {
  200. ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
  201. const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  202. if (g.find_script_index (script_tag, script_index))
  203. return TRUE;
  204. /* try finding 'DFLT' */
  205. if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
  206. return FALSE;
  207. /* try with 'dflt'; MS site has had typos and many fonts use it now :(.
  208. * including many versions of DejaVu Sans Mono! */
  209. if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
  210. return FALSE;
  211. if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
  212. return FALSE;
  213. }
  214. hb_bool_t
  215. hb_ot_layout_table_choose_script (hb_face_t *face,
  216. hb_tag_t table_tag,
  217. const hb_tag_t *script_tags,
  218. unsigned int *script_index)
  219. {
  220. ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
  221. const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  222. while (*script_tags)
  223. {
  224. if (g.find_script_index (*script_tags, script_index))
  225. return TRUE;
  226. script_tags++;
  227. }
  228. /* try finding 'DFLT' */
  229. if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
  230. return FALSE;
  231. /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
  232. if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
  233. return FALSE;
  234. if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
  235. return FALSE;
  236. }
  237. unsigned int
  238. hb_ot_layout_table_get_feature_tags (hb_face_t *face,
  239. hb_tag_t table_tag,
  240. unsigned int start_offset,
  241. unsigned int *feature_count /* IN/OUT */,
  242. hb_tag_t *feature_tags /* OUT */)
  243. {
  244. const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  245. return g.get_feature_tags (start_offset, feature_count, feature_tags);
  246. }
  247. unsigned int
  248. hb_ot_layout_script_get_language_tags (hb_face_t *face,
  249. hb_tag_t table_tag,
  250. unsigned int script_index,
  251. unsigned int start_offset,
  252. unsigned int *language_count /* IN/OUT */,
  253. hb_tag_t *language_tags /* OUT */)
  254. {
  255. const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
  256. return s.get_lang_sys_tags (start_offset, language_count, language_tags);
  257. }
  258. hb_bool_t
  259. hb_ot_layout_script_find_language (hb_face_t *face,
  260. hb_tag_t table_tag,
  261. unsigned int script_index,
  262. hb_tag_t language_tag,
  263. unsigned int *language_index)
  264. {
  265. ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
  266. const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
  267. if (s.find_lang_sys_index (language_tag, language_index))
  268. return TRUE;
  269. /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
  270. if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))
  271. return FALSE;
  272. if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
  273. return FALSE;
  274. }
  275. hb_bool_t
  276. hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
  277. hb_tag_t table_tag,
  278. unsigned int script_index,
  279. unsigned int language_index,
  280. unsigned int *feature_index)
  281. {
  282. const LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
  283. if (feature_index) *feature_index = l.get_required_feature_index ();
  284. return l.has_required_feature ();
  285. }
  286. unsigned int
  287. hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
  288. hb_tag_t table_tag,
  289. unsigned int script_index,
  290. unsigned int language_index,
  291. unsigned int start_offset,
  292. unsigned int *feature_count /* IN/OUT */,
  293. unsigned int *feature_indexes /* OUT */)
  294. {
  295. const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  296. const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
  297. return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
  298. }
  299. unsigned int
  300. hb_ot_layout_language_get_feature_tags (hb_face_t *face,
  301. hb_tag_t table_tag,
  302. unsigned int script_index,
  303. unsigned int language_index,
  304. unsigned int start_offset,
  305. unsigned int *feature_count /* IN/OUT */,
  306. hb_tag_t *feature_tags /* OUT */)
  307. {
  308. const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  309. const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
  310. ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t));
  311. unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
  312. if (feature_tags) {
  313. unsigned int count = *feature_count;
  314. for (unsigned int i = 0; i < count; i++)
  315. feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]);
  316. }
  317. return ret;
  318. }
  319. hb_bool_t
  320. hb_ot_layout_language_find_feature (hb_face_t *face,
  321. hb_tag_t table_tag,
  322. unsigned int script_index,
  323. unsigned int language_index,
  324. hb_tag_t feature_tag,
  325. unsigned int *feature_index)
  326. {
  327. ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
  328. const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  329. const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
  330. unsigned int num_features = l.get_feature_count ();
  331. for (unsigned int i = 0; i < num_features; i++) {
  332. unsigned int f_index = l.get_feature_index (i);
  333. if (feature_tag == g.get_feature_tag (f_index)) {
  334. if (feature_index) *feature_index = f_index;
  335. return TRUE;
  336. }
  337. }
  338. if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
  339. return FALSE;
  340. }
  341. unsigned int
  342. hb_ot_layout_feature_get_lookup_indexes (hb_face_t *face,
  343. hb_tag_t table_tag,
  344. unsigned int feature_index,
  345. unsigned int start_offset,
  346. unsigned int *lookup_count /* IN/OUT */,
  347. unsigned int *lookup_indexes /* OUT */)
  348. {
  349. const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  350. const Feature &f = g.get_feature (feature_index);
  351. return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
  352. }
  353. /*
  354. * GSUB
  355. */
  356. hb_bool_t
  357. hb_ot_layout_has_substitution (hb_face_t *face)
  358. {
  359. return &_get_gsub (face) != &Null(GSUB);
  360. }
  361. hb_bool_t
  362. hb_ot_layout_substitute_lookup (hb_face_t *face,
  363. hb_buffer_t *buffer,
  364. unsigned int lookup_index,
  365. hb_mask_t mask)
  366. {
  367. hb_ot_layout_context_t c;
  368. c.font = NULL;
  369. c.face = face;
  370. return _get_gsub (face).substitute_lookup (&c, buffer, lookup_index, mask);
  371. }
  372. /*
  373. * GPOS
  374. */
  375. hb_bool_t
  376. hb_ot_layout_has_positioning (hb_face_t *face)
  377. {
  378. return &_get_gpos (face) != &Null(GPOS);
  379. }
  380. hb_bool_t
  381. hb_ot_layout_position_lookup (hb_font_t *font,
  382. hb_face_t *face,
  383. hb_buffer_t *buffer,
  384. unsigned int lookup_index,
  385. hb_mask_t mask)
  386. {
  387. hb_ot_layout_context_t c;
  388. c.font = font;
  389. c.face = face;
  390. return _get_gpos (face).position_lookup (&c, buffer, lookup_index, mask);
  391. }
  392. void
  393. hb_ot_layout_position_finish (hb_face_t *face, hb_buffer_t *buffer)
  394. {
  395. /* force diacritics to have zero width */
  396. unsigned int count = buffer->len;
  397. if (hb_ot_layout_has_glyph_classes (face)) {
  398. const GDEF& gdef = _get_gdef (face);
  399. for (unsigned int i = 1; i < count; i++) {
  400. if (gdef.get_glyph_class (buffer->info[i].codepoint) == GDEF::MarkGlyph) {
  401. buffer->pos[i].x_advance = 0;
  402. }
  403. }
  404. } else {
  405. /* no GDEF classes available, so use General Category as a fallback */
  406. for (unsigned int i = 1; i < count; i++) {
  407. if (buffer->info[i].general_category() == HB_CATEGORY_NON_SPACING_MARK) {
  408. buffer->pos[i].x_advance = 0;
  409. }
  410. }
  411. }
  412. GPOS::position_finish (buffer);
  413. }
  414. HB_END_DECLS