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       /* Never shift up "below" marks. */
    265       if ((y_gap > 0) == (pos.y_offset > 0))
    266       {
    267 	base_extents.height -= pos.y_offset;
    268 	pos.y_offset = 0;
    269       }
    270       base_extents.height += mark_extents.height;
    271       break;
    272 
    273     case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
    274     case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT:
    275     case HB_UNICODE_COMBINING_CLASS_ABOVE:
    276     case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT:
    277       /* Add gap, fall-through. */
    278       base_extents.y_bearing += y_gap;
    279       base_extents.height -= y_gap;
    280 
    281     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
    282     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
    283       pos.y_offset = base_extents.y_bearing - (mark_extents.y_bearing + mark_extents.height);
    284       /* Don't shift down "above" marks too much. */
    285       if ((y_gap > 0) != (pos.y_offset > 0))
    286       {
    287 	unsigned int correction = -pos.y_offset / 2;
    288 	base_extents.y_bearing += correction;
    289 	base_extents.height -= correction;
    290 	pos.y_offset += correction;
    291       }
    292       base_extents.y_bearing -= mark_extents.height;
    293       base_extents.height += mark_extents.height;
    294       break;
    295   }
    296 }
    297 
    298 static inline void
    299 position_around_base (const hb_ot_shape_plan_t *plan,
    300 		      hb_font_t *font,
    301 		      hb_buffer_t  *buffer,
    302 		      unsigned int base,
    303 		      unsigned int end)
    304 {
    305   hb_direction_t horiz_dir = HB_DIRECTION_INVALID;
    306   hb_glyph_extents_t base_extents;
    307   if (!font->get_glyph_extents (buffer->info[base].codepoint,
    308 				&base_extents))
    309   {
    310     /* If extents don't work, zero marks and go home. */
    311     zero_mark_advances (buffer, base + 1, end);
    312     return;
    313   }
    314   base_extents.x_bearing += buffer->pos[base].x_offset;
    315   base_extents.y_bearing += buffer->pos[base].y_offset;
    316 
    317   unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[base]);
    318   unsigned int num_lig_components = _hb_glyph_info_get_lig_num_comps (&buffer->info[base]);
    319 
    320   hb_position_t x_offset = 0, y_offset = 0;
    321   if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
    322     x_offset -= buffer->pos[base].x_advance;
    323     y_offset -= buffer->pos[base].y_advance;
    324   }
    325 
    326   hb_glyph_extents_t component_extents = base_extents;
    327   unsigned int last_lig_component = (unsigned int) -1;
    328   unsigned int last_combining_class = 255;
    329   hb_glyph_extents_t cluster_extents = base_extents; /* Initialization is just to shut gcc up. */
    330   for (unsigned int i = base + 1; i < end; i++)
    331     if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]))
    332     {
    333       if (num_lig_components > 1) {
    334 	unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[i]);
    335 	unsigned int this_lig_component = _hb_glyph_info_get_lig_comp (&buffer->info[i]) - 1;
    336 	/* Conditions for attaching to the last component. */
    337 	if (!lig_id || lig_id != this_lig_id || this_lig_component >= num_lig_components)
    338 	  this_lig_component = num_lig_components - 1;
    339 	if (last_lig_component != this_lig_component)
    340 	{
    341 	  last_lig_component = this_lig_component;
    342 	  last_combining_class = 255;
    343 	  component_extents = base_extents;
    344 	  if (unlikely (horiz_dir == HB_DIRECTION_INVALID)) {
    345 	    if (HB_DIRECTION_IS_HORIZONTAL (plan->props.direction))
    346 	      horiz_dir = plan->props.direction;
    347 	    else
    348 	      horiz_dir = hb_script_get_horizontal_direction (plan->props.script);
    349 	  }
    350 	  if (horiz_dir == HB_DIRECTION_LTR)
    351 	    component_extents.x_bearing += (this_lig_component * component_extents.width) / num_lig_components;
    352 	  else
    353 	    component_extents.x_bearing += ((num_lig_components - 1 - this_lig_component) * component_extents.width) / num_lig_components;
    354 	  component_extents.width /= num_lig_components;
    355 	}
    356       }
    357 
    358       unsigned int this_combining_class = _hb_glyph_info_get_modified_combining_class (&buffer->info[i]);
    359       if (last_combining_class != this_combining_class)
    360       {
    361 	last_combining_class = this_combining_class;
    362         cluster_extents = component_extents;
    363       }
    364 
    365       position_mark (plan, font, buffer, cluster_extents, i, this_combining_class);
    366 
    367       buffer->pos[i].x_advance = 0;
    368       buffer->pos[i].y_advance = 0;
    369       buffer->pos[i].x_offset += x_offset;
    370       buffer->pos[i].y_offset += y_offset;
    371 
    372     } else {
    373       if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
    374 	x_offset -= buffer->pos[i].x_advance;
    375 	y_offset -= buffer->pos[i].y_advance;
    376       } else {
    377 	x_offset += buffer->pos[i].x_advance;
    378 	y_offset += buffer->pos[i].y_advance;
    379       }
    380     }
    381 }
    382 
    383 static inline void
    384 position_cluster (const hb_ot_shape_plan_t *plan,
    385 		  hb_font_t *font,
    386 		  hb_buffer_t  *buffer,
    387 		  unsigned int start,
    388 		  unsigned int end)
    389 {
    390   if (end - start < 2)
    391     return;
    392 
    393   /* Find the base glyph */
    394   for (unsigned int i = start; i < end; i++)
    395     if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[i])))
    396     {
    397       /* Find mark glyphs */
    398       unsigned int j;
    399       for (j = i + 1; j < end; j++)
    400 	if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[j])))
    401 	  break;
    402 
    403       position_around_base (plan, font, buffer, i, j);
    404 
    405       i = j - 1;
    406     }
    407 }
    408 
    409 void
    410 _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan,
    411 				hb_font_t *font,
    412 				hb_buffer_t  *buffer)
    413 {
    414   unsigned int start = 0;
    415   unsigned int last_cluster = buffer->info[0].cluster;
    416   unsigned int count = buffer->len;
    417   for (unsigned int i = 1; i < count; i++)
    418     if (buffer->info[i].cluster != last_cluster) {
    419       position_cluster (plan, font, buffer, start, i);
    420       start = i;
    421       last_cluster = buffer->info[i].cluster;
    422     }
    423   position_cluster (plan, font, buffer, start, count);
    424 }
    425 
    426 
    427 /* Performs old-style TrueType kerning. */
    428 void
    429 _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
    430 			    hb_font_t *font,
    431 			    hb_buffer_t  *buffer)
    432 {
    433   if (!plan->has_kern) return;
    434 
    435   unsigned int count = buffer->len;
    436 
    437   OT::hb_apply_context_t c (1, font, buffer);
    438   c.set_lookup_mask (plan->kern_mask);
    439   c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
    440 
    441   hb_glyph_info_t *info = buffer->info;
    442   hb_glyph_position_t *pos = buffer->pos;
    443 
    444   for (unsigned int idx = 0; idx < count;)
    445   {
    446     OT::hb_apply_context_t::skipping_forward_iterator_t skippy_iter (&c, idx, 1);
    447     if (!skippy_iter.next ())
    448     {
    449       idx++;
    450       continue;
    451     }
    452 
    453     hb_position_t x_kern, y_kern;
    454     font->get_glyph_kerning_for_direction (info[idx].codepoint,
    455 					   info[skippy_iter.idx].codepoint,
    456 					   buffer->props.direction,
    457 					   &x_kern, &y_kern);
    458 
    459     if (x_kern)
    460     {
    461       hb_position_t kern1 = x_kern >> 1;
    462       hb_position_t kern2 = x_kern - kern1;
    463       pos[idx].x_advance += kern1;
    464       pos[skippy_iter.idx].x_advance += kern2;
    465       pos[skippy_iter.idx].x_offset += kern2;
    466     }
    467 
    468     if (y_kern)
    469     {
    470       hb_position_t kern1 = y_kern >> 1;
    471       hb_position_t kern2 = y_kern - kern1;
    472       pos[idx].y_advance += kern1;
    473       pos[skippy_iter.idx].y_advance += kern2;
    474       pos[skippy_iter.idx].y_offset += kern2;
    475     }
    476 
    477     idx = skippy_iter.idx;
    478   }
    479 }
    480