| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright © 2010,2012 Google, Inc. | 2 * Copyright © 2010,2012 Google, Inc. |
| 3 * | 3 * |
| 4 * This is part of HarfBuzz, a text shaping library. | 4 * This is part of HarfBuzz, a text shaping library. |
| 5 * | 5 * |
| 6 * Permission is hereby granted, without written agreement and without | 6 * Permission is hereby granted, without written agreement and without |
| 7 * license or royalty fees, to use, copy, modify, and distribute this | 7 * license or royalty fees, to use, copy, modify, and distribute this |
| 8 * software and its documentation for any purpose, provided that the | 8 * software and its documentation for any purpose, provided that the |
| 9 * above copyright notice and the following two paragraphs appear in | 9 * above copyright notice and the following two paragraphs appear in |
| 10 * all copies of this software. | 10 * all copies of this software. |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 216 bool has_fallback = plan->props.script == HB_SCRIPT_ARABIC && !FEATURE_IS_SY
RIAC (arabic_features[i]); | 216 bool has_fallback = plan->props.script == HB_SCRIPT_ARABIC && !FEATURE_IS_SY
RIAC (arabic_features[i]); |
| 217 map->add_feature (arabic_features[i], 1, has_fallback ? F_HAS_FALLBACK : F_N
ONE); | 217 map->add_feature (arabic_features[i], 1, has_fallback ? F_HAS_FALLBACK : F_N
ONE); |
| 218 map->add_gsub_pause (NULL); | 218 map->add_gsub_pause (NULL); |
| 219 } | 219 } |
| 220 | 220 |
| 221 map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK); | 221 map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK); |
| 222 if (plan->props.script == HB_SCRIPT_ARABIC) | 222 if (plan->props.script == HB_SCRIPT_ARABIC) |
| 223 map->add_gsub_pause (arabic_fallback_shape); | 223 map->add_gsub_pause (arabic_fallback_shape); |
| 224 | 224 |
| 225 map->add_global_bool_feature (HB_TAG('c','a','l','t')); | 225 map->add_global_bool_feature (HB_TAG('c','a','l','t')); |
| 226 map->add_gsub_pause (NULL); | |
| 227 | 226 |
| 228 /* The spec includes 'cswh'. Earlier versions of Windows | 227 /* The spec includes 'cswh'. Earlier versions of Windows |
| 229 * used to enable this by default, but testing suggests | 228 * used to enable this by default, but testing suggests |
| 230 * that Windows 8 and later do not enable it by default, | 229 * that Windows 8 and later do not enable it by default, |
| 231 * and spec now says 'Off by default'. | 230 * and spec now says 'Off by default'. |
| 232 * We disabled this in ae23c24c32. | 231 * We disabled this in ae23c24c32. |
| 233 * Note that IranNastaliq uses this feature extensively | 232 * Note that IranNastaliq uses this feature extensively |
| 234 * to fixup broken glyph sequences. Oh well... | 233 * to fixup broken glyph sequences. Oh well... |
| 235 * Test case: U+0643,U+0640,U+0631. */ | 234 * Test case: U+0643,U+0640,U+0631. */ |
| 235 //map->add_gsub_pause (NULL); |
| 236 //map->add_global_bool_feature (HB_TAG('c','s','w','h')); | 236 //map->add_global_bool_feature (HB_TAG('c','s','w','h')); |
| 237 map->add_global_bool_feature (HB_TAG('m','s','e','t')); | 237 map->add_global_bool_feature (HB_TAG('m','s','e','t')); |
| 238 } | 238 } |
| 239 | 239 |
| 240 #include "hb-ot-shape-complex-arabic-fallback.hh" | 240 #include "hb-ot-shape-complex-arabic-fallback.hh" |
| 241 | 241 |
| 242 struct arabic_shape_plan_t | 242 struct arabic_shape_plan_t |
| 243 { | 243 { |
| 244 ASSERT_POD (); | 244 ASSERT_POD (); |
| 245 | 245 |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 456 | 456 |
| 457 /* The Arabic shaper currently always processes in RTL mode, so we should | 457 /* The Arabic shaper currently always processes in RTL mode, so we should |
| 458 * stretch / position the stretched pieces to the left / preceding glyphs. */ | 458 * stretch / position the stretched pieces to the left / preceding glyphs. */ |
| 459 | 459 |
| 460 /* We do a two pass implementation: | 460 /* We do a two pass implementation: |
| 461 * First pass calculates the exact number of extra glyphs we need, | 461 * First pass calculates the exact number of extra glyphs we need, |
| 462 * We then enlarge buffer to have that much room, | 462 * We then enlarge buffer to have that much room, |
| 463 * Second pass applies the stretch, copying things to the end of buffer. | 463 * Second pass applies the stretch, copying things to the end of buffer. |
| 464 */ | 464 */ |
| 465 | 465 |
| 466 /* 30 = 2048 / 70. | |
| 467 * https://www.microsoft.com/typography/cursivescriptguidelines.mspx */ | |
| 468 hb_position_t overlap = font->x_scale / 30; | |
| 469 DEBUG_MSG (ARABIC, NULL, "overlap for stretching is %d", overlap); | |
| 470 int sign = font->x_scale < 0 ? -1 : +1; | 466 int sign = font->x_scale < 0 ? -1 : +1; |
| 471 unsigned int extra_glyphs_needed = 0; // Set during MEASURE, used during CUT | 467 unsigned int extra_glyphs_needed = 0; // Set during MEASURE, used during CUT |
| 472 typedef enum { MEASURE, CUT } step_t; | 468 typedef enum { MEASURE, CUT } step_t; |
| 473 | 469 |
| 474 for (step_t step = MEASURE; step <= CUT; step = (step_t) (step + 1)) | 470 for (step_t step = MEASURE; step <= CUT; step = (step_t) (step + 1)) |
| 475 { | 471 { |
| 476 unsigned int count = buffer->len; | 472 unsigned int count = buffer->len; |
| 477 hb_glyph_info_t *info = buffer->info; | 473 hb_glyph_info_t *info = buffer->info; |
| 478 hb_glyph_position_t *pos = buffer->pos; | 474 hb_glyph_position_t *pos = buffer->pos; |
| 479 unsigned int new_len = count + extra_glyphs_needed; // write head during CUT | 475 unsigned int new_len = count + extra_glyphs_needed; // write head during CUT |
| (...skipping 17 matching lines...) Expand all Loading... |
| 497 hb_position_t w_fixed = 0; // Sum of fixed tiles | 493 hb_position_t w_fixed = 0; // Sum of fixed tiles |
| 498 hb_position_t w_repeating = 0; // Sum of repeating tiles | 494 hb_position_t w_repeating = 0; // Sum of repeating tiles |
| 499 int n_fixed = 0; | 495 int n_fixed = 0; |
| 500 int n_repeating = 0; | 496 int n_repeating = 0; |
| 501 | 497 |
| 502 unsigned int end = i; | 498 unsigned int end = i; |
| 503 while (i && | 499 while (i && |
| 504 hb_in_range<unsigned> (info[i - 1].arabic_shaping_action(), STCH_FI
XED, STCH_REPEATING)) | 500 hb_in_range<unsigned> (info[i - 1].arabic_shaping_action(), STCH_FI
XED, STCH_REPEATING)) |
| 505 { | 501 { |
| 506 i--; | 502 i--; |
| 507 » hb_glyph_extents_t extents; | 503 » hb_position_t width = font->get_glyph_h_advance (info[i].codepoint); |
| 508 » if (!font->get_glyph_extents (info[i].codepoint, &extents)) | |
| 509 » extents.width = 0; | |
| 510 » extents.width -= overlap; | |
| 511 if (info[i].arabic_shaping_action() == STCH_FIXED) | 504 if (info[i].arabic_shaping_action() == STCH_FIXED) |
| 512 { | 505 { |
| 513 » w_fixed += extents.width; | 506 » w_fixed += width; |
| 514 n_fixed++; | 507 n_fixed++; |
| 515 } | 508 } |
| 516 else | 509 else |
| 517 { | 510 { |
| 518 » w_repeating += extents.width; | 511 » w_repeating += width; |
| 519 n_repeating++; | 512 n_repeating++; |
| 520 } | 513 } |
| 521 } | 514 } |
| 522 unsigned int start = i; | 515 unsigned int start = i; |
| 523 unsigned int context = i; | 516 unsigned int context = i; |
| 524 while (context && | 517 while (context && |
| 525 !hb_in_range<unsigned> (info[context - 1].arabic_shaping_action(),
STCH_FIXED, STCH_REPEATING) && | 518 !hb_in_range<unsigned> (info[context - 1].arabic_shaping_action(),
STCH_FIXED, STCH_REPEATING) && |
| 526 (_hb_glyph_info_is_default_ignorable (&info[context - 1]) || | 519 (_hb_glyph_info_is_default_ignorable (&info[context - 1]) || |
| 527 HB_ARABIC_GENERAL_CATEGORY_IS_WORD (_hb_glyph_info_get_general_cat
egory (&info[context - 1])))) | 520 HB_ARABIC_GENERAL_CATEGORY_IS_WORD (_hb_glyph_info_get_general_cat
egory (&info[context - 1])))) |
| 528 { | 521 { |
| 529 context--; | 522 context--; |
| 530 w_total += pos[context].x_advance; | 523 w_total += pos[context].x_advance; |
| 531 } | 524 } |
| 532 i++; // Don't touch i again. | 525 i++; // Don't touch i again. |
| 533 | 526 |
| 534 DEBUG_MSG (ARABIC, NULL, "%s stretch at (%d,%d,%d)", | 527 DEBUG_MSG (ARABIC, NULL, "%s stretch at (%d,%d,%d)", |
| 535 step == MEASURE ? "measuring" : "cutting", context, start, end)
; | 528 step == MEASURE ? "measuring" : "cutting", context, start, end)
; |
| 536 DEBUG_MSG (ARABIC, NULL, "rest of word: count=%d width %d", start - con
text, w_total); | 529 DEBUG_MSG (ARABIC, NULL, "rest of word: count=%d width %d", start - con
text, w_total); |
| 537 DEBUG_MSG (ARABIC, NULL, "fixed tiles: count=%d width=%d", n_fixed, w_
fixed); | 530 DEBUG_MSG (ARABIC, NULL, "fixed tiles: count=%d width=%d", n_fixed, w_
fixed); |
| 538 DEBUG_MSG (ARABIC, NULL, "repeating tiles: count=%d width=%d", n_repeating
, w_repeating); | 531 DEBUG_MSG (ARABIC, NULL, "repeating tiles: count=%d width=%d", n_repeating
, w_repeating); |
| 539 | 532 |
| 540 /* Number of additional times to repeat each repeating tile. */ | 533 /* Number of additional times to repeat each repeating tile. */ |
| 541 int n_copies = 0; | 534 int n_copies = 0; |
| 542 | 535 |
| 543 hb_position_t w_remaining = w_total - w_fixed - overlap; | 536 hb_position_t w_remaining = w_total - w_fixed; |
| 544 if (sign * w_remaining > sign * w_repeating && sign * w_repeating > 0) | 537 if (sign * w_remaining > sign * w_repeating && sign * w_repeating > 0) |
| 545 » n_copies = (sign * w_remaining + sign * w_repeating / 4) / (sign * w_rep
eating) - 1; | 538 » n_copies = (sign * w_remaining) / (sign * w_repeating) - 1; |
| 539 |
| 540 /* See if we can improve the fit by adding an extra repeat and squeezing t
hem together a bit. */ |
| 541 hb_position_t extra_repeat_overlap = 0; |
| 542 hb_position_t shortfall = sign * w_remaining - sign * w_repeating * (n_cop
ies + 1); |
| 543 if (shortfall > 0) |
| 544 { |
| 545 ++n_copies; |
| 546 hb_position_t excess = (n_copies + 1) * sign * w_repeating - sign * w_re
maining; |
| 547 if (excess > 0) |
| 548 extra_repeat_overlap = excess / (n_copies * n_repeating); |
| 549 } |
| 546 | 550 |
| 547 if (step == MEASURE) | 551 if (step == MEASURE) |
| 548 { | 552 { |
| 549 extra_glyphs_needed += n_copies * n_repeating; | 553 extra_glyphs_needed += n_copies * n_repeating; |
| 550 DEBUG_MSG (ARABIC, NULL, "will add extra %d copies of repeating tiles",
n_copies); | 554 DEBUG_MSG (ARABIC, NULL, "will add extra %d copies of repeating tiles",
n_copies); |
| 551 } | 555 } |
| 552 else | 556 else |
| 553 { | 557 { |
| 554 hb_position_t x_offset = -overlap; | 558 » hb_position_t x_offset = 0; |
| 555 for (unsigned int k = end; k > start; k--) | 559 for (unsigned int k = end; k > start; k--) |
| 556 { | 560 { |
| 557 » hb_glyph_extents_t extents; | 561 » hb_position_t width = font->get_glyph_h_advance (info[k - 1].codepoint
); |
| 558 » if (!font->get_glyph_extents (info[k - 1].codepoint, &extents)) | |
| 559 » extents.width = 0; | |
| 560 » extents.width -= overlap; | |
| 561 | 562 |
| 562 unsigned int repeat = 1; | 563 unsigned int repeat = 1; |
| 563 if (info[k - 1].arabic_shaping_action() == STCH_REPEATING) | 564 if (info[k - 1].arabic_shaping_action() == STCH_REPEATING) |
| 564 repeat += n_copies; | 565 repeat += n_copies; |
| 565 | 566 |
| 566 DEBUG_MSG (ARABIC, NULL, "appending %d copies of glyph %d; j=%d", | 567 DEBUG_MSG (ARABIC, NULL, "appending %d copies of glyph %d; j=%d", |
| 567 repeat, info[k - 1].codepoint, j); | 568 repeat, info[k - 1].codepoint, j); |
| 568 for (unsigned int n = 0; n < repeat; n++) | 569 for (unsigned int n = 0; n < repeat; n++) |
| 569 { | 570 { |
| 570 » x_offset -= extents.width; | 571 » x_offset -= width; |
| 572 » if (n > 0) |
| 573 » x_offset += extra_repeat_overlap; |
| 571 pos[k - 1].x_offset = x_offset; | 574 pos[k - 1].x_offset = x_offset; |
| 572 /* Append copy. */ | 575 /* Append copy. */ |
| 573 --j; | 576 --j; |
| 574 info[j] = info[k - 1]; | 577 info[j] = info[k - 1]; |
| 575 pos[j] = pos[k - 1]; | 578 pos[j] = pos[k - 1]; |
| 576 } | 579 } |
| 577 } | 580 } |
| 578 } | 581 } |
| 579 } | 582 } |
| 580 | 583 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 611 data_destroy_arabic, | 614 data_destroy_arabic, |
| 612 NULL, /* preprocess_text */ | 615 NULL, /* preprocess_text */ |
| 613 postprocess_glyphs_arabic, | 616 postprocess_glyphs_arabic, |
| 614 HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT, | 617 HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT, |
| 615 NULL, /* decompose */ | 618 NULL, /* decompose */ |
| 616 NULL, /* compose */ | 619 NULL, /* compose */ |
| 617 setup_masks_arabic, | 620 setup_masks_arabic, |
| 618 HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, | 621 HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, |
| 619 true, /* fallback_position */ | 622 true, /* fallback_position */ |
| 620 }; | 623 }; |
| OLD | NEW |