hb-ot-shape-fallback.cc 17.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*
 * Copyright © 2011,2012  Google, Inc.
 *
 *  This is part of HarfBuzz, a text shaping library.
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 *
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Google Author(s): Behdad Esfahbod
 */

B
Behdad Esfahbod 已提交
27
#include "hb-ot-shape-fallback-private.hh"
28
#include "hb-ot-layout-gsubgpos-private.hh"
29

30
static unsigned int
B
Behdad Esfahbod 已提交
31
recategorize_combining_class (hb_codepoint_t u,
32
			      unsigned int klass)
33
{
34 35
  if (klass >= 200)
    return klass;
36

37
  /* Thai / Lao need some per-character work. */
38
  if ((u & ~0xFF) == 0x0E00u)
39 40 41 42 43
  {
    if (unlikely (klass == 0))
    {
      switch (u)
      {
44 45 46 47 48 49 50 51 52
        case 0x0E31u:
        case 0x0E34u:
        case 0x0E35u:
        case 0x0E36u:
        case 0x0E37u:
        case 0x0E47u:
        case 0x0E4Cu:
        case 0x0E4Du:
        case 0x0E4Eu:
53 54 55
	  klass = HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
	  break;

56 57 58 59 60 61 62 63
        case 0x0EB1u:
        case 0x0EB4u:
        case 0x0EB5u:
        case 0x0EB6u:
        case 0x0EB7u:
        case 0x0EBBu:
        case 0x0ECCu:
        case 0x0ECDu:
64 65 66
	  klass = HB_UNICODE_COMBINING_CLASS_ABOVE;
	  break;

67
        case 0x0EBCu:
68 69 70 71 72
	  klass = HB_UNICODE_COMBINING_CLASS_BELOW;
	  break;
      }
    } else {
      /* Thai virama is below-right */
73
      if (u == 0x0E3Au)
74 75 76 77 78
	klass = HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT;
    }
  }

  switch (klass)
79
  {
80

81
    /* Hebrew */
82

83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
    case HB_MODIFIED_COMBINING_CLASS_CCC10: /* sheva */
    case HB_MODIFIED_COMBINING_CLASS_CCC11: /* hataf segol */
    case HB_MODIFIED_COMBINING_CLASS_CCC12: /* hataf patah */
    case HB_MODIFIED_COMBINING_CLASS_CCC13: /* hataf qamats */
    case HB_MODIFIED_COMBINING_CLASS_CCC14: /* hiriq */
    case HB_MODIFIED_COMBINING_CLASS_CCC15: /* tsere */
    case HB_MODIFIED_COMBINING_CLASS_CCC16: /* segol */
    case HB_MODIFIED_COMBINING_CLASS_CCC17: /* patah */
    case HB_MODIFIED_COMBINING_CLASS_CCC18: /* qamats */
    case HB_MODIFIED_COMBINING_CLASS_CCC20: /* qubuts */
    case HB_MODIFIED_COMBINING_CLASS_CCC22: /* meteg */
      return HB_UNICODE_COMBINING_CLASS_BELOW;

    case HB_MODIFIED_COMBINING_CLASS_CCC23: /* rafe */
      return HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE;

    case HB_MODIFIED_COMBINING_CLASS_CCC24: /* shin dot */
      return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;

    case HB_MODIFIED_COMBINING_CLASS_CCC25: /* sin dot */
    case HB_MODIFIED_COMBINING_CLASS_CCC19: /* holam */
      return HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT;

    case HB_MODIFIED_COMBINING_CLASS_CCC26: /* point varika */
      return HB_UNICODE_COMBINING_CLASS_ABOVE;

    case HB_MODIFIED_COMBINING_CLASS_CCC21: /* dagesh */
      break;

112

113
    /* Arabic and Syriac */
114

115 116 117 118 119 120 121 122 123 124 125 126 127 128
    case HB_MODIFIED_COMBINING_CLASS_CCC27: /* fathatan */
    case HB_MODIFIED_COMBINING_CLASS_CCC28: /* dammatan */
    case HB_MODIFIED_COMBINING_CLASS_CCC30: /* fatha */
    case HB_MODIFIED_COMBINING_CLASS_CCC31: /* damma */
    case HB_MODIFIED_COMBINING_CLASS_CCC33: /* shadda */
    case HB_MODIFIED_COMBINING_CLASS_CCC34: /* sukun */
    case HB_MODIFIED_COMBINING_CLASS_CCC35: /* superscript alef */
    case HB_MODIFIED_COMBINING_CLASS_CCC36: /* superscript alaph */
      return HB_UNICODE_COMBINING_CLASS_ABOVE;

    case HB_MODIFIED_COMBINING_CLASS_CCC29: /* kasratan */
    case HB_MODIFIED_COMBINING_CLASS_CCC32: /* kasra */
      return HB_UNICODE_COMBINING_CLASS_BELOW;

129 130 131 132

    /* Thai */

    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 140 141


    /* Lao */

    case HB_MODIFIED_COMBINING_CLASS_CCC118: /* sign u / sign uu */
B
Behdad Esfahbod 已提交
142
      return HB_UNICODE_COMBINING_CLASS_BELOW;
143 144

    case HB_MODIFIED_COMBINING_CLASS_CCC122: /* mai */
B
Behdad Esfahbod 已提交
145
      return HB_UNICODE_COMBINING_CLASS_ABOVE;
146 147 148 149 150 151 152 153 154 155 156 157 158


    /* Tibetan */

    case HB_MODIFIED_COMBINING_CLASS_CCC129: /* sign aa */
      return HB_UNICODE_COMBINING_CLASS_BELOW;

    case HB_MODIFIED_COMBINING_CLASS_CCC130: /* sign i*/
      return HB_UNICODE_COMBINING_CLASS_ABOVE;

    case HB_MODIFIED_COMBINING_CLASS_CCC132: /* sign u */
      return HB_UNICODE_COMBINING_CLASS_BELOW;

159 160
  }

161
  return klass;
162 163
}

