OLD | NEW |
1 /* | 1 /* |
2 * Copyright © 2009,2010 Red Hat, Inc. | 2 * Copyright © 2009,2010 Red Hat, Inc. |
3 * Copyright © 2010,2011,2012 Google, Inc. | 3 * Copyright © 2010,2011,2012 Google, Inc. |
4 * | 4 * |
5 * This is part of HarfBuzz, a text shaping library. | 5 * This is part of HarfBuzz, a text shaping library. |
6 * | 6 * |
7 * Permission is hereby granted, without written agreement and without | 7 * Permission is hereby granted, without written agreement and without |
8 * license or royalty fees, to use, copy, modify, and distribute this | 8 * license or royalty fees, to use, copy, modify, and distribute this |
9 * software and its documentation for any purpose, provided that the | 9 * software and its documentation for any purpose, provided that the |
10 * above copyright notice and the following two paragraphs appear in | 10 * above copyright notice and the following two paragraphs appear in |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 static void | 76 static void |
77 hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, | 77 hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, |
78 const hb_segment_properties_t *props, | 78 const hb_segment_properties_t *props, |
79 const hb_feature_t *user_features, | 79 const hb_feature_t *user_features, |
80 unsigned int num_user_features) | 80 unsigned int num_user_features) |
81 { | 81 { |
82 hb_ot_map_builder_t *map = &planner->map; | 82 hb_ot_map_builder_t *map = &planner->map; |
83 | 83 |
84 switch (props->direction) { | 84 switch (props->direction) { |
85 case HB_DIRECTION_LTR: | 85 case HB_DIRECTION_LTR: |
86 map->add_bool_feature (HB_TAG ('l','t','r','a')); | 86 map->add_global_bool_feature (HB_TAG ('l','t','r','a')); |
87 map->add_bool_feature (HB_TAG ('l','t','r','m')); | 87 map->add_global_bool_feature (HB_TAG ('l','t','r','m')); |
88 break; | 88 break; |
89 case HB_DIRECTION_RTL: | 89 case HB_DIRECTION_RTL: |
90 map->add_bool_feature (HB_TAG ('r','t','l','a')); | 90 map->add_global_bool_feature (HB_TAG ('r','t','l','a')); |
91 map->add_bool_feature (HB_TAG ('r','t','l','m'), false); | 91 map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE); |
92 break; | 92 break; |
93 case HB_DIRECTION_TTB: | 93 case HB_DIRECTION_TTB: |
94 case HB_DIRECTION_BTT: | 94 case HB_DIRECTION_BTT: |
95 case HB_DIRECTION_INVALID: | 95 case HB_DIRECTION_INVALID: |
96 default: | 96 default: |
97 break; | 97 break; |
98 } | 98 } |
99 | 99 |
100 #define ADD_FEATURES(array) \ | |
101 HB_STMT_START { \ | |
102 for (unsigned int i = 0; i < ARRAY_LENGTH (array); i++) \ | |
103 map->add_bool_feature (array[i]); \ | |
104 } HB_STMT_END | |
105 | |
106 if (planner->shaper->collect_features) | 100 if (planner->shaper->collect_features) |
107 planner->shaper->collect_features (planner); | 101 planner->shaper->collect_features (planner); |
108 | 102 |
109 ADD_FEATURES (common_features); | 103 for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++) |
| 104 map->add_global_bool_feature (common_features[i]); |
110 | 105 |
111 if (HB_DIRECTION_IS_HORIZONTAL (props->direction)) | 106 if (HB_DIRECTION_IS_HORIZONTAL (props->direction)) |
112 ADD_FEATURES (horizontal_features); | 107 for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++) |
| 108 map->add_feature (horizontal_features[i], 1, F_GLOBAL | |
| 109 » » » (horizontal_features[i] == HB_TAG('k','e','r','n') ? |
| 110 » » » F_HAS_FALLBACK : F_NONE)); |
113 else | 111 else |
114 ADD_FEATURES (vertical_features); | 112 for (unsigned int i = 0; i < ARRAY_LENGTH (vertical_features); i++) |
| 113 map->add_feature (vertical_features[i], 1, F_GLOBAL | |
| 114 » » » (vertical_features[i] == HB_TAG('v','k','r','n') ? |
| 115 » » » F_HAS_FALLBACK : F_NONE)); |
115 | 116 |
116 if (planner->shaper->override_features) | 117 if (planner->shaper->override_features) |
117 planner->shaper->override_features (planner); | 118 planner->shaper->override_features (planner); |
118 | 119 |
119 #undef ADD_FEATURES | |
120 | |
121 for (unsigned int i = 0; i < num_user_features; i++) { | 120 for (unsigned int i = 0; i < num_user_features; i++) { |
122 const hb_feature_t *feature = &user_features[i]; | 121 const hb_feature_t *feature = &user_features[i]; |
123 map->add_feature (feature->tag, feature->value, (feature->start == 0 && feat
ure->end == (unsigned int) -1)); | 122 map->add_feature (feature->tag, feature->value, |
| 123 » » (feature->start == 0 && feature->end == (unsigned int) -1)
? |
| 124 » » F_GLOBAL : F_NONE); |
124 } | 125 } |
125 } | 126 } |
126 | 127 |
127 | 128 |
128 /* | 129 /* |
129 * shaper face data | 130 * shaper face data |
130 */ | 131 */ |
131 | 132 |
132 hb_ot_shaper_face_data_t * | 133 hb_ot_shaper_face_data_t * |
133 _hb_ot_shaper_face_data_create (hb_face_t *face) | 134 _hb_ot_shaper_face_data_create (hb_face_t *face) |
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
398 } | 399 } |
399 | 400 |
400 /* Position */ | 401 /* Position */ |
401 | 402 |
402 static inline void | 403 static inline void |
403 hb_ot_position_default (hb_ot_shape_context_t *c) | 404 hb_ot_position_default (hb_ot_shape_context_t *c) |
404 { | 405 { |
405 hb_ot_layout_position_start (c->font, c->buffer); | 406 hb_ot_layout_position_start (c->font, c->buffer); |
406 | 407 |
407 unsigned int count = c->buffer->len; | 408 unsigned int count = c->buffer->len; |
408 for (unsigned int i = 0; i < count; i++) { | 409 for (unsigned int i = 0; i < count; i++) |
| 410 { |
409 c->font->get_glyph_advance_for_direction (c->buffer->info[i].codepoint, | 411 c->font->get_glyph_advance_for_direction (c->buffer->info[i].codepoint, |
410 c->buffer->props.direction, | 412 c->buffer->props.direction, |
411 &c->buffer->pos[i].x_advance, | 413 &c->buffer->pos[i].x_advance, |
412 &c->buffer->pos[i].y_advance); | 414 &c->buffer->pos[i].y_advance); |
413 c->font->subtract_glyph_origin_for_direction (c->buffer->info[i].codepoint, | 415 c->font->subtract_glyph_origin_for_direction (c->buffer->info[i].codepoint, |
414 c->buffer->props.direction, | 416 c->buffer->props.direction, |
415 &c->buffer->pos[i].x_offset, | 417 &c->buffer->pos[i].x_offset, |
416 &c->buffer->pos[i].y_offset); | 418 &c->buffer->pos[i].y_offset); |
| 419 |
| 420 } |
| 421 |
| 422 /* Zero'ing mark widths by GDEF (as used in Myanmar spec) happens |
| 423 * *before* GPOS. */ |
| 424 switch (c->plan->shaper->zero_width_marks) |
| 425 { |
| 426 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF: |
| 427 for (unsigned int i = 0; i < count; i++) |
| 428 if ((c->buffer->info[i].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) |
| 429 { |
| 430 c->buffer->pos[i].x_advance = 0; |
| 431 c->buffer->pos[i].y_advance = 0; |
| 432 } |
| 433 break; |
| 434 |
| 435 default: |
| 436 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: |
| 437 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE: |
| 438 break; |
417 } | 439 } |
418 } | 440 } |
419 | 441 |
420 static inline bool | 442 static inline bool |
421 hb_ot_position_complex (hb_ot_shape_context_t *c) | 443 hb_ot_position_complex (hb_ot_shape_context_t *c) |
422 { | 444 { |
423 bool ret = false; | 445 bool ret = false; |
| 446 unsigned int count = c->buffer->len; |
424 | 447 |
425 if (hb_ot_layout_has_positioning (c->face)) | 448 if (hb_ot_layout_has_positioning (c->face)) |
426 { | 449 { |
427 /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */ | 450 /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */ |
428 | 451 |
429 unsigned int count = c->buffer->len; | |
430 for (unsigned int i = 0; i < count; i++) { | 452 for (unsigned int i = 0; i < count; i++) { |
431 c->font->add_glyph_origin_for_direction (c->buffer->info[i].codepoint, | 453 c->font->add_glyph_origin_for_direction (c->buffer->info[i].codepoint, |
432 HB_DIRECTION_LTR, | 454 HB_DIRECTION_LTR, |
433 &c->buffer->pos[i].x_offset, | 455 &c->buffer->pos[i].x_offset, |
434 &c->buffer->pos[i].y_offset); | 456 &c->buffer->pos[i].y_offset); |
435 } | 457 } |
436 | 458 |
437 c->plan->position (c->font, c->buffer); | 459 c->plan->position (c->font, c->buffer); |
438 | 460 |
439 for (unsigned int i = 0; i < count; i++) { | 461 for (unsigned int i = 0; i < count; i++) { |
440 c->font->subtract_glyph_origin_for_direction (c->buffer->info[i].codepoint
, | 462 c->font->subtract_glyph_origin_for_direction (c->buffer->info[i].codepoint
, |
441 HB_DIRECTION_LTR, | 463 HB_DIRECTION_LTR, |
442 &c->buffer->pos[i].x_offset, | 464 &c->buffer->pos[i].x_offset, |
443 &c->buffer->pos[i].y_offset)
; | 465 &c->buffer->pos[i].y_offset)
; |
444 } | 466 } |
445 | 467 |
446 ret = true; | 468 ret = true; |
447 } | 469 } |
448 | 470 |
449 hb_ot_layout_position_finish (c->font, c->buffer, c->plan->shaper->zero_width_
attached_marks); | 471 /* Zero'ing mark widths by Unicode happens |
| 472 * *after* GPOS. */ |
| 473 switch (c->plan->shaper->zero_width_marks) |
| 474 { |
| 475 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE: |
| 476 for (unsigned int i = 0; i < count; i++) |
| 477 » if (_hb_glyph_info_get_general_category (&c->buffer->info[i]) == HB_UNIC
ODE_GENERAL_CATEGORY_NON_SPACING_MARK) |
| 478 » { |
| 479 » c->buffer->pos[i].x_advance = 0; |
| 480 » c->buffer->pos[i].y_advance = 0; |
| 481 » } |
| 482 break; |
| 483 |
| 484 default: |
| 485 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: |
| 486 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF: |
| 487 break; |
| 488 } |
| 489 |
| 490 hb_ot_layout_position_finish (c->font, c->buffer); |
450 | 491 |
451 return ret; | 492 return ret; |
452 } | 493 } |
453 | 494 |
454 static inline void | 495 static inline void |
455 hb_ot_truetype_kern (hb_ot_shape_context_t *c) | |
456 { | |
457 /* TODO Check for kern=0 */ | |
458 unsigned int count = c->buffer->len; | |
459 for (unsigned int i = 1; i < count; i++) { | |
460 hb_position_t x_kern, y_kern, kern1, kern2; | |
461 c->font->get_glyph_kerning_for_direction (c->buffer->info[i - 1].codepoint,
c->buffer->info[i].codepoint, | |
462 c->buffer->props.direction, | |
463 &x_kern, &y_kern); | |
464 | |
465 kern1 = x_kern >> 1; | |
466 kern2 = x_kern - kern1; | |
467 c->buffer->pos[i - 1].x_advance += kern1; | |
468 c->buffer->pos[i].x_advance += kern2; | |
469 c->buffer->pos[i].x_offset += kern2; | |
470 | |
471 kern1 = y_kern >> 1; | |
472 kern2 = y_kern - kern1; | |
473 c->buffer->pos[i - 1].y_advance += kern1; | |
474 c->buffer->pos[i].y_advance += kern2; | |
475 c->buffer->pos[i].y_offset += kern2; | |
476 } | |
477 } | |
478 | |
479 static inline void | |
480 hb_ot_position (hb_ot_shape_context_t *c) | 496 hb_ot_position (hb_ot_shape_context_t *c) |
481 { | 497 { |
482 hb_ot_position_default (c); | 498 hb_ot_position_default (c); |
483 | 499 |
484 hb_bool_t fallback = !hb_ot_position_complex (c); | 500 hb_bool_t fallback = !hb_ot_position_complex (c); |
485 | 501 |
486 if (fallback && c->plan->shaper->fallback_position) | 502 if (fallback && c->plan->shaper->fallback_position) |
487 _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer); | 503 _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer); |
488 | 504 |
489 if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)) | 505 if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)) |
490 hb_buffer_reverse (c->buffer); | 506 hb_buffer_reverse (c->buffer); |
491 | 507 |
492 /* Visual fallback goes here. */ | 508 /* Visual fallback goes here. */ |
493 | 509 |
494 if (fallback) | 510 if (fallback) |
495 hb_ot_truetype_kern (c); | 511 _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer); |
496 } | 512 } |
497 | 513 |
498 | 514 |
499 /* Post-process */ | 515 /* Post-process */ |
500 | 516 |
501 static void | 517 static void |
502 hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c) | 518 hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c) |
503 { | 519 { |
504 if (c->buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES) | 520 if (c->buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES) |
505 return; | 521 return; |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
604 | 620 |
605 void | 621 void |
606 hb_ot_shape_glyphs_closure (hb_font_t *font, | 622 hb_ot_shape_glyphs_closure (hb_font_t *font, |
607 hb_buffer_t *buffer, | 623 hb_buffer_t *buffer, |
608 const hb_feature_t *features, | 624 const hb_feature_t *features, |
609 unsigned int num_features, | 625 unsigned int num_features, |
610 hb_set_t *glyphs) | 626 hb_set_t *glyphs) |
611 { | 627 { |
612 hb_ot_shape_plan_t plan; | 628 hb_ot_shape_plan_t plan; |
613 | 629 |
614 buffer->guess_segment_properties (); | |
615 | |
616 const char *shapers[] = {"ot", NULL}; | 630 const char *shapers[] = {"ot", NULL}; |
617 hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer
->props, | 631 hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer
->props, |
618 features, num_featu
res, shapers); | 632 features, num_featu
res, shapers); |
619 | 633 |
620 bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_
DIRECTION_RTL; | 634 bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_
DIRECTION_RTL; |
621 | 635 |
622 unsigned int count = buffer->len; | 636 unsigned int count = buffer->len; |
623 for (unsigned int i = 0; i < count; i++) | 637 for (unsigned int i = 0; i < count; i++) |
624 add_char (font, buffer->unicode, mirror, buffer->info[i].codepoint, glyphs); | 638 add_char (font, buffer->unicode, mirror, buffer->info[i].codepoint, glyphs); |
625 | 639 |
626 hb_set_t lookups; | 640 hb_set_t lookups; |
627 lookups.init (); | 641 lookups.init (); |
628 hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups); | 642 hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups); |
629 | 643 |
630 /* And find transitive closure. */ | 644 /* And find transitive closure. */ |
631 hb_set_t copy; | 645 hb_set_t copy; |
632 copy.init (); | 646 copy.init (); |
633 do { | 647 do { |
634 copy.set (glyphs); | 648 copy.set (glyphs); |
635 for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index)
;) | 649 for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index)
;) |
636 hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs); | 650 hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs); |
637 } while (!copy.is_equal (glyphs)); | 651 } while (!copy.is_equal (glyphs)); |
638 | 652 |
639 hb_shape_plan_destroy (shape_plan); | 653 hb_shape_plan_destroy (shape_plan); |
640 } | 654 } |
OLD | NEW |