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) == 0x0E00u)
     39   {
     40     if (unlikely (klass == 0))
     41     {
     42       switch (u)
     43       {
     44         case 0x0E31u:
     45         case 0x0E34u:
     46         case 0x0E35u:
     47         case 0x0E36u:
     48         case 0x0E37u:
     49         case 0x0E47u:
     50         case 0x0E4Cu:
     51         case 0x0E4Du:
     52         case 0x0E4Eu:
     53 	  klass = HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
     54 	  break;
     55 
     56         case 0x0EB1u:
     57         case 0x0EB4u:
     58         case 0x0EB5u:
     59         case 0x0EB6u:
     60         case 0x0EB7u:
     61         case 0x0EBBu:
     62         case 0x0ECCu:
     63         case 0x0ECDu:
     64 	  klass = HB_UNICODE_COMBINING_CLASS_ABOVE;
     65 	  break;
     66 
     67         case 0x0EBCu:
     68 	  klass = HB_UNICODE_COMBINING_CLASS_BELOW;
     69 	  break;
     70       }
     71     } else {
     72       /* Thai virama is below-right */
     73       if (u == 0x0E3Au)
     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   hb_glyph_info_t *info = buffer->info;
    171   for (unsigned int i = 0; i < count; i++)
    172     if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) {
    173       unsigned int combining_class = _hb_glyph_info_get_modified_combining_class (&info[i]);
    174       combining_class = recategorize_combining_class (info[i].codepoint, combining_class);
    175       _hb_glyph_info_set_modified_combining_class (&info[i], combining_class);
    176     }
    177 }
    178 
    179 
    180 static void
    181 zero_mark_advances (hb_buffer_t *buffer,
    182 		    unsigned int start,
    183 		    unsigned int end)
    184 {
    185   hb_glyph_info_t *info = buffer->info;
    186   for (unsigned int i = start; i < end; i++)
    187     if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
    188     {
    189       buffer->pos[i].x_advance = 0;
    190       buffer->pos[i].y_advance = 0;
    191     }
    192 }
    193 
    194 static inline void
    195 position_mark (const hb_ot_shape_plan_t *plan,
    196 	       hb_font_t *font,
    197 	       hb_buffer_t  *buffer,
    198 	       hb_glyph_extents_t &base_extents,
    199 	       unsigned int i,
    200 	       unsigned int combining_class)
    201 {
    202   hb_glyph_extents_t mark_extents;
    203   if (!font->get_glyph_extents (buffer->info[i].codepoint,
    204 				&mark_extents))
    205     return;
    206 
    207   hb_position_t y_gap = font->y_scale / 16;
    208 
    209   hb_glyph_position_t &pos = buffer->pos[i];
    210   pos.x_offset = pos.y_offset = 0;
    211 
    212 
    213   /* We dont position LEFT and RIGHT marks. */
    214 
    215   /* X positioning */
    216   switch (combining_class)
    217   {
    218     case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW:
    219     case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
    220       if (buffer->props.direction == HB_DIRECTION_LTR) {
    221 	pos.x_offset += base_extents.x_bearing - mark_extents.width / 2 - mark_extents.x_bearing;
    222         break;
    223       } else if (buffer->props.direction == HB_DIRECTION_RTL) {
    224 	pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width / 2 - mark_extents.x_bearing;
    225         break;
    226       }
    227       /* Fall through */
    228 
    229     default:
    230     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
    231     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
    232     case HB_UNICODE_COMBINING_CLASS_BELOW:
    233     case HB_UNICODE_COMBINING_CLASS_ABOVE:
    234       /* Center align. */
    235       pos.x_offset += base_extents.x_bearing + (base_extents.width - mark_extents.width) / 2 - mark_extents.x_bearing;
    236       break;
    237 
    238     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT:
    239     case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT:
    240     case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT:
    241       /* Left align. */
    242       pos.x_offset += base_extents.x_bearing - mark_extents.x_bearing;
    243       break;
    244 
    245     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
    246     case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT:
    247     case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT:
    248       /* Right align. */
    249       pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width - mark_extents.x_bearing;
    250       break;
    251   }
    252 
    253   /* Y positioning */
    254   switch (combining_class)
    255   {
    256     case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW:
    257     case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT:
    258     case HB_UNICODE_COMBINING_CLASS_BELOW:
    259     case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT:
    260       /* Add gap, fall-through. */
    261       base_extents.height -= y_gap;
    262 
    263     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT:
    264     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
    265       pos.y_offset = base_extents.y_bearing + base_extents.height - mark_extents.y_bearing;
    266       /* Never shift up "below" marks. */
    267       if ((y_gap > 0) == (pos.y_offset > 0))
    268       {
    269 	base_extents.height -= pos.y_offset;
    270 	pos.y_offset = 0;
    271       }
    272       base_extents.height += mark_extents.height;
    273       break;
    274 
    275     case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
    276     case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT:
    277     case HB_UNICODE_COMBINING_CLASS_ABOVE:
    278     case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT:
    279       /* Add gap, fall-through. */
    280       base_extents.y_bearing += y_gap;
    281       base_extents.height -= y_gap;
    282 
    283     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
    284     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
    285       pos.y_offset = base_extents.y_bearing - (mark_extents.y_bearing + mark_extents.height);
    286       /* Don't shift down "above" marks too much. */
    287       if ((y_gap > 0) != (pos.y_offset > 0))
    288       {
    289 	unsigned int correction = -pos.y_offset / 2;
    290 	base_extents.y_bearing += correction;
    291 	base_extents.height -= correction;
    292 	pos.y_offset += correction;
    293       }
    294       base_extents.y_bearing -= mark_extents.height;
    295       base_extents.height += mark_extents.height;
    296       break;
    297   }
    298 }
    299 
    300 static inline void
    301 position_around_base (const hb_ot_shape_plan_t *plan,
    302 		      hb_font_t *font,
    303 		      hb_buffer_t  *buffer,
    304 		      unsigned int base,
    305 		      unsigned int end)
    306 {
    307   hb_direction_t horiz_dir = HB_DIRECTION_INVALID;
    308   hb_glyph_extents_t base_extents;
    309   if (!font->get_glyph_extents (buffer->info[base].codepoint,
    310 				&base_extents))
    311   {
    312     /* If extents don't work, zero marks and go home. */
    313     zero_mark_advances (buffer, base + 1, end);
    314     return;
    315   }
    316   base_extents.x_bearing += buffer->pos[base].x_offset;
    317   base_extents.y_bearing += buffer->pos[base].y_offset;
    318 
    319   unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[base]);
    320   unsigned int num_lig_components = _hb_glyph_info_get_lig_num_comps (&buffer->info[base]);
    321 
    322   hb_position_t x_offset = 0, y_offset = 0;
    323   if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
    324     x_offset -= buffer->pos[base].x_advance;
    325     y_offset -= buffer->pos[base].y_advance;
    326   }
    327 
    328   hb_glyph_extents_t component_extents = base_extents;
    329   unsigned int last_lig_component = (unsigned int) -1;
    330   unsigned int last_combining_class = 255;
    331   hb_glyph_extents_t cluster_extents = base_extents; /* Initialization is just to shut gcc up. */
    332   hb_glyph_info_t *info = buffer->info;
    333   for (unsigned int i = base + 1; i < end; i++)
    334     if (_hb_glyph_info_get_modified_combining_class (&info[i]))
    335     {
    336       if (num_lig_components > 1) {
    337 	unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&info[i]);
    338 	unsigned int this_lig_component = _hb_glyph_info_get_lig_comp (&info[i]) - 1;
    339 	/* Conditions for attaching to the last component. */
    340 	if (!lig_id || lig_id != this_lig_id || this_lig_component >= num_lig_components)
    341 	  this_lig_component = num_lig_components - 1;
    342 	if (last_lig_component != this_lig_component)
    343 	{
    344 	  last_lig_component = this_lig_component;
    345 	  last_combining_class = 255;
    346 	  component_extents = base_extents;
    347 	  if (unlikely (horiz_dir == HB_DIRECTION_INVALID)) {
    348 	    if (HB_DIRECTION_IS_HORIZONTAL (plan->props.direction))
    349 	      horiz_dir = plan->props.direction;
    350 	    else
    351 	      horiz_dir = hb_script_get_horizontal_direction (plan->props.script);
    352 	  }
    353 	  if (horiz_dir == HB_DIRECTION_LTR)
    354 	    component_extents.x_bearing += (this_lig_component * component_extents.width) / num_lig_components;
    355 	  else
    356 	    component_extents.x_bearing += ((num_lig_components - 1 - this_lig_component) * component_extents.width) / num_lig_components;
    357 	  component_extents.width /= num_lig_components;
    358 	}
    359       }
    360 
    361       unsigned int this_combining_class = _hb_glyph_info_get_modified_combining_class (&info[i]);
    362       if (last_combining_class != this_combining_class)
    363       {
    364 	last_combining_class = this_combining_class;
    365         cluster_extents = component_extents;
    366       }
    367 
    368       position_mark (plan, font, buffer, cluster_extents, i, this_combining_class);
    369 
    370       buffer->pos[i].x_advance = 0;
    371       buffer->pos[i].y_advance = 0;
    372       buffer->pos[i].x_offset += x_offset;
    373       buffer->pos[i].y_offset += y_offset;
    374 
    375     } else {
    376       if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
    377 	x_offset -= buffer->pos[i].x_advance;
    378 	y_offset -= buffer->pos[i].y_advance;
    379       } else {
    380 	x_offset += buffer->pos[i].x_advance;
    381 	y_offset += buffer->pos[i].y_advance;
    382       }
    383     }
    384 }
    385 
    386 static inline void
    387 position_cluster (const hb_ot_shape_plan_t *plan,
    388 		  hb_font_t *font,
    389 		  hb_buffer_t  *buffer,
    390 		  unsigned int start,
    391 		  unsigned int end)
    392 {
    393   if (end - start < 2)
    394     return;
    395 
    396   /* Find the base glyph */
    397   hb_glyph_info_t *info = buffer->info;
    398   for (unsigned int i = start; i < end; i++)
    399     if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))
    400     {
    401       /* Find mark glyphs */
    402       unsigned int j;
    403       for (j = i + 1; j < end; j++)
    404 	if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[j])))
    405 	  break;
    406 
    407       position_around_base (plan, font, buffer, i, j);
    408 
    409       i = j - 1;
    410     }
    411 }
    412 
    413 void
    414 _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan,
    415 				hb_font_t *font,
    416 				hb_buffer_t  *buffer)
    417 {
    418   unsigned int start = 0;
    419   unsigned int last_cluster = buffer->info[0].cluster;
    420   unsigned int count = buffer->len;
    421   for (unsigned int i = 1; i < count; i++)
    422     if (buffer->info[i].cluster != last_cluster) {
    423       position_cluster (plan, font, buffer, start, i);
    424       start = i;
    425       last_cluster = buffer->info[i].cluster;
    426     }
    427   position_cluster (plan, font, buffer, start, count);
    428 }
    429 
    430 
    431 /* Performs old-style TrueType kerning. */
    432 void
    433 _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
    434 			    hb_font_t *font,
    435 			    hb_buffer_t  *buffer)
    436 {
    437   if (!plan->has_kern) return;
    438 
    439   OT::hb_apply_context_t c (1, font, buffer);
    440   c.set_lookup_mask (plan->kern_mask);
    441   c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
    442 
    443   unsigned int count = buffer->len;
    444   hb_glyph_info_t *info = buffer->info;
    445   hb_glyph_position_t *pos = buffer->pos;
    446   for (unsigned int idx = 0; idx < count;)
    447   {
    448     OT::hb_apply_context_t::skipping_forward_iterator_t skippy_iter (&c, idx, 1);
    449     if (!skippy_iter.next ())
    450     {
    451       idx++;
    452       continue;
    453     }
    454 
    455     hb_position_t x_kern, y_kern;
    456     font->get_glyph_kerning_for_direction (info[idx].codepoint,
    457 					   info[skippy_iter.idx].codepoint,
    458 					   buffer->props.direction,
    459 					   &x_kern, &y_kern);
    460 
    461     if (x_kern)
    462     {
    463       hb_position_t kern1 = x_kern >> 1;
    464       hb_position_t kern2 = x_kern - kern1;
    465       pos[idx].x_advance += kern1;
    466       pos[skippy_iter.idx].x_advance += kern2;
    467       pos[skippy_iter.idx].x_offset += kern2;
    468     }
    469 
    470     if (y_kern)
    471     {
    472       hb_position_t kern1 = y_kern >> 1;
    473       hb_position_t kern2 = y_kern - kern1;
    474       pos[idx].y_advance += kern1;
    475       pos[skippy_iter.idx].y_advance += kern2;
    476       pos[skippy_iter.idx].y_offset += kern2;
    477     }
    478 
    479     idx = skippy_iter.idx;
    480   }
    481 }
    482