B
Behdad Esfahbod 已提交
164
void
B
Behdad Esfahbod 已提交
165 166
_hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *plan HB_UNUSED,
						   hb_font_t *font HB_UNUSED,
B
Behdad Esfahbod 已提交
167 168 169
						   hb_buffer_t  *buffer)
{
  unsigned int count = buffer->len;
B
Behdad Esfahbod 已提交
170
  hb_glyph_info_t *info = buffer->info;
B
Behdad Esfahbod 已提交
171
  for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
172 173 174 175
    if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) {
      unsigned int combining_class = _hb_glyph_info_get_modified_combining_class (&info[i]);
      combining_class = recategorize_combining_class (info[i].codepoint, combining_class);
      _hb_glyph_info_set_modified_combining_class (&info[i], combining_class);
B
Behdad Esfahbod 已提交
176 177 178 179 180 181 182 183 184
    }
}


static void
zero_mark_advances (hb_buffer_t *buffer,
		    unsigned int start,
		    unsigned int end)
{
B
Behdad Esfahbod 已提交
185
  hb_glyph_info_t *info = buffer->info;
B
Behdad Esfahbod 已提交
186
  for (unsigned int i = start; i < end; i++)
B
Behdad Esfahbod 已提交
187
    if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
B
Behdad Esfahbod 已提交
188 189 190 191 192 193
    {
      buffer->pos[i].x_advance = 0;
      buffer->pos[i].y_advance = 0;
    }
}

