Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright  2011,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 #include "hb-ot-shape-fallback-private.hh"
     28 #include "hb-ot-layout-gsubgpos-private.hh"
     29 
     30 static unsigned int
     31 recategorize_combining_class (hb_codepoint_t u,
     32 			      unsigned int klass)
     33 {
     34   if (klass >= 200)
     35     return klass;
     36 
     37   /* Thai / Lao need some per-character work. */
     38   if ((u & ~0xFF) == 0x0E00)
     39   {
     40     if (unlikely (klass == 0))
     41     {
     42       switch (u)
     43       {
     44         case 0x0E31:
     45         case 0x0E34:
     46         case 0x0E35:
     47         case 0x0E36:
     48         case 0x0E37:
     49         case 0x0E47:
     50         case 0x0E4C:
     51         case 0x0E4D:
     52         case 0x0E4E:
     53 	  klass = HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
     54 	  break;
     55 
     56         case 0x0EB1:
     57         case 0x0EB4:
     58         case 0x0EB5:
     59         case 0x0EB6:
     60         case 0x0EB7:
     61         case 0x0EBB:
     62         case 0x0ECC:
     63         case 0x0ECD:
     64 	  klass = HB_UNICODE_COMBINING_CLASS_ABOVE;
     65 	  break;
     66 
     67         case 0x0EBC:
     68 	  klass = HB_UNICODE_COMBINING_CLASS_BELOW;
     69 	  break;
     70       }
     71     } else {
     72       /* Thai virama is below-right */
     73       if (u == 0x0E3A)
     74 	klass = HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT;
     75     }
     76   }
     77 
     78   switch (klass)
     79   {
     80 
     81     /* Hebrew */
     82 
     83     case HB_MODIFIED_COMBINING_CLASS_CCC10: /* sheva */
     84     case HB_MODIFIED_COMBINING_CLASS_CCC11: /* hataf segol */
     85     case HB_MODIFIED_COMBINING_CLASS_CCC12: /* hataf patah */
     86     case HB_MODIFIED_COMBINING_CLASS_CCC13: /* hataf qamats */
     87     case HB_MODIFIED_COMBINING_CLASS_CCC14: /* hiriq */
     88     case HB_MODIFIED_COMBINING_CLASS_CCC15: /* tsere */
     89     case HB_MODIFIED_COMBINING_CLASS_CCC16: /* segol */
     90     case HB_MODIFIED_COMBINING_CLASS_CCC17: /* patah */
     91     case HB_MODIFIED_COMBINING_CLASS_CCC18: /* qamats */
     92     case HB_MODIFIED_COMBINING_CLASS_CCC20: /* qubuts */
     93     case HB_MODIFIED_COMBINING_CLASS_CCC22: /* meteg */
     94       return HB_UNICODE_COMBINING_CLASS_BELOW;
     95 
     96     case HB_MODIFIED_COMBINING_CLASS_CCC23: /* rafe */
     97       return HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE;
     98 
     99     case HB_MODIFIED_COMBINING_CLASS_CCC24: /* shin dot */
    100       return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
    101 
    102     case HB_MODIFIED_COMBINING_CLASS_CCC25: /* sin dot */
    103     case HB_MODIFIED_COMBINING_CLASS_CCC19: /* holam */
    104       return HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT;
    105 
    106     case HB_MODIFIED_COMBINING_CLASS_CCC26: /* point varika */
    107       return HB_UNICODE_COMBINING_CLASS_ABOVE;
    108 
    109     case HB_MODIFIED_COMBINING_CLASS_CCC21: /* dagesh */
    110       break;
    111 
    112 
    113     /* Arabic and Syriac */
    114 
    115     case HB_MODIFIED_COMBINING_CLASS_CCC27: /* fathatan */
    116     case HB_MODIFIED_COMBINING_CLASS_CCC28: /* dammatan */
    117     case HB_MODIFIED_COMBINING_CLASS_CCC30: /* fatha */
    118     case HB_MODIFIED_COMBINING_CLASS_CCC31: /* damma */
    119     case HB_MODIFIED_COMBINING_CLASS_CCC33: /* shadda */
    120     case HB_MODIFIED_COMBINING_CLASS_CCC34: /* sukun */
    121     case HB_MODIFIED_COMBINING_CLASS_CCC35: /* superscript alef */
    122     case HB_MODIFIED_COMBINING_CLASS_CCC36: /* superscript alaph */
    123       return HB_UNICODE_COMBINING_CLASS_ABOVE;
    124 
    125     case HB_MODIFIED_COMBINING_CLASS_CCC29: /* kasratan */
    126     case HB_MODIFIED_COMBINING_CLASS_CCC32: /* kasra */
    127       return HB_UNICODE_COMBINING_CLASS_BELOW;
    128 
    129 
    130     /* Thai */
    131 
    132     case HB_MODIFIED_COMBINING_CLASS_CCC103: /* sara u / sara uu */
    133       return HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT;
    134 
    135     case HB_MODIFIED_COMBINING_CLASS_CCC107: /* mai */
    136       return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
    137 
    138 
    139     /* Lao */
    140 
    141     case HB_MODIFIED_COMBINING_CLASS_CCC118: /* sign u / sign uu */
    142       return HB_UNICODE_COMBINING_CLASS_BELOW;
    143 
    144     case HB_MODIFIED_COMBINING_CLASS_CCC122: /* mai */
    145       return HB_UNICODE_COMBINING_CLASS_ABOVE;
    146 
    147 
    148     /* Tibetan */
    149 
    150     case HB_MODIFIED_COMBINING_CLASS_CCC129: /* sign aa */
    151       return HB_UNICODE_COMBINING_CLASS_BELOW;
    152 
    153     case HB_MODIFIED_COMBINING_CLASS_CCC130: /* sign i*/
    154       return HB_UNICODE_COMBINING_CLASS_ABOVE;
    155 
    156     case HB_MODIFIED_COMBINING_CLASS_CCC132: /* sign u */
    157       return HB_UNICODE_COMBINING_CLASS_BELOW;
    158 
    159   }
    160 
    161   return klass;
    162 }
    163 
    164 void
    165 _hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *plan HB_UNUSED,
    166 						   hb_font_t *font HB_UNUSED,
    167 						   hb_buffer_t  *buffer)
    168 {
    169   unsigned int count = buffer->len;
    170   for (unsigned int i = 0; i < count; i++)
    171     if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) {
    172       unsigned int combining_class = _hb_glyph_info_get_modified_combining_class (&buffer->info[i]);
    173       combining_class = recategorize_combining_class (buffer->info[i].codepoint, combining_class);
    174       _hb_glyph_info_set_modified_combining_class (&buffer->info[i], combining_class);
    175     }
    176 }
    177 
    178 
    179 static void
    180 zero_mark_advances (hb_buffer_t *buffer,
    181 		    unsigned int start,
    182 		    unsigned int end)
    183 {
    184   for (unsigned int i = start; i < end; i++)
    185     if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
    186     {
    187       buffer->pos[i].x_advance = 0;
    188       buffer->pos[i].y_advance = 0;
    189     }
    190 }
    191 
    192 static inline void
    193 position_mark (const hb_ot_shape_plan_t *plan,
    194 	       hb_font_t *font,
    195 	       hb_buffer_t  *buffer,
    196 	       hb_glyph_extents_t &base_extents,
    197 	       unsigned int i,
    198 	       unsigned int combining_class)
    199 {
    200   hb_glyph_extents_t mark_extents;
    201   if (!font->get_glyph_extents (buffer->info[i].codepoint,
    202 				&mark_extents))
    203     return;
    204 
    205   hb_position_t y_gap = font->y_scale / 16;
    206 
    207   hb_glyph_position_t &pos = buffer->pos[i];
    208   pos.x_offset = pos.y_offset = 0;
    209 
    210 
    211   /* We dont position LEFT and RIGHT marks. */
    212 
    213   /* X positioning */
    214   switch (combining_class)
    215   {
    216     case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW:
    217     case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
    218       if (buffer->props.direction == HB_DIRECTION_LTR) {
    219 	pos.x_offset += base_extents.x_bearing - mark_extents.width / 2 - mark_extents.x_bearing;
    220         break;
    221       } else if (buffer->props.direction == HB_DIRECTION_RTL) {
    222 	pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width / 2 - mark_extents.x_bearing;
    223         break;
    224       }
    225       /* Fall through */
    226 
    227     default:
    228     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
    229     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
    230     case HB_UNICODE_COMBINING_CLASS_BELOW:
    231     case HB_UNICODE_COMBINING_CLASS_ABOVE:
    232       /* Center align. */
    233       pos.x_offset += base_extents.x_bearing + (base_extents.width - mark_extents.width) / 2 - mark_extents.x_bearing;
    234       break;
    235 
    236     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT:
    237     case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT:
    238     case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT:
    239       /* Left align. */
    240       pos.x_offset += base_extents.x_bearing - mark_extents.x_bearing;
    241       break;
    242 
    243     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
    244     case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT:
    245     case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT:
    246       /* Right align. */
    247       pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width - mark_extents.x_bearing;
    248       break;
    249   }
    250 
    251   /* Y positioning */
    252   switch (combining_class)
    253   {
    254     case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW:
    255     case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT:
    256     case HB_UNICODE_COMBINING_CLASS_BELOW:
    257     case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT:
    258       /* Add gap, fall-through. */
    259       base_extents.height -= y_gap;
    260 
    261     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT:
    262     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
    263       pos.y_offset += base_extents.y_bearing + base_extents.height - mark_extents.y_bearing;
    264       base_extents.height += mark_extents.height;
    265       break;
    266 
    267     case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
    268     case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT:
    269     case HB_UNICODE_COMBINING_CLASS_ABOVE:
    270     case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT:
    271       /* Add gap, fall-through. */
    272       base_extents.y_bearing += y_gap;
    273       base_extents.height -= y_gap;
    274 
    275     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
    276     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
    277       pos.y_offset += base_extents.y_bearing - (mark_extents.y_bearing + mark_extents.height);
    278       base_extents.y_bearing -= mark_extents.height;
    279       base_extents.height += mark_extents.height;
    280       break;
    281   }
    282 }
    283 
    284 static inline void
    285 position_around_base (const hb_ot_shape_plan_t *plan,
    286 		      hb_font_t *font,
    287 		      hb_buffer_t  *buffer,
    288 		      unsigned int base,
    289 		      unsigned int end)
    290 {
    291   hb_direction_t horiz_dir = HB_DIRECTION_INVALID;
    292   hb_glyph_extents_t base_extents;
    293   if (!font->get_glyph_extents (buffer->info[base].codepoint,
    294 				&base_extents))
    295   {
    296     /* If extents don't work, zero marks and go home. */
    297     zero_mark_advances (buffer, base + 1, end);
    298     return;
    299   }
    300   base_extents.x_bearing += buffer->pos[base].x_offset;
    301   base_extents.y_bearing += buffer->pos[base].y_offset;
    302 
    303   unsigned int lig_id = get_lig_id (buffer->info[base]);
    304   unsigned int num_lig_components = get_lig_num_comps (buffer->info[base]);
    305 
    306   hb_position_t x_offset = 0, y_offset = 0;
    307   if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
    308     x_offset -= buffer->pos[base].x_advance;
    309     y_offset -= buffer->pos[base].y_advance;
    310   }
    311 
    312   hb_glyph_extents_t component_extents = base_extents;
    313   unsigned int last_lig_component = (unsigned int) -1;
    314   unsigned int last_combining_class = 255;
    315   hb_glyph_extents_t cluster_extents = base_extents; /* Initialization is just to shut gcc up. */
    316   for (unsigned int i = base + 1; i < end; i++)
    317     if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]))
    318     {
    319       if (num_lig_components > 1) {
    320 	unsigned int this_lig_id = get_lig_id (buffer->info[i]);
    321 	unsigned int this_lig_component = get_lig_comp (buffer->info[i]) - 1;
    322 	/* Conditions for attaching to the last component. */
    323 	if (!lig_id || lig_id != this_lig_id || this_lig_component >= num_lig_components)
    324 	  this_lig_component = num_lig_components - 1;
    325 	if (last_lig_component != this_lig_component)
    326 	{
    327 	  last_lig_component = this_lig_component;
    328 	  last_combining_class = 255;
    329 	  component_extents = base_extents;
    330 	  if (unlikely (horiz_dir == HB_DIRECTION_INVALID)) {
    331 	    if (HB_DIRECTION_IS_HORIZONTAL (plan->props.direction))
    332 	      horiz_dir = plan->props.direction;
    333 	    else
    334 	      horiz_dir = hb_script_get_horizontal_direction (plan->props.script);
    335 	  }
    336 	  if (horiz_dir == HB_DIRECTION_LTR)
    337 	    component_extents.x_bearing += (this_lig_component * component_extents.width) / num_lig_components;
    338 	  else
    339 	    component_extents.x_bearing += ((num_lig_components - 1 - this_lig_component) * component_extents.width) / num_lig_components;
    340 	  component_extents.width /= num_lig_components;
    341 	}
    342       }
    343 
    344       unsigned int this_combining_class = _hb_glyph_info_get_modified_combining_class (&buffer->info[i]);
    345       if (last_combining_class != this_combining_class)
    346       {
    347 	last_combining_class = this_combining_class;
    348         cluster_extents = component_extents;
    349       }
    350 
    351       position_mark (plan, font, buffer, cluster_extents, i, this_combining_class);
    352 
    353       buffer->pos[i].x_advance = 0;
    354       buffer->pos[i].y_advance = 0;
    355       buffer->pos[i].x_offset += x_offset;
    356       buffer->pos[i].y_offset += y_offset;
    357 
    358     } else {
    359       if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
    360 	x_offset -= buffer->pos[i].x_advance;
    361 	y_offset -= buffer->pos[i].y_advance;
    362       } else {
    363 	x_offset += buffer->pos[i].x_advance;
    364 	y_offset += buffer->pos[i].y_advance;
    365       }
    366     }
    367 }
    368 
    369 static inline void
    370 position_cluster (const hb_ot_shape_plan_t *plan,
    371 		  hb_font_t *font,
    372 		  hb_buffer_t  *buffer,
    373 		  unsigned int start,
    374 		  unsigned int end)
    375 {
    376   if (end - start < 2)
    377     return;
    378 
    379   /* Find the base glyph */
    380   for (unsigned int i = start; i < end; i++)
    381     if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[i])))
    382     {
    383       /* Find mark glyphs */
    384       unsigned int j;
    385       for (j = i + 1; j < end; j++)
    386 	if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[j])))
    387 	  break;
    388 
    389       position_around_base (plan, font, buffer, i, j);
    390 
    391       i = j - 1;
    392     }
    393 }
    394 
    395 void
    396 _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan,
    397 				hb_font_t *font,
    398 				hb_buffer_t  *buffer)
    399 {
    400   unsigned int start = 0;
    401   unsigned int last_cluster = buffer->info[0].cluster;
    402   unsigned int count = buffer->len;
    403   for (unsigned int i = 1; i < count; i++)
    404     if (buffer->info[i].cluster != last_cluster) {
    405       position_cluster (plan, font, buffer, start, i);
    406       start = i;
    407       last_cluster = buffer->info[i].cluster;
    408     }
    409   position_cluster (plan, font, buffer, start, count);
    410 }
    411 
    412 
    413 /* Performs old-style TrueType kerning. */
    414 void
    415 _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
    416 			    hb_font_t *font,
    417 			    hb_buffer_t  *buffer)
    418 {
    419   unsigned int count = buffer->len;
    420   hb_mask_t kern_mask = plan->map.get_1_mask (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction) ?
    421 					      HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n'));
    422 
    423   OT::hb_apply_context_t c (1, font, buffer, kern_mask, true/*auto_zwj*/);
    424   c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
    425 
    426   for (buffer->idx = 0; buffer->idx < count;)
    427   {
    428     OT::hb_apply_context_t::skipping_forward_iterator_t skippy_iter (&c, buffer->idx, 1);
    429     if (!skippy_iter.next ())
    430     {
    431       buffer->idx++;
    432       continue;
    433     }
    434 
    435     hb_position_t x_kern, y_kern, kern1, kern2;
    436     font->get_glyph_kerning_for_direction (buffer->info[buffer->idx].codepoint,
    437 					   buffer->info[skippy_iter.idx].codepoint,
    438 					   buffer->props.direction,
    439 					   &x_kern, &y_kern);
    440 
    441     kern1 = x_kern >> 1;
    442     kern2 = x_kern - kern1;
    443     buffer->pos[buffer->idx].x_advance += kern1;
    444     buffer->pos[skippy_iter.idx].x_advance += kern2;
    445     buffer->pos[skippy_iter.idx].x_offset += kern2;
    446 
    447     kern1 = y_kern >> 1;
    448     kern2 = y_kern - kern1;
    449     buffer->pos[buffer->idx].y_advance += kern1;
    450     buffer->pos[skippy_iter.idx].y_advance += kern2;
    451     buffer->pos[skippy_iter.idx].y_offset += kern2;
    452 
    453     buffer->idx = skippy_iter.idx;
    454   }
    455 }
    456