gfx/harfbuzz/src/hb-ot-shape-fallback.cc

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     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  */
    27 #include "hb-ot-shape-fallback-private.hh"
    28 #include "hb-ot-layout-gsubgpos-private.hh"
    30 static unsigned int
    31 recategorize_combining_class (hb_codepoint_t u,
    32 			      unsigned int klass)
    33 {
    34   if (klass >= 200)
    35     return klass;
    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;
    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;
    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   }
    78   switch (klass)
    79   {
    81     /* Hebrew */
    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;
    96     case HB_MODIFIED_COMBINING_CLASS_CCC23: /* rafe */
    97       return HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE;
    99     case HB_MODIFIED_COMBINING_CLASS_CCC24: /* shin dot */
   100       return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
   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;
   106     case HB_MODIFIED_COMBINING_CLASS_CCC26: /* point varika */
   107       return HB_UNICODE_COMBINING_CLASS_ABOVE;
   109     case HB_MODIFIED_COMBINING_CLASS_CCC21: /* dagesh */
   110       break;
   113     /* Arabic and Syriac */
   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;
   125     case HB_MODIFIED_COMBINING_CLASS_CCC29: /* kasratan */
   126     case HB_MODIFIED_COMBINING_CLASS_CCC32: /* kasra */
   127       return HB_UNICODE_COMBINING_CLASS_BELOW;
   130     /* Thai */
   132     case HB_MODIFIED_COMBINING_CLASS_CCC103: /* sara u / sara uu */
   133       return HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT;
   135     case HB_MODIFIED_COMBINING_CLASS_CCC107: /* mai */
   136       return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
   139     /* Lao */
   141     case HB_MODIFIED_COMBINING_CLASS_CCC118: /* sign u / sign uu */
   142       return HB_UNICODE_COMBINING_CLASS_BELOW;
   144     case HB_MODIFIED_COMBINING_CLASS_CCC122: /* mai */
   145       return HB_UNICODE_COMBINING_CLASS_ABOVE;
   148     /* Tibetan */
   150     case HB_MODIFIED_COMBINING_CLASS_CCC129: /* sign aa */
   151       return HB_UNICODE_COMBINING_CLASS_BELOW;
   153     case HB_MODIFIED_COMBINING_CLASS_CCC130: /* sign i*/
   154       return HB_UNICODE_COMBINING_CLASS_ABOVE;
   156     case HB_MODIFIED_COMBINING_CLASS_CCC132: /* sign u */
   157       return HB_UNICODE_COMBINING_CLASS_BELOW;
   159   }
   161   return klass;
   162 }
   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 }
   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 }
   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;
   205   hb_position_t y_gap = font->y_scale / 16;
   207   hb_glyph_position_t &pos = buffer->pos[i];
   208   pos.x_offset = pos.y_offset = 0;
   211   /* We dont position LEFT and RIGHT marks. */
   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 */
   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;
   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;
   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   }
   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;
   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;
   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;
   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 }
   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;
   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]);
   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   }
   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       }
   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       }
   365       position_mark (plan, font, buffer, cluster_extents, i, this_combining_class);
   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;
   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 }
   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;
   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;
   403       position_around_base (plan, font, buffer, i, j);
   405       i = j - 1;
   406     }
   407 }
   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 }
   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;
   435   unsigned int count = buffer->len;
   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);
   441   hb_glyph_info_t *info = buffer->info;
   442   hb_glyph_position_t *pos = buffer->pos;
   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     }
   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);
   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     }
   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     }
   477     idx = skippy_iter.idx;
   478   }
   479 }

mercurial