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       HB_FALLTHROUGH;
    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       HB_FALLTHROUGH;
    263 
    264     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT:
    265     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
    266       pos.y_offset = base_extents.y_bearing + base_extents.height - mark_extents.y_bearing;
    267       /* Never shift up "below" marks. */
    268       if ((y_gap > 0) == (pos.y_offset > 0))
    269       {
    270 	base_extents.height -= pos.y_offset;
    271 	pos.y_offset = 0;
    272       }
    273       base_extents.height += mark_extents.height;
    274       break;
    275 
    276     case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
    277     case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT:
    278     case HB_UNICODE_COMBINING_CLASS_ABOVE:
    279     case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT:
    280       /* Add gap, fall-through. */
    281       base_extents.y_bearing += y_gap;
    282       base_extents.height -= y_gap;
    283       HB_FALLTHROUGH;
    284 
    285     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
    286     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
    287       pos.y_offset = base_extents.y_bearing - (mark_extents.y_bearing + mark_extents.height);
    288       /* Don't shift down "above" marks too much. */
    289       if ((y_gap > 0) != (pos.y_offset > 0))
    290       {
    291 	unsigned int correction = -pos.y_offset / 2;
    292 	base_extents.y_bearing += correction;
    293 	base_extents.height -= correction;
    294 	pos.y_offset += correction;
    295       }
    296       base_extents.y_bearing -= mark_extents.height;
    297       base_extents.height += mark_extents.height;
    298       break;
    299   }
    300 }
    301 
    302 static inline void
    303 position_around_base (const hb_ot_shape_plan_t *plan,
    304 		      hb_font_t *font,
    305 		      hb_buffer_t  *buffer,
    306 		      unsigned int base,
    307 		      unsigned int end)
    308 {
    309   hb_direction_t horiz_dir = HB_DIRECTION_INVALID;
    310   hb_glyph_extents_t base_extents;
    311   if (!font->get_glyph_extents (buffer->info[base].codepoint,
    312 				&base_extents))
    313   {
    314     /* If extents don't work, zero marks and go home. */
    315     zero_mark_advances (buffer, base + 1, end);
    316     return;
    317   }
    318   base_extents.x_bearing += buffer->pos[base].x_offset;
    319   base_extents.y_bearing += buffer->pos[base].y_offset;
    320 
    321   unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[base]);
    322   unsigned int num_lig_components = _hb_glyph_info_get_lig_num_comps (&buffer->info[base]);
    323 
    324   hb_position_t x_offset = 0, y_offset = 0;
    325   if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
    326     x_offset -= buffer->pos[base].x_advance;
    327     y_offset -= buffer->pos[base].y_advance;
    328   }
    329 
    330   hb_glyph_extents_t component_extents = base_extents;
    331   unsigned int last_lig_component = (unsigned int) -1;
    332   unsigned int last_combining_class = 255;
    333   hb_glyph_extents_t cluster_extents = base_extents; /* Initialization is just to shut gcc up. */
    334   hb_glyph_info_t *info = buffer->info;
    335   for (unsigned int i = base + 1; i < end; i++)
    336     if (_hb_glyph_info_get_modified_combining_class (&info[i]))
    337     {
    338       if (num_lig_components > 1) {
    339 	unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&info[i]);
    340 	unsigned int this_lig_component = _hb_glyph_info_get_lig_comp (&info[i]) - 1;
    341 	/* Conditions for attaching to the last component. */
    342 	if (!lig_id || lig_id != this_lig_id || this_lig_component >= num_lig_components)
    343 	  this_lig_component = num_lig_components - 1;
    344 	if (last_lig_component != this_lig_component)
    345 	{
    346 	  last_lig_component = this_lig_component;
    347 	  last_combining_class = 255;
    348 	  component_extents = base_extents;
    349 	  if (unlikely (horiz_dir == HB_DIRECTION_INVALID)) {
    350 	    if (HB_DIRECTION_IS_HORIZONTAL (plan->props.direction))
    351 	      horiz_dir = plan->props.direction;
    352 	    else
    353 	      horiz_dir = hb_script_get_horizontal_direction (plan->props.script);
    354 	  }
    355 	  if (horiz_dir == HB_DIRECTION_LTR)
    356 	    component_extents.x_bearing += (this_lig_component * component_extents.width) / num_lig_components;
    357 	  else
    358 	    component_extents.x_bearing += ((num_lig_components - 1 - this_lig_component) * component_extents.width) / num_lig_components;
    359 	  component_extents.width /= num_lig_components;
    360 	}
    361       }
    362 
    363       unsigned int this_combining_class = _hb_glyph_info_get_modified_combining_class (&info[i]);
    364       if (last_combining_class != this_combining_class)
    365       {
    366 	last_combining_class = this_combining_class;
    367         cluster_extents = component_extents;
    368       }
    369 
    370       position_mark (plan, font, buffer, cluster_extents, i, this_combining_class);
    371 
    372       buffer->pos[i].x_advance = 0;
    373       buffer->pos[i].y_advance = 0;
    374       buffer->pos[i].x_offset += x_offset;
    375       buffer->pos[i].y_offset += y_offset;
    376 
    377     } else {
    378       if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
    379 	x_offset -= buffer->pos[i].x_advance;
    380 	y_offset -= buffer->pos[i].y_advance;
    381       } else {
    382 	x_offset += buffer->pos[i].x_advance;
    383 	y_offset += buffer->pos[i].y_advance;
    384       }
    385     }
    386 }
    387 
    388 static inline void
    389 position_cluster (const hb_ot_shape_plan_t *plan,
    390 		  hb_font_t *font,
    391 		  hb_buffer_t  *buffer,
    392 		  unsigned int start,
    393 		  unsigned int end)
    394 {
    395   if (end - start < 2)
    396     return;
    397 
    398   /* Find the base glyph */
    399   hb_glyph_info_t *info = buffer->info;
    400   for (unsigned int i = start; i < end; i++)
    401     if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))
    402     {
    403       /* Find mark glyphs */
    404       unsigned int j;
    405       for (j = i + 1; j < end; j++)
    406 	if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[j])))
    407 	  break;
    408 
    409       position_around_base (plan, font, buffer, i, j);
    410 
    411       i = j - 1;
    412     }
    413 }
    414 
    415 void
    416 _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan,
    417 				hb_font_t *font,
    418 				hb_buffer_t  *buffer)
    419 {
    420   _hb_buffer_assert_gsubgpos_vars (buffer);
    421 
    422   unsigned int start = 0;
    423   unsigned int count = buffer->len;
    424   hb_glyph_info_t *info = buffer->info;
    425   for (unsigned int i = 1; i < count; i++)
    426     if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))) {
    427       position_cluster (plan, font, buffer, start, i);
    428       start = i;
    429     }
    430   position_cluster (plan, font, buffer, start, count);
    431 }
    432 
    433 
    434 /* Performs old-style TrueType kerning. */
    435 void
    436 _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
    437 			    hb_font_t *font,
    438 			    hb_buffer_t  *buffer)
    439 {
    440   if (!plan->has_kern) return;
    441 
    442   OT::hb_apply_context_t c (1, font, buffer);
    443   c.set_lookup_mask (plan->kern_mask);
    444   c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
    445   OT::hb_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input;
    446   skippy_iter.init (&c);
    447 
    448   unsigned int count = buffer->len;
    449   hb_glyph_info_t *info = buffer->info;
    450   hb_glyph_position_t *pos = buffer->pos;
    451   for (unsigned int idx = 0; idx < count;)
    452   {
    453     skippy_iter.reset (idx, 1);
    454     if (!skippy_iter.next ())
    455     {
    456       idx++;
    457       continue;
    458     }
    459 
    460     hb_position_t x_kern, y_kern;
    461     font->get_glyph_kerning_for_direction (info[idx].codepoint,
    462 					   info[skippy_iter.idx].codepoint,
    463 					   buffer->props.direction,
    464 					   &x_kern, &y_kern);
    465 
    466     if (x_kern)
    467     {
    468       hb_position_t kern1 = x_kern >> 1;
    469       hb_position_t kern2 = x_kern - kern1;
    470       pos[idx].x_advance += kern1;
    471       pos[skippy_iter.idx].x_advance += kern2;
    472       pos[skippy_iter.idx].x_offset += kern2;
    473     }
    474 
    475     if (y_kern)
    476     {
    477       hb_position_t kern1 = y_kern >> 1;
    478       hb_position_t kern2 = y_kern - kern1;
    479       pos[idx].y_advance += kern1;
    480       pos[skippy_iter.idx].y_advance += kern2;
    481       pos[skippy_iter.idx].y_offset += kern2;
    482     }
    483 
    484     idx = skippy_iter.idx;
    485   }
    486 }
    487 
    488 
    489 /* Adjusts width of various spaces. */
    490 void
    491 _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
    492 			      hb_font_t *font,
    493 			      hb_buffer_t  *buffer)
    494 {
    495   if (!HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
    496     return;
    497 
    498   hb_glyph_info_t *info = buffer->info;
    499   hb_glyph_position_t *pos = buffer->pos;
    500   unsigned int count = buffer->len;
    501   for (unsigned int i = 0; i < count; i++)
    502     if (_hb_glyph_info_is_unicode_space (&info[i]) && !_hb_glyph_info_ligated (&info[i]))
    503     {
    504       hb_unicode_funcs_t::space_t space_type = _hb_glyph_info_get_unicode_space_fallback_type (&info[i]);
    505       hb_codepoint_t glyph;
    506       typedef hb_unicode_funcs_t t;
    507       switch (space_type)
    508       {
    509 	case t::NOT_SPACE: /* Shouldn't happen. */
    510 	case t::SPACE:
    511 	  break;
    512 
    513 	case t::SPACE_EM:
    514 	case t::SPACE_EM_2:
    515 	case t::SPACE_EM_3:
    516 	case t::SPACE_EM_4:
    517 	case t::SPACE_EM_5:
    518 	case t::SPACE_EM_6:
    519 	case t::SPACE_EM_16:
    520 	  pos[i].x_advance = (font->x_scale + ((int) space_type)/2) / (int) space_type;
    521 	  break;
    522 
    523 	case t::SPACE_4_EM_18:
    524 	  pos[i].x_advance = font->x_scale * 4 / 18;
    525 	  break;
    526 
    527 	case t::SPACE_FIGURE:
    528 	  for (char u = '0'; u <= '9'; u++)
    529 	    if (font->get_nominal_glyph (u, &glyph))
    530 	    {
    531 	      pos[i].x_advance = font->get_glyph_h_advance (glyph);
    532 	      break;
    533 	    }
    534 	  break;
    535 
    536 	case t::SPACE_PUNCTUATION:
    537 	  if (font->get_nominal_glyph ('.', &glyph))
    538 	    pos[i].x_advance = font->get_glyph_h_advance (glyph);
    539 	  else if (font->get_nominal_glyph (',', &glyph))
    540 	    pos[i].x_advance = font->get_glyph_h_advance (glyph);
    541 	  break;
    542 
    543 	case t::SPACE_NARROW:
    544 	  /* Half-space?
    545 	   * Unicode doc http://www.unicode.org/charts/PDF/U2000.pdf says ~1/4 or 1/5 of EM.
    546 	   * However, in my testing, many fonts have their regular space being about that
    547 	   * size.  To me, a percentage of the space width makes more sense.  Half is as
    548 	   * good as any. */
    549 	  pos[i].x_advance /= 2;
    550 	  break;
    551       }
    552     }
    553 }
    554