| 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 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 return face_data; | 133 return face_data; |
| 134 } | 134 } |
| 135 | 135 |
| 136 | 136 |
| 137 /* | 137 /* |
| 138 * shaper font data | 138 * shaper font data |
| 139 */ | 139 */ |
| 140 | 140 |
| 141 struct hb_coretext_shaper_font_data_t { | 141 struct hb_coretext_shaper_font_data_t { |
| 142 CTFontRef ct_font; | 142 CTFontRef ct_font; |
| 143 CGFloat x_mult, y_mult; /* From CT space to HB space. */ |
| 143 }; | 144 }; |
| 144 | 145 |
| 145 hb_coretext_shaper_font_data_t * | 146 hb_coretext_shaper_font_data_t * |
| 146 _hb_coretext_shaper_font_data_create (hb_font_t *font) | 147 _hb_coretext_shaper_font_data_create (hb_font_t *font) |
| 147 { | 148 { |
| 148 if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL; | 149 if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL; |
| 149 | 150 |
| 150 hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) call
oc (1, sizeof (hb_coretext_shaper_font_data_t)); | 151 hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) call
oc (1, sizeof (hb_coretext_shaper_font_data_t)); |
| 151 if (unlikely (!data)) | 152 if (unlikely (!data)) |
| 152 return NULL; | 153 return NULL; |
| 153 | 154 |
| 154 hb_face_t *face = font->face; | 155 hb_face_t *face = font->face; |
| 155 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); | 156 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); |
| 156 | 157 |
| 157 data->ct_font = CTFontCreateWithGraphicsFont (face_data, font->y_scale, NULL,
NULL); | 158 /* Choose a CoreText font size and calculate multipliers to convert to HarfBuz
z space. */ |
| 159 CGFloat font_size = 36.; /* Default... */ |
| 160 /* No idea if the following is even a good idea. */ |
| 161 if (font->y_ppem) |
| 162 font_size = font->y_ppem; |
| 163 |
| 164 if (font_size < 0) |
| 165 font_size = -font_size; |
| 166 data->x_mult = (CGFloat) font->x_scale / font_size; |
| 167 data->y_mult = (CGFloat) font->y_scale / font_size; |
| 168 data->ct_font = CTFontCreateWithGraphicsFont (face_data, font_size, NULL, NULL
); |
| 158 if (unlikely (!data->ct_font)) { | 169 if (unlikely (!data->ct_font)) { |
| 159 DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed"); | 170 DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed"); |
| 160 free (data); | 171 free (data); |
| 161 return NULL; | 172 return NULL; |
| 162 } | 173 } |
| 163 | 174 |
| 164 return data; | 175 return data; |
| 165 } | 176 } |
| 166 | 177 |
| 167 void | 178 void |
| (...skipping 601 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 769 if (unlikely (!line)) | 780 if (unlikely (!line)) |
| 770 FAIL ("CTTypesetterCreateLine failed"); | 781 FAIL ("CTTypesetterCreateLine failed"); |
| 771 } | 782 } |
| 772 | 783 |
| 773 CFArrayRef glyph_runs = CTLineGetGlyphRuns (line); | 784 CFArrayRef glyph_runs = CTLineGetGlyphRuns (line); |
| 774 unsigned int num_runs = CFArrayGetCount (glyph_runs); | 785 unsigned int num_runs = CFArrayGetCount (glyph_runs); |
| 775 DEBUG_MSG (CORETEXT, NULL, "Num runs: %d", num_runs); | 786 DEBUG_MSG (CORETEXT, NULL, "Num runs: %d", num_runs); |
| 776 | 787 |
| 777 buffer->len = 0; | 788 buffer->len = 0; |
| 778 uint32_t status_and = ~0, status_or = 0; | 789 uint32_t status_and = ~0, status_or = 0; |
| 790 double advances_so_far = 0; |
| 779 | 791 |
| 780 const CFRange range_all = CFRangeMake (0, 0); | 792 const CFRange range_all = CFRangeMake (0, 0); |
| 781 | 793 |
| 782 for (unsigned int i = 0; i < num_runs; i++) | 794 for (unsigned int i = 0; i < num_runs; i++) |
| 783 { | 795 { |
| 784 CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex (glyph_runs, i
)); | 796 CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex (glyph_runs, i
)); |
| 785 CTRunStatus run_status = CTRunGetStatus (run); | 797 CTRunStatus run_status = CTRunGetStatus (run); |
| 786 status_or |= run_status; | 798 status_or |= run_status; |
| 787 status_and &= run_status; | 799 status_and &= run_status; |
| 788 DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status); | 800 DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status); |
| 801 double run_advance = CTRunGetTypographicBounds (run, range_all, NULL, NULL
, NULL); |
| 802 if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction)) |
| 803 run_advance = -run_advance; |
| 804 DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance); |
| 789 | 805 |
| 790 /* CoreText does automatic font fallback (AKA "cascading") for characters | 806 /* CoreText does automatic font fallback (AKA "cascading") for characters |
| 791 * not supported by the requested font, and provides no way to turn it off
, | 807 * not supported by the requested font, and provides no way to turn it off
, |
| 792 * so we must detect if the returned run uses a font other than the reques
ted | 808 * so we must detect if the returned run uses a font other than the reques
ted |
| 793 * one and fill in the buffer with .notdef glyphs instead of random glyph | 809 * one and fill in the buffer with .notdef glyphs instead of random glyph |
| 794 * indices from a different font. | 810 * indices from a different font. |
| 795 */ | 811 */ |
| 796 CFDictionaryRef attributes = CTRunGetAttributes (run); | 812 CFDictionaryRef attributes = CTRunGetAttributes (run); |
| 797 CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attri
butes, kCTFontAttributeName)); | 813 CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attri
butes, kCTFontAttributeName)); |
| 798 if (!CFEqual (run_ct_font, font_data->ct_font)) | 814 if (!CFEqual (run_ct_font, font_data->ct_font)) |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 853 } | 869 } |
| 854 if (!matched) | 870 if (!matched) |
| 855 { | 871 { |
| 856 CFRange range = CTRunGetStringRange (run); | 872 CFRange range = CTRunGetStringRange (run); |
| 857 DEBUG_MSG (CORETEXT, run, "Run used fallback font: %ld..%ld", | 873 DEBUG_MSG (CORETEXT, run, "Run used fallback font: %ld..%ld", |
| 858 range.location, range.location + range.length); | 874 range.location, range.location + range.length); |
| 859 if (!buffer->ensure_inplace (buffer->len + range.length)) | 875 if (!buffer->ensure_inplace (buffer->len + range.length)) |
| 860 goto resize_and_retry; | 876 goto resize_and_retry; |
| 861 hb_glyph_info_t *info = buffer->info + buffer->len; | 877 hb_glyph_info_t *info = buffer->info + buffer->len; |
| 862 | 878 |
| 863 » CGGlyph notdef = 0; | 879 » hb_codepoint_t notdef = 0; |
| 864 » double advance = CTFontGetAdvancesForGlyphs (font_data->ct_font, kCTFo
ntHorizontalOrientation, ¬def, NULL, 1); | 880 » hb_direction_t dir = buffer->props.direction; |
| 881 » hb_position_t x_advance, y_advance, x_offset, y_offset; |
| 882 » hb_font_get_glyph_advance_for_direction (font, notdef, dir, &x_advance
, &y_advance); |
| 883 » hb_font_get_glyph_origin_for_direction (font, notdef, dir, &x_offset,
&y_offset); |
| 884 » hb_position_t advance = x_advance + y_advance; |
| 885 » x_offset = -x_offset; |
| 886 » y_offset = -y_offset; |
| 865 | 887 |
| 866 unsigned int old_len = buffer->len; | 888 unsigned int old_len = buffer->len; |
| 867 for (CFIndex j = range.location; j < range.location + range.length; j+
+) | 889 for (CFIndex j = range.location; j < range.location + range.length; j+
+) |
| 868 { | 890 { |
| 869 UniChar ch = CFStringGetCharacterAtIndex (string_ref, j); | 891 UniChar ch = CFStringGetCharacterAtIndex (string_ref, j); |
| 870 if (hb_in_range<UniChar> (ch, 0xDC00u, 0xDFFFu) && range.location
< j) | 892 if (hb_in_range<UniChar> (ch, 0xDC00u, 0xDFFFu) && range.location
< j) |
| 871 { | 893 { |
| 872 ch = CFStringGetCharacterAtIndex (string_ref, j - 1); | 894 ch = CFStringGetCharacterAtIndex (string_ref, j - 1); |
| 873 if (hb_in_range<UniChar> (ch, 0xD800u, 0xDBFFu)) | 895 if (hb_in_range<UniChar> (ch, 0xD800u, 0xDBFFu)) |
| 874 /* This is the second of a surrogate pair. Don't need .notdef | 896 /* This is the second of a surrogate pair. Don't need .notdef |
| 875 * for this one. */ | 897 * for this one. */ |
| 876 continue; | 898 continue; |
| 877 } | 899 } |
| 900 if (buffer->unicode->is_default_ignorable (ch)) |
| 901 continue; |
| 878 | 902 |
| 879 info->codepoint = notdef; | 903 info->codepoint = notdef; |
| 880 info->cluster = log_clusters[j]; | 904 info->cluster = log_clusters[j]; |
| 881 | 905 |
| 882 info->mask = advance; | 906 info->mask = advance; |
| 883 » info->var1.u32 = 0; | 907 » info->var1.u32 = x_offset; |
| 884 » info->var2.u32 = 0; | 908 » info->var2.u32 = y_offset; |
| 885 | 909 |
| 886 info++; | 910 info++; |
| 887 buffer->len++; | 911 buffer->len++; |
| 888 } | 912 } |
| 889 if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) | 913 if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) |
| 890 buffer->reverse_range (old_len, buffer->len); | 914 buffer->reverse_range (old_len, buffer->len); |
| 915 advances_so_far += run_advance; |
| 891 continue; | 916 continue; |
| 892 } | 917 } |
| 893 } | 918 } |
| 894 | 919 |
| 895 unsigned int num_glyphs = CTRunGetGlyphCount (run); | 920 unsigned int num_glyphs = CTRunGetGlyphCount (run); |
| 896 if (num_glyphs == 0) | 921 if (num_glyphs == 0) |
| 897 continue; | 922 continue; |
| 898 | 923 |
| 899 if (!buffer->ensure_inplace (buffer->len + num_glyphs)) | 924 if (!buffer->ensure_inplace (buffer->len + num_glyphs)) |
| 900 goto resize_and_retry; | 925 goto resize_and_retry; |
| 901 | 926 |
| 902 hb_glyph_info_t *run_info = buffer->info + buffer->len; | 927 hb_glyph_info_t *run_info = buffer->info + buffer->len; |
| 903 | 928 |
| 904 /* Testing used to indicate that CTRunGetGlyphsPtr, etc (almost?) always | 929 /* Testing used to indicate that CTRunGetGlyphsPtr, etc (almost?) always |
| 905 * succeed, and so copying data to our own buffer will be rare. Reports | 930 * succeed, and so copying data to our own buffer will be rare. Reports |
| 906 * have it that this changed in OS X 10.10 Yosemite, and NULL is returned | 931 * have it that this changed in OS X 10.10 Yosemite, and NULL is returned |
| 907 * frequently. At any rate, we can test that codepath by setting USE_PTR | 932 * frequently. At any rate, we can test that codepath by setting USE_PTR |
| 908 * to false. */ | 933 * to false. */ |
| 909 | 934 |
| 910 #define USE_PTR true | 935 #define USE_PTR true |
| 911 | 936 |
| 912 #define SCRATCH_SAVE() \ | 937 #define SCRATCH_SAVE() \ |
| 913 unsigned int scratch_size_saved = scratch_size; \ | 938 unsigned int scratch_size_saved = scratch_size; \ |
| 914 hb_buffer_t::scratch_buffer_t *scratch_saved = scratch | 939 hb_buffer_t::scratch_buffer_t *scratch_saved = scratch |
| 915 | 940 |
| 916 #define SCRATCH_RESTORE() \ | 941 #define SCRATCH_RESTORE() \ |
| 917 scratch_size = scratch_size_saved; \ | 942 scratch_size = scratch_size_saved; \ |
| 918 scratch = scratch_saved; | 943 scratch = scratch_saved; |
| 919 | 944 |
| 920 { | 945 { /* Setup glyphs */ |
| 921 SCRATCH_SAVE(); | 946 SCRATCH_SAVE(); |
| 922 const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : NULL; | 947 const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : NULL; |
| 923 if (!glyphs) { | 948 if (!glyphs) { |
| 924 ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs, goto resize_and_retry)
; | 949 ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs, goto resize_and_retry)
; |
| 925 CTRunGetGlyphs (run, range_all, glyph_buf); | 950 CTRunGetGlyphs (run, range_all, glyph_buf); |
| 926 glyphs = glyph_buf; | 951 glyphs = glyph_buf; |
| 927 } | 952 } |
| 928 const CFIndex* string_indices = USE_PTR ? CTRunGetStringIndicesPtr (run)
: NULL; | 953 const CFIndex* string_indices = USE_PTR ? CTRunGetStringIndicesPtr (run)
: NULL; |
| 929 if (!string_indices) { | 954 if (!string_indices) { |
| 930 ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs, goto resize_and_retry)
; | 955 ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs, goto resize_and_retry)
; |
| 931 CTRunGetStringIndices (run, range_all, index_buf); | 956 CTRunGetStringIndices (run, range_all, index_buf); |
| 932 string_indices = index_buf; | 957 string_indices = index_buf; |
| 933 } | 958 } |
| 934 hb_glyph_info_t *info = run_info; | 959 hb_glyph_info_t *info = run_info; |
| 935 for (unsigned int j = 0; j < num_glyphs; j++) | 960 for (unsigned int j = 0; j < num_glyphs; j++) |
| 936 { | 961 { |
| 937 info->codepoint = glyphs[j]; | 962 info->codepoint = glyphs[j]; |
| 938 info->cluster = log_clusters[string_indices[j]]; | 963 info->cluster = log_clusters[string_indices[j]]; |
| 939 info++; | 964 info++; |
| 940 } | 965 } |
| 941 SCRATCH_RESTORE(); | 966 SCRATCH_RESTORE(); |
| 942 } | 967 } |
| 943 { | 968 { |
| 969 /* Setup positions. |
| 970 * Note that CoreText does not return advances for glyphs. As such, |
| 971 * for all but last glyph, we use the delta position to next glyph as |
| 972 * advance (in the advance direction only), and for last glyph we set |
| 973 * whatever is needed to make the whole run's advance add up. */ |
| 944 SCRATCH_SAVE(); | 974 SCRATCH_SAVE(); |
| 945 const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : NULL; | 975 const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : NULL; |
| 946 if (!positions) { | 976 if (!positions) { |
| 947 ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_ret
ry); | 977 ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_ret
ry); |
| 948 CTRunGetPositions (run, range_all, position_buf); | 978 CTRunGetPositions (run, range_all, position_buf); |
| 949 positions = position_buf; | 979 positions = position_buf; |
| 950 } | 980 } |
| 951 double run_advance = CTRunGetTypographicBounds (run, range_all, NULL, NU
LL, NULL); | |
| 952 DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance); | |
| 953 hb_glyph_info_t *info = run_info; | 981 hb_glyph_info_t *info = run_info; |
| 982 CGFloat x_mult = font_data->x_mult, y_mult = font_data->y_mult; |
| 954 if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) | 983 if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) |
| 955 { | 984 { |
| 985 hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult; |
| 956 for (unsigned int j = 0; j < num_glyphs; j++) | 986 for (unsigned int j = 0; j < num_glyphs; j++) |
| 957 { | 987 { |
| 958 » double advance = (j + 1 < num_glyphs ? positions[j + 1].x : position
s[0].x + run_advance) - positions[j].x; | 988 » double advance; |
| 959 » info->mask = advance; | 989 » if (likely (j + 1 < num_glyphs)) |
| 960 » info->var1.u32 = positions[0].x; /* Yes, zero. */ | 990 » advance = positions[j + 1].x - positions[j].x; |
| 961 » info->var2.u32 = positions[j].y; | 991 » else /* last glyph */ |
| 992 » advance = run_advance - (positions[j].x - positions[0].x); |
| 993 » info->mask = advance * x_mult; |
| 994 » info->var1.u32 = x_offset; |
| 995 » info->var2.u32 = positions[j].y * y_mult; |
| 962 info++; | 996 info++; |
| 963 } | 997 } |
| 964 } | 998 } |
| 965 else | 999 else |
| 966 { | 1000 { |
| 967 » run_advance = -run_advance; | 1001 » hb_position_t y_offset = (positions[0].y - advances_so_far) * y_mult; |
| 968 for (unsigned int j = 0; j < num_glyphs; j++) | 1002 for (unsigned int j = 0; j < num_glyphs; j++) |
| 969 { | 1003 { |
| 970 » double advance = (j + 1 < num_glyphs ? positions[j + 1].y : position
s[0].y + run_advance) - positions[j].y; | 1004 » double advance; |
| 971 » info->mask = advance; | 1005 » if (likely (j + 1 < num_glyphs)) |
| 972 » info->var1.u32 = positions[j].x; | 1006 » advance = positions[j + 1].y - positions[j].y; |
| 973 » info->var2.u32 = positions[0].y; /* Yes, zero. */ | 1007 » else /* last glyph */ |
| 1008 » advance = run_advance - (positions[j].y - positions[0].y); |
| 1009 » info->mask = advance * y_mult; |
| 1010 » info->var1.u32 = positions[j].x * x_mult; |
| 1011 » info->var2.u32 = y_offset; |
| 974 info++; | 1012 info++; |
| 975 } | 1013 } |
| 976 } | 1014 } |
| 977 SCRATCH_RESTORE(); | 1015 SCRATCH_RESTORE(); |
| 1016 advances_so_far += run_advance; |
| 978 } | 1017 } |
| 979 #undef SCRATCH_RESTORE | 1018 #undef SCRATCH_RESTORE |
| 980 #undef SCRATCH_SAVE | 1019 #undef SCRATCH_SAVE |
| 981 #undef USE_PTR | 1020 #undef USE_PTR |
| 982 #undef ALLOCATE_ARRAY | 1021 #undef ALLOCATE_ARRAY |
| 983 | 1022 |
| 984 buffer->len += num_glyphs; | 1023 buffer->len += num_glyphs; |
| 985 } | 1024 } |
| 986 | 1025 |
| 987 /* Make sure all runs had the expected direction. */ | 1026 /* Make sure all runs had the expected direction. */ |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1146 | 1185 |
| 1147 hb_bool_t | 1186 hb_bool_t |
| 1148 _hb_coretext_aat_shape (hb_shape_plan_t *shape_plan, | 1187 _hb_coretext_aat_shape (hb_shape_plan_t *shape_plan, |
| 1149 hb_font_t *font, | 1188 hb_font_t *font, |
| 1150 hb_buffer_t *buffer, | 1189 hb_buffer_t *buffer, |
| 1151 const hb_feature_t *features, | 1190 const hb_feature_t *features, |
| 1152 unsigned int num_features) | 1191 unsigned int num_features) |
| 1153 { | 1192 { |
| 1154 return _hb_coretext_shape (shape_plan, font, buffer, features, num_features); | 1193 return _hb_coretext_shape (shape_plan, font, buffer, features, num_features); |
| 1155 } | 1194 } |
| OLD | NEW |