LCOV - code coverage report
Current view: directory - gfx/harfbuzz/src - hb-ot-shape-complex-indic.cc (source / functions) Found Hit Coverage
Test: app.info Lines: 136 0 0.0 %
Date: 2012-06-02 Functions: 16 0 0.0 %

       1                 : /*
       2                 :  * Copyright © 2011  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                 : #include "hb-ot-shape-complex-private.hh"
      28                 : 
      29                 : 
      30                 : 
      31                 : /* buffer var allocations */
      32                 : #define indic_category() complex_var_persistent_u8_0() /* indic_category_t */
      33                 : #define indic_position() complex_var_persistent_u8_1() /* indic_matra_category_t */
      34                 : 
      35                 : #define INDIC_TABLE_ELEMENT_TYPE uint8_t
      36                 : 
      37                 : /* Cateories used in the OpenType spec:
      38                 :  * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx
      39                 :  */
      40                 : /* Note: This enum is duplicated in the -machine.rl source file.
      41                 :  * Not sure how to avoid duplication. */
      42                 : enum indic_category_t {
      43                 :   OT_X = 0,
      44                 :   OT_C,
      45                 :   OT_Ra, /* Not explicitly listed in the OT spec, but used in the grammar. */
      46                 :   OT_V,
      47                 :   OT_N,
      48                 :   OT_H,
      49                 :   OT_ZWNJ,
      50                 :   OT_ZWJ,
      51                 :   OT_M,
      52                 :   OT_SM,
      53                 :   OT_VD,
      54                 :   OT_A,
      55                 :   OT_NBSP
      56                 : };
      57                 : 
      58                 : /* Visual positions in a syllable from left to right. */
      59                 : enum indic_position_t {
      60                 :   POS_PRE,
      61                 :   POS_BASE,
      62                 :   POS_ABOVE,
      63                 :   POS_BELOW,
      64                 :   POS_POST
      65                 : };
      66                 : 
      67                 : /* Categories used in IndicSyllabicCategory.txt from UCD */
      68                 : /* The assignments are guesswork */
      69                 : enum indic_syllabic_category_t {
      70                 :   INDIC_SYLLABIC_CATEGORY_OTHER                 = OT_X,
      71                 : 
      72                 :   INDIC_SYLLABIC_CATEGORY_AVAGRAHA              = OT_X,
      73                 :   INDIC_SYLLABIC_CATEGORY_BINDU                 = OT_SM,
      74                 :   INDIC_SYLLABIC_CATEGORY_CONSONANT             = OT_C,
      75                 :   INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD        = OT_C,
      76                 :   INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL       = OT_C,
      77                 :   INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER = OT_C,
      78                 :   INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL      = OT_C,
      79                 :   INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER = OT_NBSP,
      80                 :   INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED   = OT_C,
      81                 :   INDIC_SYLLABIC_CATEGORY_CONSONANT_REPHA       = OT_C,
      82                 :   INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER      = OT_X,
      83                 :   INDIC_SYLLABIC_CATEGORY_NUKTA                 = OT_N,
      84                 :   INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER      = OT_X,
      85                 :   INDIC_SYLLABIC_CATEGORY_TONE_LETTER           = OT_X,
      86                 :   INDIC_SYLLABIC_CATEGORY_TONE_MARK             = OT_X,
      87                 :   INDIC_SYLLABIC_CATEGORY_VIRAMA                = OT_H,
      88                 :   INDIC_SYLLABIC_CATEGORY_VISARGA               = OT_SM,
      89                 :   INDIC_SYLLABIC_CATEGORY_VOWEL                 = OT_V,
      90                 :   INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT       = OT_M,
      91                 :   INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT     = OT_V
      92                 : };
      93                 : 
      94                 : /* Categories used in IndicSMatraCategory.txt from UCD */
      95                 : enum indic_matra_category_t {
      96                 :   INDIC_MATRA_CATEGORY_NOT_APPLICABLE           = POS_BASE,
      97                 : 
      98                 :   INDIC_MATRA_CATEGORY_LEFT                     = POS_PRE,
      99                 :   INDIC_MATRA_CATEGORY_TOP                      = POS_ABOVE,
     100                 :   INDIC_MATRA_CATEGORY_BOTTOM                   = POS_BELOW,
     101                 :   INDIC_MATRA_CATEGORY_RIGHT                    = POS_POST,
     102                 : 
     103                 :   /* We don't really care much about these since we decompose them
     104                 :    * in the generic pre-shaping layer.  They will only be used if
     105                 :    * the font does not cover the decomposition.  In which case, we
     106                 :    * define these as aliases to the place we want the split-matra
     107                 :    * glyph to show up.  Quite arbitrary. */
     108                 :   INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT         = INDIC_MATRA_CATEGORY_BOTTOM,
     109                 :   INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT           = INDIC_MATRA_CATEGORY_LEFT,
     110                 :   INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM           = INDIC_MATRA_CATEGORY_BOTTOM,
     111                 :   INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT = INDIC_MATRA_CATEGORY_BOTTOM,
     112                 :   INDIC_MATRA_CATEGORY_TOP_AND_LEFT             = INDIC_MATRA_CATEGORY_LEFT,
     113                 :   INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT   = INDIC_MATRA_CATEGORY_LEFT,
     114                 :   INDIC_MATRA_CATEGORY_TOP_AND_RIGHT            = INDIC_MATRA_CATEGORY_RIGHT,
     115                 : 
     116                 :   INDIC_MATRA_CATEGORY_INVISIBLE                = INDIC_MATRA_CATEGORY_NOT_APPLICABLE,
     117                 :   INDIC_MATRA_CATEGORY_OVERSTRUCK               = INDIC_MATRA_CATEGORY_NOT_APPLICABLE,
     118                 :   INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT        = INDIC_MATRA_CATEGORY_NOT_APPLICABLE
     119                 : };
     120                 : 
     121                 : /* Note: We use ASSERT_STATIC_EXPR_ZERO() instead of ASSERT_STATIC_EXPR() and the comma operation
     122                 :  * because gcc fails to optimize the latter and fills the table in at runtime. */
     123                 : #define INDIC_COMBINE_CATEGORIES(S,M) \
     124                 :   (ASSERT_STATIC_EXPR_ZERO (M == INDIC_MATRA_CATEGORY_NOT_APPLICABLE || (S == INDIC_SYLLABIC_CATEGORY_VIRAMA || S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT)) + \
     125                 :    ASSERT_STATIC_EXPR_ZERO (S < 16 && M < 16) + \
     126                 :    ((M << 4) | S))
     127                 : 
     128                 : #include "hb-ot-shape-complex-indic-table.hh"
     129                 : 
     130                 : /* XXX
     131                 :  * This is a hack for now.  We should:
     132                 :  * 1. Move this data into the main Indic table,
     133                 :  * and/or
     134                 :  * 2. Probe font lookups to determine consonant positions.
     135                 :  */
     136                 : static const struct consonant_position_t {
     137                 :   hb_codepoint_t u;
     138                 :   indic_position_t position;
     139                 : } consonant_positions[] = {
     140                 :   {0x0930, POS_BELOW},
     141                 :   {0x09AC, POS_BELOW},
     142                 :   {0x09AF, POS_POST},
     143                 :   {0x09B0, POS_BELOW},
     144                 :   {0x09F0, POS_BELOW},
     145                 :   {0x0A2F, POS_POST},
     146                 :   {0x0A30, POS_BELOW},
     147                 :   {0x0A35, POS_BELOW},
     148                 :   {0x0A39, POS_BELOW},
     149                 :   {0x0AB0, POS_BELOW},
     150                 :   {0x0B24, POS_BELOW},
     151                 :   {0x0B28, POS_BELOW},
     152                 :   {0x0B2C, POS_BELOW},
     153                 :   {0x0B2D, POS_BELOW},
     154                 :   {0x0B2E, POS_BELOW},
     155                 :   {0x0B2F, POS_POST},
     156                 :   {0x0B30, POS_BELOW},
     157                 :   {0x0B32, POS_BELOW},
     158                 :   {0x0B33, POS_BELOW},
     159                 :   {0x0B5F, POS_POST},
     160                 :   {0x0B71, POS_BELOW},
     161                 :   {0x0C15, POS_BELOW},
     162                 :   {0x0C16, POS_BELOW},
     163                 :   {0x0C17, POS_BELOW},
     164                 :   {0x0C18, POS_BELOW},
     165                 :   {0x0C19, POS_BELOW},
     166                 :   {0x0C1A, POS_BELOW},
     167                 :   {0x0C1B, POS_BELOW},
     168                 :   {0x0C1C, POS_BELOW},
     169                 :   {0x0C1D, POS_BELOW},
     170                 :   {0x0C1E, POS_BELOW},
     171                 :   {0x0C1F, POS_BELOW},
     172                 :   {0x0C20, POS_BELOW},
     173                 :   {0x0C21, POS_BELOW},
     174                 :   {0x0C22, POS_BELOW},
     175                 :   {0x0C23, POS_BELOW},
     176                 :   {0x0C24, POS_BELOW},
     177                 :   {0x0C25, POS_BELOW},
     178                 :   {0x0C26, POS_BELOW},
     179                 :   {0x0C27, POS_BELOW},
     180                 :   {0x0C28, POS_BELOW},
     181                 :   {0x0C2A, POS_BELOW},
     182                 :   {0x0C2B, POS_BELOW},
     183                 :   {0x0C2C, POS_BELOW},
     184                 :   {0x0C2D, POS_BELOW},
     185                 :   {0x0C2E, POS_BELOW},
     186                 :   {0x0C2F, POS_BELOW},
     187                 :   {0x0C30, POS_BELOW},
     188                 :   {0x0C32, POS_BELOW},
     189                 :   {0x0C33, POS_BELOW},
     190                 :   {0x0C35, POS_BELOW},
     191                 :   {0x0C36, POS_BELOW},
     192                 :   {0x0C37, POS_BELOW},
     193                 :   {0x0C38, POS_BELOW},
     194                 :   {0x0C39, POS_BELOW},
     195                 :   {0x0C95, POS_BELOW},
     196                 :   {0x0C96, POS_BELOW},
     197                 :   {0x0C97, POS_BELOW},
     198                 :   {0x0C98, POS_BELOW},
     199                 :   {0x0C99, POS_BELOW},
     200                 :   {0x0C9A, POS_BELOW},
     201                 :   {0x0C9B, POS_BELOW},
     202                 :   {0x0C9C, POS_BELOW},
     203                 :   {0x0C9D, POS_BELOW},
     204                 :   {0x0C9E, POS_BELOW},
     205                 :   {0x0C9F, POS_BELOW},
     206                 :   {0x0CA0, POS_BELOW},
     207                 :   {0x0CA1, POS_BELOW},
     208                 :   {0x0CA2, POS_BELOW},
     209                 :   {0x0CA3, POS_BELOW},
     210                 :   {0x0CA4, POS_BELOW},
     211                 :   {0x0CA5, POS_BELOW},
     212                 :   {0x0CA6, POS_BELOW},
     213                 :   {0x0CA7, POS_BELOW},
     214                 :   {0x0CA8, POS_BELOW},
     215                 :   {0x0CAA, POS_BELOW},
     216                 :   {0x0CAB, POS_BELOW},
     217                 :   {0x0CAC, POS_BELOW},
     218                 :   {0x0CAD, POS_BELOW},
     219                 :   {0x0CAE, POS_BELOW},
     220                 :   {0x0CAF, POS_BELOW},
     221                 :   {0x0CB0, POS_BELOW},
     222                 :   {0x0CB2, POS_BELOW},
     223                 :   {0x0CB3, POS_BELOW},
     224                 :   {0x0CB5, POS_BELOW},
     225                 :   {0x0CB6, POS_BELOW},
     226                 :   {0x0CB7, POS_BELOW},
     227                 :   {0x0CB8, POS_BELOW},
     228                 :   {0x0CB9, POS_BELOW},
     229                 :   {0x0CDE, POS_BELOW},
     230                 :   {0x0D2F, POS_POST},
     231                 :   {0x0D30, POS_POST},
     232                 :   {0x0D32, POS_BELOW},
     233                 :   {0x0D35, POS_POST},
     234                 : };
     235                 : 
     236                 : /* XXX
     237                 :  * This is a hack for now.  We should move this data into the main Indic table.
     238                 :  */
     239                 : static const hb_codepoint_t ra_chars[] = {
     240                 :   0x0930, /* Devanagari */
     241                 :   0x09B0, /* Bengali */
     242                 :   0x09F0, /* Bengali */
     243                 : //0x09F1, /* Bengali */
     244                 : //0x0A30, /* Gurmukhi */
     245                 :   0x0AB0, /* Gujarati */
     246                 :   0x0B30, /* Oriya */
     247                 : //0x0BB0, /* Tamil */
     248                 : //0x0C30, /* Telugu */
     249                 :   0x0CB0, /* Kannada */
     250                 : //0x0D30, /* Malayalam */
     251                 : };
     252                 : 
     253                 : static int
     254               0 : compare_codepoint (const void *pa, const void *pb)
     255                 : {
     256               0 :   hb_codepoint_t a = * (hb_codepoint_t *) pa;
     257               0 :   hb_codepoint_t b = * (hb_codepoint_t *) pb;
     258                 : 
     259               0 :   return a < b ? -1 : a == b ? 0 : +1;
     260                 : }
     261                 : 
     262                 : static indic_position_t
     263               0 : consonant_position (hb_codepoint_t u)
     264                 : {
     265                 :   consonant_position_t *record;
     266                 : 
     267                 :   record = (consonant_position_t *) bsearch (&u, consonant_positions,
     268                 :                                              ARRAY_LENGTH (consonant_positions),
     269                 :                                              sizeof (consonant_positions[0]),
     270               0 :                                              compare_codepoint);
     271                 : 
     272               0 :   return record ? record->position : POS_BASE;
     273                 : }
     274                 : 
     275                 : static bool
     276               0 : is_ra (hb_codepoint_t u)
     277                 : {
     278                 :   return !!bsearch (&u, ra_chars,
     279                 :                     ARRAY_LENGTH (ra_chars),
     280                 :                     sizeof (ra_chars[0]),
     281               0 :                     compare_codepoint);
     282                 : }
     283                 : 
     284                 : static bool
     285               0 : is_joiner (const hb_glyph_info_t &info)
     286                 : {
     287               0 :   return !!(FLAG (info.indic_category()) & (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ)));
     288                 : }
     289                 : 
     290                 : static bool
     291               0 : is_consonant (const hb_glyph_info_t &info)
     292                 : {
     293               0 :   return !!(FLAG (info.indic_category()) & (FLAG (OT_C) | FLAG (OT_Ra)));
     294                 : }
     295                 : 
     296                 : static const struct {
     297                 :   hb_tag_t tag;
     298                 :   hb_bool_t is_global;
     299                 : } indic_basic_features[] =
     300                 : {
     301                 :   {HB_TAG('n','u','k','t'), true},
     302                 :   {HB_TAG('a','k','h','n'), false},
     303                 :   {HB_TAG('r','p','h','f'), false},
     304                 :   {HB_TAG('r','k','r','f'), false},
     305                 :   {HB_TAG('p','r','e','f'), false},
     306                 :   {HB_TAG('b','l','w','f'), false},
     307                 :   {HB_TAG('h','a','l','f'), false},
     308                 :   {HB_TAG('v','a','t','u'), true},
     309                 :   {HB_TAG('p','s','t','f'), false},
     310                 :   {HB_TAG('c','j','c','t'), false},
     311                 : };
     312                 : 
     313                 : /* Same order as the indic_basic_features array */
     314                 : enum {
     315                 :   _NUKT,
     316                 :   AKHN,
     317                 :   RPHF,
     318                 :   RKRF,
     319                 :   PREF,
     320                 :   BLWF,
     321                 :   HALF,
     322                 :   _VATU,
     323                 :   PSTF,
     324                 :   CJCT
     325                 : };
     326                 : 
     327                 : static const hb_tag_t indic_other_features[] =
     328                 : {
     329                 :   HB_TAG('p','r','e','s'),
     330                 :   HB_TAG('a','b','v','s'),
     331                 :   HB_TAG('b','l','w','s'),
     332                 :   HB_TAG('p','s','t','s'),
     333                 :   HB_TAG('h','a','l','n'),
     334                 : 
     335                 :   HB_TAG('d','i','s','t'),
     336                 :   HB_TAG('a','b','v','m'),
     337                 :   HB_TAG('b','l','w','m'),
     338                 : };
     339                 : 
     340                 : 
     341                 : static void
     342                 : initial_reordering (const hb_ot_map_t *map,
     343                 :                     hb_face_t *face,
     344                 :                     hb_buffer_t *buffer,
     345                 :                     void *user_data HB_UNUSED);
     346                 : static void
     347                 : final_reordering (const hb_ot_map_t *map,
     348                 :                   hb_face_t *face,
     349                 :                   hb_buffer_t *buffer,
     350                 :                   void *user_data HB_UNUSED);
     351                 : 
     352                 : void
     353               0 : _hb_ot_shape_complex_collect_features_indic (hb_ot_map_builder_t *map, const hb_segment_properties_t  *props)
     354                 : {
     355               0 :   map->add_bool_feature (HB_TAG('l','o','c','l'));
     356                 :   /* The Indic specs do not require ccmp, but we apply it here since if
     357                 :    * there is a use of it, it's typically at the beginning. */
     358               0 :   map->add_bool_feature (HB_TAG('c','c','m','p'));
     359                 : 
     360               0 :   map->add_gsub_pause (initial_reordering, NULL);
     361                 : 
     362               0 :   for (unsigned int i = 0; i < ARRAY_LENGTH (indic_basic_features); i++)
     363               0 :     map->add_bool_feature (indic_basic_features[i].tag, indic_basic_features[i].is_global);
     364                 : 
     365               0 :   map->add_gsub_pause (final_reordering, NULL);
     366                 : 
     367               0 :   for (unsigned int i = 0; i < ARRAY_LENGTH (indic_other_features); i++)
     368               0 :     map->add_bool_feature (indic_other_features[i], true);
     369               0 : }
     370                 : 
     371                 : 
     372                 : bool
     373               0 : _hb_ot_shape_complex_prefer_decomposed_indic (void)
     374                 : {
     375                 :   /* We want split matras decomposed by the common shaping logic. */
     376               0 :   return TRUE;
     377                 : }
     378                 : 
     379                 : 
     380                 : void
     381               0 : _hb_ot_shape_complex_setup_masks_indic (hb_ot_map_t *map, hb_buffer_t *buffer)
     382                 : {
     383               0 :   HB_BUFFER_ALLOCATE_VAR (buffer, indic_category);
     384               0 :   HB_BUFFER_ALLOCATE_VAR (buffer, indic_position);
     385                 : 
     386                 :   /* We cannot setup masks here.  We save information about characters
     387                 :    * and setup masks later on in a pause-callback. */
     388                 : 
     389               0 :   unsigned int count = buffer->len;
     390               0 :   for (unsigned int i = 0; i < count; i++)
     391                 :   {
     392               0 :     unsigned int type = get_indic_categories (buffer->info[i].codepoint);
     393                 : 
     394               0 :     buffer->info[i].indic_category() = type & 0x0F;
     395               0 :     buffer->info[i].indic_position() = type >> 4;
     396                 : 
     397               0 :     if (buffer->info[i].indic_category() == OT_C) {
     398               0 :       buffer->info[i].indic_position() = consonant_position (buffer->info[i].codepoint);
     399               0 :       if (is_ra (buffer->info[i].codepoint))
     400               0 :         buffer->info[i].indic_category() = OT_Ra;
     401               0 :     } else if (buffer->info[i].codepoint == 0x200C)
     402               0 :       buffer->info[i].indic_category() = OT_ZWNJ;
     403               0 :     else if (buffer->info[i].codepoint == 0x200D)
     404               0 :       buffer->info[i].indic_category() = OT_ZWJ;
     405                 :   }
     406               0 : }
     407                 : 
     408                 : static int
     409               0 : compare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
     410                 : {
     411               0 :   int a = pa->indic_position();
     412               0 :   int b = pb->indic_position();
     413                 : 
     414               0 :   return a < b ? -1 : a == b ? 0 : +1;
     415                 : }
     416                 : 
     417                 : static void
     418               0 : found_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array,
     419                 :                           unsigned int start, unsigned int end)
     420                 : {
     421                 :   unsigned int i;
     422               0 :   hb_glyph_info_t *info = buffer->info;
     423                 : 
     424                 :   /* Comments from:
     425                 :    * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */
     426                 : 
     427                 :   /* 1. Find base consonant:
     428                 :    *
     429                 :    * The shaping engine finds the base consonant of the syllable, using the
     430                 :    * following algorithm: starting from the end of the syllable, move backwards
     431                 :    * until a consonant is found that does not have a below-base or post-base
     432                 :    * form (post-base forms have to follow below-base forms), or that is not a
     433                 :    * pre-base reordering Ra, or arrive at the first consonant. The consonant
     434                 :    * stopped at will be the base.
     435                 :    *
     436                 :    *   o If the syllable starts with Ra + Halant (in a script that has Reph)
     437                 :    *     and has more than one consonant, Ra is excluded from candidates for
     438                 :    *     base consonants.
     439                 :    */
     440                 : 
     441               0 :   unsigned int base = end;
     442                 : 
     443                 :   /* -> starting from the end of the syllable, move backwards */
     444               0 :   i = end;
     445               0 :   unsigned int limit = start;
     446               0 :   if (info[start].indic_category() == OT_Ra && start + 2 <= end) {
     447               0 :     limit += 2;
     448               0 :     base = start;
     449                 :   };
     450               0 :   do {
     451               0 :     i--;
     452                 :     /* -> until a consonant is found */
     453               0 :     if (is_consonant (info[i]))
     454                 :     {
     455                 :       /* -> that does not have a below-base or post-base form
     456                 :        * (post-base forms have to follow below-base forms), */
     457               0 :       if (info[i].indic_position() != POS_BELOW &&
     458               0 :           info[i].indic_position() != POS_POST)
     459                 :       {
     460               0 :         base = i;
     461               0 :         break;
     462                 :       }
     463                 : 
     464                 :       /* -> or that is not a pre-base reordering Ra,
     465                 :        *
     466                 :        * TODO
     467                 :        */
     468                 : 
     469                 :       /* ->  o If the syllable starts with Ra + Halant (in a script that has Reph)
     470                 :        *       and has more than one consonant, Ra is excluded from candidates for
     471                 :        *       base consonants.
     472                 :        *
     473                 :        * IMPLEMENTATION NOTES:
     474                 :        *
     475                 :        * We do this by adjusting limit accordingly before entering the loop.
     476                 :        */
     477                 : 
     478                 :       /* -> or arrive at the first consonant. The consonant stopped at will
     479                 :        * be the base. */
     480               0 :       base = i;
     481                 :     }
     482                 :     else
     483               0 :       if (is_joiner (info[i]))
     484               0 :         break;
     485                 :   } while (i > limit);
     486               0 :   if (base < start)
     487               0 :     base = start; /* Just in case... */
     488                 : 
     489                 : 
     490                 :   /* 2. Decompose and reorder Matras:
     491                 :    *
     492                 :    * Each matra and any syllable modifier sign in the cluster are moved to the
     493                 :    * appropriate position relative to the consonant(s) in the cluster. The
     494                 :    * shaping engine decomposes two- or three-part matras into their constituent
     495                 :    * parts before any repositioning. Matra characters are classified by which
     496                 :    * consonant in a conjunct they have affinity for and are reordered to the
     497                 :    * following positions:
     498                 :    *
     499                 :    *   o Before first half form in the syllable
     500                 :    *   o After subjoined consonants
     501                 :    *   o After post-form consonant
     502                 :    *   o After main consonant (for above marks)
     503                 :    *
     504                 :    * IMPLEMENTATION NOTES:
     505                 :    *
     506                 :    * The normalize() routine has already decomposed matras for us, so we don't
     507                 :    * need to worry about that.
     508                 :    */
     509                 : 
     510                 : 
     511                 :   /* 3.  Reorder marks to canonical order:
     512                 :    *
     513                 :    * Adjacent nukta and halant or nukta and vedic sign are always repositioned
     514                 :    * if necessary, so that the nukta is first.
     515                 :    *
     516                 :    * IMPLEMENTATION NOTES:
     517                 :    *
     518                 :    * We don't need to do this: the normalize() routine already did this for us.
     519                 :    */
     520                 : 
     521                 : 
     522                 :   /* Reorder characters */
     523                 : 
     524               0 :   for (i = start; i < base; i++)
     525               0 :     info[i].indic_position() = POS_PRE;
     526               0 :   info[base].indic_position() = POS_BASE;
     527                 : 
     528                 : 
     529                 :   /* Handle beginning Ra */
     530               0 :   if (start + 3 <= end &&
     531               0 :       info[start].indic_category() == OT_Ra &&
     532               0 :       info[start + 1].indic_category() == OT_H &&
     533               0 :       !is_joiner (info[start + 2]))
     534                 :    {
     535               0 :     info[start].indic_position() = POS_POST;
     536               0 :     info[start].mask = mask_array[RPHF];
     537                 :    }
     538                 : 
     539                 :   /* For old-style Indic script tags, move the first post-base Halant after
     540                 :    * last consonant. */
     541               0 :   if ((map->get_chosen_script (0) & 0x000000FF) != '2') {
     542                 :     /* We should only do this for Indic scripts which have a version two I guess. */
     543               0 :     for (i = base + 1; i < end; i++)
     544               0 :       if (info[i].indic_category() == OT_H) {
     545                 :         unsigned int j;
     546               0 :         for (j = end - 1; j > i; j--)
     547               0 :           if ((FLAG (info[j].indic_category()) & (FLAG (OT_C) | FLAG (OT_Ra))))
     548               0 :             break;
     549               0 :         if (j > i) {
     550                 :           /* Move Halant to after last consonant. */
     551               0 :           hb_glyph_info_t t = info[i];
     552               0 :           memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0]));
     553               0 :           info[j] = t;
     554                 :         }
     555               0 :         break;
     556                 :       }
     557                 :   }
     558                 : 
     559                 :   /* Attach ZWJ, ZWNJ, nukta, and halant to previous char to move with them. */
     560               0 :   for (i = start + 1; i < end; i++)
     561               0 :     if ((FLAG (info[i].indic_category()) &
     562                 :          (FLAG (OT_ZWNJ) | FLAG (OT_ZWJ) | FLAG (OT_N) | FLAG (OT_H))))
     563               0 :       info[i].indic_position() = info[i - 1].indic_position();
     564                 : 
     565                 :   /* We do bubble-sort, skip malicious clusters attempts */
     566               0 :   if (end - start > 20)
     567               0 :     return;
     568                 : 
     569                 :   /* Sit tight, rock 'n roll! */
     570               0 :   hb_bubble_sort (info + start, end - start, compare_indic_order);
     571                 : 
     572                 :   /* Setup masks now */
     573                 : 
     574                 :   {
     575                 :     hb_mask_t mask;
     576                 : 
     577                 :     /* Pre-base */
     578               0 :     mask = mask_array[HALF] | mask_array[AKHN] | mask_array[CJCT];
     579               0 :     for (i = start; i < base; i++)
     580               0 :       info[i].mask  |= mask;
     581                 :     /* Base */
     582               0 :     mask = mask_array[AKHN] | mask_array[CJCT];
     583               0 :     info[base].mask |= mask;
     584                 :     /* Post-base */
     585               0 :     mask = mask_array[BLWF] | mask_array[PSTF] | mask_array[CJCT];
     586               0 :     for (i = base + 1; i < end; i++)
     587               0 :       info[i].mask  |= mask;
     588                 :   }
     589                 : 
     590                 :   /* Apply ZWJ/ZWNJ effects */
     591               0 :   for (i = start + 1; i < end; i++)
     592               0 :     if (is_joiner (info[i])) {
     593               0 :       bool non_joiner = info[i].indic_category() == OT_ZWNJ;
     594               0 :       unsigned int j = i;
     595                 : 
     596               0 :       do {
     597               0 :         j--;
     598                 : 
     599                 :         /* Reading the Unicode and OpenType specs, I think the following line
     600                 :          * is correct, but this is not what the test suite expects currently.
     601                 :          * The test suite has been drinking, not me...  But disable while
     602                 :          * investigating.
     603                 :          */
     604                 :         //info[j].mask &= !mask_array[CJCT];
     605               0 :         if (non_joiner)
     606               0 :           info[j].mask &= !mask_array[HALF];
     607                 : 
     608               0 :       } while (j > start && !is_consonant (info[j]));
     609                 :     }
     610                 : }
     611                 : 
     612                 : 
     613                 : static void
     614               0 : found_vowel_syllable (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array,
     615                 :                       unsigned int start, unsigned int end)
     616                 : {
     617                 :   /* TODO
     618                 :    * Not clear to me how this should work.  Do the matras move to before the
     619                 :    * independent vowel?  No idea.
     620                 :    */
     621               0 : }
     622                 : 
     623                 : static void
     624               0 : found_standalone_cluster (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array,
     625                 :                           unsigned int start, unsigned int end)
     626                 : {
     627                 :   /* TODO
     628                 :    * Easiest thing to do here is to convert the NBSP to consonant and
     629                 :    * call found_consonant_syllable.
     630                 :    */
     631               0 : }
     632                 : 
     633                 : static void
     634               0 : found_non_indic (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array,
     635                 :                  unsigned int start, unsigned int end)
     636                 : {
     637                 :   /* Nothing to do right now.  If we ever switch to using the output
     638                 :    * buffer in the reordering process, we'd need to next_glyph() here. */
     639               0 : }
     640                 : 
     641                 : #include "hb-ot-shape-complex-indic-machine.hh"
     642                 : 
     643                 : static void
     644               0 : remove_joiners (hb_buffer_t *buffer)
     645                 : {
     646                 :   /* For now we remove joiners.  However, Uniscbire seems to keep them
     647                 :    * and output a zero-width space glyph for them.  It is not clear to
     648                 :    * me how that is supposed to interact with GSUB. */
     649                 : 
     650               0 :   buffer->clear_output ();
     651               0 :   unsigned int count = buffer->len;
     652               0 :   for (buffer->idx = 0; buffer->idx < count;)
     653               0 :     if (unlikely (is_joiner (buffer->info[buffer->idx])))
     654               0 :       buffer->skip_glyph ();
     655                 :     else
     656               0 :       buffer->next_glyph ();
     657                 : 
     658               0 :   buffer->swap_buffers ();
     659               0 : }
     660                 : 
     661                 : static void
     662               0 : initial_reordering (const hb_ot_map_t *map,
     663                 :                     hb_face_t *face,
     664                 :                     hb_buffer_t *buffer,
     665                 :                     void *user_data HB_UNUSED)
     666                 : {
     667               0 :   hb_mask_t mask_array[ARRAY_LENGTH (indic_basic_features)] = {0};
     668               0 :   unsigned int num_masks = ARRAY_LENGTH (indic_basic_features);
     669               0 :   for (unsigned int i = 0; i < num_masks; i++)
     670               0 :     mask_array[i] = map->get_1_mask (indic_basic_features[i].tag);
     671                 : 
     672               0 :   find_syllables (map, buffer, mask_array);
     673                 : 
     674               0 :   remove_joiners (buffer);
     675               0 : }
     676                 : 
     677                 : static void
     678               0 : final_reordering (const hb_ot_map_t *map,
     679                 :                   hb_face_t *face,
     680                 :                   hb_buffer_t *buffer,
     681                 :                   void *user_data HB_UNUSED)
     682                 : {
     683                 :   /* 4. Final reordering:
     684                 :    *
     685                 :    * After the localized forms and basic shaping forms GSUB features have been
     686                 :    * applied (see below), the shaping engine performs some final glyph
     687                 :    * reordering before applying all the remaining font features to the entire
     688                 :    * cluster.
     689                 :    *
     690                 :    *   o Reorder matras:
     691                 :    *
     692                 :    *     If a pre-base matra character had been reordered before applying basic
     693                 :    *     features, the glyph can be moved closer to the main consonant based on
     694                 :    *     whether half-forms had been formed. Actual position for the matra is
     695                 :    *     defined as “after last standalone halant glyph, after initial matra
     696                 :    *     position and before the main consonant”. If ZWJ or ZWNJ follow this
     697                 :    *     halant, position is moved after it.
     698                 :    *
     699                 :    *   o Reorder reph:
     700                 :    *
     701                 :    *     Reph’s original position is always at the beginning of the syllable,
     702                 :    *     (i.e. it is not reordered at the character reordering stage). However,
     703                 :    *     it will be reordered according to the basic-forms shaping results.
     704                 :    *     Possible positions for reph, depending on the script, are; after main,
     705                 :    *     before post-base consonant forms, and after post-base consonant forms.
     706                 :    *
     707                 :    *       1. If reph should be positioned after post-base consonant forms,
     708                 :    *          proceed to step 5.
     709                 :    *
     710                 :    *       2. If the reph repositioning class is not after post-base: target
     711                 :    *          position is after the first explicit halant glyph between the
     712                 :    *          first post-reph consonant and last main consonant. If ZWJ or ZWNJ
     713                 :    *          are following this halant, position is moved after it. If such
     714                 :    *          position is found, this is the target position. Otherwise,
     715                 :    *          proceed to the next step.
     716                 :    *
     717                 :    *          Note: in old-implementation fonts, where classifications were
     718                 :    *          fixed in shaping engine, there was no case where reph position
     719                 :    *          will be found on this step.
     720                 :    *
     721                 :    *       3. If reph should be repositioned after the main consonant: from the
     722                 :    *          first consonant not ligated with main, or find the first
     723                 :    *          consonant that is not a potential pre-base reordering Ra.
     724                 :    *
     725                 :    *
     726                 :    *       4. If reph should be positioned before post-base consonant, find
     727                 :    *          first post-base classified consonant not ligated with main. If no
     728                 :    *          consonant is found, the target position should be before the
     729                 :    *          first matra, syllable modifier sign or vedic sign.
     730                 :    *
     731                 :    *       5. If no consonant is found in steps 3 or 4, move reph to a position
     732                 :    *          immediately before the first post-base matra, syllable modifier
     733                 :    *          sign or vedic sign that has a reordering class after the intended
     734                 :    *          reph position. For example, if the reordering position for reph
     735                 :    *          is post-main, it will skip above-base matras that also have a
     736                 :    *          post-main position.
     737                 :    *
     738                 :    *       6. Otherwise, reorder reph to the end of the syllable.
     739                 :    *
     740                 :    *   o Reorder pre-base reordering consonants:
     741                 :    *
     742                 :    *     If a pre-base reordering consonant is found, reorder it according to
     743                 :    *     the following rules:
     744                 :    *
     745                 :    *       1. Only reorder a glyph produced by substitution during application
     746                 :    *          of the feature. (Note that a font may shape a Ra consonant with
     747                 :    *          the feature generally but block it in certain contexts.)
     748                 :    *
     749                 :    *       2. Try to find a target position the same way as for pre-base matra.
     750                 :    *          If it is found, reorder pre-base consonant glyph.
     751                 :    *
     752                 :    *       3. If position is not found, reorder immediately before main
     753                 :    *          consonant.
     754                 :    */
     755                 : 
     756                 :   /* TODO */
     757                 : 
     758                 : 
     759                 : 
     760               0 :   HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category);
     761               0 :   HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position);
     762               0 : }
     763                 : 
     764                 : 
     765                 : 

Generated by: LCOV version 1.7