194 195 196 197 198 199 200 201 202
static inline void
position_mark (const hb_ot_shape_plan_t *plan,
	       hb_font_t *font,
	       hb_buffer_t  *buffer,
	       hb_glyph_extents_t &base_extents,
	       unsigned int i,
	       unsigned int combining_class)
{
  hb_glyph_extents_t mark_extents;
203
  if (!font->get_glyph_extents (buffer->info[i].codepoint, &mark_extents))
204 205 206 207 208 209 210 211
    return;

  hb_position_t y_gap = font->y_scale / 16;

  hb_glyph_position_t &pos = buffer->pos[i];
  pos.x_offset = pos.y_offset = 0;


U
Unknown 已提交
212
  /* We don't position LEFT and RIGHT marks. */
213 214 215 216 217 218

  /* X positioning */
  switch (combining_class)
  {
    case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW:
    case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
219
      if (buffer->props.direction == HB_DIRECTION_LTR) {
220
	pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width / 2 - mark_extents.x_bearing;
221 222
        break;
      } else if (buffer->props.direction == HB_DIRECTION_RTL) {
223
	pos.x_offset += base_extents.x_bearing - mark_extents.width / 2 - mark_extents.x_bearing;
224 225
        break;
      }
B
Behdad Esfahbod 已提交
226
      HB_FALLTHROUGH;
227

228
    default:
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
    case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
    case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
    case HB_UNICODE_COMBINING_CLASS_BELOW:
    case HB_UNICODE_COMBINING_CLASS_ABOVE:
      /* Center align. */
      pos.x_offset += base_extents.x_bearing + (base_extents.width - mark_extents.width) / 2 - mark_extents.x_bearing;
      break;

    case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT:
    case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT:
    case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT:
      /* Left align. */
      pos.x_offset += base_extents.x_bearing - mark_extents.x_bearing;
      break;

    case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
    case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT:
    case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT:
      /* Right align. */
      pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width - mark_extents.x_bearing;
      break;
  }

  /* Y positioning */
  switch (combining_class)
  {
    case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW:
    case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT:
    case HB_UNICODE_COMBINING_CLASS_BELOW:
    case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT:
      /* Add gap, fall-through. */
      base_extents.height -= y_gap;
B
Behdad Esfahbod 已提交
261
      HB_FALLTHROUGH;
262 263 264

    case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT:
    case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
B
Minor  
Behdad Esfahbod 已提交
265
      pos.y_offset = base_extents.y_bearing + base_extents.height - mark_extents.y_bearing;
266
      /* Never shift up "below" marks. */
267 268 269 270 271
      if ((y_gap > 0) == (pos.y_offset > 0))
      {
	base_extents.height -= pos.y_offset;
	pos.y_offset = 0;
      }
272 273 274 275 276 277 278 279 280 281
      base_extents.height += mark_extents.height;
      break;

    case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
    case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT:
    case HB_UNICODE_COMBINING_CLASS_ABOVE:
    case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT:
      /* Add gap, fall-through. */
      base_extents.y_bearing += y_gap;
      base_extents.height -= y_gap;
B
Behdad Esfahbod 已提交
282
      HB_FALLTHROUGH;
283 284 285

    case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
    case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
B
Minor  
Behdad Esfahbod 已提交
286
      pos.y_offset = base_extents.y_bearing - (mark_extents.y_bearing + mark_extents.height);
287 288 289 290 291 292 293 294
      /* Don't shift down "above" marks too much. */
      if ((y_gap > 0) != (pos.y_offset > 0))
      {
	unsigned int correction = -pos.y_offset / 2;
	base_extents.y_bearing += correction;
	base_extents.height -= correction;
	pos.y_offset += correction;
      }
295 296 297 298 299 300 301 302 303 304 305 306 307
      base_extents.y_bearing -= mark_extents.height;
      base_extents.height += mark_extents.height;
      break;
  }
}

static inline void
position_around_base (const hb_ot_shape_plan_t *plan,
		      hb_font_t *font,
		      hb_buffer_t  *buffer,
		      unsigned int base,
		      unsigned int end)
{
308
  hb_direction_t horiz_dir = HB_DIRECTION_INVALID;
309 310 311

  buffer->unsafe_to_break (base, end);

312
  hb_glyph_extents_t base_extents;
B
Behdad Esfahbod 已提交
313 314
  if (!font->get_glyph_extents (buffer->info[base].codepoint,
				&base_extents))
315 316 317 318 319 320 321 322
  {
    /* If extents don't work, zero marks and go home. */
    zero_mark_advances (buffer, base + 1, end);
    return;
  }
  base_extents.x_bearing += buffer->pos[base].x_offset;
  base_extents.y_bearing += buffer->pos[base].y_offset;

B
Behdad Esfahbod 已提交
323
  unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[base]);
324 325 326
  /* Use integer for num_lig_components such that it doesn't convert to unsigned
   * when we divide or multiply by it. */
  int num_lig_components = _hb_glyph_info_get_lig_num_comps (&buffer->info[base]);
327 328

  hb_position_t x_offset = 0, y_offset = 0;
329 330 331 332
  if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
    x_offset -= buffer->pos[base].x_advance;
    y_offset -= buffer->pos[base].y_advance;
  }
333 334

  hb_glyph_extents_t component_extents = base_extents;
335
  int last_lig_component = -1;
336
  unsigned int last_combining_class = 255;
B
Minor  
Behdad Esfahbod 已提交
337
  hb_glyph_extents_t cluster_extents = base_extents; /* Initialization is just to shut gcc up. */
B
Behdad Esfahbod 已提交
338
  hb_glyph_info_t *info = buffer->info;
339
  for (unsigned int i = base + 1; i < end; i++)
B
Behdad Esfahbod 已提交
340
    if (_hb_glyph_info_get_modified_combining_class (&info[i]))
