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

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     1 /*
     2  * Copyright © 1998-2004  David Turner and Werner Lemberg
     3  * Copyright © 2006  Behdad Esfahbod
     4  * Copyright © 2007,2008,2009  Red Hat, Inc.
     5  * Copyright © 2012,2013  Google, Inc.
     6  *
     7  *  This is part of HarfBuzz, a text shaping library.
     8  *
     9  * Permission is hereby granted, without written agreement and without
    10  * license or royalty fees, to use, copy, modify, and distribute this
    11  * software and its documentation for any purpose, provided that the
    12  * above copyright notice and the following two paragraphs appear in
    13  * all copies of this software.
    14  *
    15  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
    16  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
    17  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
    18  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
    19  * DAMAGE.
    20  *
    21  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
    22  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    23  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
    24  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
    25  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
    26  *
    27  * Red Hat Author(s): Behdad Esfahbod
    28  * Google Author(s): Behdad Esfahbod
    29  */
    31 #include "hb-ot-layout-private.hh"
    33 #include "hb-ot-layout-gdef-table.hh"
    34 #include "hb-ot-layout-gsub-table.hh"
    35 #include "hb-ot-layout-gpos-table.hh"
    36 #include "hb-ot-layout-jstf-table.hh"
    38 #include "hb-ot-map-private.hh"
    40 #include <stdlib.h>
    41 #include <string.h>
    44 HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
    46 hb_ot_layout_t *
    47 _hb_ot_layout_create (hb_face_t *face)
    48 {
    49   hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
    50   if (unlikely (!layout))
    51     return NULL;
    53   layout->gdef_blob = OT::Sanitizer<OT::GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF));
    54   layout->gdef = OT::Sanitizer<OT::GDEF>::lock_instance (layout->gdef_blob);
    56   layout->gsub_blob = OT::Sanitizer<OT::GSUB>::sanitize (face->reference_table (HB_OT_TAG_GSUB));
    57   layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob);
    59   layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
    60   layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
    62   layout->gsub_lookup_count = layout->gsub->get_lookup_count ();
    63   layout->gpos_lookup_count = layout->gpos->get_lookup_count ();
    65   layout->gsub_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
    66   layout->gpos_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
    68   if (unlikely ((layout->gsub_lookup_count && !layout->gsub_accels) ||
    69 		(layout->gpos_lookup_count && !layout->gpos_accels)))
    70   {
    71     _hb_ot_layout_destroy (layout);
    72     return NULL;
    73   }
    75   for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
    76     layout->gsub_accels[i].init (layout->gsub->get_lookup (i));
    77   for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
    78     layout->gpos_accels[i].init (layout->gpos->get_lookup (i));
    80   return layout;
    81 }
    83 void
    84 _hb_ot_layout_destroy (hb_ot_layout_t *layout)
    85 {
    86   for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
    87     layout->gsub_accels[i].fini (layout->gsub->get_lookup (i));
    88   for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
    89     layout->gpos_accels[i].fini (layout->gpos->get_lookup (i));
    91   free (layout->gsub_accels);
    92   free (layout->gpos_accels);
    94   hb_blob_destroy (layout->gdef_blob);
    95   hb_blob_destroy (layout->gsub_blob);
    96   hb_blob_destroy (layout->gpos_blob);
    98   free (layout);
    99 }
   101 static inline const OT::GDEF&
   102 _get_gdef (hb_face_t *face)
   103 {
   104   if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GDEF);
   105   return *hb_ot_layout_from_face (face)->gdef;
   106 }
   107 static inline const OT::GSUB&
   108 _get_gsub (hb_face_t *face)
   109 {
   110   if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GSUB);
   111   return *hb_ot_layout_from_face (face)->gsub;
   112 }
   113 static inline const OT::GPOS&
   114 _get_gpos (hb_face_t *face)
   115 {
   116   if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GPOS);
   117   return *hb_ot_layout_from_face (face)->gpos;
   118 }
   121 /*
   122  * GDEF
   123  */
   125 hb_bool_t
   126 hb_ot_layout_has_glyph_classes (hb_face_t *face)
   127 {
   128   return _get_gdef (face).has_glyph_classes ();
   129 }
   131 hb_ot_layout_glyph_class_t
   132 hb_ot_layout_get_glyph_class (hb_face_t      *face,
   133 			      hb_codepoint_t  glyph)
   134 {
   135   return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph);
   136 }
   138 void
   139 hb_ot_layout_get_glyphs_in_class (hb_face_t                  *face,
   140 				  hb_ot_layout_glyph_class_t  klass,
   141 				  hb_set_t                   *glyphs /* OUT */)
   142 {
   143   return _get_gdef (face).get_glyphs_in_class (klass, glyphs);
   144 }
   146 unsigned int
   147 hb_ot_layout_get_attach_points (hb_face_t      *face,
   148 				hb_codepoint_t  glyph,
   149 				unsigned int    start_offset,
   150 				unsigned int   *point_count /* IN/OUT */,
   151 				unsigned int   *point_array /* OUT */)
   152 {
   153   return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array);
   154 }
   156 unsigned int
   157 hb_ot_layout_get_ligature_carets (hb_font_t      *font,
   158 				  hb_direction_t  direction,
   159 				  hb_codepoint_t  glyph,
   160 				  unsigned int    start_offset,
   161 				  unsigned int   *caret_count /* IN/OUT */,
   162 				  int            *caret_array /* OUT */)
   163 {
   164   return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
   165 }
   168 /*
   169  * GSUB/GPOS
   170  */
   172 static const OT::GSUBGPOS&
   173 get_gsubgpos_table (hb_face_t *face,
   174 		    hb_tag_t   table_tag)
   175 {
   176   switch (table_tag) {
   177     case HB_OT_TAG_GSUB: return _get_gsub (face);
   178     case HB_OT_TAG_GPOS: return _get_gpos (face);
   179     default:             return OT::Null(OT::GSUBGPOS);
   180   }
   181 }
   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 OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
   193   return g.get_script_tags (start_offset, script_count, script_tags);
   194 }
   196 #define HB_OT_TAG_LATIN_SCRIPT		HB_TAG ('l', 'a', 't', 'n')
   198 hb_bool_t
   199 hb_ot_layout_table_find_script (hb_face_t    *face,
   200 				hb_tag_t      table_tag,
   201 				hb_tag_t      script_tag,
   202 				unsigned int *script_index)
   203 {
   204   ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
   205   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
   207   if (g.find_script_index (script_tag, script_index))
   208     return true;
   210   /* try finding 'DFLT' */
   211   if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
   212     return false;
   214   /* try with 'dflt'; MS site has had typos and many fonts use it now :(.
   215    * including many versions of DejaVu Sans Mono! */
   216   if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
   217     return false;
   219   /* try with 'latn'; some old fonts put their features there even though
   220      they're really trying to support Thai, for example :( */
   221   if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index))
   222     return false;
   224   if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
   225   return false;
   226 }
   228 hb_bool_t
   229 hb_ot_layout_table_choose_script (hb_face_t      *face,
   230 				  hb_tag_t        table_tag,
   231 				  const hb_tag_t *script_tags,
   232 				  unsigned int   *script_index,
   233 				  hb_tag_t       *chosen_script)
   234 {
   235   ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
   236   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
   238   while (*script_tags)
   239   {
   240     if (g.find_script_index (*script_tags, script_index)) {
   241       if (chosen_script)
   242         *chosen_script = *script_tags;
   243       return true;
   244     }
   245     script_tags++;
   246   }
   248   /* try finding 'DFLT' */
   249   if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) {
   250     if (chosen_script)
   251       *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT;
   252     return false;
   253   }
   255   /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
   256   if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) {
   257     if (chosen_script)
   258       *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE;
   259     return false;
   260   }
   262   /* try with 'latn'; some old fonts put their features there even though
   263      they're really trying to support Thai, for example :( */
   264   if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) {
   265     if (chosen_script)
   266       *chosen_script = HB_OT_TAG_LATIN_SCRIPT;
   267     return false;
   268   }
   270   if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
   271   if (chosen_script)
   272     *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
   273   return false;
   274 }
   276 unsigned int
   277 hb_ot_layout_table_get_feature_tags (hb_face_t    *face,
   278 				     hb_tag_t      table_tag,
   279 				     unsigned int  start_offset,
   280 				     unsigned int *feature_count /* IN/OUT */,
   281 				     hb_tag_t     *feature_tags /* OUT */)
   282 {
   283   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
   285   return g.get_feature_tags (start_offset, feature_count, feature_tags);
   286 }
   289 unsigned int
   290 hb_ot_layout_script_get_language_tags (hb_face_t    *face,
   291 				       hb_tag_t      table_tag,
   292 				       unsigned int  script_index,
   293 				       unsigned int  start_offset,
   294 				       unsigned int *language_count /* IN/OUT */,
   295 				       hb_tag_t     *language_tags /* OUT */)
   296 {
   297   const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
   299   return s.get_lang_sys_tags (start_offset, language_count, language_tags);
   300 }
   302 hb_bool_t
   303 hb_ot_layout_script_find_language (hb_face_t    *face,
   304 				   hb_tag_t      table_tag,
   305 				   unsigned int  script_index,
   306 				   hb_tag_t      language_tag,
   307 				   unsigned int *language_index)
   308 {
   309   ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
   310   const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
   312   if (s.find_lang_sys_index (language_tag, language_index))
   313     return true;
   315   /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
   316   if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))
   317     return false;
   319   if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
   320   return false;
   321 }
   323 hb_bool_t
   324 hb_ot_layout_language_get_required_feature_index (hb_face_t    *face,
   325 						  hb_tag_t      table_tag,
   326 						  unsigned int  script_index,
   327 						  unsigned int  language_index,
   328 						  unsigned int *feature_index)
   329 {
   330   const OT::LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
   332   if (feature_index) *feature_index = l.get_required_feature_index ();
   334   return l.has_required_feature ();
   335 }
   337 unsigned int
   338 hb_ot_layout_language_get_feature_indexes (hb_face_t    *face,
   339 					   hb_tag_t      table_tag,
   340 					   unsigned int  script_index,
   341 					   unsigned int  language_index,
   342 					   unsigned int  start_offset,
   343 					   unsigned int *feature_count /* IN/OUT */,
   344 					   unsigned int *feature_indexes /* OUT */)
   345 {
   346   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
   347   const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
   349   return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
   350 }
   352 unsigned int
   353 hb_ot_layout_language_get_feature_tags (hb_face_t    *face,
   354 					hb_tag_t      table_tag,
   355 					unsigned int  script_index,
   356 					unsigned int  language_index,
   357 					unsigned int  start_offset,
   358 					unsigned int *feature_count /* IN/OUT */,
   359 					hb_tag_t     *feature_tags /* OUT */)
   360 {
   361   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
   362   const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
   364   ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t));
   365   unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
   367   if (feature_tags) {
   368     unsigned int count = *feature_count;
   369     for (unsigned int i = 0; i < count; i++)
   370       feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]);
   371   }
   373   return ret;
   374 }
   377 hb_bool_t
   378 hb_ot_layout_language_find_feature (hb_face_t    *face,
   379 				    hb_tag_t      table_tag,
   380 				    unsigned int  script_index,
   381 				    unsigned int  language_index,
   382 				    hb_tag_t      feature_tag,
   383 				    unsigned int *feature_index)
   384 {
   385   ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
   386   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
   387   const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
   389   unsigned int num_features = l.get_feature_count ();
   390   for (unsigned int i = 0; i < num_features; i++) {
   391     unsigned int f_index = l.get_feature_index (i);
   393     if (feature_tag == g.get_feature_tag (f_index)) {
   394       if (feature_index) *feature_index = f_index;
   395       return true;
   396     }
   397   }
   399   if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
   400   return false;
   401 }
   403 unsigned int
   404 hb_ot_layout_feature_get_lookups (hb_face_t    *face,
   405 				  hb_tag_t      table_tag,
   406 				  unsigned int  feature_index,
   407 				  unsigned int  start_offset,
   408 				  unsigned int *lookup_count /* IN/OUT */,
   409 				  unsigned int *lookup_indexes /* OUT */)
   410 {
   411   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
   412   const OT::Feature &f = g.get_feature (feature_index);
   414   return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
   415 }
   417 unsigned int
   418 hb_ot_layout_table_get_lookup_count (hb_face_t    *face,
   419 				     hb_tag_t      table_tag)
   420 {
   421   switch (table_tag)
   422   {
   423     case HB_OT_TAG_GSUB:
   424     {
   425       return hb_ot_layout_from_face (face)->gsub_lookup_count;
   426     }
   427     case HB_OT_TAG_GPOS:
   428     {
   429       return hb_ot_layout_from_face (face)->gpos_lookup_count;
   430     }
   431   }
   432   return 0;
   433 }
   435 static void
   436 _hb_ot_layout_collect_lookups_lookups (hb_face_t      *face,
   437 				       hb_tag_t        table_tag,
   438 				       unsigned int    feature_index,
   439 				       hb_set_t       *lookup_indexes /* OUT */)
   440 {
   441   unsigned int lookup_indices[32];
   442   unsigned int offset, len;
   444   offset = 0;
   445   do {
   446     len = ARRAY_LENGTH (lookup_indices);
   447     hb_ot_layout_feature_get_lookups (face,
   448 				      table_tag,
   449 				      feature_index,
   450 				      offset, &len,
   451 				      lookup_indices);
   453     for (unsigned int i = 0; i < len; i++)
   454       lookup_indexes->add (lookup_indices[i]);
   456     offset += len;
   457   } while (len == ARRAY_LENGTH (lookup_indices));
   458 }
   460 static void
   461 _hb_ot_layout_collect_lookups_features (hb_face_t      *face,
   462 					hb_tag_t        table_tag,
   463 					unsigned int    script_index,
   464 					unsigned int    language_index,
   465 					const hb_tag_t *features,
   466 					hb_set_t       *lookup_indexes /* OUT */)
   467 {
   468   if (!features)
   469   {
   470     unsigned int required_feature_index;
   471     if (hb_ot_layout_language_get_required_feature_index (face,
   472 							  table_tag,
   473 							  script_index,
   474 							  language_index,
   475 							  &required_feature_index))
   476       _hb_ot_layout_collect_lookups_lookups (face,
   477 					     table_tag,
   478 					     required_feature_index,
   479 					     lookup_indexes);
   481     /* All features */
   482     unsigned int feature_indices[32];
   483     unsigned int offset, len;
   485     offset = 0;
   486     do {
   487       len = ARRAY_LENGTH (feature_indices);
   488       hb_ot_layout_language_get_feature_indexes (face,
   489 						 table_tag,
   490 						 script_index,
   491 						 language_index,
   492 						 offset, &len,
   493 						 feature_indices);
   495       for (unsigned int i = 0; i < len; i++)
   496 	_hb_ot_layout_collect_lookups_lookups (face,
   497 					       table_tag,
   498 					       feature_indices[i],
   499 					       lookup_indexes);
   501       offset += len;
   502     } while (len == ARRAY_LENGTH (feature_indices));
   503   }
   504   else
   505   {
   506     for (; *features; features++)
   507     {
   508       unsigned int feature_index;
   509       if (hb_ot_layout_language_find_feature (face,
   510 					      table_tag,
   511 					      script_index,
   512 					      language_index,
   513 					      *features,
   514 					      &feature_index))
   515         _hb_ot_layout_collect_lookups_lookups (face,
   516 					       table_tag,
   517 					       feature_index,
   518 					       lookup_indexes);
   519     }
   520   }
   521 }
   523 static void
   524 _hb_ot_layout_collect_lookups_languages (hb_face_t      *face,
   525 					 hb_tag_t        table_tag,
   526 					 unsigned int    script_index,
   527 					 const hb_tag_t *languages,
   528 					 const hb_tag_t *features,
   529 					 hb_set_t       *lookup_indexes /* OUT */)
   530 {
   531   _hb_ot_layout_collect_lookups_features (face,
   532 					  table_tag,
   533 					  script_index,
   534 					  HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
   535 					  features,
   536 					  lookup_indexes);
   538   if (!languages)
   539   {
   540     /* All languages */
   541     unsigned int count = hb_ot_layout_script_get_language_tags (face,
   542 								table_tag,
   543 								script_index,
   544 								0, NULL, NULL);
   545     for (unsigned int language_index = 0; language_index < count; language_index++)
   546       _hb_ot_layout_collect_lookups_features (face,
   547 					      table_tag,
   548 					      script_index,
   549 					      language_index,
   550 					      features,
   551 					      lookup_indexes);
   552   }
   553   else
   554   {
   555     for (; *languages; languages++)
   556     {
   557       unsigned int language_index;
   558       if (hb_ot_layout_script_find_language (face,
   559 					     table_tag,
   560 					     script_index,
   561 					     *languages,
   562 					     &language_index))
   563         _hb_ot_layout_collect_lookups_features (face,
   564 						table_tag,
   565 						script_index,
   566 						language_index,
   567 						features,
   568 						lookup_indexes);
   569     }
   570   }
   571 }
   573 void
   574 hb_ot_layout_collect_lookups (hb_face_t      *face,
   575 			      hb_tag_t        table_tag,
   576 			      const hb_tag_t *scripts,
   577 			      const hb_tag_t *languages,
   578 			      const hb_tag_t *features,
   579 			      hb_set_t       *lookup_indexes /* OUT */)
   580 {
   581   if (!scripts)
   582   {
   583     /* All scripts */
   584     unsigned int count = hb_ot_layout_table_get_script_tags (face,
   585 							     table_tag,
   586 							     0, NULL, NULL);
   587     for (unsigned int script_index = 0; script_index < count; script_index++)
   588       _hb_ot_layout_collect_lookups_languages (face,
   589 					       table_tag,
   590 					       script_index,
   591 					       languages,
   592 					       features,
   593 					       lookup_indexes);
   594   }
   595   else
   596   {
   597     for (; *scripts; scripts++)
   598     {
   599       unsigned int script_index;
   600       if (hb_ot_layout_table_find_script (face,
   601 					  table_tag,
   602 					  *scripts,
   603 					  &script_index))
   604         _hb_ot_layout_collect_lookups_languages (face,
   605 						 table_tag,
   606 						 script_index,
   607 						 languages,
   608 						 features,
   609 						 lookup_indexes);
   610     }
   611   }
   612 }
   614 void
   615 hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
   616 				    hb_tag_t      table_tag,
   617 				    unsigned int  lookup_index,
   618 				    hb_set_t     *glyphs_before, /* OUT. May be NULL */
   619 				    hb_set_t     *glyphs_input,  /* OUT. May be NULL */
   620 				    hb_set_t     *glyphs_after,  /* OUT. May be NULL */
   621 				    hb_set_t     *glyphs_output  /* OUT. May be NULL */)
   622 {
   623   if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
   625   OT::hb_collect_glyphs_context_t c (face,
   626 				     glyphs_before,
   627 				     glyphs_input,
   628 				     glyphs_after,
   629 				     glyphs_output);
   631   switch (table_tag)
   632   {
   633     case HB_OT_TAG_GSUB:
   634     {
   635       const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
   636       l.collect_glyphs (&c);
   637       return;
   638     }
   639     case HB_OT_TAG_GPOS:
   640     {
   641       const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index);
   642       l.collect_glyphs (&c);
   643       return;
   644     }
   645   }
   646 }
   649 /*
   650  * OT::GSUB
   651  */
   653 hb_bool_t
   654 hb_ot_layout_has_substitution (hb_face_t *face)
   655 {
   656   return &_get_gsub (face) != &OT::Null(OT::GSUB);
   657 }
   659 hb_bool_t
   660 hb_ot_layout_lookup_would_substitute (hb_face_t            *face,
   661 				      unsigned int          lookup_index,
   662 				      const hb_codepoint_t *glyphs,
   663 				      unsigned int          glyphs_length,
   664 				      hb_bool_t             zero_context)
   665 {
   666   if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false;
   667   return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context);
   668 }
   670 hb_bool_t
   671 hb_ot_layout_lookup_would_substitute_fast (hb_face_t            *face,
   672 					   unsigned int          lookup_index,
   673 					   const hb_codepoint_t *glyphs,
   674 					   unsigned int          glyphs_length,
   675 					   hb_bool_t             zero_context)
   676 {
   677   if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
   678   OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, zero_context);
   680   const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
   682   return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index].digest);
   683 }
   685 void
   686 hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer)
   687 {
   688   OT::GSUB::substitute_start (font, buffer);
   689 }
   691 void
   692 hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
   693 {
   694   OT::GSUB::substitute_finish (font, buffer);
   695 }
   697 void
   698 hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
   699 				        unsigned int  lookup_index,
   700 				        hb_set_t     *glyphs)
   701 {
   702   OT::hb_closure_context_t c (face, glyphs);
   704   const OT::SubstLookup& l = _get_gsub (face).get_lookup (lookup_index);
   706   l.closure (&c);
   707 }
   709 /*
   710  * OT::GPOS
   711  */
   713 hb_bool_t
   714 hb_ot_layout_has_positioning (hb_face_t *face)
   715 {
   716   return &_get_gpos (face) != &OT::Null(OT::GPOS);
   717 }
   719 void
   720 hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
   721 {
   722   OT::GPOS::position_start (font, buffer);
   723 }
   725 void
   726 hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer)
   727 {
   728   OT::GPOS::position_finish (font, buffer);
   729 }
   731 hb_bool_t
   732 hb_ot_layout_get_size_params (hb_face_t    *face,
   733 			      unsigned int *design_size,       /* OUT.  May be NULL */
   734 			      unsigned int *subfamily_id,      /* OUT.  May be NULL */
   735 			      unsigned int *subfamily_name_id, /* OUT.  May be NULL */
   736 			      unsigned int *range_start,       /* OUT.  May be NULL */
   737 			      unsigned int *range_end          /* OUT.  May be NULL */)
   738 {
   739   const OT::GPOS &gpos = _get_gpos (face);
   740   const hb_tag_t tag = HB_TAG ('s','i','z','e');
   742   unsigned int num_features = gpos.get_feature_count ();
   743   for (unsigned int i = 0; i < num_features; i++)
   744   {
   745     if (tag == gpos.get_feature_tag (i))
   746     {
   747       const OT::Feature &f = gpos.get_feature (i);
   748       const OT::FeatureParamsSize &params = f.get_feature_params ().get_size_params (tag);
   750       if (params.designSize)
   751       {
   752 #define PARAM(a, A) if (a) *a = params.A
   753 	PARAM (design_size, designSize);
   754 	PARAM (subfamily_id, subfamilyID);
   755 	PARAM (subfamily_name_id, subfamilyNameID);
   756 	PARAM (range_start, rangeStart);
   757 	PARAM (range_end, rangeEnd);
   758 #undef PARAM
   760 	return true;
   761       }
   762     }
   763   }
   765 #define PARAM(a, A) if (a) *a = 0
   766   PARAM (design_size, designSize);
   767   PARAM (subfamily_id, subfamilyID);
   768   PARAM (subfamily_name_id, subfamilyNameID);
   769   PARAM (range_start, rangeStart);
   770   PARAM (range_end, rangeEnd);
   771 #undef PARAM
   773   return false;
   774 }
   777 /*
   778  * Parts of different types are implemented here such that they have direct
   779  * access to GSUB/GPOS lookups.
   780  */
   783 struct GSUBProxy
   784 {
   785   static const unsigned int table_index = 0;
   786   static const bool inplace = false;
   787   typedef OT::SubstLookup Lookup;
   789   GSUBProxy (hb_face_t *face) :
   790     table (*hb_ot_layout_from_face (face)->gsub),
   791     accels (hb_ot_layout_from_face (face)->gsub_accels) {}
   793   const OT::GSUB &table;
   794   const hb_ot_layout_lookup_accelerator_t *accels;
   795 };
   797 struct GPOSProxy
   798 {
   799   static const unsigned int table_index = 1;
   800   static const bool inplace = true;
   801   typedef OT::PosLookup Lookup;
   803   GPOSProxy (hb_face_t *face) :
   804     table (*hb_ot_layout_from_face (face)->gpos),
   805     accels (hb_ot_layout_from_face (face)->gpos_accels) {}
   807   const OT::GPOS &table;
   808   const hb_ot_layout_lookup_accelerator_t *accels;
   809 };
   812 template <typename Lookup>
   813 static inline bool apply_once (OT::hb_apply_context_t *c,
   814 			       const Lookup &lookup)
   815 {
   816   if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
   817     return false;
   818   return lookup.dispatch (c);
   819 }
   821 template <typename Proxy>
   822 static inline bool
   823 apply_string (OT::hb_apply_context_t *c,
   824 	      const typename Proxy::Lookup &lookup,
   825 	      const hb_ot_layout_lookup_accelerator_t &accel)
   826 {
   827   bool ret = false;
   828   hb_buffer_t *buffer = c->buffer;
   830   if (unlikely (!buffer->len || !c->lookup_mask))
   831     return false;
   833   c->set_lookup (lookup);
   835   if (likely (!lookup.is_reverse ()))
   836   {
   837     /* in/out forward substitution/positioning */
   838     if (Proxy::table_index == 0)
   839       buffer->clear_output ();
   840     buffer->idx = 0;
   842     while (buffer->idx < buffer->len)
   843     {
   844       if (accel.digest.may_have (buffer->cur().codepoint) &&
   845 	  (buffer->cur().mask & c->lookup_mask) &&
   846 	  apply_once (c, lookup))
   847 	ret = true;
   848       else
   849 	buffer->next_glyph ();
   850     }
   851     if (ret)
   852     {
   853       if (!Proxy::inplace)
   854 	buffer->swap_buffers ();
   855       else
   856         assert (!buffer->has_separate_output ());
   857     }
   858   }
   859   else
   860   {
   861     /* in-place backward substitution/positioning */
   862     if (Proxy::table_index == 0)
   863       buffer->remove_output ();
   864     buffer->idx = buffer->len - 1;
   865     do
   866     {
   867       if (accel.digest.may_have (buffer->cur().codepoint) &&
   868 	  (buffer->cur().mask & c->lookup_mask) &&
   869 	  apply_once (c, lookup))
   870 	ret = true;
   871       /* The reverse lookup doesn't "advance" cursor (for good reason). */
   872       buffer->idx--;
   874     }
   875     while ((int) buffer->idx >= 0);
   876   }
   878   return ret;
   879 }
   881 template <typename Proxy>
   882 inline void hb_ot_map_t::apply (const Proxy &proxy,
   883 				const hb_ot_shape_plan_t *plan,
   884 				hb_font_t *font,
   885 				hb_buffer_t *buffer) const
   886 {
   887   const unsigned int table_index = proxy.table_index;
   888   unsigned int i = 0;
   889   OT::hb_apply_context_t c (table_index, font, buffer);
   890   c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
   892   for (unsigned int stage_index = 0; stage_index < stages[table_index].len; stage_index++) {
   893     const stage_map_t *stage = &stages[table_index][stage_index];
   894     for (; i < stage->last_lookup; i++)
   895     {
   896       unsigned int lookup_index = lookups[table_index][i].index;
   897       c.set_lookup_mask (lookups[table_index][i].mask);
   898       c.set_auto_zwj (lookups[table_index][i].auto_zwj);
   899       apply_string<Proxy> (&c,
   900 			   proxy.table.get_lookup (lookup_index),
   901 			   proxy.accels[lookup_index]);
   902     }
   904     if (stage->pause_func)
   905     {
   906       buffer->clear_output ();
   907       stage->pause_func (plan, font, buffer);
   908     }
   909   }
   910 }
   912 void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
   913 {
   914   GSUBProxy proxy (font->face);
   915   apply (proxy, plan, font, buffer);
   916 }
   918 void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
   919 {
   920   GPOSProxy proxy (font->face);
   921   apply (proxy, plan, font, buffer);
   922 }
   924 HB_INTERNAL void
   925 hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
   926 				const OT::SubstLookup &lookup,
   927 				const hb_ot_layout_lookup_accelerator_t &accel)
   928 {
   929   apply_string<GSUBProxy> (c, lookup, accel);
   930 }

mercurial