OLD | NEW |
1 /* | 1 /* |
2 * Copyright © 2012,2013 Mozilla Foundation. | 2 * Copyright © 2012,2013 Mozilla Foundation. |
3 * Copyright © 2012,2013 Google, Inc. | 3 * Copyright © 2012,2013 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 19 matching lines...) Expand all Loading... |
30 #include "hb-shaper-impl-private.hh" | 30 #include "hb-shaper-impl-private.hh" |
31 | 31 |
32 #include "hb-coretext.h" | 32 #include "hb-coretext.h" |
33 | 33 |
34 | 34 |
35 #ifndef HB_DEBUG_CORETEXT | 35 #ifndef HB_DEBUG_CORETEXT |
36 #define HB_DEBUG_CORETEXT (HB_DEBUG+0) | 36 #define HB_DEBUG_CORETEXT (HB_DEBUG+0) |
37 #endif | 37 #endif |
38 | 38 |
39 | 39 |
| 40 static void |
| 41 release_table_data (void *user_data) |
| 42 { |
| 43 CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data); |
| 44 CFRelease(cf_data); |
| 45 } |
| 46 |
| 47 static hb_blob_t * |
| 48 reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) |
| 49 { |
| 50 CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data); |
| 51 CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag); |
| 52 if (unlikely (!cf_data)) |
| 53 return NULL; |
| 54 |
| 55 const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data)); |
| 56 const size_t length = CFDataGetLength (cf_data); |
| 57 if (!data || !length) |
| 58 return NULL; |
| 59 |
| 60 return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY, |
| 61 reinterpret_cast<void *> (const_cast<__CFData *> (cf_da
ta)), |
| 62 release_table_data); |
| 63 } |
| 64 |
| 65 hb_face_t * |
| 66 hb_coretext_face_create (CGFontRef cg_font) |
| 67 { |
| 68 return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), (hb
_destroy_func_t) CGFontRelease); |
| 69 } |
| 70 |
| 71 |
40 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face) | 72 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face) |
41 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font) | 73 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font) |
42 | 74 |
43 | 75 |
44 /* | 76 /* |
45 * shaper face data | 77 * shaper face data |
46 */ | 78 */ |
47 | 79 |
48 struct hb_coretext_shaper_face_data_t { | 80 struct hb_coretext_shaper_face_data_t { |
49 CGFontRef cg_font; | 81 CGFontRef cg_font; |
50 }; | 82 }; |
51 | 83 |
52 static void | 84 static void |
53 release_data (void *info, const void *data, size_t size) | 85 release_data (void *info, const void *data, size_t size) |
54 { | 86 { |
55 assert (hb_blob_get_length ((hb_blob_t *) info) == size && | 87 assert (hb_blob_get_length ((hb_blob_t *) info) == size && |
56 hb_blob_get_data ((hb_blob_t *) info, NULL) == data); | 88 hb_blob_get_data ((hb_blob_t *) info, NULL) == data); |
57 | 89 |
58 hb_blob_destroy ((hb_blob_t *) info); | 90 hb_blob_destroy ((hb_blob_t *) info); |
59 } | 91 } |
60 | 92 |
61 hb_coretext_shaper_face_data_t * | 93 hb_coretext_shaper_face_data_t * |
62 _hb_coretext_shaper_face_data_create (hb_face_t *face) | 94 _hb_coretext_shaper_face_data_create (hb_face_t *face) |
63 { | 95 { |
64 hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) call
oc (1, sizeof (hb_coretext_shaper_face_data_t)); | 96 hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) call
oc (1, sizeof (hb_coretext_shaper_face_data_t)); |
65 if (unlikely (!data)) | 97 if (unlikely (!data)) |
66 return NULL; | 98 return NULL; |
67 | 99 |
68 hb_blob_t *blob = hb_face_reference_blob (face); | 100 if (face->destroy == (hb_destroy_func_t) CGFontRelease) |
69 unsigned int blob_length; | 101 { |
70 const char *blob_data = hb_blob_get_data (blob, &blob_length); | 102 data->cg_font = CGFontRetain ((CGFontRef) face->user_data); |
71 if (unlikely (!blob_length)) | 103 } |
72 DEBUG_MSG (CORETEXT, face, "Face has empty blob"); | 104 else |
| 105 { |
| 106 hb_blob_t *blob = hb_face_reference_blob (face); |
| 107 unsigned int blob_length; |
| 108 const char *blob_data = hb_blob_get_data (blob, &blob_length); |
| 109 if (unlikely (!blob_length)) |
| 110 DEBUG_MSG (CORETEXT, face, "Face has empty blob"); |
73 | 111 |
74 CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, bl
ob_length, &release_data); | 112 CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data,
blob_length, &release_data); |
75 data->cg_font = CGFontCreateWithDataProvider (provider); | 113 data->cg_font = CGFontCreateWithDataProvider (provider); |
76 CGDataProviderRelease (provider); | 114 CGDataProviderRelease (provider); |
| 115 } |
77 | 116 |
78 if (unlikely (!data->cg_font)) { | 117 if (unlikely (!data->cg_font)) { |
79 DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed"); | 118 DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed"); |
80 free (data); | 119 free (data); |
81 return NULL; | 120 return NULL; |
82 } | 121 } |
83 | 122 |
84 return data; | 123 return data; |
85 } | 124 } |
86 | 125 |
(...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
387 } | 426 } |
388 | 427 |
389 hb_bool_t | 428 hb_bool_t |
390 _hb_coretext_shape (hb_shape_plan_t *shape_plan, | 429 _hb_coretext_shape (hb_shape_plan_t *shape_plan, |
391 hb_font_t *font, | 430 hb_font_t *font, |
392 hb_buffer_t *buffer, | 431 hb_buffer_t *buffer, |
393 const hb_feature_t *features, | 432 const hb_feature_t *features, |
394 unsigned int num_features) | 433 unsigned int num_features) |
395 { | 434 { |
396 hb_face_t *face = font->face; | 435 hb_face_t *face = font->face; |
| 436 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); |
397 hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); | 437 hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); |
398 | 438 |
399 /* | 439 /* |
400 * Set up features. | 440 * Set up features. |
401 * (copied + modified from code from hb-uniscribe.cc) | 441 * (copied + modified from code from hb-uniscribe.cc) |
402 */ | 442 */ |
403 hb_auto_array_t<feature_record_t> feature_records; | 443 hb_auto_array_t<feature_record_t> feature_records; |
404 hb_auto_array_t<range_record_t> range_records; | 444 hb_auto_array_t<range_record_t> range_records; |
405 if (num_features) | 445 if (num_features) |
406 { | 446 { |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
583 } | 623 } |
584 | 624 |
585 #undef utf16_index | 625 #undef utf16_index |
586 | 626 |
587 CFStringRef string_ref = CFStringCreateWithCharactersNoCopy (NULL, | 627 CFStringRef string_ref = CFStringCreateWithCharactersNoCopy (NULL, |
588 pchars, chars_len
, | 628 pchars, chars_len
, |
589 kCFAllocatorNull)
; | 629 kCFAllocatorNull)
; |
590 | 630 |
591 CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (NU
LL, chars_len); | 631 CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (NU
LL, chars_len); |
592 CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref); | 632 CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref); |
593 CFRelease (string_ref); | |
594 CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len), | 633 CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len), |
595 kCTFontAttributeName, font_data->ct_font); | 634 kCTFontAttributeName, font_data->ct_font); |
596 | 635 |
597 if (num_features) | 636 if (num_features) |
598 { | 637 { |
599 ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len); | 638 ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len); |
600 | 639 |
601 /* Need log_clusters to assign features. */ | 640 /* Need log_clusters to assign features. */ |
602 chars_len = 0; | 641 chars_len = 0; |
603 for (unsigned int i = 0; i < buffer->len; i++) | 642 for (unsigned int i = 0; i < buffer->len; i++) |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
641 CTLineRef line = CTLineCreateWithAttributedString (attr_string); | 680 CTLineRef line = CTLineCreateWithAttributedString (attr_string); |
642 CFRelease (attr_string); | 681 CFRelease (attr_string); |
643 | 682 |
644 CFArrayRef glyph_runs = CTLineGetGlyphRuns (line); | 683 CFArrayRef glyph_runs = CTLineGetGlyphRuns (line); |
645 unsigned int num_runs = CFArrayGetCount (glyph_runs); | 684 unsigned int num_runs = CFArrayGetCount (glyph_runs); |
646 | 685 |
647 buffer->len = 0; | 686 buffer->len = 0; |
648 | 687 |
649 const CFRange range_all = CFRangeMake (0, 0); | 688 const CFRange range_all = CFRangeMake (0, 0); |
650 | 689 |
651 for (unsigned int i = 0; i < num_runs; i++) { | 690 for (unsigned int i = 0; i < num_runs; i++) |
| 691 { |
652 CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (glyph_runs, i); | 692 CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (glyph_runs, i); |
653 | 693 |
| 694 /* CoreText does automatic font fallback (AKA "cascading") for characters |
| 695 * not supported by the requested font, and provides no way to turn it off, |
| 696 * so we detect if the returned run uses a font other than the requested |
| 697 * one and fill in the buffer with .notdef glyphs instead of random glyph |
| 698 * indices from a different font. |
| 699 */ |
| 700 CFDictionaryRef attributes = CTRunGetAttributes (run); |
| 701 CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attribu
tes, kCTFontAttributeName)); |
| 702 CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0); |
| 703 if (!CFEqual (run_cg_font, face_data->cg_font)) |
| 704 { |
| 705 CFRelease (run_cg_font); |
| 706 |
| 707 CFRange range = CTRunGetStringRange (run); |
| 708 buffer->ensure (buffer->len + range.length); |
| 709 if (buffer->in_error) |
| 710 FAIL ("Buffer resize failed"); |
| 711 hb_glyph_info_t *info = buffer->info + buffer->len; |
| 712 |
| 713 CGGlyph notdef = 0; |
| 714 double advance = CTFontGetAdvancesForGlyphs (font_data->ct_font, kCTFont
HorizontalOrientation, ¬def, NULL, 1); |
| 715 |
| 716 for (CFIndex j = range.location; j < range.location + range.length; j++) |
| 717 { |
| 718 UniChar ch = CFStringGetCharacterAtIndex (string_ref, j); |
| 719 if (hb_in_range<UniChar> (ch, 0xDC00, 0xDFFF) && range.location < j) |
| 720 { |
| 721 ch = CFStringGetCharacterAtIndex (string_ref, j - 1); |
| 722 if (hb_in_range<UniChar> (ch, 0xD800, 0xDBFF)) |
| 723 /* This is the second of a surrogate pair. Don't need .notdef |
| 724 * for this one. */ |
| 725 continue; |
| 726 } |
| 727 |
| 728 info->codepoint = notdef; |
| 729 /* TODO We have to fixup clusters later. See vis_clusters in |
| 730 * hb-uniscribe.cc for example. */ |
| 731 info->cluster = j; |
| 732 |
| 733 info->mask = advance; |
| 734 info->var1.u32 = 0; |
| 735 info->var2.u32 = 0; |
| 736 |
| 737 info++; |
| 738 buffer->len++; |
| 739 } |
| 740 continue; |
| 741 } |
| 742 CFRelease (run_cg_font); |
| 743 |
654 unsigned int num_glyphs = CTRunGetGlyphCount (run); | 744 unsigned int num_glyphs = CTRunGetGlyphCount (run); |
655 if (num_glyphs == 0) | 745 if (num_glyphs == 0) |
656 continue; | 746 continue; |
657 | 747 |
658 buffer->ensure (buffer->len + num_glyphs); | 748 buffer->ensure (buffer->len + num_glyphs); |
659 | 749 |
660 scratch = buffer->get_scratch_buffer (&scratch_size); | 750 scratch = buffer->get_scratch_buffer (&scratch_size); |
661 | 751 |
662 /* Testing indicates that CTRunGetGlyphsPtr, etc (almost?) always | 752 /* Testing indicates that CTRunGetGlyphsPtr, etc (almost?) always |
663 * succeed, and so copying data to our own buffer will be rare. */ | 753 * succeed, and so copying data to our own buffer will be rare. */ |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
747 if (buffer->info[j - 1].cluster < curr_cluster) | 837 if (buffer->info[j - 1].cluster < curr_cluster) |
748 buffer->info[j - 1].cluster = curr_cluster; | 838 buffer->info[j - 1].cluster = curr_cluster; |
749 else | 839 else |
750 break; | 840 break; |
751 } | 841 } |
752 } | 842 } |
753 prev_cluster = curr_cluster; | 843 prev_cluster = curr_cluster; |
754 } | 844 } |
755 } | 845 } |
756 | 846 |
| 847 CFRelease (string_ref); |
757 CFRelease (line); | 848 CFRelease (line); |
758 | 849 |
759 return true; | 850 return true; |
760 } | 851 } |
| 852 |
| 853 |
| 854 /* |
| 855 * AAT shaper |
| 856 */ |
| 857 |
| 858 HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face) |
| 859 HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font) |
| 860 |
| 861 |
| 862 /* |
| 863 * shaper face data |
| 864 */ |
| 865 |
| 866 struct hb_coretext_aat_shaper_face_data_t {}; |
| 867 |
| 868 hb_coretext_aat_shaper_face_data_t * |
| 869 _hb_coretext_aat_shaper_face_data_create (hb_face_t *face) |
| 870 { |
| 871 hb_blob_t *mort_blob = face->reference_table (HB_CORETEXT_TAG_MORT); |
| 872 /* Umm, we just reference the table to check whether it exists. |
| 873 * Maybe add better API for this? */ |
| 874 if (!hb_blob_get_length (mort_blob)) |
| 875 { |
| 876 hb_blob_destroy (mort_blob); |
| 877 mort_blob = face->reference_table (HB_CORETEXT_TAG_MORX); |
| 878 if (!hb_blob_get_length (mort_blob)) |
| 879 { |
| 880 hb_blob_destroy (mort_blob); |
| 881 return NULL; |
| 882 } |
| 883 } |
| 884 hb_blob_destroy (mort_blob); |
| 885 |
| 886 return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_fa
ce_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL; |
| 887 } |
| 888 |
| 889 void |
| 890 _hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *d
ata HB_UNUSED) |
| 891 { |
| 892 } |
| 893 |
| 894 |
| 895 /* |
| 896 * shaper font data |
| 897 */ |
| 898 |
| 899 struct hb_coretext_aat_shaper_font_data_t {}; |
| 900 |
| 901 hb_coretext_aat_shaper_font_data_t * |
| 902 _hb_coretext_aat_shaper_font_data_create (hb_font_t *font) |
| 903 { |
| 904 return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_fo
nt_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL; |
| 905 } |
| 906 |
| 907 void |
| 908 _hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *d
ata HB_UNUSED) |
| 909 { |
| 910 } |
| 911 |
| 912 |
| 913 /* |
| 914 * shaper shape_plan data |
| 915 */ |
| 916 |
| 917 struct hb_coretext_aat_shaper_shape_plan_data_t {}; |
| 918 |
| 919 hb_coretext_aat_shaper_shape_plan_data_t * |
| 920 _hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan H
B_UNUSED, |
| 921 const hb_feature_t *user_features H
B_UNUSED, |
| 922 unsigned int num_user_featur
es HB_UNUSED) |
| 923 { |
| 924 return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; |
| 925 } |
| 926 |
| 927 void |
| 928 _hb_coretext_aat_shaper_shape_plan_data_destroy (hb_coretext_aat_shaper_shape_pl
an_data_t *data HB_UNUSED) |
| 929 { |
| 930 } |
| 931 |
| 932 |
| 933 /* |
| 934 * shaper |
| 935 */ |
| 936 |
| 937 hb_bool_t |
| 938 _hb_coretext_aat_shape (hb_shape_plan_t *shape_plan, |
| 939 hb_font_t *font, |
| 940 hb_buffer_t *buffer, |
| 941 const hb_feature_t *features, |
| 942 unsigned int num_features) |
| 943 { |
| 944 return _hb_coretext_shape (shape_plan, font, buffer, features, num_features); |
| 945 } |
OLD | NEW |