341
    {
342
      if (num_lig_components > 1) {
B
Behdad Esfahbod 已提交
343
	unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&info[i]);
344
	int this_lig_component = _hb_glyph_info_get_lig_comp (&info[i]) - 1;
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
	/* Conditions for attaching to the last component. */
	if (!lig_id || lig_id != this_lig_id || this_lig_component >= num_lig_components)
	  this_lig_component = num_lig_components - 1;
	if (last_lig_component != this_lig_component)
	{
	  last_lig_component = this_lig_component;
	  last_combining_class = 255;
	  component_extents = base_extents;
	  if (unlikely (horiz_dir == HB_DIRECTION_INVALID)) {
	    if (HB_DIRECTION_IS_HORIZONTAL (plan->props.direction))
	      horiz_dir = plan->props.direction;
	    else
	      horiz_dir = hb_script_get_horizontal_direction (plan->props.script);
	  }
	  if (horiz_dir == HB_DIRECTION_LTR)
	    component_extents.x_bearing += (this_lig_component * component_extents.width) / num_lig_components;
	  else
	    component_extents.x_bearing += ((num_lig_components - 1 - this_lig_component) * component_extents.width) / num_lig_components;
	  component_extents.width /= num_lig_components;
	}
      }

B
Behdad Esfahbod 已提交
367
      unsigned int this_combining_class = _hb_glyph_info_get_modified_combining_class (&info[i]);
368 369 370 371 372
      if (last_combining_class != this_combining_class)
      {
	last_combining_class = this_combining_class;
        cluster_extents = component_extents;
      }
373

B
Minor  
Behdad Esfahbod 已提交
374
      position_mark (plan, font, buffer, cluster_extents, i, this_combining_class);
375 376 377 378 379 380 381

      buffer->pos[i].x_advance = 0;
      buffer->pos[i].y_advance = 0;
      buffer->pos[i].x_offset += x_offset;
      buffer->pos[i].y_offset += y_offset;

    } else {
382 383 384 385 386 387 388
      if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
	x_offset -= buffer->pos[i].x_advance;
	y_offset -= buffer->pos[i].y_advance;
      } else {
	x_offset += buffer->pos[i].x_advance;
	y_offset += buffer->pos[i].y_advance;
      }
389 390 391 392 393 394 395 396 397 398 399 400 401 402
    }
}

static inline void
position_cluster (const hb_ot_shape_plan_t *plan,
		  hb_font_t *font,
		  hb_buffer_t  *buffer,
		  unsigned int start,
		  unsigned int end)
{
  if (end - start < 2)
    return;

  /* Find the base glyph */
B
Behdad Esfahbod 已提交
403
  hb_glyph_info_t *info = buffer->info;
404
  for (unsigned int i = start; i < end; i++)
B
Behdad Esfahbod 已提交
405
    if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))
406
    {
407 408 409
      /* Find mark glyphs */
      unsigned int j;
      for (j = i + 1; j < end; j++)
B
Behdad Esfahbod 已提交
410
	if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[j])))
411 412 413 414 415
	  break;

      position_around_base (plan, font, buffer, i, j);

      i = j - 1;
416 417 418
    }
}

419
void
B
Behdad Esfahbod 已提交
420
_hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan,
421 422 423
				hb_font_t *font,
				hb_buffer_t  *buffer)
{
424 425
  _hb_buffer_assert_gsubgpos_vars (buffer);

426 427
  unsigned int start = 0;
  unsigned int count = buffer->len;
428
  hb_glyph_info_t *info = buffer->info;
429
  for (unsigned int i = 1; i < count; i++)
430
    if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))) {
431 432 433 434
      position_cluster (plan, font, buffer, start, i);
      start = i;
    }
  position_cluster (plan, font, buffer, start, count);
435
}
B
Behdad Esfahbod 已提交
436 437 438 439 440 441 442 443


