LCOV - code coverage report
Current view: top level - gfx/harfbuzz/src - hb-ot-shape-complex-arabic-fallback.hh (source / functions) Hit Total Coverage
Test: output.info Lines: 0 109 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 8 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright © 2012  Google, Inc.
       3             :  *
       4             :  *  This is part of HarfBuzz, a text shaping library.
       5             :  *
       6             :  * Permission is hereby granted, without written agreement and without
       7             :  * license or royalty fees, to use, copy, modify, and distribute this
       8             :  * software and its documentation for any purpose, provided that the
       9             :  * above copyright notice and the following two paragraphs appear in
      10             :  * all copies of this software.
      11             :  *
      12             :  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
      13             :  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
      14             :  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
      15             :  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
      16             :  * DAMAGE.
      17             :  *
      18             :  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
      19             :  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
      20             :  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
      21             :  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
      22             :  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
      23             :  *
      24             :  * Google Author(s): Behdad Esfahbod
      25             :  */
      26             : 
      27             : #ifndef HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH
      28             : #define HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH
      29             : 
      30             : #include "hb-private.hh"
      31             : 
      32             : #include "hb-ot-shape-private.hh"
      33             : #include "hb-ot-layout-gsub-table.hh"
      34             : 
      35             : 
      36             : /* Features ordered the same as the entries in shaping_table rows,
      37             :  * followed by rlig.  Don't change. */
      38             : static const hb_tag_t arabic_fallback_features[] =
      39             : {
      40             :   HB_TAG('i','n','i','t'),
      41             :   HB_TAG('m','e','d','i'),
      42             :   HB_TAG('f','i','n','a'),
      43             :   HB_TAG('i','s','o','l'),
      44             :   HB_TAG('r','l','i','g'),
      45             : };
      46             : 
      47             : static OT::SubstLookup *
      48           0 : arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUSED,
      49             :                                           hb_font_t *font,
      50             :                                           unsigned int feature_index)
      51             : {
      52             :   OT::GlyphID glyphs[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
      53             :   OT::GlyphID substitutes[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
      54           0 :   unsigned int num_glyphs = 0;
      55             : 
      56             :   /* Populate arrays */
      57           0 :   for (hb_codepoint_t u = SHAPING_TABLE_FIRST; u < SHAPING_TABLE_LAST + 1; u++)
      58             :   {
      59           0 :     hb_codepoint_t s = shaping_table[u - SHAPING_TABLE_FIRST][feature_index];
      60             :     hb_codepoint_t u_glyph, s_glyph;
      61             : 
      62           0 :     if (!s ||
      63           0 :         !hb_font_get_glyph (font, u, 0, &u_glyph) ||
      64           0 :         !hb_font_get_glyph (font, s, 0, &s_glyph) ||
      65           0 :         u_glyph == s_glyph ||
      66           0 :         u_glyph > 0xFFFFu || s_glyph > 0xFFFFu)
      67           0 :       continue;
      68             : 
      69           0 :     glyphs[num_glyphs].set (u_glyph);
      70           0 :     substitutes[num_glyphs].set (s_glyph);
      71             : 
      72           0 :     num_glyphs++;
      73             :   }
      74             : 
      75           0 :   if (!num_glyphs)
      76           0 :     return NULL;
      77             : 
      78             :   /* Bubble-sort or something equally good!
      79             :    * May not be good-enough for presidential candidate interviews, but good-enough for us... */
      80           0 :   hb_stable_sort (&glyphs[0], num_glyphs, OT::GlyphID::cmp, &substitutes[0]);
      81             : 
      82           0 :   OT::Supplier<OT::GlyphID> glyphs_supplier      (glyphs, num_glyphs);
      83           0 :   OT::Supplier<OT::GlyphID> substitutes_supplier (substitutes, num_glyphs);
      84             : 
      85             :   /* Each glyph takes four bytes max, and there's some overhead. */
      86             :   char buf[(SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1) * 4 + 128];
      87           0 :   OT::hb_serialize_context_t c (buf, sizeof (buf));
      88           0 :   OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> ();
      89             :   bool ret = lookup->serialize_single (&c,
      90             :                                        OT::LookupFlag::IgnoreMarks,
      91             :                                        glyphs_supplier,
      92             :                                        substitutes_supplier,
      93           0 :                                        num_glyphs);
      94           0 :   c.end_serialize ();
      95             :   /* TODO sanitize the results? */
      96             : 
      97           0 :   return ret ? c.copy<OT::SubstLookup> () : NULL;
      98             : }
      99             : 
     100             : static OT::SubstLookup *
     101           0 : arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UNUSED,
     102             :                                             hb_font_t *font)
     103             : {
     104             :   OT::GlyphID first_glyphs[ARRAY_LENGTH_CONST (ligature_table)];
     105             :   unsigned int first_glyphs_indirection[ARRAY_LENGTH_CONST (ligature_table)];
     106             :   unsigned int ligature_per_first_glyph_count_list[ARRAY_LENGTH_CONST (first_glyphs)];
     107           0 :   unsigned int num_first_glyphs = 0;
     108             : 
     109             :   /* We know that all our ligatures are 2-component */
     110             :   OT::GlyphID ligature_list[ARRAY_LENGTH_CONST (first_glyphs) * ARRAY_LENGTH_CONST(ligature_table[0].ligatures)];
     111             :   unsigned int component_count_list[ARRAY_LENGTH_CONST (ligature_list)];
     112             :   OT::GlyphID component_list[ARRAY_LENGTH_CONST (ligature_list) * 1/* One extra component per ligature */];
     113           0 :   unsigned int num_ligatures = 0;
     114             : 
     115             :   /* Populate arrays */
     116             : 
     117             :   /* Sort out the first-glyphs */
     118           0 :   for (unsigned int first_glyph_idx = 0; first_glyph_idx < ARRAY_LENGTH (first_glyphs); first_glyph_idx++)
     119             :   {
     120           0 :     hb_codepoint_t first_u = ligature_table[first_glyph_idx].first;
     121             :     hb_codepoint_t first_glyph;
     122           0 :     if (!hb_font_get_glyph (font, first_u, 0, &first_glyph))
     123           0 :       continue;
     124           0 :     first_glyphs[num_first_glyphs].set (first_glyph);
     125           0 :     ligature_per_first_glyph_count_list[num_first_glyphs] = 0;
     126           0 :     first_glyphs_indirection[num_first_glyphs] = first_glyph_idx;
     127           0 :     num_first_glyphs++;
     128             :   }
     129           0 :   hb_stable_sort (&first_glyphs[0], num_first_glyphs, OT::GlyphID::cmp, &first_glyphs_indirection[0]);
     130             : 
     131             :   /* Now that the first-glyphs are sorted, walk again, populate ligatures. */
     132           0 :   for (unsigned int i = 0; i < num_first_glyphs; i++)
     133             :   {
     134           0 :     unsigned int first_glyph_idx = first_glyphs_indirection[i];
     135             : 
     136           0 :     for (unsigned int second_glyph_idx = 0; second_glyph_idx < ARRAY_LENGTH (ligature_table[0].ligatures); second_glyph_idx++)
     137             :     {
     138           0 :       hb_codepoint_t second_u   = ligature_table[first_glyph_idx].ligatures[second_glyph_idx].second;
     139           0 :       hb_codepoint_t ligature_u = ligature_table[first_glyph_idx].ligatures[second_glyph_idx].ligature;
     140             :       hb_codepoint_t second_glyph, ligature_glyph;
     141           0 :       if (!second_u ||
     142           0 :           !hb_font_get_glyph (font, second_u,   0, &second_glyph) ||
     143           0 :           !hb_font_get_glyph (font, ligature_u, 0, &ligature_glyph))
     144           0 :         continue;
     145             : 
     146           0 :       ligature_per_first_glyph_count_list[i]++;
     147             : 
     148           0 :       ligature_list[num_ligatures].set (ligature_glyph);
     149           0 :       component_count_list[num_ligatures] = 2;
     150           0 :       component_list[num_ligatures].set (second_glyph);
     151           0 :       num_ligatures++;
     152             :     }
     153             :   }
     154             : 
     155           0 :   if (!num_ligatures)
     156           0 :     return NULL;
     157             : 
     158           0 :   OT::Supplier<OT::GlyphID>   first_glyphs_supplier                      (first_glyphs, num_first_glyphs);
     159           0 :   OT::Supplier<unsigned int > ligature_per_first_glyph_count_supplier    (ligature_per_first_glyph_count_list, num_first_glyphs);
     160           0 :   OT::Supplier<OT::GlyphID>   ligatures_supplier                         (ligature_list, num_ligatures);
     161           0 :   OT::Supplier<unsigned int > component_count_supplier                   (component_count_list, num_ligatures);
     162           0 :   OT::Supplier<OT::GlyphID>   component_supplier                         (component_list, num_ligatures);
     163             : 
     164             :   /* 16 bytes per ligature ought to be enough... */
     165             :   char buf[ARRAY_LENGTH_CONST (ligature_list) * 16 + 128];
     166           0 :   OT::hb_serialize_context_t c (buf, sizeof (buf));
     167           0 :   OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> ();
     168             :   bool ret = lookup->serialize_ligature (&c,
     169             :                                          OT::LookupFlag::IgnoreMarks,
     170             :                                          first_glyphs_supplier,
     171             :                                          ligature_per_first_glyph_count_supplier,
     172             :                                          num_first_glyphs,
     173             :                                          ligatures_supplier,
     174             :                                          component_count_supplier,
     175           0 :                                          component_supplier);
     176             : 
     177           0 :   c.end_serialize ();
     178             :   /* TODO sanitize the results? */
     179             : 
     180           0 :   return ret ? c.copy<OT::SubstLookup> () : NULL;
     181             : }
     182             : 
     183             : static OT::SubstLookup *
     184           0 : arabic_fallback_synthesize_lookup (const hb_ot_shape_plan_t *plan,
     185             :                                    hb_font_t *font,
     186             :                                    unsigned int feature_index)
     187             : {
     188           0 :   if (feature_index < 4)
     189           0 :     return arabic_fallback_synthesize_lookup_single (plan, font, feature_index);
     190             :   else
     191           0 :     return arabic_fallback_synthesize_lookup_ligature (plan, font);
     192             : }
     193             : 
     194             : #define ARABIC_FALLBACK_MAX_LOOKUPS 5
     195             : 
     196             : struct arabic_fallback_plan_t
     197             : {
     198             :   ASSERT_POD ();
     199             : 
     200             :   unsigned int num_lookups;
     201             :   bool free_lookups;
     202             : 
     203             :   hb_mask_t mask_array[ARABIC_FALLBACK_MAX_LOOKUPS];
     204             :   OT::SubstLookup *lookup_array[ARABIC_FALLBACK_MAX_LOOKUPS];
     205             :   hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_FALLBACK_MAX_LOOKUPS];
     206             : };
     207             : 
     208             : static const arabic_fallback_plan_t arabic_fallback_plan_nil = {};
     209             : 
     210             : #if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_WIN1256)
     211             : #define HB_WITH_WIN1256
     212             : #endif
     213             : 
     214             : #ifdef HB_WITH_WIN1256
     215             : #include "hb-ot-shape-complex-arabic-win1256.hh"
     216             : #endif
     217             : 
     218             : struct ManifestLookup {
     219             :   OT::Tag tag;
     220             :   OT::OffsetTo<OT::SubstLookup> lookupOffset;
     221             : };
     222             : typedef OT::ArrayOf<ManifestLookup> Manifest;
     223             : 
     224             : static bool
     225           0 : arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan,
     226             :                                    const hb_ot_shape_plan_t *plan,
     227             :                                    hb_font_t *font)
     228             : {
     229             : #ifdef HB_WITH_WIN1256
     230             :   /* Does this font look like it's Windows-1256-encoded? */
     231             :   hb_codepoint_t g;
     232             :   if (!(hb_font_get_glyph (font, 0x0627u, 0, &g) && g == 199 /* ALEF */ &&
     233             :         hb_font_get_glyph (font, 0x0644u, 0, &g) && g == 225 /* LAM */ &&
     234             :         hb_font_get_glyph (font, 0x0649u, 0, &g) && g == 236 /* ALEF MAKSURA */ &&
     235             :         hb_font_get_glyph (font, 0x064Au, 0, &g) && g == 237 /* YEH */ &&
     236             :         hb_font_get_glyph (font, 0x0652u, 0, &g) && g == 250 /* SUKUN */))
     237             :     return false;
     238             : 
     239             :   const Manifest &manifest = reinterpret_cast<const Manifest&> (arabic_win1256_gsub_lookups.manifest);
     240             :   ASSERT_STATIC (sizeof (arabic_win1256_gsub_lookups.manifestData) / sizeof (ManifestLookup)
     241             :                  <= ARABIC_FALLBACK_MAX_LOOKUPS);
     242             :   /* TODO sanitize the table? */
     243             : 
     244             :   unsigned j = 0;
     245             :   unsigned int count = manifest.len;
     246             :   for (unsigned int i = 0; i < count; i++)
     247             :   {
     248             :     fallback_plan->mask_array[j] = plan->map.get_1_mask (manifest[i].tag);
     249             :     if (fallback_plan->mask_array[j])
     250             :     {
     251             :       fallback_plan->lookup_array[j] = const_cast<OT::SubstLookup*> (&(&manifest+manifest[i].lookupOffset));
     252             :       if (fallback_plan->lookup_array[j])
     253             :       {
     254             :         fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]);
     255             :         j++;
     256             :       }
     257             :     }
     258             :   }
     259             : 
     260             :   fallback_plan->num_lookups = j;
     261             :   fallback_plan->free_lookups = false;
     262             : 
     263             :   return j > 0;
     264             : #else
     265           0 :   return false;
     266             : #endif
     267             : }
     268             : 
     269             : static bool
     270           0 : arabic_fallback_plan_init_unicode (arabic_fallback_plan_t *fallback_plan,
     271             :                                    const hb_ot_shape_plan_t *plan,
     272             :                                    hb_font_t *font)
     273             : {
     274             :   ASSERT_STATIC (ARRAY_LENGTH_CONST(arabic_fallback_features) <= ARABIC_FALLBACK_MAX_LOOKUPS);
     275           0 :   unsigned int j = 0;
     276           0 :   for (unsigned int i = 0; i < ARRAY_LENGTH(arabic_fallback_features) ; i++)
     277             :   {
     278           0 :     fallback_plan->mask_array[j] = plan->map.get_1_mask (arabic_fallback_features[i]);
     279           0 :     if (fallback_plan->mask_array[j])
     280             :     {
     281           0 :       fallback_plan->lookup_array[j] = arabic_fallback_synthesize_lookup (plan, font, i);
     282           0 :       if (fallback_plan->lookup_array[j])
     283             :       {
     284           0 :         fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]);
     285           0 :         j++;
     286             :       }
     287             :     }
     288             :   }
     289             : 
     290           0 :   fallback_plan->num_lookups = j;
     291           0 :   fallback_plan->free_lookups = true;
     292             : 
     293           0 :   return j > 0;
     294             : }
     295             : 
     296             : static arabic_fallback_plan_t *
     297           0 : arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
     298             :                              hb_font_t *font)
     299             : {
     300           0 :   arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) calloc (1, sizeof (arabic_fallback_plan_t));
     301           0 :   if (unlikely (!fallback_plan))
     302           0 :     return const_cast<arabic_fallback_plan_t *> (&arabic_fallback_plan_nil);
     303             : 
     304           0 :   fallback_plan->num_lookups = 0;
     305           0 :   fallback_plan->free_lookups = false;
     306             : 
     307             :   /* Try synthesizing GSUB table using Unicode Arabic Presentation Forms,
     308             :    * in case the font has cmap entries for the presentation-forms characters. */
     309           0 :   if (arabic_fallback_plan_init_unicode (fallback_plan, plan, font))
     310           0 :     return fallback_plan;
     311             : 
     312             :   /* See if this looks like a Windows-1256-encoded font.  If it does, use a
     313             :    * hand-coded GSUB table. */
     314           0 :   if (arabic_fallback_plan_init_win1256 (fallback_plan, plan, font))
     315           0 :     return fallback_plan;
     316             : 
     317           0 :   free (fallback_plan);
     318           0 :   return const_cast<arabic_fallback_plan_t *> (&arabic_fallback_plan_nil);
     319             : }
     320             : 
     321             : static void
     322           0 : arabic_fallback_plan_destroy (arabic_fallback_plan_t *fallback_plan)
     323             : {
     324           0 :   if (!fallback_plan || fallback_plan == &arabic_fallback_plan_nil)
     325           0 :     return;
     326             : 
     327           0 :   for (unsigned int i = 0; i < fallback_plan->num_lookups; i++)
     328           0 :     if (fallback_plan->lookup_array[i])
     329             :     {
     330           0 :       fallback_plan->accel_array[i].fini ();
     331           0 :       if (fallback_plan->free_lookups)
     332           0 :         free (fallback_plan->lookup_array[i]);
     333             :     }
     334             : 
     335           0 :   free (fallback_plan);
     336             : }
     337             : 
     338             : static void
     339           0 : arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan,
     340             :                             hb_font_t *font,
     341             :                             hb_buffer_t *buffer)
     342             : {
     343           0 :   OT::hb_apply_context_t c (0, font, buffer);
     344           0 :   for (unsigned int i = 0; i < fallback_plan->num_lookups; i++)
     345           0 :     if (fallback_plan->lookup_array[i]) {
     346           0 :       c.set_lookup_mask (fallback_plan->mask_array[i]);
     347           0 :       hb_ot_layout_substitute_lookup (&c,
     348           0 :                                       *fallback_plan->lookup_array[i],
     349           0 :                                       fallback_plan->accel_array[i]);
     350             :     }
     351           0 : }
     352             : 
     353             : 
     354             : #endif /* HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH */

Generated by: LCOV version 1.13