/* Performs old-style TrueType kerning. */
void
_hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
			    hb_font_t *font,
			    hb_buffer_t  *buffer)
{
444
  if (!plan->has_kern) return;
B
Behdad Esfahbod 已提交
445

446
  OT::hb_ot_apply_context_t c (1, font, buffer);
447
  c.set_lookup_mask (plan->kern_mask);
448
  c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
449
  OT::hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input;
450
  skippy_iter.init (&c);
B
Behdad Esfahbod 已提交
451

B
Behdad Esfahbod 已提交
452
  unsigned int count = buffer->len;
B
Behdad Esfahbod 已提交
453 454 455
  hb_glyph_info_t *info = buffer->info;
  hb_glyph_position_t *pos = buffer->pos;
  for (unsigned int idx = 0; idx < count;)
B
Behdad Esfahbod 已提交
456
  {
457
    skippy_iter.reset (idx, 1);
458
    if (!skippy_iter.next ())
B
Behdad Esfahbod 已提交
459
    {
B
Behdad Esfahbod 已提交
460
      idx++;
461
      continue;
B
Behdad Esfahbod 已提交
462
    }
463

B
Behdad Esfahbod 已提交
464 465 466
    hb_position_t x_kern, y_kern;
    font->get_glyph_kerning_for_direction (info[idx].codepoint,
					   info[skippy_iter.idx].codepoint,
467 468 469
					   buffer->props.direction,
					   &x_kern, &y_kern);

B
Behdad Esfahbod 已提交
470 471 472 473 474 475 476
    if (x_kern)
    {
      hb_position_t kern1 = x_kern >> 1;
      hb_position_t kern2 = x_kern - kern1;
      pos[idx].x_advance += kern1;
      pos[skippy_iter.idx].x_advance += kern2;
      pos[skippy_iter.idx].x_offset += kern2;
B
Behdad Esfahbod 已提交
477
      buffer->unsafe_to_break (idx, skippy_iter.idx + 1);
B
Behdad Esfahbod 已提交
478
    }
479

B
Behdad Esfahbod 已提交
480 481 482 483 484 485 486
    if (y_kern)
    {
      hb_position_t kern1 = y_kern >> 1;
      hb_position_t kern2 = y_kern - kern1;
      pos[idx].y_advance += kern1;
      pos[skippy_iter.idx].y_advance += kern2;
      pos[skippy_iter.idx].y_offset += kern2;
B
Behdad Esfahbod 已提交
487
      buffer->unsafe_to_break (idx, skippy_iter.idx + 1);
B
Behdad Esfahbod 已提交
488
    }
489

B
Behdad Esfahbod 已提交
490
    idx = skippy_iter.idx;
B
Behdad Esfahbod 已提交
491 492
  }
}
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529


/* Adjusts width of various spaces. */
void
_hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
			      hb_font_t *font,
			      hb_buffer_t  *buffer)
{
  if (!HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
    return;

  hb_glyph_info_t *info = buffer->info;
  hb_glyph_position_t *pos = buffer->pos;
  unsigned int count = buffer->len;
  for (unsigned int i = 0; i < count; i++)
    if (_hb_glyph_info_is_unicode_space (&info[i]) && !_hb_glyph_info_ligated (&info[i]))
    {
      hb_unicode_funcs_t::space_t space_type = _hb_glyph_info_get_unicode_space_fallback_type (&info[i]);
      hb_codepoint_t glyph;
      typedef hb_unicode_funcs_t t;
      switch (space_type)
      {
	case t::NOT_SPACE: /* Shouldn't happen. */
	case t::SPACE:
	  break;

	case t::SPACE_EM:
	case t::SPACE_EM_2:
	case t::SPACE_EM_3:
	case t::SPACE_EM_4:
	case t::SPACE_EM_5:
	case t::SPACE_EM_6:
	case t::SPACE_EM_16:
	  pos[i].x_advance = (font->x_scale + ((int) space_type)/2) / (int) space_type;
	  break;

	case t::SPACE_4_EM_18:
530
	  pos[i].x_advance = (int64_t) font->x_scale * 4 / 18;
531 532 533 534
	  break;

	case t::SPACE_FIGURE:
	  for (char u = '0'; u <= '9'; u++)
535
	    if (font->get_nominal_glyph (u, &glyph))
536 537 538 539 540 541 542
	    {
	      pos[i].x_advance = font->get_glyph_h_advance (glyph);
	      break;
	    }
	  break;

	case t::SPACE_PUNCTUATION:
543
	  if (font->get_nominal_glyph ('.', &glyph))
544
	    pos[i].x_advance = font->get_glyph_h_advance (glyph);
545
	  else if (font->get_nominal_glyph (',', &glyph))
546 547 548 549 550
	    pos[i].x_advance = font->get_glyph_h_advance (glyph);
	  break;

	case t::SPACE_NARROW:
	  /* Half-space?
551
	   * Unicode doc https://unicode.org/charts/PDF/U2000.pdf says ~1/4 or 1/5 of EM.
552 553 554 555 556 557 558 559
	   * However, in my testing, many fonts have their regular space being about that
	   * size.  To me, a percentage of the space width makes more sense.  Half is as
	   * good as any. */
	  pos[i].x_advance /= 2;
	  break;
      }
    }
}